tufang14

Merge pull request #1 from winlinvip/develop

merge origin
@@ -468,6 +468,13 @@ Supported operating systems and hardware: @@ -468,6 +468,13 @@ Supported operating systems and hardware:
468 [EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream) 468 [EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream)
469 ) by srs-librtmp. 469 ) by srs-librtmp.
470 1. Support 0.1s+ latency, read [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257). 470 1. Support 0.1s+ latency, read [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257).
  471 +1. Support allow/deny publish/play for all or specified ip(
  472 +[CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_Security),
  473 +[EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_Security)
  474 +).
  475 +1. Support custom dvr path and http callback, read
  476 +[#179](https://github.com/winlinvip/simple-rtmp-server/issues/179) and
  477 +[274](https://github.com/winlinvip/simple-rtmp-server/issues/274).
471 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech). 478 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
472 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). 479 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
473 1. [no-plan] Support multiple processes, for both origin and edge 480 1. [no-plan] Support multiple processes, for both origin and edge
@@ -501,6 +508,10 @@ Supported operating systems and hardware: @@ -501,6 +508,10 @@ Supported operating systems and hardware:
501 * 2013-10-17, Created.<br/> 508 * 2013-10-17, Created.<br/>
502 509
503 ## History 510 ## History
  511 +* 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
  512 +* v2.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 2.0.88
  513 +* 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
  514 +* 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
504 * 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 515 * 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
505 * 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 516 * 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
506 * 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 517 * 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: @@ -550,6 +561,7 @@ Supported operating systems and hardware:
550 * v2.0, 2014-10-18, remove supports for OSX(darwin). 2.0.1. 561 * v2.0, 2014-10-18, remove supports for OSX(darwin). 2.0.1.
551 * v2.0, 2014-10-16, revert github srs README to English. 2.0.0. 562 * v2.0, 2014-10-16, revert github srs README to English. 2.0.0.
552 563
  564 +* v1.0, 2015-01-03, hotfix to remove the pageUrl for http callback. 1.0.19
553 * 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 565 * 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
554 * 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 566 * 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
555 * 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 567 * 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
  1 +# the config for srs to dvr in custom path.
  2 +# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
  3 +# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
  4 +# @see full.conf for detail config.
  5 +
  6 +listen 1935;
  7 +max_connections 1000;
  8 +vhost __defaultVhost__ {
  9 + dvr {
  10 + enabled on;
  11 + dvr_path ./objs/nginx/html/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
  12 + dvr_plan segment;
  13 + dvr_duration 30;
  14 + dvr_wait_keyframe on;
  15 + }
  16 +}
