配置文件如下
listen 1935;
chunk_size 65000;
log_dir ./objs/logs;
max_connections 2000;
vhost __defaultVhost__ {
enabled on;
gop_cache on;
queue_length 30;
forward 127.0.0.1:19350;
hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 5;
hls_window 30;
}
}
vhost aaa {
enabled on;
gop_cache on;
queue_length 30;
forward 127.0.0.1:19360;
hls {
enabled on;
hls_path ./objs/nginx/html;
hls_fragment 5;
hls_window 30;
}
http_hooks {
enabled on;
on_connect http://127.0.0.1:8085/api/v1/clients;
on_close http://127.0.0.1:8085/api/v1/clients;
on_publish http://127.0.0.1:8085/api/v1/streams;
on_unpublish http://127.0.0.1:8085/api/v1/streams;
on_play http://127.0.0.1:8085/api/v1/sessions;
on_stop http://127.0.0.1:8085/api/v1/sessions;
}
}
main.cpp
int main(int argc, char** argv){
config->parse_options(argc,argv);
return ret;
}
config.hpp
#ifndef CONIFG_HPP
#define CONIFG_HPP
#include "core.hpp"
#include <vector>
#include <string>
#include "srs_core_reload.hpp"
//default vhost for rtmp
class SrsFileBuffer;
class SrsConfDirective{
public:
int conf_line;
std::string name;
std::vector<std::string> args;
std::vector<SrsConfDirective*> directives;
public:
SrsConfDirective();
virtual ~SrsConfDirective();
public:
virtual int parse(const char* filename);
public:
enum SrsDirectiveType{parse_file,parse_block};
virtual int parse_conf(SrsFileBuffer* buffer,SrsDirectiveType type);
virtual int read_token(SrsFileBuffer* buffer,std::vector<std::string>& args);
};
class SrsConfig
{
private:
bool show_help;
bool show_version;
std::string config_file;
SrsConfDirective* root;
std::vector<ISrsReloadHandler*> subscribes;
public:
SrsConfig();
virtual ~SrsConfig();
public:
virtual int reload();
virtual void subscribe(ISrsReloadHandler* handler);
virtual void unsubsribe(ISrsReloadHandler* handler);
public:
virtual int parse_options(int argc,char** argv);
virtual void printtree(SrsConfDirective *root);
private:
virtual int parse_file();
virtual int parse_argv(int& i,char** argv);
virtual void print_help(char** argv);
};
bool srs_dective_equals(SrsConfDirective* a,SrsConfDirective* b);
extern SrsConfig *config;
#endif
config.cpp
#include "srs_core_config.hpp"
#include "srs_core_error.hpp"
#include "srs_core_log.hpp"
#include "srs_core.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// file operations.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define FILE_OFFSET(fd) lseek(fd,0,SEEK_CUR)
int64_t FILE_SIZE(int fd)
{
int64_t pre = FILE_OFFSET(fd);
int64_t pos = lseek(fd,0,SEEK_END);
lseek(fd,pre,SEEK_SET);
return pos;
}
#define LF (char)0x0a
#define CR (char)0x0d
bool is_common_space(char ch)
{
return (ch==' '||ch=='\t'||ch==CR||ch==LF);
}
class SrsFileBuffer
{
private:
// last available position
char* last;
// end of buffer
char* end;
// start of buffer
char* start;
public:
//current consumed position.
char* pos;
//current parsed line.
int line;
SrsFileBuffer();
virtual ~SrsFileBuffer();
virtual int fullfill(const char* filename);
virtual bool empty();
};
SrsFileBuffer::SrsFileBuffer()
{
line = 0;
pos = last = start = NULL;
end = start;
}
SrsFileBuffer::~SrsFileBuffer()
{
srs_freepa(start);
}
int SrsFileBuffer::fullfill(const char* filename)
{
int ret = ERROR_SUCCESS;
int fd = -1;
int nread = 0;
int filesize = 0;
if((fd=::open(filename,O_RDONLY,0))<0){
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("open conf file error. ret=%d", ret);
goto finish;
}
if((filesize = FILE_SIZE(fd)-FILE_OFFSET(fd))<=0){
ret = ERROR_SYSTEM_CONFIG_EOF;
srs_error("read conf file error. ret=%d", ret);
goto finish;
}
srs_freepa(start);
pos = last = start = new char[filesize];
end = start + filesize;
if((nread = read(fd, start, filesize)) != filesize)
{
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("read file read error. expect %d, actual %d bytes,ret=%d",filesize, nread,ret);
goto finish;
}
finish:
if(fd>0){
::close(fd);
}
return ret;
}
bool SrsFileBuffer::empty(){
return pos >= end;
}
SrsConfDirective::SrsConfDirective()
{
}
SrsConfDirective::~SrsConfDirective()
{
std::vector<SrsConfDirective*>::iterator it;
for(it = directives.begin();it!=directives.end();++it){
SrsConfDirective* directive = * it;
srs_freep(directive);
}
directives.clear();
}
void SrsConfig::printtree(SrsConfDirective *root){
std::vector<SrsConfDirective*>::iterator it;
std::vector<std::string>::iterator subit;
cout << "name: "<< root->name << " value:";
for(subit=root->args.begin();subit!=root->args.end();++subit){
cout << " " <<*subit <<" ";
}
cout << endl;
if(!root->directives.empty()){
cout << "======" << root->name <<" sub =======" <<endl;
for(it = root->directives.begin();it!=root->directives.end();++it){
SrsConfDirective* directive = *it;
printtree(directive);
}
cout << "======" << root->name <<" sub end =======" <<endl;
}
}
int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
{
int ret = ERROR_SUCCESS;
while(true){
std::vector<string> args;
ret = read_token(buffer,args);
/**
ret maybe:
ERROR_SYSTEM_CONFIG_INVALID error
ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found
ERROR_SYSTEM_CONFIG_BLOCK_START toket 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 \"}\"",buffer->line);
return ret;
}
return ERROR_SUCCESS;
}
if(ret == ERROR_SYSTEM_CONFIG_EOF){
if(type == parse_block){
//srs_error("line %d : unexpected end of file, expecting\"}\"",buffer->line);
return ret;
}
return ERROR_SUCCESS;
}
if(args.empty()){
srs_error("line %d: empty directive.",buffer->line);
return ret;
}
SrsConfDirective* directive = new SrsConfDirective();
directive->conf_line = buffer->line;
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;
}
int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<string>& args)
{
int ret = ERROR_SUCCESS;
char* pstart = buffer->pos;
int startline = buffer->line;
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_error("end of file. ret=%d",ret);
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;
startline = buffer->line;
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;
}
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 {
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* word = new char[len];
memcpy(word,pstart,len);
word[len-1]=0;
string word_str = word;
if(!word_str.empty()){
args.push_back(word_str);
}
srs_freepa(word);
if(ch==';'){
return ERROR_SYSTEM_CONFIG_DIRECTIVE;
}
if(ch=='{'){
return ERROR_SYSTEM_CONFIG_BLOCK_START;
}
}
}
}
return ret;
}
int SrsConfDirective::parse(const char* filename)
{
int ret = ERROR_SUCCESS;
SrsFileBuffer buffer;
if((ret=buffer.fullfill(filename))!=ERROR_SUCCESS){
return ret;
}
return parse_conf(&buffer,parse_file);
}
SrsConfig* config = new SrsConfig();
SrsConfig::SrsConfig()
{
show_help = false;
show_version = false;
root = new SrsConfDirective();
root->conf_line = 0;
root->name = "root";
}
SrsConfig::~SrsConfig()
{
//SrsConfig::printtree(root);
delete root;
}
int SrsConfig::parse_options(int argc,char** argv)
{
int ret = ERROR_SUCCESS;
for(int i=1;i<argc;i++){
if((ret=parse_argv(i,argv))!=ERROR_SUCCESS){
return ret;
}
}
if(show_help){
print_help(argv);
}
if(show_version){
printf("%s\n",RTMP_SIG_SRS_VERSION);
}
if(show_help || show_version){
exit(0);
}
return parse_file();
}
int SrsConfig::parse_file()
{
int ret = ERROR_SUCCESS;
if(config_file.empty()){
//return ERROR_SYSTEM_CONFIG_INVALID;
}
if(config_file.empty()){
return ERROR_SYSTEM_CONFIG_INVALID;
}
config_file = CONFIG_DIRECTORY + config_file;
//cout << config_file << endl;
if((ret=root->parse(config_file.c_str()))!=ERROR_SUCCESS){
return ret;
}
return ret;
}
void SrsConfig::print_help(char** argv){
printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION
" Copyright (c) 2013 winlin\n"
"Contributors: "RTMP_SIG_SRS_CONTRIBUTOR"\n"
"Build: "SRS_BUILD_DATE" Configuration: "SRS_CONFIGURE"\n"
"Usage: %s [-h?Vv] [-c <filename>]\n"
"\n"
"Options:\n"
" -?-h : show help\n"
" -v-V : show version and exit\n"
" -c filename : set configuration file\n"
"\n",
argv[0]);
}
int SrsConfig::parse_argv(int& i, char** argv){
int ret = ERROR_SUCCESS;
char* p = argv[i];
if(p==NULL)
return ERROR_SYSTEM_CONFIG_INVALID;
if(*p++!='-'){
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("invalid options(index=%d,value=%s), must start with - ,see help:%s -h,ret=%d",i,argv[i],argv[0],ret );
return ret;
}
while(*p){
switch(*p++){
case '?':
case 'h':
show_help = true;
break;
case 'v':
case 'V':
show_version = true;
break;
case 'c':
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::subscribe(ISrsReloadHandler* handler)
{
}
void SrsConfig::unsubsribe(ISrsReloadHandler* handler)
{
}
int SrsConfig::reload()
{
return 0;
}