diff --git a/README.md b/README.md index 4c13ccb59..1d0f83756 100755 --- a/README.md +++ b/README.md @@ -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) ) by srs-librtmp. 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 RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). 1. [no-plan] Support multiple processes, for both origin and edge @@ -501,6 +508,10 @@ Supported operating systems and hardware: * 2013-10-17, Created.
## 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, 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 @@ -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-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 [#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 diff --git a/trunk/conf/dvr.path.conf b/trunk/conf/dvr.path.conf new file mode 100644 index 000000000..cb07d6612 --- /dev/null +++ b/trunk/conf/dvr.path.conf @@ -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; + } +} diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf old mode 100755 new mode 100644 index 6b6b273d7..3f7e860c9 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -142,6 +142,35 @@ http_stream { 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| + # 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 MW(merged-write) settings for player. vhost mrw.srs.com { @@ -207,15 +236,38 @@ vhost dvr.srs.com { # default: off enabled on; # the dvr output path. - # the app dir is auto created under the dvr_path. - # for example, for rtmp stream: - # rtmp://127.0.0.1/live/livestream - # http://127.0.0.1/live/livestream.m3u8 - # where dvr_path is /dvr, srs will create the following files: - # /dvr/live the app dir for all streams. - # /dvr/live/livestream.{time}.flv the dvr flv file. - # @remark, the time use system timestamp in ms, user can use http callback to rename it. - # in a word, the dvr_path is for vhost. + # we supports some variables to generate the filename. + # [vhost], the vhost of stream. + # [app], the app of stream. + # [stream], the stream name of stream. + # [2006], replace this const to current year. + # [01], replace this const to current month. + # [02], replace this const to current date. + # [15], replace this const to current hour. + # [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 dvr_path ./objs/nginx/html; # the dvr plan. canbe: @@ -244,6 +296,11 @@ vhost dvr.srs.com { # 3. off, disable the time jitter algorithm, like atc. # default: 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 { # http vhost specified config http { @@ -438,6 +495,20 @@ vhost hooks.callback.srs.com { # support multiple api hooks, format: # 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; + # 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, # active-active for cdn to build high available fault tolerance system. # 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; } +# 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 vhost mirror.transcode.srs.com { transcode { @@ -536,10 +701,8 @@ vhost mirror.transcode.srs.com { } } } -# # 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. -# ####################################################################################################### # the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop vhost crop.transcode.srs.com { @@ -656,97 +819,41 @@ vhost copy.transcode.srs.com { } } # transcode all app and stream of vhost +# the comments, read example.transcode.srs.com vhost all.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 ffsuper { - # 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]; } engine ffhd { diff --git a/trunk/conf/realtime.conf b/trunk/conf/realtime.conf old mode 100755 new mode 100644 diff --git a/trunk/conf/security.deny.publish.conf b/trunk/conf/security.deny.publish.conf new file mode 100644 index 000000000..a2c6e59da --- /dev/null +++ b/trunk/conf/security.deny.publish.conf @@ -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; + } +} diff --git a/trunk/configure b/trunk/configure index c543d150c..47265e6fb 100755 --- a/trunk/configure +++ b/trunk/configure @@ -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_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_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_OBJS="${MODULE_OBJS[@]}" fi diff --git a/trunk/research/api-server/server.py b/trunk/research/api-server/server.py index 8f0f51e61..8c1f4823b 100755 --- a/trunk/research/api-server/server.py +++ b/trunk/research/api-server/server.py @@ -240,6 +240,74 @@ class RESTStreams(object): 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 ''' @@ -1039,6 +1107,7 @@ class V1(object): self.clients = RESTClients() self.streams = RESTStreams() self.sessions = RESTSessions() + self.dvrs = RESTDvrs() self.chats = RESTChats() self.servers = RESTServers() self.nodes = RESTNodes() @@ -1048,6 +1117,7 @@ class V1(object): "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.", "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.", "nodes": { "summary": "for srs cdn node", diff --git a/trunk/scripts/git2unix.sh b/trunk/scripts/git2unix.sh index 4f78ada6f..9aeddfb00 100755 --- a/trunk/scripts/git2unix.sh +++ b/trunk/scripts/git2unix.sh @@ -15,7 +15,7 @@ ret=$?; if [[ 0 -ne $ret ]]; then exit $ret 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 dos2unix $file; echo $file|grep ".sh$" >/dev/null 2>&1; EOF_SH=$? diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 72031ad70..a6a695fb8 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -434,7 +434,8 @@ int SrsConfig::reload_conf(SrsConfig* conf) // always support reload without additional code: // chunk_size, ff_log_dir, max_connections, // bandcheck, http_hooks, heartbeat, - // token_traverse, debug_srs_upnode + // token_traverse, debug_srs_upnode, + // security // merge config: 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 != "debug_srs_upnode" && n != "mr" && n != "mw_latency" && n != "min_latency" + && n != "security" ) { ret = ERROR_SYSTEM_CONFIG_INVALID; 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(); if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" && m != "on_unpublish" && m != "on_play" && m != "on_stop" + && m != "on_dvr" ) { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); @@ -1440,6 +1443,16 @@ int SrsConfig::check_config() 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") { for (int j = 0; j < (int)conf->directives.size(); j++) { SrsConfDirective* trans = conf->at(j); @@ -2323,6 +2336,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) 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) { SrsConfDirective* conf = get_vhost(vhost); @@ -2456,6 +2480,43 @@ bool SrsConfig::get_vhost_edge_token_traverse(string vhost) 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* conf = get_vhost(vhost); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index aaf7f973f..80858be5a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -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_SUMMARIES false +#define SRS_CONF_DEFAULT_SECURITY_ENABLED false + #define SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX 0 #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. */ 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 public: /** @@ -659,6 +666,16 @@ public: * all clients connected to edge must be tranverse to origin to verify. */ 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 public: /** @@ -776,7 +793,7 @@ public: * @remark, we will use some variable, for instance, [vhost] to substitude with vhost. */ virtual std::string get_engine_output(SrsConfDirective* engine); -// ingest section +// vhost ingest section public: /** * get the ingest directives of vhost. diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index 06c70eaf9..631513698 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include using namespace std; #include @@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment() SrsRequest* req = _req; - // new flv file - std::stringstream path; + // the path in config, for example, + // /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) - << "/" << req->app << "/" - << req->stream << "." << srs_get_system_time_ms() << ".flv"; + // add [stream].[timestamp].flv as filename for dir + if (path_config.find(".flv") != path_config.length() - 4) { + 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; } dvr_enabled = true; @@ -320,6 +404,30 @@ int SrsDvrPlan::flv_close() 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; } diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index f08c0ac8f..460d03b0a 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir() app_dir += app; // 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 (::mkdir(app_dir.c_str(), mode) < 0) { - if (errno != EEXIST) { - ret = ERROR_HLS_CREATE_DIR; - srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret); - return ret; - } + + if ((ret = srs_create_dir_recursively(app_dir)) != ERROR_SUCCESS) { + 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; } diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index a0c43492e..41c752dde 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -26,7 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifdef SRS_AUTO_HTTP_API #include -#include using namespace std; #include @@ -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("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("vhosts", "list all vhosts") << __SRS_JFIELD_CONT - << __SRS_JFIELD_STR("streams", "list streams that match the name or vhost") + << __SRS_JFIELD_STR("vhosts", "dumps vhost to json") << __SRS_JFIELD_CONT + << __SRS_JFIELD_STR("streams", "dumps streams to json") << __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) { + std::stringstream data; + SrsStatistic* stat = SrsStatistic::instance(); + int ret = stat->dumps_vhosts(data); + std::stringstream ss; - std::set vhost_set; - SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool(); - SrsStreamInfoMap::iterator it; - for (it = pool->begin(); it != pool->end(); it++) { - if (it->second->_req == NULL) - continue; - vhost_set.insert(it->second->_req->vhost); - } - - ss << __SRS_JARRAY_START; - bool first = true; - std::set::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; + ss << __SRS_JOBJECT_START + << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("vhosts", __SRS_JARRAY_START) + << data.str() + << __SRS_JARRAY_END + << __SRS_JOBJECT_END; 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) { + std::stringstream data; + SrsStatistic* stat = SrsStatistic::instance(); + int ret = stat->dumps_streams(data); + std::stringstream ss; - std::string query_name = req->query_get("name"); - std::string query_vhost = req->query_get("vhost"); - if (query_name.size() > 0 || query_vhost.size() > 0) { - ss << __SRS_JARRAY_START; - bool first = true; - SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool(); - SrsStreamInfoMap::iterator it; - 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"); - } + ss << __SRS_JOBJECT_START + << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT + << __SRS_JFIELD_ORG("streams", __SRS_JARRAY_START) + << data.str() + << __SRS_JARRAY_END + << __SRS_JOBJECT_END; return res_json(skt, req, ss.str()); } diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp index 5d792c6a7..cfa4712f6 100644 --- a/trunk/src/app/srs_app_http_hooks.cpp +++ b/trunk/src/app/srs_app_http_hooks.cpp @@ -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_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("pageUrl", req->pageUrl) + << __SRS_JFIELD_STR("app", req->app) << __SRS_JOBJECT_END; std::string data = ss.str(); 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("vhost", req->vhost) << __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_JOBJECT_END; 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("vhost", req->vhost) << __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_JOBJECT_END; 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("vhost", req->vhost) << __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_JOBJECT_END; 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("vhost", req->vhost) << __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_JOBJECT_END; std::string data = ss.str(); @@ -384,5 +379,61 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req 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 diff --git a/trunk/src/app/srs_app_http_hooks.hpp b/trunk/src/app/srs_app_http_hooks.hpp index b6c9ca6a2..c4286d13c 100644 --- a/trunk/src/app/srs_app_http_hooks.hpp +++ b/trunk/src/app/srs_app_http_hooks.hpp @@ -58,7 +58,6 @@ public: * @param client_id the id of client on server. * @param url the api server url, to valid the client. * 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); /** @@ -73,7 +72,6 @@ public: * @param client_id the id of client on server. * @param url the api server url, to valid the client. * 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); /** @@ -88,7 +86,6 @@ public: * @param client_id the id of client on server. * @param url the api server url, to valid the client. * 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); /** @@ -98,6 +95,15 @@ public: * ignore if empty. */ 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 diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 43feda5a7..b7bb4d815 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -51,6 +51,7 @@ using namespace std; #include #include #include +#include #include // 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); refer = new SrsRefer(); bandwidth = new SrsBandwidth(); + security = new SrsSecurity(); duration = 0; kbps = new SrsKbps(); kbps->set_io(skt, skt); @@ -103,6 +105,7 @@ SrsRtmpConn::~SrsRtmpConn() srs_freep(skt); srs_freep(refer); srs_freep(bandwidth); + srs_freep(security); srs_freep(kbps); } @@ -133,6 +136,9 @@ int SrsRtmpConn::do_cycle() } srs_verbose("rtmp connect app success"); + // set client ip to request. + req->ip = ip; + // discovery vhost, resolve the vhost from config SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost); if (parsed_vhost) { @@ -361,6 +367,13 @@ int SrsRtmpConn::stream_service_cycle() req->strip(); srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f", 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. rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); @@ -383,7 +396,12 @@ int SrsRtmpConn::stream_service_cycle() } 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. if (type != SrsRtmpConnPlay && !vhost_is_edge) { diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index 111fc0f83..ea3fc7619 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -51,6 +51,7 @@ class SrsRtmpClient; class SrsSharedPtrMessage; class SrsQueueRecvThread; class SrsPublishRecvThread; +class SrsSecurity; /** * the client provides the main logic control for RTMP clients. @@ -66,6 +67,7 @@ private: SrsRtmpServer* rtmp; SrsRefer* refer; SrsBandwidth* bandwidth; + SrsSecurity* security; // elapse duration in ms // for live play duration, for instance, rtmpdump to record. // @see https://github.com/winlinvip/simple-rtmp-server/issues/47 diff --git a/trunk/src/app/srs_app_security.cpp b/trunk/src/app/srs_app_security.cpp new file mode 100644 index 000000000..b843e58b0 --- /dev/null +++ b/trunk/src/app/srs_app_security.cpp @@ -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 + +#include +#include + +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; +} + diff --git a/trunk/src/app/srs_app_security.hpp b/trunk/src/app/srs_app_security.hpp new file mode 100644 index 000000000..9f1e9dec4 --- /dev/null +++ b/trunk/src/app/srs_app_security.hpp @@ -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 +*/ + +#include + +#include + +#include + +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 + diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index d93dfe737..45e0019c7 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -23,53 +23,142 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include +#include +using namespace std; + #include +#include -SrsStreamInfo::SrsStreamInfo() +int64_t __srs_gvid = getpid(); + +int64_t __srs_generate_id() { - _req = NULL; + return __srs_gvid++; } -SrsStreamInfo::~SrsStreamInfo() +SrsStatisticVhost::SrsStatisticVhost() { - if (_req != NULL) - delete _req; + id = __srs_generate_id(); } -SrsStatistic *SrsStatistic::_instance = NULL; +SrsStatisticVhost::~SrsStatisticVhost() +{ +} + +SrsStatisticStream::SrsStatisticStream() +{ + id = __srs_generate_id(); + vhost = NULL; +} + +SrsStatisticStream::~SrsStatisticStream() +{ +} + +SrsStatistic* SrsStatistic::_instance = new SrsStatistic(); SrsStatistic::SrsStatistic() { - + _server_id = __srs_generate_id(); } SrsStatistic::~SrsStatistic() { - SrsStreamInfoMap::iterator it; - for (it = pool.begin(); it != pool.end(); it++) { - delete it->second; - } + if (true) { + std::map::iterator it; + for (it = vhosts.begin(); it != vhosts.end(); it++) { + SrsStatisticVhost* vhost = it->second; + srs_freep(vhost); + } + } + if (true) { + std::map::iterator it; + for (it = streams.begin(); it != streams.end(); it++) { + SrsStatisticStream* stream = it->second; + srs_freep(stream); + } + } + if (true) { + std::map::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); - if (it == pool.end()) { - pool[p] = new SrsStreamInfo(); - return pool[p]; - } else { - return it->second; - } + int ret = ERROR_SUCCESS; + + // create vhost if not exists. + SrsStatisticVhost* vhost = NULL; + if (vhosts.find(req->vhost) == vhosts.end()) { + 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); - if (info->_req == NULL) - info->_req = req->copy(); -} \ No newline at end of file + return _server_id; +} + +int SrsStatistic::dumps_vhosts(stringstream& ss) +{ + int ret = ERROR_SUCCESS; + + std::map::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::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; +} diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 42e0d81d2..f261962ea 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -31,40 +31,78 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include class SrsRequest; -class SrsStreamInfo +struct SrsStatisticVhost { public: - SrsStreamInfo(); - virtual ~SrsStreamInfo(); - - SrsRequest *_req; + int64_t id; + std::string vhost; +public: + 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 SrsStreamInfoMap; class SrsStatistic { -public: - static SrsStatistic *instance() - { - if (_instance == NULL) { - _instance = new SrsStatistic(); - } - return _instance; - } - - virtual SrsStreamInfoMap* get_pool(); - - virtual void add_request_info(void *p, SrsRequest *req); - +private: + static SrsStatistic *_instance; + // the id to identify the sever. + int64_t _server_id; + // key: vhost name, value: vhost object. + std::map vhosts; + // key: stream name, value: stream object. + std::map streams; + // key: client id, value: stream object. + std::map clients; private: SrsStatistic(); virtual ~SrsStatistic(); - static SrsStatistic *_instance; - SrsStreamInfoMap pool; - virtual SrsStreamInfo *get(void *p); +public: + static SrsStatistic* instance(); +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 \ No newline at end of file +#endif diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index e5a742acc..327630442 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR 2 #define VERSION_MINOR 0 -#define VERSION_REVISION 85 +#define VERSION_REVISION 89 // server info. #define RTMP_SIG_SRS_KEY "SRS" #define RTMP_SIG_SRS_ROLE "origin/edge server" diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 7bbfeb525..d8907ef96 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -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_IO_INVALID 1050 #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. @@ -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_DECODE_ERROR 3001 -#define ERROR_HLS_CREATE_DIR 3002 +//#define ERROR_HLS_CREATE_DIR 3002 #define ERROR_HLS_OPEN_FAILED 3003 #define ERROR_HLS_WRITE_FAILED 3004 #define ERROR_HLS_AAC_FRAME_LENGTH 3005 diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index c19fb7d05..1bb6bee35 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #endif #include +#include +#include using namespace std; #include +#include // this value must: // 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(); } +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; +} + diff --git a/trunk/src/kernel/srs_kernel_utility.hpp b/trunk/src/kernel/srs_kernel_utility.hpp index 36d2155cd..a1a03e0ed 100644 --- a/trunk/src/kernel/srs_kernel_utility.hpp +++ b/trunk/src/kernel/srs_kernel_utility.hpp @@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars); // whether string end with 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 diff --git a/trunk/src/rtmp/srs_protocol_rtmp.cpp b/trunk/src/rtmp/srs_protocol_rtmp.cpp index d1ab088b3..713910bf9 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp.cpp +++ b/trunk/src/rtmp/srs_protocol_rtmp.cpp @@ -91,6 +91,7 @@ SrsRequest* SrsRequest::copy() { SrsRequest* cp = new SrsRequest(); + cp->ip = ip; cp->app = app; cp->objectEncoding = objectEncoding; cp->pageUrl = pageUrl; diff --git a/trunk/src/rtmp/srs_protocol_rtmp.hpp b/trunk/src/rtmp/srs_protocol_rtmp.hpp index a8de64d56..7451823f1 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp.hpp +++ b/trunk/src/rtmp/srs_protocol_rtmp.hpp @@ -53,6 +53,9 @@ class IMergeReadHandler; */ class SrsRequest { +public: + // client ip. + std::string ip; public: /** * tcUrl: rtmp://request_vhost:port/app/stream diff --git a/trunk/src/srs/srs.upp b/trunk/src/srs/srs.upp index c400d51a7..b267c032a 100755 --- a/trunk/src/srs/srs.upp +++ b/trunk/src/srs/srs.upp @@ -1,151 +1,155 @@ file - main readonly separator, - ..\main\srs_main_server.cpp, - auto readonly separator, - ..\..\objs\srs_auto_headers.hpp, - libs readonly separator, - ..\libs\srs_librtmp.hpp, - ..\libs\srs_librtmp.cpp, - ..\libs\srs_lib_bandwidth.hpp, - ..\libs\srs_lib_bandwidth.cpp, - ..\libs\srs_lib_simple_socket.hpp, - ..\libs\srs_lib_simple_socket.cpp, - core readonly separator, - ..\core\srs_core.hpp, - ..\core\srs_core.cpp, - ..\core\srs_core_autofree.hpp, - ..\core\srs_core_autofree.cpp, - ..\core\srs_core_performance.hpp, - ..\core\srs_core_performance.cpp, - kernel readonly separator, - ..\kernel\srs_kernel_codec.hpp, - ..\kernel\srs_kernel_codec.cpp, - ..\kernel\srs_kernel_consts.hpp, - ..\kernel\srs_kernel_consts.cpp, - ..\kernel\srs_kernel_error.hpp, - ..\kernel\srs_kernel_error.cpp, - ..\kernel\srs_kernel_file.hpp, - ..\kernel\srs_kernel_file.cpp, - ..\kernel\srs_kernel_flv.hpp, - ..\kernel\srs_kernel_flv.cpp, - ..\kernel\srs_kernel_log.hpp, - ..\kernel\srs_kernel_log.cpp, - ..\kernel\srs_kernel_stream.hpp, - ..\kernel\srs_kernel_stream.cpp, - ..\kernel\srs_kernel_utility.hpp, - ..\kernel\srs_kernel_utility.cpp, - rtmp-protocol readonly separator, - ..\rtmp\srs_protocol_amf0.hpp, - ..\rtmp\srs_protocol_amf0.cpp, - ..\rtmp\srs_protocol_buffer.hpp, - ..\rtmp\srs_protocol_buffer.cpp, - ..\rtmp\srs_protocol_handshake.hpp, - ..\rtmp\srs_protocol_handshake.cpp, - ..\rtmp\srs_protocol_io.hpp, - ..\rtmp\srs_protocol_io.cpp, - ..\rtmp\srs_protocol_msg_array.hpp, - ..\rtmp\srs_protocol_msg_array.cpp, - ..\rtmp\srs_protocol_rtmp.hpp, - ..\rtmp\srs_protocol_rtmp.cpp, - ..\rtmp\srs_protocol_stack.hpp, - ..\rtmp\srs_protocol_stack.cpp, - ..\rtmp\srs_protocol_utility.hpp, - ..\rtmp\srs_protocol_utility.cpp, - app readonly separator, - ..\app\srs_app_avc_aac.hpp, - ..\app\srs_app_avc_aac.cpp, - ..\app\srs_app_bandwidth.hpp, - ..\app\srs_app_bandwidth.cpp, - ..\app\srs_app_conn.hpp, - ..\app\srs_app_conn.cpp, - ..\app\srs_app_config.hpp, - ..\app\srs_app_config.cpp, - ..\app\srs_app_dvr.hpp, - ..\app\srs_app_dvr.cpp, - ..\app\srs_app_edge.hpp, - ..\app\srs_app_edge.cpp, - ..\app\srs_app_empty.hpp, - ..\app\srs_app_empty.cpp, - ..\app\srs_app_encoder.hpp, - ..\app\srs_app_encoder.cpp, - ..\app\srs_app_ffmpeg.hpp, - ..\app\srs_app_ffmpeg.cpp, - ..\app\srs_app_forward.hpp, - ..\app\srs_app_forward.cpp, - ..\app\srs_app_heartbeat.hpp, - ..\app\srs_app_heartbeat.cpp, - ..\app\srs_app_hls.hpp, - ..\app\srs_app_hls.cpp, - ..\app\srs_app_http.hpp, - ..\app\srs_app_http.cpp, - ..\app\srs_app_http_api.hpp, - ..\app\srs_app_http_api.cpp, - ..\app\srs_app_http_client.hpp, - ..\app\srs_app_http_client.cpp, - ..\app\srs_app_http_conn.hpp, - ..\app\srs_app_http_conn.cpp, - ..\app\srs_app_http_hooks.hpp, - ..\app\srs_app_http_hooks.cpp, - ..\app\srs_app_ingest.hpp, - ..\app\srs_app_ingest.cpp, - ..\app\srs_app_json.hpp, - ..\app\srs_app_json.cpp, - ..\app\srs_app_kbps.hpp, - ..\app\srs_app_kbps.cpp, - ..\app\srs_app_log.hpp, - ..\app\srs_app_log.cpp, - ..\app\srs_app_recv_thread.hpp, - ..\app\srs_app_recv_thread.cpp, - ..\app\srs_app_refer.hpp, - ..\app\srs_app_refer.cpp, - ..\app\srs_app_reload.hpp, - ..\app\srs_app_reload.cpp, - ..\app\srs_app_rtmp_conn.hpp, - ..\app\srs_app_rtmp_conn.cpp, - ..\app\srs_app_pithy_print.hpp, - ..\app\srs_app_pithy_print.cpp, - ..\app\srs_app_server.hpp, - ..\app\srs_app_server.cpp, - ..\app\srs_app_st.hpp, - ..\app\srs_app_st.cpp, - ..\app\srs_app_st_socket.hpp, - ..\app\srs_app_st_socket.cpp, - ..\app\srs_app_source.hpp, - ..\app\srs_app_source.cpp, - ..\app\srs_app_thread.hpp, - ..\app\srs_app_thread.cpp, - ..\app\srs_app_utility.hpp, - ..\app\srs_app_utility.cpp, - utest readonly separator, - ..\utest\srs_utest.hpp, - ..\utest\srs_utest.cpp, - ..\utest\srs_utest_amf0.hpp, - ..\utest\srs_utest_amf0.cpp, - ..\utest\srs_utest_config.hpp, - ..\utest\srs_utest_config.cpp, - ..\utest\srs_utest_core.hpp, - ..\utest\srs_utest_core.cpp, - ..\utest\srs_utest_kernel.hpp, - ..\utest\srs_utest_kernel.cpp, - ..\utest\srs_utest_protocol.hpp, - ..\utest\srs_utest_protocol.cpp, - ..\utest\srs_utest_reload.hpp, - ..\utest\srs_utest_reload.cpp, - research readonly separator, - ..\..\research\librtmp\srs_aac_raw_publish.c, - ..\..\research\librtmp\srs_audio_raw_publish.c, - ..\..\research\librtmp\srs_bandwidth_check.c, - ..\..\research\librtmp\srs_detect_rtmp.c, - ..\..\research\librtmp\srs_flv_injecter.c, - ..\..\research\librtmp\srs_flv_parser.c, - ..\..\research\librtmp\srs_h264_raw_publish.c, - ..\..\research\librtmp\srs_ingest_flv.c, - ..\..\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; + main readonly separator, + ..\main\srs_main_server.cpp, + auto readonly separator, + ..\..\objs\srs_auto_headers.hpp, + libs readonly separator, + ..\libs\srs_librtmp.hpp, + ..\libs\srs_librtmp.cpp, + ..\libs\srs_lib_bandwidth.hpp, + ..\libs\srs_lib_bandwidth.cpp, + ..\libs\srs_lib_simple_socket.hpp, + ..\libs\srs_lib_simple_socket.cpp, + core readonly separator, + ..\core\srs_core.hpp, + ..\core\srs_core.cpp, + ..\core\srs_core_autofree.hpp, + ..\core\srs_core_autofree.cpp, + ..\core\srs_core_performance.hpp, + ..\core\srs_core_performance.cpp, + kernel readonly separator, + ..\kernel\srs_kernel_codec.hpp, + ..\kernel\srs_kernel_codec.cpp, + ..\kernel\srs_kernel_consts.hpp, + ..\kernel\srs_kernel_consts.cpp, + ..\kernel\srs_kernel_error.hpp, + ..\kernel\srs_kernel_error.cpp, + ..\kernel\srs_kernel_file.hpp, + ..\kernel\srs_kernel_file.cpp, + ..\kernel\srs_kernel_flv.hpp, + ..\kernel\srs_kernel_flv.cpp, + ..\kernel\srs_kernel_log.hpp, + ..\kernel\srs_kernel_log.cpp, + ..\kernel\srs_kernel_stream.hpp, + ..\kernel\srs_kernel_stream.cpp, + ..\kernel\srs_kernel_utility.hpp, + ..\kernel\srs_kernel_utility.cpp, + rtmp-protocol readonly separator, + ..\rtmp\srs_protocol_amf0.hpp, + ..\rtmp\srs_protocol_amf0.cpp, + ..\rtmp\srs_protocol_buffer.hpp, + ..\rtmp\srs_protocol_buffer.cpp, + ..\rtmp\srs_protocol_handshake.hpp, + ..\rtmp\srs_protocol_handshake.cpp, + ..\rtmp\srs_protocol_io.hpp, + ..\rtmp\srs_protocol_io.cpp, + ..\rtmp\srs_protocol_msg_array.hpp, + ..\rtmp\srs_protocol_msg_array.cpp, + ..\rtmp\srs_protocol_rtmp.hpp, + ..\rtmp\srs_protocol_rtmp.cpp, + ..\rtmp\srs_protocol_stack.hpp, + ..\rtmp\srs_protocol_stack.cpp, + ..\rtmp\srs_protocol_utility.hpp, + ..\rtmp\srs_protocol_utility.cpp, + app readonly separator, + ..\app\srs_app_avc_aac.hpp, + ..\app\srs_app_avc_aac.cpp, + ..\app\srs_app_bandwidth.hpp, + ..\app\srs_app_bandwidth.cpp, + ..\app\srs_app_conn.hpp, + ..\app\srs_app_conn.cpp, + ..\app\srs_app_config.hpp, + ..\app\srs_app_config.cpp, + ..\app\srs_app_dvr.hpp, + ..\app\srs_app_dvr.cpp, + ..\app\srs_app_edge.hpp, + ..\app\srs_app_edge.cpp, + ..\app\srs_app_empty.hpp, + ..\app\srs_app_empty.cpp, + ..\app\srs_app_encoder.hpp, + ..\app\srs_app_encoder.cpp, + ..\app\srs_app_ffmpeg.hpp, + ..\app\srs_app_ffmpeg.cpp, + ..\app\srs_app_forward.hpp, + ..\app\srs_app_forward.cpp, + ..\app\srs_app_heartbeat.hpp, + ..\app\srs_app_heartbeat.cpp, + ..\app\srs_app_hls.hpp, + ..\app\srs_app_hls.cpp, + ..\app\srs_app_http.hpp, + ..\app\srs_app_http.cpp, + ..\app\srs_app_http_api.hpp, + ..\app\srs_app_http_api.cpp, + ..\app\srs_app_http_client.hpp, + ..\app\srs_app_http_client.cpp, + ..\app\srs_app_http_conn.hpp, + ..\app\srs_app_http_conn.cpp, + ..\app\srs_app_http_hooks.hpp, + ..\app\srs_app_http_hooks.cpp, + ..\app\srs_app_ingest.hpp, + ..\app\srs_app_ingest.cpp, + ..\app\srs_app_json.hpp, + ..\app\srs_app_json.cpp, + ..\app\srs_app_kbps.hpp, + ..\app\srs_app_kbps.cpp, + ..\app\srs_app_log.hpp, + ..\app\srs_app_log.cpp, + ..\app\srs_app_recv_thread.hpp, + ..\app\srs_app_recv_thread.cpp, + ..\app\srs_app_refer.hpp, + ..\app\srs_app_refer.cpp, + ..\app\srs_app_reload.hpp, + ..\app\srs_app_reload.cpp, + ..\app\srs_app_rtmp_conn.hpp, + ..\app\srs_app_rtmp_conn.cpp, + ..\app\srs_app_pithy_print.hpp, + ..\app\srs_app_pithy_print.cpp, + ..\app\srs_app_security.hpp, + ..\app\srs_app_security.cpp, + ..\app\srs_app_server.hpp, + ..\app\srs_app_server.cpp, + ..\app\srs_app_st.hpp, + ..\app\srs_app_st.cpp, + ..\app\srs_app_st_socket.hpp, + ..\app\srs_app_st_socket.cpp, + ..\app\srs_app_statistic.hpp, + ..\app\srs_app_statistic.cpp, + ..\app\srs_app_source.hpp, + ..\app\srs_app_source.cpp, + ..\app\srs_app_thread.hpp, + ..\app\srs_app_thread.cpp, + ..\app\srs_app_utility.hpp, + ..\app\srs_app_utility.cpp, + utest readonly separator, + ..\utest\srs_utest.hpp, + ..\utest\srs_utest.cpp, + ..\utest\srs_utest_amf0.hpp, + ..\utest\srs_utest_amf0.cpp, + ..\utest\srs_utest_config.hpp, + ..\utest\srs_utest_config.cpp, + ..\utest\srs_utest_core.hpp, + ..\utest\srs_utest_core.cpp, + ..\utest\srs_utest_kernel.hpp, + ..\utest\srs_utest_kernel.cpp, + ..\utest\srs_utest_protocol.hpp, + ..\utest\srs_utest_protocol.cpp, + ..\utest\srs_utest_reload.hpp, + ..\utest\srs_utest_reload.cpp, + research readonly separator, + ..\..\research\librtmp\srs_aac_raw_publish.c, + ..\..\research\librtmp\srs_audio_raw_publish.c, + ..\..\research\librtmp\srs_bandwidth_check.c, + ..\..\research\librtmp\srs_detect_rtmp.c, + ..\..\research\librtmp\srs_flv_injecter.c, + ..\..\research\librtmp\srs_flv_parser.c, + ..\..\research\librtmp\srs_h264_raw_publish.c, + ..\..\research\librtmp\srs_ingest_flv.c, + ..\..\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 - "" = "MAIN"; + "" = "MAIN"; diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index 14beb553f..52124ff68 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -1206,12 +1206,12 @@ VOID TEST(KernelStreamTest, StreamRead8Bytes) data[18] = 0x13; data[19] = 0x14; - EXPECT_EQ(0x0102030405060708, s.read_8bytes()); - EXPECT_EQ(0x090a0b0c0d0e0f10, s.read_8bytes()); + EXPECT_EQ(0x0102030405060708LL, s.read_8bytes()); + EXPECT_EQ(0x090a0b0c0d0e0f10LL, s.read_8bytes()); s.skip(-1 * s.pos()); 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)); - s.write_8bytes(0x1011121314151617); - s.write_8bytes(0x1819202122232425); + s.write_8bytes(0x1011121314151617LL); + s.write_8bytes(0x1819202122232425LL); s.skip(-1 * s.pos()); EXPECT_EQ(0x10, s.read_1bytes());