@@ -142,6 +142,35 @@ http_stream { @@ -142,6 +142,35 @@ http_stream {
142 vhost __defaultVhost__ { 142 vhost __defaultVhost__ {
143 } 143 }
144 144
  145 +# the security to allow or deny clients.
  146 +vhost security.srs.com {
  147 + # security for host to allow or deny clients.
  148 + # @see https://github.com/winlinvip/simple-rtmp-server/issues/211
  149 + security {
  150 + # whether enable the security for vhost.
  151 + # default: off
  152 + enabled on;
  153 + # the security list, each item format as:
  154 + # allow|deny publish|play all|<ip>
  155 + # for example:
  156 + # allow publish all;
  157 + # deny publish all;
  158 + # allow publish 127.0.0.1;
  159 + # deny publish 127.0.0.1;
  160 + # allow play all;
  161 + # deny play all;
  162 + # allow play 127.0.0.1;
  163 + # deny play 127.0.0.1;
  164 + # SRS apply the following simple strategies one by one:
  165 + # 1. allow all if security disabled.
  166 + # 2. default to deny all when security enabled.
  167 + # 3. allow if matches allow strategy.
  168 + # 4. deny if matches deny strategy.
  169 + allow play all;
  170 + allow publish all;
  171 + }
  172 +}
  173 +
145 # the MR(merged-read) setting for publisher. 174 # the MR(merged-read) setting for publisher.
146 # the MW(merged-write) settings for player. 175 # the MW(merged-write) settings for player.
147 vhost mrw.srs.com { 176 vhost mrw.srs.com {
@@ -207,15 +236,38 @@ vhost dvr.srs.com { @@ -207,15 +236,38 @@ vhost dvr.srs.com {
207 # default: off 236 # default: off
208 enabled on; 237 enabled on;
209 # the dvr output path. 238 # the dvr output path.
210 - # the app dir is auto created under the dvr_path.  
211 - # for example, for rtmp stream:  
212 - # rtmp://127.0.0.1/live/livestream  
213 - # http://127.0.0.1/live/livestream.m3u8  
214 - # where dvr_path is /dvr, srs will create the following files:  
215 - # /dvr/live the app dir for all streams.  
216 - # /dvr/live/livestream.{time}.flv the dvr flv file.  
217 - # @remark, the time use system timestamp in ms, user can use http callback to rename it.  
218 - # in a word, the dvr_path is for vhost. 239 + # we supports some variables to generate the filename.
  240 + # [vhost], the vhost of stream.
  241 + # [app], the app of stream.
  242 + # [stream], the stream name of stream.
  243 + # [2006], replace this const to current year.
  244 + # [01], replace this const to current month.
  245 + # [02], replace this const to current date.
  246 + # [15], replace this const to current hour.
  247 + # [04], repleace this const to current minute.
  248 + # [05], repleace this const to current second.
  249 + # [999], repleace this const to current millisecond.
  250 + # [timestamp],replace this const to current UNIX timestamp in ms.
  251 + # @remark we use golang time format "2006-01-02 15:04:05.999"
  252 + # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776
  253 + # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
  254 + # dvr_path ./objs/nginx/html;
  255 + # =>
  256 + # dvr_path ./objs/nginx/html/live/livestream.1420254068776.flv;
  257 + # 2. Use stream and date as dir name, time as filename:
  258 + # dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv;
  259 + # =>
  260 + # dvr_path /data/ossrs.net/live/livestream/2015/01/03/10.57.30.776.flv;
  261 + # 3. Use stream and year/month as dir name, date and time as filename:
  262 + # dvr_path /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]-[15].[04].[05].[999].flv;
  263 + # =>
  264 + # dvr_path /data/ossrs.net/live/livestream/2015/01/03-10.57.30.776.flv;
  265 + # 4. Use vhost/app and year/month as dir name, stream/date/time as filename:
  266 + # dvr_path /data/[vhost]/[app]/[2006]/[01]/[stream]-[02]-[15].[04].[05].[999].flv;
  267 + # =>
  268 + # dvr_path /data/ossrs.net/live/2015/01/livestream-03-10.57.30.776.flv;
  269 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
  270 + # @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
219 # default: ./objs/nginx/html 271 # default: ./objs/nginx/html
220 dvr_path ./objs/nginx/html; 272 dvr_path ./objs/nginx/html;
221 # the dvr plan. canbe: 273 # the dvr plan. canbe:
@@ -244,6 +296,11 @@ vhost dvr.srs.com { @@ -244,6 +296,11 @@ vhost dvr.srs.com {
244 # 3. off, disable the time jitter algorithm, like atc. 296 # 3. off, disable the time jitter algorithm, like atc.
245 # default: full 297 # default: full
246 time_jitter full; 298 time_jitter full;
  299 +
  300 + # on_dvr
  301 + # for the dvr http callback, @see http_hooks.on_dvr of vhost hooks.callback.srs.com
  302 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#http-callback
  303 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#http-callback
247 } 304 }
248 } 305 }
249 306
@@ -286,7 +343,7 @@ vhost ingest.srs.com { @@ -286,7 +343,7 @@ vhost ingest.srs.com {
286 } 343 }
287 } 344 }
288 345
289 -# vhost for http 346 +# vhost for http server config in each vhost.
290 vhost http.srs.com { 347 vhost http.srs.com {
291 # http vhost specified config 348 # http vhost specified config
292 http { 349 http {
@@ -438,6 +495,20 @@ vhost hooks.callback.srs.com { @@ -438,6 +495,20 @@ vhost hooks.callback.srs.com {
438 # support multiple api hooks, format: 495 # support multiple api hooks, format:
439 # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN 496 # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
440 on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions; 497 on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
  498 + # when srs reap a dvr file, call the hook,
  499 + # the request in the POST data string is a object encode by json:
  500 + # {
  501 + # "action": "on_dvr",
  502 + # "client_id": 1985,
  503 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  504 + # "stream": "livestream",
  505 + # "cwd": "/usr/local/srs",
  506 + # "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
  507 + # }
  508 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  509 + # an int value specifies the error code(0 corresponding to success):
  510 + # 0
  511 + on_dvr http://127.0.0.1:8085/api/v1/dvrs http://localhost:8085/api/v1/dvrs;
441 } 512 }
442 } 513 }
443 514
@@ -501,11 +572,105 @@ vhost same.vhost.forward.srs.com { @@ -501,11 +572,105 @@ vhost same.vhost.forward.srs.com {
501 # this used to split/forward the current stream for cluster active-standby, 572 # this used to split/forward the current stream for cluster active-standby,
502 # active-active for cdn to build high available fault tolerance system. 573 # active-active for cdn to build high available fault tolerance system.
503 # format: {ip}:{port} {ip_N}:{port_N} 574 # format: {ip}:{port} {ip_N}:{port_N}
504 - # or specify the vhost by params, @see: change.vhost.forward.srs.com  
505 - # if vhost not specified, use the request vhost instead.  
506 forward 127.0.0.1:1936 127.0.0.1:1937; 575 forward 127.0.0.1:1936 127.0.0.1:1937;
507 } 576 }
508 577
  578 +# the main comments for transcode
  579 +vhost example.transcode.srs.com {
  580 + # the streaming transcode configs.
  581 + transcode {
  582 + # whether the transcode enabled.
  583 + # if off, donot transcode.
  584 + # default: off.
  585 + enabled on;
  586 + # the ffmpeg
  587 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
  588 + # the transcode engine for matched stream.
  589 + # all matched stream will transcoded to the following stream.
  590 + # the transcode set name(ie. hd) is optional and not used.
  591 + engine example {
  592 + # whether the engine is enabled
  593 + # default: off.
  594 + enabled on;
  595 + # input format, can be:
  596 + # off, do not specifies the format, ffmpeg will guess it.
  597 + # flv, for flv or RTMP stream.
  598 + # other format, for example, mp4/aac whatever.
  599 + # default: flv
  600 + iformat flv;
  601 + # ffmpeg filters, follows the main input.
  602 + vfilter {
  603 + # the logo input file.
  604 + i ./doc/ffmpeg-logo.png;
  605 + # the ffmpeg complex filter.
  606 + # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html
  607 + filter_complex 'overlay=10:10';
  608 + }
  609 + # video encoder name. can be:
  610 + # libx264: use h.264(libx264) video encoder.
  611 + # copy: donot encoder the video stream, copy it.
  612 + # vn: disable video output.
  613 + vcodec libx264;
  614 + # video bitrate, in kbps
  615 + vbitrate 1500;
  616 + # video framerate.
  617 + vfps 25;
  618 + # video width, must be even numbers.
  619 + vwidth 768;
  620 + # video height, must be even numbers.
  621 + vheight 320;
  622 + # the max threads for ffmpeg to used.
  623 + vthreads 12;
  624 + # x264 profile, @see x264 -help, can be:
  625 + # high,main,baseline
  626 + vprofile main;
  627 + # x264 preset, @see x264 -help, can be:
  628 + # ultrafast,superfast,veryfast,faster,fast
  629 + # medium,slow,slower,veryslow,placebo
  630 + vpreset medium;
  631 + # other x264 or ffmpeg video params
  632 + vparams {
  633 + # ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html
  634 + t 100;
  635 + # 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264
  636 + coder 1;
  637 + b_strategy 2;
  638 + bf 3;
  639 + refs 10;
  640 + }
  641 + # audio encoder name. can be:
  642 + # libaacplus: use aac(libaacplus) audio encoder.
  643 + # copy: donot encoder the audio stream, copy it.
  644 + # an: disable audio output.
  645 + acodec libaacplus;
  646 + # audio bitrate, in kbps. [16, 72] for libaacplus.
  647 + abitrate 70;
  648 + # audio sample rate. for flv/rtmp, it must be:
  649 + # 44100,22050,11025,5512
  650 + asample_rate 44100;
  651 + # audio channel, 1 for mono, 2 for stereo.
  652 + achannels 2;
  653 + # other ffmpeg audio params
  654 + aparams {
  655 + # audio params, @see: http://ffmpeg.org/ffmpeg-codecs.html#Audio-Encoders
  656 + profile:a aac_low;
  657 + }
  658 + # output format, can be:
  659 + # off, do not specifies the format, ffmpeg will guess it.
  660 + # flv, for flv or RTMP stream.
  661 + # other format, for example, mp4/aac whatever.
  662 + # default: flv
  663 + oformat flv;
  664 + # output stream. variables:
  665 + # [vhost] the input stream vhost.
  666 + # [port] the intput stream port.
  667 + # [app] the input stream app.
  668 + # [stream] the input stream name.
  669 + # [engine] the tanscode engine name.
  670 + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
  671 + }
  672 + }
  673 +}
509 # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction 674 # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction
510 vhost mirror.transcode.srs.com { 675 vhost mirror.transcode.srs.com {
511 transcode { 676 transcode {
@@ -536,10 +701,8 @@ vhost mirror.transcode.srs.com { @@ -536,10 +701,8 @@ vhost mirror.transcode.srs.com {
536 } 701 }
537 } 702 }
538 } 703 }
539 -#  
540 # the drawtext filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#drawtext-1 704 # the drawtext filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#drawtext-1
541 # remark: we remove the libfreetype which always cause build failed, you must add it manual if needed. 705 # remark: we remove the libfreetype which always cause build failed, you must add it manual if needed.
542 -#  
543 ####################################################################################################### 706 #######################################################################################################
544 # the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop 707 # the crop filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#crop
545 vhost crop.transcode.srs.com { 708 vhost crop.transcode.srs.com {
@@ -656,97 +819,41 @@ vhost copy.transcode.srs.com { @@ -656,97 +819,41 @@ vhost copy.transcode.srs.com {
656 } 819 }
657 } 820 }
658 # transcode all app and stream of vhost 821 # transcode all app and stream of vhost
  822 +# the comments, read example.transcode.srs.com
659 vhost all.transcode.srs.com { 823 vhost all.transcode.srs.com {
660 - # the streaming transcode configs.  
661 transcode { 824 transcode {
662 - # whether the transcode enabled.  
663 - # if off, donot transcode.  
664 - # default: off.  
665 enabled on; 825 enabled on;
666 - # the ffmpeg  
667 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 826 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
668 - # the transcode engine for matched stream.  
669 - # all matched stream will transcoded to the following stream.  
670 - # the transcode set name(ie. hd) is optional and not used.  
671 engine ffsuper { 827 engine ffsuper {
672 - # whether the engine is enabled  
673 - # default: off.  
674 enabled on; 828 enabled on;
675 - # input format, can be:  
676 - # off, do not specifies the format, ffmpeg will guess it.  
677 - # flv, for flv or RTMP stream.  
678 - # other format, for example, mp4/aac whatever.  
679 - # default: flv  
680 iformat flv; 829 iformat flv;
681 - # ffmpeg filters, follows the main input.  
682 vfilter { 830 vfilter {
683 - # the logo input file.  
684 i ./doc/ffmpeg-logo.png; 831 i ./doc/ffmpeg-logo.png;
685 - # the ffmpeg complex filter.  
686 - # for filters, @see: http://ffmpeg.org/ffmpeg-filters.html  
687 filter_complex 'overlay=10:10'; 832 filter_complex 'overlay=10:10';
688 } 833 }
689 - # video encoder name. can be:  
690 - # libx264: use h.264(libx264) video encoder.  
691 - # copy: donot encoder the video stream, copy it.  
692 - # vn: disable video output.  
693 vcodec libx264; 834 vcodec libx264;
694 - # video bitrate, in kbps  
695 vbitrate 1500; 835 vbitrate 1500;
696 - # video framerate.  
697 vfps 25; 836 vfps 25;
698 - # video width, must be even numbers.  
699 vwidth 768; 837 vwidth 768;
700 - # video height, must be even numbers.  
701 vheight 320; 838 vheight 320;
702 - # the max threads for ffmpeg to used.  
703 vthreads 12; 839 vthreads 12;
704 - # x264 profile, @see x264 -help, can be:  
705 - # high,main,baseline  
706 vprofile main; 840 vprofile main;
707 - # x264 preset, @see x264 -help, can be:  
708 - # ultrafast,superfast,veryfast,faster,fast  
709 - # medium,slow,slower,veryslow,placebo  
710 vpreset medium; 841 vpreset medium;
711 - # other x264 or ffmpeg video params  
712 vparams { 842 vparams {
713 - # ffmpeg options, @see: http://ffmpeg.org/ffmpeg.html  
714 t 100; 843 t 100;
715 - # 264 params, @see: http://ffmpeg.org/ffmpeg-codecs.html#libx264  
716 coder 1; 844 coder 1;
717 b_strategy 2; 845 b_strategy 2;
718 bf 3; 846 bf 3;
719 refs 10; 847 refs 10;
720 } 848 }
721 - # audio encoder name. can be:  
722 - # libaacplus: use aac(libaacplus) audio encoder.  
723 - # copy: donot encoder the audio stream, copy it.  
724 - # an: disable audio output.  
725 acodec libaacplus; 849 acodec libaacplus;
726 - # audio bitrate, in kbps. [16, 72] for libaacplus.  
727 abitrate 70; 850 abitrate 70;
728 - # audio sample rate. for flv/rtmp, it must be:  
729 - # 44100,22050,11025,5512  
730 asample_rate 44100; 851 asample_rate 44100;
731 - # audio channel, 1 for mono, 2 for stereo.  
732 achannels 2; 852 achannels 2;
733 - # other ffmpeg audio params  
734 aparams { 853 aparams {
735 - # audio params, @see: http://ffmpeg.org/ffmpeg-codecs.html#Audio-Encoders  
736 profile:a aac_low; 854 profile:a aac_low;
737 } 855 }
738 - # output format, can be:  
739 - # off, do not specifies the format, ffmpeg will guess it.  
740 - # flv, for flv or RTMP stream.  
741 - # other format, for example, mp4/aac whatever.  
742 - # default: flv  
743 oformat flv; 856 oformat flv;
744 - # output stream. variables:  
745 - # [vhost] the input stream vhost.  
746 - # [port] the intput stream port.  
747 - # [app] the input stream app.  
748 - # [stream] the input stream name.  
749 - # [engine] the tanscode engine name.  
750 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; 857 output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
751 } 858 }
752 engine ffhd { 859 engine ffhd {
  1 +# security config for srs, allow play and deny publish.
  2 +# @see https://github.com/winlinvip/simple-rtmp-server/issues/211#issuecomment-68507035
  3 +# @see full.conf for detail config.
  4 +
  5 +listen 1935;
  6 +max_connections 1000;
  7 +vhost __defaultVhost__ {
  8 + security {
  9 + enabled on;
  10 + deny publish all;
  11 + allow play all;
  12 + }
  13 +}
@@ -389,7 +389,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then @@ -389,7 +389,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
389 "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks" 389 "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks"
390 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge" 390 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
391 "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_avc_aac" 391 "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_avc_aac"
392 - "srs_app_recv_thread" "srs_app_statistic") 392 + "srs_app_recv_thread" "srs_app_security" "srs_app_statistic")
393 APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh 393 APP_INCS="src/app"; MODULE_DIR=${APP_INCS} . auto/modules.sh
394 APP_OBJS="${MODULE_OBJS[@]}" 394 APP_OBJS="${MODULE_OBJS[@]}"
395 fi 395 fi
@@ -241,6 +241,74 @@ class RESTStreams(object): @@ -241,6 +241,74 @@ class RESTStreams(object):
241 return code 241 return code
242 242
243 ''' 243 '''
  244 +handle the dvrs requests: dvr stream.
  245 +'''
  246 +class RESTDvrs(object):
  247 + exposed = True
  248 +
  249 + def GET(self):
  250 + enable_crossdomain()
  251 +
  252 + dvrs = {}
  253 + return json.dumps(dvrs)
  254 +
  255 + '''
  256 + for SRS hook: on_dvr
  257 + on_dvr:
  258 + when srs reap a dvr file, call the hook,
  259 + the request in the POST data string is a object encode by json:
  260 + {
  261 + "action": "on_dvr",
  262 + "client_id": 1985,
  263 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  264 + "stream": "livestream",
  265 + "cwd": "/usr/local/srs",
  266 + "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
  267 + }
  268 + if valid, the hook must return HTTP code 200(Stauts OK) and response
  269 + an int value specifies the error code(0 corresponding to success):
  270 + 0
  271 + '''
  272 + def POST(self):
  273 + enable_crossdomain()
  274 +
  275 + # return the error code in str
  276 + code = Error.success
  277 +
  278 + req = cherrypy.request.body.read()
  279 + trace("post to dvrs, req=%s"%(req))
  280 + try:
  281 + json_req = json.loads(req)
  282 + except Exception, ex:
  283 + code = Error.system_parse_json
  284 + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
  285 + return str(code)
  286 +
  287 + action = json_req["action"]
  288 + if action == "on_dvr":
  289 + code = self.__on_dvr(json_req)
  290 + else:
  291 + trace("invalid request action: %s"%(json_req["action"]))
  292 + code = Error.request_invalid_action
  293 +
  294 + return str(code)
  295 +
  296 + def OPTIONS(self, *args, **kwargs):
  297 + enable_crossdomain()
  298 +
  299 + def __on_dvr(self, req):
  300 + code = Error.success
  301 +
  302 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
  303 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"],
  304 + req["cwd"], req["file"]
  305 + ))
  306 +
  307 + # TODO: process the on_dvr event
  308 +
  309 + return code
  310 +
  311 +'''
244 handle the sessions requests: client play/stop stream 312 handle the sessions requests: client play/stop stream
245 ''' 313 '''
246 class RESTSessions(object): 314 class RESTSessions(object):
@@ -1039,6 +1107,7 @@ class V1(object): @@ -1039,6 +1107,7 @@ class V1(object):
1039 self.clients = RESTClients() 1107 self.clients = RESTClients()
1040 self.streams = RESTStreams() 1108 self.streams = RESTStreams()
1041 self.sessions = RESTSessions() 1109 self.sessions = RESTSessions()
  1110 + self.dvrs = RESTDvrs()
1042 self.chats = RESTChats() 1111 self.chats = RESTChats()
1043 self.servers = RESTServers() 1112 self.servers = RESTServers()
1044 self.nodes = RESTNodes() 1113 self.nodes = RESTNodes()
@@ -1048,6 +1117,7 @@ class V1(object): @@ -1048,6 +1117,7 @@ class V1(object):
1048 "clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.", 1117 "clients": "for srs http callback, to handle the clients requests: connect/disconnect vhost/app.",
1049 "streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.", 1118 "streams": "for srs http callback, to handle the streams requests: publish/unpublish stream.",
1050 "sessions": "for srs http callback, to handle the sessions requests: client play/stop stream", 1119 "sessions": "for srs http callback, to handle the sessions requests: client play/stop stream",
  1120 + "dvrs": "for srs http callback, to handle the dvr requests: dvr stream.",
1051 "chats": "for srs demo meeting, the chat streams, public chat room.", 1121 "chats": "for srs demo meeting, the chat streams, public chat room.",
1052 "nodes": { 1122 "nodes": {
1053 "summary": "for srs cdn node", 1123 "summary": "for srs cdn node",
@@ -15,7 +15,7 @@ ret=$?; if [[ 0 -ne $ret ]]; then @@ -15,7 +15,7 @@ ret=$?; if [[ 0 -ne $ret ]]; then
15 exit $ret 15 exit $ret
16 fi 16 fi
17 17
18 -files=`git status|egrep "(modified|new file)"|awk -F ':' '{print $2}'|awk '{print $1}'|egrep "(.hpp$|.cpp$|.cc$|.h$|.c$|.txt$|.sh$)"`; 18 +files=`git status|egrep "(modified|new file)"|awk -F ':' '{print $2}'|awk '{print $1}'|egrep "(.hpp$|.cpp$|.cc$|.h$|.c$|.txt$|.sh|.conf$)"`;
19 for file in $files; do 19 for file in $files; do
20 dos2unix $file; 20 dos2unix $file;
21 echo $file|grep ".sh$" >/dev/null 2>&1; EOF_SH=$? 21 echo $file|grep ".sh$" >/dev/null 2>&1; EOF_SH=$?
@@ -434,7 +434,8 @@ int SrsConfig::reload_conf(SrsConfig* conf) @@ -434,7 +434,8 @@ int SrsConfig::reload_conf(SrsConfig* conf)
434 // always support reload without additional code: 434 // always support reload without additional code:
435 // chunk_size, ff_log_dir, max_connections, 435 // chunk_size, ff_log_dir, max_connections,
436 // bandcheck, http_hooks, heartbeat, 436 // bandcheck, http_hooks, heartbeat,
437 - // token_traverse, debug_srs_upnode 437 + // token_traverse, debug_srs_upnode,
  438 + // security
438 439
439 // merge config: listen 440 // merge config: listen
440 if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { 441 if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
@@ -1363,6 +1364,7 @@ int SrsConfig::check_config() @@ -1363,6 +1364,7 @@ int SrsConfig::check_config()
1363 && n != "atc" && n != "atc_auto" 1364 && n != "atc" && n != "atc_auto"
1364 && n != "debug_srs_upnode" 1365 && n != "debug_srs_upnode"
1365 && n != "mr" && n != "mw_latency" && n != "min_latency" 1366 && n != "mr" && n != "mw_latency" && n != "min_latency"
  1367 + && n != "security"
1366 ) { 1368 ) {
1367 ret = ERROR_SYSTEM_CONFIG_INVALID; 1369 ret = ERROR_SYSTEM_CONFIG_INVALID;
1368 srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret); 1370 srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret);
@@ -1424,6 +1426,7 @@ int SrsConfig::check_config() @@ -1424,6 +1426,7 @@ int SrsConfig::check_config()
1424 string m = conf->at(j)->name.c_str(); 1426 string m = conf->at(j)->name.c_str();
1425 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" 1427 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
1426 && m != "on_unpublish" && m != "on_play" && m != "on_stop" 1428 && m != "on_unpublish" && m != "on_play" && m != "on_stop"
  1429 + && m != "on_dvr"
1427 ) { 1430 ) {
1428 ret = ERROR_SYSTEM_CONFIG_INVALID; 1431 ret = ERROR_SYSTEM_CONFIG_INVALID;
1429 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); 1432 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
@@ -1440,6 +1443,16 @@ int SrsConfig::check_config() @@ -1440,6 +1443,16 @@ int SrsConfig::check_config()
1440 return ret; 1443 return ret;
1441 } 1444 }
1442 }*/ 1445 }*/
  1446 + } else if (n == "security") {
  1447 + for (int j = 0; j < (int)conf->directives.size(); j++) {
  1448 + SrsConfDirective* security = conf->at(j);
  1449 + string m = security->name.c_str();
  1450 + if (m != "enabled" && m != "deny" && m != "allow") {
  1451 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  1452 + srs_error("unsupported vhost security directive %s, ret=%d", m.c_str(), ret);
  1453 + return ret;
  1454 + }
  1455 + }
1443 } else if (n == "transcode") { 1456 } else if (n == "transcode") {
1444 for (int j = 0; j < (int)conf->directives.size(); j++) { 1457 for (int j = 0; j < (int)conf->directives.size(); j++) {
1445 SrsConfDirective* trans = conf->at(j); 1458 SrsConfDirective* trans = conf->at(j);
@@ -2323,6 +2336,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) @@ -2323,6 +2336,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
2323 return conf->get("on_stop"); 2336 return conf->get("on_stop");
2324 } 2337 }
2325 2338
  2339 +SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
  2340 +{
  2341 + SrsConfDirective* conf = get_vhost_http_hooks(vhost);
  2342 +
  2343 + if (!conf) {
  2344 + return NULL;
  2345 + }
  2346 +
  2347 + return conf->get("on_dvr");
  2348 +}
  2349 +
2326 bool SrsConfig::get_bw_check_enabled(string vhost) 2350 bool SrsConfig::get_bw_check_enabled(string vhost)
2327 { 2351 {
2328 SrsConfDirective* conf = get_vhost(vhost); 2352 SrsConfDirective* conf = get_vhost(vhost);
@@ -2456,6 +2480,43 @@ bool SrsConfig::get_vhost_edge_token_traverse(string vhost) @@ -2456,6 +2480,43 @@ bool SrsConfig::get_vhost_edge_token_traverse(string vhost)
2456 return true; 2480 return true;
2457 } 2481 }
2458 2482
  2483 +bool SrsConfig::get_security_enabled(string vhost)
  2484 +{
  2485 + SrsConfDirective* conf = get_vhost(vhost);
  2486 +
  2487 + if (!conf) {
  2488 + return SRS_CONF_DEFAULT_SECURITY_ENABLED;
  2489 + }
  2490 +
  2491 + SrsConfDirective* security = conf->get("security");
  2492 + if (!security) {
  2493 + return SRS_CONF_DEFAULT_SECURITY_ENABLED;
  2494 + }
  2495 +
  2496 + conf = security->get("enabled");
  2497 + if (!conf || conf->arg0() != "on") {
  2498 + return SRS_CONF_DEFAULT_SECURITY_ENABLED;
  2499 + }
  2500 +
  2501 + return true;
  2502 +}
  2503 +
  2504 +SrsConfDirective* SrsConfig::get_security_rules(string vhost)
  2505 +{
  2506 + SrsConfDirective* conf = get_vhost(vhost);
  2507 +
  2508 + if (!conf) {
  2509 + return NULL;
  2510 + }
  2511 +
  2512 + SrsConfDirective* security = conf->get("security");
  2513 + if (!security) {
  2514 + return NULL;
  2515 + }
  2516 +
  2517 + return security;
  2518 +}
  2519 +
2459 SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope) 2520 SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)
2460 { 2521 {
2461 SrsConfDirective* conf = get_vhost(vhost); 2522 SrsConfDirective* conf = get_vhost(vhost);
@@ -76,6 +76,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -76,6 +76,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76 #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL "http://"SRS_CONSTS_LOCALHOST":8085/api/v1/servers" 76 #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_URL "http://"SRS_CONSTS_LOCALHOST":8085/api/v1/servers"
77 #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES false 77 #define SRS_CONF_DEFAULT_HTTP_HEAETBEAT_SUMMARIES false
78 78
  79 +#define SRS_CONF_DEFAULT_SECURITY_ENABLED false
  80 +
79 #define SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX 0 81 #define SRS_CONF_DEFAULT_STATS_NETWORK_DEVICE_INDEX 0
80 82
81 #define SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS 10000 83 #define SRS_CONF_DEFAULT_STAGE_PLAY_USER_INTERVAL_MS 10000
@@ -608,6 +610,11 @@ public: @@ -608,6 +610,11 @@ public:
608 * @return the on_stop callback directive, the args is the url to callback. 610 * @return the on_stop callback directive, the args is the url to callback.
609 */ 611 */
610 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost); 612 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
  613 + /**
  614 + * get the on_dvr callbacks of vhost.
  615 + * @return the on_dvr callback directive, the args is the url to callback.
  616 + */
  617 + virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
611 // bwct(bandwidth check tool) section 618 // bwct(bandwidth check tool) section
612 public: 619 public:
613 /** 620 /**
@@ -659,6 +666,16 @@ public: @@ -659,6 +666,16 @@ public:
659 * all clients connected to edge must be tranverse to origin to verify. 666 * all clients connected to edge must be tranverse to origin to verify.
660 */ 667 */
661 virtual bool get_vhost_edge_token_traverse(std::string vhost); 668 virtual bool get_vhost_edge_token_traverse(std::string vhost);
  669 +// vhost security section
  670 +public:
  671 + /**
  672 + * whether the secrity of vhost enabled.
  673 + */
  674 + virtual bool get_security_enabled(std::string vhost);
  675 + /**
  676 + * get the security rules.
  677 + */
  678 + virtual SrsConfDirective* get_security_rules(std::string vhost);
662 // vhost transcode section 679 // vhost transcode section
663 public: 680 public:
664 /** 681 /**
@@ -776,7 +793,7 @@ public: @@ -776,7 +793,7 @@ public:
776 * @remark, we will use some variable, for instance, [vhost] to substitude with vhost. 793 * @remark, we will use some variable, for instance, [vhost] to substitude with vhost.
777 */ 794 */
778 virtual std::string get_engine_output(SrsConfDirective* engine); 795 virtual std::string get_engine_output(SrsConfDirective* engine);
779 -// ingest section 796 +// vhost ingest section
780 public: 797 public:
781 /** 798 /**
782 * get the ingest directives of vhost. 799 * get the ingest directives of vhost.
@@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 27
28 #include <fcntl.h> 28 #include <fcntl.h>
29 #include <sstream> 29 #include <sstream>
  30 +#include <sys/time.h>
30 using namespace std; 31 using namespace std;
31 32
32 #include <srs_app_config.hpp> 33 #include <srs_app_config.hpp>
@@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment() @@ -136,14 +137,97 @@ int SrsDvrPlan::open_new_segment()
136 137
137 SrsRequest* req = _req; 138 SrsRequest* req = _req;
138 139
139 - // new flv file  
140 - std::stringstream path; 140 + // the path in config, for example,
  141 + // /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv
  142 + std::string path_config = _srs_config->get_dvr_path(req->vhost);
141 143
142 - path << _srs_config->get_dvr_path(req->vhost)  
143 - << "/" << req->app << "/"  
144 - << req->stream << "." << srs_get_system_time_ms() << ".flv"; 144 + // add [stream].[timestamp].flv as filename for dir
  145 + if (path_config.find(".flv") != path_config.length() - 4) {
  146 + path_config += "/[stream].[timestamp].flv";
  147 + }
  148 +
  149 + // the flv file path
  150 + std::string path = path_config;
  151 +
  152 + // variable [vhost]
  153 + path = srs_string_replace(path, "[vhost]", req->vhost);
  154 + // variable [app]
  155 + path = srs_string_replace(path, "[app]", req->app);
  156 + // variable [stream]
  157 + path = srs_string_replace(path, "[stream]", req->stream);
  158 +
  159 + // date and time substitude
  160 + // clock time
  161 + timeval tv;
  162 + if (gettimeofday(&tv, NULL) == -1) {
  163 + return ERROR_SYSTEM_TIME;
  164 + }
  165 +
  166 + // to calendar time
  167 + struct tm* tm;
  168 + if ((tm = localtime(&tv.tv_sec)) == NULL) {
  169 + return ERROR_SYSTEM_TIME;
  170 + }
  171 +
  172 + // the buffer to format the date and time.
  173 + char buf[64];
  174 +
  175 + // [2006], replace with current year.
  176 + if (true) {
  177 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  178 + path = srs_string_replace(path, "[2006]", buf);
  179 + }
  180 + // [2006], replace with current year.
  181 + if (true) {
  182 + snprintf(buf, sizeof(buf), "%d", 1900 + tm->tm_year);
  183 + path = srs_string_replace(path, "[2006]", buf);
  184 + }
  185 + // [01], replace this const to current month.
  186 + if (true) {
  187 + snprintf(buf, sizeof(buf), "%d", 1 + tm->tm_mon);
  188 + path = srs_string_replace(path, "[01]", buf);
  189 + }
  190 + // [02], replace this const to current date.
  191 + if (true) {
  192 + snprintf(buf, sizeof(buf), "%d", tm->tm_mday);
  193 + path = srs_string_replace(path, "[02]", buf);
  194 + }
  195 + // [15], replace this const to current hour.
  196 + if (true) {
  197 + snprintf(buf, sizeof(buf), "%d", tm->tm_hour);
  198 + path = srs_string_replace(path, "[15]", buf);
  199 + }
  200 + // [04], repleace this const to current minute.
  201 + if (true) {
  202 + snprintf(buf, sizeof(buf), "%d", tm->tm_min);
  203 + path = srs_string_replace(path, "[04]", buf);
  204 + }
  205 + // [05], repleace this const to current second.
  206 + if (true) {
  207 + snprintf(buf, sizeof(buf), "%d", tm->tm_sec);
  208 + path = srs_string_replace(path, "[05]", buf);
  209 + }
  210 + // [999], repleace this const to current millisecond.
  211 + if (true) {
  212 + snprintf(buf, sizeof(buf), "%03d", (int)(tv.tv_usec / 1000));
  213 + path = srs_string_replace(path, "[999]", buf);
  214 + }
  215 + // [timestamp],replace this const to current UNIX timestamp in ms.
  216 + if (true) {
  217 + int64_t now_us = ((int64_t)tv.tv_sec) * 1000 * 1000 + (int64_t)tv.tv_usec;
  218 + snprintf(buf, sizeof(buf), "%"PRId64, now_us / 1000);
  219 + path = srs_string_replace(path, "[timestamp]", buf);
  220 + }
  221 +
  222 + // create dir first.
  223 + std::string dir = path.substr(0, path.rfind("/"));
  224 + if ((ret = srs_create_dir_recursively(dir)) != ERROR_SUCCESS) {
  225 + srs_error("create dir=%s failed. ret=%d", dir.c_str(), ret);
  226 + return ret;
  227 + }
  228 + srs_info("create dir=%s ok", dir.c_str());
145 229
146 - if ((ret = flv_open(req->get_stream_url(), path.str())) != ERROR_SUCCESS) { 230 + if ((ret = flv_open(req->get_stream_url(), path)) != ERROR_SUCCESS) {
147 return ret; 231 return ret;
148 } 232 }
149 dvr_enabled = true; 233 dvr_enabled = true;
@@ -320,6 +404,30 @@ int SrsDvrPlan::flv_close() @@ -320,6 +404,30 @@ int SrsDvrPlan::flv_close()
320 return ret; 404 return ret;
321 } 405 }
322 406
  407 +#ifdef SRS_AUTO_HTTP_CALLBACK
  408 + SrsRequest* req = _req;
  409 + if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
  410 + // HTTP: on_dvr
  411 + SrsConfDirective* on_dvr = _srs_config->get_vhost_on_dvr(req->vhost);
  412 + if (!on_dvr) {
  413 + srs_info("ignore the empty http callback: on_dvr");
  414 + return ret;
  415 + }
  416 +
  417 + int connection_id = _srs_context->get_id();
  418 + std::string ip = req->ip;
  419 + std::string cwd = _srs_config->cwd();
  420 + std::string file = segment->path;
  421 + for (int i = 0; i < (int)on_dvr->args.size(); i++) {
  422 + std::string url = on_dvr->args.at(i);
  423 + if ((ret = SrsHttpHooks::on_dvr(url, connection_id, ip, req, cwd, file)) != ERROR_SUCCESS) {
  424 + srs_error("hook client on_dvr failed. url=%s, ret=%d", url.c_str(), ret);
  425 + return ret;
  426 + }
  427 + }
  428 + }
  429 +#endif
  430 +
323 return ret; 431 return ret;
324 } 432 }
325 433
@@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir() @@ -951,16 +951,12 @@ int SrsHlsMuxer::create_dir()
951 app_dir += app; 951 app_dir += app;
952 952
953 // TODO: cleanup the dir when startup. 953 // TODO: cleanup the dir when startup.
954 -  
955 - mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;  
956 - if (::mkdir(app_dir.c_str(), mode) < 0) {  
957 - if (errno != EEXIST) {  
958 - ret = ERROR_HLS_CREATE_DIR;  
959 - srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);  
960 - return ret;  
961 - } 954 +
  955 + if ((ret = srs_create_dir_recursively(app_dir)) != ERROR_SUCCESS) {
  956 + srs_error("create app dir %s failed. ret=%d", app_dir.c_str(), ret);
  957 + return ret;
962 } 958 }
963 - srs_info("create app dir %s success.", app_dir.c_str()); 959 + srs_info("create app dir %s ok", app_dir.c_str());
964 960
965 return ret; 961 return ret;
966 } 962 }
@@ -26,7 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -26,7 +26,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #ifdef SRS_AUTO_HTTP_API 26 #ifdef SRS_AUTO_HTTP_API
27 27
28 #include <sstream> 28 #include <sstream>
29 -#include <set>  
30 using namespace std; 29 using namespace std;
31 30
32 #include <srs_kernel_log.hpp> 31 #include <srs_kernel_log.hpp>
@@ -153,8 +152,8 @@ int SrsApiV1::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) @@ -153,8 +152,8 @@ int SrsApiV1::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
153 << __SRS_JFIELD_STR("meminfos", "the meminfo of system") << __SRS_JFIELD_CONT 152 << __SRS_JFIELD_STR("meminfos", "the meminfo of system") << __SRS_JFIELD_CONT
154 << __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT 153 << __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT
155 << __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT 154 << __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT
156 - << __SRS_JFIELD_STR("vhosts", "list all vhosts") << __SRS_JFIELD_CONT  
157 - << __SRS_JFIELD_STR("streams", "list streams that match the name or vhost") 155 + << __SRS_JFIELD_STR("vhosts", "dumps vhost to json") << __SRS_JFIELD_CONT
  156 + << __SRS_JFIELD_STR("streams", "dumps streams to json")
158 << __SRS_JOBJECT_END 157 << __SRS_JOBJECT_END
159 << __SRS_JOBJECT_END; 158 << __SRS_JOBJECT_END;
160 159
@@ -522,30 +521,19 @@ bool SrsApiVhosts::can_handle(const char* path, int length, const char** /*pchil @@ -522,30 +521,19 @@ bool SrsApiVhosts::can_handle(const char* path, int length, const char** /*pchil
522 521
523 int SrsApiVhosts::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) 522 int SrsApiVhosts::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
524 { 523 {
  524 + std::stringstream data;
  525 + SrsStatistic* stat = SrsStatistic::instance();
  526 + int ret = stat->dumps_vhosts(data);
  527 +
525 std::stringstream ss; 528 std::stringstream ss;
526 529
527 - std::set<std::string> vhost_set;  
528 - SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool();  
529 - SrsStreamInfoMap::iterator it;  
530 - for (it = pool->begin(); it != pool->end(); it++) {  
531 - if (it->second->_req == NULL)  
532 - continue;  
533 - vhost_set.insert(it->second->_req->vhost);  
534 - }  
535 -  
536 - ss << __SRS_JARRAY_START;  
537 - bool first = true;  
538 - std::set<std::string>::iterator it_set;  
539 - for (it_set = vhost_set.begin(); it_set != vhost_set.end(); it_set++) {  
540 - if (first) {  
541 - first = false;  
542 - } else {  
543 - ss << __SRS_JFIELD_CONT;  
544 - }  
545 -  
546 - ss << "\"" << (*it_set) << "\"";  
547 - }  
548 - ss << __SRS_JARRAY_END; 530 + ss << __SRS_JOBJECT_START
  531 + << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
  532 + << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT
  533 + << __SRS_JFIELD_ORG("vhosts", __SRS_JARRAY_START)
  534 + << data.str()
  535 + << __SRS_JARRAY_END
  536 + << __SRS_JOBJECT_END;
549 537
550 return res_json(skt, req, ss.str()); 538 return res_json(skt, req, ss.str());
551 } 539 }
@@ -565,41 +553,19 @@ bool SrsApiStreams::can_handle(const char* path, int length, const char** /*pchi @@ -565,41 +553,19 @@ bool SrsApiStreams::can_handle(const char* path, int length, const char** /*pchi
565 553
566 int SrsApiStreams::do_process_request(SrsStSocket* skt, SrsHttpMessage* req) 554 int SrsApiStreams::do_process_request(SrsStSocket* skt, SrsHttpMessage* req)
567 { 555 {
  556 + std::stringstream data;
  557 + SrsStatistic* stat = SrsStatistic::instance();
  558 + int ret = stat->dumps_streams(data);
  559 +
568 std::stringstream ss; 560 std::stringstream ss;
569 561
570 - std::string query_name = req->query_get("name");  
571 - std::string query_vhost = req->query_get("vhost");  
572 - if (query_name.size() > 0 || query_vhost.size() > 0) {  
573 - ss << __SRS_JARRAY_START;  
574 - bool first = true;  
575 - SrsStreamInfoMap* pool = SrsStatistic::instance()->get_pool();  
576 - SrsStreamInfoMap::iterator it;  
577 - for (it = pool->begin(); it != pool->end(); it++) {  
578 - SrsRequest* reqinfo = it->second->_req;  
579 - if (reqinfo == NULL)  
580 - continue;  
581 -  
582 - if (reqinfo->stream == query_name || reqinfo->vhost == query_vhost) {  
583 - if (first) {  
584 - first = false;  
585 - } else {  
586 - ss << __SRS_JFIELD_CONT;  
587 - }  
588 -  
589 - ss << __SRS_JOBJECT_START  
590 - << __SRS_JFIELD_STR("name", reqinfo->stream) << __SRS_JFIELD_CONT  
591 - << __SRS_JFIELD_STR("url", reqinfo->tcUrl) << __SRS_JFIELD_CONT  
592 - << __SRS_JFIELD_ORG("clients", 0) << __SRS_JFIELD_CONT  
593 - << __SRS_JFIELD_STR("status", "idle") << __SRS_JFIELD_CONT  
594 - << __SRS_JFIELD_STR("type", "") << __SRS_JFIELD_CONT  
595 - << __SRS_JFIELD_STR("codec", "")  
596 - << __SRS_JOBJECT_END;  
597 - }  
598 - }  
599 - ss << __SRS_JARRAY_END;  
600 - } else {  
601 - return res_error(skt, req, 400, "Bad Request", "unknown query");  
602 - } 562 + ss << __SRS_JOBJECT_START
  563 + << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
  564 + << __SRS_JFIELD_ORG("server", stat->server_id()) << __SRS_JFIELD_CONT
  565 + << __SRS_JFIELD_ORG("streams", __SRS_JARRAY_START)
  566 + << data.str()
  567 + << __SRS_JARRAY_END
  568 + << __SRS_JOBJECT_END;
603 569
604 return res_json(skt, req, ss.str()); 570 return res_json(skt, req, ss.str());
605 } 571 }
@@ -122,8 +122,7 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re @@ -122,8 +122,7 @@ void SrsHttpHooks::on_close(string url, int client_id, string ip, SrsRequest* re
122 << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT 122 << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
123 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT 123 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
124 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 124 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
125 - << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT  
126 - << __SRS_JFIELD_STR("pageUrl", req->pageUrl) 125 + << __SRS_JFIELD_STR("app", req->app)
127 << __SRS_JOBJECT_END; 126 << __SRS_JOBJECT_END;
128 std::string data = ss.str(); 127 std::string data = ss.str();
129 std::string res; 128 std::string res;
@@ -178,7 +177,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r @@ -178,7 +177,6 @@ int SrsHttpHooks::on_publish(string url, int client_id, string ip, SrsRequest* r
178 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT 177 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
179 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 178 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
180 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT 179 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
181 - << __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT  
182 << __SRS_JFIELD_STR("stream", req->stream) 180 << __SRS_JFIELD_STR("stream", req->stream)
183 << __SRS_JOBJECT_END; 181 << __SRS_JOBJECT_END;
184 std::string data = ss.str(); 182 std::string data = ss.str();
@@ -234,7 +232,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest @@ -234,7 +232,6 @@ void SrsHttpHooks::on_unpublish(string url, int client_id, string ip, SrsRequest
234 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT 232 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
235 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 233 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
236 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT 234 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
237 - << __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT  
238 << __SRS_JFIELD_STR("stream", req->stream) 235 << __SRS_JFIELD_STR("stream", req->stream)
239 << __SRS_JOBJECT_END; 236 << __SRS_JOBJECT_END;
240 std::string data = ss.str(); 237 std::string data = ss.str();
@@ -290,7 +287,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req) @@ -290,7 +287,6 @@ int SrsHttpHooks::on_play(string url, int client_id, string ip, SrsRequest* req)
290 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT 287 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
291 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 288 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
292 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT 289 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
293 - << __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT  
294 << __SRS_JFIELD_STR("stream", req->stream) 290 << __SRS_JFIELD_STR("stream", req->stream)
295 << __SRS_JOBJECT_END; 291 << __SRS_JOBJECT_END;
296 std::string data = ss.str(); 292 std::string data = ss.str();
@@ -346,7 +342,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req @@ -346,7 +342,6 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
346 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT 342 << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
347 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 343 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
348 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT 344 << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
349 - << __SRS_JFIELD_STR("pageUrl", req->pageUrl) << __SRS_JFIELD_CONT  
350 << __SRS_JFIELD_STR("stream", req->stream) 345 << __SRS_JFIELD_STR("stream", req->stream)
351 << __SRS_JOBJECT_END; 346 << __SRS_JOBJECT_END;
352 std::string data = ss.str(); 347 std::string data = ss.str();
@@ -384,5 +379,61 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req @@ -384,5 +379,61 @@ void SrsHttpHooks::on_stop(string url, int client_id, string ip, SrsRequest* req
384 return; 379 return;
385 } 380 }
386 381
387 -#endif 382 +int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, string cwd, string file)
  383 +{
  384 + int ret = ERROR_SUCCESS;
  385 +
  386 + SrsHttpUri uri;
  387 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  388 + srs_error("http uri parse on_dvr url failed, ignored. "
  389 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  390 + return ret;
  391 + }
  392 +
  393 + std::stringstream ss;
  394 + ss << __SRS_JOBJECT_START
  395 + << __SRS_JFIELD_STR("action", "on_dvr") << __SRS_JFIELD_CONT
  396 + << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
  397 + << __SRS_JFIELD_STR("ip", ip) << __SRS_JFIELD_CONT
  398 + << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
  399 + << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
  400 + << __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
  401 + << __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
  402 + << __SRS_JFIELD_STR("file", file)
  403 + << __SRS_JOBJECT_END;
  404 + std::string data = ss.str();
  405 + std::string res;
  406 + int status_code;
  407 +
  408 + SrsHttpClient http;
  409 + if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
  410 + srs_error("http post on_dvr uri failed, ignored. "
  411 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  412 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  413 + return ret;
  414 + }
  415 +
  416 + // ensure the http status is ok.
  417 + // https://github.com/winlinvip/simple-rtmp-server/issues/158
  418 + if (status_code != SRS_CONSTS_HTTP_OK) {
  419 + ret = ERROR_HTTP_STATUS_INVLIAD;
  420 + srs_error("http hook on_dvr status failed. "
  421 + "client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
  422 + return ret;
  423 + }
  424 +
  425 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  426 + ret = ERROR_HTTP_DATA_INVLIAD;
  427 + srs_warn("http hook on_dvr validate failed, ignored. "
  428 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  429 + return ret;
  430 + }
  431 +
  432 + srs_trace("http hook on_dvr success. "
  433 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  434 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  435 +
  436 + return ret;
  437 +}
388 438
  439 +#endif
@@ -58,7 +58,6 @@ public: @@ -58,7 +58,6 @@ public:
58 * @param client_id the id of client on server. 58 * @param client_id the id of client on server.
59 * @param url the api server url, to valid the client. 59 * @param url the api server url, to valid the client.
60 * ignore if empty. 60 * ignore if empty.
61 - * @return valid failed or connect to the url failed.  
62 */ 61 */
63 static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req); 62 static int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req);
64 /** 63 /**
@@ -73,7 +72,6 @@ public: @@ -73,7 +72,6 @@ public:
73 * @param client_id the id of client on server. 72 * @param client_id the id of client on server.
74 * @param url the api server url, to valid the client. 73 * @param url the api server url, to valid the client.
75 * ignore if empty. 74 * ignore if empty.
76 - * @return valid failed or connect to the url failed.  
77 */ 75 */
78 static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req); 76 static int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req);
79 /** 77 /**
@@ -88,7 +86,6 @@ public: @@ -88,7 +86,6 @@ public:
88 * @param client_id the id of client on server. 86 * @param client_id the id of client on server.
89 * @param url the api server url, to valid the client. 87 * @param url the api server url, to valid the client.
90 * ignore if empty. 88 * ignore if empty.
91 - * @return valid failed or connect to the url failed.  
92 */ 89 */
93 static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req); 90 static int on_play(std::string url, int client_id, std::string ip, SrsRequest* req);
94 /** 91 /**
@@ -98,6 +95,15 @@ public: @@ -98,6 +95,15 @@ public:
98 * ignore if empty. 95 * ignore if empty.
99 */ 96 */
100 static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req); 97 static void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
  98 + /**
  99 + * on_dvr hook, when reap a dvr file.
  100 + * @param client_id the id of client on server.
  101 + * @param url the api server url, to process the event.
  102 + * ignore if empty.
  103 + * @param cwd the current work directory, used to resolve the reltive file path.
  104 + * @param file the file path, can be relative or absolute path.
  105 + */
  106 + static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file);
