diff --git a/README.md b/README.md
index 6871c2d78..d5a9f81de 100755
--- a/README.md
+++ b/README.md
@@ -12,16 +12,8 @@ Download binaries from github.io: [Centos6-x86_64][centos0], [more...][more0]
About the wiki of SRS/3.0, please read [Chinese][srs_CN] or [English][srs_EN].
-> Remark: SRS3 hasn't been released and it's really unstable, please use stable branches such as [SRS2](https://github.com/ossrs/srs/tree/2.0release) or [SRS1](https://github.com/ossrs/srs/tree/1.0release) instead, unless you can fix bugs and debug it.
-
> Remark: Although SRS is licenced under [MIT][LICENSE], but there are some depended libraries which are distributed using their own licenses, please read [License Mixing][LicenseMixing].
-> Remark: About the milestone and product plan, please read ([CN][v1_CN_Product], [EN][v1_EN_Product]) wiki.
-
-> Remark: The origin-edge cluster is released, while the origin-origin cluster is coming soon.
-
-> Remark: We are working on utest now.
-
Enjoy it!
## Content
@@ -89,6 +81,7 @@ cd srs/trunk
* Usage: How to delivery HLS by embeded HTTP server?([CN][v3_CN_SampleHTTP], [EN][v3_EN_SampleHTTP])
* Usage: How to run the demostration of SRS? ([CN][v1_CN_SampleDemo], [EN][v1_EN_SampleDemo])
* Usage: How to publish h.264 raw stream as RTMP? ([CN][v3_CN_SrsLibrtmp2], [EN][v3_EN_SrsLibrtmp2])
+* Usage: How to improve edge performance by multiple CPUs? ([CN][v3_CN_REUSEPORT], [EN][v3_EN_REUSEPORT])
* Usage: Who are using SRS?([CN][v1_CN_Sample])
* Usage: Why choose SRS? About the milestone and product plan? ([CN][v1_CN_Product], [EN][v1_EN_Product])
@@ -148,6 +141,7 @@ Please select according to languages:
- [x] Enhanced RTMP url which supports vhost in stream, read [#1059][bug #1059].
- [x] Support origin cluster, please read [#464][bug #464], [RTMP 302][bug #92].
- [x] Support listen at IPv4 and IPv6, read [#460][bug #460].
+- [x] Support SO_REUSEPORT, to improve edge server performance, read [#775][bug #775].
- [ ] Utest cover almost all kernel code.
- [ ] Enhanced forwarding with vhost and variables.
- [ ] Support source cleanup for idle streams.
@@ -166,6 +160,8 @@ Please select according to languages:
### V3 changes
+* v3.0, 2019-10-04, Support go-oryx rtmplb with [proxy protocol](https://github.com/ossrs/go-oryx/wiki/RtmpProxy). 3.0.56
+* v3.0, 2019-10-03, Fix [#775][bug #775], Support SO_REUSEPORT to improve edge performance. 3.0.54
* v3.0, 2019-10-03, Remove KAFKA. 3.0.53
* v3.0, 2019-05-14, Covert Kernel File reader/writer. 3.0.52
* v3.0, 2019-04-30, Refine typo in files. 3.0.51
@@ -784,7 +780,7 @@ The performance benchmark data and corelative commits are listed here.
* See also: [Performance for x86/x64 Test Guide][v1_CN_Performance].
* See also: [Performance for RaspberryPi][v1_CN_RaspberryPi].
-* For multiple processes performance, read [go-oryx][oryx].
+* For multiple processes performance, read [#775: REUSEPORT][bug #775] or OriginCluster([CN](v3_EN_OriginCluster)/[EN](v3_EN_OriginCluster)) or [go-oryx][oryx].
#### Play RTMP benchmark
@@ -1100,8 +1096,12 @@ Winlin
[v3_EN_SampleHTTP]: https://github.com/ossrs/srs/wiki/v3_EN_SampleHTTP
[v1_CN_SampleDemo]: https://github.com/ossrs/srs/wiki/v1_CN_SampleDemo
[v1_EN_SampleDemo]: https://github.com/ossrs/srs/wiki/v1_EN_SampleDemo
+[v3_CN_OriginCluster]: https://github.com/ossrs/srs/wiki/v3_CN_OriginCluster
+[v3_EN_OriginCluster]: https://github.com/ossrs/srs/wiki/v3_EN_OriginCluster
[v3_CN_SrsLibrtmp2]: https://github.com/ossrs/srs/wiki/v3_CN_SrsLibrtmp#publish-h264-raw-data
[v3_EN_SrsLibrtmp2]: https://github.com/ossrs/srs/wiki/v3_EN_SrsLibrtmp#publish-h264-raw-data
+[v3_CN_REUSEPORT]: https://github.com/ossrs/srs/wiki/v3_CN_REUSEPORT
+[v3_EN_REUSEPORT]: https://github.com/ossrs/srs/wiki/v3_EN_REUSEPORT
[v1_CN_Sample]: https://github.com/ossrs/srs/wiki/v1_CN_Sample
[v1_EN_Sample]: https://github.com/ossrs/srs/wiki/v1_EN_Sample
[v1_CN_Product]: https://github.com/ossrs/srs/wiki/v1_CN_Product
@@ -1476,6 +1476,7 @@ Winlin
[bug #821]: https://github.com/ossrs/srs/issues/821
[bug #913]: https://github.com/ossrs/srs/issues/913
[bug #460]: https://github.com/ossrs/srs/issues/460
+[bug #775]: https://github.com/ossrs/srs/issues/775
[bug #1057]: https://github.com/ossrs/srs/issues/1057
[bug #105]: https://github.com/ossrs/srs/issues/105
[bug #727]: https://github.com/ossrs/srs/issues/727
diff --git a/trunk/conf/edge2.conf b/trunk/conf/edge2.conf
new file mode 100644
index 000000000..193238d88
--- /dev/null
+++ b/trunk/conf/edge2.conf
@@ -0,0 +1,15 @@
+# the config for srs origin-edge cluster
+# @see https://github.com/ossrs/srs/wiki/v1_CN_Edge
+# @see full.conf for detail config.
+
+listen 1935;
+max_connections 1000;
+pid objs/edge2.pid;
+daemon off;
+srs_log_tank console;
+vhost __defaultVhost__ {
+ cluster {
+ mode remote;
+ origin 127.0.0.1:19350;
+ }
+}
diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp
index 7437fe68c..45a396ae5 100644
--- a/trunk/src/app/srs_app_http_hooks.cpp
+++ b/trunk/src/app/srs_app_http_hooks.cpp
@@ -464,7 +464,7 @@ srs_error_t SrsHttpHooks::discover_co_workers(string url, string& host, int& por
}
port = (int)prop->to_integer();
- srs_trace("http: on_hls ok, url=%s, response=%s", url.c_str(), res.c_str());
+ srs_trace("http: cluster redirect %s:%d ok, url=%s, response=%s", host.c_str(), port, url.c_str(), res.c_str());
return err;
}
diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp
index 850e4a1cc..e1dabc1c3 100644
--- a/trunk/src/app/srs_app_rtmp_conn.cpp
+++ b/trunk/src/app/srs_app_rtmp_conn.cpp
@@ -159,6 +159,12 @@ srs_error_t SrsRtmpConn::do_cycle()
if ((err = rtmp->handshake()) != srs_success) {
return srs_error_wrap(err, "rtmp handshake");
}
+
+ uint32_t rip = rtmp->proxy_real_ip();
+ if (rip > 0) {
+ srs_trace("RTMP proxy real client ip=%d.%d.%d.%d",
+ uint8_t(rip>>24), uint8_t(rip>>16), uint8_t(rip>>8), uint8_t(rip));
+ }
SrsRequest* req = info->req;
if ((err = rtmp->connect_app(req)) != srs_success) {
@@ -608,7 +614,8 @@ srs_error_t SrsRtmpConn::playing(SrsSource* source)
if ((err = SrsHttpHooks::discover_co_workers(url, host, port)) != srs_success) {
return srs_error_wrap(err, "discover coworkers, url=%s", url.c_str());
}
- srs_trace("rtmp: redirect in cluster, url=%s, target=%s:%d", url.c_str(), host.c_str(), port);
+ srs_trace("rtmp: redirect in cluster, from=%s:%d, target=%s:%d, url=%s",
+ req->host.c_str(), req->port, host.c_str(), port, url.c_str());
bool accepted = false;
if ((err = rtmp->redirect(req, host, port, accepted)) != srs_success) {
diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp
index 9ea41f532..5f020c54b 100644
--- a/trunk/src/core/srs_core.hpp
+++ b/trunk/src/core/srs_core.hpp
@@ -27,7 +27,7 @@
// The version config.
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
-#define VERSION_REVISION 53
+#define VERSION_REVISION 56
// The macros generated by configure script.
#include
diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp
index 88672030f..a3e56e19f 100644
--- a/trunk/src/kernel/srs_kernel_error.hpp
+++ b/trunk/src/kernel/srs_kernel_error.hpp
@@ -176,6 +176,7 @@
#define ERROR_RTMP_STREAM_NAME_EMPTY 2051
#define ERROR_HTTP_HIJACK 2052
#define ERROR_RTMP_MESSAGE_CREATE 2053
+#define ERROR_RTMP_PROXY_EXCEED 2054
//
// The system control message,
// It's not an error, but special control logic.
diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp
index af2e0eab3..57a369dff 100644
--- a/trunk/src/protocol/srs_protocol_utility.cpp
+++ b/trunk/src/protocol/srs_protocol_utility.cpp
@@ -151,7 +151,6 @@ void srs_random_generate(char* bytes, int size)
if (!_random_initialized) {
srand(0);
_random_initialized = true;
- srs_trace("srand initialized the random.");
}
for (int i = 0; i < size; i++) {
diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp
index af9850a21..5d2387aef 100644
--- a/trunk/src/protocol/srs_rtmp_stack.cpp
+++ b/trunk/src/protocol/srs_rtmp_stack.cpp
@@ -1659,9 +1659,15 @@ bool srs_client_type_is_publish(SrsRtmpConnType type)
SrsHandshakeBytes::SrsHandshakeBytes()
{
c0c1 = s0s1s2 = c2 = NULL;
+ proxy_real_ip = 0;
}
SrsHandshakeBytes::~SrsHandshakeBytes()
+{
+ dispose();
+}
+
+void SrsHandshakeBytes::dispose()
{
srs_freepa(c0c1);
srs_freepa(s0s1s2);
@@ -1682,6 +1688,26 @@ srs_error_t SrsHandshakeBytes::read_c0c1(ISrsProtocolReadWriter* io)
if ((err = io->read_fully(c0c1, 1537, &nsize)) != srs_success) {
return srs_error_wrap(err, "read c0c1");
}
+
+ // Whether RTMP proxy, @see https://github.com/ossrs/go-oryx/wiki/RtmpProxy
+ if (uint8_t(c0c1[0]) == 0xF3) {
+ uint16_t nn = uint16_t(c0c1[1])<<8 | uint16_t(c0c1[2]);
+ ssize_t nn_consumed = 3 + nn;
+ if (nn > 1024) {
+ return srs_error_new(ERROR_RTMP_PROXY_EXCEED, "proxy exceed max size, nn=%d", nn);
+ }
+
+ // 4B client real IP.
+ if (nn >= 4) {
+ proxy_real_ip = uint32_t(c0c1[3])<<24 | uint32_t(c0c1[4])<<16 | uint32_t(c0c1[5])<<8 | uint32_t(c0c1[6]);
+ nn -= 4;
+ }
+
+ memmove(c0c1, c0c1 + nn_consumed, 1537 - nn_consumed);
+ if ((err = io->read_fully(c0c1 + 1537 - nn_consumed, nn_consumed, &nsize)) != srs_success) {
+ return srs_error_wrap(err, "read c0c1");
+ }
+ }
return err;
}
@@ -1888,7 +1914,7 @@ srs_error_t SrsRtmpClient::handshake()
}
}
- srs_freep(hs_bytes);
+ hs_bytes->dispose();
return err;
}
@@ -1904,7 +1930,7 @@ srs_error_t SrsRtmpClient::simple_handshake()
return srs_error_wrap(err, "simple handshake");
}
- srs_freep(hs_bytes);
+ hs_bytes->dispose();
return err;
}
@@ -1920,7 +1946,7 @@ srs_error_t SrsRtmpClient::complex_handshake()
return srs_error_wrap(err, "complex handshake");
}
- srs_freep(hs_bytes);
+ hs_bytes->dispose();
return err;
}
@@ -2193,6 +2219,11 @@ SrsRtmpServer::~SrsRtmpServer()
srs_freep(hs_bytes);
}
+uint32_t SrsRtmpServer::proxy_real_ip()
+{
+ return hs_bytes->proxy_real_ip;
+}
+
void SrsRtmpServer::set_auto_response(bool v)
{
protocol->set_auto_response(v);
@@ -2284,9 +2315,9 @@ srs_error_t SrsRtmpServer::handshake()
return srs_error_wrap(err, "complex handshake");
}
}
-
- srs_freep(hs_bytes);
-
+
+ hs_bytes->dispose();
+
return err;
}
diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp
index 0159485fa..db8dce3db 100644
--- a/trunk/src/protocol/srs_rtmp_stack.hpp
+++ b/trunk/src/protocol/srs_rtmp_stack.hpp
@@ -500,6 +500,8 @@ bool srs_client_type_is_publish(SrsRtmpConnType type);
class SrsHandshakeBytes
{
public:
+ // For RTMP proxy, the real IP.
+ uint32_t proxy_real_ip;
// [1+1536]
char* c0c1;
// [1+1536+1536]
@@ -509,6 +511,8 @@ public:
public:
SrsHandshakeBytes();
virtual ~SrsHandshakeBytes();
+public:
+ virtual void dispose();
public:
virtual srs_error_t read_c0c1(ISrsProtocolReadWriter* io);
virtual srs_error_t read_s0s1s2(ISrsProtocolReadWriter* io);
@@ -615,6 +619,10 @@ private:
public:
SrsRtmpServer(ISrsProtocolReadWriter* skt);
virtual ~SrsRtmpServer();
+public:
+ // For RTMP proxy, the real IP. 0 if no proxy.
+ // @doc https://github.com/ossrs/go-oryx/wiki/RtmpProxy
+ virtual uint32_t proxy_real_ip();
// Protocol methods proxy
public:
// Set the auto response message when recv for protocol stack.
diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp
index 7b595baaa..e4ffe2669 100644
--- a/trunk/src/service/srs_service_st.cpp
+++ b/trunk/src/service/srs_service_st.cpp
@@ -110,6 +110,16 @@ srs_error_t srs_fd_reuseaddr(int fd)
return srs_success;
}
+srs_error_t srs_fd_reuseport(int fd)
+{
+ int v = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(int)) == -1) {
+ return srs_error_new(ERROR_SOCKET_SETREUSEADDR, "SO_REUSEPORT fd=%v", fd);
+ }
+
+ return srs_success;
+}
+
srs_error_t srs_fd_keepalive(int fd)
{
#ifdef SO_KEEPALIVE
@@ -215,6 +225,11 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd)
return srs_error_wrap(err, "set reuseaddr fd=%d", fd);
}
+ if ((err = srs_fd_reuseport(fd)) != srs_success) {
+ ::close(fd);
+ return srs_error_wrap(err, "set reuseport fd=%d", fd);
+ }
+
if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) {
::close(fd);
return srs_error_new(ERROR_SOCKET_BIND, "bind fd=%d", fd);
@@ -269,6 +284,11 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd)
return srs_error_wrap(err, "set reuseaddr fd=%d", fd);
}
+ if ((err = srs_fd_reuseport(fd)) != srs_success) {
+ ::close(fd);
+ return srs_error_wrap(err, "set reuseport fd=%d", fd);
+ }
+
if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) {
::close(fd);
return srs_error_new(ERROR_SOCKET_BIND, "bind fd=%d", fd);
diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp
index 4bb02a5b5..2c8174ab2 100644
--- a/trunk/src/service/srs_service_st.hpp
+++ b/trunk/src/service/srs_service_st.hpp
@@ -49,6 +49,9 @@ extern srs_error_t srs_fd_closeexec(int fd);
// Set the SO_REUSEADDR of fd.
extern srs_error_t srs_fd_reuseaddr(int fd);
+// Set the SO_REUSEPORT of fd.
+extern srs_error_t srs_fd_reuseport(int fd);
+
// Set the SO_KEEPALIVE of fd.
extern srs_error_t srs_fd_keepalive(int fd);