Opened 3 months ago

Last modified 3 months ago

#10838 new defect

RTMP protocol, ffmpeg to ffmpeg, always ends with a connection reset (broken pipe)

Reported by: Momtchil Momtchev Owned by:
Priority: normal Component: undetermined
Version: git-master Keywords: RTMP
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

When using ffmpeg as a server and ffmpeg as a client, RTMP streaming always ends with a connection reset.

The bug is present since at least 4.4.2 in Ubuntu 22.04 to the latest git of today.

The server sends its data, then once it is finished, it immediately closes its end. The TCP connection remains in a half-closed state. The client continues reading and at the end sends an RTMP_PT_BYTES_READ (called an Acknowledgment, type 3, in the offical specs) message which causes the remote end to reply with a TCP RST packet. This renders checking for errors difficult, as there is no nominal case - the error is always expected.

How to reproduce:

./ffmpeg -i input.mp4 -f flv -ar 44100 -flvflags no_duration_filesize \
  -listen 1 rtmp://localhost:9099/video

./ffmpeg -y -i rtmp://localhost:9099/video output.mp4

I was not able to find anything on the connection teardown in the specifications:
https://rtmp.veriskope.com/docs/spec/#543acknowledgement-3

But given the wording of the acknowledgment section, I will be inclined to say that this is the server's fault - since it has to expect that the client will ack its last packet - which means that it should keep its end open until this ack is received.

Change History (5)

comment:1 by Momtchil Momtchev, 3 months ago

In fact, by going through the code, I have the feeling that at the moment the server simply does not care at all about acknowledgments received from the client - it parses them but doesn't do anything else.

comment:2 by Momtchil Momtchev, 3 months ago

The parsing of the received acks happens in a muxer thread, while the closing of the connection is triggered by of_write_trailer -> avio_closep in the main thread. Can you please advise on the thread model, I am willing to fix this. Should I delay the closing of the connection in avio_closep? This is something that most other protocols are likely already doing?

comment:3 by Momtchil Momtchev, 3 months ago

I found the reason and it is a design problem:
https://git.ffmpeg.org/gitweb/ffmpeg.git/blob/HEAD:/fftools/ffmpeg_mux.c#l407

In the main loop of muxer_thread(), after sch_mux_receive() has reported that the input stream is finished, the loop exits, ending the pipeline. This is simply how the pipeline works, fixing it here would require a major redesign.

A proper solution would be to implement ACK handling in the RTMP protocol and do not return from rtmp_write() until the remote has actually acknowledged - taking into account the window. It should buffer the window, handle retransmits and block when the remote is lagging.

An easy fix would be to simply delay the closing in avio_closep() / rtmp_close() with a timeout. I wonder if this would have any consequences?

comment:4 by Momtchil Momtchev, 3 months ago

Just tested VLC which behaves the same way as the ffmpeg client - it sends one last ack after receiving everything that is rejected by the ffmpeg server. However VLC does not report an error to the user, it simply hides it.

Note: See TracTickets for help on using tickets.