101 }; 107 };
102 108
103 #endif 109 #endif
@@ -51,6 +51,7 @@ using namespace std; @@ -51,6 +51,7 @@ using namespace std;
51 #include <srs_app_recv_thread.hpp> 51 #include <srs_app_recv_thread.hpp>
52 #include <srs_core_performance.hpp> 52 #include <srs_core_performance.hpp>
53 #include <srs_kernel_utility.hpp> 53 #include <srs_kernel_utility.hpp>
  54 +#include <srs_app_security.hpp>
54 #include <srs_app_statistic.hpp> 55 #include <srs_app_statistic.hpp>
55 56
56 // when stream is busy, for example, streaming is already 57 // when stream is busy, for example, streaming is already
@@ -82,6 +83,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd) @@ -82,6 +83,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd)
82 rtmp = new SrsRtmpServer(skt); 83 rtmp = new SrsRtmpServer(skt);
83 refer = new SrsRefer(); 84 refer = new SrsRefer();
84 bandwidth = new SrsBandwidth(); 85 bandwidth = new SrsBandwidth();
  86 + security = new SrsSecurity();
85 duration = 0; 87 duration = 0;
86 kbps = new SrsKbps(); 88 kbps = new SrsKbps();
87 kbps->set_io(skt, skt); 89 kbps->set_io(skt, skt);
@@ -103,6 +105,7 @@ SrsRtmpConn::~SrsRtmpConn() @@ -103,6 +105,7 @@ SrsRtmpConn::~SrsRtmpConn()
103 srs_freep(skt); 105 srs_freep(skt);
104 srs_freep(refer); 106 srs_freep(refer);
105 srs_freep(bandwidth); 107 srs_freep(bandwidth);
  108 + srs_freep(security);
