diff --git a/srtcore/core.cpp b/srtcore/core.cpp index abee338d12..c3a102b1ef 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -331,33 +331,27 @@ void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) } // Post-action, if applicable - if (IsSet(oflags, SRTO_POST_SPEC)) + if (IsSet(oflags, SRTO_POST_SPEC) && m_bConnected) { - if (m_bConnected) - if (m_bOpened) - throw CUDTException(MJ_NOTSUP, MN_ISBOUND, 0); - + switch (optName) { - switch (optName) - { - case SRTO_MAXBW: - updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET)); - break; + case SRTO_MAXBW: + updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET)); + break; - case SRTO_INPUTBW: - case SRTO_MININPUTBW: - updateCC(TEV_INIT, EventVariant(TEV_INIT_INPUTBW)); - break; + case SRTO_INPUTBW: + case SRTO_MININPUTBW: + updateCC(TEV_INIT, EventVariant(TEV_INIT_INPUTBW)); + break; - case SRTO_OHEADBW: - updateCC(TEV_INIT, EventVariant(TEV_INIT_OHEADBW)); - break; + case SRTO_OHEADBW: + updateCC(TEV_INIT, EventVariant(TEV_INIT_OHEADBW)); + break; - case SRTO_LOSSMAXTTL: - m_iReorderTolerance = m_config.m_iMaxReorderTolerance; + case SRTO_LOSSMAXTTL: + m_iReorderTolerance = m_config.m_iMaxReorderTolerance; - default: break; - } + default: break; } } } @@ -452,6 +446,8 @@ void CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) break; case SRTO_MININPUTBW: + if (optlen < sizeof (m_config.m_llMinInputBW)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); *(int64_t*)optval = m_config.m_llMinInputBW; optlen = sizeof(int64_t); break; diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index ace07c1e24..40cbc2a019 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -82,6 +82,7 @@ static struct SrtConfigSetter DISPATCH(SRTO_IPTOS); DISPATCH(SRTO_BINDTODEVICE); DISPATCH(SRTO_INPUTBW); + DISPATCH(SRTO_MININPUTBW); DISPATCH(SRTO_OHEADBW); DISPATCH(SRTO_SENDER); DISPATCH(SRTO_TSBPDMODE); diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 4ca9dfa048..c415d6ae20 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -560,7 +560,11 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.m_llMaxBW = cast_optval(optval, optlen); + const int64_t val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.m_llMaxBW = val; } }; @@ -621,7 +625,10 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.m_llInputBW = cast_optval(optval, optlen); + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.m_llInputBW = val; } }; template<> @@ -629,7 +636,10 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.m_llMinInputBW = cast_optval(optval, optlen); + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.m_llMinInputBW = val; } }; template<> @@ -637,7 +647,7 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - int32_t val = cast_optval(optval, optlen); + const int32_t val = cast_optval(optval, optlen); if (val < 5 || val > 100) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); co.m_iOverheadBW = val; diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 705db5a091..a94d18eecf 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -33,6 +33,36 @@ class TestSocketOptions // cleanup any pending stuff, but no exceptions allowed } +public: + void StartListener() + { + // Specify address of the listener + sockaddr* psa = (sockaddr*)&m_sa; + ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR); + + srt_listen(m_listen_sock, 1); + } + + SRTSOCKET EstablishConnection() + { + auto accept_async = [](SRTSOCKET listen_sock) { + sockaddr_in client_address; + int length = sizeof(sockaddr_in); + const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length); + return accepted_socket; + }; + auto accept_res = async(launch::async, accept_async, m_listen_sock); + + sockaddr* psa = (sockaddr*)&m_sa; + const int connect_res = srt_connect(m_caller_sock, psa, sizeof m_sa); + EXPECT_EQ(connect_res, SRT_SUCCESS); + + const SRTSOCKET accepted_sock = accept_res.get(); + EXPECT_NE(accepted_sock, SRT_INVALID_SOCK); + + return accepted_sock; + } + protected: // SetUp() is run immediately before a test starts. void SetUp() @@ -40,6 +70,11 @@ class TestSocketOptions ASSERT_GE(srt_startup(), 0); const int yes = 1; + memset(&m_sa, 0, sizeof m_sa); + m_sa.sin_family = AF_INET; + m_sa.sin_port = htons(5200); + ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &m_sa.sin_addr), 1); + m_caller_sock = srt_create_socket(); ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK); ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect @@ -63,6 +98,7 @@ class TestSocketOptions protected: // put in any custom data members that you need + sockaddr_in m_sa; SRTSOCKET m_caller_sock = SRT_INVALID_SOCK; SRTSOCKET m_listen_sock = SRT_INVALID_SOCK; @@ -78,30 +114,8 @@ TEST_F(TestSocketOptions, LossMaxTTL) const int loss_max_ttl = 5; ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &loss_max_ttl, sizeof loss_max_ttl), SRT_SUCCESS); - // Specify address - sockaddr_in sa; - memset(&sa, 0, sizeof sa); - sa.sin_family = AF_INET; - sa.sin_port = htons(5200); - ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1); - sockaddr* psa = (sockaddr*)&sa; - ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof sa), SRT_ERROR); - - srt_listen(m_listen_sock, 1); - - auto accept_async = [](SRTSOCKET listen_sock) { - sockaddr_in client_address; - int length = sizeof(sockaddr_in); - const SRTSOCKET accepted_socket = srt_accept(listen_sock, (sockaddr*)&client_address, &length); - return accepted_socket; - }; - auto accept_res = async(launch::async, accept_async, m_listen_sock); - - const int connect_res = srt_connect(m_caller_sock, psa, sizeof sa); - EXPECT_EQ(connect_res, SRT_SUCCESS); - - const SRTSOCKET accepted_sock = accept_res.get(); - ASSERT_NE(accepted_sock, SRT_INVALID_SOCK); + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); int opt_val = 0; int opt_len = 0; @@ -121,3 +135,114 @@ TEST_F(TestSocketOptions, LossMaxTTL) } +// Try to set/get SRTO_MININPUTBW with wrong optlen +TEST_F(TestSocketOptions, MinInputBWWrongLen) +{ + int64_t mininputbw = 0; + int optlen = (int)(sizeof mininputbw) - 1; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); + optlen += 2; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS) << "Bigger storage is allowed"; + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw - 1), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, sizeof mininputbw + 1), SRT_ERROR); + EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM); +} + +// Check the default SRTO_MININPUTBW is SRT_PACING_MAXBW_DEFAULT +TEST_F(TestSocketOptions, MinInputBWDefault) +{ + const int mininputbw_expected = 0; + int64_t mininputbw = 1; + int optlen = (int)(sizeof mininputbw); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + EXPECT_EQ(mininputbw, mininputbw_expected); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check both listener and accepted socket have default values + for (SRTSOCKET sock : { m_listen_sock, accepted_sock }) + { + optlen = (int)(sizeof mininputbw); + EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &mininputbw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof mininputbw)); + EXPECT_EQ(mininputbw, mininputbw_expected); + } + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + +// Check setting and getting SRT_MININPUTBW +TEST_F(TestSocketOptions, MinInputBWSet) +{ + const int64_t mininputbw_dflt = 0; + const int64_t mininputbw = 50000000; + int optlen = (int)(sizeof mininputbw); + + int64_t bw = -100; + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_ERROR) << "Has to be a non-negative number"; + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw_dflt); + + bw = mininputbw; + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check accepted socket inherits values + for (SRTSOCKET sock : { m_listen_sock, accepted_sock }) + { + optlen = (int)(sizeof bw); + EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof bw)); + EXPECT_EQ(bw, mininputbw); + } + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + +// Check setting and getting SRTO_MININPUTBW in runtime +TEST_F(TestSocketOptions, MinInputBWRuntime) +{ + const int64_t mininputbw = 50000000; + + // Establish a connection + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Test a connected socket + int64_t bw = mininputbw; + int optlen = (int)(sizeof bw); + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + bw = 0; + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_INPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, 0); + + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MAXBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, 0); + + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, mininputbw); + + const int64_t new_mininputbw = 20000000; + bw = new_mininputbw; + EXPECT_EQ(srt_setsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_MININPUTBW, &bw, &optlen), SRT_SUCCESS); + EXPECT_EQ(bw, new_mininputbw); + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} +