From 123cf619a2210658c818fcfc5fc0734bc7c69e48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:59:57 +0000 Subject: [PATCH 1/6] Initial plan From cf1b1c1084dda1e9f40a39511e5d5da3d1f20ab0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:07:29 +0000 Subject: [PATCH 2/6] Fix RTSP server crash on TCP transport connect Three fixes: 1. Fix race condition on sessions_ map - accept_task_function now locks session_mutex_ when modifying sessions_, matching the locking in session_task_function that iterates/erases sessions. 2. Teardown session after failed SETUP - when TCP transport is rejected (or any SETUP parse failure), the session is properly torn down so it gets cleaned up instead of remaining as a zombie. 3. Include CSeq in 461 response - the "Unsupported Transport" response now includes the sequence number per RTSP protocol. Co-authored-by: finger563 <213467+finger563@users.noreply.github.com> --- components/rtsp/src/rtsp_server.cpp | 5 ++++- components/rtsp/src/rtsp_session.cpp | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/components/rtsp/src/rtsp_server.cpp b/components/rtsp/src/rtsp_server.cpp index 40fd27025..f753a7776 100644 --- a/components/rtsp/src/rtsp_server.cpp +++ b/components/rtsp/src/rtsp_server.cpp @@ -186,7 +186,10 @@ bool RtspServer::accept_task_function(std::mutex &m, std::condition_variable &cv // add the session to the list of sessions auto session_id = session->get_session_id(); - sessions_.emplace(session_id, std::move(session)); + { + std::lock_guard lk(session_mutex_); + sessions_.emplace(session_id, std::move(session)); + } // start the session task if it is not already running using namespace std::placeholders; diff --git a/components/rtsp/src/rtsp_session.cpp b/components/rtsp/src/rtsp_session.cpp index 1917a8a48..5a9e6386c 100644 --- a/components/rtsp/src/rtsp_session.cpp +++ b/components/rtsp/src/rtsp_session.cpp @@ -152,7 +152,9 @@ bool RtspSession::handle_rtsp_setup(std::string_view request) { int client_rtp_port; int client_rtcp_port; if (!parse_rtsp_setup_request(request, rtsp_path, client_rtp_port, client_rtcp_port)) { - // the parse function will send the response, so we just need to return + // the parse function will send the response, so we just need to + // teardown the session since setup failed and streaming cannot proceed + teardown(); return false; } // parse the sequence number from the request @@ -378,8 +380,9 @@ bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string // we don't support TCP, so return an error if the transport is not RTP/AVP/UDP if (transport.find("RTP/AVP/TCP") != std::string::npos) { logger_.error("TCP transport is not supported"); - // TODO: this doesn't send the sequence number back to the client - send_response(461, "Unsupported Transport"); + int sequence_number = 0; + parse_rtsp_command_sequence(request, sequence_number); + send_response(461, "Unsupported Transport", sequence_number); return false; } From e9218a57ce6d0b10cc60548ad7e00d34df592c5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:08:04 +0000 Subject: [PATCH 3/6] Fix RTSP server crash on TCP transport connect Co-authored-by: finger563 <213467+finger563@users.noreply.github.com> --- _codeql_detected_source_root | 1 + 1 file changed, 1 insertion(+) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file From 21cad236e0225858f1adab229727e0210161bdb9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:08:29 +0000 Subject: [PATCH 4/6] Remove codeql artifact Co-authored-by: finger563 <213467+finger563@users.noreply.github.com> --- _codeql_detected_source_root | 1 - 1 file changed, 1 deletion(-) delete mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root deleted file mode 120000 index 945c9b46d..000000000 --- a/_codeql_detected_source_root +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file From a86ad63262bed5a239300ef8d9d099400018fe68 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sat, 21 Feb 2026 16:51:40 -0600 Subject: [PATCH 5/6] ensure all false return paths from `parse_rtsp_setup_request` respond with an error to the client --- components/rtsp/include/rtsp_session.hpp | 7 +++++++ components/rtsp/src/rtsp_session.cpp | 26 +++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/components/rtsp/include/rtsp_session.hpp b/components/rtsp/include/rtsp_session.hpp index 4048dd913..2d6ae5c84 100644 --- a/components/rtsp/include/rtsp_session.hpp +++ b/components/rtsp/include/rtsp_session.hpp @@ -169,6 +169,13 @@ class RtspSession : public BaseComponent { /// @return The RTSP path std::string_view parse_rtsp_path(std::string_view request); + /// Handle a bad RTSP setup request by sending an error response to the client + /// @param request The request to handle + /// @param code The response code to send (default: 400) + /// @param message The response message to send (default: "Bad Request") + void handle_bad_rtsp_setup_request(std::string_view request, int code = 400, + std::string_view message = "Bad Request"); + /// Parse a RTSP setup request /// Looks for the client RTP and RTCP port numbers in the request /// and returns them diff --git a/components/rtsp/src/rtsp_session.cpp b/components/rtsp/src/rtsp_session.cpp index 5a9e6386c..181c296fe 100644 --- a/components/rtsp/src/rtsp_session.cpp +++ b/components/rtsp/src/rtsp_session.cpp @@ -354,35 +354,51 @@ std::string_view RtspSession::parse_rtsp_path(std::string_view request) { return rtsp_path; } +void RtspSession::handle_bad_rtsp_setup_request(std::string_view request, int code, + std::string_view message) { + int sequence_number = 0; + if (!parse_rtsp_command_sequence(request, sequence_number)) { + send_response(code, message); + return; + } + send_response(code, message, sequence_number); +} + bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string_view &rtsp_path, int &client_rtp_port, int &client_rtcp_port) { // parse the rtsp path from the request rtsp_path = parse_rtsp_path(request); if (rtsp_path.empty()) { + logger_.error("Failed to parse RTSP path from request"); + handle_bad_rtsp_setup_request(request); return false; } logger_.debug("Parsing setup request:\n{}", request); // parse the transport header from the request auto transport_index = request.find("Transport: "); if (transport_index == std::string::npos) { + logger_.error("Failed to parse Transport header (start) from request"); + handle_bad_rtsp_setup_request(request); return false; } auto transport_end_index = request.find('\r', transport_index); if (transport_end_index == std::string::npos) { + logger_.error("Failed to parse Transport header (end) from request"); + handle_bad_rtsp_setup_request(request); return false; } std::string_view transport = request.substr(transport_index + 11, transport_end_index - transport_index - 11); if (transport.empty()) { + logger_.error("Transport header is empty"); + handle_bad_rtsp_setup_request(request); return false; } logger_.debug("Transport header: {}", transport); // we don't support TCP, so return an error if the transport is not RTP/AVP/UDP if (transport.find("RTP/AVP/TCP") != std::string::npos) { logger_.error("TCP transport is not supported"); - int sequence_number = 0; - parse_rtsp_command_sequence(request, sequence_number); - send_response(461, "Unsupported Transport", sequence_number); + handle_bad_rtsp_setup_request(request, 461, "Unsupported Transport"); return false; } @@ -392,12 +408,16 @@ bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string std::string_view rtp_port = request.substr(client_port_index + 12, dash_index - client_port_index - 12); if (rtp_port.empty()) { + logger_.error("Failed to parse client RTP port from request"); + handle_bad_rtsp_setup_request(request); return false; } // parse the rtcp port from the request std::string_view rtcp_port = request.substr(dash_index + 1, request.find('\r', client_port_index) - dash_index - 1); if (rtcp_port.empty()) { + logger_.error("Empty client RTCP port in request"); + handle_bad_rtsp_setup_request(request); return false; } // convert the rtp and rtcp ports to integers From 0b5973502d687b40296a80cd2685d2ed79f68a0b Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Sat, 21 Feb 2026 16:56:17 -0600 Subject: [PATCH 6/6] update to use existing function modified instead of new function --- components/rtsp/include/rtsp_session.hpp | 12 ++++------ components/rtsp/src/rtsp_session.cpp | 29 ++++++++---------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/components/rtsp/include/rtsp_session.hpp b/components/rtsp/include/rtsp_session.hpp index 2d6ae5c84..cf7c83c0c 100644 --- a/components/rtsp/include/rtsp_session.hpp +++ b/components/rtsp/include/rtsp_session.hpp @@ -136,8 +136,11 @@ class RtspSession : public BaseComponent { /// Handle an invalid RTSP request /// @param request The request to handle + /// @param code The response code to send (default: 400) + /// @param message The response message to send (default: "Bad Request") /// @return True if the request was handled successfully, false otherwise - bool handle_rtsp_invalid_request(std::string_view request); + bool handle_rtsp_invalid_request(std::string_view request, int code = 400, + std::string_view message = "Bad Request"); /// Handle a single RTSP request /// @note Requests are of the form "METHOD RTSP_PATH RTSP_VERSION" @@ -169,13 +172,6 @@ class RtspSession : public BaseComponent { /// @return The RTSP path std::string_view parse_rtsp_path(std::string_view request); - /// Handle a bad RTSP setup request by sending an error response to the client - /// @param request The request to handle - /// @param code The response code to send (default: 400) - /// @param message The response message to send (default: "Bad Request") - void handle_bad_rtsp_setup_request(std::string_view request, int code = 400, - std::string_view message = "Bad Request"); - /// Parse a RTSP setup request /// Looks for the client RTP and RTCP port numbers in the request /// and returns them diff --git a/components/rtsp/src/rtsp_session.cpp b/components/rtsp/src/rtsp_session.cpp index 181c296fe..c7338ddab 100644 --- a/components/rtsp/src/rtsp_session.cpp +++ b/components/rtsp/src/rtsp_session.cpp @@ -217,11 +217,10 @@ bool RtspSession::handle_rtsp_teardown(std::string_view request) { return send_response(code, message, sequence_number, headers); } -bool RtspSession::handle_rtsp_invalid_request(std::string_view request) { +bool RtspSession::handle_rtsp_invalid_request(std::string_view request, int code, + std::string_view message) { logger_.info("RTSP invalid request"); // create a response - int code = 400; - std::string message = "Bad Request"; int sequence_number = 0; if (!parse_rtsp_command_sequence(request, sequence_number)) { return send_response(code, message); @@ -354,23 +353,13 @@ std::string_view RtspSession::parse_rtsp_path(std::string_view request) { return rtsp_path; } -void RtspSession::handle_bad_rtsp_setup_request(std::string_view request, int code, - std::string_view message) { - int sequence_number = 0; - if (!parse_rtsp_command_sequence(request, sequence_number)) { - send_response(code, message); - return; - } - send_response(code, message, sequence_number); -} - bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string_view &rtsp_path, int &client_rtp_port, int &client_rtcp_port) { // parse the rtsp path from the request rtsp_path = parse_rtsp_path(request); if (rtsp_path.empty()) { logger_.error("Failed to parse RTSP path from request"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } logger_.debug("Parsing setup request:\n{}", request); @@ -378,27 +367,27 @@ bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string auto transport_index = request.find("Transport: "); if (transport_index == std::string::npos) { logger_.error("Failed to parse Transport header (start) from request"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } auto transport_end_index = request.find('\r', transport_index); if (transport_end_index == std::string::npos) { logger_.error("Failed to parse Transport header (end) from request"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } std::string_view transport = request.substr(transport_index + 11, transport_end_index - transport_index - 11); if (transport.empty()) { logger_.error("Transport header is empty"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } logger_.debug("Transport header: {}", transport); // we don't support TCP, so return an error if the transport is not RTP/AVP/UDP if (transport.find("RTP/AVP/TCP") != std::string::npos) { logger_.error("TCP transport is not supported"); - handle_bad_rtsp_setup_request(request, 461, "Unsupported Transport"); + handle_rtsp_invalid_request(request, 461, "Unsupported Transport"); return false; } @@ -409,7 +398,7 @@ bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string request.substr(client_port_index + 12, dash_index - client_port_index - 12); if (rtp_port.empty()) { logger_.error("Failed to parse client RTP port from request"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } // parse the rtcp port from the request @@ -417,7 +406,7 @@ bool RtspSession::parse_rtsp_setup_request(std::string_view request, std::string request.substr(dash_index + 1, request.find('\r', client_port_index) - dash_index - 1); if (rtcp_port.empty()) { logger_.error("Empty client RTCP port in request"); - handle_bad_rtsp_setup_request(request); + handle_rtsp_invalid_request(request); return false; } // convert the rtp and rtcp ports to integers