Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix Issue 3701 : HTTP streaming support listening at both IPv4 and IPv6 #4265

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 142 additions & 10 deletions trunk/src/app/srs_app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2512,22 +2512,54 @@ srs_error_t SrsConfig::check_normal_config()
// Check HTTP API and server.
////////////////////////////////////////////////////////////////////////
if (true) {
string api = get_http_api_listen();
string server = get_http_stream_listen();
if (api.empty()) {
vector<string> api_vec = get_http_apis_listens();
vector<string> server_vec = get_http_streams_listens();
if (api_vec.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "http_api.listen requires params");
}
if (server.empty()) {
if (server_vec.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "http_server.listen requires params");
}

string apis = get_https_api_listen();
string servers = get_https_stream_listen();
if (api == server && apis != servers) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "for same http, https api(%s) != server(%s)", apis.c_str(), servers.c_str());
std::sort(api_vec.begin(), api_vec.end());
std::sort(server_vec.begin(), server_vec.end());

std::vector<string> intersection_result;
std::vector<string> intersections_result;
std::set_intersection(
api_vec.begin(), api_vec.end(),
server_vec.begin(), server_vec.end(),
std::back_inserter(intersection_result)
);

bool isNotSameHttp = intersection_result.size() == 0;
bool isFullyContainedHttp = !isNotSameHttp && intersection_result.size() == api_vec.size();
if (!isNotSameHttp && !isFullyContainedHttp)
{
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "http api and http server intersect in functionality, but an http server does not fully encapsulate an http api");
}
if (apis == servers && api != server) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "for same https, http api(%s) != server(%s)", api.c_str(), server.c_str());
vector<string> apis_vec = get_https_apis_listens();
vector<string> servers_vec = get_https_streams_listens();

std::sort(apis_vec.begin(), apis_vec.end());
std::sort(servers_vec.begin(), servers_vec.end());
std::set_intersection(
apis_vec.begin(), apis_vec.end(),
servers_vec.begin(), servers_vec.end(),
std::back_inserter(intersections_result)
);

bool isNotSameHttps = intersections_result.size() == 0;
bool isFullyContainedHttps = !isNotSameHttps && intersections_result.size() == apis_vec.size();
if (!isNotSameHttps && !isFullyContainedHttps)
{
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "https api and https server intersect in functionality, but an https server does not fully encapsulate an https api");
}
if (!isNotSameHttp && isNotSameHttps) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "for same http, https api != server");
}
if (!isNotSameHttps && isNotSameHttp) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "for same https, http api != server");
}

if (get_https_api_enabled() && !get_http_api_enabled()) {
Expand Down Expand Up @@ -7696,6 +7728,30 @@ string SrsConfig::get_http_api_listen()
return conf->arg0();
}

std::vector<std::string> SrsConfig::get_http_apis_listens()
{
std::vector<string> ports;
if (!srs_getenv("srs.http_api.listen").empty()) { // SRS_LISTEN
return srs_string_split(srs_getenv("srs.http_api.listen"), " ");
}
string DEFAULT = "1985";
SrsConfDirective* conf = root->get("http_api");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
conf = conf->get("listen");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
for (int i = 0; i < (int)conf->args.size(); i++) {
ports.push_back(conf->args.at(i));
}

return ports;
}

bool SrsConfig::get_http_api_crossdomain()
{
SRS_OVERWRITE_BY_ENV_BOOL2("srs.http_api.crossdomain"); // SRS_HTTP_API_CROSSDOMAIN
Expand Down Expand Up @@ -7900,6 +7956,35 @@ string SrsConfig::get_https_api_listen()
return conf->arg0();
}

std::vector<std::string> SrsConfig::get_https_apis_listens()
{
std::vector<string> ports;
if (!srs_getenv("srs.http_api.https.listen").empty()) { // SRS_LISTEN
return srs_string_split(srs_getenv("srs.http_api.https.listen"), " ");
}
static string DEFAULT = "1990";
if (get_http_api_listen() == get_http_stream_listen()) {
DEFAULT = get_https_stream_listen();
}

SrsConfDirective* conf = get_https_api();
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
conf = conf->get("listen");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
for (int i = 0; i < (int)conf->args.size(); i++) {
ports.push_back(conf->args.at(i));
}

return ports;
}


string SrsConfig::get_https_api_ssl_key()
{
SRS_OVERWRITE_BY_ENV_STRING("srs.http_api.https.key"); // SRS_HTTP_API_HTTPS_KEY
Expand Down Expand Up @@ -8315,6 +8400,29 @@ bool SrsConfig::get_http_stream_enabled(SrsConfDirective* conf)

return SRS_CONF_PREFER_FALSE(conf->arg0());
}
std::vector<std::string> SrsConfig::get_http_streams_listens()
{
std::vector<string> ports;
if (!srs_getenv("srs.http_server.listen").empty()) { // SRS_LISTEN
return srs_string_split(srs_getenv("srs.http_server.listen"), " ");
}
string DEFAULT = "8080";
SrsConfDirective* conf = root->get("http_server");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
conf = conf->get("listen");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
for (int i = 0; i < (int)conf->args.size(); i++) {
ports.push_back(conf->args.at(i));
}

return ports;
}

