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);