1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Merge pull request #1 from winlinvip/develop

merge origin
This commit is contained in:
tufang14 2015-01-05 14:02:29 +08:00
commit 532a48409d
29 changed files with 1234 additions and 362 deletions

View file

@ -468,6 +468,13 @@ Supported operating systems and hardware:
[EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream) [EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream)
) by srs-librtmp. ) by srs-librtmp.
1. Support 0.1s+ latency, read [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257). 1. Support 0.1s+ latency, read [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257).
1. Support allow/deny publish/play for all or specified ip(
[CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_Security),
[EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_Security)
).
1. Support custom dvr path and http callback, read
[#179](https://github.com/winlinvip/simple-rtmp-server/issues/179) and
[274](https://github.com/winlinvip/simple-rtmp-server/issues/274).
1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech). 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
1. [no-plan] Support multiple processes, for both origin and edge 1. [no-plan] Support multiple processes, for both origin and edge
@ -501,6 +508,10 @@ Supported operating systems and hardware:
* 2013-10-17, Created.<br/> * 2013-10-17, Created.<br/>
## History ## History
* v2.0, 2015-01-03, fix [#274](https://github.com/winlinvip/simple-rtmp-server/issues/274), http-callback support on_dvr when reap a dvr file. 2.0.89
* v2.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 2.0.88
* v2.0, 2015-01-03, fix [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), dvr support custom filepath by variables. 2.0.87
* v2.0, 2015-01-02, fix [#211](https://github.com/winlinvip/simple-rtmp-server/issues/211), support security allow/deny publish/play all/ip. 2.0.86
* v2.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 2.0.85 * v2.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 2.0.85
* v2.0, 2014-01-02, fix [#158](https://github.com/winlinvip/simple-rtmp-server/issues/158), http-callback check http status code ok(200). 2.0.84 * v2.0, 2014-01-02, fix [#158](https://github.com/winlinvip/simple-rtmp-server/issues/158), http-callback check http status code ok(200). 2.0.84
* v2.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 2.0.83 * v2.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 2.0.83
@ -550,6 +561,7 @@ Supported operating systems and hardware:
* v2.0, 2014-10-18, remove supports for OSX(darwin). 2.0.1. * v2.0, 2014-10-18, remove supports for OSX(darwin). 2.0.1.
* v2.0, 2014-10-16, revert github srs README to English. 2.0.0. * v2.0, 2014-10-16, revert github srs README to English. 2.0.0.
* v1.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 1.0.19
* v1.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 1.0.18 * v1.0, 2015-01-02, hotfix [#207](https://github.com/winlinvip/simple-rtmp-server/issues/207), trim the last 0 of log. 1.0.18
* v1.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 1.0.17 * v1.0, 2015-01-02, hotfix [#216](https://github.com/winlinvip/simple-rtmp-server/issues/216), http-callback post in application/json content-type. 1.0.17
* v1.0, 2015-01-01, hotfix [#270](https://github.com/winlinvip/simple-rtmp-server/issues/270), memory leak for http client post. 1.0.16 * v1.0, 2015-01-01, hotfix [#270](https://github.com/winlinvip/simple-rtmp-server/issues/270), memory leak for http client post. 1.0.16

16
trunk/conf/dvr.path.conf Normal file
View file

@ -0,0 +1,16 @@
# the config for srs to dvr in custom path.
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
# @see full.conf for detail config.
listen 1935;
max_connections 1000;
vhost __defaultVhost__ {
dvr {
enabled on;
dvr_path ./objs/nginx/html/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
dvr_plan segment;
dvr_duration 30;
dvr_wait_keyframe on;
}
}

249
trunk/conf/full.conf Executable file → Normal file
View file

@ -142,6 +142,35 @@ http_stream {
vhost __defaultVhost__ { vhost __defaultVhost__ {
} }
# the security to allow or deny clients.
vhost security.srs.com {
# security for host to allow or deny clients.
# @see https://github.com/winlinvip/simple-rtmp-server/issues/211
security {
# whether enable the security for vhost.
# default: off
enabled on;
# the security list, each item format as:
# allow|deny publish|play all|<ip>
# for example:
# allow publish all;
# deny publish all;
# allow publish 127.0.0.1;
# deny publish 127.0.0.1;
# allow play all;
# deny play all;
# allow play 127.0.0.1;
# deny play 127.0.0.1;
# SRS apply the following simple strategies one by one:
# 1. allow all if security disabled.
# 2. default to deny all when security enabled.
# 3. allow if matches allow strategy.
# 4. deny if matches deny strategy.
allow play all;
allow publish all;
}
}
# the MR(merged-read) setting for publisher. # the MR(merged-read) setting for publisher.
# the MW(merged-write) settings for player. # the MW(merged-write) settings for player.
vhost mrw.srs.com { vhost mrw.srs.com {
@ -207,15 +236,38 @@ vhost dvr.srs.com {
# default: off # default: off
enabled on; enabled on;
# the dvr output path. # the dvr output path.
# the app dir is auto created under the dvr_path. # we supports some variables to generate the filename.
# for example, for rtmp stream: # [vhost], the vhost of stream.
# rtmp://127.0.0.1/live/livestream # [app], the app of stream.
# http://127.0.0.1/live/livestream.m3u8 # [stream], the stream name of stream.
# where dvr_path is /dvr, srs will create the following files: # [2006], replace this const to current year.
# /dvr/live the app dir for all streams. # [01], replace this const to current month.
# /dvr/live/livestream.{time}.flv the dvr flv file. # [02], replace this const to current date.
# @remark, the time use system timestamp in ms, user can use http callback to rename it. # [15], replace this const to current hour.
# in a word, the dvr_path is for vhost. # [04], repleace this const to current minute.
# [05], repleace this const to current second.
# [999], repleace this const to current millisecond.
# [timestamp],replace this const to current UNIX timestamp in ms.
# @remark we use golang time format "2006-01-02 15:04:05.999"
# for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776
# 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
# dvr_path ./objs/nginx/html;
# =>
# dvr_path ./objs/nginx/html/live/livestream.1420254068776.flv;
# 2. Use stream and date as dir name, time as filename:
# dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
# =>
# dvr_path /data/ossrs.net/live/livestream/2015/01/03/10.57.30.776.flv;
# 3. Use stream and year/month as dir name, date and time as filename:
# dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]-[15].[04].[05].[999].flv;
# =>
# dvr_path /data/ossrs.net/live/livestream/2015/01/03-10.57.30.776.flv;
# 4. Use vhost/app and year/month as dir name, stream/date/time as filename:
# dvr_path /data/[vhost]/[app]/[2006]/[01]/[stream]-[02]-[15].[04].[05].[999].flv;
# =>
# dvr_path /data/ossrs.net/live/2015/01/livestream-03-10.57.30.776.flv;
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
# default: ./objs/nginx/html # default: ./objs/nginx/html
dvr_path ./objs/nginx/html; dvr_path ./objs/nginx/html;
# the dvr plan. canbe: # the dvr plan. canbe:
@ -244,6 +296,11 @@ vhost dvr.srs.com {
# 3. off, disable the time jitter algorithm, like atc. # 3. off, disable the time jitter algorithm, like atc.
# default: full # default: full
time_jitter full; time_jitter full;
# on_dvr
# for the dvr http callback, @see http_hooks.on_dvr of vhost hooks.callback.srs.com
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#http-callback
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#http-callback
} }
} }
@ -286,7 +343,7 @@ vhost ingest.srs.com {
} }
} }
# vhost for http # vhost for http server config in each vhost.
vhost http.srs.com { vhost http.srs.com {
# http vhost specified config # http vhost specified config
http { http {
@ -438,6 +495,20 @@ vhost hooks.callback.srs.com {
# support multiple api hooks, format: # support multiple api hooks, format:
# on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions; on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
# when srs reap a dvr file, call the hook,
# the request in the POST data string is a object encode by json:
# {
# "action": "on_dvr",
# "client_id": 1985,
# "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
# "stream": "livestream",
# "cwd": "/usr/local/srs",
# "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
# }
# if valid, the hook must return HTTP code 200(Stauts OK) and response
# an int value specifies the error code(0 corresponding to success):
# 0
on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
} }
} }
@ -501,11 +572,105 @@ vhost same.vhost.forward.srs.com {
# this used to split/forward the current stream for cluster active-standby, # this used to split/forward the current stream for cluster active-standby,
# active-active for cdn to build high available fault tolerance system. # active-active for cdn to build high available fault tolerance system.
# format: {ip}:{port} {ip_N}:{port_N} # format: {ip}:{port} {ip_N}:{port_N}
# or specify the vhost by params, @see: change.vhost.forward.srs.com
# if vhost not specified, use the request vhost instead.
forward 127.0.0.1:1936 127.0.0.1:1937; forward 127.0.0.1:1936 127.0.0.1:1937;
} }
# the main comments for transcode
vhost example.transcode.srs.com {
# the streaming transcode configs.
transcode {
# whether the transcode enabled.
# if off, donot transcode.
# default: off.
enabled on;
# the ffmpeg
ffmpeg ./objs/ffmpeg/bin/ffmpeg;
# the transcode engine for matched stream.
# all matched stream will transcoded to the following stream.
# the transcode set name(ie. hd) is optional and not used.
engine example {
# whether the engine is enabled
# default: off.
enabled on;
# input format, can be:
# off, do not specifies the format, ffmpeg will guess it.
# flv, for flv or RTMP stream.
# other format, for example, mp4/aac whatever.
# default: flv
iformat flv;
# ffmpeg filters, follows the main input.
vfilter {
# the logo input file.
i ./doc/ffmpeg-logo.png;
# the ffmpeg complex filter.
# for filters, @see: http://ffmpeg.org/ffmpeg-filters.html
filter_complex 'overlay=10:10';
}
# video encoder name. can be:
# libx264: use h.264(libx264) video encoder.
# copy: donot encoder the video stream, copy it.
# vn: disable video output.
vcodec libx264;
# video bitrate, in kbps
vbitrate 1500;
# video framerate.
vfps 25;
# video width, must be even numbers.
vwidth 768;
# video height, must be even numbers.
vheight 320;
# the max threads for ffmpeg to used.
vthreads 12;
# x264 profile, @see x264 -help, can be:
# high,main,baseline
vprofile main;
# x264 preset, @see x264 -help, can be:
# ultrafast,superfast,veryfast,faster,fast
# medium,slow,slower,veryslow,placebo
vpreset medium;
# other x264 or ffmpeg video params
vparams {
# ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html
t 100;
# 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264
coder 1;
b_strategy 2;
bf 3;
refs 10;
}
# audio encoder name. can be:
# libaacplus: use aac(libaacplus) audio encoder.
# copy: donot encoder the audio stream, copy it.
# an: disable audio output.
acodec libaacplus;
# audio bitrate, in kbps. [16, 72] for libaacplus.
abitrate 70;
# audio sample rate. for flv/rtmp, it must be:
# 44100,22050,11025,5512
asample_rate 44100;
# audio channel, 1 for mono, 2 for stereo.
achannels 2;
# other ffmpeg audio params
aparams {
# audio params, @see: http://ffmpeg.org/ffmpeg-codecs.html#Audio-Encoders
profile:a aac_low;
}
# output format, can be:
# off, do not specifies the format, ffmpeg will guess it.
# flv, for flv or RTMP stream.
# other format, for example, mp4/aac whatever.
# default: flv
oformat flv;
# output stream. variables:
# [vhost] the input stream vhost.
# [port] the intput stream port.
# [app] the input stream app.
# [stream] the input stream name.
# [engine] the tanscode engine name.
output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
}
}
}
# the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction
vhost mirror.transcode.srs.com { vhost mirror.transcode.srs.com {
transcode { transcode {
@ -536,10 +701,8 @@ vhost mirror.transcode.srs.com {
} }
} }
} }
#
# the drawtext filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#drawtext-1 # the drawtext filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#drawtext-1
# remark: we remove the libfreetype which always cause build failed, you must add it manual if needed. # remark: we remove the libfreetype which always cause build failed, you must add it manual if needed.
#
####################################################################################################### #######################################################################################################
# the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop # the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop
vhost crop.transcode.srs.com { vhost crop.transcode.srs.com {
@ -656,97 +819,41 @@ vhost copy.transcode.srs.com {
} }
} }
# transcode all app and stream of vhost # transcode all app and stream of vhost
# the comments, read example.transcode.srs.com
vhost all.transcode.srs.com { vhost all.transcode.srs.com {
# the streaming transcode configs.
transcode { transcode {
# whether the transcode enabled.
# if off, donot transcode.
# default: off.
enabled on; enabled on;
# the ffmpeg
ffmpeg ./objs/ffmpeg/bin/ffmpeg; ffmpeg ./objs/ffmpeg/bin/ffmpeg;
# the transcode engine for matched stream.
# all matched stream will transcoded to the following stream.
# the transcode set name(ie. hd) is optional and not used.
engine ffsuper { engine ffsuper {
# whether the engine is enabled
# default: off.
enabled on; enabled on;
# input format, can be:
# off, do not specifies the format, ffmpeg will guess it.
# flv, for flv or RTMP stream.
# other format, for example, mp4/aac whatever.
# default: flv
iformat flv; iformat flv;
# ffmpeg filters, follows the main input.
vfilter { vfilter {
# the logo input file.
i ./doc/ffmpeg-logo.png; i ./doc/ffmpeg-logo.png;
# the ffmpeg complex filter.
# for filters, @see: http://ffmpeg.org/ffmpeg-filters.html
filter_complex 'overlay=10:10'; filter_complex 'overlay=10:10';
} }
# video encoder name. can be:
# libx264: use h.264(libx264) video encoder.
# copy: donot encoder the video stream, copy it.
# vn: disable video output.
vcodec libx264; vcodec libx264;
# video bitrate, in kbps
vbitrate 1500; vbitrate 1500;
# video framerate.
vfps 25; vfps 25;
# video width, must be even numbers.
vwidth 768; vwidth 768;
# video height, must be even numbers.
vheight 320; vheight 320;
# the max threads for ffmpeg to used.
vthreads 12; vthreads 12;
# x264 profile, @see x264 -help, can be:
# high,main,baseline
vprofile main; vprofile main;
# x264 preset, @see x264 -help, can be:
# ultrafast,superfast,veryfast,faster,fast
# medium,slow,slower,veryslow,placebo
vpreset medium; vpreset medium;
# other x264 or ffmpeg video params
vparams { vparams {
# ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html
t 100; t 100;
# 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264
coder 1; coder 1;
b_strategy 2; b_strategy 2;
bf 3; bf 3;
refs 10; refs 10;
} }
# audio encoder name. can be:
# libaacplus: use aac(libaacplus) audio encoder.
# copy: donot encoder the audio stream, copy it.
# an: disable audio output.
acodec libaacplus; acodec libaacplus;
# audio bitrate, in kbps. [16, 72] for libaacplus.
abitrate 70; abitrate 70;
# audio sample rate. for flv/rtmp, it must be:
# 44100,22050,11025,5512
asample_rate 44100; asample_rate 44100;
# audio channel, 1 for mono, 2 for stereo.
achannels 2; achannels 2;
# other ffmpeg audio params
aparams { aparams {
# audio params, @see: http://ffmpeg.org/ffmpeg-codecs.html#Audio-Encoders
profile:a aac_low; profile:a aac_low;
} }
# output format, can be:
# off, do not specifies the format, ffmpeg will guess it.
# flv, for flv or RTMP stream.
# other format, for example, mp4/aac whatever.
# default: flv
oformat flv; oformat flv;
# output stream. variables:
# [vhost] the input stream vhost.
# [port] the intput stream port.
# [app] the input stream app.
# [stream] the input stream name.
# [engine] the tanscode engine name.
output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
} }
engine ffhd { engine ffhd {

0
trunk/conf/realtime.conf Executable file → Normal file
View file

View file

@ -0,0 +1,13 @@
# security config for srs, allow play and deny publish.
# @see https://github.com/winlinvip/simple-rtmp-server/issues/211#issuecomment-68507035
# @see full.conf for detail config.
listen 1935;
max_connections 1000;
vhost __defaultVhost__ {
security {
enabled on;
deny publish all;
allow play all;
}
}

2
trunk/configure vendored
View file

@ -389,7 +389,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
"srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks" "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks"
"srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge" "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
"srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_avc_aac" "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_avc_aac"
"srs_app_recv_thread" "srs_app_statistic") "srs_app_recv_thread" "srs_app_security" "srs_app_statistic")
APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh
APP_OBJS="${MODULE_OBJS[@]}" APP_OBJS="${MODULE_OBJS[@]}"
fi fi

View file

@ -240,6 +240,74 @@ class RESTStreams(object):
return code return code
'''
handle the dvrs requests: dvr stream.
'''
class RESTDvrs(object):
exposed = True
def GET(self):
enable_crossdomain()
dvrs = {}
return json.dumps(dvrs)
'''
for SRS hook: on_dvr
on_dvr:
when srs reap a dvr file, call the hook,
the request in the POST data string is a object encode by json:
{
"action": "on_dvr",
"client_id": 1985,
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
"stream": "livestream",
"cwd": "/usr/local/srs",
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
}
if valid, the hook must return HTTP code 200(Stauts OK) and response
an int value specifies the error code(0 corresponding to success):
0
'''
def POST(self):
enable_crossdomain()
# return the error code in str
code = Error.success
req = cherrypy.request.body.read()
trace("post to dvrs, req=%s"%(req))
try:
json_req = json.loads(req)
except Exception, ex:
code = Error.system_parse_json
trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
return str(code)
action = json_req["action"]
if action == "on_dvr":
code = self.__on_dvr(json_req)
else:
trace("invalid request action: %s"%(json_req["action"]))
code = Error.request_invalid_action
return str(code)
def OPTIONS(self, *args, **kwargs):
enable_crossdomain()
def __on_dvr(self, req):
code = Error.success
trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"],
req["cwd"], req["file"]
))
# TODO: process the on_dvr event
return code
''' '''
handle the sessions requests: client play/stop stream handle the sessions requests: client play/stop stream
''' '''
@ -1039,6 +1107,7 @@ class V1(object):
self.clients = RESTClients() self.clients = RESTClients()
self.streams = RESTStreams() self.streams = RESTStreams()
self.sessions = RESTSessions() self.sessions = RESTSessions()
self.dvrs = RESTDvrs()
self.chats = RESTChats() self.chats = RESTChats()
self.servers = RESTServers() self.servers = RESTServers()
self.nodes = RESTNodes() self.nodes = RESTNodes()
@ -1048,6 +1117,7 @@ class V1(object):
"clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.", "clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.",
"streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.", "streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.",
"sessions": "for srs http callback, to handle the sessions requests: client play/stop stream", "sessions": "for srs http callback, to handle the sessions requests: client play/stop stream",
"dvrs": "for srs http callback, to handle the dvr requests: dvr stream.",
"chats": "for srs demo meeting, the chat streams, public chat room.", "chats": "for srs demo meeting, the chat streams, public chat room.",
"nodes": { "nodes": {
"summary": "for srs cdn node", "summary": "for srs cdn node",

View file

@ -15,7 +15,7 @@ ret=$?; if [[ 0 -ne $ret ]]; then
exit $ret exit $ret
fi fi
files=`git status|egrep "(modified|new file)"|awk -F ':' '{print $2}'|awk '{print $1}'|egrep "(.hpp$|.cpp$|.cc$|.h$|.c$|.txt$|.sh$)"`; files=`git status|egrep "(modified|new file)"|awk -F ':' '{print $2}'|awk '{print $1}'|egrep "(.hpp$|.cpp$|.cc$|.h$|.c$|.txt$|.sh|.conf$)"`;
for file in $files; do for file in $files; do
dos2unix $file; dos2unix $file;
echo $file|grep ".sh$" >/dev/null 2>&1; EOF_SH=$? echo $file|grep ".sh$" >/dev/null 2>&1; EOF_SH=$?

View file

@ -434,7 +434,8 @@ int SrsConfig::reload_conf(SrsConfig* conf)
// always support reload without additional code: // always support reload without additional code:
// chunk_size, ff_log_dir, max_connections, // chunk_size, ff_log_dir, max_connections,
// bandcheck, http_hooks, heartbeat, // bandcheck, http_hooks, heartbeat,
// token_traverse, debug_srs_upnode // token_traverse, debug_srs_upnode,
// security
// merge config: listen // merge config: listen
if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
@ -1363,6 +1364,7 @@ int SrsConfig::check_config()
&& n != "atc" && n != "atc_auto" && n != "atc" && n != "atc_auto"
&& n != "debug_srs_upnode" && n != "debug_srs_upnode"
&& n != "mr" && n != "mw_latency" && n != "min_latency" && n != "mr" && n != "mw_latency" && n != "min_latency"
&& n != "security"
) { ) {
ret = ERROR_SYSTEM_CONFIG_INVALID; ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret); srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret);
@ -1424,6 +1426,7 @@ int SrsConfig::check_config()
string m = conf->at(j)->name.c_str(); string m = conf->at(j)->name.c_str();
if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
&& m != "on_unpublish" && m != "on_play" && m != "on_stop" && m != "on_unpublish" && m != "on_play" && m != "on_stop"
&& m != "on_dvr"
) { ) {
ret = ERROR_SYSTEM_CONFIG_INVALID; ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
@ -1440,6 +1443,16 @@ int SrsConfig::check_config()
return ret; return ret;
} }
}*/ }*/
} else if (n == "security") {
for (int j = 0; j < (int)conf->directives.size(); j++) {
SrsConfDirective* security = conf->at(j);
string m = security->name.c_str();
if (m != "enabled" && m != "deny" && m != "allow") {
ret = ERROR_SYSTEM_CONFIG_INVALID;
srs_error("unsupported vhost security directive %s, ret=%d", m.c_str(), ret);
return ret;
}
}
} else if (n == "transcode") { } else if (n == "transcode") {
for (int j = 0; j < (int)conf->directives.size(); j++) { for (int j = 0; j < (int)conf->directives.size(); j++) {
SrsConfDirective* trans = conf->at(j); SrsConfDirective* trans = conf->at(j);
@ -2323,6 +2336,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
return conf->get("on_stop"); return conf->get("on_stop");
} }
SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
{
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
if (!conf) {
return NULL;
}
return conf->get("on_dvr");
}
bool SrsConfig::get_bw_check_enabled(string vhost) bool SrsConfig::get_bw_check_enabled(string vhost)
{ {
SrsConfDirective* conf = get_vhost(vhost); SrsConfDirective* conf = get_vhost(vhost);
@ -2456,6 +2480,43 @@ bool SrsConfig::get_vhost_edge_token_traverse(string vhost)
return true; return true;
} }
bool SrsConfig::get_security_enabled(string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
if (!conf) {
return SRS_CONF_DEFAULT_SECURITY_ENABLED;
}
SrsConfDirective* security = conf->get("security");
if (!security) {
return SRS_CONF_DEFAULT_SECURITY_ENABLED;
}
conf = security->get("enabled");
if (!conf || conf->arg0() != "on") {
return SRS_CONF_DEFAULT_SECURITY_ENABLED;
}
return true;
}
SrsConfDirective* SrsConfig::get_security_rules(string vhost)
{
SrsConfDirective* conf = get_vhost(vhost);
if (!conf) {
return NULL;
}
SrsConfDirective* security = conf->get("security");
if (!security) {
return NULL;
}
return security;
}
SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope) SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)
{ {
SrsConfDirective* conf = get_vhost(vhost); SrsConfDirective* conf = get_vhost(vhost);

View file

@ -76,6 +76,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL "http://"SRS_CONSTS_LOCALHOST":8085/api/v1/servers" #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL "http://"SRS_CONSTS_LOCALHOST":8085/api/v1/servers"
#define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES false #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES false
#define SRS_CONF_DEFAULT_SECURITY_ENABLED false
#define SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX 0 #define SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX 0
#define SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS 10000 #define SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS 10000
@ -608,6 +610,11 @@ public:
* @return the on_stop callback directive, the args is the url to callback. * @return the on_stop callback directive, the args is the url to callback.
*/ */
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost); virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
/**
* get the on_dvr callbacks of vhost.
* @return the on_dvr callback directive, the args is the url to callback.
*/
virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
// bwct(bandwidth check tool) section // bwct(bandwidth check tool) section
public: public:
/** /**
@ -659,6 +666,16 @@ public:
* all clients connected to edge must be tranverse to origin to verify. * all clients connected to edge must be tranverse to origin to verify.
*/ */
virtual bool get_vhost_edge_token_traverse(std::string vhost); virtual bool get_vhost_edge_token_traverse(std::string vhost);
// vhost security section
public:
/**
* whether the secrity of vhost enabled.
*/
virtual bool get_security_enabled(std::string vhost);
/**
* get the security rules.
*/
virtual SrsConfDirective* get_security_rules(std::string vhost);
// vhost transcode section // vhost transcode section
public: public:
/** /**
@ -776,7 +793,7 @@ public:
* @remark, we will use some variable, for instance, [vhost] to substitude with vhost. * @remark, we will use some variable, for instance, [vhost] to substitude with vhost.
*/ */
virtual std::string get_engine_output(SrsConfDirective* engine); virtual std::string get_engine_output(SrsConfDirective* engine);
// ingest section // vhost ingest section
public: public:
/** /**
* get the ingest directives of vhost. * get the ingest directives of vhost.

View file

@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <fcntl.h> #include <fcntl.h>
#include <sstream> #include <sstream>
#include <sys/time.h>
using namespace std; using namespace std;
#include <srs_app_config.hpp> #include <srs_app_config.hpp>
@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment()
SrsRequest* req = _req; SrsRequest* req = _req;
// new flv file // the path in config, for example,
std::stringstream path; // /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv
std::string path_config = _srs_config->get_dvr_path(req->vhost);
path << _srs_config->get_dvr_path(req->vhost) // add [stream].[timestamp].flv as filename for dir
<< "/" << req->app << "/" if (path_config.find(".flv") != path_config.length() - 4) {
<< req->stream << "." << srs_get_system_time_ms() << ".flv"; path_config += "/[stream].[timestamp].flv";
}
if ((ret = flv_open(req->get_stream_url(), path.str())) != ERROR_SUCCESS) { // the flv file path
std::string path = path_config;
// variable [vhost]
path = srs_string_replace(path, "[vhost]", req->vhost);
// variable [app]
path = srs_string_replace(path, "[app]", req->app);
// variable [stream]
path = srs_string_replace(path, "[stream]", req->stream);
// date and time substitude
// clock time
timeval tv;
if (gettimeofday(&tv, NULL) == -1) {
return ERROR_SYSTEM_TIME;
}
// to calendar time
struct tm* tm;
if ((tm = localtime(&tv.tv_sec)) == NULL) {
return ERROR_SYSTEM_TIME;
}
// the buffer to format the date and time.
char buf[64];
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
path = srs_string_replace(path, "[2006]", buf);
}
// [2006], replace with current year.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
path = srs_string_replace(path, "[2006]", buf);
}
// [01], replace this const to current month.
if (true) {
snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
path = srs_string_replace(path, "[01]", buf);
}
// [02], replace this const to current date.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
path = srs_string_replace(path, "[02]", buf);
}
// [15], replace this const to current hour.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
path = srs_string_replace(path, "[15]", buf);
}
// [04], repleace this const to current minute.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_min);
path = srs_string_replace(path, "[04]", buf);
}
// [05], repleace this const to current second.
if (true) {
snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
path = srs_string_replace(path, "[05]", buf);
}
// [999], repleace this const to current millisecond.
if (true) {
snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
path = srs_string_replace(path, "[999]", buf);
}
// [timestamp],replace this const to current UNIX timestamp in ms.
if (true) {
int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
path = srs_string_replace(path, "[timestamp]", buf);
}
// create dir first.
std::string dir = path.substr(0, path.rfind("/"));
if ((ret = srs_create_dir_recursively(dir)) != ERROR_SUCCESS) {
srs_error("create dir=%s failed. ret=%d", dir.c_str(), ret);
return ret;
}
srs_info("create dir=%s ok", dir.c_str());
if ((ret = flv_open(req->get_stream_url(), path)) != ERROR_SUCCESS) {
return ret; return ret;
} }
dvr_enabled = true; dvr_enabled = true;
@ -320,6 +404,30 @@ int SrsDvrPlan::flv_close()
return ret; return ret;
} }
#ifdef SRS_AUTO_HTTP_CALLBACK
SrsRequest* req = _req;
if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
// HTTP: on_dvr
SrsConfDirective* on_dvr = _srs_config->get_vhost_on_dvr(req->vhost);
if (!on_dvr) {
srs_info("ignore the empty http callback: on_dvr");
return ret;
}
int connection_id = _srs_context->get_id();
std::string ip = req->ip;
std::string cwd = _srs_config->cwd();
std::string file = segment->path;
for (int i = 0; i < (int)on_dvr->args.size(); i++) {
std::string url = on_dvr->args.at(i);
if ((ret = SrsHttpHooks::on_dvr(url, connection_id, ip, req, cwd, file)) != ERROR_SUCCESS) {
srs_error("hook client on_dvr failed. url=%s, ret=%d", url.c_str(), ret);
return ret;
}
}
}
#endif
return ret; return ret;
} }

View file

@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir()
app_dir += app; app_dir += app;
// TODO: cleanup the dir when startup. // TODO: cleanup the dir when startup.
mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH; if ((ret = srs_create_dir_recursively(app_dir)) != ERROR_SUCCESS) {
if (::mkdir(app_dir.c_str(), mode) < 0) { srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);
if (errno != EEXIST) { return ret;
ret = ERROR_HLS_CREATE_DIR;
srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);
return ret;
}
} }
srs_info("create app dir %s success.", app_dir.c_str()); srs_info("create app dir %s ok", app_dir.c_str());
return ret; return ret;
} }

View file

@ -26,7 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef SRS_AUTO_HTTP_API #ifdef SRS_AUTO_HTTP_API
#include <sstream> #include <sstream>
#include <set>
using namespace std; using namespace std;
#include <srs_kernel_log.hpp> #include <srs_kernel_log.hpp>
@ -153,8 +152,8 @@ int SrsApiV1::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
<< __SRS_JFIELD_STR("meminfos", "the meminfo of system") << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("meminfos", "the meminfo of system") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhosts", "list all vhosts") << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhosts", "dumps vhost to json") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("streams", "list streams that match the name or vhost") << __SRS_JFIELD_STR("streams", "dumps streams to json")
<< __SRS_JOBJECT_END << __SRS_JOBJECT_END
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
@ -522,30 +521,19 @@ bool SrsApiVhosts::can_handle(const char* path, int length, const char** /*pchil
int SrsApiVhosts::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) int SrsApiVhosts::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
{ {
std::stringstream data;
SrsStatistic* stat = SrsStatistic::instance();
int ret = stat->dumps_vhosts(data);
std::stringstream ss; std::stringstream ss;
std::set<std::string> vhost_set; ss << __SRS_JOBJECT_START
SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool(); << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
SrsStreamInfoMap::iterator it; << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT
for (it = pool->begin(); it != pool->end(); it++) { << __SRS_JFIELD_ORG("vhosts", __SRS_JARRAY_START)
if (it->second->_req == NULL) << data.str()
continue; << __SRS_JARRAY_END
vhost_set.insert(it->second->_req->vhost); << __SRS_JOBJECT_END;
}
ss << __SRS_JARRAY_START;
bool first = true;
std::set<std::string>::iterator it_set;
for (it_set = vhost_set.begin(); it_set != vhost_set.end(); it_set++) {
if (first) {
first = false;
} else {
ss << __SRS_JFIELD_CONT;
}
ss << "\"" << (*it_set) << "\"";
}
ss << __SRS_JARRAY_END;
return res_json(skt, req, ss.str()); return res_json(skt, req, ss.str());
} }
@ -565,41 +553,19 @@ bool SrsApiStreams::can_handle(const char* path, int length, const char** /*pchi
int SrsApiStreams::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) int SrsApiStreams::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
{ {
std::stringstream data;
SrsStatistic* stat = SrsStatistic::instance();
int ret = stat->dumps_streams(data);
std::stringstream ss; std::stringstream ss;
std::string query_name = req->query_get("name"); ss << __SRS_JOBJECT_START
std::string query_vhost = req->query_get("vhost"); << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
if (query_name.size() > 0 || query_vhost.size() > 0) { << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT
ss << __SRS_JARRAY_START; << __SRS_JFIELD_ORG("streams", __SRS_JARRAY_START)
bool first = true; << data.str()
SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool(); << __SRS_JARRAY_END
SrsStreamInfoMap::iterator it; << __SRS_JOBJECT_END;
for (it = pool->begin(); it != pool->end(); it++) {
SrsRequest* reqinfo = it->second->_req;
if (reqinfo == NULL)
continue;
if (reqinfo->stream == query_name || reqinfo->vhost == query_vhost) {
if (first) {
first = false;
} else {
ss << __SRS_JFIELD_CONT;
}
ss << __SRS_JOBJECT_START
<< __SRS_JFIELD_STR("name", reqinfo->stream) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("url", reqinfo->tcUrl) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_ORG("clients", 0) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("status", "idle") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("type", "") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("codec", "")
<< __SRS_JOBJECT_END;
}
}
ss << __SRS_JARRAY_END;
} else {
return res_error(skt, req, 400, "Bad Request", "unknown query");
}
return res_json(skt, req, ss.str()); return res_json(skt, req, ss.str());
} }

View file

@ -122,8 +122,7 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
<< __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("app", req->app)
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl)
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
std::string data = ss.str(); std::string data = ss.str();
std::string res; std::string res;
@ -178,7 +177,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_STR("stream", req->stream)
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
std::string data = ss.str(); std::string data = ss.str();
@ -234,7 +232,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_STR("stream", req->stream)
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
std::string data = ss.str(); std::string data = ss.str();
@ -290,7 +287,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_STR("stream", req->stream)
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
std::string data = ss.str(); std::string data = ss.str();
@ -346,7 +342,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_STR("stream", req->stream)
<< __SRS_JOBJECT_END; << __SRS_JOBJECT_END;
std::string data = ss.str(); std::string data = ss.str();
@ -384,5 +379,61 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
return; return;
} }
#endif int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, string cwd, string file)
{
int ret = ERROR_SUCCESS;
SrsHttpUri uri;
if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
srs_error("http uri parse on_dvr url failed, ignored. "
"client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
return ret;
}
std::stringstream ss;
ss << __SRS_JOBJECT_START
<< __SRS_JFIELD_STR("action", "on_dvr") << __SRS_JFIELD_CONT
<< __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("file", file)
<< __SRS_JOBJECT_END;
std::string data = ss.str();
std::string res;
int status_code;
SrsHttpClient http;
if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
srs_error("http post on_dvr uri failed, ignored. "
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
return ret;
}
// ensure the http status is ok.
// https://github.com/winlinvip/simple-rtmp-server/issues/158
if (status_code != SRS_CONSTS_HTTP_OK) {
ret = ERROR_HTTP_STATUS_INVLIAD;
srs_error("http hook on_dvr status failed. "
"client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
return ret;
}
if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
ret = ERROR_HTTP_DATA_INVLIAD;
srs_warn("http hook on_dvr validate failed, ignored. "
"client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
return ret;
}
srs_trace("http hook on_dvr success. "
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
return ret;
}
#endif

View file

@ -58,7 +58,6 @@ public:
* @param client_id the id of client on server. * @param client_id the id of client on server.
* @param url the api server url, to valid the client. * @param url the api server url, to valid the client.
* ignore if empty. * ignore if empty.
* @return valid failed or connect to the url failed.
*/ */
static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req); static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req);
/** /**
@ -73,7 +72,6 @@ public:
* @param client_id the id of client on server. * @param client_id the id of client on server.
* @param url the api server url, to valid the client. * @param url the api server url, to valid the client.
* ignore if empty. * ignore if empty.
* @return valid failed or connect to the url failed.
*/ */
static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req); static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req);
/** /**
@ -88,7 +86,6 @@ public:
* @param client_id the id of client on server. * @param client_id the id of client on server.
* @param url the api server url, to valid the client. * @param url the api server url, to valid the client.
* ignore if empty. * ignore if empty.
* @return valid failed or connect to the url failed.
*/ */
static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req); static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req);
/** /**
@ -98,6 +95,15 @@ public:
* ignore if empty. * ignore if empty.
*/ */
static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req); static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
/**
* on_dvr hook, when reap a dvr file.
* @param client_id the id of client on server.
* @param url the api server url, to process the event.
* ignore if empty.
* @param cwd the current work directory, used to resolve the reltive file path.
* @param file the file path, can be relative or absolute path.
*/
static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file);
}; };
#endif #endif

