From 21835c38b7f418d56eee78b1260dcc3eebdcb531 Mon Sep 17 00:00:00 2001 From: winlin <winlin@vip.126.com> Date: Sat, 25 Jul 2020 09:33:18 +0800 Subject: [PATCH] RTC: Support multiple address for client. 4.0.36 --- README.md | 1 + trunk/src/app/srs_app_rtc_api.cpp | 3 +- trunk/src/app/srs_app_rtc_conn.cpp | 95 ++++++++++++++++++---------- trunk/src/app/srs_app_rtc_conn.hpp | 16 +++-- trunk/src/app/srs_app_rtc_server.cpp | 28 ++++---- trunk/src/app/srs_app_rtc_server.hpp | 2 +- trunk/src/core/srs_core_version4.hpp | 2 +- 7 files changed, 87 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 1075f7b02..a8ceb58ca 100755 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ For previous versions, please read: ## V4 changes +* v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36 * v4.0, 2020-07-11, Refine log context with random string. 4.0.35 * v4.0, 2020-07-04, Fix some bugs for RTC. 4.0.34 * v4.0, 2020-07-03, Merge [#1830][bug #1830] to fix bugs in GB28181. 4.0.33 diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index c2ff32a96..3a5791cb2 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -808,8 +808,7 @@ srs_error_t SrsGoApiRtcNACK::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe session->simulate_nack_drop(drop); - srs_trace("RTC NACK session peer_id=%s, username=%s, drop=%s/%d", session->peer_id().c_str(), - username.c_str(), dropv.c_str(), drop); + srs_trace("RTC: NACK session username=%s, drop=%s/%d", username.c_str(), dropv.c_str(), drop); return srs_success; } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c737bf774..da29fceeb 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -113,7 +113,8 @@ srs_error_t SrsSecurityTransport::on_dtls_handshake_done() return err; } - srs_trace("RTC session=%s, DTLS handshake done.", session_->id().c_str()); + // TODO: FIXME: Add cost for DTLS. + srs_trace("RTC: DTLS handshake done."); handshake_done = true; if ((err = srtp_initialize()) != srs_success) { @@ -366,13 +367,13 @@ srs_error_t SrsRtcPlayStream::cycle() realtime = _srs_config->get_realtime_enabled(req->vhost, true); mw_msgs = _srs_config->get_mw_msgs(req->vhost, realtime, true); - srs_trace("RTC source url=%s, source_id=[%d][%s], encrypt=%d, realtime=%d, mw_msgs=%d", req->get_stream_url().c_str(), + // TODO: FIXME: Add cost in ms. + srs_trace("RTC: start play, url=%s, source_id=[%d][%s], encrypt=%d, realtime=%d, mw_msgs=%d", req->get_stream_url().c_str(), ::getpid(), source->source_id().c_str(), session_->encrypt, realtime, mw_msgs); SrsPithyPrint* pprint = SrsPithyPrint::create_rtc_play(); SrsAutoFree(SrsPithyPrint, pprint); - srs_trace("RTC session=%s, start play", session_->id().c_str()); bool stat_enabled = _srs_config->get_rtc_server_perf_stat(); SrsStatistic* stat = SrsStatistic::instance(); @@ -1582,8 +1583,15 @@ SrsRtcConnection::~SrsRtcConnection() srs_freep(publisher_); srs_freep(transport_); srs_freep(req); - srs_freep(sendonly_skt); srs_freep(stat_); + + // Note that we should never delete the sendonly_skt, + // it's just point to the object in peer_addresses_. + map<string, SrsUdpMuxSocket*>::iterator it; + for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) { + SrsUdpMuxSocket* addr = it->second; + srs_freep(addr); + } } SrsSdp* SrsRtcConnection::get_local_sdp() @@ -1616,20 +1624,22 @@ void SrsRtcConnection::set_state(SrsRtcConnectionStateType state) state_ = state; } -string SrsRtcConnection::id() +string SrsRtcConnection::username() { - return peer_id_ + "/" + username_; + return username_; } - -string SrsRtcConnection::peer_id() +vector<SrsUdpMuxSocket*> SrsRtcConnection::peer_addresses() { - return peer_id_; -} + vector<SrsUdpMuxSocket*> addresses; -string SrsRtcConnection::username() -{ - return username_; + map<string, SrsUdpMuxSocket*>::iterator it; + for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) { + SrsUdpMuxSocket* addr = it->second; + addresses.push_back(addr); + } + + return addresses; } void SrsRtcConnection::set_encrypt(bool v) @@ -1774,8 +1784,8 @@ srs_error_t SrsRtcConnection::initialize(SrsRtcStream* source, SrsRequest* r, bo session_timeout = _srs_config->get_rtc_stun_timeout(req->vhost); last_stun_time = srs_get_system_time(); - srs_trace("RTC init session, DTLS(role=%s, version=%s), timeout=%dms", - cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(session_timeout)); + srs_trace("RTC init session, user=%s, url=%s, DTLS(role=%s, version=%s), timeout=%dms", username.c_str(), + r->get_stream_url().c_str(), cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(session_timeout)); return err; } @@ -1792,9 +1802,7 @@ srs_error_t SrsRtcConnection::on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r) // We are running in the ice-lite(server) mode. If client have multi network interface, // we only choose one candidate pair which is determined by client. - if (!sendonly_skt || sendonly_skt->peer_id() != skt->peer_id()) { - update_sendonly_socket(skt); - } + update_sendonly_socket(skt); // Write STUN messages to blackhole. if (_srs_blackhole->blackhole) { @@ -1865,8 +1873,8 @@ srs_error_t SrsRtcConnection::on_connection_established() { srs_error_t err = srs_success; - srs_trace("RTC %s session=%s, to=%dms connection established", (is_publisher_? "Publisher":"Subscriber"), - id().c_str(), srsu2msi(session_timeout)); + srs_trace("RTC: session %s, to=%dms connection established", (is_publisher_? "Publisher":"Subscriber"), + srsu2msi(session_timeout)); if (is_publisher_) { if ((err = start_publish()) != srs_success) { @@ -1908,28 +1916,44 @@ bool SrsRtcConnection::is_stun_timeout() return last_stun_time + session_timeout < srs_get_system_time(); } -// TODO: FIXME: We should support multiple addresses, because client may use more than one addresses. void SrsRtcConnection::update_sendonly_socket(SrsUdpMuxSocket* skt) { - std::string old_peer_id; + // TODO: FIXME: Refine performance. + string prev_peer_id, peer_id = skt->peer_id(); if (sendonly_skt) { - srs_trace("session %s address changed, update %s -> %s", - id().c_str(), sendonly_skt->peer_id().c_str(), skt->peer_id().c_str()); - old_peer_id = sendonly_skt->peer_id(); + prev_peer_id = sendonly_skt->peer_id(); } - // Update the transport. - srs_freep(sendonly_skt); - sendonly_skt = skt->copy_sendonly(); + // Ignore if same address. + if (prev_peer_id == peer_id) { + return; + } - // Update the sessions to handle packets from the new address. - peer_id_ = sendonly_skt->peer_id(); - server_->insert_into_id_sessions(peer_id_, this); + // Detect address change. + if (prev_peer_id.empty()) { + srs_trace("RTC: session address init %s", peer_id.c_str()); + } else { + srs_trace("RTC: session address changed, update %s -> %s, total %u", prev_peer_id.c_str(), + peer_id.c_str(), peer_addresses_.size()); + } - // Remove the old address. - if (!old_peer_id.empty()) { - server_->remove_id_sessions(old_peer_id); + // Find object from cache. + SrsUdpMuxSocket* addr_cache = NULL; + if (true) { + map<string, SrsUdpMuxSocket*>::iterator it = peer_addresses_.find(peer_id); + if (it != peer_addresses_.end()) { + addr_cache = it->second; + } + } + + // If no cache, build cache and setup the relations in connection. + if (!addr_cache) { + peer_addresses_[peer_id] = addr_cache = skt->copy_sendonly(); + server_->insert_into_id_sessions(peer_id, this); } + + // Update the transport. + sendonly_skt = addr_cache; } void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ssrc) @@ -2248,7 +2272,8 @@ srs_error_t SrsRtcConnection::on_binding_request(SrsStunPacket* r) if (state_ == WAITING_STUN) { state_ = DOING_DTLS_HANDSHAKE; - srs_trace("RTC session=%s, STUN done, waiting DTLS handshake.", id().c_str()); + // TODO: FIXME: Add cost. + srs_trace("RTC: session STUN done, waiting DTLS handshake."); if((err = transport_->start_active_handshake()) != srs_success) { return srs_error_wrap(err, "fail to dtls handshake"); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index a7e4726af..d3a2c127d 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -323,9 +323,12 @@ private: SrsRtcPublishStream* publisher_; bool is_publisher_; private: - SrsUdpMuxSocket* sendonly_skt; + // The local:remote username, such as m5x0n128:jvOm where local name is m5x0n128. std::string username_; - std::string peer_id_; + // The peer address, client maybe use more than one address, it's the current selected one. + SrsUdpMuxSocket* sendonly_skt; + // The address list, client may use multiple addresses. + std::map<std::string, SrsUdpMuxSocket*> peer_addresses_; private: // The timeout of session, keep alive by STUN ping pong. srs_utime_t session_timeout; @@ -343,6 +346,7 @@ private: SrsSdp remote_sdp; SrsSdp local_sdp; public: + // TODO: FIXME: Remove dead code. // User debugging parameters, overwrite config. std::string sequence_startup; std::string sequence_delta; @@ -364,12 +368,10 @@ public: // Connection level state machine, for ARQ of UDP packets. SrsRtcConnectionStateType state(); void set_state(SrsRtcConnectionStateType state); - // TODO: FIXME: Rename it. - std::string id(); - // TODO: FIXME: Rename it. - std::string peer_id(); - // TODO: FIXME: Rename it. + // Get username pair for this connection, used as ID of session. std::string username(); + // Get all addresses client used. + std::vector<SrsUdpMuxSocket*> peer_addresses(); public: void set_encrypt(bool v); void switch_to_context(); diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index ce8412367..e2b101636 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -542,17 +542,20 @@ void SrsRtcServer::destroy(SrsRtcConnection* session) std::map<std::string, SrsRtcConnection*>::iterator it; - if ((it = map_username_session.find(session->username())) != map_username_session.end()) { + string username = session->username(); + if ((it = map_username_session.find(username)) != map_username_session.end()) { map_username_session.erase(it); } - if ((it = map_id_session.find(session->peer_id())) != map_id_session.end()) { - map_id_session.erase(it); + vector<SrsUdpMuxSocket*> addresses = session->peer_addresses(); + for (int i = 0; i < (int)addresses.size(); i++) { + SrsUdpMuxSocket* addr = addresses.at(i); + map_id_session.erase(addr->peer_id()); } SrsContextRestore(_srs_context->get_id()); session->switch_to_context(); - srs_trace("RTC session=%s, destroy, summary: %s", session->id().c_str(), session->stat_->summary().c_str()); + srs_trace("RTC: session destroy, username=%s, summary: %s", username.c_str(), session->stat_->summary().c_str()); zombies_.push_back(session); } @@ -562,14 +565,6 @@ bool SrsRtcServer::insert_into_id_sessions(const string& peer_id, SrsRtcConnecti return map_id_session.insert(make_pair(peer_id, session)).second; } -void SrsRtcServer::remove_id_sessions(const string& peer_id) -{ - std::map<std::string, SrsRtcConnection*>::iterator it; - if ((it = map_id_session.find(peer_id)) != map_id_session.end()) { - map_id_session.erase(it); - } -} - void SrsRtcServer::check_and_clean_timeout_session() { map<string, SrsRtcConnection*>::iterator iter = map_username_session.begin(); @@ -585,14 +580,19 @@ void SrsRtcServer::check_and_clean_timeout_session() // Now, we got the RTC session to cleanup, switch to its context // to make all logs write to the "correct" pid+cid. session->switch_to_context(); - srs_trace("RTC session=%s, STUN timeout, summary: %s", session->id().c_str(), session->stat_->summary().c_str()); + srs_trace("RTC: session STUN timeout, summary: %s", session->stat_->summary().c_str()); session->disposing_ = true; zombies_.push_back(session); // Use C++98 style: https://stackoverflow.com/a/4636230 map_username_session.erase(iter++); - map_id_session.erase(session->peer_id()); + + vector<SrsUdpMuxSocket*> addresses = session->peer_addresses(); + for (int i = 0; i < (int)addresses.size(); i++) { + SrsUdpMuxSocket* addr = addresses.at(i); + map_id_session.erase(addr->peer_id()); + } if (handler) { handler->on_timeout(session); diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 3a878aa7e..f44428023 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -118,7 +118,7 @@ public: void destroy(SrsRtcConnection* session); public: bool insert_into_id_sessions(const std::string& peer_id, SrsRtcConnection* session); - void remove_id_sessions(const std::string& peer_id); + // TODO: FIXME: Change to private. void check_and_clean_timeout_session(); int nn_sessions(); SrsRtcConnection* find_session_by_username(const std::string& ufrag); diff --git a/trunk/src/core/srs_core_version4.hpp b/trunk/src/core/srs_core_version4.hpp index 0ca8ba1f3..035cfb349 100644 --- a/trunk/src/core/srs_core_version4.hpp +++ b/trunk/src/core/srs_core_version4.hpp @@ -24,6 +24,6 @@ #ifndef SRS_CORE_VERSION4_HPP #define SRS_CORE_VERSION4_HPP -#define SRS_VERSION4_REVISION 35 +#define SRS_VERSION4_REVISION 36 #endif