string SrsConfig::get_http_stream_listen()
{
Expand Down Expand Up @@ -8421,6 +8529,30 @@ string SrsConfig::get_https_stream_listen()
return conf->arg0();
}

std::vector<std::string> SrsConfig::get_https_streams_listens()
{
std::vector<string> ports;
if (!srs_getenv("srs.http_server.https.listen").empty()) { // SRS_LISTEN
return srs_string_split(srs_getenv("srs.http_server.https.listen"), " ");
}
static string DEFAULT = "8088";
SrsConfDirective* conf = get_https_stream();
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
conf = conf->get("listen");
if (!conf) {
ports.push_back(DEFAULT);
return ports;
}
for (int i = 0; i < (int)conf->args.size(); i++) {
ports.push_back(conf->args.at(i));
}

return ports;
}

string SrsConfig::get_https_stream_ssl_key()
{
SRS_OVERWRITE_BY_ENV_STRING("srs.http_server.https.key"); // SRS_HTTP_SERVER_HTTPS_KEY
Expand Down
10 changes: 10 additions & 0 deletions trunk/src/app/srs_app_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,10 @@ class SrsConfig
virtual bool get_http_api_enabled();
// Get the http api listen port.
virtual std::string get_http_api_listen();
// Get the http api listen port.
// user can specifies multiple listen ports,
// each args of directive is a listen port.
virtual std::vector<std::string> get_http_apis_listens();
// Whether enable crossdomain for http api.
virtual bool get_http_api_crossdomain();
// Whether enable the HTTP RAW API.
Expand All @@ -1053,6 +1057,7 @@ class SrsConfig
public:
virtual bool get_https_api_enabled();
virtual std::string get_https_api_listen();
virtual std::vector<std::string> get_https_apis_listens();
virtual std::string get_https_api_ssl_key();
virtual std::string get_https_api_ssl_cert();
// http stream section
Expand All @@ -1065,6 +1070,10 @@ class SrsConfig
virtual bool get_http_stream_enabled();
// Get the http stream listen port.
virtual std::string get_http_stream_listen();
// Get the http stream listen port.
// user can specifies multiple listen ports,
// each args of directive is a listen port.
virtual std::vector<std::string> get_http_streams_listens();
// Get the http stream root dir.
virtual std::string get_http_stream_dir();
// Whether enable crossdomain for http static and stream server.
Expand All @@ -1075,6 +1084,7 @@ class SrsConfig
public:
virtual bool get_https_stream_enabled();
virtual std::string get_https_stream_listen();
virtual std::vector<std::string> get_https_streams_listens();
virtual std::string get_https_stream_ssl_key();
virtual std::string get_https_stream_ssl_cert();
public:
Expand Down
99 changes: 77 additions & 22 deletions trunk/src/app/srs_app_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,10 @@ SrsServer::SrsServer()
ppid = ::getppid();

rtmp_listener_ = new SrsMultipleTcpListeners(this);
api_listener_ = new SrsTcpListener(this);
apis_listener_ = new SrsTcpListener(this);
http_listener_ = new SrsTcpListener(this);
https_listener_ = new SrsTcpListener(this);
api_listener_ = new SrsMultipleTcpListeners(this);
apis_listener_ = new SrsMultipleTcpListeners(this);
http_listener_ = new SrsMultipleTcpListeners(this);
https_listener_ = new SrsMultipleTcpListeners(this);
webrtc_listener_ = new SrsTcpListener(this);
stream_caster_flv_listener_ = new SrsHttpFlvListener();
stream_caster_mpegts_ = new SrsUdpCasterListener();
Expand Down Expand Up @@ -491,32 +491,87 @@ srs_error_t SrsServer::initialize()
_srs_config->subscribe(this);

bool stream = _srs_config->get_http_stream_enabled();
string http_listen = _srs_config->get_http_stream_listen();
string https_listen = _srs_config->get_https_stream_listen();
vector<string> server_vec = _srs_config->get_http_streams_listens();
vector<string> servers_vec = _srs_config->get_https_streams_listens();
std::sort(server_vec.begin(), server_vec.end());
std::sort(servers_vec.begin(), servers_vec.end());




#ifdef SRS_RTC
bool rtc = _srs_config->get_rtc_server_enabled();
bool rtc_tcp = _srs_config->get_rtc_server_tcp_enabled();
string rtc_listen = srs_int2str(_srs_config->get_rtc_server_tcp_listen());
// If enabled and listen is the same value, resue port for WebRTC over TCP.
if (stream && rtc && rtc_tcp && http_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses http=%s server", rtc_listen.c_str(), http_listen.c_str());
reuse_rtc_over_server_ = true;
for (int idx = 0; idx < server_vec.size(); idx++)
{
string http_listen = server_vec[idx];
if (stream && rtc && rtc_tcp && http_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses http=%s server", rtc_listen.c_str(), http_listen.c_str());
reuse_rtc_over_server_ = true;
}
}
if (stream && rtc && rtc_tcp && https_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses https=%s server", rtc_listen.c_str(), https_listen.c_str());
reuse_rtc_over_server_ = true;
for (int idx = 0; idx < servers_vec.size(); idx++)
{
string https_listen = servers_vec[idx];
if (stream && rtc && rtc_tcp && https_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses https=%s server", rtc_listen.c_str(), https_listen.c_str());
reuse_rtc_over_server_ = true;
}
}
#endif

// If enabled and the listen is the same value, reuse port.
bool api = _srs_config->get_http_api_enabled();
string api_listen = _srs_config->get_http_api_listen();
string apis_listen = _srs_config->get_https_api_listen();
if (stream && api && api_listen == http_listen && apis_listen == https_listen) {
srs_trace("API reuses http=%s and https=%s server", http_listen.c_str(), https_listen.c_str());
vector<string> api_vec = _srs_config->get_http_apis_listens();
vector<string> apis_vec = _srs_config->get_https_apis_listens();

std::sort(api_vec.begin(), api_vec.end());
std::sort(apis_vec.begin(), apis_vec.end());

std::vector<string> intersection_result;
std::vector<string> intersections_result;

std::set_intersection(
api_vec.begin(), api_vec.end(),
server_vec.begin(), server_vec.end(),
std::back_inserter(intersection_result)
);
std::set_intersection(
apis_vec.begin(), apis_vec.end(),
servers_vec.begin(), servers_vec.end(),
std::back_inserter(intersections_result)
);
bool isNotSameHttp = intersection_result.size() == 0;
bool isFullyContainedHttp = !isNotSameHttp && intersection_result.size() == api_vec.size();
bool isNotSameHttps = intersections_result.size() == 0;
bool isFullyContainedHttps = !isNotSameHttps && intersections_result.size() == apis_vec.size();

if ((!isNotSameHttp && !isFullyContainedHttp) || (!isNotSameHttps && !isFullyContainedHttps))
{
return srs_error_wrap(err, "http api and http server intersect in functionality, but an http server does not fully encapsulate an http api");
}

if (stream && api && isFullyContainedHttp && isFullyContainedHttps)
{
srs_trace("API reuses http and https server");
for (int idx = 0; idx < intersection_result.size(); idx++)
{
string http_listen = intersection_result[idx];
srs_trace("API reuses http=%s server", http_listen.c_str());
}
for (int idx = 0; idx < intersections_result.size(); idx++)
{
string https_listen = intersections_result[idx];
srs_trace("API reuses https=%s server", https_listen.c_str());
}
reuse_api_over_server_ = true;
}
else if (isNotSameHttp && isNotSameHttps)
{
reuse_api_over_server_ = false;
}

// Only init HTTP API when not reusing HTTP server.
if (!reuse_api_over_server_) {
Expand Down Expand Up @@ -585,8 +640,8 @@ srs_error_t SrsServer::listen()
if (reuse_api_over_server_) {
srs_trace("HTTP-API: Reuse listen to http server %s", _srs_config->get_http_stream_listen().c_str());
} else {
api_listener_->set_endpoint(_srs_config->get_http_api_listen())->set_label("HTTP-API");
if ((err = api_listener_->listen()) != srs_success) {
api_listener_->add(_srs_config->get_http_apis_listens())->set_label("HTTP_API");
if ((err = api_listener_->listen()) != srs_success) {
return srs_error_wrap(err, "http api listen");
}
}
Expand All @@ -597,24 +652,24 @@ srs_error_t SrsServer::listen()
if (reuse_api_over_server_) {
srs_trace("HTTPS-API: Reuse listen to http server %s", _srs_config->get_https_stream_listen().c_str());
} else {
apis_listener_->set_endpoint(_srs_config->get_https_api_listen())->set_label("HTTPS-API");
if ((err = apis_listener_->listen()) != srs_success) {
apis_listener_->add(_srs_config->get_https_apis_listens())->set_label("HTTPS_API");
if ((err = apis_listener_->listen()) != srs_success) {
return srs_error_wrap(err, "https api listen");
}
}
}

// Create HTTP server listener.
if (_srs_config->get_http_stream_enabled()) {
http_listener_->set_endpoint(_srs_config->get_http_stream_listen())->set_label("HTTP-Server");
http_listener_->add(_srs_config->get_http_streams_listens())->set_label("HTTP-Server");
if ((err = http_listener_->listen()) != srs_success) {
return srs_error_wrap(err, "http server listen");
}
}

// Create HTTPS server listener.
if (_srs_config->get_https_stream_enabled()) {
https_listener_->set_endpoint(_srs_config->get_https_stream_listen())->set_label("HTTPS-Server");
https_listener_->add(_srs_config->get_https_streams_listens())->set_label("HTTPS-Server");
if ((err = https_listener_->listen()) != srs_success) {
return srs_error_wrap(err, "https server listen");
}
Expand Down
Loading
Loading