View file

@ -51,6 +51,7 @@ using namespace std;
#include <srs_app_recv_thread.hpp> #include <srs_app_recv_thread.hpp>
#include <srs_core_performance.hpp> #include <srs_core_performance.hpp>
#include <srs_kernel_utility.hpp> #include <srs_kernel_utility.hpp>
#include <srs_app_security.hpp>
#include <srs_app_statistic.hpp> #include <srs_app_statistic.hpp>
// when stream is busy, for example, streaming is already // when stream is busy, for example, streaming is already
@ -82,6 +83,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd)
rtmp = new SrsRtmpServer(skt); rtmp = new SrsRtmpServer(skt);
refer = new SrsRefer(); refer = new SrsRefer();
bandwidth = new SrsBandwidth(); bandwidth = new SrsBandwidth();
security = new SrsSecurity();
duration = 0; duration = 0;
kbps = new SrsKbps(); kbps = new SrsKbps();
kbps->set_io(skt, skt); kbps->set_io(skt, skt);
@ -103,6 +105,7 @@ SrsRtmpConn::~SrsRtmpConn()
srs_freep(skt); srs_freep(skt);
srs_freep(refer); srs_freep(refer);
srs_freep(bandwidth); srs_freep(bandwidth);
srs_freep(security);
srs_freep(kbps); srs_freep(kbps);
} }
@ -133,6 +136,9 @@ int SrsRtmpConn::do_cycle()
} }
srs_verbose("rtmp connect app success"); srs_verbose("rtmp connect app success");
// set client ip to request.
req->ip = ip;
// discovery vhost, resolve the vhost from config // discovery vhost, resolve the vhost from config
SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost); SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
if (parsed_vhost) { if (parsed_vhost) {
@ -361,6 +367,13 @@ int SrsRtmpConn::stream_service_cycle()
req->strip(); req->strip();
srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f", srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f",
srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration); srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration);
// security check
if ((ret = security->check(type, ip, req)) != ERROR_SUCCESS) {
srs_error("security check failed. ret=%d", ret);
return ret;
}
srs_info("security check ok");
// client is identified, set the timeout to service timeout. // client is identified, set the timeout to service timeout.
rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US);
@ -383,7 +396,12 @@ int SrsRtmpConn::stream_service_cycle()
} }
srs_assert(source != NULL); srs_assert(source != NULL);
SrsStatistic::instance()->add_request_info(source, req); // update the statistic when source disconveried.
SrsStatistic* stat = SrsStatistic::instance();
if ((ret = stat->on_client(_srs_context->get_id(), req)) != ERROR_SUCCESS) {
srs_error("stat client failed. ret=%d", ret);
return ret;
}
// check ASAP, to fail it faster if invalid. // check ASAP, to fail it faster if invalid.
if (type != SrsRtmpConnPlay && !vhost_is_edge) { if (type != SrsRtmpConnPlay && !vhost_is_edge) {

View file

@ -51,6 +51,7 @@ class SrsRtmpClient;
class SrsSharedPtrMessage; class SrsSharedPtrMessage;
class SrsQueueRecvThread; class SrsQueueRecvThread;
class SrsPublishRecvThread; class SrsPublishRecvThread;
class SrsSecurity;
/** /**
* the client provides the main logic control for RTMP clients. * the client provides the main logic control for RTMP clients.
@ -66,6 +67,7 @@ private:
SrsRtmpServer* rtmp; SrsRtmpServer* rtmp;
SrsRefer* refer; SrsRefer* refer;
SrsBandwidth* bandwidth; SrsBandwidth* bandwidth;
SrsSecurity* security;
// elapse duration in ms // elapse duration in ms
// for live play duration, for instance, rtmpdump to record. // for live play duration, for instance, rtmpdump to record.
// @see https://github.com/winlinvip/simple-rtmp-server/issues/47 // @see https://github.com/winlinvip/simple-rtmp-server/issues/47

View file

@ -0,0 +1,159 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 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_app_security.hpp>
#include <srs_kernel_error.hpp>
#include <srs_app_config.hpp>
using namespace std;
SrsSecurity::SrsSecurity()
{
}
SrsSecurity::~SrsSecurity()
{
}
int SrsSecurity::check(SrsRtmpConnType type, string ip, SrsRequest* req)
{
int ret = ERROR_SUCCESS;
// allow all if security disabled.
if (!_srs_config->get_security_enabled(req->vhost)) {
return ret;
}
// default to deny all when security enabled.
ret = ERROR_SYSTEM_SECURITY;
// rules to apply
SrsConfDirective* rules = _srs_config->get_security_rules(req->vhost);
if (!rules) {
return ret;
}
// allow if matches allow strategy.
if (allow_check(rules, type, ip) == ERROR_SYSTEM_SECURITY_ALLOW) {
ret = ERROR_SUCCESS;
}
// deny if matches deny strategy.
if (deny_check(rules, type, ip) == ERROR_SYSTEM_SECURITY_DENY) {
ret = ERROR_SYSTEM_SECURITY_DENY;
}
return ret;
}
int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip)
{
int ret = ERROR_SUCCESS;
for (int i = 0; i < (int)rules->directives.size(); i++) {
SrsConfDirective* rule = rules->at(i);
if (rule->name != "allow") {
continue;
}
switch (type) {
case SrsRtmpConnPlay:
if (rule->arg0() != "play") {
break;
}
if (rule->arg1() == "all" || rule->arg1() == ip) {
ret = ERROR_SYSTEM_SECURITY_ALLOW;
break;
}
break;
case SrsRtmpConnFMLEPublish:
case SrsRtmpConnFlashPublish:
if (rule->arg0() != "publish") {
break;
}
if (rule->arg1() == "all" || rule->arg1() == ip) {
ret = ERROR_SYSTEM_SECURITY_ALLOW;
break;
}
break;
case SrsRtmpConnUnknown:
default:
break;
}
// when matched, donot search more.
if (ret == ERROR_SYSTEM_SECURITY_ALLOW) {
break;
}
}
return ret;
}
int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip)
{
int ret = ERROR_SUCCESS;
for (int i = 0; i < (int)rules->directives.size(); i++) {
SrsConfDirective* rule = rules->at(i);
if (rule->name != "deny") {
continue;
}
switch (type) {
case SrsRtmpConnPlay:
if (rule->arg0() != "play") {
break;
}
if (rule->arg1() == "all" || rule->arg1() == ip) {
ret = ERROR_SYSTEM_SECURITY_DENY;
break;
}
break;
case SrsRtmpConnFMLEPublish:
case SrsRtmpConnFlashPublish:
if (rule->arg0() != "publish") {
break;
}
if (rule->arg1() == "all" || rule->arg1() == ip) {
ret = ERROR_SYSTEM_SECURITY_DENY;
break;
}
break;
case SrsRtmpConnUnknown:
default:
break;
}
// when matched, donot search more.
if (ret == ERROR_SYSTEM_SECURITY_DENY) {
break;
}
}
return ret;
}

View file

@ -0,0 +1,70 @@
/*
The MIT License (MIT)
Copyright (c) 2013-2015 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_APP_SECURITY_HPP
#define SRS_APP_SECURITY_HPP
/*
#include <srs_app_security.hpp>
*/
#include <srs_core.hpp>
#include <string>
#include <srs_protocol_rtmp.hpp>
class SrsConfDirective;
/**
* the security apply on vhost.
* @see https://github.com/winlinvip/simple-rtmp-server/issues/211
*/
class SrsSecurity
{
public:
SrsSecurity();
virtual ~SrsSecurity();
public:
/**
* security check the client apply by vhost security strategy
* @param type the client type, publish or play.
* @param ip the ip address of client.
* @param req the request object of client.
*/
virtual int check(SrsRtmpConnType type, std::string ip, SrsRequest* req);
private:
/**
* security check the allow,
* @return, if allowed, ERROR_SYSTEM_SECURITY_ALLOW.
*/
virtual int allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip);
/**
* security check the deny,
* @return, if denied, ERROR_SYSTEM_SECURITY_DENY.
*/
virtual int deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip);
};
#endif

