diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp old mode 100644 new mode 100755 index 285bb37a8..3589b6461 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1,3407 +1,3433 @@ -/* -The MIT License (MIT) - -Copyright (c) 2013-2014 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 -#include -#include -// file operations. -#include -#include -#include -#include - -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include - -using namespace _srs_internal; - -#define SRS_WIKI_URL_LOG "https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_SrsLog" - -// '\n' -#define __LF (char)0x0a - -// '\r' -#define __CR (char)0x0d - -bool is_common_space(char ch) -{ - return (ch == ' ' || ch == '\t' || ch == __CR || ch == __LF); -} - -SrsConfDirective::SrsConfDirective() -{ -} - -SrsConfDirective::~SrsConfDirective() -{ - std::vector::iterator it; - for (it = directives.begin(); it != directives.end(); ++it) { - SrsConfDirective* directive = *it; - srs_freep(directive); - } - directives.clear(); -} - -string SrsConfDirective::arg0() -{ - if (args.size() > 0) { - return args.at(0); - } - - return ""; -} - -string SrsConfDirective::arg1() -{ - if (args.size() > 1) { - return args.at(1); - } - - return ""; -} - -string SrsConfDirective::arg2() -{ - if (args.size() > 2) { - return args.at(2); - } - - return ""; -} - -SrsConfDirective* SrsConfDirective::at(int index) -{ - srs_assert(index < (int)directives.size()); - return directives.at(index); -} - -SrsConfDirective* SrsConfDirective::get(string _name) -{ - std::vector::iterator it; - for (it = directives.begin(); it != directives.end(); ++it) { - SrsConfDirective* directive = *it; - if (directive->name == _name) { - return directive; - } - } - - return NULL; -} - -SrsConfDirective* SrsConfDirective::get(string _name, string _arg0) -{ - std::vector::iterator it; - for (it = directives.begin(); it != directives.end(); ++it) { - SrsConfDirective* directive = *it; - if (directive->name == _name && directive->arg0() == _arg0) { - return directive; - } - } - - return NULL; -} - -bool SrsConfDirective::is_vhost() -{ - return name == "vhost"; -} - -int SrsConfDirective::parse(SrsConfigBuffer* buffer) -{ - return parse_conf(buffer, parse_file); -} - -// see: ngx_conf_parse -int SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type) -{ - int ret = ERROR_SUCCESS; - - while (true) { - std::vector args; - int line_start = 0; - ret = read_token(buffer, args, line_start); - - /** - * ret maybe: - * ERROR_SYSTEM_CONFIG_INVALID error. - * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found - * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found - * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found - * ERROR_SYSTEM_CONFIG_EOF the config file is done - */ - if (ret == ERROR_SYSTEM_CONFIG_INVALID) { - return ret; - } - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) { - if (type != parse_block) { - srs_error("line %d: unexpected \"}\", ret=%d", buffer->line, ret); - return ret; - } - return ERROR_SUCCESS; - } - if (ret == ERROR_SYSTEM_CONFIG_EOF) { - if (type == parse_block) { - srs_error("line %d: unexpected end of file, expecting \"}\", ret=%d", conf_line, ret); - return ret; - } - return ERROR_SUCCESS; - } - - if (args.empty()) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("line %d: empty directive. ret=%d", conf_line, ret); - return ret; - } - - // build directive tree. - SrsConfDirective* directive = new SrsConfDirective(); - - directive->conf_line = line_start; - directive->name = args[0]; - args.erase(args.begin()); - directive->args.swap(args); - - directives.push_back(directive); - - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) { - if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) { - return ret; - } - } - } - - return ret; -} - -// see: ngx_conf_read_token -int SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector& args, int& line_start) -{ - int ret = ERROR_SUCCESS; - - char* pstart = buffer->pos; - - bool sharp_comment = false; - - bool d_quoted = false; - bool s_quoted = false; - - bool need_space = false; - bool last_space = true; - - while (true) { - if (buffer->empty()) { - ret = ERROR_SYSTEM_CONFIG_EOF; - - if (!args.empty() || !last_space) { - srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line); - return ERROR_SYSTEM_CONFIG_INVALID; - } - srs_trace("config parse complete"); - - return ret; - } - - char ch = *buffer->pos++; - - if (ch == __LF) { - buffer->line++; - sharp_comment = false; - } - - if (sharp_comment) { - continue; - } - - if (need_space) { - if (is_common_space(ch)) { - last_space = true; - need_space = false; - continue; - } - if (ch == ';') { - return ERROR_SYSTEM_CONFIG_DIRECTIVE; - } - if (ch == '{') { - return ERROR_SYSTEM_CONFIG_BLOCK_START; - } - srs_error("line %d: unexpected '%c'", buffer->line, ch); - return ERROR_SYSTEM_CONFIG_INVALID; - } - - // last charecter is space. - if (last_space) { - if (is_common_space(ch)) { - continue; - } - pstart = buffer->pos - 1; - switch (ch) { - case ';': - if (args.size() == 0) { - srs_error("line %d: unexpected ';'", buffer->line); - return ERROR_SYSTEM_CONFIG_INVALID; - } - return ERROR_SYSTEM_CONFIG_DIRECTIVE; - case '{': - if (args.size() == 0) { - srs_error("line %d: unexpected '{'", buffer->line); - return ERROR_SYSTEM_CONFIG_INVALID; - } - return ERROR_SYSTEM_CONFIG_BLOCK_START; - case '}': - if (args.size() != 0) { - srs_error("line %d: unexpected '}'", buffer->line); - return ERROR_SYSTEM_CONFIG_INVALID; - } - return ERROR_SYSTEM_CONFIG_BLOCK_END; - case '#': - sharp_comment = 1; - continue; - case '"': - pstart++; - d_quoted = true; - last_space = 0; - continue; - case '\'': - pstart++; - s_quoted = true; - last_space = 0; - continue; - default: - last_space = 0; - continue; - } - } else { - // last charecter is not space - if (line_start == 0) { - line_start = buffer->line; - } - - bool found = false; - if (d_quoted) { - if (ch == '"') { - d_quoted = false; - need_space = true; - found = true; - } - } else if (s_quoted) { - if (ch == '\'') { - s_quoted = false; - need_space = true; - found = true; - } - } else if (is_common_space(ch) || ch == ';' || ch == '{') { - last_space = true; - found = 1; - } - - if (found) { - int len = buffer->pos - pstart; - char* aword = new char[len]; - memcpy(aword, pstart, len); - aword[len - 1] = 0; - - string word_str = aword; - if (!word_str.empty()) { - args.push_back(word_str); - } - srs_freep(aword); - - if (ch == ';') { - return ERROR_SYSTEM_CONFIG_DIRECTIVE; - } - if (ch == '{') { - return ERROR_SYSTEM_CONFIG_BLOCK_START; - } - } - } - } - - return ret; -} - -SrsConfig::SrsConfig() -{ - show_help = false; - show_version = false; - test_conf = false; - - root = new SrsConfDirective(); - root->conf_line = 0; - root->name = "root"; -} - -SrsConfig::~SrsConfig() -{ - srs_freep(root); -} - -void SrsConfig::subscribe(ISrsReloadHandler* handler) -{ - std::vector::iterator it; - - it = std::find(subscribes.begin(), subscribes.end(), handler); - if (it != subscribes.end()) { - return; - } - - subscribes.push_back(handler); -} - -void SrsConfig::unsubscribe(ISrsReloadHandler* handler) -{ - std::vector::iterator it; - - it = std::find(subscribes.begin(), subscribes.end(), handler); - if (it == subscribes.end()) { - return; - } - - subscribes.erase(it); -} - -int SrsConfig::reload() -{ - int ret = ERROR_SUCCESS; - - SrsConfig conf; - - if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) { - srs_error("ignore config reloader parse file failed. ret=%d", ret); - ret = ERROR_SUCCESS; - return ret; - } - srs_info("config reloader parse file success."); - - if ((ret = conf.check_config()) != ERROR_SUCCESS) { - srs_error("ignore config reloader check config failed. ret=%d", ret); - ret = ERROR_SUCCESS; - return ret; - } - - return reload_conf(&conf); -} - -int SrsConfig::reload_conf(SrsConfig* conf) -{ - int ret = ERROR_SUCCESS; - - SrsConfDirective* old_root = root; - SrsAutoFree(SrsConfDirective, old_root); - - root = conf->root; - conf->root = NULL; - - // merge config. - std::vector::iterator it; - - // never support reload: - // daemon - // - // always support reload without additional code: - // chunk_size, ff_log_dir, max_connections, - // bandcheck, http_hooks, heartbeat, - // token_traverse, debug_srs_upnode - - // merge config: listen - if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload listen failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload listen success."); - } - - // merge config: pid - if (!srs_directive_equals(root->get("pid"), old_root->get("pid"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_pid()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload pid failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload pid success."); - } - - // merge config: srs_log_tank - if (!srs_directive_equals(root->get("srs_log_tank"), old_root->get("srs_log_tank"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_tank()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_tank failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload srs_log_tank success."); - } - - // merge config: srs_log_level - if (!srs_directive_equals(root->get("srs_log_level"), old_root->get("srs_log_level"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_level()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_level failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload srs_log_level success."); - } - - // merge config: srs_log_file - if (!srs_directive_equals(root->get("srs_log_file"), old_root->get("srs_log_file"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_file()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_file failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload srs_log_file success."); - } - - // merge config: pithy_print - if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) { - srs_error("notify subscribes pithy_print listen failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload pithy_print success."); - } - - // merge config: http_api - if ((ret = reload_http_api(old_root)) != ERROR_SUCCESS) { - return ret; - } - - // merge config: http_stream - if ((ret = reload_http_stream(old_root)) != ERROR_SUCCESS) { - return ret; - } - - // merge config: vhost - if ((ret = reload_vhost(old_root)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -int SrsConfig::reload_http_api(SrsConfDirective* old_root) -{ - int ret = ERROR_SUCCESS; - - // merge config. - std::vector::iterator it; - - // state graph - // old_http_api new_http_api - // DISABLED => ENABLED - // ENABLED => DISABLED - // ENABLED => ENABLED (modified) - - SrsConfDirective* new_http_api = root->get("http_api"); - SrsConfDirective* old_http_api = old_root->get("http_api"); - - // DISABLED => ENABLED - if (!get_http_api_enabled(old_http_api) && get_http_api_enabled(new_http_api)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_api_enabled()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_api disabled=>enabled failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload disabled=>enabled http_api success."); - - return ret; - } - - // ENABLED => DISABLED - if (get_http_api_enabled(old_http_api) && !get_http_api_enabled(new_http_api)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_api_disabled()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_api enabled=>disabled failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload enabled=>disabled http_api success."); - - return ret; - } - - // ENABLED => ENABLED (modified) - if (get_http_api_enabled(old_http_api) && get_http_api_enabled(new_http_api) - && !srs_directive_equals(old_http_api, new_http_api) - ) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_api_enabled()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_api enabled modified failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload enabled modified http_api success."); - - return ret; - } - - srs_trace("reload http_api not changed success."); - - return ret; -} - -int SrsConfig::reload_http_stream(SrsConfDirective* old_root) -{ - int ret = ERROR_SUCCESS; - - // merge config. - std::vector::iterator it; - - // state graph - // old_http_stream new_http_stream - // DISABLED => ENABLED - // ENABLED => DISABLED - // ENABLED => ENABLED (modified) - - SrsConfDirective* new_http_stream = root->get("http_stream"); - SrsConfDirective* old_http_stream = old_root->get("http_stream"); - - // DISABLED => ENABLED - if (!get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_stream_enabled()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_stream disabled=>enabled failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload disabled=>enabled http_stream success."); - - return ret; - } - - // ENABLED => DISABLED - if (get_http_stream_enabled(old_http_stream) && !get_http_stream_enabled(new_http_stream)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_stream_disabled()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_stream enabled=>disabled failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload enabled=>disabled http_stream success."); - - return ret; - } - - // ENABLED => ENABLED (modified) - if (get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream) - && !srs_directive_equals(old_http_stream, new_http_stream) - ) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_http_stream_updated()) != ERROR_SUCCESS) { - srs_error("notify subscribes http_stream enabled modified failed. ret=%d", ret); - return ret; - } - } - srs_trace("reload enabled modified http_stream success."); - - return ret; - } - - srs_trace("reload http_stream not changed success."); - - return ret; -} - -int SrsConfig::reload_vhost(SrsConfDirective* old_root) -{ - int ret = ERROR_SUCCESS; - - // merge config. - std::vector::iterator it; - - // state graph - // old_vhost new_vhost - // DISABLED => ENABLED - // ENABLED => DISABLED - // ENABLED => ENABLED (modified) - - // collect all vhost names - std::vector vhosts; - for (int i = 0; i < (int)root->directives.size(); i++) { - SrsConfDirective* vhost = root->at(i); - if (vhost->name != "vhost") { - continue; - } - vhosts.push_back(vhost->arg0()); - } - for (int i = 0; i < (int)old_root->directives.size(); i++) { - SrsConfDirective* vhost = old_root->at(i); - if (vhost->name != "vhost") { - continue; - } - if (root->get("vhost", vhost->arg0())) { - continue; - } - vhosts.push_back(vhost->arg0()); - } - - // process each vhost - for (int i = 0; i < (int)vhosts.size(); i++) { - std::string vhost = vhosts.at(i); - - SrsConfDirective* old_vhost = old_root->get("vhost", vhost); - SrsConfDirective* new_vhost = root->get("vhost", vhost); - - // DISABLED => ENABLED - if (!get_vhost_enabled(old_vhost) && get_vhost_enabled(new_vhost)) { - srs_trace("vhost %s added, reload it.", vhost.c_str()); - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_added(vhost)) != ERROR_SUCCESS) { - srs_error("notify subscribes added " - "vhost %s failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("reload new vhost %s success.", vhost.c_str()); - continue; - } - - // ENABLED => DISABLED - if (get_vhost_enabled(old_vhost) && !get_vhost_enabled(new_vhost)) { - srs_trace("vhost %s removed, reload it.", vhost.c_str()); - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_removed(vhost)) != ERROR_SUCCESS) { - srs_error("notify subscribes removed " - "vhost %s failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("reload removed vhost %s success.", vhost.c_str()); - continue; - } - - // mode, never supports reload. - // first, for the origin and edge role change is too complex. - // second, the vhosts in origin device group normally are all origin, - // they never change to edge sometimes. - // third, the origin or upnode device can always be restart, - // edge will retry and the users connected to edge are ok. - // it's ok to add or remove edge/origin vhost. - if (get_vhost_is_edge(old_vhost) != get_vhost_is_edge(new_vhost)) { - ret = ERROR_RTMP_EDGE_RELOAD; - srs_error("reload never supports mode changed. ret=%d", ret); - return ret; - } - - // ENABLED => ENABLED (modified) - if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) { - srs_trace("vhost %s maybe modified, reload its detail.", vhost.c_str()); - // atc, only one per vhost - if (!srs_directive_equals(new_vhost->get("atc"), old_vhost->get("atc"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_atc(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes atc failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload atc success.", vhost.c_str()); - } - // gop_cache, only one per vhost - if (!srs_directive_equals(new_vhost->get("gop_cache"), old_vhost->get("gop_cache"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_gop_cache(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes gop_cache failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload gop_cache success.", vhost.c_str()); - } - // queue_length, only one per vhost - if (!srs_directive_equals(new_vhost->get("queue_length"), old_vhost->get("queue_length"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_queue_length(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes queue_length failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload queue_length success.", vhost.c_str()); - } - // time_jitter, only one per vhost - if (!srs_directive_equals(new_vhost->get("time_jitter"), old_vhost->get("time_jitter"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_time_jitter(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes time_jitter failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload time_jitter success.", vhost.c_str()); - } - // forward, only one per vhost - if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_forward(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes forward failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload forward success.", vhost.c_str()); - } - // hls, only one per vhost - if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_hls(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes hls failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload hls success.", vhost.c_str()); - } - // dvr, only one per vhost - if (!srs_directive_equals(new_vhost->get("dvr"), old_vhost->get("dvr"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_dvr(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes dvr failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload hls success.", vhost.c_str()); - } - // http, only one per vhost. - if (!srs_directive_equals(new_vhost->get("http"), old_vhost->get("http"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_http_updated()) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes http failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload http success.", vhost.c_str()); - } - // transcode, many per vhost. - if ((ret = reload_transcode(new_vhost, old_vhost)) != ERROR_SUCCESS) { - return ret; - } - // ingest, many per vhost. - if ((ret = reload_ingest(new_vhost, old_vhost)) != ERROR_SUCCESS) { - return ret; - } - continue; - } - srs_trace("igreno reload vhost, enabled old: %d, new: %d", - get_vhost_enabled(old_vhost), get_vhost_enabled(new_vhost)); - } - - return ret; -} - -int SrsConfig::reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost) -{ - int ret = ERROR_SUCCESS; - - std::vector old_transcoders; - for (int i = 0; i < (int)old_vhost->directives.size(); i++) { - SrsConfDirective* conf = old_vhost->at(i); - if (conf->name == "transcode") { - old_transcoders.push_back(conf); - } - } - - std::vector new_transcoders; - for (int i = 0; i < (int)new_vhost->directives.size(); i++) { - SrsConfDirective* conf = new_vhost->at(i); - if (conf->name == "transcode") { - new_transcoders.push_back(conf); - } - } - - std::vector::iterator it; - - std::string vhost = new_vhost->arg0(); - - // to be simple: - // whatever, once tiny changed of transcode, - // restart all ffmpeg of vhost. - bool changed = false; - - // discovery the removed ffmpeg. - for (int i = 0; !changed && i < (int)old_transcoders.size(); i++) { - SrsConfDirective* old_transcoder = old_transcoders.at(i); - std::string transcoder_id = old_transcoder->arg0(); - - // if transcoder exists in new vhost, not removed, ignore. - if (new_vhost->get("transcode", transcoder_id)) { - continue; - } - - changed = true; - } - - // discovery the added ffmpeg. - for (int i = 0; !changed && i < (int)new_transcoders.size(); i++) { - SrsConfDirective* new_transcoder = new_transcoders.at(i); - std::string transcoder_id = new_transcoder->arg0(); - - // if transcoder exists in old vhost, not added, ignore. - if (old_vhost->get("transcode", transcoder_id)) { - continue; - } - - changed = true; - } - - // for updated transcoders, restart them. - for (int i = 0; !changed && i < (int)new_transcoders.size(); i++) { - SrsConfDirective* new_transcoder = new_transcoders.at(i); - std::string transcoder_id = new_transcoder->arg0(); - SrsConfDirective* old_transcoder = old_vhost->get("transcode", transcoder_id); - srs_assert(old_transcoder); - - if (srs_directive_equals(new_transcoder, old_transcoder)) { - continue; - } - - changed = true; - } - - // transcode, many per vhost - if (changed) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_vhost_transcode(vhost)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes transcode failed. ret=%d", vhost.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload transcode success.", vhost.c_str()); - } - - return ret; -} - -int SrsConfig::reload_ingest(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost) -{ - int ret = ERROR_SUCCESS; - - std::vector old_ingesters; - for (int i = 0; i < (int)old_vhost->directives.size(); i++) { - SrsConfDirective* conf = old_vhost->at(i); - if (conf->name == "ingest") { - old_ingesters.push_back(conf); - } - } - - std::vector new_ingesters; - for (int i = 0; i < (int)new_vhost->directives.size(); i++) { - SrsConfDirective* conf = new_vhost->at(i); - if (conf->name == "ingest") { - new_ingesters.push_back(conf); - } - } - - std::vector::iterator it; - - std::string vhost = new_vhost->arg0(); - - // for removed ingesters, stop them. - for (int i = 0; i < (int)old_ingesters.size(); i++) { - SrsConfDirective* old_ingester = old_ingesters.at(i); - std::string ingest_id = old_ingester->arg0(); - SrsConfDirective* new_ingester = new_vhost->get("ingest", ingest_id); - - // ENABLED => DISABLED - if (get_ingest_enabled(old_ingester) && !get_ingest_enabled(new_ingester)) { - // notice handler ingester removed. - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_ingest_removed(vhost, ingest_id)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes ingest=%s removed failed. ret=%d", - vhost.c_str(), ingest_id.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload ingest=%s removed success.", vhost.c_str(), ingest_id.c_str()); - } - } - - // for added ingesters, start them. - for (int i = 0; i < (int)new_ingesters.size(); i++) { - SrsConfDirective* new_ingester = new_ingesters.at(i); - std::string ingest_id = new_ingester->arg0(); - SrsConfDirective* old_ingester = old_vhost->get("ingest", ingest_id); - - // DISABLED => ENABLED - if (!get_ingest_enabled(old_ingester) && get_ingest_enabled(new_ingester)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_ingest_added(vhost, ingest_id)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes ingest=%s added failed. ret=%d", - vhost.c_str(), ingest_id.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload ingest=%s added success.", vhost.c_str(), ingest_id.c_str()); - } - } - - // for updated ingesters, restart them. - for (int i = 0; i < (int)new_ingesters.size(); i++) { - SrsConfDirective* new_ingester = new_ingesters.at(i); - std::string ingest_id = new_ingester->arg0(); - SrsConfDirective* old_ingester = old_vhost->get("ingest", ingest_id); - - // ENABLED => ENABLED - if (get_ingest_enabled(old_ingester) && get_ingest_enabled(new_ingester)) { - if (srs_directive_equals(new_ingester, old_ingester)) { - continue; - } - - // notice handler ingester removed. - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_ingest_updated(vhost, ingest_id)) != ERROR_SUCCESS) { - srs_error("vhost %s notify subscribes ingest=%s updated failed. ret=%d", - vhost.c_str(), ingest_id.c_str(), ret); - return ret; - } - } - srs_trace("vhost %s reload ingest=%s updated success.", vhost.c_str(), ingest_id.c_str()); - } - } - - srs_trace("ingest not changed for vhost=%s", vhost.c_str()); - - return ret; -} - -// see: ngx_get_options -int SrsConfig::parse_options(int argc, char** argv) -{ - int ret = ERROR_SUCCESS; - - // argv - for (int i = 0; i < argc; i++) { - _argv.append(argv[i]); - - if (i < argc - 1) { - _argv.append(" "); - } - } - - // cwd - char cwd[256]; - getcwd(cwd, sizeof(cwd)); - _cwd = cwd; - - // config - show_help = true; - for (int i = 1; i < argc; i++) { - if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) { - return ret; - } - } - - if (show_help) { - print_help(argv); - exit(0); - } - - if (show_version) { - fprintf(stderr, "%s\n", RTMP_SIG_SRS_VERSION); - exit(0); - } - - if (config_file.empty()) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret); - return ret; - } - - ret = parse_file(config_file.c_str()); - - if (test_conf) { - // the parse_file never check the config, - // we check it when user requires check config file. - if (ret == ERROR_SUCCESS) { - ret = check_config(); - } - - if (ret == ERROR_SUCCESS) { - srs_trace("config file is ok"); - exit(0); - } else { - srs_error("config file is invalid"); - exit(ret); - } - } - - //////////////////////////////////////////////////////////////////////// - // check log name and level - //////////////////////////////////////////////////////////////////////// - if (true) { - std::string log_filename = this->get_log_file(); - if (get_log_tank_file() && log_filename.empty()) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("must specifies the file to write log to. ret=%d", ret); - return ret; - } - if (get_log_tank_file()) { - srs_trace("write log to file %s", log_filename.c_str()); - srs_trace("you can: tailf %s", log_filename.c_str()); - srs_trace("@see: %s", SRS_WIKI_URL_LOG); - } else { - srs_trace("write log to console"); - } - } - - return ret; -} - -string SrsConfig::config() -{ - return config_file; -} - -int SrsConfig::parse_argv(int& i, char** argv) -{ - int ret = ERROR_SUCCESS; - - char* p = argv[i]; - - if (*p++ != '-') { - show_help = true; - return ret; - } - - while (*p) { - switch (*p++) { - case '?': - case 'h': - show_help = true; - break; - case 't': - show_help = false; - test_conf = true; - break; - case 'v': - case 'V': - show_help = false; - show_version = true; - break; - case 'c': - show_help = false; - if (*p) { - config_file = p; - return ret; - } - if (argv[++i]) { - config_file = argv[i]; - return ret; - } - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("option \"-c\" requires parameter, ret=%d", ret); - return ret; - default: - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret); - return ret; - } - } - - return ret; -} - -void SrsConfig::print_help(char** argv) -{ - printf( - RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION" "RTMP_SIG_SRS_COPYRIGHT"\n" - "License: "RTMP_SIG_SRS_LICENSE"\n" - "Primary Authors: "RTMP_SIG_SRS_PRIMARY_AUTHROS"\n" - "Build: "SRS_AUTO_BUILD_DATE" Configuration:"SRS_AUTO_USER_CONFIGURE"\n" - "Features:"SRS_AUTO_CONFIGURE"\n""\n" - "Usage: %s [-h?vV] [[-t] -c ]\n" - "\n" - "Options:\n" - " -?, -h : show this help and exit(0)\n" - " -v, -V : show version and exit(0)\n" - " -t : test configuration file, exit(error_code).\n" - " -c filename : use configuration file for SRS\n" - "\n" - RTMP_SIG_SRS_WEB"\n" - RTMP_SIG_SRS_URL"\n" - "Email: "RTMP_SIG_SRS_EMAIL"\n" - "\n" - "For example:\n" - " %s -v\n" - " %s -t -c "SRS_CONF_DEFAULT_COFNIG_FILE"\n" - " %s -c "SRS_CONF_DEFAULT_COFNIG_FILE"\n", - argv[0], argv[0], argv[0], argv[0]); -} - -int SrsConfig::parse_file(const char* filename) -{ - int ret = ERROR_SUCCESS; - - config_file = filename; - - if (config_file.empty()) { - return ERROR_SYSTEM_CONFIG_INVALID; - } - - SrsConfigBuffer buffer; - - if ((ret = buffer.fullfill(config_file.c_str())) != ERROR_SUCCESS) { - return ret; - } - - return parse_buffer(&buffer); -} - -int SrsConfig::check_config() -{ - int ret = ERROR_SUCCESS; - - srs_trace("srs checking config..."); - - vector vhosts = get_vhosts(); - - //////////////////////////////////////////////////////////////////////// - // check empty - //////////////////////////////////////////////////////////////////////// - if (root->directives.size() == 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("conf is empty, ret=%d", ret); - return ret; - } - - //////////////////////////////////////////////////////////////////////// - // check root directives. - //////////////////////////////////////////////////////////////////////// - for (int i = 0; i < (int)root->directives.size(); i++) { - SrsConfDirective* conf = root->at(i); - std::string n = conf->name; - if (n != "listen" && n != "pid" && n != "chunk_size" && n != "ff_log_dir" - && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" - && n != "max_connections" && n != "daemon" && n != "heartbeat" - && n != "http_api" && n != "http_stream" && n != "stats" && n != "vhost" - && n != "pithy_print") - { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - if (true) { - SrsConfDirective* conf = get_http_api(); - for (int i = 0; conf && i < (int)conf->directives.size(); i++) { - string n = conf->at(i)->name; - if (n != "enabled" && n != "listen") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - } - if (true) { - SrsConfDirective* conf = get_http_stream(); - for (int i = 0; conf && i < (int)conf->directives.size(); i++) { - string n = conf->at(i)->name; - if (n != "enabled" && n != "listen" && n != "dir") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported http_stream directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - } - if (true) { - SrsConfDirective* conf = get_heartbeart(); - for (int i = 0; conf && i < (int)conf->directives.size(); i++) { - string n = conf->at(i)->name; - if (n != "enabled" && n != "interval" && n != "url" - && n != "device_id" && n != "summaries" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported heartbeat directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - } - if (true) { - SrsConfDirective* conf = get_stats(); - for (int i = 0; conf && i < (int)conf->directives.size(); i++) { - string n = conf->at(i)->name; - if (n != "network" && n != "disk") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported stats directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - } - if (true) { - SrsConfDirective* conf = get_pithy_print(); - for (int i = 0; conf && i < (int)conf->directives.size(); i++) { - string n = conf->at(i)->name; - if (n != "publish" && n != "play" && n != "forwarder" - && n != "encoder" && n != "ingester" && n != "hls" && n != "edge" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported pithy_print directive %s, ret=%d", n.c_str(), ret); - return ret; - } - } - } - for (int n = 0; n < (int)vhosts.size(); n++) { - SrsConfDirective* vhost = vhosts[n]; - for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) { - SrsConfDirective* conf = vhost->at(i); - string n = conf->name; - if (n != "enabled" && n != "chunk_size" - && n != "mode" && n != "origin" && n != "token_traverse" - && n != "dvr" && n != "ingest" && n != "http" && n != "hls" && n != "http_hooks" - && n != "gop_cache" && n != "queue_length" - && n != "refer" && n != "refer_publish" && n != "refer_play" - && n != "forward" && n != "transcode" && n != "bandcheck" - && n != "time_jitter" - && n != "atc" && n != "atc_auto" - && n != "debug_srs_upnode" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret); - return ret; - } - // for each sub directives of vhost. - if (n == "dvr") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "dvr_path" && m != "dvr_plan" - && m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } else if (n == "ingest") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "input" && m != "ffmpeg" - && m != "engine" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } else if (n == "http") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "mount" && m != "dir") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } else if (n == "hls") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "hls_path" && m != "hls_fragment" && m != "hls_window") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } else if (n == "http_hooks") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" - && m != "on_unpublish" && m != "on_play" && m != "on_stop" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } else if (n == "forward") { - // TODO: FIXME: implements it. - /*for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "vhost" && m != "refer") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret); - return ret; - } - }*/ - } else if (n == "transcode") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - SrsConfDirective* trans = conf->at(j); - string m = trans->name.c_str(); - if (m != "enabled" && m != "ffmpeg" && m != "engine") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost transcode directive %s, ret=%d", m.c_str(), ret); - return ret; - } - if (m == "engine") { - for (int k = 0; k < (int)trans->directives.size(); k++) { - string e = trans->at(k)->name; - if (e != "enabled" && e != "vfilter" && e != "vcodec" - && e != "vbitrate" && e != "vfps" && e != "vwidth" && e != "vheight" - && e != "vthreads" && e != "vprofile" && e != "vpreset" && e != "vparams" - && e != "acodec" && e != "abitrate" && e != "asample_rate" && e != "achannels" - && e != "aparams" && e != "output" - && e != "iformat" && e != "oformat" - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost transcode engine directive %s, ret=%d", e.c_str(), ret); - return ret; - } - } - } - } - } else if (n == "bandcheck") { - for (int j = 0; j < (int)conf->directives.size(); j++) { - string m = conf->at(j)->name.c_str(); - if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret); - return ret; - } - } - } - } - } - // check ingest id unique. - for (int i = 0; i < (int)vhosts.size(); i++) { - SrsConfDirective* vhost = vhosts[i]; - std::vector ids; - - for (int j = 0; j < (int)vhost->directives.size(); j++) { - SrsConfDirective* conf = vhost->at(j); - if (conf->name != "ingest") { - continue; - } - - std::string id = conf->arg0(); - for (int k = 0; k < (int)ids.size(); k++) { - if (id == ids.at(k)) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive \"ingest\" id duplicated, vhost=%s, id=%s, ret=%d", - vhost->name.c_str(), id.c_str(), ret); - return ret; - } - } - ids.push_back(id); - } - } - - //////////////////////////////////////////////////////////////////////// - // check listen for rtmp. - //////////////////////////////////////////////////////////////////////// - if (true) { - vector listens = get_listen(); - if (listens.size() <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive \"listen\" is empty, ret=%d", ret); - return ret; - } - for (int i = 0; i < (int)listens.size(); i++) { - string port = listens[i]; - if (port.empty() || ::atoi(port.c_str()) <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive listen invalid, port=%s, ret=%d", port.c_str(), ret); - return ret; - } - } - } - - //////////////////////////////////////////////////////////////////////// - // check max connections - //////////////////////////////////////////////////////////////////////// - if (get_max_connections() <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive max_connections invalid, max_connections=%d, ret=%d", get_max_connections(), ret); - return ret; - } - - // check max connections of system limits - if (true) { - int max_open_files = sysconf(_SC_OPEN_MAX); - if (get_max_connections() > max_open_files) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("invalid max_connections=%d, system limit to %d, ret=%d. " - "you can login as root and set the limit: ulimit -HSn %d", get_max_connections(), max_open_files, - ret, get_max_connections()); - return ret; - } - } - - //////////////////////////////////////////////////////////////////////// - // check heartbeat - //////////////////////////////////////////////////////////////////////// - if (get_heartbeat_interval() <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive heartbeat interval invalid, interval=%"PRId64", ret=%d", - get_heartbeat_interval(), ret); - return ret; - } - - //////////////////////////////////////////////////////////////////////// - // check stats - //////////////////////////////////////////////////////////////////////// - if (get_stats_network() < 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive stats network invalid, network=%d, ret=%d", - get_stats_network(), ret); - return ret; - } - if (true) { - vector ips = srs_get_local_ipv4_ips(); - int index = get_stats_network(); - if (index >= (int)ips.size()) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("stats network invalid, total local ip count=%d, index=%d, ret=%d", - (int)ips.size(), index, ret); - return ret; - } - srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str()); - } - if (true) { - SrsConfDirective* conf = get_stats_disk_device(); - if (conf == NULL || (int)conf->args.size() <= 0) { - srs_warn("stats disk not configed, disk iops disabled."); - } else { - string disks; - for (int i = 0; i < (int)conf->args.size(); i++) { - disks += conf->args.at(i); - disks += " "; - } - srs_warn("stats disk list: %s", disks.c_str()); - } - } - - //////////////////////////////////////////////////////////////////////// - // check http api - //////////////////////////////////////////////////////////////////////// - if (get_http_api_listen() <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive http_api listen invalid, listen=%d, ret=%d", - get_http_api_listen(), ret); - return ret; - } - - //////////////////////////////////////////////////////////////////////// - // check http stream - //////////////////////////////////////////////////////////////////////// - if (get_http_stream_listen() <= 0) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive http_stream listen invalid, listen=%d, ret=%d", - get_http_stream_listen(), ret); - return ret; - } - - //////////////////////////////////////////////////////////////////////// - // check chunk size - //////////////////////////////////////////////////////////////////////// - if (get_global_chunk_size() < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE - || get_global_chunk_size() > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", - get_global_chunk_size(), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, - SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret); - return ret; - } - for (int i = 0; i < (int)vhosts.size(); i++) { - SrsConfDirective* vhost = vhosts[i]; - if (get_chunk_size(vhost->arg0()) < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE - || get_chunk_size(vhost->arg0()) > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE - ) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("directive vhost %s chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", - vhost->arg0().c_str(), get_chunk_size(vhost->arg0()), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, - SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret); - return ret; - } - } - - //////////////////////////////////////////////////////////////////////// - // check log name and level - //////////////////////////////////////////////////////////////////////// - if (true) { - std::string log_filename = this->get_log_file(); - if (get_log_tank_file() && log_filename.empty()) { - ret = ERROR_SYSTEM_CONFIG_INVALID; - srs_error("must specifies the file to write log to. ret=%d", ret); - return ret; - } - if (get_log_tank_file()) { - srs_trace("write log to file %s", log_filename.c_str()); - srs_trace("you can: tailf %s", log_filename.c_str()); - srs_trace("@see: %s", SRS_WIKI_URL_LOG); - } else { - srs_trace("write log to console"); - } - } - - //////////////////////////////////////////////////////////////////////// - // check features - //////////////////////////////////////////////////////////////////////// -#ifndef SRS_AUTO_HTTP_SERVER - if (get_http_stream_enabled()) { - srs_warn("http_stream is disabled by configure"); - } -#endif -#ifndef SRS_AUTO_HTTP_API - if (get_http_api_enabled()) { - srs_warn("http_api is disabled by configure"); - } -#endif - for (int i = 0; i < (int)vhosts.size(); i++) { - SrsConfDirective* vhost = vhosts[i]; - srs_assert(vhost != NULL); -#ifndef SRS_AUTO_DVR - if (get_dvr_enabled(vhost->arg0())) { - srs_warn("dvr of vhost %s is disabled by configure", vhost->arg0().c_str()); - } -#endif -#ifndef SRS_AUTO_HLS - if (get_hls_enabled(vhost->arg0())) { - srs_warn("hls of vhost %s is disabled by configure", vhost->arg0().c_str()); - } -#endif -#ifndef SRS_AUTO_HTTP_CALLBACK - if (get_vhost_http_hooks_enabled(vhost->arg0())) { - srs_warn("http_hooks of vhost %s is disabled by configure", vhost->arg0().c_str()); - } -#endif -#ifndef SRS_AUTO_TRANSCODE - if (get_transcode_enabled(get_transcode(vhost->arg0(), ""))) { - srs_warn("transcode of vhost %s is disabled by configure", vhost->arg0().c_str()); - } -#endif -#ifndef SRS_AUTO_INGEST - vector ingesters = get_ingesters(vhost->arg0()); - for (int j = 0; j < (int)ingesters.size(); j++) { - SrsConfDirective* ingest = ingesters[j]; - if (get_ingest_enabled(ingest)) { - srs_warn("ingest %s of vhost %s is disabled by configure", - ingest->arg0().c_str(), vhost->arg0().c_str() - ); - } - } -#endif - } - - return ret; -} - -int SrsConfig::parse_buffer(SrsConfigBuffer* buffer) -{ - int ret = ERROR_SUCCESS; - - if ((ret = root->parse(buffer)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -string SrsConfig::cwd() -{ - return _cwd; -} - -string SrsConfig::argv() -{ - return _argv; -} - -bool SrsConfig::get_deamon() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("daemon"); - if (conf && conf->arg0() == "off") { - return false; - } - - return true; -} - -SrsConfDirective* SrsConfig::get_root() -{ - return root; -} - -int SrsConfig::get_max_connections() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("max_connections"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_MAX_CONNECTIONS; - } - - return ::atoi(conf->arg0().c_str()); -} - -vector SrsConfig::get_listen() -{ - std::vector ports; - - SrsConfDirective* conf = root->get("listen"); - if (!conf) { - return ports; - } - - for (int i = 0; i < (int)conf->args.size(); i++) { - ports.push_back(conf->args.at(i)); - } - - return ports; -} - -string SrsConfig::get_pid_file() -{ - SrsConfDirective* conf = root->get("pid"); - - if (!conf) { - return SRS_CONF_DEFAULT_PID_FILE; - } - - return conf->arg0(); -} - -SrsConfDirective* SrsConfig::get_pithy_print() -{ - return root->get("pithy_print"); -} - -int SrsConfig::get_pithy_print_publish() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_PUBLISH_USER_INTERVAL_MS; - } - - pithy = pithy->get("publish"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_PUBLISH_USER_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_forwarder() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_FORWARDER_INTERVAL_MS; - } - - pithy = pithy->get("forwarder"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_FORWARDER_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_encoder() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_ENCODER_INTERVAL_MS; - } - - pithy = pithy->get("encoder"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_ENCODER_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_ingester() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_INGESTER_INTERVAL_MS; - } - - pithy = pithy->get("ingester"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_INGESTER_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_hls() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_HLS_INTERVAL_MS; - } - - pithy = pithy->get("hls"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_HLS_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_play() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS; - } - - pithy = pithy->get("play"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -int SrsConfig::get_pithy_print_edge() -{ - SrsConfDirective* pithy = get_pithy_print(); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_EDGE_INTERVAL_MS; - } - - pithy = pithy->get("edge"); - if (!pithy) { - return SRS_CONF_DEFAULT_STAGE_EDGE_INTERVAL_MS; - } - - return ::atoi(pithy->arg0().c_str()); -} - -SrsConfDirective* SrsConfig::get_vhost(string vhost) -{ - srs_assert(root); - - for (int i = 0; i < (int)root->directives.size(); i++) { - SrsConfDirective* conf = root->at(i); - - if (!conf->is_vhost()) { - continue; - } - - if (conf->arg0() == vhost) { - return conf; - } - } - - if (vhost != SRS_CONSTS_RTMP_DEFAULT_VHOST) { - return get_vhost(SRS_CONSTS_RTMP_DEFAULT_VHOST); - } - - return NULL; -} - -vector SrsConfig::get_vhosts() -{ - srs_assert(root); - - std::vector vhosts; - - for (int i = 0; i < (int)root->directives.size(); i++) { - SrsConfDirective* conf = root->at(i); - - if (!conf->is_vhost()) { - continue; - } - - vhosts.push_back(conf); - } - - return vhosts; -} - -bool SrsConfig::get_vhost_enabled(string vhost) -{ - SrsConfDirective* vhost_conf = get_vhost(vhost); - - return get_vhost_enabled(vhost_conf); -} - -bool SrsConfig::get_vhost_enabled(SrsConfDirective* vhost) -{ - if (!vhost) { - return false; - } - - SrsConfDirective* conf = vhost->get("enabled"); - if (!conf) { - return true; - } - - if (conf->arg0() == "off") { - return false; - } - - return true; -} - -bool SrsConfig::get_gop_cache(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return true; - } - - conf = conf->get("gop_cache"); - if (conf && conf->arg0() == "off") { - return false; - } - - return true; -} - -bool SrsConfig::get_debug_srs_upnode(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return true; - } - - conf = conf->get("debug_srs_upnode"); - if (conf && conf->arg0() == "off") { - return false; - } - - return true; -} - -bool SrsConfig::get_atc(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return false; - } - - conf = conf->get("atc"); - if (conf && conf->arg0() == "on") { - return true; - } - - return false; -} - -bool SrsConfig::get_atc_auto(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return true; - } - - conf = conf->get("atc_auto"); - if (conf && conf->arg0() == "off") { - return false; - } - - return true; -} - -int SrsConfig::get_time_jitter(string vhost) -{ - SrsConfDirective* dvr = get_vhost(vhost); - - std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER; - - if (dvr) { - SrsConfDirective* conf = dvr->get("time_jitter"); - - if (conf) { - time_jitter = conf->arg0(); - } - } - - return _srs_time_jitter_string2int(time_jitter); -} - -double SrsConfig::get_queue_length(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return SRS_CONF_DEFAULT_QUEUE_LENGTH; - } - - conf = conf->get("queue_length"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_QUEUE_LENGTH; - } - - return ::atoi(conf->arg0().c_str()); -} - -SrsConfDirective* SrsConfig::get_refer(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("refer"); -} - -SrsConfDirective* SrsConfig::get_refer_play(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("refer_play"); -} - -SrsConfDirective* SrsConfig::get_refer_publish(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("refer_publish"); -} - -int SrsConfig::get_chunk_size(string vhost) -{ - if (vhost.empty()) { - return get_global_chunk_size(); - } - - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - // vhost does not specify the chunk size, - // use the global instead. - return get_global_chunk_size(); - } - - conf = conf->get("chunk_size"); - if (!conf) { - // vhost does not specify the chunk size, - // use the global instead. - return get_global_chunk_size(); - } - - return ::atoi(conf->arg0().c_str()); -} - -int SrsConfig::get_global_chunk_size() -{ - SrsConfDirective* conf = root->get("chunk_size"); - if (!conf) { - return SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; - } - - return ::atoi(conf->arg0().c_str()); -} - -SrsConfDirective* SrsConfig::get_forward(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("forward"); -} - -SrsConfDirective* SrsConfig::get_vhost_http_hooks(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("http_hooks"); -} - -bool SrsConfig::get_vhost_http_hooks_enabled(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return false; - } - - SrsConfDirective* enabled = conf->get("enabled"); - if (!enabled || enabled->arg0() != "on") { - return false; - } - - return true; -} - -SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_connect"); -} - -SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_close"); -} - -SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_publish"); -} - -SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_unpublish"); -} - -SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_play"); -} - -SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) -{ - SrsConfDirective* conf = get_vhost_http_hooks(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("on_stop"); -} - -bool SrsConfig::get_bw_check_enabled(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return false; - } - - conf = conf->get("bandcheck"); - if (!conf) { - return false; - } - - conf = conf->get("enabled"); - if (!conf || conf->arg0() != "on") { - return false; - } - - return true; -} - -string SrsConfig::get_bw_check_key(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return ""; - } - - conf = conf->get("bandcheck"); - if (!conf) { - return ""; - } - - conf = conf->get("key"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -int SrsConfig::get_bw_check_interval_ms(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; - } - - conf = conf->get("bandcheck"); - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; - } - - conf = conf->get("interval"); - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; - } - - return (int)(::atof(conf->arg0().c_str()) * 1000); -} - -int SrsConfig::get_bw_check_limit_kbps(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; - } - - conf = conf->get("bandcheck"); - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; - } - - conf = conf->get("limit_kbps"); - if (!conf) { - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; - } - - return ::atoi(conf->arg0().c_str()); -} - -bool SrsConfig::get_vhost_is_edge(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - return get_vhost_is_edge(conf); -} - -bool SrsConfig::get_vhost_is_edge(SrsConfDirective* vhost) -{ - SrsConfDirective* conf = vhost; - - if (!conf) { - return false; - } - - conf = conf->get("mode"); - if (!conf || conf->arg0() != "remote") { - return false; - } - - return true; -} - -SrsConfDirective* SrsConfig::get_vhost_edge_origin(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("origin"); -} - -bool SrsConfig::get_vhost_edge_token_traverse(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return false; - } - - conf = conf->get("token_traverse"); - if (!conf || conf->arg0() != "on") { - return false; - } - - return true; -} - -SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - SrsConfDirective* transcode = conf->get("transcode"); - if (!transcode) { - return NULL; - } - - if (transcode->arg0() == scope) { - return transcode; - } - - return NULL; -} - -bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode) -{ - if (!transcode) { - return false; - } - - SrsConfDirective* conf = transcode->get("enabled"); - if (!conf || conf->arg0() != "on") { - return false; - } - - return true; -} - -string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode) -{ - if (!transcode) { - return ""; - } - - SrsConfDirective* conf = transcode->get("ffmpeg"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -vector SrsConfig::get_transcode_engines(SrsConfDirective* transcode) -{ - vector engines; - - if (!transcode) { - return engines; - } - - for (int i = 0; i < (int)transcode->directives.size(); i++) { - SrsConfDirective* conf = transcode->directives[i]; - - if (conf->name == "engine") { - engines.push_back(conf); - } - } - - return engines; -} - -bool SrsConfig::get_engine_enabled(SrsConfDirective* engine) -{ - if (!engine) { - return false; - } - - SrsConfDirective* conf = engine->get("enabled"); - if (!conf || conf->arg0() != "on") { - return false; - } - - return true; -} - -string SrsConfig::get_engine_iformat(SrsConfDirective* engine) -{ - if (!engine) { - return SRS_CONF_DEFAULT_TRANSCODE_IFORMAT; - } - - SrsConfDirective* conf = engine->get("iformat"); - if (!conf) { - return SRS_CONF_DEFAULT_TRANSCODE_IFORMAT; - } - - return conf->arg0(); -} - -vector SrsConfig::get_engine_vfilter(SrsConfDirective* engine) -{ - vector vfilter; - - if (!engine) { - return vfilter; - } - - SrsConfDirective* conf = engine->get("vfilter"); - if (!conf) { - return vfilter; - } - - for (int i = 0; i < (int)conf->directives.size(); i++) { - SrsConfDirective* p = conf->directives[i]; - if (!p) { - continue; - } - - vfilter.push_back("-" + p->name); - vfilter.push_back(p->arg0()); - } - - return vfilter; -} - -string SrsConfig::get_engine_vcodec(SrsConfDirective* engine) -{ - if (!engine) { - return ""; - } - - SrsConfDirective* conf = engine->get("vcodec"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("vbitrate"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -double SrsConfig::get_engine_vfps(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("vfps"); - if (!conf) { - return 0; - } - - return ::atof(conf->arg0().c_str()); -} - -int SrsConfig::get_engine_vwidth(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("vwidth"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -int SrsConfig::get_engine_vheight(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("vheight"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -int SrsConfig::get_engine_vthreads(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("vthreads"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -string SrsConfig::get_engine_vprofile(SrsConfDirective* engine) -{ - if (!engine) { - return ""; - } - - SrsConfDirective* conf = engine->get("vprofile"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) -{ - if (!engine) { - return ""; - } - - SrsConfDirective* conf = engine->get("vpreset"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -vector SrsConfig::get_engine_vparams(SrsConfDirective* engine) -{ - vector vparams; - - if (!engine) { - return vparams; - } - - SrsConfDirective* conf = engine->get("vparams"); - if (!conf) { - return vparams; - } - - for (int i = 0; i < (int)conf->directives.size(); i++) { - SrsConfDirective* p = conf->directives[i]; - if (!p) { - continue; - } - - vparams.push_back("-" + p->name); - vparams.push_back(p->arg0()); - } - - return vparams; -} - -string SrsConfig::get_engine_acodec(SrsConfDirective* engine) -{ - if (!engine) { - return ""; - } - - SrsConfDirective* conf = engine->get("acodec"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -int SrsConfig::get_engine_abitrate(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("abitrate"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("asample_rate"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -int SrsConfig::get_engine_achannels(SrsConfDirective* engine) -{ - if (!engine) { - return 0; - } - - SrsConfDirective* conf = engine->get("achannels"); - if (!conf) { - return 0; - } - - return ::atoi(conf->arg0().c_str()); -} - -vector SrsConfig::get_engine_aparams(SrsConfDirective* engine) -{ - vector aparams; - - if (!engine) { - return aparams; - } - - SrsConfDirective* conf = engine->get("aparams"); - if (!conf) { - return aparams; - } - - for (int i = 0; i < (int)conf->directives.size(); i++) { - SrsConfDirective* p = conf->directives[i]; - if (!p) { - continue; - } - - aparams.push_back("-" + p->name); - aparams.push_back(p->arg0()); - } - - return aparams; -} - -string SrsConfig::get_engine_oformat(SrsConfDirective* engine) -{ - if (!engine) { - return SRS_CONF_DEFAULT_TRANSCODE_OFORMAT; - } - - SrsConfDirective* conf = engine->get("oformat"); - if (!conf) { - return SRS_CONF_DEFAULT_TRANSCODE_OFORMAT; - } - - return conf->arg0(); -} - -string SrsConfig::get_engine_output(SrsConfDirective* engine) -{ - if (!engine) { - return ""; - } - - SrsConfDirective* conf = engine->get("output"); - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -vector SrsConfig::get_ingesters(string vhost) -{ - vector ingeters; - - SrsConfDirective* vhost_conf = get_vhost(vhost); - if (!vhost_conf) { - return ingeters; - } - - for (int i = 0; i < (int)vhost_conf->directives.size(); i++) { - SrsConfDirective* conf = vhost_conf->directives[i]; - - if (conf->name == "ingest") { - ingeters.push_back(conf); - } - } - - return ingeters; -} - -SrsConfDirective* SrsConfig::get_ingest_by_id(string vhost, string ingest_id) -{ - SrsConfDirective* conf = get_vhost(vhost); - if (!conf) { - return NULL; - } - - conf = conf->get("ingest", ingest_id); - return conf; -} - -bool SrsConfig::get_ingest_enabled(SrsConfDirective* ingest) -{ - if (!ingest) { - return false; - } - - SrsConfDirective* conf = ingest->get("enabled"); - - if (!conf || conf->arg0() != "on") { - return false; - } - - return true; -} - -string SrsConfig::get_ingest_ffmpeg(SrsConfDirective* ingest) -{ - if (!ingest) { - return ""; - } - - SrsConfDirective* conf = ingest->get("ffmpeg"); - - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -string SrsConfig::get_ingest_input_type(SrsConfDirective* ingest) -{ - if (!ingest) { - return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; - } - - SrsConfDirective* conf = ingest->get("input"); - - if (!conf) { - return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; - } - - conf = conf->get("type"); - - if (!conf) { - return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; - } - - return conf->arg0(); -} - -string SrsConfig::get_ingest_input_url(SrsConfDirective* ingest) -{ - if (!ingest) { - return ""; - } - - SrsConfDirective* conf = ingest->get("input"); - - if (!conf) { - return ""; - } - - conf = conf->get("url"); - - if (!conf) { - return ""; - } - - return conf->arg0(); -} - -bool SrsConfig::get_log_tank_file() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("srs_log_tank"); - if (conf && conf->arg0() == SRS_CONF_DEFAULT_LOG_TANK_CONSOLE) { - return false; - } - - return true; -} - -string SrsConfig::get_log_level() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("srs_log_level"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_LOG_LEVEL; - } - - return conf->arg0(); -} - -string SrsConfig::get_log_file() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("srs_log_file"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_LOG_FILE; - } - - return conf->arg0(); -} - -bool SrsConfig::get_ffmpeg_log_enabled() -{ - string log = get_ffmpeg_log_dir(); - return log != SRS_CONSTS_NULL_FILE; -} - -string SrsConfig::get_ffmpeg_log_dir() -{ - srs_assert(root); - - SrsConfDirective* conf = root->get("ff_log_dir"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_FF_LOG_DIR; - } - - return conf->arg0(); -} - -SrsConfDirective* SrsConfig::get_hls(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("hls"); -} - -bool SrsConfig::get_hls_enabled(string vhost) -{ - SrsConfDirective* hls = get_hls(vhost); - - if (!hls) { - return false; - } - - SrsConfDirective* conf = hls->get("enabled"); - - if (!conf) { - return false; - } - - if (conf->arg0() == "on") { - return true; - } - - return false; -} - -string SrsConfig::get_hls_path(string vhost) -{ - SrsConfDirective* hls = get_hls(vhost); - - if (!hls) { - return SRS_CONF_DEFAULT_HLS_PATH; - } - - SrsConfDirective* conf = hls->get("hls_path"); - - if (!conf) { - return SRS_CONF_DEFAULT_HLS_PATH; - } - - return conf->arg0(); -} - -double SrsConfig::get_hls_fragment(string vhost) -{ - SrsConfDirective* hls = get_hls(vhost); - - if (!hls) { - return SRS_CONF_DEFAULT_HLS_FRAGMENT; - } - - SrsConfDirective* conf = hls->get("hls_fragment"); - - if (!conf) { - return SRS_CONF_DEFAULT_HLS_FRAGMENT; - } - - return ::atof(conf->arg0().c_str()); -} - -double SrsConfig::get_hls_window(string vhost) -{ - SrsConfDirective* hls = get_hls(vhost); - - if (!hls) { - return SRS_CONF_DEFAULT_HLS_WINDOW; - } - - SrsConfDirective* conf = hls->get("hls_window"); - - if (!conf) { - return SRS_CONF_DEFAULT_HLS_WINDOW; - } - - return ::atof(conf->arg0().c_str()); -} - -SrsConfDirective* SrsConfig::get_dvr(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - - if (!conf) { - return NULL; - } - - return conf->get("dvr"); -} - -bool SrsConfig::get_dvr_enabled(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - if (!dvr) { - return false; - } - - SrsConfDirective* conf = dvr->get("enabled"); - - if (!conf) { - return false; - } - - if (conf->arg0() == "on") { - return true; - } - - return false; -} - -string SrsConfig::get_dvr_path(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - if (!dvr) { - return SRS_CONF_DEFAULT_DVR_PATH; - } - - SrsConfDirective* conf = dvr->get("dvr_path"); - - if (!conf) { - return SRS_CONF_DEFAULT_DVR_PATH; - } - - return conf->arg0(); -} - -string SrsConfig::get_dvr_plan(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - if (!dvr) { - return SRS_CONF_DEFAULT_DVR_PLAN; - } - - SrsConfDirective* conf = dvr->get("dvr_plan"); - - if (!conf) { - return SRS_CONF_DEFAULT_DVR_PLAN; - } - - return conf->arg0(); -} - -int SrsConfig::get_dvr_duration(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - if (!dvr) { - return SRS_CONF_DEFAULT_DVR_DURATION; - } - - SrsConfDirective* conf = dvr->get("dvr_duration"); - - if (!conf) { - return SRS_CONF_DEFAULT_DVR_DURATION; - } - - return ::atoi(conf->arg0().c_str()); -} - -bool SrsConfig::get_dvr_wait_keyframe(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - if (!dvr) { - return true; - } - - SrsConfDirective* conf = dvr->get("dvr_wait_keyframe"); - - if (!conf || conf->arg0() != "off") { - return true; - } - - return false; -} - -int SrsConfig::get_dvr_time_jitter(string vhost) -{ - SrsConfDirective* dvr = get_dvr(vhost); - - std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER; - - if (dvr) { - SrsConfDirective* conf = dvr->get("time_jitter"); - - if (conf) { - time_jitter = conf->arg0(); - } - } - - return _srs_time_jitter_string2int(time_jitter); -} - -bool SrsConfig::get_http_api_enabled() -{ - SrsConfDirective* conf = get_http_api(); - return get_http_api_enabled(conf); -} - -SrsConfDirective* SrsConfig::get_http_api() -{ - return root->get("http_api"); -} - -bool SrsConfig::get_http_api_enabled(SrsConfDirective* conf) -{ - if (!conf) { - return false; - } - - conf = conf->get("enabled"); - if (conf && conf->arg0() == "on") { - return true; - } - - return false; -} - -int SrsConfig::get_http_api_listen() -{ - SrsConfDirective* conf = get_http_api(); - - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_API_PORT; - } - - conf = conf->get("listen"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_API_PORT; - } - - return ::atoi(conf->arg0().c_str()); -} - -bool SrsConfig::get_http_stream_enabled() -{ - SrsConfDirective* conf = get_http_stream(); - return get_http_stream_enabled(conf); -} - -SrsConfDirective* SrsConfig::get_http_stream() -{ - return root->get("http_stream"); -} - -bool SrsConfig::get_http_stream_enabled(SrsConfDirective* conf) -{ - if (!conf) { - return false; - } - - conf = conf->get("enabled"); - if (conf && conf->arg0() == "on") { - return true; - } - - return false; -} - -int SrsConfig::get_http_stream_listen() -{ - SrsConfDirective* conf = get_http_stream(); - - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_STREAM_PORT; - } - - conf = conf->get("listen"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_STREAM_PORT; - } - - return ::atoi(conf->arg0().c_str()); -} - -string SrsConfig::get_http_stream_dir() -{ - SrsConfDirective* conf = get_http_stream(); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - conf = conf->get("dir"); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - if (conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - return conf->arg0(); -} - -bool SrsConfig::get_vhost_http_enabled(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - if (!conf) { - return false; - } - - conf = conf->get("http"); - if (!conf) { - return false; - } - - conf = conf->get("enabled"); - if (!conf) { - return false; - } - - if (conf->arg0() == "on") { - return true; - } - - return false; -} - -string SrsConfig::get_vhost_http_mount(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_MOUNT; - } - - conf = conf->get("http"); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_MOUNT; - } - - conf = conf->get("mount"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_MOUNT; - } - - return conf->arg0(); -} - -string SrsConfig::get_vhost_http_dir(string vhost) -{ - SrsConfDirective* conf = get_vhost(vhost); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - conf = conf->get("http"); - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - conf = conf->get("dir"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_DIR; - } - - return conf->arg0(); -} - -SrsConfDirective* SrsConfig::get_heartbeart() -{ - return root->get("heartbeat"); -} - -bool SrsConfig::get_heartbeat_enabled() -{ - SrsConfDirective* conf = get_heartbeart(); - - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED; - } - - conf = conf->get("enabled"); - if (!conf || conf->arg0() != "on") { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED; - } - - return true; -} - -int64_t SrsConfig::get_heartbeat_interval() -{ - SrsConfDirective* conf = get_heartbeart(); - - if (!conf) { - return (int64_t)(SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL * 1000); - } - conf = conf->get("interval"); - if (!conf || conf->arg0().empty()) { - return (int64_t)(SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL * 1000); - } - - return (int64_t)(::atof(conf->arg0().c_str()) * 1000); -} - -string SrsConfig::get_heartbeat_url() -{ - SrsConfDirective* conf = get_heartbeart(); - - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL; - } - - conf = conf->get("url"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL; - } - - return conf->arg0(); -} - -string SrsConfig::get_heartbeat_device_id() -{ - SrsConfDirective* conf = get_heartbeart(); - - if (!conf) { - return ""; - } - - conf = conf->get("device_id"); - if (!conf || conf->arg0().empty()) { - return ""; - } - - return conf->arg0(); -} - -bool SrsConfig::get_heartbeat_summaries() -{ - SrsConfDirective* conf = get_heartbeart(); - - if (!conf) { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES; - } - - conf = conf->get("summaries"); - if (!conf || conf->arg0() != "on") { - return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES; - } - - return true; -} - -SrsConfDirective* SrsConfig::get_stats() -{ - return root->get("stats"); -} - -int SrsConfig::get_stats_network() -{ - SrsConfDirective* conf = get_stats(); - - if (!conf) { - return SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX; - } - - conf = conf->get("network"); - if (!conf || conf->arg0().empty()) { - return SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX; - } - - return ::atoi(conf->arg0().c_str()); -} - -SrsConfDirective* SrsConfig::get_stats_disk_device() -{ - SrsConfDirective* conf = get_stats(); - - if (!conf) { - return NULL; - } - - conf = conf->get("disk"); - if (!conf || conf->args.size() == 0) { - return NULL; - } - - return conf; -} - -namespace _srs_internal -{ - SrsConfigBuffer::SrsConfigBuffer() - { - line = 1; - - pos = last = start = NULL; - end = start; - } - - SrsConfigBuffer::~SrsConfigBuffer() - { - srs_freep(start); - } - - int SrsConfigBuffer::fullfill(const char* filename) - { - int ret = ERROR_SUCCESS; - - SrsFileReader reader; - - // open file reader. - if ((ret = reader.open(filename)) != ERROR_SUCCESS) { - srs_error("open conf file error. ret=%d", ret); - return ret; - } - - // read all. - int filesize = (int)reader.filesize(); - - // create buffer - srs_freep(start); - pos = last = start = new char[filesize]; - end = start + filesize; - - // read total content from file. - ssize_t nread = 0; - if ((ret = reader.read(start, filesize, &nread)) != ERROR_SUCCESS) { - srs_error("read file read error. expect %d, actual %d bytes, ret=%d", - filesize, nread, ret); - return ret; - } - - return ret; - } - - bool SrsConfigBuffer::empty() - { - return pos >= end; - } -}; - -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b) -{ - // both NULL, equal. - if (!a && !b) { - return true; - } - - if (!a || !b) { - return false; - } - - if (a->name != b->name) { - return false; - } - - if (a->args.size() != b->args.size()) { - return false; - } - - for (int i = 0; i < (int)a->args.size(); i++) { - if (a->args.at(i) != b->args.at(i)) { - return false; - } - } - - if (a->directives.size() != b->directives.size()) { - return false; - } - - for (int i = 0; i < (int)a->directives.size(); i++) { - SrsConfDirective* a0 = a->at(i); - SrsConfDirective* b0 = b->at(i); - - if (!srs_directive_equals(a0, b0)) { - return false; - } - } - - return true; -} - +/* +The MIT License (MIT) + +Copyright (c) 2013-2014 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 +#include +#include +// file operations. +#include +#include +#include +#include + +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include + +using namespace _srs_internal; + +#define SRS_WIKI_URL_LOG "https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_SrsLog" + +// '\n' +#define __LF (char)0x0a + +// '\r' +#define __CR (char)0x0d + +bool is_common_space(char ch) +{ + return (ch == ' ' || ch == '\t' || ch == __CR || ch == __LF); +} + +SrsConfDirective::SrsConfDirective() +{ +} + +SrsConfDirective::~SrsConfDirective() +{ + std::vector::iterator it; + for (it = directives.begin(); it != directives.end(); ++it) { + SrsConfDirective* directive = *it; + srs_freep(directive); + } + directives.clear(); +} + +string SrsConfDirective::arg0() +{ + if (args.size() > 0) { + return args.at(0); + } + + return ""; +} + +string SrsConfDirective::arg1() +{ + if (args.size() > 1) { + return args.at(1); + } + + return ""; +} + +string SrsConfDirective::arg2() +{ + if (args.size() > 2) { + return args.at(2); + } + + return ""; +} + +SrsConfDirective* SrsConfDirective::at(int index) +{ + srs_assert(index < (int)directives.size()); + return directives.at(index); +} + +SrsConfDirective* SrsConfDirective::get(string _name) +{ + std::vector::iterator it; + for (it = directives.begin(); it != directives.end(); ++it) { + SrsConfDirective* directive = *it; + if (directive->name == _name) { + return directive; + } + } + + return NULL; +} + +SrsConfDirective* SrsConfDirective::get(string _name, string _arg0) +{ + std::vector::iterator it; + for (it = directives.begin(); it != directives.end(); ++it) { + SrsConfDirective* directive = *it; + if (directive->name == _name && directive->arg0() == _arg0) { + return directive; + } + } + + return NULL; +} + +bool SrsConfDirective::is_vhost() +{ + return name == "vhost"; +} + +int SrsConfDirective::parse(SrsConfigBuffer* buffer) +{ + return parse_conf(buffer, parse_file); +} + +// see: ngx_conf_parse +int SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type) +{ + int ret = ERROR_SUCCESS; + + while (true) { + std::vector args; + int line_start = 0; + ret = read_token(buffer, args, line_start); + + /** + * ret maybe: + * ERROR_SYSTEM_CONFIG_INVALID error. + * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found + * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found + * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found + * ERROR_SYSTEM_CONFIG_EOF the config file is done + */ + if (ret == ERROR_SYSTEM_CONFIG_INVALID) { + return ret; + } + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) { + if (type != parse_block) { + srs_error("line %d: unexpected \"}\", ret=%d", buffer->line, ret); + return ret; + } + return ERROR_SUCCESS; + } + if (ret == ERROR_SYSTEM_CONFIG_EOF) { + if (type == parse_block) { + srs_error("line %d: unexpected end of file, expecting \"}\", ret=%d", conf_line, ret); + return ret; + } + return ERROR_SUCCESS; + } + + if (args.empty()) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("line %d: empty directive. ret=%d", conf_line, ret); + return ret; + } + + // build directive tree. + SrsConfDirective* directive = new SrsConfDirective(); + + directive->conf_line = line_start; + directive->name = args[0]; + args.erase(args.begin()); + directive->args.swap(args); + + directives.push_back(directive); + + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) { + if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) { + return ret; + } + } + } + + return ret; +} + +// see: ngx_conf_read_token +int SrsConfDirective::read_token(SrsConfigBuffer* buffer, vector& args, int& line_start) +{ + int ret = ERROR_SUCCESS; + + char* pstart = buffer->pos; + + bool sharp_comment = false; + + bool d_quoted = false; + bool s_quoted = false; + + bool need_space = false; + bool last_space = true; + + while (true) { + if (buffer->empty()) { + ret = ERROR_SYSTEM_CONFIG_EOF; + + if (!args.empty() || !last_space) { + srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line); + return ERROR_SYSTEM_CONFIG_INVALID; + } + srs_trace("config parse complete"); + + return ret; + } + + char ch = *buffer->pos++; + + if (ch == __LF) { + buffer->line++; + sharp_comment = false; + } + + if (sharp_comment) { + continue; + } + + if (need_space) { + if (is_common_space(ch)) { + last_space = true; + need_space = false; + continue; + } + if (ch == ';') { + return ERROR_SYSTEM_CONFIG_DIRECTIVE; + } + if (ch == '{') { + return ERROR_SYSTEM_CONFIG_BLOCK_START; + } + srs_error("line %d: unexpected '%c'", buffer->line, ch); + return ERROR_SYSTEM_CONFIG_INVALID; + } + + // last charecter is space. + if (last_space) { + if (is_common_space(ch)) { + continue; + } + pstart = buffer->pos - 1; + switch (ch) { + case ';': + if (args.size() == 0) { + srs_error("line %d: unexpected ';'", buffer->line); + return ERROR_SYSTEM_CONFIG_INVALID; + } + return ERROR_SYSTEM_CONFIG_DIRECTIVE; + case '{': + if (args.size() == 0) { + srs_error("line %d: unexpected '{'", buffer->line); + return ERROR_SYSTEM_CONFIG_INVALID; + } + return ERROR_SYSTEM_CONFIG_BLOCK_START; + case '}': + if (args.size() != 0) { + srs_error("line %d: unexpected '}'", buffer->line); + return ERROR_SYSTEM_CONFIG_INVALID; + } + return ERROR_SYSTEM_CONFIG_BLOCK_END; + case '#': + sharp_comment = 1; + continue; + case '"': + pstart++; + d_quoted = true; + last_space = 0; + continue; + case '\'': + pstart++; + s_quoted = true; + last_space = 0; + continue; + default: + last_space = 0; + continue; + } + } else { + // last charecter is not space + if (line_start == 0) { + line_start = buffer->line; + } + + bool found = false; + if (d_quoted) { + if (ch == '"') { + d_quoted = false; + need_space = true; + found = true; + } + } else if (s_quoted) { + if (ch == '\'') { + s_quoted = false; + need_space = true; + found = true; + } + } else if (is_common_space(ch) || ch == ';' || ch == '{') { + last_space = true; + found = 1; + } + + if (found) { + int len = buffer->pos - pstart; + char* aword = new char[len]; + memcpy(aword, pstart, len); + aword[len - 1] = 0; + + string word_str = aword; + if (!word_str.empty()) { + args.push_back(word_str); + } + srs_freep(aword); + + if (ch == ';') { + return ERROR_SYSTEM_CONFIG_DIRECTIVE; + } + if (ch == '{') { + return ERROR_SYSTEM_CONFIG_BLOCK_START; + } + } + } + } + + return ret; +} + +SrsConfig::SrsConfig() +{ + show_help = false; + show_version = false; + test_conf = false; + + root = new SrsConfDirective(); + root->conf_line = 0; + root->name = "root"; +} + +SrsConfig::~SrsConfig() +{ + srs_freep(root); +} + +void SrsConfig::subscribe(ISrsReloadHandler* handler) +{ + std::vector::iterator it; + + it = std::find(subscribes.begin(), subscribes.end(), handler); + if (it != subscribes.end()) { + return; + } + + subscribes.push_back(handler); +} + +void SrsConfig::unsubscribe(ISrsReloadHandler* handler) +{ + std::vector::iterator it; + + it = std::find(subscribes.begin(), subscribes.end(), handler); + if (it == subscribes.end()) { + return; + } + + subscribes.erase(it); +} + +int SrsConfig::reload() +{ + int ret = ERROR_SUCCESS; + + SrsConfig conf; + + if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) { + srs_error("ignore config reloader parse file failed. ret=%d", ret); + ret = ERROR_SUCCESS; + return ret; + } + srs_info("config reloader parse file success."); + + if ((ret = conf.check_config()) != ERROR_SUCCESS) { + srs_error("ignore config reloader check config failed. ret=%d", ret); + ret = ERROR_SUCCESS; + return ret; + } + + return reload_conf(&conf); +} + +int SrsConfig::reload_conf(SrsConfig* conf) +{ + int ret = ERROR_SUCCESS; + + SrsConfDirective* old_root = root; + SrsAutoFree(SrsConfDirective, old_root); + + root = conf->root; + conf->root = NULL; + + // merge config. + std::vector::iterator it; + + // never support reload: + // daemon + // + // always support reload without additional code: + // chunk_size, ff_log_dir, max_connections, + // bandcheck, http_hooks, heartbeat, + // token_traverse, debug_srs_upnode + + // merge config: listen + if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload listen failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload listen success."); + } + + // merge config: pid + if (!srs_directive_equals(root->get("pid"), old_root->get("pid"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_pid()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload pid failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload pid success."); + } + + // merge config: srs_log_tank + if (!srs_directive_equals(root->get("srs_log_tank"), old_root->get("srs_log_tank"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_tank()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_tank failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_tank success."); + } + + // merge config: srs_log_level + if (!srs_directive_equals(root->get("srs_log_level"), old_root->get("srs_log_level"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_level()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_level failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_level success."); + } + + // merge config: srs_log_file + if (!srs_directive_equals(root->get("srs_log_file"), old_root->get("srs_log_file"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_file()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_file failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_file success."); + } + + // merge config: pithy_print + if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) { + srs_error("notify subscribes pithy_print listen failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload pithy_print success."); + } + + // merge config: http_api + if ((ret = reload_http_api(old_root)) != ERROR_SUCCESS) { + return ret; + } + + // merge config: http_stream + if ((ret = reload_http_stream(old_root)) != ERROR_SUCCESS) { + return ret; + } + + // merge config: vhost + if ((ret = reload_vhost(old_root)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +int SrsConfig::reload_http_api(SrsConfDirective* old_root) +{ + int ret = ERROR_SUCCESS; + + // merge config. + std::vector::iterator it; + + // state graph + // old_http_api new_http_api + // DISABLED => ENABLED + // ENABLED => DISABLED + // ENABLED => ENABLED (modified) + + SrsConfDirective* new_http_api = root->get("http_api"); + SrsConfDirective* old_http_api = old_root->get("http_api"); + + // DISABLED => ENABLED + if (!get_http_api_enabled(old_http_api) && get_http_api_enabled(new_http_api)) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_api_enabled()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_api disabled=>enabled failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload disabled=>enabled http_api success."); + + return ret; + } + + // ENABLED => DISABLED + if (get_http_api_enabled(old_http_api) && !get_http_api_enabled(new_http_api)) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_api_disabled()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_api enabled=>disabled failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload enabled=>disabled http_api success."); + + return ret; + } + + // ENABLED => ENABLED (modified) + if (get_http_api_enabled(old_http_api) && get_http_api_enabled(new_http_api) + && !srs_directive_equals(old_http_api, new_http_api) + ) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_api_enabled()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_api enabled modified failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload enabled modified http_api success."); + + return ret; + } + + srs_trace("reload http_api not changed success."); + + return ret; +} + +int SrsConfig::reload_http_stream(SrsConfDirective* old_root) +{ + int ret = ERROR_SUCCESS; + + // merge config. + std::vector::iterator it; + + // state graph + // old_http_stream new_http_stream + // DISABLED => ENABLED + // ENABLED => DISABLED + // ENABLED => ENABLED (modified) + + SrsConfDirective* new_http_stream = root->get("http_stream"); + SrsConfDirective* old_http_stream = old_root->get("http_stream"); + + // DISABLED => ENABLED + if (!get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream)) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_stream_enabled()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_stream disabled=>enabled failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload disabled=>enabled http_stream success."); + + return ret; + } + + // ENABLED => DISABLED + if (get_http_stream_enabled(old_http_stream) && !get_http_stream_enabled(new_http_stream)) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_stream_disabled()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_stream enabled=>disabled failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload enabled=>disabled http_stream success."); + + return ret; + } + + // ENABLED => ENABLED (modified) + if (get_http_stream_enabled(old_http_stream) && get_http_stream_enabled(new_http_stream) + && !srs_directive_equals(old_http_stream, new_http_stream) + ) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_http_stream_updated()) != ERROR_SUCCESS) { + srs_error("notify subscribes http_stream enabled modified failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload enabled modified http_stream success."); + + return ret; + } + + srs_trace("reload http_stream not changed success."); + + return ret; +} + +int SrsConfig::reload_vhost(SrsConfDirective* old_root) +{ + int ret = ERROR_SUCCESS; + + // merge config. + std::vector::iterator it; + + // state graph + // old_vhost new_vhost + // DISABLED => ENABLED + // ENABLED => DISABLED + // ENABLED => ENABLED (modified) + + // collect all vhost names + std::vector vhosts; + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* vhost = root->at(i); + if (vhost->name != "vhost") { + continue; + } + vhosts.push_back(vhost->arg0()); + } + for (int i = 0; i < (int)old_root->directives.size(); i++) { + SrsConfDirective* vhost = old_root->at(i); + if (vhost->name != "vhost") { + continue; + } + if (root->get("vhost", vhost->arg0())) { + continue; + } + vhosts.push_back(vhost->arg0()); + } + + // process each vhost + for (int i = 0; i < (int)vhosts.size(); i++) { + std::string vhost = vhosts.at(i); + + SrsConfDirective* old_vhost = old_root->get("vhost", vhost); + SrsConfDirective* new_vhost = root->get("vhost", vhost); + + // DISABLED => ENABLED + if (!get_vhost_enabled(old_vhost) && get_vhost_enabled(new_vhost)) { + srs_trace("vhost %s added, reload it.", vhost.c_str()); + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_added(vhost)) != ERROR_SUCCESS) { + srs_error("notify subscribes added " + "vhost %s failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("reload new vhost %s success.", vhost.c_str()); + continue; + } + + // ENABLED => DISABLED + if (get_vhost_enabled(old_vhost) && !get_vhost_enabled(new_vhost)) { + srs_trace("vhost %s removed, reload it.", vhost.c_str()); + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_removed(vhost)) != ERROR_SUCCESS) { + srs_error("notify subscribes removed " + "vhost %s failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("reload removed vhost %s success.", vhost.c_str()); + continue; + } + + // mode, never supports reload. + // first, for the origin and edge role change is too complex. + // second, the vhosts in origin device group normally are all origin, + // they never change to edge sometimes. + // third, the origin or upnode device can always be restart, + // edge will retry and the users connected to edge are ok. + // it's ok to add or remove edge/origin vhost. + if (get_vhost_is_edge(old_vhost) != get_vhost_is_edge(new_vhost)) { + ret = ERROR_RTMP_EDGE_RELOAD; + srs_error("reload never supports mode changed. ret=%d", ret); + return ret; + } + + // ENABLED => ENABLED (modified) + if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) { + srs_trace("vhost %s maybe modified, reload its detail.", vhost.c_str()); + // atc, only one per vhost + if (!srs_directive_equals(new_vhost->get("atc"), old_vhost->get("atc"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_atc(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes atc failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload atc success.", vhost.c_str()); + } + // gop_cache, only one per vhost + if (!srs_directive_equals(new_vhost->get("gop_cache"), old_vhost->get("gop_cache"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_gop_cache(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes gop_cache failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload gop_cache success.", vhost.c_str()); + } + // queue_length, only one per vhost + if (!srs_directive_equals(new_vhost->get("queue_length"), old_vhost->get("queue_length"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_queue_length(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes queue_length failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload queue_length success.", vhost.c_str()); + } + // time_jitter, only one per vhost + if (!srs_directive_equals(new_vhost->get("time_jitter"), old_vhost->get("time_jitter"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_time_jitter(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes time_jitter failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload time_jitter success.", vhost.c_str()); + } + // forward, only one per vhost + if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_forward(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes forward failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload forward success.", vhost.c_str()); + } + // hls, only one per vhost + if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_hls(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes hls failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload hls success.", vhost.c_str()); + } + // dvr, only one per vhost + if (!srs_directive_equals(new_vhost->get("dvr"), old_vhost->get("dvr"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_dvr(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes dvr failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload hls success.", vhost.c_str()); + } + // http, only one per vhost. + if (!srs_directive_equals(new_vhost->get("http"), old_vhost->get("http"))) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_http_updated()) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes http failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload http success.", vhost.c_str()); + } + // transcode, many per vhost. + if ((ret = reload_transcode(new_vhost, old_vhost)) != ERROR_SUCCESS) { + return ret; + } + // ingest, many per vhost. + if ((ret = reload_ingest(new_vhost, old_vhost)) != ERROR_SUCCESS) { + return ret; + } + continue; + } + srs_trace("igreno reload vhost, enabled old: %d, new: %d", + get_vhost_enabled(old_vhost), get_vhost_enabled(new_vhost)); + } + + return ret; +} + +int SrsConfig::reload_transcode(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost) +{ + int ret = ERROR_SUCCESS; + + std::vector old_transcoders; + for (int i = 0; i < (int)old_vhost->directives.size(); i++) { + SrsConfDirective* conf = old_vhost->at(i); + if (conf->name == "transcode") { + old_transcoders.push_back(conf); + } + } + + std::vector new_transcoders; + for (int i = 0; i < (int)new_vhost->directives.size(); i++) { + SrsConfDirective* conf = new_vhost->at(i); + if (conf->name == "transcode") { + new_transcoders.push_back(conf); + } + } + + std::vector::iterator it; + + std::string vhost = new_vhost->arg0(); + + // to be simple: + // whatever, once tiny changed of transcode, + // restart all ffmpeg of vhost. + bool changed = false; + + // discovery the removed ffmpeg. + for (int i = 0; !changed && i < (int)old_transcoders.size(); i++) { + SrsConfDirective* old_transcoder = old_transcoders.at(i); + std::string transcoder_id = old_transcoder->arg0(); + + // if transcoder exists in new vhost, not removed, ignore. + if (new_vhost->get("transcode", transcoder_id)) { + continue; + } + + changed = true; + } + + // discovery the added ffmpeg. + for (int i = 0; !changed && i < (int)new_transcoders.size(); i++) { + SrsConfDirective* new_transcoder = new_transcoders.at(i); + std::string transcoder_id = new_transcoder->arg0(); + + // if transcoder exists in old vhost, not added, ignore. + if (old_vhost->get("transcode", transcoder_id)) { + continue; + } + + changed = true; + } + + // for updated transcoders, restart them. + for (int i = 0; !changed && i < (int)new_transcoders.size(); i++) { + SrsConfDirective* new_transcoder = new_transcoders.at(i); + std::string transcoder_id = new_transcoder->arg0(); + SrsConfDirective* old_transcoder = old_vhost->get("transcode", transcoder_id); + srs_assert(old_transcoder); + + if (srs_directive_equals(new_transcoder, old_transcoder)) { + continue; + } + + changed = true; + } + + // transcode, many per vhost + if (changed) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_vhost_transcode(vhost)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes transcode failed. ret=%d", vhost.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload transcode success.", vhost.c_str()); + } + + return ret; +} + +int SrsConfig::reload_ingest(SrsConfDirective* new_vhost, SrsConfDirective* old_vhost) +{ + int ret = ERROR_SUCCESS; + + std::vector old_ingesters; + for (int i = 0; i < (int)old_vhost->directives.size(); i++) { + SrsConfDirective* conf = old_vhost->at(i); + if (conf->name == "ingest") { + old_ingesters.push_back(conf); + } + } + + std::vector new_ingesters; + for (int i = 0; i < (int)new_vhost->directives.size(); i++) { + SrsConfDirective* conf = new_vhost->at(i); + if (conf->name == "ingest") { + new_ingesters.push_back(conf); + } + } + + std::vector::iterator it; + + std::string vhost = new_vhost->arg0(); + + // for removed ingesters, stop them. + for (int i = 0; i < (int)old_ingesters.size(); i++) { + SrsConfDirective* old_ingester = old_ingesters.at(i); + std::string ingest_id = old_ingester->arg0(); + SrsConfDirective* new_ingester = new_vhost->get("ingest", ingest_id); + + // ENABLED => DISABLED + if (get_ingest_enabled(old_ingester) && !get_ingest_enabled(new_ingester)) { + // notice handler ingester removed. + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_ingest_removed(vhost, ingest_id)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes ingest=%s removed failed. ret=%d", + vhost.c_str(), ingest_id.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload ingest=%s removed success.", vhost.c_str(), ingest_id.c_str()); + } + } + + // for added ingesters, start them. + for (int i = 0; i < (int)new_ingesters.size(); i++) { + SrsConfDirective* new_ingester = new_ingesters.at(i); + std::string ingest_id = new_ingester->arg0(); + SrsConfDirective* old_ingester = old_vhost->get("ingest", ingest_id); + + // DISABLED => ENABLED + if (!get_ingest_enabled(old_ingester) && get_ingest_enabled(new_ingester)) { + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_ingest_added(vhost, ingest_id)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes ingest=%s added failed. ret=%d", + vhost.c_str(), ingest_id.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload ingest=%s added success.", vhost.c_str(), ingest_id.c_str()); + } + } + + // for updated ingesters, restart them. + for (int i = 0; i < (int)new_ingesters.size(); i++) { + SrsConfDirective* new_ingester = new_ingesters.at(i); + std::string ingest_id = new_ingester->arg0(); + SrsConfDirective* old_ingester = old_vhost->get("ingest", ingest_id); + + // ENABLED => ENABLED + if (get_ingest_enabled(old_ingester) && get_ingest_enabled(new_ingester)) { + if (srs_directive_equals(new_ingester, old_ingester)) { + continue; + } + + // notice handler ingester removed. + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_ingest_updated(vhost, ingest_id)) != ERROR_SUCCESS) { + srs_error("vhost %s notify subscribes ingest=%s updated failed. ret=%d", + vhost.c_str(), ingest_id.c_str(), ret); + return ret; + } + } + srs_trace("vhost %s reload ingest=%s updated success.", vhost.c_str(), ingest_id.c_str()); + } + } + + srs_trace("ingest not changed for vhost=%s", vhost.c_str()); + + return ret; +} + +// see: ngx_get_options +int SrsConfig::parse_options(int argc, char** argv) +{ + int ret = ERROR_SUCCESS; + + // argv + for (int i = 0; i < argc; i++) { + _argv.append(argv[i]); + + if (i < argc - 1) { + _argv.append(" "); + } + } + + // cwd + char cwd[256]; + getcwd(cwd, sizeof(cwd)); + _cwd = cwd; + + // config + show_help = true; + for (int i = 1; i < argc; i++) { + if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) { + return ret; + } + } + + if (show_help) { + print_help(argv); + exit(0); + } + + if (show_version) { + fprintf(stderr, "%s\n", RTMP_SIG_SRS_VERSION); + exit(0); + } + + if (config_file.empty()) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret); + return ret; + } + + ret = parse_file(config_file.c_str()); + + if (test_conf) { + // the parse_file never check the config, + // we check it when user requires check config file. + if (ret == ERROR_SUCCESS) { + ret = check_config(); + } + + if (ret == ERROR_SUCCESS) { + srs_trace("config file is ok"); + exit(0); + } else { + srs_error("config file is invalid"); + exit(ret); + } + } + + //////////////////////////////////////////////////////////////////////// + // check log name and level + //////////////////////////////////////////////////////////////////////// + if (true) { + std::string log_filename = this->get_log_file(); + if (get_log_tank_file() && log_filename.empty()) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("must specifies the file to write log to. ret=%d", ret); + return ret; + } + if (get_log_tank_file()) { + srs_trace("write log to file %s", log_filename.c_str()); + srs_trace("you can: tailf %s", log_filename.c_str()); + srs_trace("@see: %s", SRS_WIKI_URL_LOG); + } else { + srs_trace("write log to console"); + } + } + + return ret; +} + +string SrsConfig::config() +{ + return config_file; +} + +int SrsConfig::parse_argv(int& i, char** argv) +{ + int ret = ERROR_SUCCESS; + + char* p = argv[i]; + + if (*p++ != '-') { + show_help = true; + return ret; + } + + while (*p) { + switch (*p++) { + case '?': + case 'h': + show_help = true; + break; + case 't': + show_help = false; + test_conf = true; + break; + case 'v': + case 'V': + show_help = false; + show_version = true; + break; + case 'c': + show_help = false; + if (*p) { + config_file = p; + return ret; + } + if (argv[++i]) { + config_file = argv[i]; + return ret; + } + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("option \"-c\" requires parameter, ret=%d", ret); + return ret; + default: + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret); + return ret; + } + } + + return ret; +} + +void SrsConfig::print_help(char** argv) +{ + printf( + RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION" "RTMP_SIG_SRS_COPYRIGHT"\n" + "License: "RTMP_SIG_SRS_LICENSE"\n" + "Primary Authors: "RTMP_SIG_SRS_PRIMARY_AUTHROS"\n" + "Build: "SRS_AUTO_BUILD_DATE" Configuration:"SRS_AUTO_USER_CONFIGURE"\n" + "Features:"SRS_AUTO_CONFIGURE"\n""\n" + "Usage: %s [-h?vV] [[-t] -c ]\n" + "\n" + "Options:\n" + " -?, -h : show this help and exit(0)\n" + " -v, -V : show version and exit(0)\n" + " -t : test configuration file, exit(error_code).\n" + " -c filename : use configuration file for SRS\n" + "\n" + RTMP_SIG_SRS_WEB"\n" + RTMP_SIG_SRS_URL"\n" + "Email: "RTMP_SIG_SRS_EMAIL"\n" + "\n" + "For example:\n" + " %s -v\n" + " %s -t -c "SRS_CONF_DEFAULT_COFNIG_FILE"\n" + " %s -c "SRS_CONF_DEFAULT_COFNIG_FILE"\n", + argv[0], argv[0], argv[0], argv[0]); +} + +int SrsConfig::parse_file(const char* filename) +{ + int ret = ERROR_SUCCESS; + + config_file = filename; + + if (config_file.empty()) { + return ERROR_SYSTEM_CONFIG_INVALID; + } + + SrsConfigBuffer buffer; + + if ((ret = buffer.fullfill(config_file.c_str())) != ERROR_SUCCESS) { + return ret; + } + + return parse_buffer(&buffer); +} + +int SrsConfig::check_config() +{ + int ret = ERROR_SUCCESS; + + srs_trace("srs checking config..."); + + vector vhosts = get_vhosts(); + + //////////////////////////////////////////////////////////////////////// + // check empty + //////////////////////////////////////////////////////////////////////// + if (root->directives.size() == 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("conf is empty, ret=%d", ret); + return ret; + } + + //////////////////////////////////////////////////////////////////////// + // check root directives. + //////////////////////////////////////////////////////////////////////// + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* conf = root->at(i); + std::string n = conf->name; + if (n != "listen" && n != "pid" && n != "chunk_size" && n != "ff_log_dir" + && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" + && n != "max_connections" && n != "daemon" && n != "heartbeat" + && n != "http_api" && n != "http_stream" && n != "stats" && n != "vhost" + && n != "pithy_print") + { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + if (true) { + SrsConfDirective* conf = get_http_api(); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "enabled" && n != "listen") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + } + if (true) { + SrsConfDirective* conf = get_http_stream(); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "enabled" && n != "listen" && n != "dir") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported http_stream directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + } + if (true) { + SrsConfDirective* conf = get_heartbeart(); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "enabled" && n != "interval" && n != "url" + && n != "device_id" && n != "summaries" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported heartbeat directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + } + if (true) { + SrsConfDirective* conf = get_stats(); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "network" && n != "disk") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported stats directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + } + if (true) { + SrsConfDirective* conf = get_pithy_print(); + for (int i = 0; conf && i < (int)conf->directives.size(); i++) { + string n = conf->at(i)->name; + if (n != "publish" && n != "play" && n != "forwarder" + && n != "encoder" && n != "ingester" && n != "hls" && n != "edge" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported pithy_print directive %s, ret=%d", n.c_str(), ret); + return ret; + } + } + } + for (int n = 0; n < (int)vhosts.size(); n++) { + SrsConfDirective* vhost = vhosts[n]; + for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) { + SrsConfDirective* conf = vhost->at(i); + string n = conf->name; + if (n != "enabled" && n != "chunk_size" + && n != "mode" && n != "origin" && n != "token_traverse" + && n != "dvr" && n != "ingest" && n != "http" && n != "hls" && n != "http_hooks" + && n != "gop_cache" && n != "queue_length" + && n != "refer" && n != "refer_publish" && n != "refer_play" + && n != "forward" && n != "transcode" && n != "bandcheck" + && n != "time_jitter" + && n != "atc" && n != "atc_auto" + && n != "debug_srs_upnode" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret); + return ret; + } + // for each sub directives of vhost. + if (n == "dvr") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "dvr_path" && m != "dvr_plan" + && m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } else if (n == "ingest") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "input" && m != "ffmpeg" + && m != "engine" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } else if (n == "http") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "mount" && m != "dir") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } else if (n == "hls") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "hls_path" && m != "hls_fragment" && m != "hls_window") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } else if (n == "http_hooks") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" + && m != "on_unpublish" && m != "on_play" && m != "on_stop" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } else if (n == "forward") { + // TODO: FIXME: implements it. + /*for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "vhost" && m != "refer") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret); + return ret; + } + }*/ + } else if (n == "transcode") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + SrsConfDirective* trans = conf->at(j); + string m = trans->name.c_str(); + if (m != "enabled" && m != "ffmpeg" && m != "engine") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost transcode directive %s, ret=%d", m.c_str(), ret); + return ret; + } + if (m == "engine") { + for (int k = 0; k < (int)trans->directives.size(); k++) { + string e = trans->at(k)->name; + if (e != "enabled" && e != "vfilter" && e != "vcodec" + && e != "vbitrate" && e != "vfps" && e != "vwidth" && e != "vheight" + && e != "vthreads" && e != "vprofile" && e != "vpreset" && e != "vparams" + && e != "acodec" && e != "abitrate" && e != "asample_rate" && e != "achannels" + && e != "aparams" && e != "output" + && e != "iformat" && e != "oformat" + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost transcode engine directive %s, ret=%d", e.c_str(), ret); + return ret; + } + } + } + } + } else if (n == "bandcheck") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name.c_str(); + if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret); + return ret; + } + } + } + } + } + // check ingest id unique. + for (int i = 0; i < (int)vhosts.size(); i++) { + SrsConfDirective* vhost = vhosts[i]; + std::vector ids; + + for (int j = 0; j < (int)vhost->directives.size(); j++) { + SrsConfDirective* conf = vhost->at(j); + if (conf->name != "ingest") { + continue; + } + + std::string id = conf->arg0(); + for (int k = 0; k < (int)ids.size(); k++) { + if (id == ids.at(k)) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive \"ingest\" id duplicated, vhost=%s, id=%s, ret=%d", + vhost->name.c_str(), id.c_str(), ret); + return ret; + } + } + ids.push_back(id); + } + } + + //////////////////////////////////////////////////////////////////////// + // check listen for rtmp. + //////////////////////////////////////////////////////////////////////// + if (true) { + vector listens = get_listen(); + if (listens.size() <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive \"listen\" is empty, ret=%d", ret); + return ret; + } + for (int i = 0; i < (int)listens.size(); i++) { + string port = listens[i]; + if (port.empty() || ::atoi(port.c_str()) <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive listen invalid, port=%s, ret=%d", port.c_str(), ret); + return ret; + } + } + } + + //////////////////////////////////////////////////////////////////////// + // check max connections + //////////////////////////////////////////////////////////////////////// + if (get_max_connections() <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive max_connections invalid, max_connections=%d, ret=%d", get_max_connections(), ret); + return ret; + } + + // check max connections of system limits + if (true) { + int nb_consumed_fds = (int)get_listen().size(); + if (get_http_api_listen() > 0) { + nb_consumed_fds++; + } + if (get_http_stream_listen() > 0) { + nb_consumed_fds++; + } + if (get_log_tank_file()) { + nb_consumed_fds++; + } + // 0, 1, 2 for stdin, stdout and stderr. + nb_consumed_fds += 3; + + int nb_connections = get_max_connections(); + int nb_pipes = nb_connections * 2; + int nb_reserved = 10; // reserved + int nb_total = nb_connections + nb_pipes + nb_consumed_fds + nb_reserved; + + int max_open_files = sysconf(_SC_OPEN_MAX); + int nb_canbe = (max_open_files - (nb_consumed_fds + nb_reserved)) / 3 - 1; + + // for each play connections, we open a pipe(2fds) to convert SrsConsumver to io, + // refine performance, @see: https://github.com/winlinvip/simple-rtmp-server/issues/194 + if (nb_total >= max_open_files) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("invalid max_connections=%d, required=%d, system limit to %d, " + "total=%d(max_connections=%d, nb_pipes=%d, nb_consumed_fds=%d, nb_reserved=%d), ret=%d. " + "you can change max_connections from %d to %d, or " + "you can login as root and set the limit: ulimit -HSn %d", + nb_connections, nb_total, max_open_files, + nb_total, nb_connections, nb_pipes, nb_consumed_fds, nb_reserved, + ret, nb_connections, nb_canbe, nb_total); + return ret; + } + } + + //////////////////////////////////////////////////////////////////////// + // check heartbeat + //////////////////////////////////////////////////////////////////////// + if (get_heartbeat_interval() <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive heartbeat interval invalid, interval=%"PRId64", ret=%d", + get_heartbeat_interval(), ret); + return ret; + } + + //////////////////////////////////////////////////////////////////////// + // check stats + //////////////////////////////////////////////////////////////////////// + if (get_stats_network() < 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive stats network invalid, network=%d, ret=%d", + get_stats_network(), ret); + return ret; + } + if (true) { + vector ips = srs_get_local_ipv4_ips(); + int index = get_stats_network(); + if (index >= (int)ips.size()) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("stats network invalid, total local ip count=%d, index=%d, ret=%d", + (int)ips.size(), index, ret); + return ret; + } + srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str()); + } + if (true) { + SrsConfDirective* conf = get_stats_disk_device(); + if (conf == NULL || (int)conf->args.size() <= 0) { + srs_warn("stats disk not configed, disk iops disabled."); + } else { + string disks; + for (int i = 0; i < (int)conf->args.size(); i++) { + disks += conf->args.at(i); + disks += " "; + } + srs_warn("stats disk list: %s", disks.c_str()); + } + } + + //////////////////////////////////////////////////////////////////////// + // check http api + //////////////////////////////////////////////////////////////////////// + if (get_http_api_listen() <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive http_api listen invalid, listen=%d, ret=%d", + get_http_api_listen(), ret); + return ret; + } + + //////////////////////////////////////////////////////////////////////// + // check http stream + //////////////////////////////////////////////////////////////////////// + if (get_http_stream_listen() <= 0) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive http_stream listen invalid, listen=%d, ret=%d", + get_http_stream_listen(), ret); + return ret; + } + + //////////////////////////////////////////////////////////////////////// + // check chunk size + //////////////////////////////////////////////////////////////////////// + if (get_global_chunk_size() < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE + || get_global_chunk_size() > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", + get_global_chunk_size(), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, + SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret); + return ret; + } + for (int i = 0; i < (int)vhosts.size(); i++) { + SrsConfDirective* vhost = vhosts[i]; + if (get_chunk_size(vhost->arg0()) < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE + || get_chunk_size(vhost->arg0()) > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE + ) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("directive vhost %s chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", + vhost->arg0().c_str(), get_chunk_size(vhost->arg0()), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, + SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret); + return ret; + } + } + + //////////////////////////////////////////////////////////////////////// + // check log name and level + //////////////////////////////////////////////////////////////////////// + if (true) { + std::string log_filename = this->get_log_file(); + if (get_log_tank_file() && log_filename.empty()) { + ret = ERROR_SYSTEM_CONFIG_INVALID; + srs_error("must specifies the file to write log to. ret=%d", ret); + return ret; + } + if (get_log_tank_file()) { + srs_trace("write log to file %s", log_filename.c_str()); + srs_trace("you can: tailf %s", log_filename.c_str()); + srs_trace("@see: %s", SRS_WIKI_URL_LOG); + } else { + srs_trace("write log to console"); + } + } + + //////////////////////////////////////////////////////////////////////// + // check features + //////////////////////////////////////////////////////////////////////// +#ifndef SRS_AUTO_HTTP_SERVER + if (get_http_stream_enabled()) { + srs_warn("http_stream is disabled by configure"); + } +#endif +#ifndef SRS_AUTO_HTTP_API + if (get_http_api_enabled()) { + srs_warn("http_api is disabled by configure"); + } +#endif + for (int i = 0; i < (int)vhosts.size(); i++) { + SrsConfDirective* vhost = vhosts[i]; + srs_assert(vhost != NULL); +#ifndef SRS_AUTO_DVR + if (get_dvr_enabled(vhost->arg0())) { + srs_warn("dvr of vhost %s is disabled by configure", vhost->arg0().c_str()); + } +#endif +#ifndef SRS_AUTO_HLS + if (get_hls_enabled(vhost->arg0())) { + srs_warn("hls of vhost %s is disabled by configure", vhost->arg0().c_str()); + } +#endif +#ifndef SRS_AUTO_HTTP_CALLBACK + if (get_vhost_http_hooks_enabled(vhost->arg0())) { + srs_warn("http_hooks of vhost %s is disabled by configure", vhost->arg0().c_str()); + } +#endif +#ifndef SRS_AUTO_TRANSCODE + if (get_transcode_enabled(get_transcode(vhost->arg0(), ""))) { + srs_warn("transcode of vhost %s is disabled by configure", vhost->arg0().c_str()); + } +#endif +#ifndef SRS_AUTO_INGEST + vector ingesters = get_ingesters(vhost->arg0()); + for (int j = 0; j < (int)ingesters.size(); j++) { + SrsConfDirective* ingest = ingesters[j]; + if (get_ingest_enabled(ingest)) { + srs_warn("ingest %s of vhost %s is disabled by configure", + ingest->arg0().c_str(), vhost->arg0().c_str() + ); + } + } +#endif + } + + return ret; +} + +int SrsConfig::parse_buffer(SrsConfigBuffer* buffer) +{ + int ret = ERROR_SUCCESS; + + if ((ret = root->parse(buffer)) != ERROR_SUCCESS) { + return ret; + } + + return ret; +} + +string SrsConfig::cwd() +{ + return _cwd; +} + +string SrsConfig::argv() +{ + return _argv; +} + +bool SrsConfig::get_deamon() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("daemon"); + if (conf && conf->arg0() == "off") { + return false; + } + + return true; +} + +SrsConfDirective* SrsConfig::get_root() +{ + return root; +} + +int SrsConfig::get_max_connections() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("max_connections"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_MAX_CONNECTIONS; + } + + return ::atoi(conf->arg0().c_str()); +} + +vector SrsConfig::get_listen() +{ + std::vector ports; + + SrsConfDirective* conf = root->get("listen"); + if (!conf) { + return ports; + } + + for (int i = 0; i < (int)conf->args.size(); i++) { + ports.push_back(conf->args.at(i)); + } + + return ports; +} + +string SrsConfig::get_pid_file() +{ + SrsConfDirective* conf = root->get("pid"); + + if (!conf) { + return SRS_CONF_DEFAULT_PID_FILE; + } + + return conf->arg0(); +} + +SrsConfDirective* SrsConfig::get_pithy_print() +{ + return root->get("pithy_print"); +} + +int SrsConfig::get_pithy_print_publish() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_PUBLISH_USER_INTERVAL_MS; + } + + pithy = pithy->get("publish"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_PUBLISH_USER_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_forwarder() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_FORWARDER_INTERVAL_MS; + } + + pithy = pithy->get("forwarder"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_FORWARDER_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_encoder() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_ENCODER_INTERVAL_MS; + } + + pithy = pithy->get("encoder"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_ENCODER_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_ingester() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_INGESTER_INTERVAL_MS; + } + + pithy = pithy->get("ingester"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_INGESTER_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_hls() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_HLS_INTERVAL_MS; + } + + pithy = pithy->get("hls"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_HLS_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_play() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS; + } + + pithy = pithy->get("play"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +int SrsConfig::get_pithy_print_edge() +{ + SrsConfDirective* pithy = get_pithy_print(); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_EDGE_INTERVAL_MS; + } + + pithy = pithy->get("edge"); + if (!pithy) { + return SRS_CONF_DEFAULT_STAGE_EDGE_INTERVAL_MS; + } + + return ::atoi(pithy->arg0().c_str()); +} + +SrsConfDirective* SrsConfig::get_vhost(string vhost) +{ + srs_assert(root); + + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* conf = root->at(i); + + if (!conf->is_vhost()) { + continue; + } + + if (conf->arg0() == vhost) { + return conf; + } + } + + if (vhost != SRS_CONSTS_RTMP_DEFAULT_VHOST) { + return get_vhost(SRS_CONSTS_RTMP_DEFAULT_VHOST); + } + + return NULL; +} + +vector SrsConfig::get_vhosts() +{ + srs_assert(root); + + std::vector vhosts; + + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* conf = root->at(i); + + if (!conf->is_vhost()) { + continue; + } + + vhosts.push_back(conf); + } + + return vhosts; +} + +bool SrsConfig::get_vhost_enabled(string vhost) +{ + SrsConfDirective* vhost_conf = get_vhost(vhost); + + return get_vhost_enabled(vhost_conf); +} + +bool SrsConfig::get_vhost_enabled(SrsConfDirective* vhost) +{ + if (!vhost) { + return false; + } + + SrsConfDirective* conf = vhost->get("enabled"); + if (!conf) { + return true; + } + + if (conf->arg0() == "off") { + return false; + } + + return true; +} + +bool SrsConfig::get_gop_cache(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return true; + } + + conf = conf->get("gop_cache"); + if (conf && conf->arg0() == "off") { + return false; + } + + return true; +} + +bool SrsConfig::get_debug_srs_upnode(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return true; + } + + conf = conf->get("debug_srs_upnode"); + if (conf && conf->arg0() == "off") { + return false; + } + + return true; +} + +bool SrsConfig::get_atc(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return false; + } + + conf = conf->get("atc"); + if (conf && conf->arg0() == "on") { + return true; + } + + return false; +} + +bool SrsConfig::get_atc_auto(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return true; + } + + conf = conf->get("atc_auto"); + if (conf && conf->arg0() == "off") { + return false; + } + + return true; +} + +int SrsConfig::get_time_jitter(string vhost) +{ + SrsConfDirective* dvr = get_vhost(vhost); + + std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER; + + if (dvr) { + SrsConfDirective* conf = dvr->get("time_jitter"); + + if (conf) { + time_jitter = conf->arg0(); + } + } + + return _srs_time_jitter_string2int(time_jitter); +} + +double SrsConfig::get_queue_length(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return SRS_CONF_DEFAULT_QUEUE_LENGTH; + } + + conf = conf->get("queue_length"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_QUEUE_LENGTH; + } + + return ::atoi(conf->arg0().c_str()); +} + +SrsConfDirective* SrsConfig::get_refer(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer"); +} + +SrsConfDirective* SrsConfig::get_refer_play(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer_play"); +} + +SrsConfDirective* SrsConfig::get_refer_publish(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("refer_publish"); +} + +int SrsConfig::get_chunk_size(string vhost) +{ + if (vhost.empty()) { + return get_global_chunk_size(); + } + + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + // vhost does not specify the chunk size, + // use the global instead. + return get_global_chunk_size(); + } + + conf = conf->get("chunk_size"); + if (!conf) { + // vhost does not specify the chunk size, + // use the global instead. + return get_global_chunk_size(); + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_global_chunk_size() +{ + SrsConfDirective* conf = root->get("chunk_size"); + if (!conf) { + return SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; + } + + return ::atoi(conf->arg0().c_str()); +} + +SrsConfDirective* SrsConfig::get_forward(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("forward"); +} + +SrsConfDirective* SrsConfig::get_vhost_http_hooks(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("http_hooks"); +} + +bool SrsConfig::get_vhost_http_hooks_enabled(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return false; + } + + SrsConfDirective* enabled = conf->get("enabled"); + if (!enabled || enabled->arg0() != "on") { + return false; + } + + return true; +} + +SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_connect"); +} + +SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_close"); +} + +SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_publish"); +} + +SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_unpublish"); +} + +SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_play"); +} + +SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) +{ + SrsConfDirective* conf = get_vhost_http_hooks(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("on_stop"); +} + +bool SrsConfig::get_bw_check_enabled(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return false; + } + + conf = conf->get("bandcheck"); + if (!conf) { + return false; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +string SrsConfig::get_bw_check_key(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return ""; + } + + conf = conf->get("bandcheck"); + if (!conf) { + return ""; + } + + conf = conf->get("key"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +int SrsConfig::get_bw_check_interval_ms(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; + } + + conf = conf->get("bandcheck"); + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; + } + + conf = conf->get("interval"); + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL * 1000; + } + + return (int)(::atof(conf->arg0().c_str()) * 1000); +} + +int SrsConfig::get_bw_check_limit_kbps(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; + } + + conf = conf->get("bandcheck"); + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; + } + + conf = conf->get("limit_kbps"); + if (!conf) { + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS; + } + + return ::atoi(conf->arg0().c_str()); +} + +bool SrsConfig::get_vhost_is_edge(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + return get_vhost_is_edge(conf); +} + +bool SrsConfig::get_vhost_is_edge(SrsConfDirective* vhost) +{ + SrsConfDirective* conf = vhost; + + if (!conf) { + return false; + } + + conf = conf->get("mode"); + if (!conf || conf->arg0() != "remote") { + return false; + } + + return true; +} + +SrsConfDirective* SrsConfig::get_vhost_edge_origin(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("origin"); +} + +bool SrsConfig::get_vhost_edge_token_traverse(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return false; + } + + conf = conf->get("token_traverse"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + SrsConfDirective* transcode = conf->get("transcode"); + if (!transcode) { + return NULL; + } + + if (transcode->arg0() == scope) { + return transcode; + } + + return NULL; +} + +bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode) +{ + if (!transcode) { + return false; + } + + SrsConfDirective* conf = transcode->get("enabled"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode) +{ + if (!transcode) { + return ""; + } + + SrsConfDirective* conf = transcode->get("ffmpeg"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +vector SrsConfig::get_transcode_engines(SrsConfDirective* transcode) +{ + vector engines; + + if (!transcode) { + return engines; + } + + for (int i = 0; i < (int)transcode->directives.size(); i++) { + SrsConfDirective* conf = transcode->directives[i]; + + if (conf->name == "engine") { + engines.push_back(conf); + } + } + + return engines; +} + +bool SrsConfig::get_engine_enabled(SrsConfDirective* engine) +{ + if (!engine) { + return false; + } + + SrsConfDirective* conf = engine->get("enabled"); + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +string SrsConfig::get_engine_iformat(SrsConfDirective* engine) +{ + if (!engine) { + return SRS_CONF_DEFAULT_TRANSCODE_IFORMAT; + } + + SrsConfDirective* conf = engine->get("iformat"); + if (!conf) { + return SRS_CONF_DEFAULT_TRANSCODE_IFORMAT; + } + + return conf->arg0(); +} + +vector SrsConfig::get_engine_vfilter(SrsConfDirective* engine) +{ + vector vfilter; + + if (!engine) { + return vfilter; + } + + SrsConfDirective* conf = engine->get("vfilter"); + if (!conf) { + return vfilter; + } + + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + vfilter.push_back("-" + p->name); + vfilter.push_back(p->arg0()); + } + + return vfilter; +} + +string SrsConfig::get_engine_vcodec(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vcodec"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vbitrate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +double SrsConfig::get_engine_vfps(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vfps"); + if (!conf) { + return 0; + } + + return ::atof(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vwidth(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vwidth"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vheight(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vheight"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_vthreads(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("vthreads"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +string SrsConfig::get_engine_vprofile(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vprofile"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("vpreset"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +vector SrsConfig::get_engine_vparams(SrsConfDirective* engine) +{ + vector vparams; + + if (!engine) { + return vparams; + } + + SrsConfDirective* conf = engine->get("vparams"); + if (!conf) { + return vparams; + } + + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + vparams.push_back("-" + p->name); + vparams.push_back(p->arg0()); + } + + return vparams; +} + +string SrsConfig::get_engine_acodec(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("acodec"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +int SrsConfig::get_engine_abitrate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("abitrate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("asample_rate"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +int SrsConfig::get_engine_achannels(SrsConfDirective* engine) +{ + if (!engine) { + return 0; + } + + SrsConfDirective* conf = engine->get("achannels"); + if (!conf) { + return 0; + } + + return ::atoi(conf->arg0().c_str()); +} + +vector SrsConfig::get_engine_aparams(SrsConfDirective* engine) +{ + vector aparams; + + if (!engine) { + return aparams; + } + + SrsConfDirective* conf = engine->get("aparams"); + if (!conf) { + return aparams; + } + + for (int i = 0; i < (int)conf->directives.size(); i++) { + SrsConfDirective* p = conf->directives[i]; + if (!p) { + continue; + } + + aparams.push_back("-" + p->name); + aparams.push_back(p->arg0()); + } + + return aparams; +} + +string SrsConfig::get_engine_oformat(SrsConfDirective* engine) +{ + if (!engine) { + return SRS_CONF_DEFAULT_TRANSCODE_OFORMAT; + } + + SrsConfDirective* conf = engine->get("oformat"); + if (!conf) { + return SRS_CONF_DEFAULT_TRANSCODE_OFORMAT; + } + + return conf->arg0(); +} + +string SrsConfig::get_engine_output(SrsConfDirective* engine) +{ + if (!engine) { + return ""; + } + + SrsConfDirective* conf = engine->get("output"); + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +vector SrsConfig::get_ingesters(string vhost) +{ + vector ingeters; + + SrsConfDirective* vhost_conf = get_vhost(vhost); + if (!vhost_conf) { + return ingeters; + } + + for (int i = 0; i < (int)vhost_conf->directives.size(); i++) { + SrsConfDirective* conf = vhost_conf->directives[i]; + + if (conf->name == "ingest") { + ingeters.push_back(conf); + } + } + + return ingeters; +} + +SrsConfDirective* SrsConfig::get_ingest_by_id(string vhost, string ingest_id) +{ + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return NULL; + } + + conf = conf->get("ingest", ingest_id); + return conf; +} + +bool SrsConfig::get_ingest_enabled(SrsConfDirective* ingest) +{ + if (!ingest) { + return false; + } + + SrsConfDirective* conf = ingest->get("enabled"); + + if (!conf || conf->arg0() != "on") { + return false; + } + + return true; +} + +string SrsConfig::get_ingest_ffmpeg(SrsConfDirective* ingest) +{ + if (!ingest) { + return ""; + } + + SrsConfDirective* conf = ingest->get("ffmpeg"); + + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +string SrsConfig::get_ingest_input_type(SrsConfDirective* ingest) +{ + if (!ingest) { + return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; + } + + SrsConfDirective* conf = ingest->get("input"); + + if (!conf) { + return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; + } + + conf = conf->get("type"); + + if (!conf) { + return SRS_CONF_DEFAULT_INGEST_TYPE_FILE; + } + + return conf->arg0(); +} + +string SrsConfig::get_ingest_input_url(SrsConfDirective* ingest) +{ + if (!ingest) { + return ""; + } + + SrsConfDirective* conf = ingest->get("input"); + + if (!conf) { + return ""; + } + + conf = conf->get("url"); + + if (!conf) { + return ""; + } + + return conf->arg0(); +} + +bool SrsConfig::get_log_tank_file() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("srs_log_tank"); + if (conf && conf->arg0() == SRS_CONF_DEFAULT_LOG_TANK_CONSOLE) { + return false; + } + + return true; +} + +string SrsConfig::get_log_level() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("srs_log_level"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_LOG_LEVEL; + } + + return conf->arg0(); +} + +string SrsConfig::get_log_file() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("srs_log_file"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_LOG_FILE; + } + + return conf->arg0(); +} + +bool SrsConfig::get_ffmpeg_log_enabled() +{ + string log = get_ffmpeg_log_dir(); + return log != SRS_CONSTS_NULL_FILE; +} + +string SrsConfig::get_ffmpeg_log_dir() +{ + srs_assert(root); + + SrsConfDirective* conf = root->get("ff_log_dir"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_FF_LOG_DIR; + } + + return conf->arg0(); +} + +SrsConfDirective* SrsConfig::get_hls(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("hls"); +} + +bool SrsConfig::get_hls_enabled(string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return false; + } + + SrsConfDirective* conf = hls->get("enabled"); + + if (!conf) { + return false; + } + + if (conf->arg0() == "on") { + return true; + } + + return false; +} + +string SrsConfig::get_hls_path(string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return SRS_CONF_DEFAULT_HLS_PATH; + } + + SrsConfDirective* conf = hls->get("hls_path"); + + if (!conf) { + return SRS_CONF_DEFAULT_HLS_PATH; + } + + return conf->arg0(); +} + +double SrsConfig::get_hls_fragment(string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return SRS_CONF_DEFAULT_HLS_FRAGMENT; + } + + SrsConfDirective* conf = hls->get("hls_fragment"); + + if (!conf) { + return SRS_CONF_DEFAULT_HLS_FRAGMENT; + } + + return ::atof(conf->arg0().c_str()); +} + +double SrsConfig::get_hls_window(string vhost) +{ + SrsConfDirective* hls = get_hls(vhost); + + if (!hls) { + return SRS_CONF_DEFAULT_HLS_WINDOW; + } + + SrsConfDirective* conf = hls->get("hls_window"); + + if (!conf) { + return SRS_CONF_DEFAULT_HLS_WINDOW; + } + + return ::atof(conf->arg0().c_str()); +} + +SrsConfDirective* SrsConfig::get_dvr(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + + if (!conf) { + return NULL; + } + + return conf->get("dvr"); +} + +bool SrsConfig::get_dvr_enabled(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + if (!dvr) { + return false; + } + + SrsConfDirective* conf = dvr->get("enabled"); + + if (!conf) { + return false; + } + + if (conf->arg0() == "on") { + return true; + } + + return false; +} + +string SrsConfig::get_dvr_path(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + if (!dvr) { + return SRS_CONF_DEFAULT_DVR_PATH; + } + + SrsConfDirective* conf = dvr->get("dvr_path"); + + if (!conf) { + return SRS_CONF_DEFAULT_DVR_PATH; + } + + return conf->arg0(); +} + +string SrsConfig::get_dvr_plan(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + if (!dvr) { + return SRS_CONF_DEFAULT_DVR_PLAN; + } + + SrsConfDirective* conf = dvr->get("dvr_plan"); + + if (!conf) { + return SRS_CONF_DEFAULT_DVR_PLAN; + } + + return conf->arg0(); +} + +int SrsConfig::get_dvr_duration(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + if (!dvr) { + return SRS_CONF_DEFAULT_DVR_DURATION; + } + + SrsConfDirective* conf = dvr->get("dvr_duration"); + + if (!conf) { + return SRS_CONF_DEFAULT_DVR_DURATION; + } + + return ::atoi(conf->arg0().c_str()); +} + +bool SrsConfig::get_dvr_wait_keyframe(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + if (!dvr) { + return true; + } + + SrsConfDirective* conf = dvr->get("dvr_wait_keyframe"); + + if (!conf || conf->arg0() != "off") { + return true; + } + + return false; +} + +int SrsConfig::get_dvr_time_jitter(string vhost) +{ + SrsConfDirective* dvr = get_dvr(vhost); + + std::string time_jitter = SRS_CONF_DEFAULT_TIME_JITTER; + + if (dvr) { + SrsConfDirective* conf = dvr->get("time_jitter"); + + if (conf) { + time_jitter = conf->arg0(); + } + } + + return _srs_time_jitter_string2int(time_jitter); +} + +bool SrsConfig::get_http_api_enabled() +{ + SrsConfDirective* conf = get_http_api(); + return get_http_api_enabled(conf); +} + +SrsConfDirective* SrsConfig::get_http_api() +{ + return root->get("http_api"); +} + +bool SrsConfig::get_http_api_enabled(SrsConfDirective* conf) +{ + if (!conf) { + return false; + } + + conf = conf->get("enabled"); + if (conf && conf->arg0() == "on") { + return true; + } + + return false; +} + +int SrsConfig::get_http_api_listen() +{ + SrsConfDirective* conf = get_http_api(); + + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_API_PORT; + } + + conf = conf->get("listen"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_API_PORT; + } + + return ::atoi(conf->arg0().c_str()); +} + +bool SrsConfig::get_http_stream_enabled() +{ + SrsConfDirective* conf = get_http_stream(); + return get_http_stream_enabled(conf); +} + +SrsConfDirective* SrsConfig::get_http_stream() +{ + return root->get("http_stream"); +} + +bool SrsConfig::get_http_stream_enabled(SrsConfDirective* conf) +{ + if (!conf) { + return false; + } + + conf = conf->get("enabled"); + if (conf && conf->arg0() == "on") { + return true; + } + + return false; +} + +int SrsConfig::get_http_stream_listen() +{ + SrsConfDirective* conf = get_http_stream(); + + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_STREAM_PORT; + } + + conf = conf->get("listen"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_STREAM_PORT; + } + + return ::atoi(conf->arg0().c_str()); +} + +string SrsConfig::get_http_stream_dir() +{ + SrsConfDirective* conf = get_http_stream(); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + conf = conf->get("dir"); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + if (conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + return conf->arg0(); +} + +bool SrsConfig::get_vhost_http_enabled(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return false; + } + + conf = conf->get("http"); + if (!conf) { + return false; + } + + conf = conf->get("enabled"); + if (!conf) { + return false; + } + + if (conf->arg0() == "on") { + return true; + } + + return false; +} + +string SrsConfig::get_vhost_http_mount(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_MOUNT; + } + + conf = conf->get("http"); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_MOUNT; + } + + conf = conf->get("mount"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_MOUNT; + } + + return conf->arg0(); +} + +string SrsConfig::get_vhost_http_dir(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + conf = conf->get("http"); + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + conf = conf->get("dir"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_DIR; + } + + return conf->arg0(); +} + +SrsConfDirective* SrsConfig::get_heartbeart() +{ + return root->get("heartbeat"); +} + +bool SrsConfig::get_heartbeat_enabled() +{ + SrsConfDirective* conf = get_heartbeart(); + + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0() != "on") { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_ENABLED; + } + + return true; +} + +int64_t SrsConfig::get_heartbeat_interval() +{ + SrsConfDirective* conf = get_heartbeart(); + + if (!conf) { + return (int64_t)(SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL * 1000); + } + conf = conf->get("interval"); + if (!conf || conf->arg0().empty()) { + return (int64_t)(SRS_CONF_DEFAULT_HTTP_HEAETBEAT_INTERVAL * 1000); + } + + return (int64_t)(::atof(conf->arg0().c_str()) * 1000); +} + +string SrsConfig::get_heartbeat_url() +{ + SrsConfDirective* conf = get_heartbeart(); + + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL; + } + + conf = conf->get("url"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL; + } + + return conf->arg0(); +} + +string SrsConfig::get_heartbeat_device_id() +{ + SrsConfDirective* conf = get_heartbeart(); + + if (!conf) { + return ""; + } + + conf = conf->get("device_id"); + if (!conf || conf->arg0().empty()) { + return ""; + } + + return conf->arg0(); +} + +bool SrsConfig::get_heartbeat_summaries() +{ + SrsConfDirective* conf = get_heartbeart(); + + if (!conf) { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES; + } + + conf = conf->get("summaries"); + if (!conf || conf->arg0() != "on") { + return SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES; + } + + return true; +} + +SrsConfDirective* SrsConfig::get_stats() +{ + return root->get("stats"); +} + +int SrsConfig::get_stats_network() +{ + SrsConfDirective* conf = get_stats(); + + if (!conf) { + return SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX; + } + + conf = conf->get("network"); + if (!conf || conf->arg0().empty()) { + return SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX; + } + + return ::atoi(conf->arg0().c_str()); +} + +SrsConfDirective* SrsConfig::get_stats_disk_device() +{ + SrsConfDirective* conf = get_stats(); + + if (!conf) { + return NULL; + } + + conf = conf->get("disk"); + if (!conf || conf->args.size() == 0) { + return NULL; + } + + return conf; +} + +namespace _srs_internal +{ + SrsConfigBuffer::SrsConfigBuffer() + { + line = 1; + + pos = last = start = NULL; + end = start; + } + + SrsConfigBuffer::~SrsConfigBuffer() + { + srs_freep(start); + } + + int SrsConfigBuffer::fullfill(const char* filename) + { + int ret = ERROR_SUCCESS; + + SrsFileReader reader; + + // open file reader. + if ((ret = reader.open(filename)) != ERROR_SUCCESS) { + srs_error("open conf file error. ret=%d", ret); + return ret; + } + + // read all. + int filesize = (int)reader.filesize(); + + // create buffer + srs_freep(start); + pos = last = start = new char[filesize]; + end = start + filesize; + + // read total content from file. + ssize_t nread = 0; + if ((ret = reader.read(start, filesize, &nread)) != ERROR_SUCCESS) { + srs_error("read file read error. expect %d, actual %d bytes, ret=%d", + filesize, nread, ret); + return ret; + } + + return ret; + } + + bool SrsConfigBuffer::empty() + { + return pos >= end; + } +}; + +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b) +{ + // both NULL, equal. + if (!a && !b) { + return true; + } + + if (!a || !b) { + return false; + } + + if (a->name != b->name) { + return false; + } + + if (a->args.size() != b->args.size()) { + return false; + } + + for (int i = 0; i < (int)a->args.size(); i++) { + if (a->args.at(i) != b->args.at(i)) { + return false; + } + } + + if (a->directives.size() != b->directives.size()) { + return false; + } + + for (int i = 0; i < (int)a->directives.size(); i++) { + SrsConfDirective* a0 = a->at(i); + SrsConfDirective* b0 = b->at(i); + + if (!srs_directive_equals(a0, b0)) { + return false; + } + } + + return true; +} +