diff --git a/apps/android/native/rtc_bridge.cpp b/apps/android/native/rtc_bridge.cpp index a0ebbc79..df4a0506 100644 --- a/apps/android/native/rtc_bridge.cpp +++ b/apps/android/native/rtc_bridge.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,6 @@ #include #include "controller_protocol.h" #include "file_transfer_session.h" -#include "android_codec_support.h" #include "latest_frame_worker.h" #include "video_picture.h" #include "video_timing.h" @@ -289,7 +287,7 @@ Session* From(jlong handle) { return reinterpret_cast(handle); } extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* java_vm, void*) { vm = java_vm; - minirtc::android::SetJavaVm(java_vm); + if (SetMiniRtcAndroidJavaVm(java_vm) != 0) return JNI_ERR; return JNI_VERSION_1_6; } #define JNI_METHOD(name) Java_cn_crossdesk_mobile_NativeSession_##name @@ -343,8 +341,8 @@ extern "C" JNIEXPORT jlong JNICALL JNI_METHOD(nCreate)( throw std::runtime_error("Unable to configure Android trust bundle"); // MiniRTC's diagnostic log includes login identities. Keep credentials // solely in Keystore-backed storage; do not persist its session logging. - minirtc::InitLogger(s->log_path); - minirtc::get_logger()->set_level(spdlog::level::off); + if (ConfigureMiniRtcLogging(MiniRtcLogOff, nullptr, nullptr) != 0) + throw std::runtime_error("Unable to configure MiniRTC logging"); auto params = Parameters(s.get(), false); s->identity = CreatePeer(¶ms); if (!s->identity || Init(s->identity) != 0) return 0; diff --git a/apps/android/native/xmake.lua b/apps/android/native/xmake.lua index 82366181..b245d572 100644 --- a/apps/android/native/xmake.lua +++ b/apps/android/native/xmake.lua @@ -9,11 +9,9 @@ includes("../../../deps/submodules/minirtc") target("crossdesk_android") set_kind("shared") add_deps("minirtc") - add_packages("nlohmann_json", "libyuv", "spdlog") + add_packages("nlohmann_json", "libyuv") add_files("rtc_bridge.cpp", "../../../libs/wire/src/remote_action.cpp", "../../../libs/wire/src/app_version.cpp", "../../../libs/wire/src/file_transfer.cpp") add_includedirs("../../../deps/submodules/minirtc/src/api", "../../../libs/wire/include") - -- This source-level JNI adapter is the only application layer using MiniRTC internals. - add_includedirs("../../../deps/submodules/minirtc/src/media/mediacodec") add_syslinks("android", "log") add_shflags("-Wl,-z,max-page-size=16384", "-Wl,-z,common-page-size=16384", {force = true}) set_targetdir("../app/build/native/arm64-v8a") diff --git a/apps/cli/xmake.lua b/apps/cli/xmake.lua index b4f02b2a..a135f0d7 100644 --- a/apps/cli/xmake.lua +++ b/apps/cli/xmake.lua @@ -16,7 +16,6 @@ target("crossdesk_controller") add_packages("spdlog", "libpng", "libyuv") add_includedirs(path.join(controller_dir, "include"), path.join(minirtc_dir, "src/api"), {public = true}) - add_includedirs(path.join(minirtc_dir, "src/log")) add_files(path.join(controller_dir, "src/*.cpp")) remove_files(path.join(controller_dir, "src/file_browser.cpp")) target_end() diff --git a/apps/desktop/src/config_center/config_center.cpp b/apps/desktop/src/config_center/config_center.cpp index 587ae5f7..4cee7957 100644 --- a/apps/desktop/src/config_center/config_center.cpp +++ b/apps/desktop/src/config_center/config_center.cpp @@ -10,7 +10,7 @@ #include "SimpleIni.h" #include "autostart.h" #include "rd_log.h" -#include "signal_server_address.h" +#include namespace crossdesk { @@ -349,22 +349,24 @@ int ConfigCenter::SetForceRelay(bool force_relay) { } int ConfigCenter::SetServerHost(const std::string& host) { - const auto address = minirtc::ParseSignalServerAddress(host); - if (!address) return -1; - if (address->port) return SetServerEndpoint(host, *address->port); - if (StoreValues({{"signal_server_host", address->Address()}}) != 0) return -1; - signal_server_host_ = address->Address(); + MiniRtcSignalServerAddress address{}; + if (ParseMiniRtcSignalServerAddress(host.data(), host.size(), &address) != 0) return -1; + if (address.port) return SetServerEndpoint(host, address.port); + const auto normalized = std::string(address.host) + address.target; + if (StoreValues({{"signal_server_host", normalized}}) != 0) return -1; + signal_server_host_ = normalized; return 0; } int ConfigCenter::SetServerEndpoint(const std::string& host, int port) { - const auto address = minirtc::ParseSignalServerAddress(host); - if (!address) return -1; - port = address->port.value_or(port); + MiniRtcSignalServerAddress address{}; + if (ParseMiniRtcSignalServerAddress(host.data(), host.size(), &address) != 0) return -1; + if (address.port) port = address.port; if (port < 1 || port > 65535) return -1; - if (StoreValues({{"signal_server_host", address->Address()}, + const auto normalized = std::string(address.host) + address.target; + if (StoreValues({{"signal_server_host", normalized}, {"signal_server_port", std::to_string(port)}}) != 0) return -1; - signal_server_host_ = address->Address(); + signal_server_host_ = normalized; signal_server_port_ = port; return 0; } diff --git a/apps/desktop/src/gui/application/gui_application.cpp b/apps/desktop/src/gui/application/gui_application.cpp index 9056b5e0..4c99bada 100644 --- a/apps/desktop/src/gui/application/gui_application.cpp +++ b/apps/desktop/src/gui/application/gui_application.cpp @@ -87,7 +87,7 @@ #include "rd_log.h" #include "server_window_state.h" #include "signal_server_settings.h" -#include "signal_server_address.h" +#include #include "ui/announcement_text.h" #include "ui/model_update.h" #include "ui/release_notes_text.h" @@ -3532,11 +3532,11 @@ void GuiApplication::SyncConnectionDialog() { : auth.incorrect_password ? localization::reinput_password[localization_language_index_] : localization::input_password[localization_language_index_]; - } else if (auth.error == minirtc::JoinFailureKind::Throttled) { + } else if (auth.error == MiniRtcJoinFailureKind::Throttled) { text = localization::connection_auth_throttled[localization_language_index_]; - } else if (auth.error == minirtc::JoinFailureKind::Busy) { + } else if (auth.error == MiniRtcJoinFailureKind::Busy) { text = localization::connection_service_busy[localization_language_index_]; - } else if (auth.error == minirtc::JoinFailureKind::NotAuthenticated) { + } else if (auth.error == MiniRtcJoinFailureKind::NotAuthenticated) { text = localization::connection_not_authenticated[localization_language_index_]; } else { text = props->lan_session_ && !props->lan_session_->error.empty() @@ -4782,20 +4782,20 @@ void GuiApplication::SyncFileTransferNotifications() { bool GuiApplication::ValidateSelfHostedSettingsFromUi(bool gallery_window) { auto& main = ui_->Window(gallery_window); - const auto address = minirtc::ParseSignalServerAddress( - std::string(main->get_server_host())); - if (!address) { + const auto input = std::string(main->get_server_host()); + MiniRtcSignalServerAddress address{}; + if (ParseMiniRtcSignalServerAddress(input.data(), input.size(), &address) != 0) { main->set_self_host_settings_error(UiText( localization::self_hosted_address_invalid[localization_language_index_])); return false; } - const auto port = address->port ? address->port : ParsePort(main->get_server_port()); + const auto port = address.port ? std::optional(address.port) : ParsePort(main->get_server_port()); if (!port) { main->set_self_host_settings_error(UiText( localization::self_hosted_port_invalid[localization_language_index_])); return false; } - main->set_server_host(UiText(address->Address())); + main->set_server_host(UiText(std::string(address.host) + address.target)); main->set_server_port(UiText(std::to_string(*port))); main->set_self_host_settings_error(""); return true; diff --git a/apps/desktop/src/gui/runtime/announcement_inbox.cpp b/apps/desktop/src/gui/runtime/announcement_inbox.cpp index 1183e7f9..1bf72c03 100644 --- a/apps/desktop/src/gui/runtime/announcement_inbox.cpp +++ b/apps/desktop/src/gui/runtime/announcement_inbox.cpp @@ -8,7 +8,7 @@ #include #include -#include "signal_server_address.h" +#include #ifdef _WIN32 #include @@ -53,12 +53,13 @@ void AnnouncementInbox::Configure(std::string host, int port, std::lock_guard lock(mutex_); if (directory_.empty() || host.empty() || port <= 0 || device_id.empty()) return; - auto address = minirtc::ParseSignalServerAddress(host); - if (!address) return; - for (auto& ch : address->host) + MiniRtcSignalServerAddress address{}; + if (ParseMiniRtcSignalServerAddress(host.data(), host.size(), &address) != 0) return; + std::string normalized_host(address.host); + for (auto& ch : normalized_host) if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; - if (address->host.back() == '.') address->host.pop_back(); - host = address->Address(); + if (normalized_host.back() == '.') normalized_host.pop_back(); + host = normalized_host + address.target; const auto scope = json::array({host, port, device_id}).dump(); if (scope_ == scope) return; scope_ = scope; diff --git a/apps/desktop/src/gui/runtime/connection_auth_state.h b/apps/desktop/src/gui/runtime/connection_auth_state.h index e87e1e41..9cee03fb 100644 --- a/apps/desktop/src/gui/runtime/connection_auth_state.h +++ b/apps/desktop/src/gui/runtime/connection_auth_state.h @@ -5,7 +5,8 @@ #include #include -#include "join_failure.h" +#include +#include namespace crossdesk { @@ -18,7 +19,7 @@ class ConnectionAuthState { bool password_required = false; bool validating = false; bool incorrect_password = false; - minirtc::JoinFailureKind error = minirtc::JoinFailureKind::Unknown; + MiniRtcJoinFailureKind error = MiniRtcJoinFailureKind::Unknown; int retry_after = 0; }; @@ -34,15 +35,16 @@ class ConnectionAuthState { void Rejected(const nlohmann::json& reply, Clock::time_point now = Clock::now()) { - const auto failure = minirtc::ParseJoinFailure(reply); + const auto message = reply.dump(); + const auto failure = ParseMiniRtcJoinFailure(message.data(), message.size()); std::lock_guard lock(mutex_); state_ = {}; state_.error = failure.kind; state_.incorrect_password = - failure.kind == minirtc::JoinFailureKind::AuthenticationFailed; + failure.kind == MiniRtcJoinFailureKind::AuthenticationFailed; state_.password_required = state_.incorrect_password || - failure.kind == minirtc::JoinFailureKind::PasswordRequired; + failure.kind == MiniRtcJoinFailureKind::PasswordRequired; retry_at_ = now + std::chrono::seconds(failure.retry_after); } diff --git a/apps/desktop/src/network/lan/lan_identity.cpp b/apps/desktop/src/network/lan/lan_identity.cpp index 3099d87d..eb6bdb36 100644 --- a/apps/desktop/src/network/lan/lan_identity.cpp +++ b/apps/desktop/src/network/lan/lan_identity.cpp @@ -13,7 +13,7 @@ #include #include -#include "direct_address.h" +#include #include "lan_password.h" #ifdef _WIN32 // Winsock must precede windows.h; the networking headers need its types. @@ -212,12 +212,14 @@ unsigned ParsePort(const std::string& value) { return port; } bool IsIpAddress(const std::string& value) { - return minirtc::ParseDirectAddress(value).has_value(); + char normalized[129]{}; + return NormalizeMiniRtcDirectAddress(value.data(), value.size(), normalized, sizeof(normalized)) == 0; } std::string NormalizeAddress(const std::string& value) { - const auto address = minirtc::ParseDirectAddress(value); - Require(address.has_value(), "Invalid LAN endpoint"); - return minirtc::DirectAddressString(*address); + char normalized[129]{}; + Require(NormalizeMiniRtcDirectAddress(value.data(), value.size(), normalized, sizeof(normalized)) == 0, + "Invalid LAN endpoint"); + return normalized; } std::string FormatEndpoint(const std::string& address, unsigned port) { return (address.find(':') == std::string::npos ? address diff --git a/apps/desktop/src/network/lan/lan_transport.cpp b/apps/desktop/src/network/lan/lan_transport.cpp index e99367b5..7c3ebaa6 100644 --- a/apps/desktop/src/network/lan/lan_transport.cpp +++ b/apps/desktop/src/network/lan/lan_transport.cpp @@ -13,7 +13,7 @@ #include #include -#include "direct_address.h" +#include namespace crossdesk::lan { namespace { @@ -147,7 +147,11 @@ bool SupportsDualStack() { std::string SocketAddress(asio::ip::address address) { if (address.is_v6() && address.to_v6().is_v4_mapped()) address = asio::ip::make_address_v4(asio::ip::v4_mapped, address.to_v6()); - return minirtc::DirectAddressString(address); + if (address.is_v4()) return address.to_string(); + auto ipv6 = address.to_v6(); + const auto scope = ipv6.scope_id(); + ipv6.scope_id(0); + return ipv6.to_string() + (scope ? "%" + std::to_string(scope) : ""); } std::shared_ptr TlsContext() { auto context = std::make_shared(Context::tls); @@ -323,7 +327,8 @@ struct Transport::Impl { c->local_address = SocketAddress(local.address()); c->remote_address = SocketAddress(remote.address()); const auto interfaces = LocalIpInterfaces(); - if (!minirtc::IsDirectAddressPair(c->local_address, c->remote_address) || + if (IsMiniRtcDirectAddressPair(c->local_address.data(), c->local_address.size(), + c->remote_address.data(), c->remote_address.size()) != 1 || std::none_of( interfaces.begin(), interfaces.end(), [&](const auto& i) { return i.address == c->local_address; })) { diff --git a/apps/desktop/src/platform/linux/headless/headless_settings.cpp b/apps/desktop/src/platform/linux/headless/headless_settings.cpp index 60074fe8..01ae8afd 100644 --- a/apps/desktop/src/platform/linux/headless/headless_settings.cpp +++ b/apps/desktop/src/platform/linux/headless/headless_settings.cpp @@ -10,7 +10,7 @@ #include #include "config_center.h" -#include "signal_server_address.h" +#include #include "signal_server_settings.h" namespace crossdesk { @@ -88,7 +88,8 @@ SettingResult ApplyConsoleSetting(ConfigCenter& config, const std::string& key, canonical = value; save = [&config, mode] { return config.SetTurnMode(static_cast(mode)); }; } else if (key == "server_host") { - if (!minirtc::ParseSignalServerAddress(input)) return result; + MiniRtcSignalServerAddress address{}; + if (ParseMiniRtcSignalServerAddress(input.data(), input.size(), &address) != 0) return result; save = [&] { return config.SetServerHost(input); }; } else if (key == "server_port") { int port = 0; diff --git a/apps/harmony/native/mobile_session.cpp b/apps/harmony/native/mobile_session.cpp index 3fc9c401..9471bd83 100644 --- a/apps/harmony/native/mobile_session.cpp +++ b/apps/harmony/native/mobile_session.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -257,7 +256,9 @@ class MobileSession { preview_directory_=v.at("previewDirectory").get(); if (server_.empty()||server_.size()>=256||server_.find('@')!=std::string::npos||port_<1||port_>65535|| logs_.size()>=256||roots.empty()||directory_.empty()) throw std::runtime_error("Invalid configuration"); - setenv("SSL_CERT_DIR",roots.c_str(),1); minirtc::InitLogger(logs_); minirtc::get_logger()->set_level(spdlog::level::off); + setenv("SSL_CERT_DIR",roots.c_str(),1); + if (ConfigureMiniRtcLogging(MiniRtcLogOff, nullptr, nullptr) != 0) + throw std::runtime_error("Unable to configure MiniRTC logging"); identity_context_=std::make_unique(Context{this,false,session_}); auto p=Parameters(false); identity_=CreatePeer(&p); signal_started_=Clock::now(); if (!identity_||Init(identity_)!=0) { throw std::runtime_error("Identity initialization failed"); } diff --git a/apps/harmony/native/xmake.lua b/apps/harmony/native/xmake.lua index 2205fa44..68881e46 100644 --- a/apps/harmony/native/xmake.lua +++ b/apps/harmony/native/xmake.lua @@ -10,7 +10,7 @@ target("crossdesk_harmony_mobile") set_kind("shared") set_default(false) add_deps("minirtc") - add_packages("nlohmann_json", "libyuv", "spdlog") + add_packages("nlohmann_json", "libyuv") add_files("mobile_session.cpp", "media.cpp", "audio.cpp", "../../../libs/wire/src/remote_action.cpp", "../../../libs/wire/src/file_transfer.cpp", "../../../libs/wire/src/app_version.cpp") -- Export only the bridge API; bundled static dependencies are internal. add_cxflags("-fvisibility=hidden", "-fvisibility-inlines-hidden") diff --git a/deps/submodules/minirtc b/deps/submodules/minirtc index f67e251a..25ae2403 160000 --- a/deps/submodules/minirtc +++ b/deps/submodules/minirtc @@ -1 +1 @@ -Subproject commit f67e251af32fe74029f249ef393336db2f1a8ff2 +Subproject commit 25ae240374083611516ff2c3641154903150ac62 diff --git a/libs/controller/include/controller_diagnostics.h b/libs/controller/include/controller_diagnostics.h index 3a25745d..f1075795 100644 --- a/libs/controller/include/controller_diagnostics.h +++ b/libs/controller/include/controller_diagnostics.h @@ -11,6 +11,7 @@ namespace crossdesk { void InitializeControllerDiagnostics(const std::string &directory); +void WriteControllerDiagnostic(const std::string &message) noexcept; } #endif diff --git a/libs/controller/src/controller_diagnostics.cpp b/libs/controller/src/controller_diagnostics.cpp index fecb072c..095e4c15 100644 --- a/libs/controller/src/controller_diagnostics.cpp +++ b/libs/controller/src/controller_diagnostics.cpp @@ -1,19 +1,22 @@ #include "controller_diagnostics.h" -#include +#include +#include +#include +#include +#include +#include #include namespace crossdesk { namespace { // Signaling errors and SDP can contain credentials. Only audited transport // events reach this sink; arbitrary MiniRTC messages remain suppressed. -std::string DiagnosticEvent(const spdlog::details::log_msg &message) { - std::string_view source = message.source.filename ? message.source.filename : ""; +std::string DiagnosticEvent(const MiniRtcLogRecord &message) { + std::string_view source = message.source_file ? message.source_file : ""; const auto slash = source.find_last_of("/\\"); if (slash != std::string_view::npos) source.remove_prefix(slash + 1); - const std::string_view text(message.payload.data(), message.payload.size()); - if (source == "controller_session.cpp") - return std::string(text); // Local states/counters only at these call sites. + const std::string_view text(message.message, message.message_size); if (source == "ws_client.cpp") { if (text == "WebSocket connection opened") return std::string(text); // These call sites contain library category names, numeric codes and retry @@ -59,30 +62,56 @@ std::string DiagnosticEvent(const spdlog::details::log_msg &message) { return {}; } -class DiagnosticSink final : public spdlog::sinks::base_sink { +class DiagnosticWriter { public: - explicit DiagnosticSink(const std::string &directory) + explicit DiagnosticWriter(const std::string &directory) : file_(directory + "/transport.log", 1024 * 1024, 2) {} - -private: - void sink_it_(const spdlog::details::log_msg &message) override { - const auto event = DiagnosticEvent(message); - if (event.empty()) - return; - auto sanitized = message; - sanitized.payload = spdlog::string_view_t(event.data(), event.size()); - file_.log(sanitized); + void Write(const std::string &event, const MiniRtcLogRecord *record = nullptr) { + if (event.empty()) return; + spdlog::details::log_msg message("crossdesk", spdlog::level::info, event); + if (record) { + message.level = static_cast(record->level); + message.time = spdlog::log_clock::time_point(std::chrono::microseconds(record->timestamp_us)); + message.source = {record->source_file, record->source_line, ""}; + } + file_.log(message); file_.flush(); } - void flush_() override { file_.flush(); } +private: spdlog::sinks::rotating_file_sink_mt file_; }; +void ReceiveLog(const MiniRtcLogRecord *message, void *context) { + if (message) static_cast(context)->Write(DiagnosticEvent(*message), message); +} +struct Diagnostics { + std::mutex initialization, mutex; + std::shared_ptr writer; + ~Diagnostics() { + // Quiesce the callback before releasing its application-owned context. + ConfigureMiniRtcLogging(MiniRtcLogOff, nullptr, nullptr); + } +}; +Diagnostics &State() { + static Diagnostics state; + return state; +} } // namespace void InitializeControllerDiagnostics(const std::string &directory) { - auto sink = std::make_shared(directory); - minirtc::InitLogger(directory, std::move(sink)); - auto logger = minirtc::get_logger(); - logger->set_level(spdlog::level::info); + auto &state = State(); + std::lock_guard initialize(state.initialization); + auto writer = std::make_shared(directory); + if (ConfigureMiniRtcLogging(MiniRtcLogInfo, ReceiveLog, writer.get()) != 0) + throw std::runtime_error("Unable to configure MiniRTC diagnostics"); + std::lock_guard lock(state.mutex); + state.writer = std::move(writer); +} +void WriteControllerDiagnostic(const std::string &message) noexcept { + try { + auto &state = State(); + std::shared_ptr writer; + { std::lock_guard lock(state.mutex); writer = state.writer; } + if (writer) writer->Write(message); + } catch (...) {} } } // namespace crossdesk diff --git a/libs/controller/src/controller_session.cpp b/libs/controller/src/controller_session.cpp index 0e7e20e4..f6414497 100644 --- a/libs/controller/src/controller_session.cpp +++ b/libs/controller/src/controller_session.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -159,7 +158,7 @@ void ControllerSession::Connect(SessionOptions options, std::string device, // Never register a desktop identity or persist local credentials. client_id_.clear(); InitializeControllerDiagnostics(options_.log_directory); - SPDLOG_LOGGER_INFO(minirtc::get_logger(), "Session registering"); + WriteControllerDiagnostic("Session registering"); auto p = Parameters(); peer_ = CreatePeer(&p); if (!peer_) { @@ -198,7 +197,7 @@ void ControllerSession::Tick() { if (Finished()) break; if (e.kind == 0) { - SPDLOG_LOGGER_INFO(minirtc::get_logger(), "Signal status: {}", e.code); + WriteControllerDiagnostic("Signal status: " + std::to_string(e.code)); if (e.code == SignalTlsCertError) { Fail("tls_certificate_error"); break; @@ -210,8 +209,7 @@ void ControllerSession::Tick() { // The initial signaling transport can recover before a remote join is // sent. Keep its backoff worker alive within the original deadline. if (e.code == SignalReconnecting && state_ == "registering") { - SPDLOG_LOGGER_INFO(minirtc::get_logger(), - "Initial signaling retry within connection deadline"); + WriteControllerDiagnostic("Initial signaling retry within connection deadline"); continue; } if (e.code == SignalClosed || e.code == SignalServerClosed || @@ -236,8 +234,7 @@ void ControllerSession::Tick() { password_.clear(); } } else if (e.kind == 1) { - SPDLOG_LOGGER_INFO(minirtc::get_logger(), "Connection status: {} (session {})", - e.code, state_); + WriteControllerDiagnostic("Connection status: " + std::to_string(e.code) + " (session " + state_ + ")"); if (e.code == ::Connected && !Connected()) { state_ = "connected"; auto hello = MakeHostInformation("CrossDesk CLI", {}, false); @@ -365,8 +362,7 @@ void ControllerSession::ClosePeers() { password_.clear(); } void ControllerSession::Fail(const char *reason) { - SPDLOG_LOGGER_INFO(minirtc::get_logger(), "Session failed: {} (stage {})", - reason, state_); + WriteControllerDiagnostic("Session failed: " + std::string(reason) + " (stage " + state_ + ")"); ReleaseInput(); error_ = reason; state_ = "failed"; @@ -449,7 +445,7 @@ void ControllerSession::Preview() { } void ControllerSession::SetControl(bool enabled) { if (control_ != enabled) - SPDLOG_LOGGER_INFO(minirtc::get_logger(), "Remote control: {}", enabled); + WriteControllerDiagnostic(std::string("Remote control: ") + (enabled ? "true" : "false")); if (!enabled) ReleaseInput(); control_ = enabled;