diff --git a/README.md b/README.md
index 7b2619c47..c2d3f544e 100755
--- a/README.md
+++ b/README.md
@@ -188,6 +188,11 @@ Other documents:
+## V5 changes
+
+* v5.0, 2021-03-17, Live: Refine edge to follow client and HTTP/302. 5.0.1
+* v5.0, 2021-03-15, Init SRS/5. 5.0.0
+
## V4 changes
* v4.0, 2021-03-09, DTLS: Fix ARQ bug, use openssl timeout. 4.0.84
diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf
index e1b64f10d..70d199e4a 100644
--- a/trunk/conf/full.conf
+++ b/trunk/conf/full.conf
@@ -708,6 +708,11 @@ vhost cluster.srs.com {
# flvs, Connect origin by HTTPS-FLV
# Default: rtmp
protocol rtmp;
+
+ # Whether follow client protocol to connect to origin.
+ # @remark The FLV might use different signature(in query string) to RTMP.
+ # Default: off
+ follow_client off;
}
}
diff --git a/trunk/configure b/trunk/configure
index 70a8319f9..9fba358e6 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -204,7 +204,7 @@ fi
MODULE_ID="CORE"
MODULE_DEPENDS=()
ModuleLibIncs=(${SRS_OBJS_DIR})
-MODULE_FILES=("srs_core" "srs_core_version4" "srs_core_autofree" "srs_core_performance"
+MODULE_FILES=("srs_core" "srs_core_version5" "srs_core_autofree" "srs_core_performance"
"srs_core_time")
CORE_INCS="src/core"; MODULE_DIR=${CORE_INCS} . auto/modules.sh
CORE_OBJS="${MODULE_OBJS[@]}"
diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp
index 7e538389b..cbf710c7a 100644
--- a/trunk/src/app/srs_app_config.cpp
+++ b/trunk/src/app/srs_app_config.cpp
@@ -3829,7 +3829,7 @@ srs_error_t SrsConfig::check_normal_config()
for (int j = 0; j < (int)conf->directives.size(); j++) {
string m = conf->at(j)->name;
if (m != "mode" && m != "origin" && m != "token_traverse" && m != "vhost" && m != "debug_srs_upnode" && m != "coworkers"
- && m != "origin_cluster" && m != "protocol") {
+ && m != "origin_cluster" && m != "protocol" && m != "follow_client") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.cluster.%s of %s", m.c_str(), vhost->arg0().c_str());
}
}
@@ -6218,6 +6218,28 @@ string SrsConfig::get_vhost_edge_protocol(string vhost)
return conf->arg0();
}
+bool SrsConfig::get_vhost_edge_follow_client(string vhost)
+{
+ static bool DEFAULT = false;
+
+ SrsConfDirective* conf = get_vhost(vhost);
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("cluster");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ conf = conf->get("follow_client");
+ if (!conf) {
+ return DEFAULT;
+ }
+
+ return SRS_CONF_PERFER_FALSE(conf->arg0());
+}
+
bool SrsConfig::get_vhost_edge_token_traverse(string vhost)
{
static bool DEFAULT = false;
diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp
index 0ace96eb6..f880da403 100644
--- a/trunk/src/app/srs_app_config.hpp
+++ b/trunk/src/app/srs_app_config.hpp
@@ -775,6 +775,8 @@ public:
virtual SrsConfDirective* get_vhost_edge_origin(std::string vhost);
// Get the procotol to connect to origin server.
virtual std::string get_vhost_edge_protocol(std::string vhost);
+ // Whether follow client protocol to connect to origin.
+ virtual bool get_vhost_edge_follow_client(std::string vhost);
// Whether edge token tranverse is enabled,
// If true, edge will send connect origin to verfy the token of client.
// For example, we verify all clients on the origin FMS by server-side as,
diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp
index 64fbe61fa..9cdbaf5c4 100644
--- a/trunk/src/app/srs_app_edge.cpp
+++ b/trunk/src/app/srs_app_edge.cpp
@@ -183,6 +183,7 @@ SrsEdgeFlvUpstream::SrsEdgeFlvUpstream(std::string schema)
hr_ = NULL;
reader_ = NULL;
decoder_ = NULL;
+ req_ = NULL;
}
SrsEdgeFlvUpstream::~SrsEdgeFlvUpstream()
@@ -191,12 +192,24 @@ SrsEdgeFlvUpstream::~SrsEdgeFlvUpstream()
}
srs_error_t SrsEdgeFlvUpstream::connect(SrsRequest* r, SrsLbRoundRobin* lb)
+{
+ // Because we might modify the r, which cause retry fail, so we must copy it.
+ SrsRequest* cp = r->copy();
+
+ // Free the request when close upstream.
+ srs_freep(req_);
+ req_ = cp;
+
+ return do_connect(cp, lb, 0);
+}
+
+srs_error_t SrsEdgeFlvUpstream::do_connect(SrsRequest* r, SrsLbRoundRobin* lb, int redirect_depth)
{
srs_error_t err = srs_success;
SrsRequest* req = r;
- if (true) {
+ if (redirect_depth == 0) {
SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(req->vhost);
// @see https://github.com/ossrs/srs/issues/79
@@ -217,12 +230,20 @@ srs_error_t SrsEdgeFlvUpstream::connect(SrsRequest* r, SrsLbRoundRobin* lb)
// Remember the current selected server.
selected_ip = server;
selected_port = port;
+ } else {
+ // If HTTP redirect, use the server in location.
+ schema_ = req->schema;
+ selected_ip = req->host;
+ selected_port = req->port;
}
srs_freep(sdk_);
sdk_ = new SrsHttpClient();
- string path = "/" + req->app + "/" + req->stream + ".flv";
+ string path = "/" + req->app + "/" + req->stream;
+ if (!srs_string_ends_with(req->stream, ".flv")) {
+ path += ".flv";
+ }
if (!req->param.empty()) {
path += req->param;
}
@@ -240,6 +261,37 @@ srs_error_t SrsEdgeFlvUpstream::connect(SrsRequest* r, SrsLbRoundRobin* lb)
return srs_error_wrap(err, "edge get %s failed, path=%s", url.c_str(), path.c_str());
}
+ if (hr_->status_code() == 404) {
+ return srs_error_new(ERROR_RTMP_STREAM_NOT_FOUND, "Connect to %s, status=%d", url.c_str(), hr_->status_code());
+ }
+
+ string location;
+ if (hr_->status_code() == 302) {
+ location = hr_->header()->get("Location");
+ }
+ srs_trace("Edge: Connect to %s ok, status=%d, location=%s", url.c_str(), hr_->status_code(), location.c_str());
+
+ if (hr_->status_code() == 302) {
+ if (redirect_depth >= 3) {
+ return srs_error_new(ERROR_HTTP_302_INVALID, "redirect to %s fail, depth=%d", location.c_str(), redirect_depth);
+ }
+
+ string app;
+ string stream_name;
+ if (true) {
+ string tcUrl;
+ srs_parse_rtmp_url(location, tcUrl, stream_name);
+
+ int port;
+ string schema, host, vhost, param;
+ srs_discovery_tc_url(tcUrl, schema, host, vhost, app, stream_name, port, param);
+
+ r->schema = schema; r->host = host; r->port = port;
+ r->app = app; r->stream = stream_name; r->param = param;
+ }
+ return do_connect(r, lb, redirect_depth + 1);
+ }
+
srs_freep(reader_);
reader_ = new SrsHttpFileReader(hr_->body_reader());
@@ -330,6 +382,7 @@ void SrsEdgeFlvUpstream::close()
srs_freep(hr_);
srs_freep(reader_);
srs_freep(decoder_);
+ srs_freep(req_);
}
void SrsEdgeFlvUpstream::selected(string& server, int& port)
@@ -446,8 +499,17 @@ srs_error_t SrsEdgeIngester::do_cycle()
return srs_error_wrap(err, "do cycle pull");
}
- srs_freep(upstream);
+ // Use protocol in config.
string edge_protocol = _srs_config->get_vhost_edge_protocol(req->vhost);
+
+ // If follow client protocol, change to protocol of client.
+ bool follow_client = _srs_config->get_vhost_edge_follow_client(req->vhost);
+ if (follow_client && !req->protocol.empty()) {
+ edge_protocol = req->protocol;
+ }
+
+ // Create object by protocol.
+ srs_freep(upstream);
if (edge_protocol == "flv" || edge_protocol == "flvs") {
upstream = new SrsEdgeFlvUpstream(edge_protocol == "flv"? "http" : "https");
} else {
diff --git a/trunk/src/app/srs_app_edge.hpp b/trunk/src/app/srs_app_edge.hpp
index 80d9a1b31..6c50814d2 100644
--- a/trunk/src/app/srs_app_edge.hpp
+++ b/trunk/src/app/srs_app_edge.hpp
@@ -127,6 +127,8 @@ private:
SrsHttpFileReader* reader_;
SrsFlvDecoder* decoder_;
private:
+ // We might modify the request by HTTP redirect.
+ SrsRequest* req_;
// Current selected server, the ip:port.
std::string selected_ip;
int selected_port;
@@ -135,6 +137,9 @@ public:
virtual ~SrsEdgeFlvUpstream();
public:
virtual srs_error_t connect(SrsRequest* r, SrsLbRoundRobin* lb);
+private:
+ virtual srs_error_t do_connect(SrsRequest* r, SrsLbRoundRobin* lb, int redirect_depth);
+public:
virtual srs_error_t recv_message(SrsCommonMessage** pmsg);
virtual srs_error_t decode_message(SrsCommonMessage* msg, SrsPacket** ppacket);
virtual void close();
diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp
index e6afab909..65fb9b421 100644
--- a/trunk/src/app/srs_app_rtc_conn.cpp
+++ b/trunk/src/app/srs_app_rtc_conn.cpp
@@ -1327,12 +1327,7 @@ srs_error_t SrsRtcPublishStream::send_periodic_twcc()
return srs_error_wrap(err, "encode, count=%u", twcc_fb_count_);
}
- int nb_protected_buf = buffer->pos();
- if ((err = session_->transport_->protect_rtcp(pkt, &nb_protected_buf)) != srs_success) {
- return srs_error_wrap(err, "protect rtcp, size=%u", nb_protected_buf);
- }
-
- return session_->sendonly_skt->sendto(pkt, nb_protected_buf, 0);
+ return session_->send_rtcp(pkt, buffer->pos());
}
srs_error_t SrsRtcPublishStream::on_rtcp(SrsRtcpCommon* rtcp)
@@ -2366,17 +2361,11 @@ void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ss
rtcpNack.encode(&stream);
// TODO: FIXME: Check error.
- int nb_protected_buf = stream.pos();
- transport_->protect_rtcp(stream.data(), &nb_protected_buf);
-
- // TODO: FIXME: Check error.
- sendonly_skt->sendto(stream.data(), nb_protected_buf, 0);
+ send_rtcp(stream.data(), stream.pos());
}
srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_queue, const uint64_t& last_send_systime, const SrsNtp& last_send_ntp)
{
- srs_error_t err = srs_success;
-
++_srs_pps_srtcps->sugar;
// @see https://tools.ietf.org/html/rfc3550#section-6.4.2
@@ -2412,18 +2401,11 @@ srs_error_t SrsRtcConnection::send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer* rtp_
srs_info("RR ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, extended_highest_sequence=%u, interarrival_jitter=%u",
ssrc, fraction_lost, cumulative_number_of_packets_lost, extended_highest_sequence, interarrival_jitter);
- int nb_protected_buf = stream.pos();
- if ((err = transport_->protect_rtcp(stream.data(), &nb_protected_buf)) != srs_success) {
- return srs_error_wrap(err, "protect rtcp rr");
- }
-
- return sendonly_skt->sendto(stream.data(), nb_protected_buf, 0);
+ return send_rtcp(stream.data(), stream.pos());
}
srs_error_t SrsRtcConnection::send_rtcp_xr_rrtr(uint32_t ssrc)
{
- srs_error_t err = srs_success;
-
++_srs_pps_srtcps->sugar;
/*
@@ -2466,18 +2448,11 @@ srs_error_t SrsRtcConnection::send_rtcp_xr_rrtr(uint32_t ssrc)
stream.write_4bytes(cur_ntp.ntp_second_);
stream.write_4bytes(cur_ntp.ntp_fractions_);
- int nb_protected_buf = stream.pos();
- if ((err = transport_->protect_rtcp(stream.data(), &nb_protected_buf)) != srs_success) {
- return srs_error_wrap(err, "protect rtcp xr");
- }
-
- return sendonly_skt->sendto(stream.data(), nb_protected_buf, 0);
+ return send_rtcp(stream.data(), stream.pos());
}
srs_error_t SrsRtcConnection::send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId& cid_of_subscriber)
{
- srs_error_t err = srs_success;
-
++_srs_pps_srtcps->sugar;
char buf[kRtpPacketSize];
@@ -2498,12 +2473,7 @@ srs_error_t SrsRtcConnection::send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId
_srs_blackhole->sendto(stream.data(), stream.pos());
}
- int nb_protected_buf = stream.pos();
- if ((err = transport_->protect_rtcp(stream.data(), &nb_protected_buf)) != srs_success) {
- return srs_error_wrap(err, "protect rtcp psfb pli");
- }
-
- return sendonly_skt->sendto(stream.data(), nb_protected_buf, 0);
+ return send_rtcp(stream.data(), stream.pos());
}
void SrsRtcConnection::simulate_nack_drop(int nn)
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index 0fbe07c39..af46019db 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -25,10 +25,7 @@
#define SRS_CORE_HPP
// The version config.
-#define VERSION_MAJOR 4
-#define VERSION_MINOR 0
-#include
-#define VERSION_REVISION SRS_VERSION4_REVISION
+#include
// The macros generated by configure script.
#include
diff --git a/trunk/src/core/srs_core_version3.hpp b/trunk/src/core/srs_core_version3.hpp
index b4c8f7273..dae57fe2f 100644
--- a/trunk/src/core/srs_core_version3.hpp
+++ b/trunk/src/core/srs_core_version3.hpp
@@ -24,6 +24,8 @@
#ifndef SRS_CORE_VERSION3_HPP
#define SRS_CORE_VERSION3_HPP
+#define VERSION_MAJOR 3
+#define VERSION_MINOR 0
#define SRS_VERSION3_REVISION 158
#endif
diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp
index ddca1c39d..0e7f31831 100644
--- a/trunk/src/core/srs_core_version4.hpp
+++ b/trunk/src/core/srs_core_version4.hpp
@@ -24,6 +24,8 @@
#ifndef SRS_CORE_VERSION4_HPP
#define SRS_CORE_VERSION4_HPP
+#define VERSION_MAJOR 4
+#define VERSION_MINOR 0
#define SRS_VERSION4_REVISION 85
#endif
diff --git a/trunk/src/core/srs_core_version5.cpp b/trunk/src/core/srs_core_version5.cpp
new file mode 100644
index 000000000..e5071d6ef
--- /dev/null
+++ b/trunk/src/core/srs_core_version5.cpp
@@ -0,0 +1,24 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2020 Winlin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include
diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp
new file mode 100644
index 000000000..7c598a58e
--- /dev/null
+++ b/trunk/src/core/srs_core_version5.hpp
@@ -0,0 +1,31 @@
+/**
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2020 Winlin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SRS_CORE_VERSION5_HPP
+#define SRS_CORE_VERSION5_HPP
+
+#define VERSION_MAJOR 5
+#define VERSION_MINOR 0
+#define VERSION_REVISION 1
+
+#endif
diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp
index ece4ef0bc..6b61aceb5 100644
--- a/trunk/src/protocol/srs_protocol_utility.cpp
+++ b/trunk/src/protocol/srs_protocol_utility.cpp
@@ -106,6 +106,10 @@ void srs_discovery_tc_url(string tcUrl, string& schema, string& host, string& vh
}
port = SRS_CONSTS_RTMP_DEFAULT_PORT;
+ if (schema == "https") {
+ port = SRS_DEFAULT_HTTPS_PORT;
+ }
+
if ((pos = host.find(":")) != std::string::npos) {
srs_parse_hostport(host, host, port);
srs_info("discovery host=%s, port=%d", host.c_str(), port);
diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp
index f80cf77cd..25c0b7acc 100644
--- a/trunk/src/protocol/srs_rtmp_stack.cpp
+++ b/trunk/src/protocol/srs_rtmp_stack.cpp
@@ -1578,6 +1578,8 @@ SrsRequest::SrsRequest()
duration = -1;
port = SRS_CONSTS_RTMP_DEFAULT_PORT;
args = NULL;
+
+ protocol = "rtmp";
}
SrsRequest::~SrsRequest()
@@ -1605,6 +1607,8 @@ SrsRequest* SrsRequest::copy()
if (args) {
cp->args = args->copy()->to_object();
}
+
+ cp->protocol = protocol;
return cp;
}
@@ -1632,6 +1636,8 @@ void SrsRequest::update_auth(SrsRequest* req)
if (req->args) {
args = req->args->copy()->to_object();
}
+
+ protocol = req->protocol;
srs_info("update req of soruce for auth ok");
}
diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp
index 6f311383f..2f4741fe2 100644
--- a/trunk/src/protocol/srs_rtmp_stack.hpp
+++ b/trunk/src/protocol/srs_rtmp_stack.hpp
@@ -489,6 +489,12 @@ public:
public:
// Transform it as HTTP request.
virtual SrsRequest* as_http();
+public:
+ // The protocol of client:
+ // rtmp, Adobe RTMP protocol.
+ // flv, HTTP-FLV protocol.
+ // flvs, HTTPS-FLV protocol.
+ std::string protocol;
};
// The response to client.
diff --git a/trunk/src/protocol/srs_service_http_conn.cpp b/trunk/src/protocol/srs_service_http_conn.cpp
index d239972b2..49b3defdd 100644
--- a/trunk/src/protocol/srs_service_http_conn.cpp
+++ b/trunk/src/protocol/srs_service_http_conn.cpp
@@ -680,6 +680,9 @@ SrsRequest* SrsHttpMessage::to_request(string vhost)
if (!oip.empty()) {
req->ip = oip;
}
+
+ // The request streaming protocol.
+ req->protocol = (schema_ == "http")? "flv" : "flvs";
return req;
}