View file

@ -23,53 +23,142 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_app_statistic.hpp> #include <srs_app_statistic.hpp>
#include <unistd.h>
#include <sstream>
using namespace std;
#include <srs_protocol_rtmp.hpp> #include <srs_protocol_rtmp.hpp>
#include <srs_app_json.hpp>
SrsStreamInfo::SrsStreamInfo() int64_t __srs_gvid = getpid();
int64_t __srs_generate_id()
{ {
_req = NULL; return __srs_gvid++;
} }
SrsStreamInfo::~SrsStreamInfo() SrsStatisticVhost::SrsStatisticVhost()
{ {
if (_req != NULL) id = __srs_generate_id();
delete _req;
} }
SrsStatistic *SrsStatistic::_instance = NULL; SrsStatisticVhost::~SrsStatisticVhost()
{
}
SrsStatisticStream::SrsStatisticStream()
{
id = __srs_generate_id();
vhost = NULL;
}
SrsStatisticStream::~SrsStatisticStream()
{
}
SrsStatistic* SrsStatistic::_instance = new SrsStatistic();
SrsStatistic::SrsStatistic() SrsStatistic::SrsStatistic()
{ {
_server_id = __srs_generate_id();
} }
SrsStatistic::~SrsStatistic() SrsStatistic::~SrsStatistic()
{ {
SrsStreamInfoMap::iterator it; if (true) {
for (it = pool.begin(); it != pool.end(); it++) { std::map<std::string, SrsStatisticVhost*>::iterator it;
delete it->second; for (it = vhosts.begin(); it != vhosts.end(); it++) {
} SrsStatisticVhost* vhost = it->second;
srs_freep(vhost);
}
}
if (true) {
std::map<std::string, SrsStatisticStream*>::iterator it;
for (it = streams.begin(); it != streams.end(); it++) {
SrsStatisticStream* stream = it->second;
srs_freep(stream);
}
}
if (true) {
std::map<int, SrsStatisticClient*>::iterator it;
for (it = clients.begin(); it != clients.end(); it++) {
SrsStatisticClient* client = it->second;
srs_freep(client);
}
}
} }
SrsStreamInfoMap* SrsStatistic::get_pool() SrsStatistic* SrsStatistic::instance()
{ {
return &pool; return _instance;
} }
SrsStreamInfo* SrsStatistic::get(void *p) int SrsStatistic::on_client(int id, SrsRequest* req)
{ {
SrsStreamInfoMap::iterator it = pool.find(p); int ret = ERROR_SUCCESS;
if (it == pool.end()) {
pool[p] = new SrsStreamInfo(); // create vhost if not exists.
return pool[p]; SrsStatisticVhost* vhost = NULL;
} else { if (vhosts.find(req->vhost) == vhosts.end()) {
return it->second; vhost = new SrsStatisticVhost();
} vhost->vhost = req->vhost;
vhosts[req->vhost] = vhost;
} else {
vhost = vhosts[req->vhost];
}
// the url to identify the stream.
std::string url = req->get_stream_url();
// create stream if not exists.
SrsStatisticStream* stream = NULL;
if (streams.find(url) == streams.end()) {
stream = new SrsStatisticStream();
stream->vhost = vhost;
stream->stream = req->stream;
stream->url = url;
streams[url] = stream;
} else {
stream = streams[url];
}
return ret;
} }
void SrsStatistic::add_request_info(void *p, SrsRequest *req) int64_t SrsStatistic::server_id()
{ {
SrsStreamInfo *info = get(p); return _server_id;
if (info->_req == NULL) }
info->_req = req->copy();
} int SrsStatistic::dumps_vhosts(stringstream& ss)
{
int ret = ERROR_SUCCESS;
std::map<std::string, SrsStatisticVhost*>::iterator it;
for (it = vhosts.begin(); it != vhosts.end(); it++) {
SrsStatisticVhost* vhost = it->second;
ss << __SRS_JOBJECT_START
<< __SRS_JFIELD_ORG("id", vhost->id) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("name", vhost->vhost)
<< __SRS_JOBJECT_END;
}
return ret;
}
int SrsStatistic::dumps_streams(stringstream& ss)
{
int ret = ERROR_SUCCESS;
std::map<std::string, SrsStatisticStream*>::iterator it;
for (it = streams.begin(); it != streams.end(); it++) {
SrsStatisticStream* stream = it->second;
ss << __SRS_JOBJECT_START
<< __SRS_JFIELD_ORG("id", stream->id) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_STR("name", stream->stream) << __SRS_JFIELD_CONT
<< __SRS_JFIELD_ORG("vhost", stream->vhost->id)
<< __SRS_JOBJECT_END;
}
return ret;
}

