From 58d9677ddd3418dce74ecb6b713d57d0f82ecb10 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 4 Nov 2013 22:42:03 +0800 Subject: [PATCH] support vhosts specified config. --- README.md | 1 + trunk/conf/srs.conf | 13 +++-- trunk/configure | 2 +- trunk/src/core/srs_core_client.cpp | 71 +++++++++++++++++++++- trunk/src/core/srs_core_client.hpp | 3 + trunk/src/core/srs_core_config.cpp | 94 ++++++++++++++++++++++++++++++ trunk/src/core/srs_core_config.hpp | 14 +++++ trunk/src/core/srs_core_error.hpp | 2 + trunk/src/core/srs_core_refer.cpp | 88 ++++++++++++++++++++++++++++ trunk/src/core/srs_core_refer.hpp | 49 ++++++++++++++++ trunk/src/core/srs_core_rtmp.cpp | 29 ++++++++- trunk/src/core/srs_core_rtmp.hpp | 3 + trunk/src/core/srs_core_source.cpp | 13 +++++ trunk/src/core/srs_core_source.hpp | 1 + trunk/src/srs/srs.upp | 2 + 15 files changed, 376 insertions(+), 9 deletions(-) create mode 100755 trunk/src/core/srs_core_refer.cpp create mode 100755 trunk/src/core/srs_core_refer.hpp diff --git a/README.md b/README.md index 4cde2a35c..1222b0396 100755 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ url: rtmp://127.0.0.1:1935/live/livestream * nginx v1.5.0: 139524 lines
### History +* v0.3, 2013-11-04, support vhosts specified config. * v0.3, 2013-11-02, support listen multiple ports. * v0.3, 2013-11-02, support config file in nginx-conf style. * v0.3, 2013-10-29, support pithy print log message specified by stage. diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf index 1af614102..36702d7c9 100755 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -1,7 +1,12 @@ listen 1935 19350; vhost __defaultVhost__ { - application live { - no_delay on; - allow all; - } + enabled on; + gop_cache on; + #refer github.com github.io; + #refer_publish github.com github.io; + refer_play github.com github.io .com; } +vhost winlinvip.github.com { + gop_cache off; +} + diff --git a/trunk/configure b/trunk/configure index ad23cb03b..0149d34c7 100755 --- a/trunk/configure +++ b/trunk/configure @@ -91,7 +91,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server" "srs_core_auto_free" "srs_core_protocol" "srs_core_amf0" "srs_core_stream" "srs_core_source" "srs_core_codec" "srs_core_complex_handshake" "srs_core_pithy_print" - "srs_core_config") + "srs_core_config" "srs_core_refer") MODULE_DIR="src/core" . auto/modules.sh CORE_OBJS="${MODULE_OBJS[@]}" diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index 782e0a872..1c1118c25 100755 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include +#include #define SRS_PULSE_TIMEOUT_MS 100 #define SRS_SEND_TIMEOUT_MS 5000000L @@ -45,6 +47,7 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) req = new SrsRequest(); res = new SrsResponse(); rtmp = new SrsRtmp(client_stfd); + refer = new SrsRefer(); } SrsClient::~SrsClient() @@ -53,6 +56,7 @@ SrsClient::~SrsClient() srs_freep(req); srs_freep(res); srs_freep(rtmp); + srs_freep(refer); } int SrsClient::do_cycle() @@ -79,11 +83,25 @@ int SrsClient::do_cycle() srs_error("rtmp connect vhost/app failed. ret=%d", ret); return ret; } + srs_verbose("rtmp connect app success"); + + if ((ret = check_vhost()) != ERROR_SUCCESS) { + srs_error("check vhost failed. ret=%d", ret); + return ret; + } + srs_verbose("check vhost success."); + srs_trace("rtmp connect app success. " "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s", req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(), req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), req->app.c_str()); + + if ((ret = refer->check(req->pageUrl, config->get_refer(req->vhost))) != ERROR_SUCCESS) { + srs_error("check refer failed. ret=%d", ret); + return ret; + } + srs_verbose("check refer success."); if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) { srs_error("set window acknowledgement size failed. ret=%d", ret); @@ -114,7 +132,8 @@ int SrsClient::do_cycle() srs_error("identify client failed. ret=%d", ret); return ret; } - srs_verbose("identify client success. type=%d, stream_name=%s", type, req->stream.c_str()); + req->strip(); + srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str()); // TODO: read from config. int chunk_size = 4096; @@ -127,7 +146,15 @@ int SrsClient::do_cycle() // find a source to publish. SrsSource* source = SrsSource::find(req->get_stream_url()); srs_assert(source != NULL); - srs_info("source found, url=%s", req->get_stream_url().c_str()); + + SrsConfDirective* conf = config->get_gop_cache(req->vhost); + bool enabled_cache = true; + if (conf && conf->arg0() == "off") { + enabled_cache = false; + } + source->set_cache(enabled_cache); + + srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache); switch (type) { case SrsClientPlay: { @@ -174,10 +201,44 @@ int SrsClient::do_cycle() return ret; } +int SrsClient::check_vhost() +{ + int ret = ERROR_SUCCESS; + + srs_assert(req != NULL); + + SrsConfDirective* vhost = config->get_vhost(req->vhost); + if (vhost == NULL) { + ret = ERROR_RTMP_VHOST_NOT_FOUND; + srs_error("vhost %s not found. ret=%d", req->vhost.c_str(), ret); + return ret; + } + + SrsConfDirective* conf = NULL; + if ((conf = vhost->get(RTMP_VHOST_ENABLED)) != NULL && conf->arg0() == "off") { + ret = ERROR_RTMP_VHOST_NOT_FOUND; + srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret); + return ret; + } + + if (req->vhost != vhost->arg0()) { + srs_trace("vhost change from %s to %s", req->vhost.c_str(), vhost->arg0().c_str()); + req->vhost = vhost->arg0(); + } + + return ret; +} + int SrsClient::playing(SrsSource* source) { int ret = ERROR_SUCCESS; + if ((ret = refer->check(req->pageUrl, config->get_refer_play(req->vhost))) != ERROR_SUCCESS) { + srs_error("check play_refer failed. ret=%d", ret); + return ret; + } + srs_verbose("check play_refer success."); + SrsConsumer* consumer = NULL; if ((ret = source->create_consumer(consumer)) != ERROR_SUCCESS) { srs_error("create consumer failed. ret=%d", ret); @@ -258,6 +319,12 @@ int SrsClient::publish(SrsSource* source, bool is_fmle) { int ret = ERROR_SUCCESS; + if ((ret = refer->check(req->pageUrl, config->get_refer_publish(req->vhost))) != ERROR_SUCCESS) { + srs_error("check publish_refer failed. ret=%d", ret); + return ret; + } + srs_verbose("check publish_refer success."); + SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER); while (true) { diff --git a/trunk/src/core/srs_core_client.hpp b/trunk/src/core/srs_core_client.hpp index 763d3ecec..dab54e170 100755 --- a/trunk/src/core/srs_core_client.hpp +++ b/trunk/src/core/srs_core_client.hpp @@ -36,6 +36,7 @@ class SrsRtmp; class SrsRequest; class SrsResponse; class SrsSource; +class SrsRefer; /** * the client provides the main logic control for RTMP clients. @@ -47,12 +48,14 @@ private: SrsRequest* req; SrsResponse* res; SrsRtmp* rtmp; + SrsRefer* refer; public: SrsClient(SrsServer* srs_server, st_netfd_t client_stfd); virtual ~SrsClient(); protected: virtual int do_cycle(); private: + virtual int check_vhost(); virtual int playing(SrsSource* source); virtual int publish(SrsSource* source, bool is_fmle); virtual int get_peer_ip(); diff --git a/trunk/src/core/srs_core_config.cpp b/trunk/src/core/srs_core_config.cpp index 0aa3ba6fe..3a183e14b 100755 --- a/trunk/src/core/srs_core_config.cpp +++ b/trunk/src/core/srs_core_config.cpp @@ -102,6 +102,33 @@ SrsConfDirective::~SrsConfDirective() directives.clear(); } +std::string SrsConfDirective::arg0() +{ + if (args.size() > 0) { + return args.at(0); + } + + return ""; +} + +std::string SrsConfDirective::arg1() +{ + if (args.size() > 1) { + return args.at(1); + } + + return ""; +} + +std::string SrsConfDirective::arg2() +{ + if (args.size() > 2) { + return args.at(2); + } + + return ""; +} + SrsConfDirective* SrsConfDirective::at(int index) { return directives.at(index); @@ -437,6 +464,73 @@ int Config::parse_options(int argc, char** argv) return ret; } +SrsConfDirective* Config::get_vhost(std::string vhost) +{ + srs_assert(root); + + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* conf = root->at(i); + + if (conf->name != "vhost") { + continue; + } + + if (conf->arg0() == vhost) { + return conf; + } + } + + if (vhost != RTMP_VHOST_DEFAULT) { + return get_vhost(RTMP_VHOST_DEFAULT); + } + + return NULL; +} + +SrsConfDirective* Config::get_gop_cache(std::string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("gop_cache"); +} + +SrsConfDirective* Config::get_refer(std::string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer"); +} + +SrsConfDirective* Config::get_refer_play(std::string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer_play"); +} + +SrsConfDirective* Config::get_refer_publish(std::string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer_publish"); +} + SrsConfDirective* Config::get_listen() { return root->get("listen"); diff --git a/trunk/src/core/srs_core_config.hpp b/trunk/src/core/srs_core_config.hpp index 323690e4a..189e8411e 100755 --- a/trunk/src/core/srs_core_config.hpp +++ b/trunk/src/core/srs_core_config.hpp @@ -32,6 +32,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +// default vhost for rtmp +#define RTMP_VHOST_DEFAULT "__defaultVhost__" + +// conf node: enabled. +#define RTMP_VHOST_ENABLED "enabled" + class SrsFileBuffer { public: @@ -61,6 +67,9 @@ public: public: SrsConfDirective(); virtual ~SrsConfDirective(); + std::string arg0(); + std::string arg1(); + std::string arg2(); SrsConfDirective* at(int index); SrsConfDirective* get(std::string _name); public: @@ -87,6 +96,11 @@ public: virtual ~Config(); public: virtual int parse_options(int argc, char** argv); + virtual SrsConfDirective* get_vhost(std::string vhost); + virtual SrsConfDirective* get_gop_cache(std::string vhost); + virtual SrsConfDirective* get_refer(std::string vhost); + virtual SrsConfDirective* get_refer_play(std::string vhost); + virtual SrsConfDirective* get_refer_publish(std::string vhost); virtual SrsConfDirective* get_listen(); private: virtual int parse_argv(int& i, char** argv); diff --git a/trunk/src/core/srs_core_error.hpp b/trunk/src/core/srs_core_error.hpp index e51cde12b..6dca9bbee 100755 --- a/trunk/src/core/srs_core_error.hpp +++ b/trunk/src/core/srs_core_error.hpp @@ -65,6 +65,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_RTMP_TRY_SIMPLE_HS 311 #define ERROR_RTMP_CH_SCHEMA 312 #define ERROR_RTMP_PACKET_SIZE 313 +#define ERROR_RTMP_VHOST_NOT_FOUND 314 +#define ERROR_RTMP_ACCESS_DENIED 315 #define ERROR_SYSTEM_STREAM_INIT 400 #define ERROR_SYSTEM_PACKET_INVALID 401 diff --git a/trunk/src/core/srs_core_refer.cpp b/trunk/src/core/srs_core_refer.cpp new file mode 100755 index 000000000..7fd1aa860 --- /dev/null +++ b/trunk/src/core/srs_core_refer.cpp @@ -0,0 +1,88 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include +#include + +int SrsRefer::check(std::string page_url, SrsConfDirective* refer) +{ + int ret = ERROR_SUCCESS; + + if (!refer) { + srs_verbose("ignore refer check for page_url=%s", page_url.c_str()); + return ret; + } + + for (int i = 0; i < (int)refer->args.size(); i++) { + if ((ret = check_single_refer(page_url, refer->args.at(i))) == ERROR_SUCCESS) { + srs_verbose("check refer success. page_url=%s, refer=%s", + page_url.c_str(), refer->args.at(i).c_str()); + return ret; + } + } + + ret = ERROR_RTMP_ACCESS_DENIED; + srs_error("check refer failed. ret=%d", ret); + + return ret; +} + +int SrsRefer::check_single_refer(std::string page_url, std::string refer) +{ + int ret = ERROR_SUCCESS; + + size_t pos = std::string::npos; + + std::string domain_name = page_url; + if ((pos = domain_name.find("://")) != std::string::npos) { + domain_name = domain_name.substr(pos + 3); + } + + if ((pos = domain_name.find("/")) != std::string::npos) { + domain_name = domain_name.substr(0, pos); + } + + if ((pos = domain_name.find(":")) != std::string::npos) { + domain_name = domain_name.substr(0, pos); + } + + pos = domain_name.find(refer); + if (pos == std::string::npos) { + ret = ERROR_RTMP_ACCESS_DENIED; + } + // match primary domain. + if (pos != domain_name.length() - refer.length()) { + ret = ERROR_RTMP_ACCESS_DENIED; + } + + if (ret != ERROR_SUCCESS) { + srs_verbose("access denied, page_url=%s, domain_name=%s, refer=%s, ret=%d", + page_url.c_str(), domain_name.c_str(), refer.c_str(), ret); + } + + return ret; +} + diff --git a/trunk/src/core/srs_core_refer.hpp b/trunk/src/core/srs_core_refer.hpp new file mode 100755 index 000000000..aeab41733 --- /dev/null +++ b/trunk/src/core/srs_core_refer.hpp @@ -0,0 +1,49 @@ +/* +The MIT License (MIT) + +Copyright (c) 2013 winlin + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef SRS_CORE_REFER_HPP +#define SRS_CORE_REFER_HPP + +/* +#include +*/ +#include + +#include + +class SrsConfDirective; + +class SrsRefer +{ +public: + /** + * to check the refer. + * @param page_url the client page url. + * @param refer the refer in config. + */ + virtual int check(std::string page_url, SrsConfDirective* refer); +private: + virtual int check_single_refer(std::string page_url, std::string refer); +}; + +#endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_rtmp.cpp b/trunk/src/core/srs_core_rtmp.cpp index 1d1907e21..db777f149 100755 --- a/trunk/src/core/srs_core_rtmp.cpp +++ b/trunk/src/core/srs_core_rtmp.cpp @@ -110,6 +110,8 @@ int SrsRequest::discovery_app() return ret; } + strip(); + return ret; } @@ -117,8 +119,7 @@ std::string SrsRequest::get_stream_url() { std::string url = ""; - //url += vhost; - + url += vhost; url += "/"; url += app; url += "/"; @@ -127,6 +128,30 @@ std::string SrsRequest::get_stream_url() return url; } +void SrsRequest::strip() +{ + trim(vhost, "/ \n\r\t"); + trim(app, "/ \n\r\t"); + trim(stream, "/ \n\r\t"); +} + +std::string& SrsRequest::trim(std::string& str, std::string chs) +{ + for (int i = 0; i < (int)chs.length(); i++) { + char ch = chs.at(i); + + for (std::string::iterator it = str.begin(); it != str.end();) { + if (ch == *it) { + it = str.erase(it); + } else { + ++it; + } + } + } + + return str; +} + SrsResponse::SrsResponse() { stream_id = SRS_DEFAULT_SID; diff --git a/trunk/src/core/srs_core_rtmp.hpp b/trunk/src/core/srs_core_rtmp.hpp index 8ea3d9cce..547082379 100755 --- a/trunk/src/core/srs_core_rtmp.hpp +++ b/trunk/src/core/srs_core_rtmp.hpp @@ -66,6 +66,9 @@ struct SrsRequest */ virtual int discovery_app(); virtual std::string get_stream_url(); + virtual void strip(); +private: + std::string& trim(std::string& str, std::string chs); }; /** diff --git a/trunk/src/core/srs_core_source.cpp b/trunk/src/core/srs_core_source.cpp index 9349fb13d..53c288e66 100755 --- a/trunk/src/core/srs_core_source.cpp +++ b/trunk/src/core/srs_core_source.cpp @@ -391,6 +391,19 @@ void SrsSource::on_unpublish() srs_trace("clear cache/metadata/sequence-headers when unpublish."); } +void SrsSource::set_cache(bool enabled) +{ + enable_gop_cache = enabled; + + if (!enabled) { + srs_info("disable gop cache, clear %d packets.", (int)gop_cache.size()); + clear_gop_cache(); + return; + } + + srs_info("enable gop cache"); +} + int SrsSource::cache_last_gop(SrsSharedPtrMessage* msg) { int ret = ERROR_SUCCESS; diff --git a/trunk/src/core/srs_core_source.hpp b/trunk/src/core/srs_core_source.hpp index 30f2cfa6f..9b14002de 100755 --- a/trunk/src/core/srs_core_source.hpp +++ b/trunk/src/core/srs_core_source.hpp @@ -134,6 +134,7 @@ public: virtual int create_consumer(SrsConsumer*& consumer); virtual void on_consumer_destroy(SrsConsumer* consumer); virtual void on_unpublish(); + virtual void set_cache(bool enabled); private: /** * only for h264 codec diff --git a/trunk/src/srs/srs.upp b/trunk/src/srs/srs.upp index a9120396b..887601492 100755 --- a/trunk/src/srs/srs.upp +++ b/trunk/src/srs/srs.upp @@ -12,6 +12,8 @@ file ..\core\srs_core_server.cpp, ..\core\srs_core_config.hpp, ..\core\srs_core_config.cpp, + ..\core\srs_core_refer.hpp, + ..\core\srs_core_refer.cpp, ..\core\srs_core_conn.hpp, ..\core\srs_core_conn.cpp, ..\core\srs_core_client.hpp,