ref:3a196379c79cff062cf7efb4b2332b385066ce42

fix(web): disconnect only the disabled client instead of all sessions (#5138)

SHA: 3a196379c79cff062cf7efb4b2332b385066ce42
Author: neatnoise <neatnoise@gmail.com>
Date: 2026-05-18 22:53
Parents: 6d7740c
7 files changed +46 -1
Type
src/confighttp.cpp +4 −1
@@ -882,7 +882,10 @@
output_tree["status"] = nvhttp::set_client_enabled(uuid, enabled);
if (!enabled && output_tree["status"]) {
rtsp_stream::terminate_sessions();
auto cert = nvhttp::get_cert_by_uuid(uuid);
if (!cert.empty()) {
rtsp_stream::terminate_sessions_by_cert(cert);
}
if (rtsp_stream::session_count() == 0 && proc::proc.running() > 0) {
proc::proc.terminate();
src/nvhttp.cpp +14 −0
@@ -144,6 +144,9 @@
client_t client_root;
std::atomic<uint32_t> session_id_counter;
// Set by TLS verify callback, read by launch/resume handler (single-threaded HTTPS server)
std::string last_verified_client_cert; // NOSONAR(cpp:S5421) - intentionally mutable global
using args_t = SimpleWeb::CaseInsensitiveMultimap;
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>;
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Request>;
@@ -326,6 +329,7 @@
launch_session->rtsp_iv_counter = 0;
}
launch_session->rtsp_url_scheme = launch_session->rtsp_cipher ? "rtspenc://"s : "rtsp://"s;
launch_session->client_cert = last_verified_client_cert;
// Generate the unique identifiers for this connection that we will send later during RTSP handshake
unsigned char raw_payload[8];
@@ -1141,6 +1145,7 @@
return verified;
}
last_verified_client_cert = pem;
verified = 1;
return verified;
@@ -1253,6 +1258,15 @@
}
}
return false;
}
std::string get_cert_by_uuid(const std::string_view uuid) {
for (const auto &named_cert : client_root.named_devices) {
if (named_cert.uuid == uuid) {
return named_cert.cert;
}
}
return {};
}
bool is_client_enabled(const std::string_view cert_pem) {
src/nvhttp.h +1 −0
@@ -191,6 +191,7 @@
* @return true if the client was found and updated.
*/
bool set_client_enabled(std::string_view uuid, bool enabled);
std::string get_cert_by_uuid(std::string_view uuid);
/**
* @brief Get all paired clients.
src/rtsp.cpp +18 −0
@@ -569,6 +569,20 @@
}
}
void clear_by_cert(std::string_view cert) {
auto lg = _session_slots.lock();
for (auto i = _session_slots->begin(); i != _session_slots->end();) {
auto &slot = *(*i);
if (stream::session::client_cert(slot) == cert) {
stream::session::stop(slot);
stream::session::join(slot);
i = _session_slots->erase(i);
} else {
i++;
}
}
}
/**
* @brief Removes the provided session from the set of sessions.
* @param session The session to remove.
@@ -641,6 +655,10 @@
void terminate_sessions() {
server.clear(true);
}
void terminate_sessions_by_cert(std::string_view cert) {
server.clear_by_cert(cert);
}
int send(tcp::socket &sock, const std::string_view &sv) {
src/rtsp.h +2 −0
@@ -39,6 +39,7 @@
std::optional<crypto::cipher::gcm_t> rtsp_cipher;
std::string rtsp_url_scheme;
uint32_t rtsp_iv_counter;
std::string client_cert;
};
void launch_session_raise(std::shared_ptr<launch_session_t> launch_session);
@@ -59,6 +60,7 @@
* @brief Terminates all running streaming sessions.
*/
void terminate_sessions();
void terminate_sessions_by_cert(std::string_view cert);
/**
* @brief Runs the RTSP server loop.
src/stream.cpp +6 −0
@@ -405,6 +405,7 @@
} control;
std::uint32_t launch_session_id;
std::string client_cert;
safe::mail_raw_t::event_t<bool> shutdown_event;
safe::signal_t controlEnd;
@@ -1902,6 +1903,10 @@
return session.state.load(std::memory_order_relaxed);
}
const std::string &client_cert(session_t &session) {
return session.client_cert;
}
void stop(session_t &session) {
while_starting_do_nothing(session.state);
auto expected = state_e::RUNNING;
@@ -2009,5 +2014,6 @@
session->shutdown_event = mail->event<bool>(mail::shutdown);
session->launch_session_id = launch_session.id;
session->client_cert = launch_session.client_cert;
session->config = config;
src/stream.h +1 −0
@@ -51,5 +51,6 @@
void stop(session_t &session);
void join(session_t &session);
state_e state(session_t &session);
const std::string &client_cert(session_t &session);
} // namespace session
} // namespace stream