View file

@ -31,40 +31,78 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core.hpp> #include <srs_core.hpp>
#include <map> #include <map>
#include <string>
class SrsRequest; class SrsRequest;
class SrsStreamInfo struct SrsStatisticVhost
{ {
public: public:
SrsStreamInfo(); int64_t id;
virtual ~SrsStreamInfo(); std::string vhost;
public:
SrsRequest *_req; SrsStatisticVhost();
virtual ~SrsStatisticVhost();
};
struct SrsStatisticStream
{
public:
int64_t id;
SrsStatisticVhost* vhost;
std::string app;
std::string stream;
std::string url;
public:
SrsStatisticStream();
virtual ~SrsStatisticStream();
};
struct SrsStatisticClient
{
public:
SrsStatisticStream* stream;
int id;
}; };
typedef std::map<void*, SrsStreamInfo*> SrsStreamInfoMap;
class SrsStatistic class SrsStatistic
{ {
public: private:
static SrsStatistic *instance() static SrsStatistic *_instance;
{ // the id to identify the sever.
if (_instance == NULL) { int64_t _server_id;
_instance = new SrsStatistic(); // key: vhost name, value: vhost object.
} std::map<std::string, SrsStatisticVhost*> vhosts;
return _instance; // key: stream name, value: stream object.
} std::map<std::string, SrsStatisticStream*> streams;
// key: client id, value: stream object.
virtual SrsStreamInfoMap* get_pool(); std::map<int, SrsStatisticClient*> clients;
virtual void add_request_info(void *p, SrsRequest *req);
private: private:
SrsStatistic(); SrsStatistic();
virtual ~SrsStatistic(); virtual ~SrsStatistic();
static SrsStatistic *_instance; public:
SrsStreamInfoMap pool; static SrsStatistic* instance();
virtual SrsStreamInfo *get(void *p); public:
/**
* when got a client to publish/play stream,
* @param id, the client srs id.
* @param req, the client request object.
*/
virtual int on_client(int id, SrsRequest* req);
public:
/**
* get the server id, used to identify the server.
* for example, when restart, the server id must changed.
*/
virtual int64_t server_id();
/**
* dumps the vhosts to sstream in json.
*/
virtual int dumps_vhosts(std::stringstream& ss);
/**
* dumps the streams to sstream in json.
*/
virtual int dumps_streams(std::stringstream& ss);
}; };
#endif #endif

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version // current release version
#define VERSION_MAJOR 2 #define VERSION_MAJOR 2
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 85 #define VERSION_REVISION 89
// server info. // server info.
#define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_KEY "SRS"
#define RTMP_SIG_SRS_ROLE "origin/edge server" #define RTMP_SIG_SRS_ROLE "origin/edge server"