106 srs_freep(kbps); 109 srs_freep(kbps);
107 } 110 }
108 111
@@ -133,6 +136,9 @@ int SrsRtmpConn::do_cycle() @@ -133,6 +136,9 @@ int SrsRtmpConn::do_cycle()
133 } 136 }
134 srs_verbose("rtmp connect app success"); 137 srs_verbose("rtmp connect app success");
135 138
  139 + // set client ip to request.
  140 + req->ip = ip;
  141 +
136 // discovery vhost, resolve the vhost from config 142 // discovery vhost, resolve the vhost from config
137 SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost); 143 SrsConfDirective* parsed_vhost = _srs_config->get_vhost(req->vhost);
138 if (parsed_vhost) { 144 if (parsed_vhost) {
@@ -361,6 +367,13 @@ int SrsRtmpConn::stream_service_cycle() @@ -361,6 +367,13 @@ int SrsRtmpConn::stream_service_cycle()
361 req->strip(); 367 req->strip();
362 srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f", 368 srs_trace("client identified, type=%s, stream_name=%s, duration=%.2f",
363 srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration); 369 srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration);
  370 +
  371 + // security check
  372 + if ((ret = security->check(type, ip, req)) != ERROR_SUCCESS) {
  373 + srs_error("security check failed. ret=%d", ret);
  374 + return ret;
  375 + }
  376 + srs_info("security check ok");
