From 036cc2a7a2f2c753afa4ef56677a2558c8593421 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 19 Aug 2020 21:28:06 +0800 Subject: [PATCH] RTC: Limit the ARQ for DTLS --- trunk/src/app/srs_app_rtc_dtls.cpp | 5 +- trunk/src/utest/srs_utest_rtc.cpp | 132 +++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 2 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_dtls.cpp b/trunk/src/app/srs_app_rtc_dtls.cpp index 69e2de4fc..2044987d9 100644 --- a/trunk/src/app/srs_app_rtc_dtls.cpp +++ b/trunk/src/app/srs_app_rtc_dtls.cpp @@ -677,8 +677,9 @@ srs_error_t SrsDtlsClientImpl::cycle() // The first ARQ delay. srs_usleep(arq_first); - while (true) { - srs_info("arq cycle, state=%u", state_); + // Limit the max retry for ARQ. + for (int arq_retry_left = 7; arq_retry_left > 0; arq_retry_left--) { + srs_info("arq cycle, state=%u, retry=%d", state_, arq_retry_left); // We ignore any error for ARQ thread. if ((err = trd->pull()) != srs_success) { diff --git a/trunk/src/utest/srs_utest_rtc.cpp b/trunk/src/utest/srs_utest_rtc.cpp index c7211a2ba..0c8de5247 100644 --- a/trunk/src/utest/srs_utest_rtc.cpp +++ b/trunk/src/utest/srs_utest_rtc.cpp @@ -382,6 +382,138 @@ std::ostream& operator<< (std::ostream& stream, const DTLSServerFlowCase& c) return stream; } +VOID TEST(KernelRTCTest, DTLSARQLimitTest) +{ + srs_error_t err = srs_success; + + // ClientHello lost, client retransmit the ClientHello. + if (true) { + MockDtlsCallback cio; SrsDtls client(&cio); + MockDtlsCallback sio; SrsDtls server(&sio); + MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL); + HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0")); + HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0")); + + // Use very short interval for utest. + dynamic_cast(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS; + dynamic_cast(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS; + + // Lost 10 packets, total packets should be 8(max to 8). + // Note that only one server hello. + cio.nn_client_hello_lost = 10; + + HELPER_EXPECT_SUCCESS(client.start_active_handshake()); + mock_wait_dtls_io_done(10, 3); + + EXPECT_TRUE(sio.r0 == srs_success); + EXPECT_TRUE(cio.r0 == srs_success); + + EXPECT_FALSE(cio.done); + EXPECT_FALSE(sio.done); + + EXPECT_EQ(8, cio.nn_client_hello); + EXPECT_EQ(0, sio.nn_server_hello); + EXPECT_EQ(0, cio.nn_certificate); + EXPECT_EQ(0, sio.nn_new_session); + EXPECT_EQ(0, sio.nn_change_cipher); + } + + // Certificate lost, client retransmit the Certificate. + if (true) { + MockDtlsCallback cio; SrsDtls client(&cio); + MockDtlsCallback sio; SrsDtls server(&sio); + MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL); + HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0")); + HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0")); + + // Use very short interval for utest. + dynamic_cast(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS; + dynamic_cast(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS; + + // Lost 10 packets, total packets should be 8(max to 8). + // Note that only one server NewSessionTicket. + cio.nn_certificate_lost = 10; + + HELPER_EXPECT_SUCCESS(client.start_active_handshake()); + mock_wait_dtls_io_done(10, 3); + + EXPECT_TRUE(sio.r0 == srs_success); + EXPECT_TRUE(cio.r0 == srs_success); + + EXPECT_FALSE(cio.done); + EXPECT_FALSE(sio.done); + + EXPECT_EQ(1, cio.nn_client_hello); + EXPECT_EQ(1, sio.nn_server_hello); + EXPECT_EQ(8, cio.nn_certificate); + EXPECT_EQ(0, sio.nn_new_session); + EXPECT_EQ(0, sio.nn_change_cipher); + } + + // ServerHello lost, client retransmit the ClientHello. + if (true) { + MockDtlsCallback cio; SrsDtls client(&cio); + MockDtlsCallback sio; SrsDtls server(&sio); + MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL); + HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0")); + HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0")); + + // Use very short interval for utest. + dynamic_cast(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS; + dynamic_cast(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS; + + // Lost 10 packets, total packets should be 8(max to 8). + sio.nn_server_hello_lost = 10; + + HELPER_EXPECT_SUCCESS(client.start_active_handshake()); + mock_wait_dtls_io_done(10, 3); + + EXPECT_TRUE(sio.r0 == srs_success); + EXPECT_TRUE(cio.r0 == srs_success); + + EXPECT_FALSE(cio.done); + EXPECT_FALSE(sio.done); + + EXPECT_EQ(8, cio.nn_client_hello); + EXPECT_EQ(8, sio.nn_server_hello); + EXPECT_EQ(0, cio.nn_certificate); + EXPECT_EQ(0, sio.nn_new_session); + EXPECT_EQ(0, sio.nn_change_cipher); + } + + // NewSessionTicket lost, client retransmit the Certificate. + if (true) { + MockDtlsCallback cio; SrsDtls client(&cio); + MockDtlsCallback sio; SrsDtls server(&sio); + MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL); + HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0")); + HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0")); + + // Use very short interval for utest. + dynamic_cast(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS; + dynamic_cast(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS; + + // Lost 10 packets, total packets should be 8(max to 8). + sio.nn_new_session_lost = 10; + + HELPER_EXPECT_SUCCESS(client.start_active_handshake()); + mock_wait_dtls_io_done(10, 3); + + EXPECT_TRUE(sio.r0 == srs_success); + EXPECT_TRUE(cio.r0 == srs_success); + + // Although the packet is lost, but it's done for server, and not done for client. + EXPECT_FALSE(cio.done); + EXPECT_TRUE(sio.done); + + EXPECT_EQ(1, cio.nn_client_hello); + EXPECT_EQ(1, sio.nn_server_hello); + EXPECT_EQ(8, cio.nn_certificate); + EXPECT_EQ(8, sio.nn_new_session); + EXPECT_EQ(0, sio.nn_change_cipher); + } +} + VOID TEST(KernelRTCTest, DTLSClientARQTest) { srs_error_t err = srs_success;