View file

@ -90,6 +90,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_SYSTEM_FILE_SEEK 1049 #define ERROR_SYSTEM_FILE_SEEK 1049
#define ERROR_SYSTEM_IO_INVALID 1050 #define ERROR_SYSTEM_IO_INVALID 1050
#define ERROR_ST_EXCEED_THREADS 1051 #define ERROR_ST_EXCEED_THREADS 1051
#define ERROR_SYSTEM_SECURITY 1052
#define ERROR_SYSTEM_SECURITY_DENY 1053
#define ERROR_SYSTEM_SECURITY_ALLOW 1054
#define ERROR_SYSTEM_TIME 1055
#define ERROR_SYSTEM_DIR_EXISTS 1056
#define ERROR_SYSTEM_CREATE_DIR 1057
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// RTMP protocol error. // RTMP protocol error.
@ -149,7 +155,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
#define ERROR_HLS_METADATA 3000 #define ERROR_HLS_METADATA 3000
#define ERROR_HLS_DECODE_ERROR 3001 #define ERROR_HLS_DECODE_ERROR 3001
#define ERROR_HLS_CREATE_DIR 3002 //#define ERROR_HLS_CREATE_DIR 3002
#define ERROR_HLS_OPEN_FAILED 3003 #define ERROR_HLS_OPEN_FAILED 3003
#define ERROR_HLS_WRITE_FAILED 3004 #define ERROR_HLS_WRITE_FAILED 3004
#define ERROR_HLS_AAC_FRAME_LENGTH 3005 #define ERROR_HLS_AAC_FRAME_LENGTH 3005