364 377
365 // client is identified, set the timeout to service timeout. 378 // client is identified, set the timeout to service timeout.
366 rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); 379 rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US);
@@ -383,7 +396,12 @@ int SrsRtmpConn::stream_service_cycle() @@ -383,7 +396,12 @@ int SrsRtmpConn::stream_service_cycle()
383 } 396 }
384 srs_assert(source != NULL); 397 srs_assert(source != NULL);
385 398
386 - SrsStatistic::instance()->add_request_info(source, req); 399 + // update the statistic when source disconveried.
  400 + SrsStatistic* stat = SrsStatistic::instance();
  401 + if ((ret = stat->on_client(_srs_context->get_id(), req)) != ERROR_SUCCESS) {
  402 + srs_error("stat client failed. ret=%d", ret);
  403 + return ret;
  404 + }
387 405
388 // check ASAP, to fail it faster if invalid. 406 // check ASAP, to fail it faster if invalid.
389 if (type != SrsRtmpConnPlay && !vhost_is_edge) { 407 if (type != SrsRtmpConnPlay && !vhost_is_edge) {
@@ -51,6 +51,7 @@ class SrsRtmpClient; @@ -51,6 +51,7 @@ class SrsRtmpClient;
51 class SrsSharedPtrMessage; 51 class SrsSharedPtrMessage;
52 class SrsQueueRecvThread; 52 class SrsQueueRecvThread;
53 class SrsPublishRecvThread; 53 class SrsPublishRecvThread;
  54 +class SrsSecurity;
54 55
55 /** 56 /**
56 * the client provides the main logic control for RTMP clients. 57 * the client provides the main logic control for RTMP clients.
@@ -66,6 +67,7 @@ private: @@ -66,6 +67,7 @@ private:
66 SrsRtmpServer* rtmp; 67 SrsRtmpServer* rtmp;
67 SrsRefer* refer; 68 SrsRefer* refer;
68 SrsBandwidth* bandwidth; 69 SrsBandwidth* bandwidth;
  70 + SrsSecurity* security;
69 // elapse duration in ms 71 // elapse duration in ms
70 // for live play duration, for instance, rtmpdump to record. 72 // for live play duration, for instance, rtmpdump to record.
71 // @see https://github.com/winlinvip/simple-rtmp-server/issues/47 73 // @see https://github.com/winlinvip/simple-rtmp-server/issues/47
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2015 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_app_security.hpp>
  25 +
  26 +#include <srs_kernel_error.hpp>
  27 +#include <srs_app_config.hpp>
  28 +
  29 +using namespace std;
  30 +
  31 +SrsSecurity::SrsSecurity()
  32 +{
  33 +}
  34 +
  35 +SrsSecurity::~SrsSecurity()
  36 +{
  37 +}
  38 +
  39 +int SrsSecurity::check(SrsRtmpConnType type, string ip, SrsRequest* req)
  40 +{
  41 + int ret = ERROR_SUCCESS;
  42 +
  43 + // allow all if security disabled.
  44 + if (!_srs_config->get_security_enabled(req->vhost)) {
  45 + return ret;
  46 + }
  47 +
  48 + // default to deny all when security enabled.
  49 + ret = ERROR_SYSTEM_SECURITY;
  50 +
  51 + // rules to apply
  52 + SrsConfDirective* rules = _srs_config->get_security_rules(req->vhost);
  53 + if (!rules) {
  54 + return ret;
  55 + }
  56 +
  57 + // allow if matches allow strategy.
  58 + if (allow_check(rules, type, ip) == ERROR_SYSTEM_SECURITY_ALLOW) {
  59 + ret = ERROR_SUCCESS;
  60 + }
  61 +
  62 + // deny if matches deny strategy.
  63 + if (deny_check(rules, type, ip) == ERROR_SYSTEM_SECURITY_DENY) {
  64 + ret = ERROR_SYSTEM_SECURITY_DENY;
  65 + }
  66 +
  67 + return ret;
  68 +}
  69 +
  70 +int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip)
  71 +{
  72 + int ret = ERROR_SUCCESS;
  73 +
  74 + for (int i = 0; i < (int)rules->directives.size(); i++) {
  75 + SrsConfDirective* rule = rules->at(i);
  76 +
  77 + if (rule->name != "allow") {
  78 + continue;
  79 + }
  80 +
  81 + switch (type) {
  82 + case SrsRtmpConnPlay:
  83 + if (rule->arg0() != "play") {
  84 + break;
  85 + }
  86 + if (rule->arg1() == "all" || rule->arg1() == ip) {
  87 + ret = ERROR_SYSTEM_SECURITY_ALLOW;
  88 + break;
  89 + }
  90 + break;
  91 + case SrsRtmpConnFMLEPublish:
  92 + case SrsRtmpConnFlashPublish:
  93 + if (rule->arg0() != "publish") {
  94 + break;
  95 + }
  96 + if (rule->arg1() == "all" || rule->arg1() == ip) {
  97 + ret = ERROR_SYSTEM_SECURITY_ALLOW;
  98 + break;
  99 + }
  100 + break;
  101 + case SrsRtmpConnUnknown:
  102 + default:
  103 + break;
  104 + }
  105 +
  106 + // when matched, donot search more.
  107 + if (ret == ERROR_SYSTEM_SECURITY_ALLOW) {
  108 + break;
  109 + }
  110 + }
  111 +
  112 + return ret;
  113 +}
  114 +
  115 +int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip)
  116 +{
  117 + int ret = ERROR_SUCCESS;
  118 +
  119 + for (int i = 0; i < (int)rules->directives.size(); i++) {
  120 + SrsConfDirective* rule = rules->at(i);
  121 +
  122 + if (rule->name != "deny") {
  123 + continue;
  124 + }
  125 +
  126 + switch (type) {
  127 + case SrsRtmpConnPlay:
  128 + if (rule->arg0() != "play") {
  129 + break;
  130 + }
  131 + if (rule->arg1() == "all" || rule->arg1() == ip) {
  132 + ret = ERROR_SYSTEM_SECURITY_DENY;
  133 + break;
  134 + }
  135 + break;
  136 + case SrsRtmpConnFMLEPublish:
  137 + case SrsRtmpConnFlashPublish:
  138 + if (rule->arg0() != "publish") {
  139 + break;
  140 + }
  141 + if (rule->arg1() == "all" || rule->arg1() == ip) {
  142 + ret = ERROR_SYSTEM_SECURITY_DENY;
  143 + break;
  144 + }
  145 + break;
  146 + case SrsRtmpConnUnknown:
  147 + default:
  148 + break;
  149 + }
  150 +
  151 + // when matched, donot search more.
  152 + if (ret == ERROR_SYSTEM_SECURITY_DENY) {
  153 + break;
  154 + }
  155 + }
  156 +
  157 + return ret;
  158 +}
  159 +
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2015 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_APP_SECURITY_HPP
  25 +#define SRS_APP_SECURITY_HPP
  26 +
  27 +/*
  28 +#include <srs_app_security.hpp>
  29 +*/
  30 +
  31 +#include <srs_core.hpp>
  32 +
  33 +#include <string>
  34 +
  35 +#include <srs_protocol_rtmp.hpp>
  36 +
  37 +class SrsConfDirective;
  38 +
  39 +/**
  40 +* the security apply on vhost.
  41 +* @see https://github.com/winlinvip/simple-rtmp-server/issues/211
  42 +*/
  43 +class SrsSecurity
  44 +{
  45 +public:
  46 + SrsSecurity();
  47 + virtual ~SrsSecurity();
  48 +public:
  49 + /**
  50 + * security check the client apply by vhost security strategy
  51 + * @param type the client type, publish or play.
  52 + * @param ip the ip address of client.
  53 + * @param req the request object of client.
  54 + */
  55 + virtual int check(SrsRtmpConnType type, std::string ip, SrsRequest* req);
  56 +private:
  57 + /**
  58 + * security check the allow,
  59 + * @return, if allowed, ERROR_SYSTEM_SECURITY_ALLOW.
  60 + */
  61 + virtual int allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip);
  62 + /**
  63 + * security check the deny,
  64 + * @return, if denied, ERROR_SYSTEM_SECURITY_DENY.
  65 + */
  66 + virtual int deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::string ip);
  67 +};
  68 +
  69 +#endif
  70 +
