diff --git a/README.md b/README.md index 3b44ac7c6a2..dc62dccfcbe 100755 --- a/README.md +++ b/README.md @@ -29,10 +29,10 @@ or [Chinese](https://ossrs.net/lts/zh-cn/docs/v5/doc/getting-started). We highly ```bash docker run --rm -it -p 1935:1935 -p 1985:1985 -p 8080:8080 \ - -p 8000:8000/udp -p 10080:10080/udp ossrs/srs:5 + -p 8000:8000/udp -p 10080:10080/udp ossrs/srs:6 ``` -> Tips: If you're in China, use this image `registry.cn-hangzhou.aliyuncs.com/ossrs/srs:5` for faster speed. +> Tips: If you're in China, use this image `registry.cn-hangzhou.aliyuncs.com/ossrs/srs:6` for faster speed. Open [http://localhost:8080/](http://localhost:8080/) to verify, and then stream using the following [FFmpeg](https://ffmpeg.org/download.html) command: diff --git a/trunk/configure b/trunk/configure index 6bfc4c2faa7..b8cd215e4aa 100755 --- a/trunk/configure +++ b/trunk/configure @@ -250,7 +250,9 @@ MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_buffer" "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_io" "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" "srs_kernel_ps" "srs_kernel_stream" "srs_kernel_balance" "srs_kernel_mp4" "srs_kernel_file" - "srs_kernel_kbps" "srs_kernel_rtc_rtp" "srs_kernel_rtc_rtcp" "srs_kernel_packet") + "srs_kernel_kbps" "srs_kernel_rtc_rtp" "srs_kernel_rtc_rtcp" "srs_kernel_packet" + "srs_kernel_uuid" "srs_kernel_st" "srs_kernel_factory" "srs_kernel_hourglass" + "srs_kernel_pithy_print" "srs_kernel_rtc_queue" "srs_kernel_resource") KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . $SRS_WORKDIR/auto/modules.sh KERNEL_OBJS="${MODULE_OBJS[@]}" # @@ -260,7 +262,7 @@ MODULE_DEPENDS=("CORE" "KERNEL") ModuleLibIncs=(${SRS_OBJS} ${LibSTRoot} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_protocol_conn" "srs_protocol_rtmp_handshake" "srs_protocol_rtmp_stack" "srs_protocol_utility" "srs_protocol_rtmp_msg_array" "srs_protocol_stream" - "srs_protocol_raw_avc" "srs_protocol_http_stack" "srs_protocol_kbps" "srs_protocol_json" + "srs_protocol_raw_avc" "srs_protocol_http_stack" "srs_protocol_json" "srs_protocol_format" "srs_protocol_log" "srs_protocol_st" "srs_protocol_http_client" "srs_protocol_http_conn" "srs_protocol_rtmp_conn" "srs_protocol_protobuf" "srs_protocol_http_stack_llhttp" "srs_protocol_http_stack_llhttpapi" @@ -268,7 +270,7 @@ MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_protocol_conn" "srs_pro # Always include SRT protocol MODULE_FILES+=("srs_protocol_srt") ModuleLibIncs+=(${LibSRTRoot}) -MODULE_FILES+=("srs_protocol_rtc_stun" "srs_protocol_rtp") +MODULE_FILES+=("srs_protocol_rtc_stun" "srs_protocol_rtp" "srs_protocol_sdp") if [[ $SRS_RTSP == YES ]]; then MODULE_FILES+=("srs_protocol_rtsp_stack") fi @@ -286,22 +288,22 @@ fi if [[ $SRS_FFMPEG_FIT == YES ]]; then ModuleLibIncs+=("${LibFfmpegRoot[*]}") fi -MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" +MODULE_FILES=("srs_app_server" "srs_app_rtmp_conn" "srs_app_rtmp_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_st" "srs_app_log" "srs_app_config" "srs_app_stream_bridge" - "srs_app_pithy_print" "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks" + "srs_app_reload" "srs_app_http_api" "srs_app_http_conn" "srs_app_http_hooks" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" - "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" + "srs_app_heartbeat" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" "srs_app_mpegts_udp" "srs_app_listener" "srs_app_async_call" - "srs_app_caster_flv" "srs_app_latest_version" "srs_app_uuid" "srs_app_process" "srs_app_ng_exec" - "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" - "srs_app_coworkers" "srs_app_circuit_breaker" + "srs_app_caster_flv" "srs_app_latest_version" "srs_app_process" "srs_app_ng_exec" + "srs_app_dash" "srs_app_fragment" "srs_app_dvr" + "srs_app_coworkers" "srs_app_circuit_breaker" "srs_app_factory" "srs_app_stream_token") # Always include SRT app modules -MODULE_FILES+=("srs_app_srt_server" "srs_app_srt_listener" "srs_app_srt_conn" "srs_app_srt_utility" "srs_app_srt_source") -MODULE_FILES+=("srs_app_rtc_conn" "srs_app_rtc_dtls" "srs_app_rtc_sdp" "srs_app_rtc_network" - "srs_app_rtc_queue" "srs_app_rtc_server" "srs_app_rtc_source" "srs_app_rtc_api") +MODULE_FILES+=("srs_app_srt_server" "srs_app_srt_listener" "srs_app_srt_conn" "srs_app_srt_source") +MODULE_FILES+=("srs_app_rtc_conn" "srs_app_rtc_dtls" "srs_app_rtc_network" + "srs_app_rtc_server" "srs_app_rtc_source" "srs_app_rtc_api") if [[ $SRS_RTSP == YES ]]; then MODULE_FILES+=("srs_app_rtsp_source" "srs_app_rtsp_conn") fi diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 2f08bca9ed4..83a79afd28a 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 7.0 Changelog +* v7.0, 2025-09-13, Merge [#4486](https://github.com/ossrs/srs/pull/4486): Move some app files to kernel. v7.0.86 (#4486) * v7.0, 2025-09-12, Merge [#4485](https://github.com/ossrs/srs/pull/4485): AI: Fix naming problem for app module. v7.0.85 (#4485) * v7.0, 2025-09-09, Merge [#4446](https://github.com/ossrs/srs/pull/4446): SRT2RTMP: fix srt bridge hevc to rtmp error. v7.0.84 (#4446) * v7.0, 2025-09-09, Merge [#4482](https://github.com/ossrs/srs/pull/4482): AI: Fix naming issue for protocol module. v7.0.83 (#4482) diff --git a/trunk/src/app/srs_app_async_call.hpp b/trunk/src/app/srs_app_async_call.hpp index 602632cc231..7f6c04fae3f 100644 --- a/trunk/src/app/srs_app_async_call.hpp +++ b/trunk/src/app/srs_app_async_call.hpp @@ -41,7 +41,7 @@ class ISrsAsyncCallTask class SrsAsyncCallWorker : public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; protected: std::vector tasks_; diff --git a/trunk/src/app/srs_app_caster_flv.cpp b/trunk/src/app/srs_app_caster_flv.cpp index 4c81b1967d3..a6d27415ce7 100644 --- a/trunk/src/app/srs_app_caster_flv.cpp +++ b/trunk/src/app/srs_app_caster_flv.cpp @@ -11,7 +11,6 @@ using namespace std; #include #include -#include #include #include #include @@ -19,6 +18,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_caster_flv.hpp b/trunk/src/app/srs_app_caster_flv.hpp index 00b42ff3ed0..3745c2cd485 100644 --- a/trunk/src/app/srs_app_caster_flv.hpp +++ b/trunk/src/app/srs_app_caster_flv.hpp @@ -24,11 +24,11 @@ class SrsTcpClient; class SrsSimpleRtmpClient; class SrsAppCasterFlv; -#include #include #include #include #include +#include // A TCP listener, for flv stream server. class SrsHttpFlvListener : public ISrsTcpHandler, public ISrsListener diff --git a/trunk/src/app/srs_app_circuit_breaker.cpp b/trunk/src/app/srs_app_circuit_breaker.cpp index db81ea38a41..d83bc3931b5 100644 --- a/trunk/src/app/srs_app_circuit_breaker.cpp +++ b/trunk/src/app/srs_app_circuit_breaker.cpp @@ -7,9 +7,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_circuit_breaker.hpp b/trunk/src/app/srs_app_circuit_breaker.hpp index a7aa6634a6d..031b141487d 100644 --- a/trunk/src/app/srs_app_circuit_breaker.hpp +++ b/trunk/src/app/srs_app_circuit_breaker.hpp @@ -9,7 +9,7 @@ #include -#include +#include // Interface for circuit breaker functionality to protect server in high load conditions. // The circuit breaker monitors CPU usage and enables different levels of protection: diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index c130d85ff78..6fbd4430e56 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -26,7 +26,7 @@ using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index c2405bcce58..e637e38ca6d 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -18,6 +18,7 @@ #include #include #include +#include class ISrsRequest; class SrsFileWriter; @@ -278,7 +279,7 @@ enum SrsReloadState { // that is, never save the SrsConfDirective* get by any api of config, // For it maybe free in the reload st-thread cycle. // You could keep it before st-thread switch, or simply never keep it. -class SrsConfig +class SrsConfig : public ISrsConfig { friend class SrsConfDirective; // user command diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp deleted file mode 100644 index 6d679640751..00000000000 --- a/trunk/src/app/srs_app_conn.cpp +++ /dev/null @@ -1,1009 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#include - -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -SrsPps *_srs_pps_ids = NULL; -SrsPps *_srs_pps_fids = NULL; -SrsPps *_srs_pps_fids_level0 = NULL; -SrsPps *_srs_pps_dispose = NULL; - -ISrsDisposingHandler::ISrsDisposingHandler() -{ -} - -ISrsDisposingHandler::~ISrsDisposingHandler() -{ -} - -SrsResourceManager::SrsResourceManager(const std::string &label, bool verbose) -{ - verbose_ = verbose; - label_ = label; - cond_ = srs_cond_new(); - trd_ = NULL; - p_disposing_ = NULL; - removing_ = false; - - nn_level0_cache_ = 100000; - conns_level0_cache_ = new SrsResourceFastIdItem[nn_level0_cache_]; -} - -SrsResourceManager::~SrsResourceManager() -{ - if (trd_) { - srs_cond_signal(cond_); - trd_->stop(); - - srs_freep(trd_); - } - srs_cond_destroy(cond_); - - clear(); - - // Free all objects not in zombies. - std::vector::iterator it; - for (it = conns_.begin(); it != conns_.end(); ++it) { - ISrsResource *resource = *it; - srs_freep(resource); - } - - srs_freepa(conns_level0_cache_); -} - -srs_error_t SrsResourceManager::start() -{ - srs_error_t err = srs_success; - - cid_ = _srs_context->generate_id(); - trd_ = new SrsSTCoroutine("manager", this, cid_); - - if ((err = trd_->start()) != srs_success) { - return srs_error_wrap(err, "conn manager"); - } - - return err; -} - -bool SrsResourceManager::empty() -{ - return conns_.empty(); -} - -size_t SrsResourceManager::size() -{ - return conns_.size(); -} - -srs_error_t SrsResourceManager::cycle() -{ - srs_error_t err = srs_success; - - srs_trace("%s: connection manager run, conns=%d", label_.c_str(), (int)conns_.size()); - - while (true) { - if ((err = trd_->pull()) != srs_success) { - return srs_error_wrap(err, "conn manager"); - } - - // Clear all zombies, because we may switch context and lost signal - // when we clear zombie connection. - while (!zombies_.empty()) { - clear(); - } - - srs_cond_wait(cond_); - } - - return err; -} - -void SrsResourceManager::add(ISrsResource *conn, bool *exists) -{ - if (std::find(conns_.begin(), conns_.end(), conn) == conns_.end()) { - conns_.push_back(conn); - } else { - if (exists) { - *exists = true; - } - } -} - -void SrsResourceManager::add_with_id(const std::string &id, ISrsResource *conn) -{ - add(conn); - conns_id_[id] = conn; -} - -void SrsResourceManager::add_with_fast_id(uint64_t id, ISrsResource *conn) -{ - bool exists = false; - add(conn, &exists); - conns_fast_id_[id] = conn; - - if (exists) { - return; - } - - // For new resource, build the level-0 cache for fast-id. - SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; - - // Ignore if exits item. - if (item->fast_id_ && item->fast_id_ == id) { - return; - } - - // Fresh one, create the item. - if (!item->fast_id_) { - item->fast_id_ = id; - item->impl_ = conn; - item->nn_collisions_ = 1; - item->available_ = true; - } - - // Collision, increase the collisions. - if (item->fast_id_ != id) { - item->nn_collisions_++; - item->available_ = false; - } -} - -void SrsResourceManager::add_with_name(const std::string &name, ISrsResource *conn) -{ - add(conn); - conns_name_[name] = conn; -} - -ISrsResource *SrsResourceManager::at(int index) -{ - return (index < (int)conns_.size()) ? conns_.at(index) : NULL; -} - -ISrsResource *SrsResourceManager::find_by_id(std::string id) -{ - ++_srs_pps_ids->sugar_; - map::iterator it = conns_id_.find(id); - return (it != conns_id_.end()) ? it->second : NULL; -} - -ISrsResource *SrsResourceManager::find_by_fast_id(uint64_t id) -{ - SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; - if (item->available_ && item->fast_id_ == id) { - ++_srs_pps_fids_level0->sugar_; - return item->impl_; - } - - ++_srs_pps_fids->sugar_; - map::iterator it = conns_fast_id_.find(id); - return (it != conns_fast_id_.end()) ? it->second : NULL; -} - -ISrsResource *SrsResourceManager::find_by_name(std::string name) -{ - ++_srs_pps_ids->sugar_; - map::iterator it = conns_name_.find(name); - return (it != conns_name_.end()) ? it->second : NULL; -} - -void SrsResourceManager::subscribe(ISrsDisposingHandler *h) -{ - if (std::find(handlers_.begin(), handlers_.end(), h) == handlers_.end()) { - handlers_.push_back(h); - } - - // Restore the handler from unsubscribing handlers. - vector::iterator it; - if ((it = std::find(unsubs_.begin(), unsubs_.end(), h)) != unsubs_.end()) { - it = unsubs_.erase(it); - } -} - -void SrsResourceManager::unsubscribe(ISrsDisposingHandler *h) -{ - vector::iterator it = find(handlers_.begin(), handlers_.end(), h); - if (it != handlers_.end()) { - it = handlers_.erase(it); - } - - // Put it to the unsubscribing handlers. - if (std::find(unsubs_.begin(), unsubs_.end(), h) == unsubs_.end()) { - unsubs_.push_back(h); - } -} - -void SrsResourceManager::remove(ISrsResource *c) -{ - SrsContextRestore(_srs_context->get_id()); - - removing_ = true; - do_remove(c); - removing_ = false; -} - -void SrsResourceManager::do_remove(ISrsResource *c) -{ - bool in_zombie = false; - bool in_disposing = false; - check_remove(c, in_zombie, in_disposing); - bool ignored = in_zombie || in_disposing; - - if (verbose_) { - _srs_context->set_id(c->get_id()); - srs_trace("%s: before dispose resource(%s)(%p), conns=%d, zombies=%d, ign=%d, inz=%d, ind=%d", - label_.c_str(), c->desc().c_str(), c, (int)conns_.size(), (int)zombies_.size(), ignored, - in_zombie, in_disposing); - } - if (ignored) { - return; - } - - // Push to zombies, we will free it in another coroutine. - zombies_.push_back(c); - - // We should copy all handlers, because it may change during callback. - vector handlers = handlers_; - - // Notify other handlers to handle the before-dispose event. - for (int i = 0; i < (int)handlers.size(); i++) { - ISrsDisposingHandler *h = handlers.at(i); - - // Ignore if handler is unsubscribing. - if (!unsubs_.empty() && std::find(unsubs_.begin(), unsubs_.end(), h) != unsubs_.end()) { - srs_warn2(TAG_RESOURCE_UNSUB, "%s: ignore before-dispose resource(%s)(%p) for %p, conns=%d", - label_.c_str(), c->desc().c_str(), c, h, (int)conns_.size()); - continue; - } - - h->on_before_dispose(c); - } - - // Notify the coroutine to free it. - srs_cond_signal(cond_); -} - -void SrsResourceManager::check_remove(ISrsResource *c, bool &in_zombie, bool &in_disposing) -{ - // Only notify when not removed(in zombies_). - vector::iterator it = std::find(zombies_.begin(), zombies_.end(), c); - if (it != zombies_.end()) { - in_zombie = true; - } - - // Also ignore when we are disposing it. - if (p_disposing_) { - it = std::find(p_disposing_->begin(), p_disposing_->end(), c); - if (it != p_disposing_->end()) { - in_disposing = true; - } - } -} - -void SrsResourceManager::clear() -{ - if (zombies_.empty()) { - return; - } - - SrsContextRestore(cid_); - if (verbose_) { - srs_trace("%s: clear zombies=%d resources, conns=%d, removing=%d, unsubs=%d", - label_.c_str(), (int)zombies_.size(), (int)conns_.size(), removing_, (int)unsubs_.size()); - } - - // Clear all unsubscribing handlers, if not removing any resource. - if (!removing_ && !unsubs_.empty()) { - vector().swap(unsubs_); - } - - do_clear(); -} - -void SrsResourceManager::do_clear() -{ - // To prevent thread switch when delete connection, - // we copy all connections then free one by one. - vector copy; - copy.swap(zombies_); - p_disposing_ = © - - for (int i = 0; i < (int)copy.size(); i++) { - ISrsResource *conn = copy.at(i); - - if (verbose_) { - _srs_context->set_id(conn->get_id()); - srs_trace("%s: disposing #%d resource(%s)(%p), conns=%d, disposing=%d, zombies=%d", label_.c_str(), - i, conn->desc().c_str(), conn, (int)conns_.size(), (int)copy.size(), (int)zombies_.size()); - } - - ++_srs_pps_dispose->sugar_; - - dispose(conn); - } - - // Reset it for it points to a local object. - // @remark We must set the disposing to NULL to avoid reusing address, - // because the context might switch. - p_disposing_ = NULL; - - // We should free the resources when finished all disposing callbacks, - // which might cause context switch and reuse the freed addresses. - for (int i = 0; i < (int)copy.size(); i++) { - ISrsResource *conn = copy.at(i); - srs_freep(conn); - } -} - -void SrsResourceManager::dispose(ISrsResource *c) -{ - for (map::iterator it = conns_name_.begin(); it != conns_name_.end();) { - if (c != it->second) { - ++it; - } else { - // Use C++98 style: https://stackoverflow.com/a/4636230 - conns_name_.erase(it++); - } - } - - for (map::iterator it = conns_id_.begin(); it != conns_id_.end();) { - if (c != it->second) { - ++it; - } else { - // Use C++98 style: https://stackoverflow.com/a/4636230 - conns_id_.erase(it++); - } - } - - for (map::iterator it = conns_fast_id_.begin(); it != conns_fast_id_.end();) { - if (c != it->second) { - ++it; - } else { - // Update the level-0 cache for fast-id. - uint64_t id = it->first; - SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; - item->nn_collisions_--; - if (!item->nn_collisions_) { - item->fast_id_ = 0; - item->available_ = false; - } - - // Use C++98 style: https://stackoverflow.com/a/4636230 - conns_fast_id_.erase(it++); - } - } - - vector::iterator it = std::find(conns_.begin(), conns_.end(), c); - if (it != conns_.end()) { - it = conns_.erase(it); - } - - // We should copy all handlers, because it may change during callback. - vector handlers = handlers_; - - // Notify other handlers to handle the disposing event. - for (int i = 0; i < (int)handlers.size(); i++) { - ISrsDisposingHandler *h = handlers.at(i); - - // Ignore if handler is unsubscribing. - if (!unsubs_.empty() && std::find(unsubs_.begin(), unsubs_.end(), h) != unsubs_.end()) { - srs_warn2(TAG_RESOURCE_UNSUB, "%s: ignore disposing resource(%s)(%p) for %p, conns=%d", - label_.c_str(), c->desc().c_str(), c, h, (int)conns_.size()); - continue; - } - - h->on_disposing(c); - } -} - -ISrsExpire::ISrsExpire() -{ -} - -ISrsExpire::~ISrsExpire() -{ -} - -SrsTcpConnection::SrsTcpConnection(srs_netfd_t c) -{ - stfd_ = c; - skt_ = new SrsStSocket(c); -} - -SrsTcpConnection::~SrsTcpConnection() -{ - srs_freep(skt_); - srs_close_stfd(stfd_); -} - -srs_error_t SrsTcpConnection::set_tcp_nodelay(bool v) -{ - srs_error_t err = srs_success; - - int r0 = 0; - socklen_t nb_v = sizeof(int); - int fd = srs_netfd_fileno(stfd_); - - int ov = 0; - if ((r0 = getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &ov, &nb_v)) != 0) { - return srs_error_new(ERROR_SOCKET_NO_NODELAY, "getsockopt fd=%d, r0=%d", fd, r0); - } - -#ifndef SRS_PERF_TCP_NODELAY - srs_warn("ignore TCP_NODELAY, fd=%d, ov=%d", fd, ov); - return err; -#endif - - int iv = (v ? 1 : 0); - if ((r0 = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, nb_v)) != 0) { - return srs_error_new(ERROR_SOCKET_NO_NODELAY, "setsockopt fd=%d, r0=%d", fd, r0); - } - if ((r0 = getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, &nb_v)) != 0) { - return srs_error_new(ERROR_SOCKET_NO_NODELAY, "getsockopt fd=%d, r0=%d", fd, r0); - } - - srs_trace("set fd=%d TCP_NODELAY %d=>%d", fd, ov, iv); - - return err; -} - -srs_error_t SrsTcpConnection::set_socket_buffer(srs_utime_t buffer_v) -{ - srs_error_t err = srs_success; - - int r0 = 0; - int fd = srs_netfd_fileno(stfd_); - socklen_t nb_v = sizeof(int); - - int ov = 0; - if ((r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &ov, &nb_v)) != 0) { - return srs_error_new(ERROR_SOCKET_SNDBUF, "getsockopt fd=%d, r0=%d", fd, r0); - } - -#ifndef SRS_PERF_MW_SO_SNDBUF - srs_warn("ignore SO_SNDBUF, fd=%d, ov=%d", fd, ov); - return err; -#endif - - // the bytes: - // 4KB=4096, 8KB=8192, 16KB=16384, 32KB=32768, 64KB=65536, - // 128KB=131072, 256KB=262144, 512KB=524288 - // the buffer should set to sleep*kbps/8, - // for example, your system delivery stream in 1000kbps, - // sleep 800ms for small bytes, the buffer should set to: - // 800*1000/8=100000B(about 128KB). - // other examples: - // 2000*3000/8=750000B(about 732KB). - // 2000*5000/8=1250000B(about 1220KB). - int kbps = 4000; - int iv = srsu2ms(buffer_v) * kbps / 8; - - // socket send buffer, system will double it. - iv = iv / 2; - - // override the send buffer by macro. -#ifdef SRS_PERF_SO_SNDBUF_SIZE - iv = SRS_PERF_SO_SNDBUF_SIZE / 2; -#endif - - // set the socket send buffer when required larger buffer - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, nb_v) < 0) { - return srs_error_new(ERROR_SOCKET_SNDBUF, "setsockopt fd=%d, r0=%d", fd, r0); - } - if ((r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, &nb_v)) != 0) { - return srs_error_new(ERROR_SOCKET_SNDBUF, "getsockopt fd=%d, r0=%d", fd, r0); - } - - srs_trace("set fd=%d, SO_SNDBUF=%d=>%d, buffer=%dms", fd, ov, iv, srsu2ms(buffer_v)); - - return err; -} - -void SrsTcpConnection::set_recv_timeout(srs_utime_t tm) -{ - skt_->set_recv_timeout(tm); -} - -srs_utime_t SrsTcpConnection::get_recv_timeout() -{ - return skt_->get_recv_timeout(); -} - -srs_error_t SrsTcpConnection::read_fully(void *buf, size_t size, ssize_t *nread) -{ - return skt_->read_fully(buf, size, nread); -} - -int64_t SrsTcpConnection::get_recv_bytes() -{ - return skt_->get_recv_bytes(); -} - -int64_t SrsTcpConnection::get_send_bytes() -{ - return skt_->get_send_bytes(); -} - -srs_error_t SrsTcpConnection::read(void *buf, size_t size, ssize_t *nread) -{ - return skt_->read(buf, size, nread); -} - -void SrsTcpConnection::set_send_timeout(srs_utime_t tm) -{ - skt_->set_send_timeout(tm); -} - -srs_utime_t SrsTcpConnection::get_send_timeout() -{ - return skt_->get_send_timeout(); -} - -srs_error_t SrsTcpConnection::write(void *buf, size_t size, ssize_t *nwrite) -{ - return skt_->write(buf, size, nwrite); -} - -srs_error_t SrsTcpConnection::writev(const iovec *iov, int iov_size, ssize_t *nwrite) -{ - return skt_->writev(iov, iov_size, nwrite); -} - -SrsBufferedReadWriter::SrsBufferedReadWriter(ISrsProtocolReadWriter *io) -{ - io_ = io; - buf_ = NULL; -} - -SrsBufferedReadWriter::~SrsBufferedReadWriter() -{ - srs_freep(buf_); -} - -srs_error_t SrsBufferedReadWriter::peek(char *buf, int *size) -{ - srs_error_t err = srs_success; - - if ((err = reload_buffer()) != srs_success) { - return srs_error_wrap(err, "reload buffer"); - } - - int nn = srs_min(buf_->left(), *size); - *size = nn; - - if (nn) { - memcpy(buf, buf_->head(), nn); - } - - return err; -} - -srs_error_t SrsBufferedReadWriter::reload_buffer() -{ - srs_error_t err = srs_success; - - if (buf_ && !buf_->empty()) { - return err; - } - - // We use read_fully to always full fill the cache, to avoid peeking failed. - ssize_t nread = 0; - if ((err = io_->read_fully(cache_, sizeof(cache_), &nread)) != srs_success) { - return srs_error_wrap(err, "read"); - } - - srs_freep(buf_); - buf_ = new SrsBuffer(cache_, nread); - - return err; -} - -srs_error_t SrsBufferedReadWriter::read(void *buf, size_t size, ssize_t *nread) -{ - if (!buf_ || buf_->empty()) { - return io_->read(buf, size, nread); - } - - int nn = srs_min(buf_->left(), (int)size); - *nread = nn; - - if (nn) { - buf_->read_bytes((char *)buf, nn); - } - return srs_success; -} - -srs_error_t SrsBufferedReadWriter::read_fully(void *buf, size_t size, ssize_t *nread) -{ - if (!buf_ || buf_->empty()) { - return io_->read_fully(buf, size, nread); - } - - int nn = srs_min(buf_->left(), (int)size); - if (nn) { - buf_->read_bytes((char *)buf, nn); - } - - int left = size - nn; - *nread = size; - - if (left) { - return io_->read_fully((char *)buf + nn, left, NULL); - } - return srs_success; -} - -void SrsBufferedReadWriter::set_recv_timeout(srs_utime_t tm) -{ - return io_->set_recv_timeout(tm); -} - -srs_utime_t SrsBufferedReadWriter::get_recv_timeout() -{ - return io_->get_recv_timeout(); -} - -int64_t SrsBufferedReadWriter::get_recv_bytes() -{ - return io_->get_recv_bytes(); -} - -int64_t SrsBufferedReadWriter::get_send_bytes() -{ - return io_->get_send_bytes(); -} - -void SrsBufferedReadWriter::set_send_timeout(srs_utime_t tm) -{ - return io_->set_send_timeout(tm); -} - -srs_utime_t SrsBufferedReadWriter::get_send_timeout() -{ - return io_->get_send_timeout(); -} - -srs_error_t SrsBufferedReadWriter::write(void *buf, size_t size, ssize_t *nwrite) -{ - return io_->write(buf, size, nwrite); -} - -srs_error_t SrsBufferedReadWriter::writev(const iovec *iov, int iov_size, ssize_t *nwrite) -{ - return io_->writev(iov, iov_size, nwrite); -} - -SrsSslConnection::SrsSslConnection(ISrsProtocolReadWriter *c) -{ - transport_ = c; - ssl_ctx_ = NULL; - ssl_ = NULL; -} - -SrsSslConnection::~SrsSslConnection() -{ - if (ssl_) { - // this function will free bio_in_ and bio_out_ - SSL_free(ssl_); - ssl_ = NULL; - } - - if (ssl_ctx_) { - SSL_CTX_free(ssl_ctx_); - ssl_ctx_ = NULL; - } -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -srs_error_t SrsSslConnection::handshake(string key_file, string crt_file) -{ - srs_error_t err = srs_success; - - // For HTTPS, try to connect over security transport. -#if (OPENSSL_VERSION_NUMBER < 0x10002000L) // v1.0.2 - ssl_ctx_ = SSL_CTX_new(TLS_method()); -#else - ssl_ctx_ = SSL_CTX_new(TLSv1_2_method()); -#endif - SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_NONE, NULL); - srs_assert(SSL_CTX_set_cipher_list(ssl_ctx_, "ALL") == 1); - - // TODO: Setup callback, see SSL_set_ex_data and SSL_set_info_callback - if ((ssl_ = SSL_new(ssl_ctx_)) == NULL) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "SSL_new ssl"); - } - - if ((bio_in_ = BIO_new(BIO_s_mem())) == NULL) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_new in"); - } - - if ((bio_out_ = BIO_new(BIO_s_mem())) == NULL) { - BIO_free(bio_in_); - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_new out"); - } - - SSL_set_bio(ssl_, bio_in_, bio_out_); - - // SSL setup active, as server role. - SSL_set_accept_state(ssl_); - SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); - - uint8_t *data = NULL; - int r0, r1, size; - - // Setup the key and cert file for server. - if ((r0 = SSL_use_certificate_chain_file(ssl_, crt_file.c_str())) != 1) { - return srs_error_new(ERROR_TLS_KEY_CRT, "use cert %s", crt_file.c_str()); - } - - if ((r0 = SSL_use_RSAPrivateKey_file(ssl_, key_file.c_str(), SSL_FILETYPE_PEM)) != 1) { - return srs_error_new(ERROR_TLS_KEY_CRT, "use key %s", key_file.c_str()); - } - - if ((r0 = SSL_check_private_key(ssl_)) != 1) { - return srs_error_new(ERROR_TLS_KEY_CRT, "check key %s with cert %s", - key_file.c_str(), crt_file.c_str()); - } - srs_info("ssl: use key %s and cert %s", key_file.c_str(), crt_file.c_str()); - - // Receive ClientHello - while (true) { - char buf[1024]; - ssize_t nn = 0; - if ((err = transport_->read(buf, sizeof(buf), &nn)) != srs_success) { - return srs_error_wrap(err, "handshake: read"); - } - - if ((r0 = BIO_write(bio_in_, buf, nn)) <= 0) { - // TODO: 0 or -1 maybe block, use BIO_should_retry to check. - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn); - } - - r0 = SSL_do_handshake(ssl_); - r1 = SSL_get_error(ssl_, r0); - ERR_clear_error(); - if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1); - } - - if ((size = BIO_get_mem_data(bio_out_, &data)) > 0) { - // OK, reset it for the next write. - if ((r0 = BIO_reset(bio_in_)) != 1) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); - } - break; - } - } - - srs_info("tls: ClientHello done"); - - // Send ServerHello, Certificate, Server Key Exchange, Server Hello Done - size = BIO_get_mem_data(bio_out_, &data); - if (!data || size <= 0) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake data=%p, size=%d", data, size); - } - if ((err = transport_->write(data, size, NULL)) != srs_success) { - return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size); - } - if ((r0 = BIO_reset(bio_out_)) != 1) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); - } - - srs_info("tls: ServerHello done"); - - // Receive Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message - while (true) { - char buf[1024]; - ssize_t nn = 0; - if ((err = transport_->read(buf, sizeof(buf), &nn)) != srs_success) { - return srs_error_wrap(err, "handshake: read"); - } - - if ((r0 = BIO_write(bio_in_, buf, nn)) <= 0) { - // TODO: 0 or -1 maybe block, use BIO_should_retry to check. - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn); - } - - r0 = SSL_do_handshake(ssl_); - r1 = SSL_get_error(ssl_, r0); - ERR_clear_error(); - if (r0 == 1 && r1 == SSL_ERROR_NONE) { - break; - } - - if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1); - } - - if ((size = BIO_get_mem_data(bio_out_, &data)) > 0) { - // OK, reset it for the next write. - if ((r0 = BIO_reset(bio_in_)) != 1) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); - } - break; - } - } - - srs_info("tls: Client done"); - - // Send New Session Ticket, Change Cipher Spec, Encrypted Handshake Message - size = BIO_get_mem_data(bio_out_, &data); - if (!data || size <= 0) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake data=%p, size=%d", data, size); - } - if ((err = transport_->write(data, size, NULL)) != srs_success) { - return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size); - } - if ((r0 = BIO_reset(bio_out_)) != 1) { - return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); - } - - srs_info("tls: Server done"); - - return err; -} -#pragma GCC diagnostic pop - -void SrsSslConnection::set_recv_timeout(srs_utime_t tm) -{ - transport_->set_recv_timeout(tm); -} - -srs_utime_t SrsSslConnection::get_recv_timeout() -{ - return transport_->get_recv_timeout(); -} - -srs_error_t SrsSslConnection::read_fully(void *buf, size_t size, ssize_t *nread) -{ - srs_error_t err = srs_success; - ssize_t nb = 0; - void *p = buf; - while ((size_t)nb < size) { - ssize_t once_nb = 0; - if ((err = read((char *)p + nb, size - nb, &once_nb)) != srs_success) { - return srs_error_wrap(err, "tls: read"); - } - nb += once_nb; - } - - if (nread) { - *nread = nb; - } - - return err; -} - -int64_t SrsSslConnection::get_recv_bytes() -{ - return transport_->get_recv_bytes(); -} - -int64_t SrsSslConnection::get_send_bytes() -{ - return transport_->get_send_bytes(); -} - -srs_error_t SrsSslConnection::read(void *plaintext, size_t nn_plaintext, ssize_t *nread) -{ - srs_error_t err = srs_success; - - while (true) { - int r0 = SSL_read(ssl_, plaintext, nn_plaintext); - int r1 = SSL_get_error(ssl_, r0); - ERR_clear_error(); - int r2 = BIO_ctrl_pending(bio_in_); - int r3 = SSL_is_init_finished(ssl_); - - // OK, got data. - if (r0 > 0) { - srs_assert(r0 <= (int)nn_plaintext); - if (nread) { - *nread = r0; - } - return err; - } - - // Need to read more data to feed SSL. - if (r0 == -1 && r1 == SSL_ERROR_WANT_READ) { - // TODO: Can we avoid copy? - int nn_cipher = nn_plaintext; - SrsUniquePtr cipher(new char[nn_cipher]); - - // Read the cipher from SSL. - ssize_t nn = 0; - if ((err = transport_->read(cipher.get(), nn_cipher, &nn)) != srs_success) { - return srs_error_wrap(err, "tls: read"); - } - - int r0 = BIO_write(bio_in_, cipher.get(), nn); - if (r0 <= 0) { - // TODO: 0 or -1 maybe block, use BIO_should_retry to check. - return srs_error_new(ERROR_TLS_READ, "BIO_write r0=%d, cipher=%p, size=%d", r0, cipher.get(), nn); - } - continue; - } - - // Fail for error. - if (r0 <= 0) { - return srs_error_new(ERROR_TLS_READ, "SSL_read r0=%d, r1=%d, r2=%d, r3=%d", - r0, r1, r2, r3); - } - } -} - -void SrsSslConnection::set_send_timeout(srs_utime_t tm) -{ - transport_->set_send_timeout(tm); -} - -srs_utime_t SrsSslConnection::get_send_timeout() -{ - return transport_->get_send_timeout(); -} - -srs_error_t SrsSslConnection::write(void *plaintext, size_t nn_plaintext, ssize_t *nwrite) -{ - srs_error_t err = srs_success; - - for (char *p = (char *)plaintext; p < (char *)plaintext + nn_plaintext;) { - int left = (int)nn_plaintext - (p - (char *)plaintext); - int r0 = SSL_write(ssl_, (const void *)p, left); - int r1 = SSL_get_error(ssl_, r0); - ERR_clear_error(); - if (r0 <= 0) { - return srs_error_new(ERROR_TLS_WRITE, "tls: write data=%p, size=%d, r0=%d, r1=%d", p, left, r0, r1); - } - - // Move p to the next writing position. - p += r0; - if (nwrite) { - *nwrite += (ssize_t)r0; - } - - uint8_t *data = NULL; - int size = BIO_get_mem_data(bio_out_, &data); - if ((err = transport_->write(data, size, NULL)) != srs_success) { - return srs_error_wrap(err, "tls: write data=%p, size=%d", data, size); - } - if ((r0 = BIO_reset(bio_out_)) != 1) { - return srs_error_new(ERROR_TLS_WRITE, "BIO_reset r0=%d", r0); - } - } - - return err; -} - -srs_error_t SrsSslConnection::writev(const iovec *iov, int iov_size, ssize_t *nwrite) -{ - srs_error_t err = srs_success; - - for (int i = 0; i < iov_size; i++) { - const iovec *p = iov + i; - if ((err = write((void *)p->iov_base, (size_t)p->iov_len, nwrite)) != srs_success) { - return srs_error_wrap(err, "write iov #%d base=%p, size=%d", i, p->iov_base, p->iov_len); - } - } - - return err; -} - -SrsResourceManager *_srs_conn_manager = NULL; diff --git a/trunk/src/app/srs_app_dash.cpp b/trunk/src/app/srs_app_dash.cpp index f9be06cf284..0a3a0190748 100644 --- a/trunk/src/app/srs_app_dash.cpp +++ b/trunk/src/app/srs_app_dash.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index d05bc2c235a..d95915afb07 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -30,7 +30,7 @@ class SrsFormat; #include #include -#include +#include // The segmenter for DVR, to write a segment file in flv/mp4. class SrsDvrSegmenter : public ISrsReloadHandler diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index c0e4a162d3b..4d1da1c7f48 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -16,10 +16,10 @@ using namespace std; #include #include #include -#include #include -#include +#include #include +#include #include #include @@ -27,11 +27,11 @@ using namespace std; #include #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_edge.hpp b/trunk/src/app/srs_app_edge.hpp index 5998158a1d2..9a090aa98ae 100644 --- a/trunk/src/app/srs_app_edge.hpp +++ b/trunk/src/app/srs_app_edge.hpp @@ -154,7 +154,7 @@ class SrsEdgeIngester : public ISrsCoroutineHandler private: SrsPlayEdge *edge_; ISrsRequest *req_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; ISrsLbRoundRobin *lb_; SrsEdgeUpstream *upstream_; @@ -189,7 +189,7 @@ class SrsEdgeForwarder : public ISrsCoroutineHandler private: SrsPublishEdge *edge_; ISrsRequest *req_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; SrsSimpleRtmpClient *sdk_; ISrsLbRoundRobin *lb_; // we must ensure one thread one fd principle, diff --git a/trunk/src/app/srs_app_empty.cpp b/trunk/src/app/srs_app_empty.cpp deleted file mode 100644 index 939fda5dafc..00000000000 --- a/trunk/src/app/srs_app_empty.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#include diff --git a/trunk/src/app/srs_app_empty.hpp b/trunk/src/app/srs_app_empty.hpp deleted file mode 100644 index 9a5198304ee..00000000000 --- a/trunk/src/app/srs_app_empty.hpp +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_EMPTY_HPP -#define SRS_APP_EMPTY_HPP - -#include - -#endif diff --git a/trunk/src/app/srs_app_encoder.cpp b/trunk/src/app/srs_app_encoder.cpp index 4a4c0bd471e..157c588f0fc 100644 --- a/trunk/src/app/srs_app_encoder.cpp +++ b/trunk/src/app/srs_app_encoder.cpp @@ -11,10 +11,10 @@ using namespace std; #include #include -#include #include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_encoder.hpp b/trunk/src/app/srs_app_encoder.hpp index da3ebc34172..0c9b24c1247 100644 --- a/trunk/src/app/srs_app_encoder.hpp +++ b/trunk/src/app/srs_app_encoder.hpp @@ -28,7 +28,7 @@ class SrsEncoder : public ISrsCoroutineHandler std::vector ffmpegs_; private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; SrsPithyPrint *pprint_; public: diff --git a/trunk/src/app/srs_app_factory.cpp b/trunk/src/app/srs_app_factory.cpp new file mode 100644 index 00000000000..05699cba7c7 --- /dev/null +++ b/trunk/src/app/srs_app_factory.cpp @@ -0,0 +1,70 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#include + +#include +#include +#include + +SrsFinalFactory::SrsFinalFactory() +{ +} + +SrsFinalFactory::~SrsFinalFactory() +{ +} + +ISrsCoroutine *SrsFinalFactory::create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid) +{ + return new SrsSTCoroutine(name, handler, cid); +} + +ISrsTime *SrsFinalFactory::create_time() +{ + return new SrsTrueTime(); +} + +ISrsConfig *SrsFinalFactory::create_config() +{ + return new SrsConfigProxy(); +} + +ISrsCond *SrsFinalFactory::create_cond() +{ + return new SrsCond(); +} + +SrsConfigProxy::SrsConfigProxy() +{ +} + +SrsConfigProxy::~SrsConfigProxy() +{ +} + +srs_utime_t SrsConfigProxy::get_pithy_print() +{ + return _srs_config->get_pithy_print(); +} + +std::string SrsConfigProxy::get_default_app_name() +{ + return _srs_config->get_default_app_name(); +} + +SrsTrueTime::SrsTrueTime() +{ +} + +SrsTrueTime::~SrsTrueTime() +{ +} + +void SrsTrueTime::usleep(srs_utime_t duration) +{ + srs_usleep(duration); +} diff --git a/trunk/src/app/srs_app_factory.hpp b/trunk/src/app/srs_app_factory.hpp new file mode 100644 index 00000000000..7b8e057c215 --- /dev/null +++ b/trunk/src/app/srs_app_factory.hpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_APP_FACTORY_HPP +#define SRS_APP_FACTORY_HPP + +#include + +#include + +// The factory to create kernel objects. +class SrsFinalFactory : public ISrsKernelFactory +{ +public: + SrsFinalFactory(); + virtual ~SrsFinalFactory(); + +public: + virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid); + virtual ISrsTime *create_time(); + virtual ISrsConfig *create_config(); + virtual ISrsCond *create_cond(); +}; + +// The proxy for config. +class SrsConfigProxy : public ISrsConfig +{ +public: + SrsConfigProxy(); + virtual ~SrsConfigProxy(); + +public: + virtual srs_utime_t get_pithy_print(); + virtual std::string get_default_app_name(); +}; + +// The time to use system time. +class SrsTrueTime : public ISrsTime +{ +public: + SrsTrueTime(); + virtual ~SrsTrueTime(); + +public: + virtual void usleep(srs_utime_t duration); +}; + +#endif diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp index 527e9d6ac74..98facfb584a 100644 --- a/trunk/src/app/srs_app_forward.cpp +++ b/trunk/src/app/srs_app_forward.cpp @@ -14,18 +14,18 @@ using namespace std; #include -#include #include -#include +#include #include #include #include #include #include +#include #include +#include #include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_forward.hpp b/trunk/src/app/srs_app_forward.hpp index b3c50bf528a..3a22208e1ac 100644 --- a/trunk/src/app/srs_app_forward.hpp +++ b/trunk/src/app/srs_app_forward.hpp @@ -38,7 +38,7 @@ class SrsForwarder : public ISrsCoroutineHandler SrsContextId source_cid_; private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; private: SrsOriginHub *hub_; diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp index 40fe5f65bb0..4a178065bc7 100644 --- a/trunk/src/app/srs_app_gb28181.cpp +++ b/trunk/src/app/srs_app_gb28181.cpp @@ -7,23 +7,23 @@ #include #include -#include #include #include -#include -#include #include #include #include #include #include +#include #include #include #include #include +#include #include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp index 21eab1c15cf..b44cd26610c 100644 --- a/trunk/src/app/srs_app_gb28181.hpp +++ b/trunk/src/app/srs_app_gb28181.hpp @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -22,7 +21,7 @@ class SrsConfDirective; class SrsTcpListener; class SrsResourceManager; class SrsTcpConnection; -class SrsCoroutine; +class ISrsCoroutine; class SrsPackContext; class SrsBuffer; diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 14d5960a32e..5b3d8e3e778 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -20,14 +20,14 @@ using namespace std; #include #include #include -#include -#include +#include #include #include #include #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 9b4575a9a95..d94f7ebcff7 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -16,8 +16,8 @@ using namespace std; #include #include #include +#include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 2ebed90a835..d0acea1f514 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -22,10 +22,10 @@ class SrsHttpConn; #include -#include #include #include #include +#include #include extern srs_error_t srs_api_response(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string json); @@ -238,7 +238,7 @@ class SrsGoApiTcmalloc : public ISrsHttpHandler class SrsGoApiValgrind : public ISrsHttpHandler, public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; std::string task_; public: diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 90a1f7ce6bd..df47a335fdf 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -19,9 +19,8 @@ using namespace std; #include #include #include -#include +#include #include -#include #include #include #include @@ -32,6 +31,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index e40494159ad..365ee800c04 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -13,11 +13,11 @@ #include #include -#include #include -#include +#include #include #include +#include #include class SrsServer; @@ -73,7 +73,7 @@ class SrsHttpConn : public ISrsConnection, public ISrsStartable, public ISrsCoro ISrsProtocolReadWriter *skt_; // Each connection start a green thread, // when thread stop, the connection will be delete by server. - SrsCoroutine *trd_; + ISrsCoroutine *trd_; // The ip and port of client. std::string ip_; int port_; diff --git a/trunk/src/app/srs_app_http_static.cpp b/trunk/src/app/srs_app_http_static.cpp index 8eabbfcf652..a863e5f4da5 100644 --- a/trunk/src/app/srs_app_http_static.cpp +++ b/trunk/src/app/srs_app_http_static.cpp @@ -15,11 +15,9 @@ using namespace std; #include -#include #include -#include +#include #include -#include #include #include #include @@ -27,8 +25,10 @@ using namespace std; #include #include #include +#include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 6ff84b60ebc..2452a864720 100644 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -20,10 +20,9 @@ using namespace std; #include #include #include -#include #include +#include #include -#include #include #include #include @@ -33,6 +32,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_stream.hpp b/trunk/src/app/srs_app_http_stream.hpp index d3257236a37..94535b7d29d 100644 --- a/trunk/src/app/srs_app_http_stream.hpp +++ b/trunk/src/app/srs_app_http_stream.hpp @@ -30,7 +30,7 @@ class SrsBufferCache : public ISrsCoroutineHandler private: SrsMessageQueue *queue_; ISrsRequest *req_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; public: SrsBufferCache(SrsServer *s, ISrsRequest *r); diff --git a/trunk/src/app/srs_app_ingest.cpp b/trunk/src/app/srs_app_ingest.cpp index 51f2a081cdd..9435246a3ef 100644 --- a/trunk/src/app/srs_app_ingest.cpp +++ b/trunk/src/app/srs_app_ingest.cpp @@ -11,10 +11,10 @@ using namespace std; #include #include -#include #include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_ingest.hpp b/trunk/src/app/srs_app_ingest.hpp index 98bc39f5a70..fec6a0ce904 100644 --- a/trunk/src/app/srs_app_ingest.hpp +++ b/trunk/src/app/srs_app_ingest.hpp @@ -58,7 +58,7 @@ class SrsIngester : public ISrsCoroutineHandler, public ISrsReloadHandler std::vector ingesters_; private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; SrsPithyPrint *pprint_; // Whether the ingesters are expired, for example, the listen port changed, // all ingesters must be restart. diff --git a/trunk/src/app/srs_app_latest_version.cpp b/trunk/src/app/srs_app_latest_version.cpp index 395ee7474e3..ab2b6be440f 100644 --- a/trunk/src/app/srs_app_latest_version.cpp +++ b/trunk/src/app/srs_app_latest_version.cpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_latest_version.hpp b/trunk/src/app/srs_app_latest_version.hpp index 8be5991c1ea..17cfbc2ed86 100644 --- a/trunk/src/app/srs_app_latest_version.hpp +++ b/trunk/src/app/srs_app_latest_version.hpp @@ -20,7 +20,7 @@ class SrsLatestVersion : public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; std::string server_id_; std::string session_id_; diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 2dd4b728e21..a68cd2db2fa 100644 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -17,16 +17,16 @@ #include using namespace std; -#include #include #include #include #include #include #include +#include #include -#include +#include SrsPps *_srs_pps_rpkts = NULL; SrsPps *_srs_pps_addrs = NULL; diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 26eaf6ace08..d9e291e8c15 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -82,7 +82,7 @@ class SrsUdpListener : public ISrsCoroutineHandler protected: std::string label_; srs_netfd_t lfd_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; protected: char *buf_; @@ -125,7 +125,7 @@ class SrsTcpListener : public ISrsCoroutineHandler, public ISrsListener private: std::string label_; srs_netfd_t lfd_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; private: ISrsTcpHandler *handler_; @@ -229,7 +229,7 @@ class SrsUdpMuxListener : public ISrsCoroutineHandler { private: srs_netfd_t lfd_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; SrsContextId cid_; private: diff --git a/trunk/src/app/srs_app_log.hpp b/trunk/src/app/srs_app_log.hpp index 6873335526a..77e64c4313f 100644 --- a/trunk/src/app/srs_app_log.hpp +++ b/trunk/src/app/srs_app_log.hpp @@ -15,14 +15,6 @@ #include #include -// For log TAGs. -#define TAG_MAIN "MAIN" -#define TAG_MAYBE "MAYBE" -#define TAG_DTLS_ALERT "DTLS_ALERT" -#define TAG_DTLS_HANG "DTLS_HANG" -#define TAG_RESOURCE_UNSUB "RESOURCE_UNSUB" -#define TAG_LARGE_TIMER "LARGE_TIMER" - // Use memory/disk cache and donot flush when write log. // it's ok to use it without config, which will log to console, and default trace level. // when you want to use different level, override this classs, set the protected _level. diff --git a/trunk/src/app/srs_app_mpegts_udp.cpp b/trunk/src/app/srs_app_mpegts_udp.cpp index e2f491c7b35..d116b5c4d9f 100644 --- a/trunk/src/app/srs_app_mpegts_udp.cpp +++ b/trunk/src/app/srs_app_mpegts_udp.cpp @@ -14,7 +14,6 @@ using namespace std; #include -#include #include #include #include @@ -23,6 +22,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_ng_exec.cpp b/trunk/src/app/srs_app_ng_exec.cpp index cd629b4bc3b..758e368646d 100644 --- a/trunk/src/app/srs_app_ng_exec.cpp +++ b/trunk/src/app/srs_app_ng_exec.cpp @@ -10,12 +10,12 @@ using namespace std; #include -#include #include #include #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_ng_exec.hpp b/trunk/src/app/srs_app_ng_exec.hpp index 93efa1a8e13..55fd4db4788 100644 --- a/trunk/src/app/srs_app_ng_exec.hpp +++ b/trunk/src/app/srs_app_ng_exec.hpp @@ -24,7 +24,7 @@ class SrsProcess; class SrsNgExec : public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; SrsPithyPrint *pprint_; std::string input_stream_name_; std::vector exec_publishs_; diff --git a/trunk/src/app/srs_app_recv_thread.cpp b/trunk/src/app/srs_app_recv_thread.cpp index ce54aff55f5..71790d7aee2 100644 --- a/trunk/src/app/srs_app_recv_thread.cpp +++ b/trunk/src/app/srs_app_recv_thread.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_recv_thread.hpp b/trunk/src/app/srs_app_recv_thread.hpp index 381ab89587d..9f07cf7e620 100644 --- a/trunk/src/app/srs_app_recv_thread.hpp +++ b/trunk/src/app/srs_app_recv_thread.hpp @@ -64,7 +64,7 @@ class ISrsMessagePumper : public ISrsMessageConsumer class SrsRecvThread : public ISrsCoroutineHandler { protected: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; ISrsMessagePumper *pumper_; SrsRtmpServer *rtmp_; SrsContextId _parent_cid; @@ -206,7 +206,7 @@ class SrsHttpRecvThread : public ISrsCoroutineHandler { private: SrsHttpxConn *conn_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; public: SrsHttpRecvThread(SrsHttpxConn *c); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 45efb9d2469..5b46c61169d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -21,17 +21,14 @@ using namespace std; #include #include -#include #include #include #include -#include #include -#include #include #include +#include #include -#include #include #include #include @@ -39,11 +36,13 @@ using namespace std; #include #include #include +#include #include #include +#include +#include #include #include -#include #include #include #include @@ -2335,8 +2334,13 @@ void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver *nack, uint32_t ss SrsRtcpNack rtcpNack(ssrc); - rtcpNack.set_media_ssrc(ssrc); - nack->get_nack_seqs(rtcpNack, timeout_nacks); + // If circuit-breaker is enabled, disable nack. + if (_srs_circuit_breaker->hybrid_high_water_level()) { + ++_srs_pps_snack4->sugar_; + } else { + rtcpNack.set_media_ssrc(ssrc); + nack->get_nack_seqs(rtcpNack, timeout_nacks); + } if (rtcpNack.empty()) { return; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 6fc25a37cea..1423fa6258d 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -8,21 +8,20 @@ #define SRS_APP_RTC_CONN_HPP #include -#include -#include #include #include #include -#include -#include #include #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -185,7 +184,7 @@ class ISrsRtcPLIWorkerHandler class SrsRtcPLIWorker : public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; srs_cond_t wait_; ISrsRtcPLIWorkerHandler *handler_; diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index a246e648b41..5a2121c25a3 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -141,7 +141,7 @@ class SrsDtlsClientImpl : public SrsDtlsImpl, public ISrsCoroutineHandler private: // ARQ thread, for role active(DTLS client). // @note If passive(DTLS server), the ARQ is driven by DTLS client. - SrsCoroutine *trd_; + ISrsCoroutine *trd_; // The DTLS-client state to drive the ARQ thread. SrsDtlsState state_; // The max ARQ retry. diff --git a/trunk/src/app/srs_app_rtc_network.cpp b/trunk/src/app/srs_app_rtc_network.cpp index 9c9ce0e38b2..cb2f8c49440 100644 --- a/trunk/src/app/srs_app_rtc_network.cpp +++ b/trunk/src/app/srs_app_rtc_network.cpp @@ -10,7 +10,6 @@ using namespace std; #include -#include #include #include #include @@ -20,6 +19,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_rtc_network.hpp b/trunk/src/app/srs_app_rtc_network.hpp index 12600ab5f3a..1e018af3a31 100644 --- a/trunk/src/app/srs_app_rtc_network.hpp +++ b/trunk/src/app/srs_app_rtc_network.hpp @@ -18,7 +18,7 @@ #include class ISrsResourceManager; -class SrsCoroutine; +class ISrsCoroutine; class SrsNetworkDelta; class SrsTcpConnection; class ISrsKbpsDelta; diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 847c833aafd..6937d1fd7fb 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -12,9 +12,7 @@ using namespace std; #include -#include #include -#include #include #include #include @@ -27,7 +25,9 @@ using namespace std; #include #include #include +#include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 2372540963f..70998ebe75e 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -10,12 +10,12 @@ #include #include -#include #include #include #include -#include #include +#include +#include #include #include diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index ba6cfa78456..5b252c9cbe8 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -11,22 +11,22 @@ #include #include -#include -#include #include -#include #include -#include +#include #include -#include #include #include #include #include #include #include +#include +#include +#include #include #include +#include #include #include #include @@ -37,7 +37,7 @@ #include #endif -#include +#include #include #include @@ -3182,11 +3182,18 @@ srs_error_t SrsRtcRecvTrack::on_nack(SrsRtpPacket **ppkt) srs_warn("NACK: too old seq %u, range [%u, %u]", seq, rtp_queue_->begin_, rtp_queue_->end_); } + if (srs_rtp_seq_distance(nack_first, nack_last) > 0) { - srs_trace("NACK: update seq=%u, nack range [%u, %u]", seq, nack_first, - nack_last); - nack_receiver_->insert(nack_first, nack_last); - nack_receiver_->check_queue_size(); + // If circuit-breaker is enabled, disable nack. + if (_srs_circuit_breaker->hybrid_high_water_level()) { + ++_srs_pps_snack4->sugar_; + } else { + srs_trace("NACK: update seq=%u, nack range [%u, %u]", seq, nack_first, + nack_last); + + nack_receiver_->insert(nack_first, nack_last); + nack_receiver_->check_queue_size(); + } } } diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 92b85d00f56..7872b1671ba 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -14,12 +14,13 @@ #include #include -#include -#include #include #include +#include +#include #include #include +#include #include class ISrsRequest; diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index cb2887e2ad7..d5367e0c6c9 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -18,17 +18,17 @@ using namespace std; #include #include #include -#include #include #include #include +#include #include #include -#include #include #include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index 02ad4e1588a..8310cc9115f 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -11,10 +11,10 @@ #include -#include #include #include #include +#include #include #include @@ -157,7 +157,7 @@ class SrsRtmpConn : public ISrsConnection, public ISrsStartable, public ISrsRelo SrsRtmpTransport *transport_; // Each connection start a green thread, // when thread stop, the connection will be delete by server. - SrsCoroutine *trd_; + ISrsCoroutine *trd_; // The manager object to manage the connection. ISrsResourceManager *manager_; // The ip and port of client. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_rtmp_source.cpp similarity index 99% rename from trunk/src/app/srs_app_source.cpp rename to trunk/src/app/srs_app_rtmp_source.cpp index e0d876ab6a3..a5a78940a10 100644 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_rtmp_source.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT // -#include +#include #include #include @@ -1007,10 +1007,10 @@ srs_error_t SrsOriginHub::on_audio(SrsMediaPacket *shared_audio) } #ifdef SRS_HDS - if ((err = hds->on_audio(msg)) != srs_success) { + if ((err = hds_->on_audio(msg)) != srs_success) { srs_warn("hds: ignore audio error %s", srs_error_desc(err).c_str()); srs_error_reset(err); - hds->on_unpublish(); + hds_->on_unpublish(); } #endif @@ -1098,10 +1098,10 @@ srs_error_t SrsOriginHub::on_video(SrsMediaPacket *shared_video, bool is_sequenc } #ifdef SRS_HDS - if ((err = hds->on_video(msg)) != srs_success) { + if ((err = hds_->on_video(msg)) != srs_success) { srs_warn("hds: ignore video error %s", srs_error_desc(err).c_str()); srs_error_reset(err); - hds->on_unpublish(); + hds_->on_unpublish(); } #endif diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_rtmp_source.hpp similarity index 99% rename from trunk/src/app/srs_app_source.hpp rename to trunk/src/app/srs_app_rtmp_source.hpp index ad1dfbfc6b1..e4c432ca6ee 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_rtmp_source.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_SOURCE_HPP -#define SRS_APP_SOURCE_HPP +#ifndef SRS_APP_RTMP_SOURCE_HPP +#define SRS_APP_RTMP_SOURCE_HPP #include @@ -13,12 +13,12 @@ #include #include -#include #include #include #include #include #include +#include #include class SrsFormat; diff --git a/trunk/src/app/srs_app_rtsp_conn.cpp b/trunk/src/app/srs_app_rtsp_conn.cpp index 889a8c84639..f9d449efd55 100644 --- a/trunk/src/app/srs_app_rtsp_conn.cpp +++ b/trunk/src/app/srs_app_rtsp_conn.cpp @@ -14,9 +14,9 @@ using namespace std; #include #include -#include #include #include +#include #include #include #include @@ -24,8 +24,8 @@ using namespace std; #include #include #include +#include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_rtsp_conn.hpp b/trunk/src/app/srs_app_rtsp_conn.hpp index a533f9b76b6..8cf1e66db86 100644 --- a/trunk/src/app/srs_app_rtsp_conn.hpp +++ b/trunk/src/app/srs_app_rtsp_conn.hpp @@ -7,7 +7,6 @@ #ifndef SRS_APP_RTSP_CONN_HPP #define SRS_APP_RTSP_CONN_HPP -#include #include #include #include @@ -38,7 +37,7 @@ class SrsRtspPlayStream : public ISrsCoroutineHandler, public ISrsRtcSourceChang { private: SrsContextId cid_; - SrsFastCoroutine *trd_; + ISrsCoroutine *trd_; SrsRtspConnection *session_; private: @@ -106,7 +105,7 @@ class SrsRtspConnection : public ISrsResource, public ISrsDisposingHandler, publ ISrsResourceManager *manager_; // Each connection start a green thread, // when thread stop, the connection will be delete by server. - SrsCoroutine *trd_; + ISrsCoroutine *trd_; // The ip and port of client. std::string ip_; int port_; diff --git a/trunk/src/app/srs_app_rtsp_source.hpp b/trunk/src/app/srs_app_rtsp_source.hpp index 34ac420ebe3..1ece97992e8 100644 --- a/trunk/src/app/srs_app_rtsp_source.hpp +++ b/trunk/src/app/srs_app_rtsp_source.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index ac69b1a651a..cd7f802bc97 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -21,10 +21,8 @@ using namespace std; #include #include #include -#include #include #include -#include #include #include #include @@ -32,26 +30,28 @@ using namespace std; #include #include #include -#include #include #include #include #include -#include #include #include #include -#include +#include #include #include #include #include #include +#include #include #include +#include #include +#include #include #include +#include #ifdef SRS_GB28181 #include #endif diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 090cfd33d0c..7392b2200d9 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -12,15 +12,15 @@ #include #include -#include #include -#include #include #include -#include +#include #include #include #include +#include +#include #include #include @@ -269,7 +269,7 @@ class SrsSignalManager : public ISrsCoroutineHandler private: SrsServer *server_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; public: SrsSignalManager(SrsServer *s); @@ -296,7 +296,7 @@ class SrsInotifyWorker : public ISrsCoroutineHandler { private: SrsServer *server_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; srs_netfd_t inotify_fd_; public: diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index f9270f84e79..739efccb024 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -10,9 +10,8 @@ using namespace std; #include #include -#include #include -#include +#include #include #include #include @@ -20,6 +19,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index 7a92266e741..f1726284dfc 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -12,11 +12,11 @@ #include #include -#include #include -#include #include +#include #include +#include class SrsBuffer; class SrsLiveSource; @@ -73,7 +73,7 @@ class SrsSrtRecvThread : public ISrsCoroutineHandler private: SrsSrtConnection *srt_conn_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; srs_error_t recv_err_; }; @@ -132,7 +132,7 @@ class SrsMpegtsSrtConn : public ISrsConnection, public ISrsStartable, public ISr SrsNetworkKbps *kbps_; std::string ip_; int port_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; ISrsRequest *req_; SrsSharedPtr srt_source_; diff --git a/trunk/src/app/srs_app_srt_listener.hpp b/trunk/src/app/srs_app_srt_listener.hpp index 29c53755645..dcec29cce51 100644 --- a/trunk/src/app/srs_app_srt_listener.hpp +++ b/trunk/src/app/srs_app_srt_listener.hpp @@ -31,7 +31,7 @@ class SrsSrtListener : public ISrsCoroutineHandler private: srs_srt_t lfd_; SrsSrtSocket *srt_skt_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; private: ISrsSrtHandler *handler_; diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index fefa1a7b317..1b3dc1be36e 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -9,8 +9,8 @@ using namespace std; #include +#include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_srt_server.hpp b/trunk/src/app/srs_app_srt_server.hpp index 4a85caba105..8a74713383c 100644 --- a/trunk/src/app/srs_app_srt_server.hpp +++ b/trunk/src/app/srs_app_srt_server.hpp @@ -71,7 +71,7 @@ class SrsSrtEventLoop : public ISrsCoroutineHandler private: ISrsSrtPoller *srt_poller_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; }; // SrsSrtEventLoop is global singleton instance. diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 6e993862b51..db70fce8a35 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -9,12 +9,12 @@ #include using namespace std; -#include -#include +#include #include #include #include #include +#include #include #include #include diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp index 12a71e6c25b..3df46fa8557 100644 --- a/trunk/src/app/srs_app_srt_source.hpp +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -12,9 +12,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/trunk/src/app/srs_app_srt_utility.cpp b/trunk/src/app/srs_app_srt_utility.cpp deleted file mode 100644 index 2c194abaede..00000000000 --- a/trunk/src/app/srs_app_srt_utility.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#include - -using namespace std; - -#include -#include -#include -#include -#include -#include - -// See streamid of https://github.com/ossrs/srs/issues/2893 -// TODO: FIMXE: We should parse SRT streamid to URL object, rather than a HTTP url subpath. -bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::string &vhost, std::string &url_subpath) -{ - mode = SrtModePull; - - size_t pos = streamid.find("#!::"); - if (pos != 0) { - pos = streamid.find("/"); - if (pos == streamid.npos) { - url_subpath = _srs_config->get_default_app_name() + "/" + streamid; - return true; - } - url_subpath = streamid; - return true; - } - - // SRT url supports multiple QueryStrings, which are passed to RTMP to realize authentication and other capabilities - //@see https://github.com/ossrs/srs/issues/2893 - std::string params; - std::string real_streamid; - real_streamid = streamid.substr(4); - - // Compatible with previous auth querystring, like this one: - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream?secret=xxx,m=publish - real_streamid = srs_strings_replace(real_streamid, "?", ","); - - std::map query; - srs_net_url_parse_query(real_streamid, query); - for (std::map::iterator it = query.begin(); it != query.end(); ++it) { - if (it->first == "h") { - std::string host = it->second; - - size_t r0 = host.find("/"); - size_t r1 = host.rfind("/"); - if (r0 != std::string::npos && r0 != std::string::npos) { - // Compatible with previous style, see https://github.com/ossrs/srs/issues/2893#compatible - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=publish - // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=request - // srt://127.0.0.1:10080?streamid=#!::h=srs.srt.com.cn/live/livestream,m=publish - if (r0 != r1) { - // We got vhost in host. - url_subpath = host.substr(r0 + 1); - host = host.substr(0, r0); - - params.append("vhost="); - params.append(host); - params.append("&"); - vhost = host; - } else { - // Only stream in host. - url_subpath = host; - } - } else { - // New URL style, see https://github.com/ossrs/srs/issues/2893#solution - // srt://host.com:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 - // srt://1.2.3.4:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 - // srt://1.2.3.4:10080?streamid=#!::r=app/stream,key1=value1,key2=value2 - params.append("vhost="); - params.append(host); - params.append("&"); - vhost = host; - } - } else if (it->first == "r") { - url_subpath = it->second; - } else if (it->first == "m") { - std::string mode_str = it->second; // support m=publish or m=request - std::transform(it->second.begin(), it->second.end(), mode_str.begin(), ::tolower); - if (mode_str == "publish") { - mode = SrtModePush; - } else if (mode_str == "request") { - mode = SrtModePull; - } else { - srs_warn("unknown mode_str:%s", mode_str.c_str()); - return false; - } - } else { - params.append(it->first); - params.append("="); - params.append(it->second); - params.append("&"); - } - } - - if (url_subpath.empty()) { - return false; - } - - if (!params.empty()) { - url_subpath.append("?"); - url_subpath.append(params); - url_subpath = url_subpath.substr(0, url_subpath.length() - 1); // remove last '&' - } - - return true; -} - -bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request) -{ - string url_subpath = ""; - bool ret = srs_srt_streamid_info(streamid, mode, request->vhost_, url_subpath); - if (!ret) { - return ret; - } - - size_t pos = url_subpath.find("/"); - string stream_with_params = ""; - if (pos == string::npos) { - request->app_ = _srs_config->get_default_app_name(); - stream_with_params = url_subpath; - } else { - request->app_ = url_subpath.substr(0, pos); - stream_with_params = url_subpath.substr(pos + 1); - } - - pos = stream_with_params.find("?"); - if (pos == string::npos) { - request->stream_ = stream_with_params; - } else { - request->stream_ = stream_with_params.substr(0, pos); - request->param_ = stream_with_params.substr(pos + 1); - } - - request->host_ = srs_get_public_internet_address(); - if (request->vhost_.empty()) - request->vhost_ = request->host_; - request->tcUrl_ = srs_net_url_encode_tcurl("srt", request->host_, request->vhost_, request->app_, request->port_); - - return ret; -} diff --git a/trunk/src/app/srs_app_srt_utility.hpp b/trunk/src/app/srs_app_srt_utility.hpp deleted file mode 100644 index c52fa74efb5..00000000000 --- a/trunk/src/app/srs_app_srt_utility.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_APP_SRT_UTILITY_HPP -#define SRS_APP_SRT_UTILITY_HPP - -#include - -#include - -#include -#include -#include - -class ISrsRequest; - -enum SrtMode { - SrtModePull = 1, - SrtModePush = 2, -}; - -// Get SRT streamid info. -extern bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::string &vhost, std::string &url_subpath); - -// SRT streamid to request. -extern bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request); - -#endif diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index ac8966d086a..bc9695fb565 100644 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -14,54 +14,6 @@ using namespace std; #include #include -ISrsCoroutineHandler::ISrsCoroutineHandler() -{ -} - -ISrsCoroutineHandler::~ISrsCoroutineHandler() -{ -} - -ISrsStartable::ISrsStartable() -{ -} - -ISrsStartable::~ISrsStartable() -{ -} - -ISrsInterruptable::ISrsInterruptable() -{ -} - -ISrsInterruptable::~ISrsInterruptable() -{ -} - -ISrsContextIdSetter::ISrsContextIdSetter() -{ -} - -ISrsContextIdSetter::~ISrsContextIdSetter() -{ -} - -ISrsContextIdGetter::ISrsContextIdGetter() -{ -} - -ISrsContextIdGetter::~ISrsContextIdGetter() -{ -} - -SrsCoroutine::SrsCoroutine() -{ -} - -SrsCoroutine::~SrsCoroutine() -{ -} - SrsDummyCoroutine::SrsDummyCoroutine() { } diff --git a/trunk/src/app/srs_app_st.hpp b/trunk/src/app/srs_app_st.hpp index 356bdaf8d3c..858ee697937 100644 --- a/trunk/src/app/srs_app_st.hpp +++ b/trunk/src/app/srs_app_st.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -20,102 +21,9 @@ class SrsFastCoroutine; class SrsExecutorCoroutine; -// Each ST-coroutine must implements this interface, -// to do the cycle job and handle some events. -// -// Thread do a job then terminated normally, it's a SrsOneCycleThread: -// class SrsOneCycleThread : public ISrsCoroutineHandler { -// public: SrsCoroutine trd; -// public: virtual srs_error_t cycle() { -// // Do something, then return this cycle and thread terminated normally. -// } -// }; -// -// Thread has its inside loop, such as the RTMP receive thread: -// class SrsReceiveThread : public ISrsCoroutineHandler { -// public: SrsCoroutine* trd; -// public: virtual srs_error_t cycle() { -// while (true) { -// // Check whether thread interrupted. -// if ((err = trd->pull()) != srs_success) { -// return err; -// } -// // Do something, such as st_read() packets, it'll be wakeup -// // when user stop or interrupt the thread. -// } -// } -// }; -class ISrsCoroutineHandler -{ -public: - ISrsCoroutineHandler(); - virtual ~ISrsCoroutineHandler(); - -public: - // Do the work. The ST-coroutine will terminated normally if it returned. - // @remark If the cycle has its own loop, it must check the thread pull. - virtual srs_error_t cycle() = 0; -}; - -// Start the object, generally a coroutine. -class ISrsStartable -{ -public: - ISrsStartable(); - virtual ~ISrsStartable(); - -public: - virtual srs_error_t start() = 0; -}; - -// Allow user to interrupt the coroutine, for example, to stop it. -class ISrsInterruptable -{ -public: - ISrsInterruptable(); - virtual ~ISrsInterruptable(); - -public: - virtual void interrupt() = 0; - virtual srs_error_t pull() = 0; -}; - -// Get the context id. -class ISrsContextIdSetter -{ -public: - ISrsContextIdSetter(); - virtual ~ISrsContextIdSetter(); - -public: - virtual void set_cid(const SrsContextId &cid) = 0; -}; - -// Set the context id. -class ISrsContextIdGetter -{ -public: - ISrsContextIdGetter(); - virtual ~ISrsContextIdGetter(); - -public: - virtual const SrsContextId &cid() = 0; -}; - -// The coroutine object. -class SrsCoroutine : public ISrsStartable, public ISrsInterruptable, public ISrsContextIdSetter, public ISrsContextIdGetter -{ -public: - SrsCoroutine(); - virtual ~SrsCoroutine(); - -public: - virtual void stop() = 0; -}; - // An empty coroutine, user can default to this object before create any real coroutine. // @see https://github.com/ossrs/srs/pull/908 -class SrsDummyCoroutine : public SrsCoroutine +class SrsDummyCoroutine : public ISrsCoroutine { private: SrsContextId cid_; @@ -145,7 +53,7 @@ class SrsDummyCoroutine : public SrsCoroutine // https://github.com/ossrs/state-threads/blob/st-1.9/README#L115 // @remark We always create joinable thread, so we must join it or memory leak, // Please read https://github.com/ossrs/srs/issues/78 -class SrsSTCoroutine : public SrsCoroutine +class SrsSTCoroutine : public ISrsCoroutine { private: SrsFastCoroutine *impl_; @@ -186,7 +94,7 @@ class SrsSTCoroutine : public SrsCoroutine }; // High performance coroutine. -class SrsFastCoroutine +class SrsFastCoroutine : public ISrsCoroutine { private: std::string name_; @@ -297,7 +205,7 @@ class SrsExecutorCoroutine : public ISrsResource, public ISrsStartable, public I ISrsExecutorHandler *callback_; private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; public: SrsExecutorCoroutine(ISrsResourceManager *m, ISrsResource *r, ISrsCoroutineHandler *h, ISrsExecutorHandler *cb); diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 769b8bd731c..ec49f5b6056 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -11,14 +11,13 @@ using namespace std; #include -#include +#include #include #include #include #include #include -#include #include #include diff --git a/trunk/src/app/srs_app_stream_bridge.cpp b/trunk/src/app/srs_app_stream_bridge.cpp index 20423c5e2ac..58927921dcc 100644 --- a/trunk/src/app/srs_app_stream_bridge.cpp +++ b/trunk/src/app/srs_app_stream_bridge.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index e021e227053..fd05f720604 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -26,11 +26,11 @@ using namespace std; #include #include #include +#include #include #include #include #include -#include // the longest time to wait for a process to quit. #define SRS_PROCESS_QUIT_TIMEOUT_MS 1000 diff --git a/trunk/src/core/srs_core_time.cpp b/trunk/src/core/srs_core_time.cpp index 68ba596aa35..fbf06771524 100644 --- a/trunk/src/core/srs_core_time.cpp +++ b/trunk/src/core/srs_core_time.cpp @@ -14,3 +14,11 @@ srs_utime_t srs_time_since(srs_utime_t start, srs_utime_t end) return end - start; } + +ISrsTime::ISrsTime() +{ +} + +ISrsTime::~ISrsTime() +{ +} diff --git a/trunk/src/core/srs_core_time.hpp b/trunk/src/core/srs_core_time.hpp index 9da7e71d80b..6785729d74f 100644 --- a/trunk/src/core/srs_core_time.hpp +++ b/trunk/src/core/srs_core_time.hpp @@ -43,4 +43,15 @@ extern srs_utime_t srs_time_since_startup(); // A daemon st-thread updates it. extern srs_utime_t srs_time_now_realtime(); +// The time interface. +class ISrsTime +{ +public: + ISrsTime(); + virtual ~ISrsTime(); + +public: + virtual void usleep(srs_utime_t duration) = 0; +}; + #endif diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index a9c7b1284ab..3f47aea396a 100644 --- a/trunk/src/core/srs_core_version7.hpp +++ b/trunk/src/core/srs_core_version7.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 7 #define VERSION_MINOR 0 -#define VERSION_REVISION 85 +#define VERSION_REVISION 86 #endif \ No newline at end of file diff --git a/trunk/src/kernel/srs_kernel_factory.cpp b/trunk/src/kernel/srs_kernel_factory.cpp new file mode 100644 index 00000000000..8720858bd1a --- /dev/null +++ b/trunk/src/kernel/srs_kernel_factory.cpp @@ -0,0 +1,23 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#include + +ISrsConfig::ISrsConfig() +{ +} + +ISrsConfig::~ISrsConfig() +{ +} + +ISrsKernelFactory::ISrsKernelFactory() +{ +} + +ISrsKernelFactory::~ISrsKernelFactory() +{ +} diff --git a/trunk/src/kernel/srs_kernel_factory.hpp b/trunk/src/kernel/srs_kernel_factory.hpp new file mode 100644 index 00000000000..78ecaa1c759 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_factory.hpp @@ -0,0 +1,45 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_KERNEL_FACTORY_HPP +#define SRS_KERNEL_FACTORY_HPP + +#include + +#include +#include + +#include + +// The config for kernel and protocol objects. +class ISrsConfig +{ +public: + ISrsConfig(); + virtual ~ISrsConfig(); + +public: + virtual srs_utime_t get_pithy_print() = 0; + virtual std::string get_default_app_name() = 0; +}; + +// The factory to create kernel objects. +class ISrsKernelFactory +{ +public: + ISrsKernelFactory(); + virtual ~ISrsKernelFactory(); + +public: + virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid) = 0; + virtual ISrsTime *create_time() = 0; + virtual ISrsConfig *create_config() = 0; + virtual ISrsCond *create_cond() = 0; +}; + +extern ISrsKernelFactory *_srs_kernel_factory; + +#endif diff --git a/trunk/src/app/srs_app_hourglass.cpp b/trunk/src/kernel/srs_kernel_hourglass.cpp similarity index 92% rename from trunk/src/app/srs_app_hourglass.cpp rename to trunk/src/kernel/srs_kernel_hourglass.cpp index dca669f8241..e43b1b03743 100644 --- a/trunk/src/app/srs_app_hourglass.cpp +++ b/trunk/src/kernel/srs_kernel_hourglass.cpp @@ -4,17 +4,18 @@ // SPDX-License-Identifier: MIT // -#include +#include #include using namespace std; +#include #include +#include +#include #include #include -#include - SrsPps *_srs_pps_timer = NULL; SrsPps *_srs_pps_conn = NULL; SrsPps *_srs_pps_pub = NULL; @@ -43,12 +44,14 @@ SrsHourGlass::SrsHourGlass(string label, ISrsHourGlass *h, srs_utime_t resolutio handler_ = h; resolution_ = resolution; total_elapse_ = 0; - trd_ = new SrsSTCoroutine("timer-" + label, this, _srs_context->get_id()); + trd_ = _srs_kernel_factory->create_coroutine("timer-" + label, this, _srs_context->get_id()); + time_ = _srs_kernel_factory->create_time(); } SrsHourGlass::~SrsHourGlass() { srs_freep(trd_); + srs_freep(time_); } srs_error_t SrsHourGlass::start() @@ -119,7 +122,7 @@ srs_error_t SrsHourGlass::cycle() // TODO: FIXME: Maybe we should use wallclock. total_elapse_ += resolution_; - srs_usleep(resolution_); + time_->usleep(resolution_); } return err; @@ -136,12 +139,14 @@ ISrsFastTimer::~ISrsFastTimer() SrsFastTimer::SrsFastTimer(std::string label, srs_utime_t interval) { interval_ = interval; - trd_ = new SrsSTCoroutine(label, this, _srs_context->get_id()); + trd_ = _srs_kernel_factory->create_coroutine(label, this, _srs_context->get_id()); + time_ = _srs_kernel_factory->create_time(); } SrsFastTimer::~SrsFastTimer() { srs_freep(trd_); + srs_freep(time_); } srs_error_t SrsFastTimer::start() @@ -189,7 +194,7 @@ srs_error_t SrsFastTimer::cycle() } } - srs_usleep(interval_); + time_->usleep(interval_); } return err; @@ -197,10 +202,12 @@ srs_error_t SrsFastTimer::cycle() SrsClockWallMonitor::SrsClockWallMonitor() { + time_ = _srs_kernel_factory->create_time(); } SrsClockWallMonitor::~SrsClockWallMonitor() { + srs_freep(time_); } srs_error_t SrsClockWallMonitor::on_timer(srs_utime_t interval) diff --git a/trunk/src/app/srs_app_hourglass.hpp b/trunk/src/kernel/srs_kernel_hourglass.hpp similarity index 94% rename from trunk/src/app/srs_app_hourglass.hpp rename to trunk/src/kernel/srs_kernel_hourglass.hpp index ad2e5fdfc9d..e0c556c1881 100644 --- a/trunk/src/app/srs_app_hourglass.hpp +++ b/trunk/src/kernel/srs_kernel_hourglass.hpp @@ -4,18 +4,18 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_HOURGLASS_HPP -#define SRS_APP_HOURGLASS_HPP +#ifndef SRS_KERNEL_HOURGLASS_HPP +#define SRS_KERNEL_HOURGLASS_HPP #include -#include +#include #include #include #include -class SrsCoroutine; +class ISrsCoroutine; // The handler for the tick. class ISrsHourGlass @@ -57,9 +57,10 @@ class SrsHourGlass : public ISrsCoroutineHandler { private: std::string label_; - SrsCoroutine *trd_; + ISrsCoroutine *trd_; ISrsHourGlass *handler_; srs_utime_t resolution_; + ISrsTime *time_; // The ticks: // key: the event of tick. // value: the interval of tick. @@ -112,9 +113,10 @@ class ISrsFastTimer class SrsFastTimer : public ISrsCoroutineHandler { private: - SrsCoroutine *trd_; + ISrsCoroutine *trd_; srs_utime_t interval_; std::vector handlers_; + ISrsTime *time_; public: SrsFastTimer(std::string label, srs_utime_t interval); @@ -136,6 +138,9 @@ class SrsFastTimer : public ISrsCoroutineHandler // To monitor the system wall clock timer deviation. class SrsClockWallMonitor : public ISrsFastTimer { +private: + ISrsTime *time_; + public: SrsClockWallMonitor(); virtual ~SrsClockWallMonitor(); diff --git a/trunk/src/kernel/srs_kernel_io.cpp b/trunk/src/kernel/srs_kernel_io.cpp index b5706f37ad6..b9892953d3a 100644 --- a/trunk/src/kernel/srs_kernel_io.cpp +++ b/trunk/src/kernel/srs_kernel_io.cpp @@ -61,3 +61,11 @@ ISrsWriteSeeker::ISrsWriteSeeker() ISrsWriteSeeker::~ISrsWriteSeeker() { } + +ISrsProtocolStatistic::ISrsProtocolStatistic() +{ +} + +ISrsProtocolStatistic::~ISrsProtocolStatistic() +{ +} diff --git a/trunk/src/kernel/srs_kernel_io.hpp b/trunk/src/kernel/srs_kernel_io.hpp index 305db30cc07..302319b8abf 100644 --- a/trunk/src/kernel/srs_kernel_io.hpp +++ b/trunk/src/kernel/srs_kernel_io.hpp @@ -119,4 +119,20 @@ class ISrsWriteSeeker : public ISrsWriter, public ISrsSeeker virtual ~ISrsWriteSeeker(); }; +/** + * Get the statistic of channel. + */ +class ISrsProtocolStatistic +{ +public: + ISrsProtocolStatistic(); + virtual ~ISrsProtocolStatistic(); + // For protocol +public: + // Get the total recv bytes over underlay fd. + virtual int64_t get_recv_bytes() = 0; + // Get the total send bytes over underlay fd. + virtual int64_t get_send_bytes() = 0; +}; + #endif diff --git a/trunk/src/kernel/srs_kernel_kbps.cpp b/trunk/src/kernel/srs_kernel_kbps.cpp index 26b414e56f6..24c9c979877 100644 --- a/trunk/src/kernel/srs_kernel_kbps.cpp +++ b/trunk/src/kernel/srs_kernel_kbps.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -546,3 +547,282 @@ void srs_global_rtc_update(SrsKbsRtcStats *stats) fid_desc = buf; } } + +SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c) +{ + clk_ = c; + starttime_ = 0; + bytes_ = 0; +} + +SrsKbpsSlice::~SrsKbpsSlice() +{ +} + +void SrsKbpsSlice::sample() +{ + srs_utime_t now = clk_->now(); + + if (sample_30s_.time_ < 0) { + sample_30s_.update(bytes_, now, 0); + } + if (sample_1m_.time_ < 0) { + sample_1m_.update(bytes_, now, 0); + } + if (sample_5m_.time_ < 0) { + sample_5m_.update(bytes_, now, 0); + } + if (sample_60m_.time_ < 0) { + sample_60m_.update(bytes_, now, 0); + } + + if (now - sample_30s_.time_ >= 30 * SRS_UTIME_SECONDS) { + int kbps = (int)((bytes_ - sample_30s_.total_) * 8 / srsu2ms(now - sample_30s_.time_)); + sample_30s_.update(bytes_, now, kbps); + } + if (now - sample_1m_.time_ >= 60 * SRS_UTIME_SECONDS) { + int kbps = (int)((bytes_ - sample_1m_.total_) * 8 / srsu2ms(now - sample_1m_.time_)); + sample_1m_.update(bytes_, now, kbps); + } + if (now - sample_5m_.time_ >= 300 * SRS_UTIME_SECONDS) { + int kbps = (int)((bytes_ - sample_5m_.total_) * 8 / srsu2ms(now - sample_5m_.time_)); + sample_5m_.update(bytes_, now, kbps); + } + if (now - sample_60m_.time_ >= 3600 * SRS_UTIME_SECONDS) { + int kbps = (int)((bytes_ - sample_60m_.total_) * 8 / srsu2ms(now - sample_60m_.time_)); + sample_60m_.update(bytes_, now, kbps); + } +} + +ISrsKbpsDelta::ISrsKbpsDelta() +{ +} + +ISrsKbpsDelta::~ISrsKbpsDelta() +{ +} + +SrsEphemeralDelta::SrsEphemeralDelta() +{ + in_ = out_ = 0; +} + +SrsEphemeralDelta::~SrsEphemeralDelta() +{ +} + +void SrsEphemeralDelta::add_delta(int64_t in, int64_t out) +{ + in_ += in; + out_ += out; +} + +void SrsEphemeralDelta::remark(int64_t *in, int64_t *out) +{ + if (in) + *in = in_; + if (out) + *out = out_; + in_ = out_ = 0; +} + +SrsNetworkDelta::SrsNetworkDelta() +{ + in_ = out_ = NULL; + in_base_ = in_delta_ = 0; + out_base_ = out_delta_ = 0; +} + +SrsNetworkDelta::~SrsNetworkDelta() +{ +} + +void SrsNetworkDelta::set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out) +{ + if (in_) { + in_delta_ += in_->get_recv_bytes() - in_base_; + } + if (in) { + in_base_ = in->get_recv_bytes(); + in_delta_ += in_base_; + } + in_ = in; + + if (out_) { + out_delta_ += out_->get_send_bytes() - out_base_; + } + if (out) { + out_base_ = out->get_send_bytes(); + out_delta_ += out_base_; + } + out_ = out; +} + +void SrsNetworkDelta::remark(int64_t *in, int64_t *out) +{ + if (in_) { + in_delta_ += in_->get_recv_bytes() - in_base_; + in_base_ = in_->get_recv_bytes(); + } + if (out_) { + out_delta_ += out_->get_send_bytes() - out_base_; + out_base_ = out_->get_send_bytes(); + } + + *in = in_delta_; + *out = out_delta_; + in_delta_ = out_delta_ = 0; +} + +SrsKbps::SrsKbps(SrsWallClock *c) +{ + clk_ = c ? c : _srs_clock; + is_ = new SrsKbpsSlice(clk_); + os_ = new SrsKbpsSlice(clk_); +} + +SrsKbps::~SrsKbps() +{ + srs_freep(is_); + srs_freep(os_); +} + +int SrsKbps::get_send_kbps() +{ + int duration = srsu2ms(clk_->now() - is_->starttime_); + if (duration <= 0) { + return 0; + } + + int64_t bytes = get_send_bytes(); + return (int)(bytes * 8 / duration); +} + +int SrsKbps::get_recv_kbps() +{ + int duration = srsu2ms(clk_->now() - os_->starttime_); + if (duration <= 0) { + return 0; + } + + int64_t bytes = get_recv_bytes(); + return (int)(bytes * 8 / duration); +} + +int SrsKbps::get_send_kbps_30s() +{ + return os_->sample_30s_.rate_; +} + +int SrsKbps::get_recv_kbps_30s() +{ + return is_->sample_30s_.rate_; +} + +int SrsKbps::get_send_kbps_5m() +{ + return os_->sample_5m_.rate_; +} + +int SrsKbps::get_recv_kbps_5m() +{ + return is_->sample_5m_.rate_; +} + +void SrsKbps::add_delta(ISrsKbpsDelta *delta) +{ + if (!delta) + return; + + int64_t in, out; + delta->remark(&in, &out); + add_delta(in, out); +} + +void SrsKbps::add_delta(int64_t in, int64_t out) +{ + // update the total bytes + is_->bytes_ += in; + os_->bytes_ += out; + + // we donot sample, please use sample() to do resample. +} + +void SrsKbps::sample() +{ + is_->sample(); + os_->sample(); +} + +int64_t SrsKbps::get_send_bytes() +{ + return os_->bytes_; +} + +int64_t SrsKbps::get_recv_bytes() +{ + return is_->bytes_; +} + +SrsNetworkKbps::SrsNetworkKbps(SrsWallClock *clock) +{ + delta_ = new SrsNetworkDelta(); + kbps_ = new SrsKbps(clock); +} + +SrsNetworkKbps::~SrsNetworkKbps() +{ + srs_freep(kbps_); + srs_freep(delta_); +} + +void SrsNetworkKbps::set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out) +{ + delta_->set_io(in, out); +} + +void SrsNetworkKbps::sample() +{ + kbps_->add_delta(delta_); + kbps_->sample(); +} + +int SrsNetworkKbps::get_send_kbps() +{ + return kbps_->get_send_kbps(); +} + +int SrsNetworkKbps::get_recv_kbps() +{ + return kbps_->get_recv_kbps(); +} + +int SrsNetworkKbps::get_send_kbps_30s() +{ + return kbps_->get_send_kbps_30s(); +} + +int SrsNetworkKbps::get_recv_kbps_30s() +{ + return kbps_->get_recv_kbps_30s(); +} + +int SrsNetworkKbps::get_send_kbps_5m() +{ + return kbps_->get_send_kbps_5m(); +} + +int SrsNetworkKbps::get_recv_kbps_5m() +{ + return kbps_->get_recv_kbps_5m(); +} + +int64_t SrsNetworkKbps::get_send_bytes() +{ + return kbps_->get_send_bytes(); +} + +int64_t SrsNetworkKbps::get_recv_bytes() +{ + return kbps_->get_recv_bytes(); +} diff --git a/trunk/src/kernel/srs_kernel_kbps.hpp b/trunk/src/kernel/srs_kernel_kbps.hpp index 32f86105df3..745099116a2 100644 --- a/trunk/src/kernel/srs_kernel_kbps.hpp +++ b/trunk/src/kernel/srs_kernel_kbps.hpp @@ -14,6 +14,7 @@ #include class SrsWallClock; +class ISrsProtocolStatistic; // A sample for rate-based stat, such as kbps or kps. class SrsRateSample @@ -230,4 +231,171 @@ class SrsKbsRtcStats // Update the global rtc statistics variables void srs_global_rtc_update(SrsKbsRtcStats *stats); +/** + * The slice of kbps statistic, for input or output. + */ +class SrsKbpsSlice +{ +private: + SrsWallClock *clk_; + +public: + // session startup bytes + // @remark, use total_bytes() to get the total bytes of slice. + int64_t bytes_; + // slice starttime, the first time to record bytes. + srs_utime_t starttime_; + // samples + SrsRateSample sample_30s_; + SrsRateSample sample_1m_; + SrsRateSample sample_5m_; + SrsRateSample sample_60m_; + +public: + SrsKbpsSlice(SrsWallClock *c); + virtual ~SrsKbpsSlice(); + +public: + // Resample the slice to calculate the kbps. + virtual void sample(); +}; + +/** + * The interface which provices delta of bytes. For example, we got a delta from a TCP client: + * ISrsKbpsDelta* delta = ...; + * Now, we can add delta simple to a kbps: + * kbps->add_delta(delta); + * Or by multiple kbps: + * int64_t in, out; + * delta->remark(&in, &out); + * kbps1->add_delta(in, out); + * kbpsN->add_delta(in, out); + * Then you're able to use the kbps object. + */ +class ISrsKbpsDelta +{ +public: + ISrsKbpsDelta(); + virtual ~ISrsKbpsDelta(); + +public: + // Resample to get the value of delta bytes. + // @remark If no delta bytes, both in and out will be set to 0. + virtual void remark(int64_t *in, int64_t *out) = 0; +}; + +// A delta data source for SrsKbps, used in ephemeral case, for example, UDP server to increase stat when received or +// sent out each UDP packet. +class SrsEphemeralDelta : public ISrsKbpsDelta +{ +private: + uint64_t in_; + uint64_t out_; + +public: + SrsEphemeralDelta(); + virtual ~SrsEphemeralDelta(); + +public: + virtual void add_delta(int64_t in, int64_t out); + // Interface ISrsKbpsDelta. +public: + virtual void remark(int64_t *in, int64_t *out); +}; + +// A network delta data source for SrsKbps. +class SrsNetworkDelta : public ISrsKbpsDelta +{ +private: + ISrsProtocolStatistic *in_; + ISrsProtocolStatistic *out_; + uint64_t in_base_; + uint64_t in_delta_; + uint64_t out_base_; + uint64_t out_delta_; + +public: + SrsNetworkDelta(); + virtual ~SrsNetworkDelta(); + +public: + // Switch the under-layer network io, we use the bytes as a fresh delta. + virtual void set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out); + // Interface ISrsKbpsDelta. +public: + virtual void remark(int64_t *in, int64_t *out); +}; + +/** + * To statistic the kbps. For example, we got a set of connections and add the total delta: + * SrsKbps* kbps = ...; + * for conn in connections: + * kbps->add_delta(conn->delta()) // Which return an ISrsKbpsDelta object. + * Then we sample and got the total kbps: + * kbps->sample() + * kbps->get_xxx_kbps(). + */ +class SrsKbps +{ +private: + SrsKbpsSlice *is_; + SrsKbpsSlice *os_; + SrsWallClock *clk_; + +public: + // Note that we won't free the clock c. + SrsKbps(SrsWallClock *c = NULL); + virtual ~SrsKbps(); + +public: + // Get total average kbps. + virtual int get_send_kbps(); + virtual int get_recv_kbps(); + // Get the average kbps in 30s. + virtual int get_send_kbps_30s(); + virtual int get_recv_kbps_30s(); + // Get the average kbps in 5m or 300s. + virtual int get_send_kbps_5m(); + virtual int get_recv_kbps_5m(); + +public: + // Add delta to kbps. Please call sample() after all deltas are added to kbps. + virtual void add_delta(int64_t in, int64_t out); + virtual void add_delta(ISrsKbpsDelta *delta); + // Sample the kbps to get the kbps in N seconds. + virtual void sample(); + +public: + virtual int64_t get_send_bytes(); + virtual int64_t get_recv_bytes(); +}; + +// A sugar to use SrsNetworkDelta and SrsKbps. +class SrsNetworkKbps +{ +private: + SrsNetworkDelta *delta_; + SrsKbps *kbps_; + +public: + SrsNetworkKbps(SrsWallClock *c = NULL); + virtual ~SrsNetworkKbps(); + +public: + virtual void set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out); + virtual void sample(); + +public: + virtual int get_send_kbps(); + virtual int get_recv_kbps(); + virtual int get_send_kbps_30s(); + virtual int get_recv_kbps_30s(); + virtual int get_send_kbps_5m(); + virtual int get_recv_kbps_5m(); + +public: + virtual int64_t get_send_bytes(); + virtual int64_t get_recv_bytes(); +}; + #endif diff --git a/trunk/src/kernel/srs_kernel_log.cpp b/trunk/src/kernel/srs_kernel_log.cpp index 0e9cc82f74d..d8ae0c1fd43 100644 --- a/trunk/src/kernel/srs_kernel_log.cpp +++ b/trunk/src/kernel/srs_kernel_log.cpp @@ -101,6 +101,16 @@ ISrsContext::~ISrsContext() { } +impl_SrsContextRestore::impl_SrsContextRestore(SrsContextId cid) +{ + cid_ = cid; +} + +impl_SrsContextRestore::~impl_SrsContextRestore() +{ + _srs_context->set_id(cid_); +} + void srs_logger_impl(SrsLogLevel level, const char *tag, const SrsContextId &context_id, const char *fmt, ...) { if (!_srs_log) diff --git a/trunk/src/kernel/srs_kernel_log.hpp b/trunk/src/kernel/srs_kernel_log.hpp index 95df3c76db5..45042f7fa87 100644 --- a/trunk/src/kernel/srs_kernel_log.hpp +++ b/trunk/src/kernel/srs_kernel_log.hpp @@ -18,6 +18,14 @@ #include +// For log TAGs. +#define TAG_MAIN "MAIN" +#define TAG_MAYBE "MAYBE" +#define TAG_DTLS_ALERT "DTLS_ALERT" +#define TAG_DTLS_HANG "DTLS_HANG" +#define TAG_RESOURCE_UNSUB "RESOURCE_UNSUB" +#define TAG_LARGE_TIMER "LARGE_TIMER" + // The log level, see https://github.com/apache/logging-log4j2/blob/release-2.x/log4j-api/src/main/java/org/apache/logging/log4j/Level.java // Please note that the enum name might not be the string, to keep compatible with previous definition. enum SrsLogLevel { @@ -80,6 +88,20 @@ class ISrsContext virtual const SrsContextId &set_id(const SrsContextId &v) = 0; }; +// The context restore stores the context and restore it when done. +// Usage: +// SrsContextRestore(_srs_context->get_id()); +#define SrsContextRestore(cid) impl_SrsContextRestore _context_restore_instance(cid) +class impl_SrsContextRestore +{ +private: + SrsContextId cid_; + +public: + impl_SrsContextRestore(SrsContextId cid); + virtual ~impl_SrsContextRestore(); +}; + // @global User must implements the LogContext and define a global instance. extern ISrsContext *_srs_context; diff --git a/trunk/src/app/srs_app_pithy_print.cpp b/trunk/src/kernel/srs_kernel_pithy_print.cpp similarity index 97% rename from trunk/src/app/srs_app_pithy_print.cpp rename to trunk/src/kernel/srs_kernel_pithy_print.cpp index e97cd31aa2d..fcedba495a9 100644 --- a/trunk/src/app/srs_app_pithy_print.cpp +++ b/trunk/src/kernel/srs_kernel_pithy_print.cpp @@ -4,13 +4,13 @@ // SPDX-License-Identifier: MIT // -#include +#include #include using namespace std; -#include #include +#include #include #include @@ -21,20 +21,19 @@ SrsStageInfo::SrsStageInfo(int _stage_id, double ratio) age_ = 0; nn_count_ = 0; interval_ratio_ = ratio; + config_ = _srs_kernel_factory->create_config(); update_print_time(); - - _srs_config->subscribe(this); } SrsStageInfo::~SrsStageInfo() { - _srs_config->unsubscribe(this); + srs_freep(config_); } void SrsStageInfo::update_print_time() { - interval_ = _srs_config->get_pithy_print(); + interval_ = config_->get_pithy_print(); } void SrsStageInfo::elapse(srs_utime_t diff) diff --git a/trunk/src/app/srs_app_pithy_print.hpp b/trunk/src/kernel/srs_kernel_pithy_print.hpp similarity index 94% rename from trunk/src/app/srs_app_pithy_print.hpp rename to trunk/src/kernel/srs_kernel_pithy_print.hpp index fe62b05bdd8..2fca09055cd 100644 --- a/trunk/src/app/srs_app_pithy_print.hpp +++ b/trunk/src/kernel/srs_kernel_pithy_print.hpp @@ -4,17 +4,17 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_PITHY_PRINT_HPP -#define SRS_APP_PITHY_PRINT_HPP +#ifndef SRS_KERNEL_PITHY_PRINT_HPP +#define SRS_KERNEL_PITHY_PRINT_HPP #include #include -#include +class ISrsConfig; // The stage info to calc the age. -class SrsStageInfo : public ISrsReloadHandler +class SrsStageInfo { public: int stage_id_; @@ -24,6 +24,7 @@ class SrsStageInfo : public ISrsReloadHandler uint32_t nn_count_; // The ratio for interval, 1.0 means no change. double interval_ratio_; + ISrsConfig *config_; public: srs_utime_t age_; @@ -158,4 +159,7 @@ class SrsPithyPrint virtual srs_utime_t age(); }; +// Global stage manager for pithy print, multiple stages. +extern SrsStageManager *_srs_stages; + #endif diff --git a/trunk/src/kernel/srs_kernel_resource.cpp b/trunk/src/kernel/srs_kernel_resource.cpp new file mode 100644 index 00000000000..3574c1157ef --- /dev/null +++ b/trunk/src/kernel/srs_kernel_resource.cpp @@ -0,0 +1,430 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#include + +#include +#include +#include +#include + +#include +using namespace std; + +SrsPps *_srs_pps_ids = NULL; +SrsPps *_srs_pps_fids = NULL; +SrsPps *_srs_pps_fids_level0 = NULL; +SrsPps *_srs_pps_dispose = NULL; + +SrsResourceManager *_srs_conn_manager = NULL; + +ISrsDisposingHandler::ISrsDisposingHandler() +{ +} + +ISrsDisposingHandler::~ISrsDisposingHandler() +{ +} + +ISrsResource::ISrsResource() +{ +} + +ISrsResource::~ISrsResource() +{ +} + +std::string ISrsResource::desc() +{ + return "Resource"; +} + +ISrsResourceManager::ISrsResourceManager() +{ +} + +ISrsResourceManager::~ISrsResourceManager() +{ +} + +SrsResourceManager::SrsResourceManager(const std::string &label, bool verbose) +{ + verbose_ = verbose; + label_ = label; + cond_ = _srs_kernel_factory->create_cond(); + trd_ = NULL; + p_disposing_ = NULL; + removing_ = false; + + nn_level0_cache_ = 100000; + conns_level0_cache_ = new SrsResourceFastIdItem[nn_level0_cache_]; +} + +SrsResourceManager::~SrsResourceManager() +{ + if (trd_) { + cond_->signal(); + trd_->stop(); + + srs_freep(trd_); + } + srs_freep(cond_); + + clear(); + + // Free all objects not in zombies. + std::vector::iterator it; + for (it = conns_.begin(); it != conns_.end(); ++it) { + ISrsResource *resource = *it; + srs_freep(resource); + } + + srs_freepa(conns_level0_cache_); +} + +srs_error_t SrsResourceManager::start() +{ + srs_error_t err = srs_success; + + cid_ = _srs_context->generate_id(); + trd_ = _srs_kernel_factory->create_coroutine("manager", this, cid_); + + if ((err = trd_->start()) != srs_success) { + return srs_error_wrap(err, "conn manager"); + } + + return err; +} + +bool SrsResourceManager::empty() +{ + return conns_.empty(); +} + +size_t SrsResourceManager::size() +{ + return conns_.size(); +} + +srs_error_t SrsResourceManager::cycle() +{ + srs_error_t err = srs_success; + + srs_trace("%s: connection manager run, conns=%d", label_.c_str(), (int)conns_.size()); + + while (true) { + if ((err = trd_->pull()) != srs_success) { + return srs_error_wrap(err, "conn manager"); + } + + // Clear all zombies, because we may switch context and lost signal + // when we clear zombie connection. + while (!zombies_.empty()) { + clear(); + } + + cond_->wait(); + } + + return err; +} + +void SrsResourceManager::add(ISrsResource *conn, bool *exists) +{ + if (std::find(conns_.begin(), conns_.end(), conn) == conns_.end()) { + conns_.push_back(conn); + } else { + if (exists) { + *exists = true; + } + } +} + +void SrsResourceManager::add_with_id(const std::string &id, ISrsResource *conn) +{ + add(conn); + conns_id_[id] = conn; +} + +void SrsResourceManager::add_with_fast_id(uint64_t id, ISrsResource *conn) +{ + bool exists = false; + add(conn, &exists); + conns_fast_id_[id] = conn; + + if (exists) { + return; + } + + // For new resource, build the level-0 cache for fast-id. + SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; + + // Ignore if exits item. + if (item->fast_id_ && item->fast_id_ == id) { + return; + } + + // Fresh one, create the item. + if (!item->fast_id_) { + item->fast_id_ = id; + item->impl_ = conn; + item->nn_collisions_ = 1; + item->available_ = true; + } + + // Collision, increase the collisions. + if (item->fast_id_ != id) { + item->nn_collisions_++; + item->available_ = false; + } +} + +void SrsResourceManager::add_with_name(const std::string &name, ISrsResource *conn) +{ + add(conn); + conns_name_[name] = conn; +} + +ISrsResource *SrsResourceManager::at(int index) +{ + return (index < (int)conns_.size()) ? conns_.at(index) : NULL; +} + +ISrsResource *SrsResourceManager::find_by_id(std::string id) +{ + ++_srs_pps_ids->sugar_; + map::iterator it = conns_id_.find(id); + return (it != conns_id_.end()) ? it->second : NULL; +} + +ISrsResource *SrsResourceManager::find_by_fast_id(uint64_t id) +{ + SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; + if (item->available_ && item->fast_id_ == id) { + ++_srs_pps_fids_level0->sugar_; + return item->impl_; + } + + ++_srs_pps_fids->sugar_; + map::iterator it = conns_fast_id_.find(id); + return (it != conns_fast_id_.end()) ? it->second : NULL; +} + +ISrsResource *SrsResourceManager::find_by_name(std::string name) +{ + ++_srs_pps_ids->sugar_; + map::iterator it = conns_name_.find(name); + return (it != conns_name_.end()) ? it->second : NULL; +} + +void SrsResourceManager::subscribe(ISrsDisposingHandler *h) +{ + if (std::find(handlers_.begin(), handlers_.end(), h) == handlers_.end()) { + handlers_.push_back(h); + } + + // Restore the handler from unsubscribing handlers. + vector::iterator it; + if ((it = std::find(unsubs_.begin(), unsubs_.end(), h)) != unsubs_.end()) { + it = unsubs_.erase(it); + } +} + +void SrsResourceManager::unsubscribe(ISrsDisposingHandler *h) +{ + vector::iterator it = find(handlers_.begin(), handlers_.end(), h); + if (it != handlers_.end()) { + it = handlers_.erase(it); + } + + // Put it to the unsubscribing handlers. + if (std::find(unsubs_.begin(), unsubs_.end(), h) == unsubs_.end()) { + unsubs_.push_back(h); + } +} + +void SrsResourceManager::remove(ISrsResource *c) +{ + SrsContextRestore(_srs_context->get_id()); + + removing_ = true; + do_remove(c); + removing_ = false; +} + +void SrsResourceManager::do_remove(ISrsResource *c) +{ + bool in_zombie = false; + bool in_disposing = false; + check_remove(c, in_zombie, in_disposing); + bool ignored = in_zombie || in_disposing; + + if (verbose_) { + _srs_context->set_id(c->get_id()); + srs_trace("%s: before dispose resource(%s)(%p), conns=%d, zombies=%d, ign=%d, inz=%d, ind=%d", + label_.c_str(), c->desc().c_str(), c, (int)conns_.size(), (int)zombies_.size(), ignored, + in_zombie, in_disposing); + } + if (ignored) { + return; + } + + // Push to zombies, we will free it in another coroutine. + zombies_.push_back(c); + + // We should copy all handlers, because it may change during callback. + vector handlers = handlers_; + + // Notify other handlers to handle the before-dispose event. + for (int i = 0; i < (int)handlers.size(); i++) { + ISrsDisposingHandler *h = handlers.at(i); + + // Ignore if handler is unsubscribing. + if (!unsubs_.empty() && std::find(unsubs_.begin(), unsubs_.end(), h) != unsubs_.end()) { + srs_warn2(TAG_RESOURCE_UNSUB, "%s: ignore before-dispose resource(%s)(%p) for %p, conns=%d", + label_.c_str(), c->desc().c_str(), c, h, (int)conns_.size()); + continue; + } + + h->on_before_dispose(c); + } + + // Notify the coroutine to free it. + cond_->signal(); +} + +void SrsResourceManager::check_remove(ISrsResource *c, bool &in_zombie, bool &in_disposing) +{ + // Only notify when not removed(in zombies_). + vector::iterator it = std::find(zombies_.begin(), zombies_.end(), c); + if (it != zombies_.end()) { + in_zombie = true; + } + + // Also ignore when we are disposing it. + if (p_disposing_) { + it = std::find(p_disposing_->begin(), p_disposing_->end(), c); + if (it != p_disposing_->end()) { + in_disposing = true; + } + } +} + +void SrsResourceManager::clear() +{ + if (zombies_.empty()) { + return; + } + + SrsContextRestore(cid_); + if (verbose_) { + srs_trace("%s: clear zombies=%d resources, conns=%d, removing=%d, unsubs=%d", + label_.c_str(), (int)zombies_.size(), (int)conns_.size(), removing_, (int)unsubs_.size()); + } + + // Clear all unsubscribing handlers, if not removing any resource. + if (!removing_ && !unsubs_.empty()) { + vector().swap(unsubs_); + } + + do_clear(); +} + +void SrsResourceManager::do_clear() +{ + // To prevent thread switch when delete connection, + // we copy all connections then free one by one. + vector copy; + copy.swap(zombies_); + p_disposing_ = © + + for (int i = 0; i < (int)copy.size(); i++) { + ISrsResource *conn = copy.at(i); + + if (verbose_) { + _srs_context->set_id(conn->get_id()); + srs_trace("%s: disposing #%d resource(%s)(%p), conns=%d, disposing=%d, zombies=%d", label_.c_str(), + i, conn->desc().c_str(), conn, (int)conns_.size(), (int)copy.size(), (int)zombies_.size()); + } + + ++_srs_pps_dispose->sugar_; + + dispose(conn); + } + + // Reset it for it points to a local object. + // @remark We must set the disposing to NULL to avoid reusing address, + // because the context might switch. + p_disposing_ = NULL; + + // We should free the resources when finished all disposing callbacks, + // which might cause context switch and reuse the freed addresses. + for (int i = 0; i < (int)copy.size(); i++) { + ISrsResource *conn = copy.at(i); + srs_freep(conn); + } +} + +void SrsResourceManager::dispose(ISrsResource *c) +{ + for (map::iterator it = conns_name_.begin(); it != conns_name_.end();) { + if (c != it->second) { + ++it; + } else { + // Use C++98 style: https://stackoverflow.com/a/4636230 + conns_name_.erase(it++); + } + } + + for (map::iterator it = conns_id_.begin(); it != conns_id_.end();) { + if (c != it->second) { + ++it; + } else { + // Use C++98 style: https://stackoverflow.com/a/4636230 + conns_id_.erase(it++); + } + } + + for (map::iterator it = conns_fast_id_.begin(); it != conns_fast_id_.end();) { + if (c != it->second) { + ++it; + } else { + // Update the level-0 cache for fast-id. + uint64_t id = it->first; + SrsResourceFastIdItem *item = &conns_level0_cache_[(id | id >> 32) % nn_level0_cache_]; + item->nn_collisions_--; + if (!item->nn_collisions_) { + item->fast_id_ = 0; + item->available_ = false; + } + + // Use C++98 style: https://stackoverflow.com/a/4636230 + conns_fast_id_.erase(it++); + } + } + + vector::iterator it = std::find(conns_.begin(), conns_.end(), c); + if (it != conns_.end()) { + it = conns_.erase(it); + } + + // We should copy all handlers, because it may change during callback. + vector handlers = handlers_; + + // Notify other handlers to handle the disposing event. + for (int i = 0; i < (int)handlers.size(); i++) { + ISrsDisposingHandler *h = handlers.at(i); + + // Ignore if handler is unsubscribing. + if (!unsubs_.empty() && std::find(unsubs_.begin(), unsubs_.end(), h) != unsubs_.end()) { + srs_warn2(TAG_RESOURCE_UNSUB, "%s: ignore disposing resource(%s)(%p) for %p, conns=%d", + label_.c_str(), c->desc().c_str(), c, h, (int)conns_.size()); + continue; + } + + h->on_disposing(c); + } +} diff --git a/trunk/src/app/srs_app_conn.hpp b/trunk/src/kernel/srs_kernel_resource.hpp similarity index 57% rename from trunk/src/app/srs_app_conn.hpp rename to trunk/src/kernel/srs_kernel_resource.hpp index 5c8962cb91c..cd917386898 100644 --- a/trunk/src/app/srs_app_conn.hpp +++ b/trunk/src/kernel/srs_kernel_resource.hpp @@ -4,26 +4,20 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_CONN_HPP -#define SRS_APP_CONN_HPP +#ifndef SRS_KERNEL_RESOURCE_HPP +#define SRS_KERNEL_RESOURCE_HPP #include +#include +#include + #include #include #include -#include -#include - -#include -#include -#include -#include -#include - -class SrsWallClock; -class SrsBuffer; +class ISrsResource; +class ISrsCond; // Hooks for connection manager, to handle the event when disposing connections. class ISrsDisposingHandler @@ -65,6 +59,36 @@ class SrsResourceFastIdItem } }; +// The resource managed by ISrsResourceManager. +class ISrsResource +{ +public: + ISrsResource(); + virtual ~ISrsResource(); + +public: + // Get the context id of connection. + virtual const SrsContextId &get_id() = 0; + +public: + // The resource description, optional. + virtual std::string desc(); +}; + +// The manager for resource. +class ISrsResourceManager +{ +public: + ISrsResourceManager(); + virtual ~ISrsResourceManager(); + +public: + // Remove then free the specified connection. Note that the manager always free c resource, + // in the same coroutine or another coroutine. Some manager may support add c to a map, it + // should always free it even if it's in the map. + virtual void remove(ISrsResource *c) = 0; +}; + // The resource manager remove resource and delete it asynchronously. class SrsResourceManager : public ISrsCoroutineHandler, public ISrsResourceManager { @@ -74,8 +98,8 @@ class SrsResourceManager : public ISrsCoroutineHandler, public ISrsResourceManag bool verbose_; private: - SrsCoroutine *trd_; - srs_cond_t cond_; + ISrsCoroutine *trd_; + ISrsCond *cond_; // Callback handlers. std::vector handlers_; // Unsubscribing handlers, skip it for notifying. @@ -212,122 +236,6 @@ class SrsSharedResource : public ISrsResource } }; -// If a connection is able be expired, user can use HTTP-API to kick-off it. -class ISrsExpire -{ -public: - ISrsExpire(); - virtual ~ISrsExpire(); - -public: - // Set connection to expired to kick-off it. - virtual void expire() = 0; -}; - -// The basic connection of SRS, for TCP based protocols, -// all connections accept from listener must extends from this base class, -// server will add the connection to manager, and delete it when remove. -class SrsTcpConnection : public ISrsProtocolReadWriter -{ -private: - // The underlayer st fd handler. - srs_netfd_t stfd_; - // The underlayer socket. - SrsStSocket *skt_; - -public: - SrsTcpConnection(srs_netfd_t c); - virtual ~SrsTcpConnection(); - -public: - // Set socket option TCP_NODELAY. - virtual srs_error_t set_tcp_nodelay(bool v); - // Set socket option SO_SNDBUF in srs_utime_t. - virtual srs_error_t set_socket_buffer(srs_utime_t buffer_v); - // Interface ISrsProtocolReadWriter -public: - virtual void set_recv_timeout(srs_utime_t tm); - virtual srs_utime_t get_recv_timeout(); - virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); - virtual int64_t get_recv_bytes(); - virtual int64_t get_send_bytes(); - virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); - virtual void set_send_timeout(srs_utime_t tm); - virtual srs_utime_t get_send_timeout(); - virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); - virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); -}; - -// With a small fast read buffer, to support peek for protocol detecting. Note that directly write to io without any -// cache or buffer. -class SrsBufferedReadWriter : public ISrsProtocolReadWriter -{ -private: - // The under-layer transport. - ISrsProtocolReadWriter *io_; - // Fixed, small and fast buffer. Note that it must be very small piece of cache, make sure matches all protocols, - // because we will full fill it when peeking. - char cache_[16]; - // Current reading position. - SrsBuffer *buf_; - -public: - SrsBufferedReadWriter(ISrsProtocolReadWriter *io); - virtual ~SrsBufferedReadWriter(); - -public: - // Peek the head of cache to buf in size of bytes. - srs_error_t peek(char *buf, int *size); - -private: - srs_error_t reload_buffer(); - // Interface ISrsProtocolReadWriter -public: - virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); - virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); - virtual void set_recv_timeout(srs_utime_t tm); - virtual srs_utime_t get_recv_timeout(); - virtual int64_t get_recv_bytes(); - virtual int64_t get_send_bytes(); - virtual void set_send_timeout(srs_utime_t tm); - virtual srs_utime_t get_send_timeout(); - virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); - virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); -}; - -// The SSL connection over TCP transport, in server mode. -class SrsSslConnection : public ISrsProtocolReadWriter -{ -private: - // The under-layer plaintext transport. - ISrsProtocolReadWriter *transport_; - -private: - SSL_CTX *ssl_ctx_; - SSL *ssl_; - BIO *bio_in_; - BIO *bio_out_; - -public: - SrsSslConnection(ISrsProtocolReadWriter *c); - virtual ~SrsSslConnection(); - -public: - virtual srs_error_t handshake(std::string key_file, std::string crt_file); - // Interface ISrsProtocolReadWriter -public: - virtual void set_recv_timeout(srs_utime_t tm); - virtual srs_utime_t get_recv_timeout(); - virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); - virtual int64_t get_recv_bytes(); - virtual int64_t get_send_bytes(); - virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); - virtual void set_send_timeout(srs_utime_t tm); - virtual srs_utime_t get_send_timeout(); - virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); - virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); -}; - // Manager for RTC connections. extern SrsResourceManager *_srs_conn_manager; diff --git a/trunk/src/app/srs_app_rtc_queue.cpp b/trunk/src/kernel/srs_kernel_rtc_queue.cpp similarity index 93% rename from trunk/src/app/srs_app_rtc_queue.cpp rename to trunk/src/kernel/srs_kernel_rtc_queue.cpp index 3404c6574c6..f3ff5fc69fd 100644 --- a/trunk/src/app/srs_app_rtc_queue.cpp +++ b/trunk/src/kernel/srs_kernel_rtc_queue.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT // -#include +#include #include #include @@ -12,13 +12,12 @@ using namespace std; -#include -#include #include +#include #include #include -#include +#include extern SrsPps *_srs_pps_snack3; extern SrsPps *_srs_pps_snack4; @@ -215,12 +214,6 @@ SrsRtpNackForReceiver::~SrsRtpNackForReceiver() void SrsRtpNackForReceiver::insert(uint16_t first, uint16_t last) { - // If circuit-breaker is enabled, disable nack. - if (_srs_circuit_breaker->hybrid_high_water_level()) { - ++_srs_pps_snack4->sugar_; - return; - } - for (uint16_t s = first; s != last; ++s) { queue_[s] = SrsRtpNackInfo(); } @@ -252,13 +245,6 @@ void SrsRtpNackForReceiver::check_queue_size() void SrsRtpNackForReceiver::get_nack_seqs(SrsRtcpNack &seqs, uint32_t &timeout_nacks) { - // If circuit-breaker is enabled, disable nack. - if (_srs_circuit_breaker->hybrid_high_water_level()) { - queue_.clear(); - ++_srs_pps_snack4->sugar_; - return; - } - srs_utime_t now = srs_time_now_cached(); srs_utime_t interval = now - pre_check_time_; diff --git a/trunk/src/app/srs_app_rtc_queue.hpp b/trunk/src/kernel/srs_kernel_rtc_queue.hpp similarity index 98% rename from trunk/src/app/srs_app_rtc_queue.hpp rename to trunk/src/kernel/srs_kernel_rtc_queue.hpp index 6267b62bd58..9652e3f7b71 100644 --- a/trunk/src/app/srs_app_rtc_queue.hpp +++ b/trunk/src/kernel/srs_kernel_rtc_queue.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_RTC_QUEUE_HPP -#define SRS_APP_RTC_QUEUE_HPP +#ifndef SRS_KERNEL_RTC_QUEUE_HPP +#define SRS_KERNEL_RTC_QUEUE_HPP #include diff --git a/trunk/src/kernel/srs_kernel_st.cpp b/trunk/src/kernel/srs_kernel_st.cpp new file mode 100644 index 00000000000..ef8e57bed70 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_st.cpp @@ -0,0 +1,71 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#include + +ISrsCoroutineHandler::ISrsCoroutineHandler() +{ +} + +ISrsCoroutineHandler::~ISrsCoroutineHandler() +{ +} + +ISrsStartable::ISrsStartable() +{ +} + +ISrsStartable::~ISrsStartable() +{ +} + +ISrsInterruptable::ISrsInterruptable() +{ +} + +ISrsInterruptable::~ISrsInterruptable() +{ +} + +ISrsContextIdSetter::ISrsContextIdSetter() +{ +} + +ISrsContextIdSetter::~ISrsContextIdSetter() +{ +} + +ISrsContextIdGetter::ISrsContextIdGetter() +{ +} + +ISrsContextIdGetter::~ISrsContextIdGetter() +{ +} + +ISrsStoppable::ISrsStoppable() +{ +} + +ISrsStoppable::~ISrsStoppable() +{ +} + +ISrsCoroutine::ISrsCoroutine() +{ +} + +ISrsCoroutine::~ISrsCoroutine() +{ +} + +ISrsCond::ISrsCond() +{ +} + +ISrsCond::~ISrsCond() +{ +} diff --git a/trunk/src/kernel/srs_kernel_st.hpp b/trunk/src/kernel/srs_kernel_st.hpp new file mode 100644 index 00000000000..2e6d8615c15 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_st.hpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_KERNEL_ST_HPP +#define SRS_KERNEL_ST_HPP + +#include + +// Each ST-coroutine must implements this interface, +// to do the cycle job and handle some events. +// +// Thread do a job then terminated normally, it's a SrsOneCycleThread: +// class SrsOneCycleThread : public ISrsCoroutineHandler { +// public: ISrsCoroutine trd; +// public: virtual srs_error_t cycle() { +// // Do something, then return this cycle and thread terminated normally. +// } +// }; +// +// Thread has its inside loop, such as the RTMP receive thread: +// class SrsReceiveThread : public ISrsCoroutineHandler { +// public: ISrsCoroutine* trd; +// public: virtual srs_error_t cycle() { +// while (true) { +// // Check whether thread interrupted. +// if ((err = trd->pull()) != srs_success) { +// return err; +// } +// // Do something, such as st_read() packets, it'll be wakeup +// // when user stop or interrupt the thread. +// } +// } +// }; +class ISrsCoroutineHandler +{ +public: + ISrsCoroutineHandler(); + virtual ~ISrsCoroutineHandler(); + +public: + // Do the work. The ST-coroutine will terminated normally if it returned. + // @remark If the cycle has its own loop, it must check the thread pull. + virtual srs_error_t cycle() = 0; +}; + +// Start the object, generally a coroutine. +class ISrsStartable +{ +public: + ISrsStartable(); + virtual ~ISrsStartable(); + +public: + virtual srs_error_t start() = 0; +}; + +// Allow user to interrupt the coroutine, for example, to stop it. +class ISrsInterruptable +{ +public: + ISrsInterruptable(); + virtual ~ISrsInterruptable(); + +public: + virtual void interrupt() = 0; + virtual srs_error_t pull() = 0; +}; + +// Get the context id. +class ISrsContextIdSetter +{ +public: + ISrsContextIdSetter(); + virtual ~ISrsContextIdSetter(); + +public: + virtual void set_cid(const SrsContextId &cid) = 0; +}; + +// Set the context id. +class ISrsContextIdGetter +{ +public: + ISrsContextIdGetter(); + virtual ~ISrsContextIdGetter(); + +public: + virtual const SrsContextId &cid() = 0; +}; + +// Stop the object, generally a coroutine. +class ISrsStoppable +{ +public: + ISrsStoppable(); + virtual ~ISrsStoppable(); + +public: + virtual void stop() = 0; +}; + +// The coroutine object. +class ISrsCoroutine : public ISrsStoppable, public ISrsStartable, public ISrsInterruptable, public ISrsContextIdSetter, public ISrsContextIdGetter +{ +public: + ISrsCoroutine(); + virtual ~ISrsCoroutine(); +}; + +// The condition variable interface. +class ISrsCond +{ +public: + ISrsCond(); + virtual ~ISrsCond(); + +public: + virtual int wait() = 0; + virtual int timedwait(srs_utime_t timeout) = 0; + virtual int signal() = 0; + virtual int broadcast() = 0; +}; + +#endif diff --git a/trunk/src/app/srs_app_uuid.cpp b/trunk/src/kernel/srs_kernel_uuid.cpp similarity index 97% rename from trunk/src/app/srs_app_uuid.cpp rename to trunk/src/kernel/srs_kernel_uuid.cpp index 70538ccc297..7994fcaf6a4 100644 --- a/trunk/src/app/srs_app_uuid.cpp +++ b/trunk/src/kernel/srs_kernel_uuid.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: BSD-3-Clause // -#include +#include #include #include @@ -125,18 +125,18 @@ #ifndef min #define min(x, y) ({ \ - __typeof__(x) _min1 = (x); \ - __typeof__(y) _min2 = (y); \ - (void) (&_min1 == &_min2); \ - _min1 < _min2 ? _min1 : _min2; }) + __typeof__(x) _min1 = (x); \ + __typeof__(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) #endif #ifndef max #define max(x, y) ({ \ - __typeof__(x) _max1 = (x); \ - __typeof__(y) _max2 = (y); \ - (void) (&_max1 == &_max2); \ - _max1 > _max2 ? _max1 : _max2; }) + __typeof__(x) _max1 = (x); \ + __typeof__(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) #endif #ifndef offsetof @@ -145,8 +145,8 @@ #ifndef container_of #define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) ); }) + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) ); }) #endif #if 0 @@ -604,6 +604,33 @@ static int flock(int fd, int op) #endif /* LOCK_EX */ +#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) +// Helper function for reading all bytes +static ssize_t read_all(int fd, char *buf, size_t count) +{ + ssize_t ret; + ssize_t c = 0; + int tries = 0; + + memset(buf, 0, count); + while (count > 0) { + ret = read(fd, buf, count); + if (ret <= 0) { + if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) + continue; + return c ? c : -1; + } + if (ret > 0) { + tries = 0; + count -= ret; + buf += ret; + c += ret; + } + } + return c; +} +#endif + /* * Get the ethernet hardware address, if we can find it... * diff --git a/trunk/src/app/srs_app_uuid.hpp b/trunk/src/kernel/srs_kernel_uuid.hpp similarity index 100% rename from trunk/src/app/srs_app_uuid.hpp rename to trunk/src/kernel/srs_kernel_uuid.hpp diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 94086f91bc1..192dd823e12 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -33,6 +33,7 @@ using namespace std; #include #include +#include #include #include #include @@ -58,6 +59,9 @@ ISrsContext *_srs_context = NULL; // @global config object for app module. SrsConfig *_srs_config = NULL; +// @global kernel factory. +ISrsKernelFactory *_srs_kernel_factory = new SrsFinalFactory(); + // @global version of srs, which can grep keyword "XCORE" extern const char *_srs_version; diff --git a/trunk/src/protocol/srs_protocol_conn.cpp b/trunk/src/protocol/srs_protocol_conn.cpp index 6df1eeeb865..63707279832 100644 --- a/trunk/src/protocol/srs_protocol_conn.cpp +++ b/trunk/src/protocol/srs_protocol_conn.cpp @@ -6,36 +6,614 @@ #include +#include #include +#include +#include +#include #include +#include +#include using namespace std; -ISrsResource::ISrsResource() +ISrsConnection::ISrsConnection() { } -ISrsResource::~ISrsResource() +ISrsConnection::~ISrsConnection() { } -std::string ISrsResource::desc() +ISrsExpire::ISrsExpire() { - return "Resource"; } -ISrsResourceManager::ISrsResourceManager() +ISrsExpire::~ISrsExpire() { } -ISrsResourceManager::~ISrsResourceManager() +SrsTcpConnection::SrsTcpConnection(srs_netfd_t c) { + stfd_ = c; + skt_ = new SrsStSocket(c); } -ISrsConnection::ISrsConnection() +SrsTcpConnection::~SrsTcpConnection() { + srs_freep(skt_); + srs_close_stfd(stfd_); } -ISrsConnection::~ISrsConnection() +srs_error_t SrsTcpConnection::set_tcp_nodelay(bool v) +{ + srs_error_t err = srs_success; + + int r0 = 0; + socklen_t nb_v = sizeof(int); + int fd = srs_netfd_fileno(stfd_); + + int ov = 0; + if ((r0 = getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &ov, &nb_v)) != 0) { + return srs_error_new(ERROR_SOCKET_NO_NODELAY, "getsockopt fd=%d, r0=%d", fd, r0); + } + +#ifndef SRS_PERF_TCP_NODELAY + srs_warn("ignore TCP_NODELAY, fd=%d, ov=%d", fd, ov); + return err; +#endif + + int iv = (v ? 1 : 0); + if ((r0 = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, nb_v)) != 0) { + return srs_error_new(ERROR_SOCKET_NO_NODELAY, "setsockopt fd=%d, r0=%d", fd, r0); + } + if ((r0 = getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &iv, &nb_v)) != 0) { + return srs_error_new(ERROR_SOCKET_NO_NODELAY, "getsockopt fd=%d, r0=%d", fd, r0); + } + + srs_trace("set fd=%d TCP_NODELAY %d=>%d", fd, ov, iv); + + return err; +} + +srs_error_t SrsTcpConnection::set_socket_buffer(srs_utime_t buffer_v) +{ + srs_error_t err = srs_success; + + int r0 = 0; + int fd = srs_netfd_fileno(stfd_); + socklen_t nb_v = sizeof(int); + + int ov = 0; + if ((r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &ov, &nb_v)) != 0) { + return srs_error_new(ERROR_SOCKET_SNDBUF, "getsockopt fd=%d, r0=%d", fd, r0); + } + +#ifndef SRS_PERF_MW_SO_SNDBUF + srs_warn("ignore SO_SNDBUF, fd=%d, ov=%d", fd, ov); + return err; +#endif + + // the bytes: + // 4KB=4096, 8KB=8192, 16KB=16384, 32KB=32768, 64KB=65536, + // 128KB=131072, 256KB=262144, 512KB=524288 + // the buffer should set to sleep*kbps/8, + // for example, your system delivery stream in 1000kbps, + // sleep 800ms for small bytes, the buffer should set to: + // 800*1000/8=100000B(about 128KB). + // other examples: + // 2000*3000/8=750000B(about 732KB). + // 2000*5000/8=1250000B(about 1220KB). + int kbps = 4000; + int iv = srsu2ms(buffer_v) * kbps / 8; + + // socket send buffer, system will double it. + iv = iv / 2; + + // override the send buffer by macro. +#ifdef SRS_PERF_SO_SNDBUF_SIZE + iv = SRS_PERF_SO_SNDBUF_SIZE / 2; +#endif + + // set the socket send buffer when required larger buffer + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, nb_v) < 0) { + return srs_error_new(ERROR_SOCKET_SNDBUF, "setsockopt fd=%d, r0=%d", fd, r0); + } + if ((r0 = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &iv, &nb_v)) != 0) { + return srs_error_new(ERROR_SOCKET_SNDBUF, "getsockopt fd=%d, r0=%d", fd, r0); + } + + srs_trace("set fd=%d, SO_SNDBUF=%d=>%d, buffer=%dms", fd, ov, iv, srsu2ms(buffer_v)); + + return err; +} + +void SrsTcpConnection::set_recv_timeout(srs_utime_t tm) +{ + skt_->set_recv_timeout(tm); +} + +srs_utime_t SrsTcpConnection::get_recv_timeout() +{ + return skt_->get_recv_timeout(); +} + +srs_error_t SrsTcpConnection::read_fully(void *buf, size_t size, ssize_t *nread) +{ + return skt_->read_fully(buf, size, nread); +} + +int64_t SrsTcpConnection::get_recv_bytes() +{ + return skt_->get_recv_bytes(); +} + +int64_t SrsTcpConnection::get_send_bytes() +{ + return skt_->get_send_bytes(); +} + +srs_error_t SrsTcpConnection::read(void *buf, size_t size, ssize_t *nread) +{ + return skt_->read(buf, size, nread); +} + +void SrsTcpConnection::set_send_timeout(srs_utime_t tm) +{ + skt_->set_send_timeout(tm); +} + +srs_utime_t SrsTcpConnection::get_send_timeout() +{ + return skt_->get_send_timeout(); +} + +srs_error_t SrsTcpConnection::write(void *buf, size_t size, ssize_t *nwrite) +{ + return skt_->write(buf, size, nwrite); +} + +srs_error_t SrsTcpConnection::writev(const iovec *iov, int iov_size, ssize_t *nwrite) +{ + return skt_->writev(iov, iov_size, nwrite); +} + +SrsBufferedReadWriter::SrsBufferedReadWriter(ISrsProtocolReadWriter *io) +{ + io_ = io; + buf_ = NULL; +} + +SrsBufferedReadWriter::~SrsBufferedReadWriter() +{ + srs_freep(buf_); +} + +srs_error_t SrsBufferedReadWriter::peek(char *buf, int *size) +{ + srs_error_t err = srs_success; + + if ((err = reload_buffer()) != srs_success) { + return srs_error_wrap(err, "reload buffer"); + } + + int nn = srs_min(buf_->left(), *size); + *size = nn; + + if (nn) { + memcpy(buf, buf_->head(), nn); + } + + return err; +} + +srs_error_t SrsBufferedReadWriter::reload_buffer() { + srs_error_t err = srs_success; + + if (buf_ && !buf_->empty()) { + return err; + } + + // We use read_fully to always full fill the cache, to avoid peeking failed. + ssize_t nread = 0; + if ((err = io_->read_fully(cache_, sizeof(cache_), &nread)) != srs_success) { + return srs_error_wrap(err, "read"); + } + + srs_freep(buf_); + buf_ = new SrsBuffer(cache_, nread); + + return err; +} + +srs_error_t SrsBufferedReadWriter::read(void *buf, size_t size, ssize_t *nread) +{ + if (!buf_ || buf_->empty()) { + return io_->read(buf, size, nread); + } + + int nn = srs_min(buf_->left(), (int)size); + *nread = nn; + + if (nn) { + buf_->read_bytes((char *)buf, nn); + } + return srs_success; +} + +srs_error_t SrsBufferedReadWriter::read_fully(void *buf, size_t size, ssize_t *nread) +{ + if (!buf_ || buf_->empty()) { + return io_->read_fully(buf, size, nread); + } + + int nn = srs_min(buf_->left(), (int)size); + if (nn) { + buf_->read_bytes((char *)buf, nn); + } + + int left = size - nn; + *nread = size; + + if (left) { + return io_->read_fully((char *)buf + nn, left, NULL); + } + return srs_success; +} + +void SrsBufferedReadWriter::set_recv_timeout(srs_utime_t tm) +{ + return io_->set_recv_timeout(tm); +} + +srs_utime_t SrsBufferedReadWriter::get_recv_timeout() +{ + return io_->get_recv_timeout(); +} + +int64_t SrsBufferedReadWriter::get_recv_bytes() +{ + return io_->get_recv_bytes(); +} + +int64_t SrsBufferedReadWriter::get_send_bytes() +{ + return io_->get_send_bytes(); +} + +void SrsBufferedReadWriter::set_send_timeout(srs_utime_t tm) +{ + return io_->set_send_timeout(tm); +} + +srs_utime_t SrsBufferedReadWriter::get_send_timeout() +{ + return io_->get_send_timeout(); +} + +srs_error_t SrsBufferedReadWriter::write(void *buf, size_t size, ssize_t *nwrite) +{ + return io_->write(buf, size, nwrite); +} + +srs_error_t SrsBufferedReadWriter::writev(const iovec *iov, int iov_size, ssize_t *nwrite) +{ + return io_->writev(iov, iov_size, nwrite); +} + +SrsSslConnection::SrsSslConnection(ISrsProtocolReadWriter *c) +{ + transport_ = c; + ssl_ctx_ = NULL; + ssl_ = NULL; +} + +SrsSslConnection::~SrsSslConnection() +{ + if (ssl_) { + // this function will free bio_in_ and bio_out_ + SSL_free(ssl_); + ssl_ = NULL; + } + + if (ssl_ctx_) { + SSL_CTX_free(ssl_ctx_); + ssl_ctx_ = NULL; + } +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +srs_error_t SrsSslConnection::handshake(string key_file, string crt_file) +{ + srs_error_t err = srs_success; + + // For HTTPS, try to connect over security transport. +#if (OPENSSL_VERSION_NUMBER < 0x10002000L) // v1.0.2 + ssl_ctx_ = SSL_CTX_new(TLS_method()); +#else + ssl_ctx_ = SSL_CTX_new(TLSv1_2_method()); +#endif + SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_NONE, NULL); + srs_assert(SSL_CTX_set_cipher_list(ssl_ctx_, "ALL") == 1); + + // TODO: Setup callback, see SSL_set_ex_data and SSL_set_info_callback + if ((ssl_ = SSL_new(ssl_ctx_)) == NULL) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "SSL_new ssl"); + } + + if ((bio_in_ = BIO_new(BIO_s_mem())) == NULL) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_new in"); + } + + if ((bio_out_ = BIO_new(BIO_s_mem())) == NULL) { + BIO_free(bio_in_); + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_new out"); + } + + SSL_set_bio(ssl_, bio_in_, bio_out_); + + // SSL setup active, as server role. + SSL_set_accept_state(ssl_); + SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); + + uint8_t *data = NULL; + int r0, r1, size; + + // Setup the key and cert file for server. + if ((r0 = SSL_use_certificate_chain_file(ssl_, crt_file.c_str())) != 1) { + return srs_error_new(ERROR_TLS_KEY_CRT, "use cert %s", crt_file.c_str()); + } + + if ((r0 = SSL_use_RSAPrivateKey_file(ssl_, key_file.c_str(), SSL_FILETYPE_PEM)) != 1) { + return srs_error_new(ERROR_TLS_KEY_CRT, "use key %s", key_file.c_str()); + } + + if ((r0 = SSL_check_private_key(ssl_)) != 1) { + return srs_error_new(ERROR_TLS_KEY_CRT, "check key %s with cert %s", + key_file.c_str(), crt_file.c_str()); + } + srs_info("ssl: use key %s and cert %s", key_file.c_str(), crt_file.c_str()); + + // Receive ClientHello + while (true) { + char buf[1024]; + ssize_t nn = 0; + if ((err = transport_->read(buf, sizeof(buf), &nn)) != srs_success) { + return srs_error_wrap(err, "handshake: read"); + } + + if ((r0 = BIO_write(bio_in_, buf, nn)) <= 0) { + // TODO: 0 or -1 maybe block, use BIO_should_retry to check. + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn); + } + + r0 = SSL_do_handshake(ssl_); + r1 = SSL_get_error(ssl_, r0); + ERR_clear_error(); + if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1); + } + + if ((size = BIO_get_mem_data(bio_out_, &data)) > 0) { + // OK, reset it for the next write. + if ((r0 = BIO_reset(bio_in_)) != 1) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); + } + break; + } + } + + srs_info("tls: ClientHello done"); + + // Send ServerHello, Certificate, Server Key Exchange, Server Hello Done + size = BIO_get_mem_data(bio_out_, &data); + if (!data || size <= 0) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake data=%p, size=%d", data, size); + } + if ((err = transport_->write(data, size, NULL)) != srs_success) { + return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size); + } + if ((r0 = BIO_reset(bio_out_)) != 1) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); + } + + srs_info("tls: ServerHello done"); + + // Receive Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message + while (true) { + char buf[1024]; + ssize_t nn = 0; + if ((err = transport_->read(buf, sizeof(buf), &nn)) != srs_success) { + return srs_error_wrap(err, "handshake: read"); + } + + if ((r0 = BIO_write(bio_in_, buf, nn)) <= 0) { + // TODO: 0 or -1 maybe block, use BIO_should_retry to check. + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn); + } + + r0 = SSL_do_handshake(ssl_); + r1 = SSL_get_error(ssl_, r0); + ERR_clear_error(); + if (r0 == 1 && r1 == SSL_ERROR_NONE) { + break; + } + + if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1); + } + + if ((size = BIO_get_mem_data(bio_out_, &data)) > 0) { + // OK, reset it for the next write. + if ((r0 = BIO_reset(bio_in_)) != 1) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); + } + break; + } + } + + srs_info("tls: Client done"); + + // Send New Session Ticket, Change Cipher Spec, Encrypted Handshake Message + size = BIO_get_mem_data(bio_out_, &data); + if (!data || size <= 0) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "handshake data=%p, size=%d", data, size); + } + if ((err = transport_->write(data, size, NULL)) != srs_success) { + return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size); + } + if ((r0 = BIO_reset(bio_out_)) != 1) { + return srs_error_new(ERROR_TLS_HANDSHAKE, "BIO_reset r0=%d", r0); + } + + srs_info("tls: Server done"); + + return err; +} +#pragma GCC diagnostic pop + +void SrsSslConnection::set_recv_timeout(srs_utime_t tm) +{ + transport_->set_recv_timeout(tm); +} + +srs_utime_t SrsSslConnection::get_recv_timeout() +{ + return transport_->get_recv_timeout(); +} + +srs_error_t SrsSslConnection::read_fully(void *buf, size_t size, ssize_t *nread) +{ + srs_error_t err = srs_success; + ssize_t nb = 0; + void *p = buf; + while ((size_t)nb < size) { + ssize_t once_nb = 0; + if ((err = read((char *)p + nb, size - nb, &once_nb)) != srs_success) { + return srs_error_wrap(err, "tls: read"); + } + nb += once_nb; + } + + if (nread) { + *nread = nb; + } + + return err; +} + +int64_t SrsSslConnection::get_recv_bytes() +{ + return transport_->get_recv_bytes(); +} + +int64_t SrsSslConnection::get_send_bytes() +{ + return transport_->get_send_bytes(); +} + +srs_error_t SrsSslConnection::read(void *plaintext, size_t nn_plaintext, ssize_t *nread) +{ + srs_error_t err = srs_success; + + while (true) { + int r0 = SSL_read(ssl_, plaintext, nn_plaintext); + int r1 = SSL_get_error(ssl_, r0); + ERR_clear_error(); + int r2 = BIO_ctrl_pending(bio_in_); + int r3 = SSL_is_init_finished(ssl_); + + // OK, got data. + if (r0 > 0) { + srs_assert(r0 <= (int)nn_plaintext); + if (nread) { + *nread = r0; + } + return err; + } + + // Need to read more data to feed SSL. + if (r0 == -1 && r1 == SSL_ERROR_WANT_READ) { + // TODO: Can we avoid copy? + int nn_cipher = nn_plaintext; + SrsUniquePtr cipher(new char[nn_cipher]); + + // Read the cipher from SSL. + ssize_t nn = 0; + if ((err = transport_->read(cipher.get(), nn_cipher, &nn)) != srs_success) { + return srs_error_wrap(err, "tls: read"); + } + + int r0 = BIO_write(bio_in_, cipher.get(), nn); + if (r0 <= 0) { + // TODO: 0 or -1 maybe block, use BIO_should_retry to check. + return srs_error_new(ERROR_TLS_READ, "BIO_write r0=%d, cipher=%p, size=%d", r0, cipher.get(), nn); + } + continue; + } + + // Fail for error. + if (r0 <= 0) { + return srs_error_new(ERROR_TLS_READ, "SSL_read r0=%d, r1=%d, r2=%d, r3=%d", + r0, r1, r2, r3); + } + } +} + +void SrsSslConnection::set_send_timeout(srs_utime_t tm) +{ + transport_->set_send_timeout(tm); +} + +srs_utime_t SrsSslConnection::get_send_timeout() +{ + return transport_->get_send_timeout(); +} + +srs_error_t SrsSslConnection::write(void *plaintext, size_t nn_plaintext, ssize_t *nwrite) +{ + srs_error_t err = srs_success; + + for (char *p = (char *)plaintext; p < (char *)plaintext + nn_plaintext;) { + int left = (int)nn_plaintext - (p - (char *)plaintext); + int r0 = SSL_write(ssl_, (const void *)p, left); + int r1 = SSL_get_error(ssl_, r0); + ERR_clear_error(); + if (r0 <= 0) { + return srs_error_new(ERROR_TLS_WRITE, "tls: write data=%p, size=%d, r0=%d, r1=%d", p, left, r0, r1); + } + + // Move p to the next writing position. + p += r0; + if (nwrite) { + *nwrite += (ssize_t)r0; + } + + uint8_t *data = NULL; + int size = BIO_get_mem_data(bio_out_, &data); + if ((err = transport_->write(data, size, NULL)) != srs_success) { + return srs_error_wrap(err, "tls: write data=%p, size=%d", data, size); + } + if ((r0 = BIO_reset(bio_out_)) != 1) { + return srs_error_new(ERROR_TLS_WRITE, "BIO_reset r0=%d", r0); + } + } + + return err; +} + +srs_error_t SrsSslConnection::writev(const iovec *iov, int iov_size, ssize_t *nwrite) +{ + srs_error_t err = srs_success; + + for (int i = 0; i < iov_size; i++) { + const iovec *p = iov + i; + if ((err = write((void *)p->iov_base, (size_t)p->iov_len, nwrite)) != srs_success) { + return srs_error_wrap(err, "write iov #%d base=%p, size=%d", i, p->iov_base, p->iov_len); + } + } + + return err; } diff --git a/trunk/src/protocol/srs_protocol_conn.hpp b/trunk/src/protocol/srs_protocol_conn.hpp index b49cb7110d3..3eb0f136294 100644 --- a/trunk/src/protocol/srs_protocol_conn.hpp +++ b/trunk/src/protocol/srs_protocol_conn.hpp @@ -12,46 +12,142 @@ #include #include -// The resource managed by ISrsResourceManager. -class ISrsResource +#include +#include + +#include +#include +#include +#include + +class SrsBuffer; + +// The connection interface for all HTTP/RTMP/RTSP object. +class ISrsConnection : public ISrsResource { public: - ISrsResource(); - virtual ~ISrsResource(); + ISrsConnection(); + virtual ~ISrsConnection(); public: - // Get the context id of connection. - virtual const SrsContextId &get_id() = 0; + // Get remote ip address. + virtual std::string remote_ip() = 0; +}; + +// If a connection is able be expired, user can use HTTP-API to kick-off it. +class ISrsExpire +{ +public: + ISrsExpire(); + virtual ~ISrsExpire(); public: - // The resource description, optional. - virtual std::string desc(); + // Set connection to expired to kick-off it. + virtual void expire() = 0; }; -// The manager for resource. -class ISrsResourceManager +// The basic connection of SRS, for TCP based protocols, +// all connections accept from listener must extends from this base class, +// server will add the connection to manager, and delete it when remove. +class SrsTcpConnection : public ISrsProtocolReadWriter { +private: + // The underlayer st fd handler. + srs_netfd_t stfd_; + // The underlayer socket. + SrsStSocket *skt_; + public: - ISrsResourceManager(); - virtual ~ISrsResourceManager(); + SrsTcpConnection(srs_netfd_t c); + virtual ~SrsTcpConnection(); public: - // Remove then free the specified connection. Note that the manager always free c resource, - // in the same coroutine or another coroutine. Some manager may support add c to a map, it - // should always free it even if it's in the map. - virtual void remove(ISrsResource *c) = 0; + // Set socket option TCP_NODELAY. + virtual srs_error_t set_tcp_nodelay(bool v); + // Set socket option SO_SNDBUF in srs_utime_t. + virtual srs_error_t set_socket_buffer(srs_utime_t buffer_v); + // Interface ISrsProtocolReadWriter +public: + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); }; -// The connection interface for all HTTP/RTMP/RTSP object. -class ISrsConnection : public ISrsResource +// With a small fast read buffer, to support peek for protocol detecting. Note that directly write to io without any +// cache or buffer. +class SrsBufferedReadWriter : public ISrsProtocolReadWriter { +private: + // The under-layer transport. + ISrsProtocolReadWriter *io_; + // Fixed, small and fast buffer. Note that it must be very small piece of cache, make sure matches all protocols, + // because we will full fill it when peeking. + char cache_[16]; + // Current reading position. + SrsBuffer *buf_; + public: - ISrsConnection(); - virtual ~ISrsConnection(); + SrsBufferedReadWriter(ISrsProtocolReadWriter *io); + virtual ~SrsBufferedReadWriter(); public: - // Get remote ip address. - virtual std::string remote_ip() = 0; + // Peek the head of cache to buf in size of bytes. + srs_error_t peek(char *buf, int *size); + +private: + srs_error_t reload_buffer(); + // Interface ISrsProtocolReadWriter +public: + virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); + virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); +}; + +// The SSL connection over TCP transport, in server mode. +class SrsSslConnection : public ISrsProtocolReadWriter +{ +private: + // The under-layer plaintext transport. + ISrsProtocolReadWriter *transport_; + +private: + SSL_CTX *ssl_ctx_; + SSL *ssl_; + BIO *bio_in_; + BIO *bio_out_; + +public: + SrsSslConnection(ISrsProtocolReadWriter *c); + virtual ~SrsSslConnection(); + +public: + virtual srs_error_t handshake(std::string key_file, std::string crt_file); + // Interface ISrsProtocolReadWriter +public: + virtual void set_recv_timeout(srs_utime_t tm); + virtual srs_utime_t get_recv_timeout(); + virtual srs_error_t read_fully(void *buf, size_t size, ssize_t *nread); + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + virtual srs_error_t read(void *buf, size_t size, ssize_t *nread); + virtual void set_send_timeout(srs_utime_t tm); + virtual srs_utime_t get_send_timeout(); + virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite); + virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite); }; #endif diff --git a/trunk/src/protocol/srs_protocol_http_client.cpp b/trunk/src/protocol/srs_protocol_http_client.cpp index edf0c16b477..cb48b8e7dea 100644 --- a/trunk/src/protocol/srs_protocol_http_client.cpp +++ b/trunk/src/protocol/srs_protocol_http_client.cpp @@ -13,10 +13,10 @@ using namespace std; #include #include #include +#include #include #include #include -#include // The return value of verify_callback controls the strategy of the further verification process. If verify_callback // returns 0, the verification process is immediately stopped with "verification failed" state. If SSL_VERIFY_PEER is diff --git a/trunk/src/protocol/srs_protocol_io.cpp b/trunk/src/protocol/srs_protocol_io.cpp index d584522a614..2bf873c5952 100644 --- a/trunk/src/protocol/srs_protocol_io.cpp +++ b/trunk/src/protocol/srs_protocol_io.cpp @@ -6,14 +6,6 @@ #include -ISrsProtocolStatistic::ISrsProtocolStatistic() -{ -} - -ISrsProtocolStatistic::~ISrsProtocolStatistic() -{ -} - ISrsProtocolReader::ISrsProtocolReader() { } diff --git a/trunk/src/protocol/srs_protocol_io.hpp b/trunk/src/protocol/srs_protocol_io.hpp index 86c51346f91..793b863d328 100644 --- a/trunk/src/protocol/srs_protocol_io.hpp +++ b/trunk/src/protocol/srs_protocol_io.hpp @@ -39,22 +39,6 @@ * +----------------------------------+ */ -/** - * Get the statistic of channel. - */ -class ISrsProtocolStatistic -{ -public: - ISrsProtocolStatistic(); - virtual ~ISrsProtocolStatistic(); - // For protocol -public: - // Get the total recv bytes over underlay fd. - virtual int64_t get_recv_bytes() = 0; - // Get the total send bytes over underlay fd. - virtual int64_t get_send_bytes() = 0; -}; - /** * the reader for the protocol to read from whatever channel. */ diff --git a/trunk/src/protocol/srs_protocol_kbps.cpp b/trunk/src/protocol/srs_protocol_kbps.cpp deleted file mode 100644 index 09624327a7d..00000000000 --- a/trunk/src/protocol/srs_protocol_kbps.cpp +++ /dev/null @@ -1,288 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#include - -#include - -SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c) -{ - clk_ = c; - starttime_ = 0; - bytes_ = 0; -} - -SrsKbpsSlice::~SrsKbpsSlice() -{ -} - -void SrsKbpsSlice::sample() -{ - srs_utime_t now = clk_->now(); - - if (sample_30s_.time_ < 0) { - sample_30s_.update(bytes_, now, 0); - } - if (sample_1m_.time_ < 0) { - sample_1m_.update(bytes_, now, 0); - } - if (sample_5m_.time_ < 0) { - sample_5m_.update(bytes_, now, 0); - } - if (sample_60m_.time_ < 0) { - sample_60m_.update(bytes_, now, 0); - } - - if (now - sample_30s_.time_ >= 30 * SRS_UTIME_SECONDS) { - int kbps = (int)((bytes_ - sample_30s_.total_) * 8 / srsu2ms(now - sample_30s_.time_)); - sample_30s_.update(bytes_, now, kbps); - } - if (now - sample_1m_.time_ >= 60 * SRS_UTIME_SECONDS) { - int kbps = (int)((bytes_ - sample_1m_.total_) * 8 / srsu2ms(now - sample_1m_.time_)); - sample_1m_.update(bytes_, now, kbps); - } - if (now - sample_5m_.time_ >= 300 * SRS_UTIME_SECONDS) { - int kbps = (int)((bytes_ - sample_5m_.total_) * 8 / srsu2ms(now - sample_5m_.time_)); - sample_5m_.update(bytes_, now, kbps); - } - if (now - sample_60m_.time_ >= 3600 * SRS_UTIME_SECONDS) { - int kbps = (int)((bytes_ - sample_60m_.total_) * 8 / srsu2ms(now - sample_60m_.time_)); - sample_60m_.update(bytes_, now, kbps); - } -} - -ISrsKbpsDelta::ISrsKbpsDelta() -{ -} - -ISrsKbpsDelta::~ISrsKbpsDelta() -{ -} - -SrsEphemeralDelta::SrsEphemeralDelta() -{ - in_ = out_ = 0; -} - -SrsEphemeralDelta::~SrsEphemeralDelta() -{ -} - -void SrsEphemeralDelta::add_delta(int64_t in, int64_t out) -{ - in_ += in; - out_ += out; -} - -void SrsEphemeralDelta::remark(int64_t *in, int64_t *out) -{ - if (in) - *in = in_; - if (out) - *out = out_; - in_ = out_ = 0; -} - -SrsNetworkDelta::SrsNetworkDelta() -{ - in_ = out_ = NULL; - in_base_ = in_delta_ = 0; - out_base_ = out_delta_ = 0; -} - -SrsNetworkDelta::~SrsNetworkDelta() -{ -} - -void SrsNetworkDelta::set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out) -{ - if (in_) { - in_delta_ += in_->get_recv_bytes() - in_base_; - } - if (in) { - in_base_ = in->get_recv_bytes(); - in_delta_ += in_base_; - } - in_ = in; - - if (out_) { - out_delta_ += out_->get_send_bytes() - out_base_; - } - if (out) { - out_base_ = out->get_send_bytes(); - out_delta_ += out_base_; - } - out_ = out; -} - -void SrsNetworkDelta::remark(int64_t *in, int64_t *out) -{ - if (in_) { - in_delta_ += in_->get_recv_bytes() - in_base_; - in_base_ = in_->get_recv_bytes(); - } - if (out_) { - out_delta_ += out_->get_send_bytes() - out_base_; - out_base_ = out_->get_send_bytes(); - } - - *in = in_delta_; - *out = out_delta_; - in_delta_ = out_delta_ = 0; -} - -SrsKbps::SrsKbps(SrsWallClock *c) -{ - clk_ = c ? c : _srs_clock; - is_ = new SrsKbpsSlice(clk_); - os_ = new SrsKbpsSlice(clk_); -} - -SrsKbps::~SrsKbps() -{ - srs_freep(is_); - srs_freep(os_); -} - -int SrsKbps::get_send_kbps() -{ - int duration = srsu2ms(clk_->now() - is_->starttime_); - if (duration <= 0) { - return 0; - } - - int64_t bytes = get_send_bytes(); - return (int)(bytes * 8 / duration); -} - -int SrsKbps::get_recv_kbps() -{ - int duration = srsu2ms(clk_->now() - os_->starttime_); - if (duration <= 0) { - return 0; - } - - int64_t bytes = get_recv_bytes(); - return (int)(bytes * 8 / duration); -} - -int SrsKbps::get_send_kbps_30s() -{ - return os_->sample_30s_.rate_; -} - -int SrsKbps::get_recv_kbps_30s() -{ - return is_->sample_30s_.rate_; -} - -int SrsKbps::get_send_kbps_5m() -{ - return os_->sample_5m_.rate_; -} - -int SrsKbps::get_recv_kbps_5m() -{ - return is_->sample_5m_.rate_; -} - -void SrsKbps::add_delta(ISrsKbpsDelta *delta) -{ - if (!delta) - return; - - int64_t in, out; - delta->remark(&in, &out); - add_delta(in, out); -} - -void SrsKbps::add_delta(int64_t in, int64_t out) -{ - // update the total bytes - is_->bytes_ += in; - os_->bytes_ += out; - - // we donot sample, please use sample() to do resample. -} - -void SrsKbps::sample() -{ - is_->sample(); - os_->sample(); -} - -int64_t SrsKbps::get_send_bytes() -{ - return os_->bytes_; -} - -int64_t SrsKbps::get_recv_bytes() -{ - return is_->bytes_; -} - -SrsNetworkKbps::SrsNetworkKbps(SrsWallClock *clock) -{ - delta_ = new SrsNetworkDelta(); - kbps_ = new SrsKbps(clock); -} - -SrsNetworkKbps::~SrsNetworkKbps() -{ - srs_freep(kbps_); - srs_freep(delta_); -} - -void SrsNetworkKbps::set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out) -{ - delta_->set_io(in, out); -} - -void SrsNetworkKbps::sample() -{ - kbps_->add_delta(delta_); - kbps_->sample(); -} - -int SrsNetworkKbps::get_send_kbps() -{ - return kbps_->get_send_kbps(); -} - -int SrsNetworkKbps::get_recv_kbps() -{ - return kbps_->get_recv_kbps(); -} - -int SrsNetworkKbps::get_send_kbps_30s() -{ - return kbps_->get_send_kbps_30s(); -} - -int SrsNetworkKbps::get_recv_kbps_30s() -{ - return kbps_->get_recv_kbps_30s(); -} - -int SrsNetworkKbps::get_send_kbps_5m() -{ - return kbps_->get_send_kbps_5m(); -} - -int SrsNetworkKbps::get_recv_kbps_5m() -{ - return kbps_->get_recv_kbps_5m(); -} - -int64_t SrsNetworkKbps::get_send_bytes() -{ - return kbps_->get_send_bytes(); -} - -int64_t SrsNetworkKbps::get_recv_bytes() -{ - return kbps_->get_recv_bytes(); -} diff --git a/trunk/src/protocol/srs_protocol_kbps.hpp b/trunk/src/protocol/srs_protocol_kbps.hpp deleted file mode 100644 index 66e9b4db54d..00000000000 --- a/trunk/src/protocol/srs_protocol_kbps.hpp +++ /dev/null @@ -1,182 +0,0 @@ -// -// Copyright (c) 2013-2025 The SRS Authors -// -// SPDX-License-Identifier: MIT -// - -#ifndef SRS_PROTOCOL_KBPS_HPP -#define SRS_PROTOCOL_KBPS_HPP - -#include - -#include -#include - -/** - * The slice of kbps statistic, for input or output. - */ -class SrsKbpsSlice -{ -private: - SrsWallClock *clk_; - -public: - // session startup bytes - // @remark, use total_bytes() to get the total bytes of slice. - int64_t bytes_; - // slice starttime, the first time to record bytes. - srs_utime_t starttime_; - // samples - SrsRateSample sample_30s_; - SrsRateSample sample_1m_; - SrsRateSample sample_5m_; - SrsRateSample sample_60m_; - -public: - SrsKbpsSlice(SrsWallClock *c); - virtual ~SrsKbpsSlice(); - -public: - // Resample the slice to calculate the kbps. - virtual void sample(); -}; - -/** - * The interface which provices delta of bytes. For example, we got a delta from a TCP client: - * ISrsKbpsDelta* delta = ...; - * Now, we can add delta simple to a kbps: - * kbps->add_delta(delta); - * Or by multiple kbps: - * int64_t in, out; - * delta->remark(&in, &out); - * kbps1->add_delta(in, out); - * kbpsN->add_delta(in, out); - * Then you're able to use the kbps object. - */ -class ISrsKbpsDelta -{ -public: - ISrsKbpsDelta(); - virtual ~ISrsKbpsDelta(); - -public: - // Resample to get the value of delta bytes. - // @remark If no delta bytes, both in and out will be set to 0. - virtual void remark(int64_t *in, int64_t *out) = 0; -}; - -// A delta data source for SrsKbps, used in ephemeral case, for example, UDP server to increase stat when received or -// sent out each UDP packet. -class SrsEphemeralDelta : public ISrsKbpsDelta -{ -private: - uint64_t in_; - uint64_t out_; - -public: - SrsEphemeralDelta(); - virtual ~SrsEphemeralDelta(); - -public: - virtual void add_delta(int64_t in, int64_t out); - // Interface ISrsKbpsDelta. -public: - virtual void remark(int64_t *in, int64_t *out); -}; - -// A network delta data source for SrsKbps. -class SrsNetworkDelta : public ISrsKbpsDelta -{ -private: - ISrsProtocolStatistic *in_; - ISrsProtocolStatistic *out_; - uint64_t in_base_; - uint64_t in_delta_; - uint64_t out_base_; - uint64_t out_delta_; - -public: - SrsNetworkDelta(); - virtual ~SrsNetworkDelta(); - -public: - // Switch the under-layer network io, we use the bytes as a fresh delta. - virtual void set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out); - // Interface ISrsKbpsDelta. -public: - virtual void remark(int64_t *in, int64_t *out); -}; - -/** - * To statistic the kbps. For example, we got a set of connections and add the total delta: - * SrsKbps* kbps = ...; - * for conn in connections: - * kbps->add_delta(conn->delta()) // Which return an ISrsKbpsDelta object. - * Then we sample and got the total kbps: - * kbps->sample() - * kbps->get_xxx_kbps(). - */ -class SrsKbps -{ -private: - SrsKbpsSlice *is_; - SrsKbpsSlice *os_; - SrsWallClock *clk_; - -public: - // Note that we won't free the clock c. - SrsKbps(SrsWallClock *c = NULL); - virtual ~SrsKbps(); - -public: - // Get total average kbps. - virtual int get_send_kbps(); - virtual int get_recv_kbps(); - // Get the average kbps in 30s. - virtual int get_send_kbps_30s(); - virtual int get_recv_kbps_30s(); - // Get the average kbps in 5m or 300s. - virtual int get_send_kbps_5m(); - virtual int get_recv_kbps_5m(); - -public: - // Add delta to kbps. Please call sample() after all deltas are added to kbps. - virtual void add_delta(int64_t in, int64_t out); - virtual void add_delta(ISrsKbpsDelta *delta); - // Sample the kbps to get the kbps in N seconds. - virtual void sample(); - -public: - virtual int64_t get_send_bytes(); - virtual int64_t get_recv_bytes(); -}; - -// A sugar to use SrsNetworkDelta and SrsKbps. -class SrsNetworkKbps -{ -private: - SrsNetworkDelta *delta_; - SrsKbps *kbps_; - -public: - SrsNetworkKbps(SrsWallClock *c = NULL); - virtual ~SrsNetworkKbps(); - -public: - virtual void set_io(ISrsProtocolStatistic *in, ISrsProtocolStatistic *out); - virtual void sample(); - -public: - virtual int get_send_kbps(); - virtual int get_recv_kbps(); - virtual int get_send_kbps_30s(); - virtual int get_recv_kbps_30s(); - virtual int get_send_kbps_5m(); - virtual int get_recv_kbps_5m(); - -public: - virtual int64_t get_send_bytes(); - virtual int64_t get_recv_bytes(); -}; - -#endif diff --git a/trunk/src/protocol/srs_protocol_log.cpp b/trunk/src/protocol/srs_protocol_log.cpp index a7e1a3a98e5..9bea6687281 100644 --- a/trunk/src/protocol/srs_protocol_log.cpp +++ b/trunk/src/protocol/srs_protocol_log.cpp @@ -16,7 +16,7 @@ using namespace std; #include #include -#include +#include SrsPps *_srs_pps_cids_get = NULL; SrsPps *_srs_pps_cids_set = NULL; @@ -93,16 +93,6 @@ const SrsContextId &srs_context_set_cid_of(srs_thread_t trd, const SrsContextId return v; } -impl_SrsContextRestore::impl_SrsContextRestore(SrsContextId cid) -{ - cid_ = cid; -} - -impl_SrsContextRestore::~impl_SrsContextRestore() -{ - _srs_context->set_id(cid_); -} - // LCOV_EXCL_START SrsConsoleLog::SrsConsoleLog(SrsLogLevel l, bool u) { diff --git a/trunk/src/protocol/srs_protocol_log.hpp b/trunk/src/protocol/srs_protocol_log.hpp index b79d6ed8e8c..350dde9b4b9 100644 --- a/trunk/src/protocol/srs_protocol_log.hpp +++ b/trunk/src/protocol/srs_protocol_log.hpp @@ -38,20 +38,6 @@ class SrsThreadContext : public ISrsContext // Set the context id of specified thread, not self. extern const SrsContextId &srs_context_set_cid_of(srs_thread_t trd, const SrsContextId &v); -// The context restore stores the context and restore it when done. -// Usage: -// SrsContextRestore(_srs_context->get_id()); -#define SrsContextRestore(cid) impl_SrsContextRestore _context_restore_instance(cid) -class impl_SrsContextRestore -{ -private: - SrsContextId cid_; - -public: - impl_SrsContextRestore(SrsContextId cid); - virtual ~impl_SrsContextRestore(); -}; - // The basic console log, which write log to console. class SrsConsoleLog : public ISrsLog { diff --git a/trunk/src/protocol/srs_protocol_rtmp_conn.cpp b/trunk/src/protocol/srs_protocol_rtmp_conn.cpp index c9e15317e38..78093866f88 100644 --- a/trunk/src/protocol/srs_protocol_rtmp_conn.cpp +++ b/trunk/src/protocol/srs_protocol_rtmp_conn.cpp @@ -9,8 +9,8 @@ #include using namespace std; +#include #include -#include #include #include #include diff --git a/trunk/src/app/srs_app_rtc_sdp.cpp b/trunk/src/protocol/srs_protocol_sdp.cpp similarity index 99% rename from trunk/src/app/srs_app_rtc_sdp.cpp rename to trunk/src/protocol/srs_protocol_sdp.cpp index e7d934d389b..61242f76df2 100644 --- a/trunk/src/app/srs_app_rtc_sdp.cpp +++ b/trunk/src/protocol/srs_protocol_sdp.cpp @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT // -#include +#include #include diff --git a/trunk/src/app/srs_app_rtc_sdp.hpp b/trunk/src/protocol/srs_protocol_sdp.hpp similarity index 99% rename from trunk/src/app/srs_app_rtc_sdp.hpp rename to trunk/src/protocol/srs_protocol_sdp.hpp index 6633e09e880..91bf96dcda2 100644 --- a/trunk/src/app/srs_app_rtc_sdp.hpp +++ b/trunk/src/protocol/srs_protocol_sdp.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: MIT // -#ifndef SRS_APP_RTC_SDP_HPP -#define SRS_APP_RTC_SDP_HPP +#ifndef SRS_PROTOCOL_SDP_HPP +#define SRS_PROTOCOL_SDP_HPP #include #include @@ -15,6 +15,7 @@ #include #include #include + const std::string kTWCCExt = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; // TDOO: FIXME: Rename it, and add utest. diff --git a/trunk/src/protocol/srs_protocol_st.hpp b/trunk/src/protocol/srs_protocol_st.hpp index 252a53d010b..59acd275538 100644 --- a/trunk/src/protocol/srs_protocol_st.hpp +++ b/trunk/src/protocol/srs_protocol_st.hpp @@ -12,6 +12,7 @@ #include #include +#include #include // Wrap for SRT. @@ -88,7 +89,7 @@ extern int srs_mutex_unlock(srs_mutex_t mutex); // For example: // SrsUniquePtr cond(new SrsCond()); // cond->signal(); -class SrsCond +class SrsCond : public ISrsCond { private: srs_cond_t cond_; diff --git a/trunk/src/protocol/srs_protocol_utility.cpp b/trunk/src/protocol/srs_protocol_utility.cpp index 92765cc5490..e6d2f37229d 100644 --- a/trunk/src/protocol/srs_protocol_utility.cpp +++ b/trunk/src/protocol/srs_protocol_utility.cpp @@ -11,6 +11,7 @@ #include #include #include +#include using namespace std; #include @@ -36,6 +37,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -710,3 +712,136 @@ utsname *srs_get_system_uname_info() return system_info; } #endif + +// See streamid of https://github.com/ossrs/srs/issues/2893 +// TODO: FIMXE: We should parse SRT streamid to URL object, rather than a HTTP url subpath. +bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::string &vhost, std::string &url_subpath) +{ + mode = SrtModePull; + + size_t pos = streamid.find("#!::"); + if (pos != 0) { + pos = streamid.find("/"); + if (pos == streamid.npos) { + SrsUniquePtr config(_srs_kernel_factory->create_config()); + url_subpath = config->get_default_app_name() + "/" + streamid; + return true; + } + url_subpath = streamid; + return true; + } + + // SRT url supports multiple QueryStrings, which are passed to RTMP to realize authentication and other capabilities + //@see https://github.com/ossrs/srs/issues/2893 + std::string params; + std::string real_streamid; + real_streamid = streamid.substr(4); + + // Compatible with previous auth querystring, like this one: + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream?secret=xxx,m=publish + real_streamid = srs_strings_replace(real_streamid, "?", ","); + + std::map query; + srs_net_url_parse_query(real_streamid, query); + for (std::map::iterator it = query.begin(); it != query.end(); ++it) { + if (it->first == "h") { + std::string host = it->second; + + size_t r0 = host.find("/"); + size_t r1 = host.rfind("/"); + if (r0 != std::string::npos && r0 != std::string::npos) { + // Compatible with previous style, see https://github.com/ossrs/srs/issues/2893#compatible + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=publish + // srt://127.0.0.1:10080?streamid=#!::h=live/livestream,m=request + // srt://127.0.0.1:10080?streamid=#!::h=srs.srt.com.cn/live/livestream,m=publish + if (r0 != r1) { + // We got vhost in host. + url_subpath = host.substr(r0 + 1); + host = host.substr(0, r0); + + params.append("vhost="); + params.append(host); + params.append("&"); + vhost = host; + } else { + // Only stream in host. + url_subpath = host; + } + } else { + // New URL style, see https://github.com/ossrs/srs/issues/2893#solution + // srt://host.com:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 + // srt://1.2.3.4:10080?streamid=#!::h=host.com,r=app/stream,key1=value1,key2=value2 + // srt://1.2.3.4:10080?streamid=#!::r=app/stream,key1=value1,key2=value2 + params.append("vhost="); + params.append(host); + params.append("&"); + vhost = host; + } + } else if (it->first == "r") { + url_subpath = it->second; + } else if (it->first == "m") { + std::string mode_str = it->second; // support m=publish or m=request + std::transform(it->second.begin(), it->second.end(), mode_str.begin(), ::tolower); + if (mode_str == "publish") { + mode = SrtModePush; + } else if (mode_str == "request") { + mode = SrtModePull; + } else { + srs_warn("unknown mode_str:%s", mode_str.c_str()); + return false; + } + } else { + params.append(it->first); + params.append("="); + params.append(it->second); + params.append("&"); + } + } + + if (url_subpath.empty()) { + return false; + } + + if (!params.empty()) { + url_subpath.append("?"); + url_subpath.append(params); + url_subpath = url_subpath.substr(0, url_subpath.length() - 1); // remove last '&' + } + + return true; +} + +bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request) +{ + string url_subpath = ""; + bool ret = srs_srt_streamid_info(streamid, mode, request->vhost_, url_subpath); + if (!ret) { + return ret; + } + + size_t pos = url_subpath.find("/"); + string stream_with_params = ""; + if (pos == string::npos) { + SrsUniquePtr config(_srs_kernel_factory->create_config()); + request->app_ = config->get_default_app_name(); + stream_with_params = url_subpath; + } else { + request->app_ = url_subpath.substr(0, pos); + stream_with_params = url_subpath.substr(pos + 1); + } + + pos = stream_with_params.find("?"); + if (pos == string::npos) { + request->stream_ = stream_with_params; + } else { + request->stream_ = stream_with_params.substr(0, pos); + request->param_ = stream_with_params.substr(pos + 1); + } + + request->host_ = srs_get_public_internet_address(); + if (request->vhost_.empty()) + request->vhost_ = request->host_; + request->tcUrl_ = srs_net_url_encode_tcurl("srt", request->host_, request->vhost_, request->app_, request->port_); + + return ret; +} diff --git a/trunk/src/protocol/srs_protocol_utility.hpp b/trunk/src/protocol/srs_protocol_utility.hpp index 0ccc0d3509c..ef01756a5d9 100644 --- a/trunk/src/protocol/srs_protocol_utility.hpp +++ b/trunk/src/protocol/srs_protocol_utility.hpp @@ -139,4 +139,17 @@ extern std::string srs_get_system_hostname(void); extern utsname *srs_get_system_uname_info(); #endif +class ISrsRequest; + +enum SrtMode { + SrtModePull = 1, + SrtModePush = 2, +}; + +// Get SRT streamid info. +extern bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::string &vhost, std::string &url_subpath); + +// SRT streamid to request. +extern bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request); + #endif diff --git a/trunk/src/utest/srs_utest.cpp b/trunk/src/utest/srs_utest.cpp index 4850946f4cc..abfa0984dee 100644 --- a/trunk/src/utest/srs_utest.cpp +++ b/trunk/src/utest/srs_utest.cpp @@ -21,6 +21,7 @@ using namespace std; #include #include +#include #include #include @@ -39,6 +40,9 @@ SrsConfig *_srs_config = NULL; bool _srs_in_docker = false; bool _srs_config_by_env = false; +// @global kernel factory. +ISrsKernelFactory *_srs_kernel_factory = new SrsFinalFactory(); + // The binary name of SRS. const char *_srs_binary = NULL; diff --git a/trunk/src/utest/srs_utest_app.cpp b/trunk/src/utest/srs_utest_app.cpp index ce26c605c2a..01566bc0d8c 100644 --- a/trunk/src/utest/srs_utest_app.cpp +++ b/trunk/src/utest/srs_utest_app.cpp @@ -12,7 +12,6 @@ using namespace std; #include #include -#include #include #include #include diff --git a/trunk/src/utest/srs_utest_config.cpp b/trunk/src/utest/srs_utest_config.cpp index e14d7613a20..e06fe931d56 100644 --- a/trunk/src/utest/srs_utest_config.cpp +++ b/trunk/src/utest/srs_utest_config.cpp @@ -8,7 +8,7 @@ using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/utest/srs_utest_core.cpp b/trunk/src/utest/srs_utest_core.cpp index d6e9910eb89..18e3f82071c 100644 --- a/trunk/src/utest/srs_utest_core.cpp +++ b/trunk/src/utest/srs_utest_core.cpp @@ -7,7 +7,6 @@ using namespace std; -#include #include #include #include diff --git a/trunk/src/utest/srs_utest_gb28181.cpp b/trunk/src/utest/srs_utest_gb28181.cpp index 2f35ceb07ab..a474e9c0d3a 100644 --- a/trunk/src/utest/srs_utest_gb28181.cpp +++ b/trunk/src/utest/srs_utest_gb28181.cpp @@ -10,7 +10,6 @@ using namespace std; #include #include -#include #include #include #include @@ -18,6 +17,7 @@ using namespace std; #include #include #include +#include #include #include #include diff --git a/trunk/src/utest/srs_utest_pithy_print.cpp b/trunk/src/utest/srs_utest_pithy_print.cpp index 123b2a4a0ef..f80aa8d03c2 100644 --- a/trunk/src/utest/srs_utest_pithy_print.cpp +++ b/trunk/src/utest/srs_utest_pithy_print.cpp @@ -9,9 +9,9 @@ using namespace std; #include -#include #include #include +#include #include // Mock configuration for testing diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp index 4a105400f22..b04abbd091d 100644 --- a/trunk/src/utest/srs_utest_protocol.cpp +++ b/trunk/src/utest/srs_utest_protocol.cpp @@ -21,7 +21,7 @@ using namespace std; #include #include -#include +#include MockEmptyIO::MockEmptyIO() { diff --git a/trunk/src/utest/srs_utest_protocol.hpp b/trunk/src/utest/srs_utest_protocol.hpp index af6ffb35eca..b53c2fbcfad 100644 --- a/trunk/src/utest/srs_utest_protocol.hpp +++ b/trunk/src/utest/srs_utest_protocol.hpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/trunk/src/utest/srs_utest_rtc.cpp b/trunk/src/utest/srs_utest_rtc.cpp index 8ea51130338..1a9a48e3585 100644 --- a/trunk/src/utest/srs_utest_rtc.cpp +++ b/trunk/src/utest/srs_utest_rtc.cpp @@ -5,15 +5,15 @@ // #include -#include #include -#include #include #include #include #include #include +#include #include +#include #include diff --git a/trunk/src/utest/srs_utest_source_lock.cpp b/trunk/src/utest/srs_utest_source_lock.cpp index f3890028624..2612eeac993 100644 --- a/trunk/src/utest/srs_utest_source_lock.cpp +++ b/trunk/src/utest/srs_utest_source_lock.cpp @@ -9,8 +9,8 @@ using namespace std; #include #include +#include #include -#include #include #include #include diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 5a2665c2ff0..ceaa1100435 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -6,12 +6,12 @@ #include #include -#include #include #include #include #include #include +#include #include #include