View file

@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#endif #endif
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std; using namespace std;
#include <srs_kernel_log.hpp> #include <srs_kernel_log.hpp>
#include <srs_kernel_error.hpp>
// this value must: // this value must:
// equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000
@ -222,3 +225,56 @@ bool srs_string_ends_with(string str, string flag)
return str.rfind(flag) == str.length() - flag.length(); return str.rfind(flag) == str.length() - flag.length();
} }
int __srs_create_dir_recursively(string dir)
{
int ret = ERROR_SUCCESS;
struct stat st;
// stat current dir, if exists, return error.
if (stat(dir.c_str(), &st) == 0) {
return ERROR_SYSTEM_DIR_EXISTS;
}
// create parent first.
size_t pos;
if ((pos = dir.rfind("/")) != std::string::npos) {
std::string parent = dir.substr(0, pos);
ret = __srs_create_dir_recursively(parent);
// return for error.
if (ret != ERROR_SUCCESS && ret != ERROR_SYSTEM_DIR_EXISTS) {
return ret;
}
// parent exists, set to ok.
ret = ERROR_SUCCESS;
}
// create curren dir.
mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;
if (::mkdir(dir.c_str(), mode) < 0) {
if (errno == EEXIST) {
return ERROR_SYSTEM_DIR_EXISTS;
}
ret = ERROR_SYSTEM_CREATE_DIR;
srs_error("create dir %s failed. ret=%d", dir.c_str(), ret);
return ret;
}
srs_info("create dir %s success.", dir.c_str());
return ret;
}
int srs_create_dir_recursively(string dir)
{
int ret = ERROR_SUCCESS;
ret = __srs_create_dir_recursively(dir);
if (ret == ERROR_SYSTEM_DIR_EXISTS) {
return ERROR_SUCCESS;
}
return ret;
}

