diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 8bf44582b..c630002fd 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -396,6 +396,11 @@ rtc_server { # @see https://github.com/ossrs/srs/wiki/v4_CN_WebRTC#config-candidate # default: * candidate *; + # If api_as_candidates is on, SRS would try to use the IP of api server, specified by srs.sdk.js request: + # api:string "http://r.ossrs.net:1985/rtc/v1/play/" + # in this case, the r.ossrs.net and 39.107.238.185 will be added as candidates. + # Default: on + api_as_candidates on; # The IP family filter for auto discover candidate, it can be: # ipv4 Filter IP v4 candidates. # ipv6 Filter IP v6 candidates. diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 273f059fc..f7f97ffe1 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -8,6 +8,7 @@ The changelog for SRS. ## SRS 4.0 Changelog +* v4.0, 2021-01-04, Discover api server and ip as candidates. v4.0.218 * v4.0, 2021-01-04, Install test-on self-sign certificate. v4.0.217 * v4.0, 2021-01-03, For [#2824](https://github.com/ossrs/srs/issues/2824): Support config in_docker to fix the detect fail. (#2824). v4.0.216 * v4.0, 2021-12-31, For [#2728](https://github.com/ossrs/srs/issues/2728): Refine error log for rtmp2rtc. (#2728). v4.0.215 diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index d6ea94634..a984b4cd8 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2542,7 +2542,7 @@ srs_error_t SrsConfig::check_normal_config() string n = conf->at(i)->name; if (n != "enabled" && n != "listen" && n != "dir" && n != "candidate" && n != "ecdsa" && n != "encrypt" && n != "reuseport" && n != "merge_nalus" && n != "black_hole" - && n != "ip_family") { + && n != "ip_family" && n != "api_as_candidates") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal rtc_server.%s", n.c_str()); } } @@ -3544,6 +3544,23 @@ std::string SrsConfig::get_rtc_server_candidates() return conf->arg0(); } +bool SrsConfig::get_api_as_candidates() +{ + static bool DEFAULT = true; + + SrsConfDirective* conf = root->get("rtc_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("api_as_candidates"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + std::string SrsConfig::get_rtc_server_ip_family() { static string DEFAULT = "ipv4"; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 51510b5df..a37461643 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -469,6 +469,7 @@ public: virtual bool get_rtc_server_enabled(SrsConfDirective* conf); virtual int get_rtc_server_listen(); virtual std::string get_rtc_server_candidates(); + virtual bool get_api_as_candidates(); virtual std::string get_rtc_server_ip_family(); virtual bool get_rtc_server_ecdsa(); virtual bool get_rtc_server_encrypt(); diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index b64595c79..e9593ca90 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -117,6 +117,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe // The RTC user config object. SrsRtcUserConfig ruc; ruc.req_->ip = clientip; + ruc.api_ = api; srs_parse_rtmp_url(streamurl, ruc.req_->tcUrl, ruc.req_->stream); @@ -383,6 +384,7 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt // The RTC user config object. SrsRtcUserConfig ruc; ruc.req_->ip = clientip; + ruc.api_ = api; srs_parse_rtmp_url(streamurl, ruc.req_->tcUrl, ruc.req_->stream); diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 608245b3a..ab3584048 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -6,6 +6,7 @@ #include +#include using namespace std; #include @@ -149,18 +150,66 @@ bool srs_is_rtcp(const uint8_t* data, size_t len) return (len >= 12) && (data[0] & 0x80) && (data[1] >= 192 && data[1] <= 223); } -static std::vector get_candidate_ips() +srs_error_t api_server_as_candidates(string api, set& candidate_ips) { - std::vector candidate_ips; + srs_error_t err = srs_success; + if (api.empty() || !_srs_config->get_api_as_candidates()) { + return err; + } + + SrsHttpUri uri; + if ((err = uri.initialize(api)) != srs_success) { + return srs_error_wrap(err, "parse %s", api.c_str()); + } + + string hostname = uri.get_host(); + if (hostname.empty() || hostname == SRS_CONSTS_LOCALHOST_NAME) { + return err; + } + if (hostname == SRS_CONSTS_LOCALHOST || hostname == SRS_CONSTS_LOOPBACK || hostname == SRS_CONSTS_LOOPBACK6) { + return err; + } + + // Try to parse the domain name if not IP. + int family = 0; + string ip = srs_dns_resolve(hostname, family); + if (ip.empty() || ip == SRS_CONSTS_LOCALHOST || ip == SRS_CONSTS_LOOPBACK || ip == SRS_CONSTS_LOOPBACK6) { + return err; + } + + // Try to add the original hostname and ip as candidates. + candidate_ips.insert(hostname); + candidate_ips.insert(ip); + + return err; +} + +static set discover_candidates(SrsRtcUserConfig* ruc) +{ + srs_error_t err = srs_success; + + // Try to discover the eip as candidate, specified by user. + set candidate_ips; + if (!ruc->eip_.empty()) { + candidate_ips.insert(ruc->eip_); + } + + // Try to discover from api of request, if api_as_candidates enabled. + if ((err = api_server_as_candidates(ruc->api_, candidate_ips)) != srs_success) { + srs_warn("ignore discovering ip from api %s, err %s", ruc->api_.c_str(), srs_error_summary(err).c_str()); + srs_freep(err); + } + + // If not * or 0.0.0.0, use the candidate as exposed IP. string candidate = _srs_config->get_rtc_server_candidates(); if (candidate != "*" && candidate != "0.0.0.0") { - candidate_ips.push_back(candidate); + candidate_ips.insert(candidate); return candidate_ips; } - // For * or 0.0.0.0, auto discovery expose ip addresses. - std::vector& ips = srs_get_local_ips(); + // Discover from local network interface addresses. + vector& ips = srs_get_local_ips(); if (ips.empty()) { return candidate_ips; } @@ -180,7 +229,7 @@ static std::vector get_candidate_ips() continue; } - candidate_ips.push_back(ip->ip); + candidate_ips.insert(ip->ip); srs_trace("Best matched ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str()); } @@ -195,7 +244,7 @@ static std::vector get_candidate_ips() continue; } - candidate_ips.push_back(ip->ip); + candidate_ips.insert(ip->ip); srs_trace("No best matched, use first ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str()); return candidate_ips; } @@ -203,7 +252,7 @@ static std::vector get_candidate_ips() // We use the first one. if (candidate_ips.empty()) { SrsIPAddress* ip = ips[0]; - candidate_ips.push_back(ip->ip); + candidate_ips.insert(ip->ip); srs_warn("No best matched, use first ip=%s, ifname=%s", ip->ip.c_str(), ip->ifname.c_str()); return candidate_ips; } @@ -524,19 +573,17 @@ srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig* ruc, SrsSdp& local local_sdp.set_fingerprint(_srs_rtc_dtls_certificate->get_fingerprint()); // We allows to mock the eip of server. - if (!ruc->eip_.empty()) { - string host; - int port = _srs_config->get_rtc_server_listen(); - srs_parse_hostport(ruc->eip_, host, port); - - local_sdp.add_candidate(host, port, "host"); - srs_trace("RTC: Use candidate mock_eip %s as %s:%d", ruc->eip_.c_str(), host.c_str(), port); - } else { - std::vector candidate_ips = get_candidate_ips(); - for (int i = 0; i < (int)candidate_ips.size(); ++i) { - local_sdp.add_candidate(candidate_ips[i], _srs_config->get_rtc_server_listen(), "host"); + if (true) { + int listen_port = _srs_config->get_rtc_server_listen(); + set candidates = discover_candidates(ruc); + for (set::iterator it = candidates.begin(); it != candidates.end(); ++it) { + string hostname; int port = listen_port; + srs_parse_hostport(*it, hostname,port); + local_sdp.add_candidate(hostname, port, "host"); } - srs_trace("RTC: Use candidates %s", srs_join_vector_string(candidate_ips, ", ").c_str()); + + vector v = vector(candidates.begin(), candidates.end()); + srs_trace("RTC: Use candidates %s", srs_join_vector_string(v, ", ").c_str()); } // Setup the negotiate DTLS by config. diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 8d3343a28..f16530df9 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -78,6 +78,7 @@ public: SrsSdp remote_sdp_; std::string eip_; std::string codec_; + std::string api_; // Generated data. SrsRequest* req_; diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 9238cb913..5c2a4e8d1 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 217 +#define VERSION_REVISION 218 #endif diff --git a/trunk/src/kernel/srs_kernel_consts.hpp b/trunk/src/kernel/srs_kernel_consts.hpp index ef87b5575..5cac4a4bc 100644 --- a/trunk/src/kernel/srs_kernel_consts.hpp +++ b/trunk/src/kernel/srs_kernel_consts.hpp @@ -107,6 +107,7 @@ /////////////////////////////////////////////////////////// #define SRS_CONSTS_NULL_FILE "/dev/null" #define SRS_CONSTS_LOCALHOST "127.0.0.1" +#define SRS_CONSTS_LOCALHOST_NAME "localhost" #define SRS_CONSTS_LOOPBACK "0.0.0.0" #define SRS_CONSTS_LOOPBACK6 "::"