[FFmpeg-devel] [PATCH] fix rtmp handshake for some streams [v2]
William Martin
unique.will.martin at gmail.com
Sat Sep 21 01:11:38 EEST 2019
hello. I didn't see any comments about this patch - does that mean it is
ready to be merged?
On Thu, Aug 29, 2019 at 3:54 PM William Martin <unique.will.martin at gmail.com>
wrote:
> From: Will Martin <will.martin at verizondigitalmedia.com>
>
> Some rtmp streamers (i.e. AWS Elemental Encoder, Wirecast) send C0 and C1
> together and expect S0 and S1 returned together. When sent in different
> packets, this results in a C2 handshake. This patch fixes that error.
> Note that the patch is based off of a fix proposed by rubensanchez in
> https://trac.ffmpeg.org/ticket/6453.
> The only difference between that propsed fix and this patch is that
> dummy_unit is declared as a uint32_t instead of unit8_8 (this addresses a
> crash in debug builds).
> This patch being submitted in a [v2] so that these commit messages could
> be added for clarity.
> ---
> libavformat/rtmpproto.c | 103 +++++++++++++++++++++++-----------------
> 1 file changed, 59 insertions(+), 44 deletions(-)
>
> diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
> index b741e421af..24070ba0f5 100644
> --- a/libavformat/rtmpproto.c
> +++ b/libavformat/rtmpproto.c
> @@ -1416,71 +1416,86 @@ static int rtmp_send_hs_packet(RTMPContext* rt,
> uint32_t first_int,
> */
> static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
> {
> - uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
> - uint32_t hs_epoch;
> + uint8_t hs_s0s1[RTMP_HANDSHAKE_PACKET_SIZE + 1];
> + uint8_t hs_c0c1[RTMP_HANDSHAKE_PACKET_SIZE + 1];
> + uint8_t hs_c2[RTMP_HANDSHAKE_PACKET_SIZE + 1];
> + uint8_t hs_s2[RTMP_HANDSHAKE_PACKET_SIZE];
> + uint32_t dummy_uint;
> uint32_t hs_my_epoch;
> - uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
> - uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
> - uint32_t zeroes;
> uint32_t temp = 0;
> int randomidx = 0;
> int inoutsize = 0;
> int ret;
>
> - inoutsize = ffurl_read_complete(rt->stream, buffer, 1); //
> Receive C0
> - if (inoutsize <= 0) {
> - av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
> - return AVERROR(EIO);
> + /****************
> + * Receive C0+C1
> + ***************/
> + ret = rtmp_receive_hs_packet(rt, &dummy_uint, &dummy_uint, hs_c0c1,
> + RTMP_HANDSHAKE_PACKET_SIZE + 1);
> + if (ret) {
> + av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error %d\n", ret);
> + return ret;
> }
> // Check Version
> - if (buffer[0] != 3) {
> - av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
> + if (hs_c0c1[0] != 3) {
> + av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch. Expected
> 0x03 received %02x\n", hs_c0c1[0]);
> return AVERROR(EIO);
> }
> - if (ffurl_write(rt->stream, buffer, 1) <= 0) { //
> Send S0
> - av_log(s, AV_LOG_ERROR,
> - "Unable to write answer - RTMP S0\n");
> + // Get client epoch and set our with the same value
> + hs_my_epoch = AV_RB32(hs_c0c1 + 1);
> +
> + /*************
> + * Send S0+S1
> + ************/
> + // Generate random data to send it on S0+S1
> + for (randomidx = 9; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE + 1);
> + randomidx += 4)
> + AV_WB32(hs_s0s1 + randomidx, av_get_random_seed());
> + // Set the RTMP protocol code on S0+S1 (First byte)
> + hs_s0s1[0] = 0x03;
> + // Copy the random data from C1 to S1
> + memcpy(hs_s0s1 + 1, hs_c0c1 + 1, RTMP_HANDSHAKE_PACKET_SIZE);
> + AV_WB32(hs_s0s1 + 1, hs_my_epoch);
> + AV_WB32(hs_s0s1 + 5, 0);
> + inoutsize = ffurl_write(rt->stream, hs_s0s1,
> + RTMP_HANDSHAKE_PACKET_SIZE + 1);
> + if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
> + av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error %d\n", ret);
> return AVERROR(EIO);
> }
> - /* Receive C1 */
> - ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
> - RTMP_HANDSHAKE_PACKET_SIZE);
> - if (ret) {
> - av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
> - return ret;
> - }
> - /* Send S1 */
> - /* By now same epoch will be sent */
> - hs_my_epoch = hs_epoch;
> - /* Generate random */
> - for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
> - randomidx += 4)
> - AV_WB32(hs_s1 + randomidx, av_get_random_seed());
>
> - ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
> - RTMP_HANDSHAKE_PACKET_SIZE);
> - if (ret) {
> - av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
> - return ret;
> - }
> - /* Send S2 */
> - ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
> + /***********
> + * Send S2
> + **********/
> + // Get the S2 random data from C0+C1
> + memcpy(hs_s2, hs_c0c1, RTMP_HANDSHAKE_PACKET_SIZE);
> + ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s2,
> RTMP_HANDSHAKE_PACKET_SIZE);
> if (ret) {
> av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
> return ret;
> }
> - /* Receive C2 */
> - ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
> - RTMP_HANDSHAKE_PACKET_SIZE);
> - if (ret) {
> - av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
> - return ret;
> +
> + /*************
> + * Receive C2
> + ************/
> +
> + ret = ffurl_read_complete(rt->stream, hs_c2,
> + RTMP_HANDSHAKE_PACKET_SIZE + 1);
> + if (ret <= 0)
> + return AVERROR(EIO);
> + if (ret != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
> + av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
> + " not following standard\n", (int)inoutsize);
> + return AVERROR(EINVAL);
> }
> +
> + // Check timestamp and random data from C2
> + temp = AV_RB32(hs_c2 + 1);
> if (temp != hs_my_epoch)
> av_log(s, AV_LOG_WARNING,
> - "Erroneous C2 Message epoch does not match up with C1
> epoch\n");
> - if (memcmp(buffer + 8, hs_s1 + 8,
> + "Erroneous C2 Message epoch does not match up with C1
> epoch");
> + if (memcmp(hs_c2 + 9, hs_c0c1 + 9,
> RTMP_HANDSHAKE_PACKET_SIZE - 8))
> av_log(s, AV_LOG_WARNING,
> "Erroneous C2 Message random does not match up\n");
> --
> 2.20.1 (Apple Git-117)
>
>
More information about the ffmpeg-devel
mailing list