PR #25761 opened by Kilian (lusoris) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25761 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25761.patch
Keep the original error in three RTSP paths that replaced it with a fixed code. These are the pre-existing error-identity issues named in the review of pull request 25726. This branch is stacked on pull request 25726 (head edd7328845e3); only the last three commits are new here. - `rtsp_listen()` replaced every non-zero handler result with `AVERROR_INVALIDDATA`. Negative errors are now returned unchanged; a positive result keeps the existing mapping. - `check_sessionid()` returned `AVERROR_STREAM_NOT_FOUND` after a failed error-reply write. It now returns the write error. - The muxer poll loop in `rtsp_write_packet()` replaced any `ff_rtsp_read_reply()` failure with `AVERROR(EPIPE)`. It now returns the reported error. Measured with an `LD_PRELOAD` and socketpair fault probe that fails the second write with EPIPE: | Path | Before | After | | --- | --- | --- | | listen dispatch | -1094995529 (`AVERROR_INVALIDDATA`) | -32 (`AVERROR(EPIPE)`) | | `check_sessionid` | -1381258232 (`AVERROR_STREAM_NOT_FOUND`) | -32 (`AVERROR(EPIPE)`) | | muxer poll loop | -32 (substituted EPIPE) | -541478725 (`AVERROR_EOF`, the reported error) | `make fate-rtsp fate-source` passes. tools/patcheck reports nothing on the added lines. The PLAY and PAUSE status fallback from the same review is in its own pull request, #25760. >From 9fa9b661dfca684d621959362b57ab8fbd72c36e Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Tue, 3 Nov 2026 16:23:55 +0100 Subject: [PATCH 1/6] avformat/rtspenc: check the interleaved frame write ff_rtsp_tcp_write_packet() ignored the result of writing each interleaved frame to the RTSP control connection, so a failed or short write was reported as success and the muxer kept writing. Stop at the first failed write and return its error, or AVERROR(EIO) for a short write. Signed-off-by: lusoris <[email protected]> --- libavformat/rtspenc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index f2f4b6d5258..724b5c6b8b4 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -145,7 +145,7 @@ int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) RTSPState *rt = s->priv_data; AVFormatContext *rtpctx = rtsp_st->transport_priv; uint8_t *buf, *ptr; - int size; + int size, ret = 0; uint8_t *interleave_header, *interleaved_packet; size = avio_close_dyn_buf(rtpctx->pb, &buf); @@ -171,12 +171,17 @@ int ff_rtsp_tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) interleave_header[0] = '$'; interleave_header[1] = id; AV_WB16(interleave_header + 2, packet_len); - ffurl_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len); + ret = ffurl_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len); + if (ret != 4 + packet_len) { + ret = ret < 0 ? ret : AVERROR(EIO); + break; + } ptr += packet_len; size -= packet_len; } av_free(buf); - return ffio_open_dyn_packet_buf(&rtpctx->pb, rt->pkt_size); + size = ffio_open_dyn_packet_buf(&rtpctx->pb, rt->pkt_size); + return ret < 0 ? ret : size; } static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) -- 2.54.0 >From 35c136d46b71a3ccdde762f416e6674bb922ca9f Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Tue, 3 Nov 2026 16:23:56 +0100 Subject: [PATCH 2/6] avformat/rtsp: check the write of the automatic reply ff_rtsp_read_reply() answers server requests (OPTIONS, GET_PARAMETER and others) on its own but ignored whether the reply was written. Return the write error, or AVERROR(EIO) for a short write, and update last_cmd_time only after a complete write. Signed-off-by: lusoris <[email protected]> --- libavformat/rtsp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 29f219c366a..186be3def9b 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -1358,14 +1358,16 @@ start: av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf)); ptr = base64buf; } - ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr)); + ret = ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr)); - rt->last_cmd_time = av_gettime_relative(); /* Even if the request from the server had data, it is not the data * that the caller wants or expects. The memory could also be leaked * if the actual following reply has content data. */ if (content_ptr) av_freep(content_ptr); + if (ret != strlen(ptr)) + return ret < 0 ? ret : AVERROR(EIO); + rt->last_cmd_time = av_gettime_relative(); /* If method is set, this is called from ff_rtsp_send_cmd, * where a reply to exactly this request is awaited. For * callers from within packet receiving, we just want to -- 2.54.0 >From edd7328845e3c91ee9373f5d0f9a19668e7a7229 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Tue, 3 Nov 2026 16:23:58 +0100 Subject: [PATCH 3/6] avformat/rtspdec: check the listen-mode reply write rtsp_send_reply() always returned 0, so in listen mode a reply that could not be written to the client went unnoticed and the server state advanced anyway. Return the write error, or AVERROR(EIO) for a short write, and propagate it from the ANNOUNCE, OPTIONS, SETUP and RECORD handlers before the state changes. Signed-off-by: lusoris <[email protected]> --- libavformat/rtspdec.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index 0e592eebaed..e6b9b0c7382 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -118,7 +118,7 @@ static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code, { RTSPState *rt = s->priv_data; char message[MAX_URL_SIZE]; - int index = 0; + int index = 0, ret; while (status_messages[index].code) { if (status_messages[index].code == code) { snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n", @@ -135,7 +135,9 @@ static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code, av_strlcat(message, extracontent, sizeof(message)); av_strlcat(message, "\r\n", sizeof(message)); av_log(s, AV_LOG_TRACE, "Sending response:\n%s", message); - ffurl_write(rt->rtsp_hd_out, message, strlen(message)); + ret = ffurl_write(rt->rtsp_hd_out, message, strlen(message)); + if (ret != strlen(message)) + return ret < 0 ? ret : AVERROR(EIO); return 0; } @@ -225,8 +227,7 @@ static int rtsp_read_announce(AVFormatContext *s) av_free(sdp); if (ret) return ret; - rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq); - return 0; + return rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq); } av_log(s, AV_LOG_ERROR, "Invalid ANNOUNCE Content-Length %d\n", request.content_length); @@ -247,10 +248,9 @@ static int rtsp_read_options(AVFormatContext *s) return ret; rt->seq++; /* Send Reply */ - rtsp_send_reply(s, RTSP_STATUS_OK, - "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n", - request.seq); - return 0; + return rtsp_send_reply(s, RTSP_STATUS_OK, + "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n", + request.seq); } static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl) @@ -366,7 +366,9 @@ static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl) av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n", rt->session_id); /* Send Reply */ - rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq); + ret = rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq); + if (ret < 0) + return ret; rt->state = RTSP_STATE_PAUSED; return 0; @@ -388,7 +390,9 @@ static int rtsp_read_record(AVFormatContext *s) rt->seq++; snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n", rt->session_id); - rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq); + ret = rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq); + if (ret < 0) + return ret; rt->state = RTSP_STATE_STREAMING; return 0; -- 2.54.0 >From 7cf2fb7ae1a6366a76789bb865dbfbe9a94f0b67 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Wed, 4 Nov 2026 00:06:11 +0100 Subject: [PATCH 4/6] avformat/rtspdec: keep the handler error in rtsp_listen rtsp_listen() replaced every non-zero result of the OPTIONS, ANNOUNCE, RECORD and SETUP handlers with AVERROR_INVALIDDATA, so a failed reply write surfaced as invalid data instead of EPIPE or EIO. Return negative handler errors unchanged and keep the mapping for positive results. Signed-off-by: lusoris <[email protected]> --- libavformat/rtspdec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index e6b9b0c7382..69224d3596c 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -843,7 +843,8 @@ static int rtsp_listen(AVFormatContext *s) } else if (methodcode == SETUP) ret = rtsp_read_setup(s, host, uri); if (ret) { - ret = AVERROR_INVALIDDATA; + if (ret > 0) + ret = AVERROR_INVALIDDATA; goto fail; } } -- 2.54.0 >From 90782a5ef2c41be6d9c14da3805f78f95654697b Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Wed, 4 Nov 2026 00:06:19 +0100 Subject: [PATCH 5/6] avformat/rtspdec: return the reply write error in check_sessionid When the session id did not match, check_sessionid() sent the error reply and returned AVERROR_STREAM_NOT_FOUND even if that write failed. Return the write error instead, so a closed control connection is not reported as an unknown session. Signed-off-by: lusoris <[email protected]> --- libavformat/rtspdec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index 69224d3596c..40dc80e73ce 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -152,9 +152,12 @@ static inline int check_sessionid(AVFormatContext *s, return 0; } if (strcmp(session_id, request->session_id)) { + int ret; av_log(s, AV_LOG_ERROR, "Unexpected session-id %s\n", request->session_id); - rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq); + ret = rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq); + if (ret < 0) + return ret; return AVERROR_STREAM_NOT_FOUND; } return 0; -- 2.54.0 >From 9d99bd37fc8d39d8126ffcc1618ea9dd1ec964b7 Mon Sep 17 00:00:00 2001 From: lusoris <[email protected]> Date: Wed, 4 Nov 2026 00:06:22 +0100 Subject: [PATCH 6/6] avformat/rtspenc: keep the read error in the muxer poll loop rtsp_write_packet() polls the control connection for server requests between packets and replaced any failure of ff_rtsp_read_reply() with AVERROR(EPIPE). Return the error it reported, such as AVERROR_EOF when the server closed the connection. Signed-off-by: lusoris <[email protected]> --- libavformat/rtspenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index 724b5c6b8b4..0667f9c42b7 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -206,7 +206,7 @@ static int rtsp_write_packet(AVFormatContext *s, AVPacket *pkt) * interleaved packets internally. */ ret = ff_rtsp_read_reply(s, &reply, NULL, 1, NULL); if (ret < 0) - return AVERROR(EPIPE); + return ret; if (ret == 1) { ret = ff_rtsp_skip_packet(s); if (ret < 0) -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