@@ -23,53 +23,142 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -23,53 +23,142 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 23
24 #include <srs_app_statistic.hpp> 24 #include <srs_app_statistic.hpp>
25 25
  26 +#include <unistd.h>
  27 +#include <sstream>
  28 +using namespace std;
  29 +
26 #include <srs_protocol_rtmp.hpp> 30 #include <srs_protocol_rtmp.hpp>
  31 +#include <srs_app_json.hpp>
  32 +
  33 +int64_t __srs_gvid = getpid();
27 34
28 -SrsStreamInfo::SrsStreamInfo() 35 +int64_t __srs_generate_id()
29 { 36 {
30 - _req = NULL; 37 + return __srs_gvid++;
31 } 38 }
32 39
33 -SrsStreamInfo::~SrsStreamInfo() 40 +SrsStatisticVhost::SrsStatisticVhost()
34 { 41 {
35 - if (_req != NULL)  
36 - delete _req; 42 + id = __srs_generate_id();
37 } 43 }
38 44
39 -SrsStatistic *SrsStatistic::_instance = NULL; 45 +SrsStatisticVhost::~SrsStatisticVhost()
  46 +{
  47 +}
40 48
41 -SrsStatistic::SrsStatistic() 49 +SrsStatisticStream::SrsStatisticStream()
42 { 50 {
  51 + id = __srs_generate_id();
  52 + vhost = NULL;
  53 +}
  54 +
  55 +SrsStatisticStream::~SrsStatisticStream()
  56 +{
  57 +}
  58 +
  59 +SrsStatistic* SrsStatistic::_instance = new SrsStatistic();
43 60
  61 +SrsStatistic::SrsStatistic()
  62 +{
  63 + _server_id = __srs_generate_id();
44 } 64 }
45 65
46 SrsStatistic::~SrsStatistic() 66 SrsStatistic::~SrsStatistic()
47 { 67 {
48 - SrsStreamInfoMap::iterator it;  
49 - for (it = pool.begin(); it != pool.end(); it++) {  
50 - delete it->second;  
51 - } 68 + if (true) {
  69 + std::map<std::string, SrsStatisticVhost*>::iterator it;
  70 + for (it = vhosts.begin(); it != vhosts.end(); it++) {
  71 + SrsStatisticVhost* vhost = it->second;
  72 + srs_freep(vhost);
  73 + }
  74 + }
  75 + if (true) {
  76 + std::map<std::string, SrsStatisticStream*>::iterator it;
  77 + for (it = streams.begin(); it != streams.end(); it++) {
  78 + SrsStatisticStream* stream = it->second;
  79 + srs_freep(stream);
  80 + }
  81 + }
  82 + if (true) {
  83 + std::map<int, SrsStatisticClient*>::iterator it;
  84 + for (it = clients.begin(); it != clients.end(); it++) {
  85 + SrsStatisticClient* client = it->second;
  86 + srs_freep(client);
  87 + }
  88 + }
  89 +}
  90 +
  91 +SrsStatistic* SrsStatistic::instance()
  92 +{
  93 + return _instance;
52 } 94 }
53 95
54 -SrsStreamInfoMap* SrsStatistic::get_pool() 96 +int SrsStatistic::on_client(int id, SrsRequest* req)
55 { 97 {
56 - return &pool; 98 + int ret = ERROR_SUCCESS;
  99 +
  100 + // create vhost if not exists.
  101 + SrsStatisticVhost* vhost = NULL;
  102 + if (vhosts.find(req->vhost) == vhosts.end()) {
  103 + vhost = new SrsStatisticVhost();
  104 + vhost->vhost = req->vhost;
  105 + vhosts[req->vhost] = vhost;
  106 + } else {
  107 + vhost = vhosts[req->vhost];
  108 + }
  109 +
  110 + // the url to identify the stream.
  111 + std::string url = req->get_stream_url();
  112 +
  113 + // create stream if not exists.
  114 + SrsStatisticStream* stream = NULL;
  115 + if (streams.find(url) == streams.end()) {
  116 + stream = new SrsStatisticStream();
  117 + stream->vhost = vhost;
  118 + stream->stream = req->stream;
  119 + stream->url = url;
  120 + streams[url] = stream;
  121 + } else {
  122 + stream = streams[url];
  123 + }
  124 +
  125 + return ret;
57 } 126 }
58 127
59 -SrsStreamInfo* SrsStatistic::get(void *p) 128 +int64_t SrsStatistic::server_id()
60 { 129 {
61 - SrsStreamInfoMap::iterator it = pool.find(p);  
62 - if (it == pool.end()) {  
63 - pool[p] = new SrsStreamInfo();  
64 - return pool[p];  
65 - } else {  
66 - return it->second;  
67 - } 130 + return _server_id;
68 } 131 }
69 132
70 -void SrsStatistic::add_request_info(void *p, SrsRequest *req) 133 +int SrsStatistic::dumps_vhosts(stringstream& ss)
71 { 134 {
72 - SrsStreamInfo *info = get(p);  
73 - if (info->_req == NULL)  
74 - info->_req = req->copy();  
75 -}  
  135 + int ret = ERROR_SUCCESS;
  136 +
  137 + std::map<std::string, SrsStatisticVhost*>::iterator it;
  138 + for (it = vhosts.begin(); it != vhosts.end(); it++) {
  139 + SrsStatisticVhost* vhost = it->second;
  140 + ss << __SRS_JOBJECT_START
  141 + << __SRS_JFIELD_ORG("id", vhost->id) << __SRS_JFIELD_CONT
  142 + << __SRS_JFIELD_STR("name", vhost->vhost)
  143 + << __SRS_JOBJECT_END;
  144 + }
  145 +
  146 + return ret;
  147 +}
  148 +
  149 +int SrsStatistic::dumps_streams(stringstream& ss)
  150 +{
  151 + int ret = ERROR_SUCCESS;
  152 +
  153 + std::map<std::string, SrsStatisticStream*>::iterator it;
  154 + for (it = streams.begin(); it != streams.end(); it++) {
  155 + SrsStatisticStream* stream = it->second;
  156 + ss << __SRS_JOBJECT_START
  157 + << __SRS_JFIELD_ORG("id", stream->id) << __SRS_JFIELD_CONT
  158 + << __SRS_JFIELD_STR("name", stream->stream) << __SRS_JFIELD_CONT
  159 + << __SRS_JFIELD_ORG("vhost", stream->vhost->id)
  160 + << __SRS_JOBJECT_END;
  161 + }
  162 +
  163 + return ret;
  164 +}
@@ -31,40 +31,78 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,40 +31,78 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
33 #include <map> 33 #include <map>
  34 +#include <string>
34 35
35 class SrsRequest; 36 class SrsRequest;
36 37
37 -class SrsStreamInfo 38 +struct SrsStatisticVhost
38 { 39 {
39 public: 40 public:
40 - SrsStreamInfo();  
41 - virtual ~SrsStreamInfo();  
42 -  
43 - SrsRequest *_req; 41 + int64_t id;
  42 + std::string vhost;
  43 +public:
  44 + SrsStatisticVhost();
  45 + virtual ~SrsStatisticVhost();
44 }; 46 };
45 -typedef std::map<void*, SrsStreamInfo*> SrsStreamInfoMap;  
46 47
47 -class SrsStatistic 48 +struct SrsStatisticStream
48 { 49 {
49 public: 50 public:
50 - static SrsStatistic *instance()  
51 - {  
52 - if (_instance == NULL) {  
53 - _instance = new SrsStatistic();  
54 - }  
55 - return _instance;  
56 - } 51 + int64_t id;
  52 + SrsStatisticVhost* vhost;
  53 + std::string app;
  54 + std::string stream;
  55 + std::string url;
  56 +public:
  57 + SrsStatisticStream();
  58 + virtual ~SrsStatisticStream();
  59 +};
57 60
58 - virtual SrsStreamInfoMap* get_pool(); 61 +struct SrsStatisticClient
  62 +{
  63 +public:
  64 + SrsStatisticStream* stream;
  65 + int id;
  66 +};
59 67
60 - virtual void add_request_info(void *p, SrsRequest *req);  
61 - 68 +class SrsStatistic
  69 +{
  70 +private:
  71 + static SrsStatistic *_instance;
  72 + // the id to identify the sever.
  73 + int64_t _server_id;
  74 + // key: vhost name, value: vhost object.
  75 + std::map<std::string, SrsStatisticVhost*> vhosts;
  76 + // key: stream name, value: stream object.
  77 + std::map<std::string, SrsStatisticStream*> streams;
  78 + // key: client id, value: stream object.
  79 + std::map<int, SrsStatisticClient*> clients;
62 private: 80 private:
63 SrsStatistic(); 81 SrsStatistic();
64 virtual ~SrsStatistic(); 82 virtual ~SrsStatistic();
65 - static SrsStatistic *_instance;  
66 - SrsStreamInfoMap pool;  
67 - virtual SrsStreamInfo *get(void *p); 83 +public:
  84 + static SrsStatistic* instance();
  85 +public:
  86 + /**
  87 + * when got a client to publish/play stream,
  88 + * @param id, the client srs id.
  89 + * @param req, the client request object.
  90 + */
  91 + virtual int on_client(int id, SrsRequest* req);
  92 +public:
  93 + /**
  94 + * get the server id, used to identify the server.
  95 + * for example, when restart, the server id must changed.
  96 + */
  97 + virtual int64_t server_id();
  98 + /**
  99 + * dumps the vhosts to sstream in json.
  100 + */
  101 + virtual int dumps_vhosts(std::stringstream& ss);
  102 + /**
  103 + * dumps the streams to sstream in json.
  104 + */
  105 + virtual int dumps_streams(std::stringstream& ss);
68 }; 106 };
69 107
70 -#endif  
  108 +#endif
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 85 34 +#define VERSION_REVISION 89
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -90,6 +90,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -90,6 +90,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
90 #define ERROR_SYSTEM_FILE_SEEK 1049 90 #define ERROR_SYSTEM_FILE_SEEK 1049
91 #define ERROR_SYSTEM_IO_INVALID 1050 91 #define ERROR_SYSTEM_IO_INVALID 1050
92 #define ERROR_ST_EXCEED_THREADS 1051 92 #define ERROR_ST_EXCEED_THREADS 1051
  93 +#define ERROR_SYSTEM_SECURITY 1052
  94 +#define ERROR_SYSTEM_SECURITY_DENY 1053
  95 +#define ERROR_SYSTEM_SECURITY_ALLOW 1054
  96 +#define ERROR_SYSTEM_TIME 1055
  97 +#define ERROR_SYSTEM_DIR_EXISTS 1056
  98 +#define ERROR_SYSTEM_CREATE_DIR 1057
