From patchwork Thu Aug 29 22:54:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: William Martin X-Patchwork-Id: 14805 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 6134A4488F7 for ; Fri, 30 Aug 2019 02:22:47 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3EE23687F37; Fri, 30 Aug 2019 02:22:47 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f181.google.com (mail-qt1-f181.google.com [209.85.160.181]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4423C680BCF for ; Fri, 30 Aug 2019 02:22:40 +0300 (EEST) Received: by mail-qt1-f181.google.com with SMTP id b11so5659623qtp.10 for ; Thu, 29 Aug 2019 16:22:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Cb8FBb+4g5gM2DLpdWyqsDIhVwqhcKAdeUsPRuf77Mc=; b=QhB07ogYlcQ6T7lPtD2WyNZKgNU+mNug6Hk2Ynd7K8ZJz/PJwzl/jAFu268p/CeVt5 oMMQIyqu1LSCQ5Ld7pdWJL2YA9id6g7NvaIDNm7AwPvJJ5k7mo8IX3BQxj+jvj7Ldh1Z dOGcYrPN1Cwf+idvJ5UPaHWoKgb0kc3cJw830IGJ+UgjrP8vEGQ8MbbfsZCH5vyhChzt hKckl90Z1SUfaZ9+zHjlMK3g4ZtU8lphiTfE44Gl6iH2Z0fQSJOS73ymp4ylKyGPLja9 IgzHRpBVRB6kVHovwPWY6UlosrPMZmSrqBlmSIsyYmm4XLOZejt5duTH2B+3jKsKi5v7 7A3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Cb8FBb+4g5gM2DLpdWyqsDIhVwqhcKAdeUsPRuf77Mc=; b=qbhu0B3RJrnc3dO6vhkuZIW616982bpYiSJ1jdU0lhwduRII6L7N2w0FK+BuePDJop maXe10/zres/VkPmrmHkDg06gf8JX+7pM/c7LZbsGVRxabbMJsau5y0/H4MfNkvWHx8c R5LVn1HE6r9GOe74PfB7fDff6db5Y0swz7K8ZB+itF5TvTywx9TcFH5pUJZL4XZ7erRA Y5Vdyk8XCvinW0QNTALSwUnWX/jVjBfjYHYlVvgWeth3kR3HzitA74B6wp5tnBq8P4O5 AZYd+93UH7/95xlCt9igIspKLsmlr13F2gigsgeGwkNAVf+1+Sr1uOAlR2y7pJopsmtu LZ4Q== X-Gm-Message-State: APjAAAW//lUxNK297Ff3uFq10f7TA3X8dI8ucffGYF88nxPNgC4tHqZv rETozQDIRXwvMdMgLneyAe2KV1rC X-Google-Smtp-Source: APXvYqw2u5rJCYrqo7F7zO4twog7n3o2RPQw1u95GRkMP+4rgU0+qntBz0PbfEUsCPaTeSui/WEgUA== X-Received: by 2002:a63:ee08:: with SMTP id e8mr10702150pgi.70.1567119262683; Thu, 29 Aug 2019 15:54:22 -0700 (PDT) Received: from C02XG1KUJGH8.hsd1.or.comcast.net. (c-71-193-151-48.hsd1.or.comcast.net. [71.193.151.48]) by smtp.gmail.com with ESMTPSA id e129sm10335026pfa.92.2019.08.29.15.54.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 29 Aug 2019 15:54:22 -0700 (PDT) From: William Martin To: ffmpeg-devel@ffmpeg.org Date: Thu, 29 Aug 2019 15:54:21 -0700 Message-Id: <20190829225421.97898-1-unique.will.martin@gmail.com> X-Mailer: git-send-email 2.20.1 (Apple Git-117) MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] fix rtmp handshake for some streams [v2] X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Will Martin Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Will Martin 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");