Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
胡斌
/
srs
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
winlin
2013-11-24 16:49:00 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
ce021b25c718c5bb00eb9f52a5d68d80042d2f69
ce021b25
1 parent
bb775ef7
update the config file format
隐藏空白字符变更
内嵌
并排对比
正在显示
2 个修改的文件
包含
906 行增加
和
906 行删除
trunk/src/core/srs_core_config.cpp
trunk/src/core/srs_core_config.hpp
trunk/src/core/srs_core_config.cpp
100755 → 100644
查看文件 @
ce021b2
/*
The MIT License (MIT)
Copyright (c) 2013 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <srs_core_config.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 <vector>
#include <algorithm>
#include <srs_core_error.hpp>
#include <srs_core_log.hpp>
#include <srs_core_autofree.hpp>
#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
);
}
#define CONF_BUFFER_SIZE 4096
SrsFileBuffer
::
SrsFileBuffer
()
{
fd
=
-
1
;
line
=
0
;
pos
=
last
=
start
=
new
char
[
CONF_BUFFER_SIZE
];
end
=
start
+
CONF_BUFFER_SIZE
;
}
SrsFileBuffer
::~
SrsFileBuffer
()
{
if
(
fd
>
0
)
{
close
(
fd
);
}
srs_freepa
(
start
);
}
int
SrsFileBuffer
::
open
(
const
char
*
filename
)
{
assert
(
fd
==
-
1
);
if
((
fd
=
::
open
(
filename
,
O_RDONLY
,
0
))
<
0
)
{
srs_error
(
"open conf file error. errno=%d(%s)"
,
errno
,
strerror
(
errno
));
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
line
=
1
;
return
ERROR_SUCCESS
;
}
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
();
}
std
::
string
SrsConfDirective
::
arg0
()
{
if
(
args
.
size
()
>
0
)
{
return
args
.
at
(
0
);
}
return
""
;
}
std
::
string
SrsConfDirective
::
arg1
()
{
if
(
args
.
size
()
>
1
)
{
return
args
.
at
(
1
);
}
return
""
;
}
std
::
string
SrsConfDirective
::
arg2
()
{
if
(
args
.
size
()
>
2
)
{
return
args
.
at
(
2
);
}
return
""
;
}
SrsConfDirective
*
SrsConfDirective
::
at
(
int
index
)
{
return
directives
.
at
(
index
);
}
SrsConfDirective
*
SrsConfDirective
::
get
(
std
::
string
_name
)
{
std
::
vector
<
SrsConfDirective
*>::
iterator
it
;
for
(
it
=
directives
.
begin
();
it
!=
directives
.
end
();
++
it
)
{
SrsConfDirective
*
directive
=
*
it
;
if
(
directive
->
name
==
_name
)
{
return
directive
;
}
}
return
NULL
;
}
int
SrsConfDirective
::
parse
(
const
char
*
filename
)
{
int
ret
=
ERROR_SUCCESS
;
SrsFileBuffer
buffer
;
if
((
ret
=
buffer
.
open
(
filename
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
parse_conf
(
&
buffer
,
parse_file
);
}
// see: ngx_conf_parse
int
SrsConfDirective
::
parse_conf
(
SrsFileBuffer
*
buffer
,
SrsDirectiveType
type
)
{
int
ret
=
ERROR_SUCCESS
;
while
(
true
)
{
std
::
vector
<
std
::
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 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
\"
}
\"
"
,
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
;
}
// build directive tree.
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
;
}
// see: ngx_conf_read_token
int
SrsConfDirective
::
read_token
(
SrsFileBuffer
*
buffer
,
std
::
vector
<
std
::
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
((
ret
=
refill_buffer
(
buffer
,
d_quoted
,
s_quoted
,
startline
,
pstart
))
!=
ERROR_SUCCESS
)
{
if
(
!
args
.
empty
()
||
!
last_space
)
{
srs_error
(
"line %d: unexpected end of file, expecting ; or
\"
}
\"
"
,
buffer
->
line
);
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
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
;
}
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
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
;
args
.
push_back
(
word
);
srs_freepa
(
word
);
if
(
ch
==
';'
)
{
return
ERROR_SYSTEM_CONFIG_DIRECTIVE
;
}
if
(
ch
==
'{'
)
{
return
ERROR_SYSTEM_CONFIG_BLOCK_START
;
}
}
}
}
return
ret
;
}
int
SrsConfDirective
::
refill_buffer
(
SrsFileBuffer
*
buffer
,
bool
d_quoted
,
bool
s_quoted
,
int
startline
,
char
*&
pstart
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
buffer
->
pos
<
buffer
->
last
)
{
return
ret
;
}
int
size
=
FILE_SIZE
(
buffer
->
fd
)
-
FILE_OFFSET
(
buffer
->
fd
);
if
(
size
<=
0
)
{
return
ERROR_SYSTEM_CONFIG_EOF
;
}
int
len
=
buffer
->
pos
-
buffer
->
start
;
if
(
len
>=
CONF_BUFFER_SIZE
)
{
buffer
->
line
=
startline
;
if
(
!
d_quoted
&&
!
s_quoted
)
{
srs_error
(
"line %d: too long parameter
\"
%*s...
\"
started"
,
buffer
->
line
,
10
,
buffer
->
start
);
}
else
{
srs_error
(
"line %d: too long parameter, "
"probably missing terminating '%c' character"
,
buffer
->
line
,
d_quoted
?
'"'
:
'\''
);
}
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
if
(
len
)
{
memmove
(
buffer
->
start
,
pstart
,
len
);
}
size
=
srs_min
(
size
,
buffer
->
end
-
(
buffer
->
start
+
len
));
int
n
=
read
(
buffer
->
fd
,
buffer
->
start
+
len
,
size
);
if
(
n
!=
size
)
{
srs_error
(
"read file read error. expect %d, actual %d bytes."
,
size
,
n
);
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
buffer
->
pos
=
buffer
->
start
+
len
;
buffer
->
last
=
buffer
->
pos
+
n
;
pstart
=
buffer
->
start
;
return
ret
;
}
SrsConfig
*
config
=
new
SrsConfig
();
SrsConfig
::
SrsConfig
()
{
show_help
=
false
;
show_version
=
false
;
root
=
new
SrsConfDirective
();
root
->
conf_line
=
0
;
root
->
name
=
"root"
;
}
SrsConfig
::~
SrsConfig
()
{
srs_freep
(
root
);
}
int
SrsConfig
::
reload
()
{
int
ret
=
ERROR_SUCCESS
;
SrsConfig
conf
;
if
((
ret
=
conf
.
parse_file
(
config_file
.
c_str
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"config reloader parse file failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"config reloader parse file success."
);
// store current root to old_root,
// and reap the root from conf to current root.
SrsConfDirective
*
old_root
=
root
;
SrsAutoFree
(
SrsConfDirective
,
old_root
,
false
);
root
=
conf
.
root
;
conf
.
root
=
NULL
;
// merge config.
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
// merge config: listen
if
(
!
srs_directive_equals
(
root
->
get
(
"listen"
),
old_root
->
get
(
"listen"
)))
{
for
(
it
=
subscribes
.
begin
();
it
!=
subscribes
.
end
();
++
it
)
{
SrsReloadHandler
*
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: pithy_print
if
(
!
srs_directive_equals
(
root
->
get
(
"pithy_print"
),
old_root
->
get
(
"pithy_print"
)))
{
for
(
it
=
subscribes
.
begin
();
it
!=
subscribes
.
end
();
++
it
)
{
SrsReloadHandler
*
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."
);
}
return
ret
;
}
void
SrsConfig
::
subscribe
(
SrsReloadHandler
*
handler
)
{
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
it
=
std
::
find
(
subscribes
.
begin
(),
subscribes
.
end
(),
handler
);
if
(
it
!=
subscribes
.
end
())
{
return
;
}
subscribes
.
push_back
(
handler
);
}
void
SrsConfig
::
unsubscribe
(
SrsReloadHandler
*
handler
)
{
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
it
=
std
::
find
(
subscribes
.
begin
(),
subscribes
.
end
(),
handler
);
if
(
it
==
subscribes
.
end
())
{
return
;
}
subscribes
.
erase
(
it
);
}
// see: ngx_get_options
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
);
}
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
;
}
return
parse_file
(
config_file
.
c_str
());
}
SrsConfDirective
*
SrsConfig
::
get_vhost
(
std
::
string
vhost
)
{
srs_assert
(
root
);
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
conf
->
name
!=
"vhost"
)
{
continue
;
}
if
(
conf
->
arg0
()
==
vhost
)
{
return
conf
;
}
}
if
(
vhost
!=
RTMP_VHOST_DEFAULT
)
{
return
get_vhost
(
RTMP_VHOST_DEFAULT
);
}
return
NULL
;
}
SrsConfDirective
*
SrsConfig
::
get_gop_cache
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"gop_cache"
);
}
SrsConfDirective
*
SrsConfig
::
get_hls
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"hls"
);
}
SrsConfDirective
*
SrsConfig
::
get_hls_path
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"hls_path"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer_play
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer_play"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer_publish
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer_publish"
);
}
SrsConfDirective
*
SrsConfig
::
get_listen
()
{
return
root
->
get
(
"listen"
);
}
SrsConfDirective
*
SrsConfig
::
get_chunk_size
()
{
return
root
->
get
(
"chunk_size"
);
}
SrsConfDirective
*
SrsConfig
::
get_pithy_print_publish
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
NULL
;
}
return
pithy
->
get
(
"publish"
);
}
SrsConfDirective
*
SrsConfig
::
get_pithy_print_play
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
NULL
;
}
return
pithy
->
get
(
"play"
);
}
int
SrsConfig
::
parse_file
(
const
char
*
filename
)
{
int
ret
=
ERROR_SUCCESS
;
config_file
=
filename
;
if
(
config_file
.
empty
())
{
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
if
((
ret
=
root
->
parse
(
config_file
.
c_str
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsConfDirective
*
conf
=
NULL
;
if
((
conf
=
get_listen
())
==
NULL
||
conf
->
args
.
size
()
==
0
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"line %d: conf error, "
"directive
\"
listen
\"
is empty, ret=%d"
,
(
conf
?
conf
->
conf_line
:
0
),
ret
);
return
ret
;
}
return
ret
;
}
int
SrsConfig
::
parse_argv
(
int
&
i
,
char
**
argv
)
{
int
ret
=
ERROR_SUCCESS
;
char
*
p
=
argv
[
i
];
if
(
*
p
++
!=
'-'
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"invalid options(index=%d, value=%s), "
"must starts 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
::
print_help
(
char
**
argv
)
{
printf
(
RTMP_SIG_SRS_NAME
" "
RTMP_SIG_SRS_VERSION
" Copyright (c) 2013 winlin
\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
"
RTMP_SIG_SRS_WEB
"
\n
"
RTMP_SIG_SRS_URL
"
\n
"
"Email: "
RTMP_SIG_SRS_EMAIL
"
\n
"
,
argv
[
0
]);
}
bool
srs_directive_equals
(
SrsConfDirective
*
a
,
SrsConfDirective
*
b
)
{
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 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 <srs_core_config.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 <vector>
#include <algorithm>
#include <srs_core_error.hpp>
#include <srs_core_log.hpp>
#include <srs_core_autofree.hpp>
#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
);
}
#define CONF_BUFFER_SIZE 4096
SrsFileBuffer
::
SrsFileBuffer
()
{
fd
=
-
1
;
line
=
0
;
pos
=
last
=
start
=
new
char
[
CONF_BUFFER_SIZE
];
end
=
start
+
CONF_BUFFER_SIZE
;
}
SrsFileBuffer
::~
SrsFileBuffer
()
{
if
(
fd
>
0
)
{
close
(
fd
);
}
srs_freepa
(
start
);
}
int
SrsFileBuffer
::
open
(
const
char
*
filename
)
{
assert
(
fd
==
-
1
);
if
((
fd
=
::
open
(
filename
,
O_RDONLY
,
0
))
<
0
)
{
srs_error
(
"open conf file error. errno=%d(%s)"
,
errno
,
strerror
(
errno
));
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
line
=
1
;
return
ERROR_SUCCESS
;
}
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
();
}
std
::
string
SrsConfDirective
::
arg0
()
{
if
(
args
.
size
()
>
0
)
{
return
args
.
at
(
0
);
}
return
""
;
}
std
::
string
SrsConfDirective
::
arg1
()
{
if
(
args
.
size
()
>
1
)
{
return
args
.
at
(
1
);
}
return
""
;
}
std
::
string
SrsConfDirective
::
arg2
()
{
if
(
args
.
size
()
>
2
)
{
return
args
.
at
(
2
);
}
return
""
;
}
SrsConfDirective
*
SrsConfDirective
::
at
(
int
index
)
{
return
directives
.
at
(
index
);
}
SrsConfDirective
*
SrsConfDirective
::
get
(
std
::
string
_name
)
{
std
::
vector
<
SrsConfDirective
*>::
iterator
it
;
for
(
it
=
directives
.
begin
();
it
!=
directives
.
end
();
++
it
)
{
SrsConfDirective
*
directive
=
*
it
;
if
(
directive
->
name
==
_name
)
{
return
directive
;
}
}
return
NULL
;
}
int
SrsConfDirective
::
parse
(
const
char
*
filename
)
{
int
ret
=
ERROR_SUCCESS
;
SrsFileBuffer
buffer
;
if
((
ret
=
buffer
.
open
(
filename
))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
return
parse_conf
(
&
buffer
,
parse_file
);
}
// see: ngx_conf_parse
int
SrsConfDirective
::
parse_conf
(
SrsFileBuffer
*
buffer
,
SrsDirectiveType
type
)
{
int
ret
=
ERROR_SUCCESS
;
while
(
true
)
{
std
::
vector
<
std
::
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 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
\"
}
\"
"
,
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
;
}
// build directive tree.
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
;
}
// see: ngx_conf_read_token
int
SrsConfDirective
::
read_token
(
SrsFileBuffer
*
buffer
,
std
::
vector
<
std
::
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
((
ret
=
refill_buffer
(
buffer
,
d_quoted
,
s_quoted
,
startline
,
pstart
))
!=
ERROR_SUCCESS
)
{
if
(
!
args
.
empty
()
||
!
last_space
)
{
srs_error
(
"line %d: unexpected end of file, expecting ; or
\"
}
\"
"
,
buffer
->
line
);
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
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
;
}
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
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
;
args
.
push_back
(
word
);
srs_freepa
(
word
);
if
(
ch
==
';'
)
{
return
ERROR_SYSTEM_CONFIG_DIRECTIVE
;
}
if
(
ch
==
'{'
)
{
return
ERROR_SYSTEM_CONFIG_BLOCK_START
;
}
}
}
}
return
ret
;
}
int
SrsConfDirective
::
refill_buffer
(
SrsFileBuffer
*
buffer
,
bool
d_quoted
,
bool
s_quoted
,
int
startline
,
char
*&
pstart
)
{
int
ret
=
ERROR_SUCCESS
;
if
(
buffer
->
pos
<
buffer
->
last
)
{
return
ret
;
}
int
size
=
FILE_SIZE
(
buffer
->
fd
)
-
FILE_OFFSET
(
buffer
->
fd
);
if
(
size
<=
0
)
{
return
ERROR_SYSTEM_CONFIG_EOF
;
}
int
len
=
buffer
->
pos
-
buffer
->
start
;
if
(
len
>=
CONF_BUFFER_SIZE
)
{
buffer
->
line
=
startline
;
if
(
!
d_quoted
&&
!
s_quoted
)
{
srs_error
(
"line %d: too long parameter
\"
%*s...
\"
started"
,
buffer
->
line
,
10
,
buffer
->
start
);
}
else
{
srs_error
(
"line %d: too long parameter, "
"probably missing terminating '%c' character"
,
buffer
->
line
,
d_quoted
?
'"'
:
'\''
);
}
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
if
(
len
)
{
memmove
(
buffer
->
start
,
pstart
,
len
);
}
size
=
srs_min
(
size
,
buffer
->
end
-
(
buffer
->
start
+
len
));
int
n
=
read
(
buffer
->
fd
,
buffer
->
start
+
len
,
size
);
if
(
n
!=
size
)
{
srs_error
(
"read file read error. expect %d, actual %d bytes."
,
size
,
n
);
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
buffer
->
pos
=
buffer
->
start
+
len
;
buffer
->
last
=
buffer
->
pos
+
n
;
pstart
=
buffer
->
start
;
return
ret
;
}
SrsConfig
*
config
=
new
SrsConfig
();
SrsConfig
::
SrsConfig
()
{
show_help
=
false
;
show_version
=
false
;
root
=
new
SrsConfDirective
();
root
->
conf_line
=
0
;
root
->
name
=
"root"
;
}
SrsConfig
::~
SrsConfig
()
{
srs_freep
(
root
);
}
int
SrsConfig
::
reload
()
{
int
ret
=
ERROR_SUCCESS
;
SrsConfig
conf
;
if
((
ret
=
conf
.
parse_file
(
config_file
.
c_str
()))
!=
ERROR_SUCCESS
)
{
srs_error
(
"config reloader parse file failed. ret=%d"
,
ret
);
return
ret
;
}
srs_info
(
"config reloader parse file success."
);
// store current root to old_root,
// and reap the root from conf to current root.
SrsConfDirective
*
old_root
=
root
;
SrsAutoFree
(
SrsConfDirective
,
old_root
,
false
);
root
=
conf
.
root
;
conf
.
root
=
NULL
;
// merge config.
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
// merge config: listen
if
(
!
srs_directive_equals
(
root
->
get
(
"listen"
),
old_root
->
get
(
"listen"
)))
{
for
(
it
=
subscribes
.
begin
();
it
!=
subscribes
.
end
();
++
it
)
{
SrsReloadHandler
*
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: pithy_print
if
(
!
srs_directive_equals
(
root
->
get
(
"pithy_print"
),
old_root
->
get
(
"pithy_print"
)))
{
for
(
it
=
subscribes
.
begin
();
it
!=
subscribes
.
end
();
++
it
)
{
SrsReloadHandler
*
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."
);
}
return
ret
;
}
void
SrsConfig
::
subscribe
(
SrsReloadHandler
*
handler
)
{
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
it
=
std
::
find
(
subscribes
.
begin
(),
subscribes
.
end
(),
handler
);
if
(
it
!=
subscribes
.
end
())
{
return
;
}
subscribes
.
push_back
(
handler
);
}
void
SrsConfig
::
unsubscribe
(
SrsReloadHandler
*
handler
)
{
std
::
vector
<
SrsReloadHandler
*>::
iterator
it
;
it
=
std
::
find
(
subscribes
.
begin
(),
subscribes
.
end
(),
handler
);
if
(
it
==
subscribes
.
end
())
{
return
;
}
subscribes
.
erase
(
it
);
}
// see: ngx_get_options
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
);
}
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
;
}
return
parse_file
(
config_file
.
c_str
());
}
SrsConfDirective
*
SrsConfig
::
get_vhost
(
std
::
string
vhost
)
{
srs_assert
(
root
);
for
(
int
i
=
0
;
i
<
(
int
)
root
->
directives
.
size
();
i
++
)
{
SrsConfDirective
*
conf
=
root
->
at
(
i
);
if
(
conf
->
name
!=
"vhost"
)
{
continue
;
}
if
(
conf
->
arg0
()
==
vhost
)
{
return
conf
;
}
}
if
(
vhost
!=
RTMP_VHOST_DEFAULT
)
{
return
get_vhost
(
RTMP_VHOST_DEFAULT
);
}
return
NULL
;
}
SrsConfDirective
*
SrsConfig
::
get_gop_cache
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"gop_cache"
);
}
SrsConfDirective
*
SrsConfig
::
get_hls
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"hls"
);
}
SrsConfDirective
*
SrsConfig
::
get_hls_path
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"hls_path"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer_play
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer_play"
);
}
SrsConfDirective
*
SrsConfig
::
get_refer_publish
(
std
::
string
vhost
)
{
SrsConfDirective
*
conf
=
get_vhost
(
vhost
);
if
(
!
conf
)
{
return
NULL
;
}
return
conf
->
get
(
"refer_publish"
);
}
SrsConfDirective
*
SrsConfig
::
get_listen
()
{
return
root
->
get
(
"listen"
);
}
SrsConfDirective
*
SrsConfig
::
get_chunk_size
()
{
return
root
->
get
(
"chunk_size"
);
}
SrsConfDirective
*
SrsConfig
::
get_pithy_print_publish
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
NULL
;
}
return
pithy
->
get
(
"publish"
);
}
SrsConfDirective
*
SrsConfig
::
get_pithy_print_play
()
{
SrsConfDirective
*
pithy
=
root
->
get
(
"pithy_print"
);
if
(
!
pithy
)
{
return
NULL
;
}
return
pithy
->
get
(
"play"
);
}
int
SrsConfig
::
parse_file
(
const
char
*
filename
)
{
int
ret
=
ERROR_SUCCESS
;
config_file
=
filename
;
if
(
config_file
.
empty
())
{
return
ERROR_SYSTEM_CONFIG_INVALID
;
}
if
((
ret
=
root
->
parse
(
config_file
.
c_str
()))
!=
ERROR_SUCCESS
)
{
return
ret
;
}
SrsConfDirective
*
conf
=
NULL
;
if
((
conf
=
get_listen
())
==
NULL
||
conf
->
args
.
size
()
==
0
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"line %d: conf error, "
"directive
\"
listen
\"
is empty, ret=%d"
,
(
conf
?
conf
->
conf_line
:
0
),
ret
);
return
ret
;
}
return
ret
;
}
int
SrsConfig
::
parse_argv
(
int
&
i
,
char
**
argv
)
{
int
ret
=
ERROR_SUCCESS
;
char
*
p
=
argv
[
i
];
if
(
*
p
++
!=
'-'
)
{
ret
=
ERROR_SYSTEM_CONFIG_INVALID
;
srs_error
(
"invalid options(index=%d, value=%s), "
"must starts 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
::
print_help
(
char
**
argv
)
{
printf
(
RTMP_SIG_SRS_NAME
" "
RTMP_SIG_SRS_VERSION
" Copyright (c) 2013 winlin
\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
"
RTMP_SIG_SRS_WEB
"
\n
"
RTMP_SIG_SRS_URL
"
\n
"
"Email: "
RTMP_SIG_SRS_EMAIL
"
\n
"
,
argv
[
0
]);
}
bool
srs_directive_equals
(
SrsConfDirective
*
a
,
SrsConfDirective
*
b
)
{
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
;
}
...
...
trunk/src/core/srs_core_config.hpp
100755 → 100644
查看文件 @
ce021b2
/*
The MIT License (MIT)
Copyright (c) 2013 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_CORE_CONIFG_HPP
#define SRS_CORE_CONIFG_HPP
/*
#include <srs_core_config.hpp>
*/
#include <srs_core.hpp>
#include <vector>
#include <string>
#include <srs_core_reload.hpp>
// default vhost for rtmp
#define RTMP_VHOST_DEFAULT "__defaultVhost__"
// conf node: enabled.
#define RTMP_VHOST_ENABLED "enabled"
class
SrsFileBuffer
{
public
:
int
fd
;
int
line
;
// start of buffer.
char
*
start
;
// end of buffer.
char
*
end
;
// current consumed position.
char
*
pos
;
// last available position.
char
*
last
;
SrsFileBuffer
();
virtual
~
SrsFileBuffer
();
virtual
int
open
(
const
char
*
filename
);
};
class
SrsConfDirective
{
public
:
int
conf_line
;
std
::
string
name
;
std
::
vector
<
std
::
string
>
args
;
std
::
vector
<
SrsConfDirective
*>
directives
;
public
:
SrsConfDirective
();
virtual
~
SrsConfDirective
();
std
::
string
arg0
();
std
::
string
arg1
();
std
::
string
arg2
();
SrsConfDirective
*
at
(
int
index
);
SrsConfDirective
*
get
(
std
::
string
_name
);
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
);
virtual
int
refill_buffer
(
SrsFileBuffer
*
buffer
,
bool
d_quoted
,
bool
s_quoted
,
int
startline
,
char
*&
pstart
);
};
/**
* the config parser.
* for the config supports reload, so never keep the reference cross st-thread,
* that is, never save the SrsConfDirective* get by any api of config,
* for it maybe free in the reload st-thread cycle.
* you can keep it before st-thread switch, or simply never keep it.
*/
class
SrsConfig
{
private
:
bool
show_help
;
bool
show_version
;
std
::
string
config_file
;
SrsConfDirective
*
root
;
std
::
vector
<
SrsReloadHandler
*>
subscribes
;
public
:
SrsConfig
();
virtual
~
SrsConfig
();
public
:
virtual
int
reload
();
virtual
void
subscribe
(
SrsReloadHandler
*
handler
);
virtual
void
unsubscribe
(
SrsReloadHandler
*
handler
);
public
:
virtual
int
parse_options
(
int
argc
,
char
**
argv
);
virtual
SrsConfDirective
*
get_vhost
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_gop_cache
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_hls
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_hls_path
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer_play
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer_publish
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_listen
();
virtual
SrsConfDirective
*
get_chunk_size
();
virtual
SrsConfDirective
*
get_pithy_print_publish
();
virtual
SrsConfDirective
*
get_pithy_print_play
();
private
:
virtual
int
parse_file
(
const
char
*
filename
);
virtual
int
parse_argv
(
int
&
i
,
char
**
argv
);
virtual
void
print_help
(
char
**
argv
);
};
/**
* deep compare directive.
*/
bool
srs_directive_equals
(
SrsConfDirective
*
a
,
SrsConfDirective
*
b
);
// global config
extern
SrsConfig
*
config
;
/*
The MIT License (MIT)
Copyright (c) 2013 winlin
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SRS_CORE_CONIFG_HPP
#define SRS_CORE_CONIFG_HPP
/*
#include <srs_core_config.hpp>
*/
#include <srs_core.hpp>
#include <vector>
#include <string>
#include <srs_core_reload.hpp>
// default vhost for rtmp
#define RTMP_VHOST_DEFAULT "__defaultVhost__"
// conf node: enabled.
#define RTMP_VHOST_ENABLED "enabled"
class
SrsFileBuffer
{
public
:
int
fd
;
int
line
;
// start of buffer.
char
*
start
;
// end of buffer.
char
*
end
;
// current consumed position.
char
*
pos
;
// last available position.
char
*
last
;
SrsFileBuffer
();
virtual
~
SrsFileBuffer
();
virtual
int
open
(
const
char
*
filename
);
};
class
SrsConfDirective
{
public
:
int
conf_line
;
std
::
string
name
;
std
::
vector
<
std
::
string
>
args
;
std
::
vector
<
SrsConfDirective
*>
directives
;
public
:
SrsConfDirective
();
virtual
~
SrsConfDirective
();
std
::
string
arg0
();
std
::
string
arg1
();
std
::
string
arg2
();
SrsConfDirective
*
at
(
int
index
);
SrsConfDirective
*
get
(
std
::
string
_name
);
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
);
virtual
int
refill_buffer
(
SrsFileBuffer
*
buffer
,
bool
d_quoted
,
bool
s_quoted
,
int
startline
,
char
*&
pstart
);
};
/**
* the config parser.
* for the config supports reload, so never keep the reference cross st-thread,
* that is, never save the SrsConfDirective* get by any api of config,
* for it maybe free in the reload st-thread cycle.
* you can keep it before st-thread switch, or simply never keep it.
*/
class
SrsConfig
{
private
:
bool
show_help
;
bool
show_version
;
std
::
string
config_file
;
SrsConfDirective
*
root
;
std
::
vector
<
SrsReloadHandler
*>
subscribes
;
public
:
SrsConfig
();
virtual
~
SrsConfig
();
public
:
virtual
int
reload
();
virtual
void
subscribe
(
SrsReloadHandler
*
handler
);
virtual
void
unsubscribe
(
SrsReloadHandler
*
handler
);
public
:
virtual
int
parse_options
(
int
argc
,
char
**
argv
);
virtual
SrsConfDirective
*
get_vhost
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_gop_cache
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_hls
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_hls_path
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer_play
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_refer_publish
(
std
::
string
vhost
);
virtual
SrsConfDirective
*
get_listen
();
virtual
SrsConfDirective
*
get_chunk_size
();
virtual
SrsConfDirective
*
get_pithy_print_publish
();
virtual
SrsConfDirective
*
get_pithy_print_play
();
private
:
virtual
int
parse_file
(
const
char
*
filename
);
virtual
int
parse_argv
(
int
&
i
,
char
**
argv
);
virtual
void
print_help
(
char
**
argv
);
};
/**
* deep compare directive.
*/
bool
srs_directive_equals
(
SrsConfDirective
*
a
,
SrsConfDirective
*
b
);
// global config
extern
SrsConfig
*
config
;
#endif
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论