93 99
94 /////////////////////////////////////////////////////// 100 ///////////////////////////////////////////////////////
95 // RTMP protocol error. 101 // RTMP protocol error.
@@ -149,7 +155,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -149,7 +155,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
149 /////////////////////////////////////////////////////// 155 ///////////////////////////////////////////////////////
150 #define ERROR_HLS_METADATA 3000 156 #define ERROR_HLS_METADATA 3000
151 #define ERROR_HLS_DECODE_ERROR 3001 157 #define ERROR_HLS_DECODE_ERROR 3001
152 -#define ERROR_HLS_CREATE_DIR 3002 158 +//#define ERROR_HLS_CREATE_DIR 3002
153 #define ERROR_HLS_OPEN_FAILED 3003 159 #define ERROR_HLS_OPEN_FAILED 3003
154 #define ERROR_HLS_WRITE_FAILED 3004 160 #define ERROR_HLS_WRITE_FAILED 3004
155 #define ERROR_HLS_AAC_FRAME_LENGTH 3005 161 #define ERROR_HLS_AAC_FRAME_LENGTH 3005
@@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,10 +32,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #endif 32 #endif
33 33
34 #include <string.h> 34 #include <string.h>
  35 +#include <sys/stat.h>
  36 +#include <fcntl.h>
35 37
36 using namespace std; 38 using namespace std;
37 39
38 #include <srs_kernel_log.hpp> 40 #include <srs_kernel_log.hpp>
  41 +#include <srs_kernel_error.hpp>
39 42
40 // this value must: 43 // this value must:
41 // equals to (SRS_SYS_CYCLE_INTERVAL*SRS_SYS_TIME_RESOLUTION_MS_TIMES)*1000 44 // 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) @@ -222,3 +225,56 @@ bool srs_string_ends_with(string str, string flag)
222 return str.rfind(flag) == str.length() - flag.length(); 225 return str.rfind(flag) == str.length() - flag.length();
223 } 226 }
224 227
  228 +int __srs_create_dir_recursively(string dir)
  229 +{
  230 + int ret = ERROR_SUCCESS;
  231 +
  232 + struct stat st;
  233 +
  234 + // stat current dir, if exists, return error.
  235 + if (stat(dir.c_str(), &st) == 0) {
  236 + return ERROR_SYSTEM_DIR_EXISTS;
  237 + }
  238 +
  239 + // create parent first.
  240 + size_t pos;
  241 + if ((pos = dir.rfind("/")) != std::string::npos) {
  242 + std::string parent = dir.substr(0, pos);
  243 + ret = __srs_create_dir_recursively(parent);
  244 + // return for error.
  245 + if (ret != ERROR_SUCCESS && ret != ERROR_SYSTEM_DIR_EXISTS) {
  246 + return ret;
  247 + }
  248 + // parent exists, set to ok.
  249 + ret = ERROR_SUCCESS;
  250 + }
  251 +
  252 + // create curren dir.
  253 + mode_t mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IXOTH;
  254 + if (::mkdir(dir.c_str(), mode) < 0) {
  255 + if (errno == EEXIST) {
  256 + return ERROR_SYSTEM_DIR_EXISTS;
  257 + }
  258 +
  259 + ret = ERROR_SYSTEM_CREATE_DIR;
  260 + srs_error("create dir %s failed. ret=%d", dir.c_str(), ret);
  261 + return ret;
  262 + }
  263 + srs_info("create dir %s success.", dir.c_str());
  264 +
  265 + return ret;
  266 +}
  267 +
  268 +int srs_create_dir_recursively(string dir)
  269 +{
  270 + int ret = ERROR_SUCCESS;
  271 +
  272 + ret = __srs_create_dir_recursively(dir);
  273 +
  274 + if (ret == ERROR_SYSTEM_DIR_EXISTS) {
  275 + return ERROR_SUCCESS;
  276 + }
  277 +
  278 + return ret;
  279 +}
  280 +
@@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars); @@ -59,5 +59,8 @@ extern std::string srs_string_remove(std::string str, std::string remove_chars);
59 // whether string end with 59 // whether string end with
60 extern bool srs_string_ends_with(std::string str, std::string flag); 60 extern bool srs_string_ends_with(std::string str, std::string flag);
61 61
  62 +// create dir recursively
  63 +extern int srs_create_dir_recursively(std::string dir);
  64 +