View file

@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars);
// whether string end with // whether string end with
extern bool srs_string_ends_with(std::string str, std::string flag); extern bool srs_string_ends_with(std::string str, std::string flag);
// create dir recursively
extern int srs_create_dir_recursively(std::string dir);
#endif #endif

View file

@ -91,6 +91,7 @@ SrsRequest* SrsRequest::copy()
{ {
SrsRequest* cp = new SrsRequest(); SrsRequest* cp = new SrsRequest();
cp->ip = ip;
cp->app = app; cp->app = app;
cp->objectEncoding = objectEncoding; cp->objectEncoding = objectEncoding;
cp->pageUrl = pageUrl; cp->pageUrl = pageUrl;

View file

@ -53,6 +53,9 @@ class IMergeReadHandler;
*/ */
class SrsRequest class SrsRequest
{ {
public:
// client ip.
std::string ip;
public: public:
/** /**
* tcUrl: rtmp://request_vhost:port/app/stream * tcUrl: rtmp://request_vhost:port/app/stream

View file

@ -1,151 +1,155 @@
file file
main readonly separator, main readonly separator,
..\main\srs_main_server.cpp, ..\main\srs_main_server.cpp,
auto readonly separator, auto readonly separator,
..\..\objs\srs_auto_headers.hpp, ..\..\objs\srs_auto_headers.hpp,
libs readonly separator, libs readonly separator,
..\libs\srs_librtmp.hpp, ..\libs\srs_librtmp.hpp,
..\libs\srs_librtmp.cpp, ..\libs\srs_librtmp.cpp,
..\libs\srs_lib_bandwidth.hpp, ..\libs\srs_lib_bandwidth.hpp,
..\libs\srs_lib_bandwidth.cpp, ..\libs\srs_lib_bandwidth.cpp,
..\libs\srs_lib_simple_socket.hpp, ..\libs\srs_lib_simple_socket.hpp,
..\libs\srs_lib_simple_socket.cpp, ..\libs\srs_lib_simple_socket.cpp,
core readonly separator, core readonly separator,
..\core\srs_core.hpp, ..\core\srs_core.hpp,
..\core\srs_core.cpp, ..\core\srs_core.cpp,
..\core\srs_core_autofree.hpp, ..\core\srs_core_autofree.hpp,
..\core\srs_core_autofree.cpp, ..\core\srs_core_autofree.cpp,
..\core\srs_core_performance.hpp, ..\core\srs_core_performance.hpp,
..\core\srs_core_performance.cpp, ..\core\srs_core_performance.cpp,
kernel readonly separator, kernel readonly separator,
..\kernel\srs_kernel_codec.hpp, ..\kernel\srs_kernel_codec.hpp,
..\kernel\srs_kernel_codec.cpp, ..\kernel\srs_kernel_codec.cpp,
..\kernel\srs_kernel_consts.hpp, ..\kernel\srs_kernel_consts.hpp,
..\kernel\srs_kernel_consts.cpp, ..\kernel\srs_kernel_consts.cpp,
..\kernel\srs_kernel_error.hpp, ..\kernel\srs_kernel_error.hpp,
..\kernel\srs_kernel_error.cpp, ..\kernel\srs_kernel_error.cpp,
..\kernel\srs_kernel_file.hpp, ..\kernel\srs_kernel_file.hpp,
..\kernel\srs_kernel_file.cpp, ..\kernel\srs_kernel_file.cpp,
..\kernel\srs_kernel_flv.hpp, ..\kernel\srs_kernel_flv.hpp,
..\kernel\srs_kernel_flv.cpp, ..\kernel\srs_kernel_flv.cpp,
..\kernel\srs_kernel_log.hpp, ..\kernel\srs_kernel_log.hpp,
..\kernel\srs_kernel_log.cpp, ..\kernel\srs_kernel_log.cpp,
..\kernel\srs_kernel_stream.hpp, ..\kernel\srs_kernel_stream.hpp,
..\kernel\srs_kernel_stream.cpp, ..\kernel\srs_kernel_stream.cpp,
..\kernel\srs_kernel_utility.hpp, ..\kernel\srs_kernel_utility.hpp,
..\kernel\srs_kernel_utility.cpp, ..\kernel\srs_kernel_utility.cpp,
rtmp-protocol readonly separator, rtmp-protocol readonly separator,
..\rtmp\srs_protocol_amf0.hpp, ..\rtmp\srs_protocol_amf0.hpp,
..\rtmp\srs_protocol_amf0.cpp, ..\rtmp\srs_protocol_amf0.cpp,
..\rtmp\srs_protocol_buffer.hpp, ..\rtmp\srs_protocol_buffer.hpp,
..\rtmp\srs_protocol_buffer.cpp, ..\rtmp\srs_protocol_buffer.cpp,
..\rtmp\srs_protocol_handshake.hpp, ..\rtmp\srs_protocol_handshake.hpp,
..\rtmp\srs_protocol_handshake.cpp, ..\rtmp\srs_protocol_handshake.cpp,
..\rtmp\srs_protocol_io.hpp, ..\rtmp\srs_protocol_io.hpp,
..\rtmp\srs_protocol_io.cpp, ..\rtmp\srs_protocol_io.cpp,
..\rtmp\srs_protocol_msg_array.hpp, ..\rtmp\srs_protocol_msg_array.hpp,
..\rtmp\srs_protocol_msg_array.cpp, ..\rtmp\srs_protocol_msg_array.cpp,
..\rtmp\srs_protocol_rtmp.hpp, ..\rtmp\srs_protocol_rtmp.hpp,
..\rtmp\srs_protocol_rtmp.cpp, ..\rtmp\srs_protocol_rtmp.cpp,
..\rtmp\srs_protocol_stack.hpp, ..\rtmp\srs_protocol_stack.hpp,
..\rtmp\srs_protocol_stack.cpp, ..\rtmp\srs_protocol_stack.cpp,
..\rtmp\srs_protocol_utility.hpp, ..\rtmp\srs_protocol_utility.hpp,
..\rtmp\srs_protocol_utility.cpp, ..\rtmp\srs_protocol_utility.cpp,
app readonly separator, app readonly separator,
..\app\srs_app_avc_aac.hpp, ..\app\srs_app_avc_aac.hpp,
..\app\srs_app_avc_aac.cpp, ..\app\srs_app_avc_aac.cpp,
..\app\srs_app_bandwidth.hpp, ..\app\srs_app_bandwidth.hpp,
..\app\srs_app_bandwidth.cpp, ..\app\srs_app_bandwidth.cpp,
..\app\srs_app_conn.hpp, ..\app\srs_app_conn.hpp,
..\app\srs_app_conn.cpp, ..\app\srs_app_conn.cpp,
..\app\srs_app_config.hpp, ..\app\srs_app_config.hpp,
..\app\srs_app_config.cpp, ..\app\srs_app_config.cpp,
..\app\srs_app_dvr.hpp, ..\app\srs_app_dvr.hpp,
..\app\srs_app_dvr.cpp, ..\app\srs_app_dvr.cpp,
..\app\srs_app_edge.hpp, ..\app\srs_app_edge.hpp,
..\app\srs_app_edge.cpp, ..\app\srs_app_edge.cpp,
..\app\srs_app_empty.hpp, ..\app\srs_app_empty.hpp,
..\app\srs_app_empty.cpp, ..\app\srs_app_empty.cpp,
..\app\srs_app_encoder.hpp, ..\app\srs_app_encoder.hpp,
..\app\srs_app_encoder.cpp, ..\app\srs_app_encoder.cpp,
..\app\srs_app_ffmpeg.hpp, ..\app\srs_app_ffmpeg.hpp,
..\app\srs_app_ffmpeg.cpp, ..\app\srs_app_ffmpeg.cpp,
..\app\srs_app_forward.hpp, ..\app\srs_app_forward.hpp,
..\app\srs_app_forward.cpp, ..\app\srs_app_forward.cpp,
..\app\srs_app_heartbeat.hpp, ..\app\srs_app_heartbeat.hpp,
..\app\srs_app_heartbeat.cpp, ..\app\srs_app_heartbeat.cpp,
..\app\srs_app_hls.hpp, ..\app\srs_app_hls.hpp,
..\app\srs_app_hls.cpp, ..\app\srs_app_hls.cpp,
..\app\srs_app_http.hpp, ..\app\srs_app_http.hpp,
..\app\srs_app_http.cpp, ..\app\srs_app_http.cpp,
..\app\srs_app_http_api.hpp, ..\app\srs_app_http_api.hpp,
..\app\srs_app_http_api.cpp, ..\app\srs_app_http_api.cpp,
..\app\srs_app_http_client.hpp, ..\app\srs_app_http_client.hpp,
..\app\srs_app_http_client.cpp, ..\app\srs_app_http_client.cpp,
..\app\srs_app_http_conn.hpp, ..\app\srs_app_http_conn.hpp,
..\app\srs_app_http_conn.cpp, ..\app\srs_app_http_conn.cpp,
..\app\srs_app_http_hooks.hpp, ..\app\srs_app_http_hooks.hpp,
..\app\srs_app_http_hooks.cpp, ..\app\srs_app_http_hooks.cpp,
..\app\srs_app_ingest.hpp, ..\app\srs_app_ingest.hpp,
..\app\srs_app_ingest.cpp, ..\app\srs_app_ingest.cpp,
..\app\srs_app_json.hpp, ..\app\srs_app_json.hpp,
..\app\srs_app_json.cpp, ..\app\srs_app_json.cpp,
..\app\srs_app_kbps.hpp, ..\app\srs_app_kbps.hpp,
..\app\srs_app_kbps.cpp, ..\app\srs_app_kbps.cpp,
..\app\srs_app_log.hpp, ..\app\srs_app_log.hpp,
..\app\srs_app_log.cpp, ..\app\srs_app_log.cpp,
..\app\srs_app_recv_thread.hpp, ..\app\srs_app_recv_thread.hpp,
..\app\srs_app_recv_thread.cpp, ..\app\srs_app_recv_thread.cpp,
..\app\srs_app_refer.hpp, ..\app\srs_app_refer.hpp,
..\app\srs_app_refer.cpp, ..\app\srs_app_refer.cpp,
..\app\srs_app_reload.hpp, ..\app\srs_app_reload.hpp,
..\app\srs_app_reload.cpp, ..\app\srs_app_reload.cpp,
..\app\srs_app_rtmp_conn.hpp, ..\app\srs_app_rtmp_conn.hpp,
..\app\srs_app_rtmp_conn.cpp, ..\app\srs_app_rtmp_conn.cpp,
..\app\srs_app_pithy_print.hpp, ..\app\srs_app_pithy_print.hpp,
..\app\srs_app_pithy_print.cpp, ..\app\srs_app_pithy_print.cpp,
..\app\srs_app_server.hpp, ..\app\srs_app_security.hpp,
..\app\srs_app_server.cpp, ..\app\srs_app_security.cpp,
..\app\srs_app_st.hpp, ..\app\srs_app_server.hpp,
..\app\srs_app_st.cpp, ..\app\srs_app_server.cpp,
..\app\srs_app_st_socket.hpp, ..\app\srs_app_st.hpp,
..\app\srs_app_st_socket.cpp, ..\app\srs_app_st.cpp,
..\app\srs_app_source.hpp, ..\app\srs_app_st_socket.hpp,
..\app\srs_app_source.cpp, ..\app\srs_app_st_socket.cpp,
..\app\srs_app_thread.hpp, ..\app\srs_app_statistic.hpp,
..\app\srs_app_thread.cpp, ..\app\srs_app_statistic.cpp,
..\app\srs_app_utility.hpp, ..\app\srs_app_source.hpp,
..\app\srs_app_utility.cpp, ..\app\srs_app_source.cpp,
utest readonly separator, ..\app\srs_app_thread.hpp,
..\utest\srs_utest.hpp, ..\app\srs_app_thread.cpp,
..\utest\srs_utest.cpp, ..\app\srs_app_utility.hpp,
..\utest\srs_utest_amf0.hpp, ..\app\srs_app_utility.cpp,
..\utest\srs_utest_amf0.cpp, utest readonly separator,
..\utest\srs_utest_config.hpp, ..\utest\srs_utest.hpp,
..\utest\srs_utest_config.cpp, ..\utest\srs_utest.cpp,
..\utest\srs_utest_core.hpp, ..\utest\srs_utest_amf0.hpp,
..\utest\srs_utest_core.cpp, ..\utest\srs_utest_amf0.cpp,
..\utest\srs_utest_kernel.hpp, ..\utest\srs_utest_config.hpp,
..\utest\srs_utest_kernel.cpp, ..\utest\srs_utest_config.cpp,
..\utest\srs_utest_protocol.hpp, ..\utest\srs_utest_core.hpp,
..\utest\srs_utest_protocol.cpp, ..\utest\srs_utest_core.cpp,
..\utest\srs_utest_reload.hpp, ..\utest\srs_utest_kernel.hpp,
..\utest\srs_utest_reload.cpp, ..\utest\srs_utest_kernel.cpp,
research readonly separator, ..\utest\srs_utest_protocol.hpp,
..\..\research\librtmp\srs_aac_raw_publish.c, ..\utest\srs_utest_protocol.cpp,
..\..\research\librtmp\srs_audio_raw_publish.c, ..\utest\srs_utest_reload.hpp,
..\..\research\librtmp\srs_bandwidth_check.c, ..\utest\srs_utest_reload.cpp,
..\..\research\librtmp\srs_detect_rtmp.c, research readonly separator,
..\..\research\librtmp\srs_flv_injecter.c, ..\..\research\librtmp\srs_aac_raw_publish.c,
..\..\research\librtmp\srs_flv_parser.c, ..\..\research\librtmp\srs_audio_raw_publish.c,
..\..\research\librtmp\srs_h264_raw_publish.c, ..\..\research\librtmp\srs_bandwidth_check.c,
..\..\research\librtmp\srs_ingest_flv.c, ..\..\research\librtmp\srs_detect_rtmp.c,
..\..\research\librtmp\srs_ingest_rtmp.c, ..\..\research\librtmp\srs_flv_injecter.c,
..\..\research\librtmp\srs_play.c, ..\..\research\librtmp\srs_flv_parser.c,
..\..\research\librtmp\srs_publish.c, ..\..\research\librtmp\srs_h264_raw_publish.c,
..\..\research\librtmp\srs_rtmp_dump.c, ..\..\research\librtmp\srs_ingest_flv.c,
..\..\research\hls\ts_info.cc; ..\..\research\librtmp\srs_ingest_rtmp.c,
..\..\research\librtmp\srs_play.c,
..\..\research\librtmp\srs_publish.c,
..\..\research\librtmp\srs_rtmp_dump.c,
..\..\research\hls\ts_info.cc;
mainconfig mainconfig
"" = "MAIN"; "" = "MAIN";

View file

@ -1206,12 +1206,12 @@ VOID TEST(KernelStreamTest, StreamRead8Bytes)
data[18] = 0x13; data[18] = 0x13;
data[19] = 0x14; data[19] = 0x14;
EXPECT_EQ(0x0102030405060708, s.read_8bytes()); EXPECT_EQ(0x0102030405060708LL, s.read_8bytes());
EXPECT_EQ(0x090a0b0c0d0e0f10, s.read_8bytes()); EXPECT_EQ(0x090a0b0c0d0e0f10LL, s.read_8bytes());
s.skip(-1 * s.pos()); s.skip(-1 * s.pos());
s.skip(5); s.skip(5);
EXPECT_EQ(0x060708090a0b0c0d, s.read_8bytes()); EXPECT_EQ(0x060708090a0b0c0dLL, s.read_8bytes());
} }
/** /**
@ -1364,8 +1364,8 @@ VOID TEST(KernelStreamTest, StreamWrite8Bytes)
EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024)); EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
s.write_8bytes(0x1011121314151617); s.write_8bytes(0x1011121314151617LL);
s.write_8bytes(0x1819202122232425); s.write_8bytes(0x1819202122232425LL);
s.skip(-1 * s.pos()); s.skip(-1 * s.pos());
EXPECT_EQ(0x10, s.read_1bytes()); EXPECT_EQ(0x10, s.read_1bytes());