SRS学习笔记2
Posted 燕十三
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SRS学习笔记2相关的知识,希望对你有一定的参考价值。
main函数分析:
位于main\srs_main_server.cpp
// never use srs log(srs_trace, srs_error, etc) before config parse the option, // which will load the log config and apply it. if ((ret = _srs_config->parse_options(argc, argv)) != ERROR_SUCCESS) { return ret; }
先调用 SrsConfig类的 parse_options函数解析命令行参数
位于app\srs_app_config.cpp
// 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(" "); } } // 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); } // first hello message. srs_trace(_srs_version); 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; }
parse_options 函数的作用如下
1. 将命令行参数保存在成员变量_argv(std::string),参数之间用空格分隔.
2. 调用 parse_argv函数对命令行参数进行分析,并设置相应的标志变量,
show_help(显示帮助信息后退出)
test_conf(测试配置文件后退出)
show_version(显示版本信息后退出)
config_file(保存从命令行传入的配置文件路径)
3. show_help和show_version都等于false,调用 parse_file函数
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_config函数检查配置信息
4.检查写日志到控制台还是文件,如果是文件,检查文件名是否不为空
//////////////////////////////////////////////////////////////////////// // 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"); } }
parse_file函数
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); }
1. 调用 SrsConfigBuffer函数 fullfill填充缓冲区
2. 调用 parse_buffer解析配置
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_freepa(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; }
调用SrsFileReader类读配置文件内容到SrsConfigBuffer类的内部缓冲区,设置start,end,pos.last指针
SrsFileReader类位于kernel\srs_kernel_file.cpp
int SrsConfig::parse_buffer(SrsConfigBuffer* buffer) { int ret = ERROR_SUCCESS; if ((ret = root->parse(buffer)) != ERROR_SUCCESS) { return ret; } // mock by dolphin mode. // for the dolphin will start srs with specified params. if (dolphin) { // for RTMP. set_config_directive(root, "listen", dolphin_rtmp_port); // for HTTP set_config_directive(root, "http_server", ""); SrsConfDirective* http_server = root->get("http_server"); set_config_directive(http_server, "enabled", "on"); set_config_directive(http_server, "listen", dolphin_http_port); // others. set_config_directive(root, "daemon", "off"); set_config_directive(root, "srs_log_tank", "console"); } return ret; }
root变量的类型SrsConfDirective
int SrsConfDirective::parse(SrsConfigBuffer* buffer) { return parse_conf(buffer, parse_file); }
parse_file枚举变量
/** * the directive parsing type. */ enum SrsDirectiveType { /** * the root directives, parsing file. */ parse_file, /** * for each direcitve, parsing text block. */ parse_block // see: ngx_conf_parseint SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type){int ret = ERROR_SUCCESS;
while (true) { std::vector<string> args; int line_start = 0; ret = read_token(buffer, args, line_start); // 从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) {
// 此时没有遇到 { type 是 parse_file
// 相当于 } 没有匹配的 {
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<string>& 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 == SRS_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 = (int)(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_freepa(aword); if (ch == ‘;‘) { return ERROR_SYSTEM_CONFIG_DIRECTIVE; } if (ch == ‘{‘) { return ERROR_SYSTEM_CONFIG_BLOCK_START; } } } } return ret; }
至此 parse_file函数分析完毕,下一篇分析check_config函数
未完待续...
以上是关于SRS学习笔记2的主要内容,如果未能解决你的问题,请参考以下文章