diff --git a/README.md b/README.md index 01fd64992..4523fe24e 100755 --- a/README.md +++ b/README.md @@ -92,11 +92,12 @@ A big `THANK YOU` also goes to: ## Releases -* 2020-08-15, Release [v4.0.156](https://github.com/ossrs/srs/releases/tag/v4.0.156), 4.0 dev4, v4.0.156, 145490 lines. -* 2020-08-14, Release [v4.0.153](https://github.com/ossrs/srs/releases/tag/v4.0.153), 4.0 dev3, v4.0.153, 145506 lines. -* 2020-08-07, Release [v4.0.150](https://github.com/ossrs/srs/releases/tag/v4.0.150), 4.0 dev2, v4.0.150, 145289 lines. -* 2020-07-25, Release [v4.0.146](https://github.com/ossrs/srs/releases/tag/v4.0.146), 4.0 dev1, v4.0.146, 144026 lines. -* 2020-07-04, Release [v4.0.139](https://github.com/ossrs/srs/releases/tag/v4.0.139), 4.0 dev0, v4.0.139, 143245 lines. +* 2021-09-05, Release [v4.0.161](https://github.com/ossrs/srs/releases/tag/v4.0.161), 4.0 dev5, v4.0.161, 145865 lines. +* 2021-08-15, Release [v4.0.156](https://github.com/ossrs/srs/releases/tag/v4.0.156), 4.0 dev4, v4.0.156, 145490 lines. +* 2021-08-14, Release [v4.0.153](https://github.com/ossrs/srs/releases/tag/v4.0.153), 4.0 dev3, v4.0.153, 145506 lines. +* 2021-08-07, Release [v4.0.150](https://github.com/ossrs/srs/releases/tag/v4.0.150), 4.0 dev2, v4.0.150, 145289 lines. +* 2021-07-25, Release [v4.0.146](https://github.com/ossrs/srs/releases/tag/v4.0.146), 4.0 dev1, v4.0.146, 144026 lines. +* 2021-07-04, Release [v4.0.139](https://github.com/ossrs/srs/releases/tag/v4.0.139), 4.0 dev0, v4.0.139, 143245 lines. * 2020-06-27, [Release v3.0-r0][r3.0r0], 3.0 release0, 3.0.141, 122674 lines. * 2020-02-02, [Release v3.0-b0][r3.0b0], 3.0 beta0, 3.0.112, 121709 lines. * 2019-10-04, [Release v3.0-a0][r3.0a0], 3.0 alpha0, 3.0.56, 107946 lines. diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index b5cee6995..5e2795826 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -1493,6 +1493,7 @@ vhost dvr.srs.com { # /, apply to specified stream of app. # for example, to dvr the following two streams: # live/stream1 live/stream2 + # @remark Reload is disabled, @see https://github.com/ossrs/srs/issues/2181 # default: all dvr_apply all; # the dvr plan. canbe: diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 41cbee78b..86bbfe755 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -23,6 +23,9 @@ The changelog for SRS. ## SRS 4.0 Changelog +* v4.0, 2021-09-05, RTC: Merge [#2581](https://github.com/ossrs/srs/pull/2581), Fix listen ipv6 and port. 4.0.161 +* v4.0, 2021-09-04, For [#2282](https://github.com/ossrs/srs/pull/2282), [#2181](https://github.com/ossrs/srs/issues/2181), Move DVR async worker from SrsDvrPlan to global. +* v4.0, 2021-09-04, For [#2282](https://github.com/ossrs/srs/pull/2282), [#2181](https://github.com/ossrs/srs/issues/2181), Remove reload for dvr_apply. 4.0.160 * v4.0, 2021-08-28, RTC: Merge [#1859](https://github.com/ossrs/srs/pull/1859), Enhancement: Add param and stream to on_connect. 4.0.159 * v4.0, 2021-08-27, RTC: Merge [#2544](https://github.com/ossrs/srs/pull/2544), Support for multiple SPS/PPS, then pick the first one. 4.0.158 * v4.0, 2021-08-17, RTC: Merge [#2470](https://github.com/ossrs/srs/pull/2470), RTC: Fix rtc to rtmp sync timestamp using sender report. 4.0.157 diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7469ac569..87ce7c22a 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -45,8 +45,6 @@ using namespace srs_internal; // @global the version to identify the core. const char* _srs_version = "XCORE-" RTMP_SIG_SRS_SERVER; -#define SRS_WIKI_URL_LOG "https://github.com/ossrs/srs/wiki/v1_CN_SrsLog" - // when user config an invalid value, macros to perfer true or false. #define SRS_CONF_PERFER_FALSE(conf_arg) conf_arg == "on" #define SRS_CONF_PERFER_TRUE(conf_arg) conf_arg != "off" @@ -1408,17 +1406,6 @@ srs_error_t SrsConfig::reload_vhost(SrsConfDirective* old_root) } srs_trace("vhost %s reload dvr success.", vhost.c_str()); } - // dvr_apply, the dynamic dvr filter. - if (true) { - // we must reload the dvr_apply, for it's apply to specified stream, - // and we donot want one stream reload take effect on another one. - // @see https://github.com/ossrs/srs/issues/459#issuecomment-140296597 - SrsConfDirective* nda = new_vhost->get("dvr")? new_vhost->get("dvr")->get("dvr_apply") : NULL; - SrsConfDirective* oda = old_vhost->get("dvr")? old_vhost->get("dvr")->get("dvr_apply") : NULL; - if (!srs_directive_equals(nda, oda) && (err = do_reload_vhost_dvr_apply(vhost)) != srs_success) { - return srs_error_wrap(err, "reload dvr_apply"); - } - } // exec, only one per vhost if (!srs_directive_equals(new_vhost->get("exec"), old_vhost->get("exec"))) { @@ -2009,7 +1996,7 @@ srs_error_t SrsConfig::parse_options(int argc, char** argv) return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "no log file"); } if (get_log_tank_file()) { - srs_trace("you can check log by: tail -f %s (@see %s)", log_filename.c_str(), SRS_WIKI_URL_LOG); + srs_trace("you can check log by: tail -n 30 -f %s", log_filename.c_str()); srs_trace("please check SRS by: ./etc/init.d/srs status"); } else { srs_trace("write log to console"); @@ -3203,64 +3190,6 @@ srs_error_t SrsConfig::raw_enable_vhost(string vhost, bool& applied) return err; } - -srs_error_t SrsConfig::raw_enable_dvr(string vhost, string stream, bool& applied) -{ - srs_error_t err = srs_success; - - applied = false; - - SrsConfDirective* conf = root->get("vhost", vhost); - srs_assert(conf); - - conf = conf->get_or_create("dvr")->get_or_create("dvr_apply"); - - if (conf->args.size() == 1 && (conf->arg0() == "all" || conf->arg0() == "none")) { - conf->args.clear(); - } - - if (std::find(conf->args.begin(), conf->args.end(), stream) == conf->args.end()) { - conf->args.push_back(stream); - } - - if ((err = do_reload_vhost_dvr_apply(vhost)) != srs_success) { - return srs_error_wrap(err, "reload vhost dvr"); - } - - applied = true; - - return err; -} - -srs_error_t SrsConfig::raw_disable_dvr(string vhost, string stream, bool& applied) -{ - srs_error_t err = srs_success; - - applied = false; - - SrsConfDirective* conf = root->get("vhost", vhost); - srs_assert(conf); - - conf = conf->get_or_create("dvr")->get_or_create("dvr_apply"); - - std::vector::iterator it; - - if ((it = std::find(conf->args.begin(), conf->args.end(), stream)) != conf->args.end()) { - conf->args.erase(it); - } - - if (conf->args.empty()) { - conf->args.push_back("none"); - } - - if ((err = do_reload_vhost_dvr_apply(vhost)) != srs_success) { - return srs_error_wrap(err, "reload vhost dvr"); - } - - applied = true; - - return err; -} // LCOV_EXCL_STOP srs_error_t SrsConfig::do_reload_listen() @@ -3428,22 +3357,6 @@ srs_error_t SrsConfig::do_reload_vhost_removed(string vhost) return err; } -srs_error_t SrsConfig::do_reload_vhost_dvr_apply(string vhost) -{ - srs_error_t err = srs_success; - - vector::iterator it; - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((err = subscribe->on_reload_vhost_dvr_apply(vhost)) != srs_success) { - return srs_error_wrap(err, "vhost %s notify subscribes dvr_apply failed", vhost.c_str()); - } - } - srs_trace("vhost %s reload dvr_apply success.", vhost.c_str()); - - return err; -} - string SrsConfig::config() { return config_file; @@ -3704,9 +3617,17 @@ srs_error_t SrsConfig::check_normal_config() return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen requires params"); } for (int i = 0; i < (int)listens.size(); i++) { - string port = listens[i]; - if (port.empty() || ::atoi(port.c_str()) <= 0) { - return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen.port=%s is invalid", port.c_str()); + int port; string ip; + srs_parse_endpoint(listens[i], ip, port); + + // check ip + if (!srs_check_ip_addr_valid(ip)) { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen.ip=%s is invalid", ip.c_str()); + } + + // check port + if (port <= 0) { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen.port=%d is invalid", port); } } } @@ -3773,7 +3694,7 @@ srs_error_t SrsConfig::check_normal_config() return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "log file is empty"); } if (get_log_tank_file()) { - srs_trace("you can check log by: tail -f %s (@see %s)", log_filename.c_str(), SRS_WIKI_URL_LOG); + srs_trace("you can check log by: tail -n 30 -f %s", log_filename.c_str()); srs_trace("please check SRS by: ./etc/init.d/srs status"); } else { srs_trace("write log to console"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index aa14f2ccf..76e01ea95 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -371,10 +371,6 @@ public: virtual srs_error_t raw_disable_vhost(std::string vhost, bool& applied); // RAW enable the disabled vhost. virtual srs_error_t raw_enable_vhost(std::string vhost, bool& applied); - // RAW enable the dvr of stream of vhost. - virtual srs_error_t raw_enable_dvr(std::string vhost, std::string stream, bool& applied); - // RAW disable the dvr of stream of vhost. - virtual srs_error_t raw_disable_dvr(std::string vhost, std::string stream, bool& applied); private: virtual srs_error_t do_reload_listen(); virtual srs_error_t do_reload_pid(); @@ -386,7 +382,6 @@ private: virtual srs_error_t do_reload_pithy_print_ms(); virtual srs_error_t do_reload_vhost_added(std::string vhost); virtual srs_error_t do_reload_vhost_removed(std::string vhost); - virtual srs_error_t do_reload_vhost_dvr_apply(std::string vhost); public: // Get the config file path. virtual std::string config(); diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index b42160d3f..7cdeda2ad 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -566,6 +566,8 @@ string SrsDvrAsyncCallOnDvr::to_string() return ss.str(); } +extern SrsAsyncCallWorker* _srs_dvr_async; + SrsDvrPlan::SrsDvrPlan() { req = NULL; @@ -573,13 +575,11 @@ SrsDvrPlan::SrsDvrPlan() dvr_enabled = false; segment = NULL; - async = new SrsAsyncCallWorker(); } SrsDvrPlan::~SrsDvrPlan() { srs_freep(segment); - srs_freep(async); } srs_error_t SrsDvrPlan::initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsRequest* r) @@ -599,18 +599,11 @@ srs_error_t SrsDvrPlan::initialize(SrsOriginHub* h, SrsDvrSegmenter* s, SrsReque srs_error_t SrsDvrPlan::on_publish() { - srs_error_t err = srs_success; - - if ((err = async->start()) != srs_success) { - return srs_error_wrap(err, "async"); - } - - return err; + return srs_success; } void SrsDvrPlan::on_unpublish() { - async->stop(); } srs_error_t SrsDvrPlan::on_meta_data(SrsSharedPtrMessage* shared_metadata) @@ -663,7 +656,7 @@ srs_error_t SrsDvrPlan::on_reap_segment() SrsFragment* fragment = segment->current(); string fullpath = fragment->fullpath(); - if ((err = async->execute(new SrsDvrAsyncCallOnDvr(cid, req, fullpath))) != srs_success) { + if ((err = _srs_dvr_async->execute(new SrsDvrAsyncCallOnDvr(cid, req, fullpath))) != srs_success) { return srs_error_wrap(err, "reap segment"); } @@ -1008,32 +1001,3 @@ srs_error_t SrsDvr::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma return plan->on_video(shared_video, format); } -srs_error_t SrsDvr::on_reload_vhost_dvr_apply(string vhost) -{ - srs_error_t err = srs_success; - - SrsConfDirective* conf = _srs_config->get_dvr_apply(req->vhost); - bool v = srs_config_apply_filter(conf, req); - - // the apply changed, republish the dvr. - if (v == actived) { - return err; - } - actived = v; - - on_unpublish(); - if (!actived) { - return err; - } - - if ((err = on_publish()) != srs_success) { - return srs_error_wrap(err, "on publish"); - } - if ((err = hub->on_dvr_request_sh()) != srs_success) { - return srs_error_wrap(err, "request sh"); - } - - return err; -} - - diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index be060fc74..b4ed0b960 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -161,7 +161,6 @@ public: protected: SrsOriginHub* hub; SrsDvrSegmenter* segment; - SrsAsyncCallWorker* async; bool dvr_enabled; public: SrsDvrPlan(); @@ -250,9 +249,6 @@ public: // mux the video packets to dvr. // @param shared_video, directly ptr, copy it if need to save it. virtual srs_error_t on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format); -// Interface ISrsReloadHandler -public: - virtual srs_error_t on_reload_vhost_dvr_apply(std::string vhost); }; #endif diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index ded8c3c5b..9b0b09b58 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1198,37 +1198,6 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } else { // TODO: support other param. } - } else if (scope == "dvr") { - std::string action = r->query_get("param"); - std::string stream = r->query_get("data"); - extra += "/" + stream + " to " + action; - - if (action != "enable" && action != "disable") { - return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_NOT_ALLOWED); - } - - // the vhost must exists. - if (!_srs_config->get_vhost(value, false)) { - return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_PARAMS); - } - - if (!_srs_config->get_dvr_enabled(value)) { - return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_NOT_ALLOWED); - } - - if (action == "enable") { - if ((err = _srs_config->raw_enable_dvr(value, stream, applied)) != srs_success) { - int code = srs_error_code(err); - srs_error_reset(err); - return srs_api_response_code(w, r, code); - } - } else { - if ((err = _srs_config->raw_disable_dvr(value, stream, applied)) != srs_success) { - int code = srs_error_code(err); - srs_error_reset(err); - return srs_api_response_code(w, r, code); - } - } } else { // TODO: support other scope. } diff --git a/trunk/src/app/srs_app_reload.cpp b/trunk/src/app/srs_app_reload.cpp index e72b969b4..dde75ee24 100644 --- a/trunk/src/app/srs_app_reload.cpp +++ b/trunk/src/app/srs_app_reload.cpp @@ -163,11 +163,6 @@ srs_error_t ISrsReloadHandler::on_reload_vhost_dvr(string /*vhost*/) return srs_success; } -srs_error_t ISrsReloadHandler::on_reload_vhost_dvr_apply(string /*vhost*/) -{ - return srs_success; -} - srs_error_t ISrsReloadHandler::on_reload_vhost_publish(string /*vhost*/) { return srs_success; diff --git a/trunk/src/app/srs_app_reload.hpp b/trunk/src/app/srs_app_reload.hpp index 275dd850f..8d877c707 100644 --- a/trunk/src/app/srs_app_reload.hpp +++ b/trunk/src/app/srs_app_reload.hpp @@ -53,7 +53,6 @@ public: virtual srs_error_t on_reload_vhost_hls(std::string vhost); virtual srs_error_t on_reload_vhost_hds(std::string vhost); virtual srs_error_t on_reload_vhost_dvr(std::string vhost); - virtual srs_error_t on_reload_vhost_dvr_apply(std::string vhost); virtual srs_error_t on_reload_vhost_publish(std::string vhost); virtual srs_error_t on_reload_vhost_tcp_nodelay(std::string vhost); virtual srs_error_t on_reload_vhost_realtime(std::string vhost); diff --git a/trunk/src/app/srs_app_threads.cpp b/trunk/src/app/srs_app_threads.cpp index 167174e3f..39014749d 100644 --- a/trunk/src/app/srs_app_threads.cpp +++ b/trunk/src/app/srs_app_threads.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef SRS_RTC #include @@ -268,6 +269,7 @@ srs_error_t SrsCircuitBreaker::on_timer(srs_utime_t interval) } SrsCircuitBreaker* _srs_circuit_breaker = NULL; +SrsAsyncCallWorker* _srs_dvr_async = NULL; srs_error_t srs_thread_initialize() { @@ -408,6 +410,12 @@ srs_error_t srs_thread_initialize() _srs_pps_objs_rothers = new SrsPps(); #endif + // Create global async worker for DVR. + _srs_dvr_async = new SrsAsyncCallWorker(); + if ((err = _srs_dvr_async->start()) != srs_success) { + return srs_error_wrap(err, "dvr async"); + } + return err; } diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 74943f397..b03e74370 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 0 -#define VERSION_REVISION 159 +#define VERSION_REVISION 161 #endif diff --git a/trunk/src/kernel/srs_kernel_utility.cpp b/trunk/src/kernel/srs_kernel_utility.cpp index c07a37689..b3ecd91a7 100644 --- a/trunk/src/kernel/srs_kernel_utility.cpp +++ b/trunk/src/kernel/srs_kernel_utility.cpp @@ -258,6 +258,24 @@ void srs_parse_endpoint(string hostport, string& ip, int& port) } } +bool srs_check_ip_addr_valid(string ip) +{ + unsigned char buf[sizeof(struct in6_addr)]; + + // check ipv4 + int ret = inet_pton(AF_INET, ip.data(), buf); + if (ret > 0) { + return true; + } + + ret = inet_pton(AF_INET6, ip.data(), buf); + if (ret > 0) { + return true; + } + + return false; +} + string srs_int2str(int64_t value) { // len(max int64_t) is 20, plus one "+-." @@ -308,6 +326,7 @@ string srs_string_replace(string str, string old_str, string new_str) size_t pos = 0; while ((pos = ret.find(old_str, pos)) != std::string::npos) { ret = ret.replace(pos, old_str.length(), new_str); + pos += new_str.length(); } return ret; diff --git a/trunk/src/kernel/srs_kernel_utility.hpp b/trunk/src/kernel/srs_kernel_utility.hpp index 5293558b3..747df6b1b 100644 --- a/trunk/src/kernel/srs_kernel_utility.hpp +++ b/trunk/src/kernel/srs_kernel_utility.hpp @@ -45,6 +45,9 @@ extern void srs_parse_hostport(std::string hostport, std::string& host, int& por // @remark The hostport format in <[ip:]port>, where ip is default to "0.0.0.0". extern void srs_parse_endpoint(std::string hostport, std::string& ip, int& port); +// Check whether the ip is valid. +extern bool srs_check_ip_addr_valid(std::string ip); + // Parse the int64 value to string. extern std::string srs_int2str(int64_t value); // Parse the float value to string, precise is 2. diff --git a/trunk/src/srt/ts_demux.cpp b/trunk/src/srt/ts_demux.cpp index 575289b5d..7b0cb8cdd 100644 --- a/trunk/src/srt/ts_demux.cpp +++ b/trunk/src/srt/ts_demux.cpp @@ -89,6 +89,7 @@ int ts_demux::decode_unit(unsigned char* data_p, std::string key_path, TS_DATA_C field_p->_transport_private_data_length = data_p[pos]; pos++; memcpy(field_p->_private_data_byte, data_p + pos, field_p->_transport_private_data_length); + pos += field_p->_transport_private_data_length; } if( field_p->_adaptation_field_extension_flag == 1 ) { //adaptation_field_extension_length 8 uimsbf diff --git a/trunk/src/srt/ts_demux.hpp b/trunk/src/srt/ts_demux.hpp index cbdd441e2..a2bf119d4 100644 --- a/trunk/src/srt/ts_demux.hpp +++ b/trunk/src/srt/ts_demux.hpp @@ -125,6 +125,7 @@ public: unsigned short _DTS_next_AU2;//15bit unsigned char _marker_bit2;//1bit unsigned short _DTS_next_AU3;//15bit + unsigned char _marker_bit3;//1bit }; class ts_header { diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp index b613a4963..87aa4c94d 100644 --- a/trunk/src/utest/srs_utest_kernel.cpp +++ b/trunk/src/utest/srs_utest_kernel.cpp @@ -2079,6 +2079,15 @@ VOID TEST(KernelUtilityTest, UtilityString) str1 = srs_string_replace(str, "o", "XX"); EXPECT_STREQ("HellXX, WXXrld! HellXX, SRS!", str1.c_str()); + // origin_str == old_str + std::string origin_str = "xxd"; + str1 = srs_string_replace(origin_str, "xxd", "x1d"); + EXPECT_STREQ("x1d", str1.c_str()); + + // new_str include old_str. + str1 = srs_string_replace(str, "Hello", "HelloN"); + EXPECT_STREQ("HelloN, World! HelloN, SRS!", str1.c_str()); + str1 = srs_string_trim_start(str, "x"); EXPECT_STREQ("Hello, World! Hello, SRS!", str1.c_str()); @@ -5519,3 +5528,18 @@ VOID TEST(KernelUtilityTest, CoverStringAssign) ASSERT_STREQ("", sps.c_str()); } +VOID TEST(KernelUtilityTest, CoverCheckIPAddrValid) +{ + ASSERT_TRUE(srs_check_ip_addr_valid("172.16.254.1")); + ASSERT_TRUE(srs_check_ip_addr_valid("2001:0db8:85a3:0:0:8A2E:0370:7334")); + ASSERT_FALSE(srs_check_ip_addr_valid("")); + + //IPv4 any addr + ASSERT_TRUE(srs_check_ip_addr_valid("0.0.0.0")); + //IPV6 any addr + ASSERT_TRUE(srs_check_ip_addr_valid("::")); + + ASSERT_FALSE(srs_check_ip_addr_valid("256.256.256.256")); + ASSERT_FALSE(srs_check_ip_addr_valid("2001:0db8:85a3:0:0:8A2E:0370:7334:")); + ASSERT_FALSE(srs_check_ip_addr_valid("1e1.4.5.6")); +} \ No newline at end of file