62 #endif 65 #endif
63 66
@@ -91,6 +91,7 @@ SrsRequest* SrsRequest::copy() @@ -91,6 +91,7 @@ SrsRequest* SrsRequest::copy()
91 { 91 {
92 SrsRequest* cp = new SrsRequest(); 92 SrsRequest* cp = new SrsRequest();
93 93
  94 + cp->ip = ip;
94 cp->app = app; 95 cp->app = app;
95 cp->objectEncoding = objectEncoding; 96 cp->objectEncoding = objectEncoding;
96 cp->pageUrl = pageUrl; 97 cp->pageUrl = pageUrl;
@@ -54,6 +54,9 @@ class IMergeReadHandler; @@ -54,6 +54,9 @@ class IMergeReadHandler;
54 class SrsRequest 54 class SrsRequest
55 { 55 {
56 public: 56 public:
  57 + // client ip.
  58 + std::string ip;
  59 +public:
57 /** 60 /**
58 * tcUrl: rtmp://request_vhost:port/app/stream 61 * tcUrl: rtmp://request_vhost:port/app/stream
59 * support pass vhost in query string, such as: 62 * support pass vhost in query string, such as:
1 file 1 file
2 - main readonly separator,  
3 - ..\main\srs_main_server.cpp,  
4 - auto readonly separator,  
5 - ..\..\objs\srs_auto_headers.hpp,  
6 - libs readonly separator,  
7 - ..\libs\srs_librtmp.hpp,  
8 - ..\libs\srs_librtmp.cpp,  
9 - ..\libs\srs_lib_bandwidth.hpp,  
10 - ..\libs\srs_lib_bandwidth.cpp,  
11 - ..\libs\srs_lib_simple_socket.hpp,  
12 - ..\libs\srs_lib_simple_socket.cpp,  
13 - core readonly separator,  
14 - ..\core\srs_core.hpp,  
15 - ..\core\srs_core.cpp,  
16 - ..\core\srs_core_autofree.hpp,  
17 - ..\core\srs_core_autofree.cpp,  
18 - ..\core\srs_core_performance.hpp,  
19 - ..\core\srs_core_performance.cpp,  
20 - kernel readonly separator,  
21 - ..\kernel\srs_kernel_codec.hpp,  
22 - ..\kernel\srs_kernel_codec.cpp,  
23 - ..\kernel\srs_kernel_consts.hpp,  
24 - ..\kernel\srs_kernel_consts.cpp,  
25 - ..\kernel\srs_kernel_error.hpp,  
26 - ..\kernel\srs_kernel_error.cpp,  
27 - ..\kernel\srs_kernel_file.hpp,  
28 - ..\kernel\srs_kernel_file.cpp,  
29 - ..\kernel\srs_kernel_flv.hpp,  
30 - ..\kernel\srs_kernel_flv.cpp,  
31 - ..\kernel\srs_kernel_log.hpp,  
32 - ..\kernel\srs_kernel_log.cpp,  
33 - ..\kernel\srs_kernel_stream.hpp,  
34 - ..\kernel\srs_kernel_stream.cpp,  
35 - ..\kernel\srs_kernel_utility.hpp,  
36 - ..\kernel\srs_kernel_utility.cpp,  
37 - rtmp-protocol readonly separator,  
38 - ..\rtmp\srs_protocol_amf0.hpp,  
39 - ..\rtmp\srs_protocol_amf0.cpp,  
40 - ..\rtmp\srs_protocol_buffer.hpp,  
41 - ..\rtmp\srs_protocol_buffer.cpp,  
42 - ..\rtmp\srs_protocol_handshake.hpp,  
43 - ..\rtmp\srs_protocol_handshake.cpp,  
44 - ..\rtmp\srs_protocol_io.hpp,  
45 - ..\rtmp\srs_protocol_io.cpp,  
46 - ..\rtmp\srs_protocol_msg_array.hpp,  
47 - ..\rtmp\srs_protocol_msg_array.cpp,  
48 - ..\rtmp\srs_protocol_rtmp.hpp,  
49 - ..\rtmp\srs_protocol_rtmp.cpp,  
50 - ..\rtmp\srs_protocol_stack.hpp,  
51 - ..\rtmp\srs_protocol_stack.cpp,  
52 - ..\rtmp\srs_protocol_utility.hpp,  
53 - ..\rtmp\srs_protocol_utility.cpp,  
54 - app readonly separator,  
55 - ..\app\srs_app_avc_aac.hpp,  
56 - ..\app\srs_app_avc_aac.cpp,  
57 - ..\app\srs_app_bandwidth.hpp,  
58 - ..\app\srs_app_bandwidth.cpp,  
59 - ..\app\srs_app_conn.hpp,  
60 - ..\app\srs_app_conn.cpp,  
61 - ..\app\srs_app_config.hpp,  
62 - ..\app\srs_app_config.cpp,  
63 - ..\app\srs_app_dvr.hpp,  
64 - ..\app\srs_app_dvr.cpp,  
65 - ..\app\srs_app_edge.hpp,  
66 - ..\app\srs_app_edge.cpp,  
67 - ..\app\srs_app_empty.hpp,  
68 - ..\app\srs_app_empty.cpp,  
69 - ..\app\srs_app_encoder.hpp,  
70 - ..\app\srs_app_encoder.cpp,  
71 - ..\app\srs_app_ffmpeg.hpp,  
72 - ..\app\srs_app_ffmpeg.cpp,  
73 - ..\app\srs_app_forward.hpp,  
74 - ..\app\srs_app_forward.cpp,  
75 - ..\app\srs_app_heartbeat.hpp,  
76 - ..\app\srs_app_heartbeat.cpp,  
77 - ..\app\srs_app_hls.hpp,  
78 - ..\app\srs_app_hls.cpp,  
79 - ..\app\srs_app_http.hpp,  
80 - ..\app\srs_app_http.cpp,  
81 - ..\app\srs_app_http_api.hpp,  
82 - ..\app\srs_app_http_api.cpp,  
83 - ..\app\srs_app_http_client.hpp,  
84 - ..\app\srs_app_http_client.cpp,  
85 - ..\app\srs_app_http_conn.hpp,  
86 - ..\app\srs_app_http_conn.cpp,  
87 - ..\app\srs_app_http_hooks.hpp,  
88 - ..\app\srs_app_http_hooks.cpp,  
89 - ..\app\srs_app_ingest.hpp,  
90 - ..\app\srs_app_ingest.cpp,  
91 - ..\app\srs_app_json.hpp,  
92 - ..\app\srs_app_json.cpp,  
93 - ..\app\srs_app_kbps.hpp,  
94 - ..\app\srs_app_kbps.cpp,  
95 - ..\app\srs_app_log.hpp,  
96 - ..\app\srs_app_log.cpp,  
97 - ..\app\srs_app_recv_thread.hpp,  
98 - ..\app\srs_app_recv_thread.cpp,  
99 - ..\app\srs_app_refer.hpp,  
100 - ..\app\srs_app_refer.cpp,  
101 - ..\app\srs_app_reload.hpp,  
102 - ..\app\srs_app_reload.cpp,  
103 - ..\app\srs_app_rtmp_conn.hpp,  
104 - ..\app\srs_app_rtmp_conn.cpp,  
105 - ..\app\srs_app_pithy_print.hpp,  
106 - ..\app\srs_app_pithy_print.cpp,  
107 - ..\app\srs_app_server.hpp,  
108 - ..\app\srs_app_server.cpp,  
109 - ..\app\srs_app_st.hpp,  
110 - ..\app\srs_app_st.cpp,  
111 - ..\app\srs_app_st_socket.hpp,  
112 - ..\app\srs_app_st_socket.cpp,  
113 - ..\app\srs_app_source.hpp,  
114 - ..\app\srs_app_source.cpp,  
115 - ..\app\srs_app_thread.hpp,  
116 - ..\app\srs_app_thread.cpp,  
117 - ..\app\srs_app_utility.hpp,  
118 - ..\app\srs_app_utility.cpp,  
119 - utest readonly separator,  
120 - ..\utest\srs_utest.hpp,  
121 - ..\utest\srs_utest.cpp,  
122 - ..\utest\srs_utest_amf0.hpp,  
123 - ..\utest\srs_utest_amf0.cpp,  
124 - ..\utest\srs_utest_config.hpp,  
125 - ..\utest\srs_utest_config.cpp,  
126 - ..\utest\srs_utest_core.hpp,  
127 - ..\utest\srs_utest_core.cpp,  
128 - ..\utest\srs_utest_kernel.hpp,  
129 - ..\utest\srs_utest_kernel.cpp,  
130 - ..\utest\srs_utest_protocol.hpp,  
131 - ..\utest\srs_utest_protocol.cpp,  
132 - ..\utest\srs_utest_reload.hpp,  
133 - ..\utest\srs_utest_reload.cpp,  
134 - research readonly separator,  
135 - ..\..\research\librtmp\srs_aac_raw_publish.c,  
136 - ..\..\research\librtmp\srs_audio_raw_publish.c,  
137 - ..\..\research\librtmp\srs_bandwidth_check.c,  
138 - ..\..\research\librtmp\srs_detect_rtmp.c,  
139 - ..\..\research\librtmp\srs_flv_injecter.c,  
140 - ..\..\research\librtmp\srs_flv_parser.c,  
141 - ..\..\research\librtmp\srs_h264_raw_publish.c,  
142 - ..\..\research\librtmp\srs_ingest_flv.c,  
143 - ..\..\research\librtmp\srs_ingest_rtmp.c,  
144 - ..\..\research\librtmp\srs_play.c,  
145 - ..\..\research\librtmp\srs_publish.c,  
146 - ..\..\research\librtmp\srs_rtmp_dump.c,  
147 - ..\..\research\hls\ts_info.cc; 2 + main readonly separator,
  3 + ..\main\srs_main_server.cpp,
  4 + auto readonly separator,
  5 + ..\..\objs\srs_auto_headers.hpp,
  6 + libs readonly separator,
  7 + ..\libs\srs_librtmp.hpp,
  8 + ..\libs\srs_librtmp.cpp,
  9 + ..\libs\srs_lib_bandwidth.hpp,
  10 + ..\libs\srs_lib_bandwidth.cpp,
  11 + ..\libs\srs_lib_simple_socket.hpp,
  12 + ..\libs\srs_lib_simple_socket.cpp,
  13 + core readonly separator,
  14 + ..\core\srs_core.hpp,
  15 + ..\core\srs_core.cpp,
  16 + ..\core\srs_core_autofree.hpp,
  17 + ..\core\srs_core_autofree.cpp,
  18 + ..\core\srs_core_performance.hpp,
  19 + ..\core\srs_core_performance.cpp,
  20 + kernel readonly separator,
  21 + ..\kernel\srs_kernel_codec.hpp,
  22 + ..\kernel\srs_kernel_codec.cpp,
  23 + ..\kernel\srs_kernel_consts.hpp,
  24 + ..\kernel\srs_kernel_consts.cpp,
  25 + ..\kernel\srs_kernel_error.hpp,
  26 + ..\kernel\srs_kernel_error.cpp,
  27 + ..\kernel\srs_kernel_file.hpp,
  28 + ..\kernel\srs_kernel_file.cpp,
  29 + ..\kernel\srs_kernel_flv.hpp,
  30 + ..\kernel\srs_kernel_flv.cpp,
  31 + ..\kernel\srs_kernel_log.hpp,
  32 + ..\kernel\srs_kernel_log.cpp,
  33 + ..\kernel\srs_kernel_stream.hpp,
  34 + ..\kernel\srs_kernel_stream.cpp,
  35 + ..\kernel\srs_kernel_utility.hpp,
  36 + ..\kernel\srs_kernel_utility.cpp,
  37 + rtmp-protocol readonly separator,
  38 + ..\rtmp\srs_protocol_amf0.hpp,
  39 + ..\rtmp\srs_protocol_amf0.cpp,
  40 + ..\rtmp\srs_protocol_buffer.hpp,
  41 + ..\rtmp\srs_protocol_buffer.cpp,
  42 + ..\rtmp\srs_protocol_handshake.hpp,
  43 + ..\rtmp\srs_protocol_handshake.cpp,
  44 + ..\rtmp\srs_protocol_io.hpp,
  45 + ..\rtmp\srs_protocol_io.cpp,
  46 + ..\rtmp\srs_protocol_msg_array.hpp,
  47 + ..\rtmp\srs_protocol_msg_array.cpp,
  48 + ..\rtmp\srs_protocol_rtmp.hpp,
  49 + ..\rtmp\srs_protocol_rtmp.cpp,
  50 + ..\rtmp\srs_protocol_stack.hpp,
  51 + ..\rtmp\srs_protocol_stack.cpp,
  52 + ..\rtmp\srs_protocol_utility.hpp,
  53 + ..\rtmp\srs_protocol_utility.cpp,
  54 + app readonly separator,
  55 + ..\app\srs_app_avc_aac.hpp,
  56 + ..\app\srs_app_avc_aac.cpp,
  57 + ..\app\srs_app_bandwidth.hpp,
  58 + ..\app\srs_app_bandwidth.cpp,
  59 + ..\app\srs_app_conn.hpp,
  60 + ..\app\srs_app_conn.cpp,
  61 + ..\app\srs_app_config.hpp,
  62 + ..\app\srs_app_config.cpp,
  63 + ..\app\srs_app_dvr.hpp,
  64 + ..\app\srs_app_dvr.cpp,
  65 + ..\app\srs_app_edge.hpp,
  66 + ..\app\srs_app_edge.cpp,
  67 + ..\app\srs_app_empty.hpp,
  68 + ..\app\srs_app_empty.cpp,
  69 + ..\app\srs_app_encoder.hpp,
  70 + ..\app\srs_app_encoder.cpp,
  71 + ..\app\srs_app_ffmpeg.hpp,
  72 + ..\app\srs_app_ffmpeg.cpp,
  73 + ..\app\srs_app_forward.hpp,
  74 + ..\app\srs_app_forward.cpp,
  75 + ..\app\srs_app_heartbeat.hpp,
  76 + ..\app\srs_app_heartbeat.cpp,
  77 + ..\app\srs_app_hls.hpp,
  78 + ..\app\srs_app_hls.cpp,
  79 + ..\app\srs_app_http.hpp,
  80 + ..\app\srs_app_http.cpp,
  81 + ..\app\srs_app_http_api.hpp,
  82 + ..\app\srs_app_http_api.cpp,
  83 + ..\app\srs_app_http_client.hpp,
  84 + ..\app\srs_app_http_client.cpp,
  85 + ..\app\srs_app_http_conn.hpp,
  86 + ..\app\srs_app_http_conn.cpp,
  87 + ..\app\srs_app_http_hooks.hpp,
  88 + ..\app\srs_app_http_hooks.cpp,
  89 + ..\app\srs_app_ingest.hpp,
  90 + ..\app\srs_app_ingest.cpp,
  91 + ..\app\srs_app_json.hpp,
  92 + ..\app\srs_app_json.cpp,
  93 + ..\app\srs_app_kbps.hpp,
  94 + ..\app\srs_app_kbps.cpp,
  95 + ..\app\srs_app_log.hpp,
  96 + ..\app\srs_app_log.cpp,
  97 + ..\app\srs_app_recv_thread.hpp,
  98 + ..\app\srs_app_recv_thread.cpp,
  99 + ..\app\srs_app_refer.hpp,
  100 + ..\app\srs_app_refer.cpp,
  101 + ..\app\srs_app_reload.hpp,
  102 + ..\app\srs_app_reload.cpp,
  103 + ..\app\srs_app_rtmp_conn.hpp,
  104 + ..\app\srs_app_rtmp_conn.cpp,
  105 + ..\app\srs_app_pithy_print.hpp,
  106 + ..\app\srs_app_pithy_print.cpp,
  107 + ..\app\srs_app_security.hpp,
  108 + ..\app\srs_app_security.cpp,
  109 + ..\app\srs_app_server.hpp,
  110 + ..\app\srs_app_server.cpp,
  111 + ..\app\srs_app_st.hpp,
  112 + ..\app\srs_app_st.cpp,
  113 + ..\app\srs_app_st_socket.hpp,
  114 + ..\app\srs_app_st_socket.cpp,
  115 + ..\app\srs_app_statistic.hpp,
  116 + ..\app\srs_app_statistic.cpp,
  117 + ..\app\srs_app_source.hpp,
  118 + ..\app\srs_app_source.cpp,
  119 + ..\app\srs_app_thread.hpp,
  120 + ..\app\srs_app_thread.cpp,
  121 + ..\app\srs_app_utility.hpp,
  122 + ..\app\srs_app_utility.cpp,
  123 + utest readonly separator,
  124 + ..\utest\srs_utest.hpp,
  125 + ..\utest\srs_utest.cpp,
  126 + ..\utest\srs_utest_amf0.hpp,
  127 + ..\utest\srs_utest_amf0.cpp,
  128 + ..\utest\srs_utest_config.hpp,
  129 + ..\utest\srs_utest_config.cpp,
  130 + ..\utest\srs_utest_core.hpp,
  131 + ..\utest\srs_utest_core.cpp,
  132 + ..\utest\srs_utest_kernel.hpp,
  133 + ..\utest\srs_utest_kernel.cpp,
  134 + ..\utest\srs_utest_protocol.hpp,
  135 + ..\utest\srs_utest_protocol.cpp,
  136 + ..\utest\srs_utest_reload.hpp,
  137 + ..\utest\srs_utest_reload.cpp,
  138 + research readonly separator,
  139 + ..\..\research\librtmp\srs_aac_raw_publish.c,
  140 + ..\..\research\librtmp\srs_audio_raw_publish.c,
  141 + ..\..\research\librtmp\srs_bandwidth_check.c,
  142 + ..\..\research\librtmp\srs_detect_rtmp.c,
  143 + ..\..\research\librtmp\srs_flv_injecter.c,
  144 + ..\..\research\librtmp\srs_flv_parser.c,
  145 + ..\..\research\librtmp\srs_h264_raw_publish.c,
  146 + ..\..\research\librtmp\srs_ingest_flv.c,
  147 + ..\..\research\librtmp\srs_ingest_rtmp.c,
  148 + ..\..\research\librtmp\srs_play.c,
  149 + ..\..\research\librtmp\srs_publish.c,
  150 + ..\..\research\librtmp\srs_rtmp_dump.c,
  151 + ..\..\research\hls\ts_info.cc;
148 152
149 mainconfig 153 mainconfig
150 - "" = "MAIN"; 154 + "" = "MAIN";
151 155
@@ -1206,12 +1206,12 @@ VOID TEST(KernelStreamTest, StreamRead8Bytes) @@ -1206,12 +1206,12 @@ VOID TEST(KernelStreamTest, StreamRead8Bytes)
1206 data[18] = 0x13; 1206 data[18] = 0x13;
1207 data[19] = 0x14; 1207 data[19] = 0x14;
1208 1208
1209 - EXPECT_EQ(0x0102030405060708, s.read_8bytes());  
1210 - EXPECT_EQ(0x090a0b0c0d0e0f10, s.read_8bytes()); 1209 + EXPECT_EQ(0x0102030405060708LL, s.read_8bytes());
  1210 + EXPECT_EQ(0x090a0b0c0d0e0f10LL, s.read_8bytes());
1211 1211
1212 s.skip(-1 * s.pos()); 1212 s.skip(-1 * s.pos());
1213 s.skip(5); 1213 s.skip(5);
1214 - EXPECT_EQ(0x060708090a0b0c0d, s.read_8bytes()); 1214 + EXPECT_EQ(0x060708090a0b0c0dLL, s.read_8bytes());
1215 } 1215 }
1216 1216
1217 /** 1217 /**
@@ -1364,8 +1364,8 @@ VOID TEST(KernelStreamTest, StreamWrite8Bytes) @@ -1364,8 +1364,8 @@ VOID TEST(KernelStreamTest, StreamWrite8Bytes)
1364 1364
1365 EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024)); 1365 EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
1366 1366
1367 - s.write_8bytes(0x1011121314151617);  
1368 - s.write_8bytes(0x1819202122232425); 1367 + s.write_8bytes(0x1011121314151617LL);
  1368 + s.write_8bytes(0x1819202122232425LL);
1369 1369
1370 s.skip(-1 * s.pos()); 1370 s.skip(-1 * s.pos());
1371 EXPECT_EQ(0x10, s.read_1bytes()); 1371 EXPECT_EQ(0x10, s.read_1bytes());