diff --git a/.gitignore b/.gitignore index b4e22ff8d..03cca0f87 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ # Ignore any folder starting from underscore _*/ +venv/ # Ignode Visual Studio Code temp folder .vs/ diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 3291f6e27..e4879747e 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -204,7 +204,7 @@ The following table lists SRT API socket options in alphabetical order. Option d | [`SRTO_BINDTODEVICE`](#SRTO_BINDTODEVICE) | 1.4.2 | pre-bind | `string` | | | | RW | GSD+ | | [`SRTO_CONGESTION`](#SRTO_CONGESTION) | 1.3.0 | pre | `string` | | "live" | \* | W | S | | [`SRTO_CONNTIMEO`](#SRTO_CONNTIMEO) | 1.1.2 | pre | `int32_t` | ms | 3000 | 0.. | W | GSD+ | -| [`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE) | 1.5.2 | pre | `int32_t` | | 0 (Auto) | [0, 2] | W | GSD | +| [`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE) | 1.5.2 | pre | `int32_t` | | 0 (Auto) | [0, 2] | W | GSD | | [`SRTO_DRIFTTRACER`](#SRTO_DRIFTTRACER) | 1.4.2 | post | `bool` | | true | | RW | GSD | | [`SRTO_ENFORCEDENCRYPTION`](#SRTO_ENFORCEDENCRYPTION) | 1.3.2 | pre | `bool` | | true | | W | GSD | | [`SRTO_EVENT`](#SRTO_EVENT) | | | `int32_t` | flags | | | R | S | diff --git a/srtcore/group.cpp b/srtcore/group.cpp index 3a9fc3f1d..2c2d88835 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -347,6 +347,31 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) switch (optName) { + // First go options that are NOT ALLOWED to be modified on the group. + // (socket-only), or are read-only. + + case SRTO_ISN: // read-only + case SRTO_STATE: // read-only + case SRTO_EVENT: // read-only + case SRTO_SNDDATA: // read-only + case SRTO_RCVDATA: // read-only + case SRTO_KMSTATE: // read-only + case SRTO_VERSION: // read-only + case SRTO_PEERVERSION: // read-only + case SRTO_SNDKMSTATE: + case SRTO_RCVKMSTATE: + case SRTO_GROUPTYPE: // read-only + LOGC(gmlog.Error, log << "group option setter: this option ("<< int(optName) << ") is read-only"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + case SRTO_SENDER: // deprecated (1.2.0 version legacy) + case SRTO_IPV6ONLY: // link-type specific + case SRTO_RENDEZVOUS: // socket-only + case SRTO_BINDTODEVICE: // socket-specific + case SRTO_GROUPCONNECT: // listener-specific + LOGC(gmlog.Error, log << "group option setter: this option ("<< int(optName) << ") is socket- or link-specific"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + case SRTO_RCVSYN: m_bSynRecving = cast_optval(optval, optlen); return; @@ -369,7 +394,7 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) const int min_timeo_ms = (int) CSrtConfig::COMM_DEF_MIN_STABILITY_TIMEOUT_MS; if (val_ms < min_timeo_ms) { - LOGC(qmlog.Error, + LOGC(gmlog.Error, log << "group option: SRTO_GROUPMINSTABLETIMEO min allowed value is " << min_timeo_ms << " ms."); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } @@ -385,7 +410,7 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) if (val_ms > idletmo) { - LOGC(qmlog.Error, + LOGC(gmlog.Error, log << "group option: SRTO_GROUPMINSTABLETIMEO=" << val_ms << " exceeds SRTO_PEERIDLETIMEO=" << idletmo); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } @@ -472,7 +497,7 @@ template static void importStringOption(vector& storage, SRT_SOCKOPT optname, const StringStorage& optval) { if (optval.empty()) - return; + return; // Store the option when: // - option has a value (default is empty). @@ -615,9 +640,11 @@ bool CUDTGroup::applyFlags(uint32_t flags, HandshakeSide) template struct Value { - static int fill(void* optval, int, const Type& value) + static int fill(void* optval, int len, const Type& value) { - // XXX assert size >= sizeof(Type) ? + if (size_t(len) < sizeof(Type)) + return 0; + *(Type*)optval = value; return sizeof(Type); } @@ -671,7 +698,7 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen) case SRTO_SNDBUF: case SRTO_RCVBUF: - w_optlen = fillValue((pw_optval), w_optlen, CSrtConfig::DEF_BUFFER_SIZE * (CSrtConfig::DEF_MSS - CPacket::UDP_HDR_SIZE)); + w_optlen = fillValue((pw_optval), w_optlen, CSrtConfig::DEF_BUFFER_SIZE * (CSrtConfig::DEF_MSS - CPacket::UDP_HDR_SIZE)); break; case SRTO_LINGER: diff --git a/srtcore/srt.h b/srtcore/srt.h index 614a85aea..71ac2c3af 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -182,7 +182,7 @@ typedef enum SRT_SOCKOPT { SRTO_RCVTIMEO = 14, // recv() timeout SRTO_REUSEADDR = 15, // reuse an existing port or create a new one SRTO_MAXBW = 16, // maximum bandwidth (bytes per second) that the connection can use - SRTO_STATE = 17, // current socket state, see UDTSTATUS, read only + SRTO_STATE = 17, // current socket state, see SRT_SOCKSTATUS, read only SRTO_EVENT = 18, // current available events associated with the socket SRTO_SNDDATA = 19, // size of data in the sending buffer SRTO_RCVDATA = 20, // size of data available for recv diff --git a/test/test_bonding.cpp b/test/test_bonding.cpp index 54199b1d6..b86baa96d 100644 --- a/test/test_bonding.cpp +++ b/test/test_bonding.cpp @@ -352,7 +352,7 @@ TEST(Bonding, Options) TestInit srtinit; // Create a group - const SRTSOCKET grp = srt_create_group(SRT_GTYPE_BROADCAST); + MAKE_UNIQUE_SOCK(grp, "broadcast group", srt_create_group(SRT_GTYPE_BROADCAST)); // rendezvous shall not be allowed to be set on the group // XXX actually it is possible, but no one tested it. POSTPONE. @@ -367,12 +367,18 @@ TEST(Bonding, Options) uint32_t val = 16; EXPECT_NE(srt_setsockflag(grp, SRTO_PBKEYLEN, &val, (int) sizeof val), SRT_ERROR); + const bool bfalse = true; + EXPECT_EQ(srt_setsockflag(grp, SRTO_RENDEZVOUS, &bfalse, (int)sizeof bfalse), SRT_ERROR); + #ifdef ENABLE_AEAD_API_PREVIEW val = 1; EXPECT_NE(srt_setsockflag(grp, SRTO_CRYPTOMODE, &val, sizeof val), SRT_ERROR); #endif #endif + const string packet_filter = "fec,cols:10,rows:5"; + EXPECT_NE(srt_setsockflag(grp, SRTO_PACKETFILTER, packet_filter.c_str(), (int)packet_filter.size()), SRT_ERROR); + // ================ // Linger is an option of a trivial type, but differes from other integer-typed options. // Therefore checking it specifically. @@ -431,12 +437,18 @@ TEST(Bonding, Options) // First wait - until it's let go with accepting latch.wait(ux); - sockaddr_any revsa; - SRTSOCKET gs = srt_accept(lsn, revsa.get(), &revsa.len); - ASSERT_NE(gs, SRT_ERROR); + //sockaddr_any revsa; + SRTSOCKET lsna [1] = { lsn }; + SRTSOCKET gs = srt_accept_bond(lsna, 1, 1000); + ASSERT_NE(gs, SRT_INVALID_SOCK); check_streamid(gs); + std::array tmpbuf; + auto opt_len = (int)tmpbuf.size(); + EXPECT_EQ(srt_getsockflag(gs, SRTO_PACKETFILTER, tmpbuf.data(), &opt_len), SRT_SUCCESS); + std::cout << "Packet filter: " << std::string(tmpbuf.data(), opt_len) << '\n'; + // Connected, wait to close latch.wait(ux); @@ -530,7 +542,6 @@ TEST(Bonding, Options) } accept_and_close.join(); - srt_close(grp); } inline SRT_SOCKGROUPCONFIG PrepareEndpoint(const std::string& host, int port) diff --git a/test/test_group_options.cpp b/test/test_group_options.cpp new file mode 100644 index 000000000..7ffdea600 --- /dev/null +++ b/test/test_group_options.cpp @@ -0,0 +1,27 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2019 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Written by: + * Haivision Systems Inc. + */ + +#include +#include +#include +#include +#include +#include "test_env.h" + +// SRT includes +#include "any.hpp" +#include "socketconfig.h" +#include "srt.h" + +using namespace std; +using namespace srt; + diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 58e60e761..36f8b1c79 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -114,6 +114,95 @@ class TestSocketOptions int m_pollid = 0; }; +// Test group options +class TestGroupOptions + : public ::srt::Test +{ +protected: + TestGroupOptions() = default; + ~TestGroupOptions() override = default; + +public: + void BindListener() const + { + // Specify address of the listener + const auto* psa = (const sockaddr*)&m_sa; + ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR); + } + + void StartListener() const + { + BindListener(); + srt_listen(m_listen_sock, 1); + } + + int Connect() const + { + const auto* psa = (const sockaddr*)&m_sa; + return srt_connect(m_caller_sock, psa, sizeof m_sa); + } + + 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); + + // Make sure the thread was kicked + this_thread::yield(); + + const int connect_res = Connect(); + EXPECT_EQ(connect_res, SRT_SUCCESS); + + const SRTSOCKET accepted_sock = accept_res.get(); + EXPECT_NE(accepted_sock, SRT_INVALID_SOCK); + + return accepted_sock; + } + +protected: + // Is run immediately before a test starts. + void setup() override + { + 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_group(SRT_GTYPE_BROADCAST); + 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 + ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect + + m_listen_sock = srt_create_socket(); + ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK); + ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect + ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect + ASSERT_EQ(srt_setsockflag(m_listen_sock, SRTO_GROUPCONNECT, &yes, sizeof yes), SRT_SUCCESS); + + } + + void teardown() override + { + // Code here will be called just after the test completes. + // OK to throw exceptions from here if needed. + EXPECT_NE(srt_close(m_caller_sock), SRT_ERROR); + EXPECT_NE(srt_close(m_listen_sock), SRT_ERROR); + } + + sockaddr_in m_sa; + SRTSOCKET m_caller_sock = SRT_INVALID_SOCK; + SRTSOCKET m_listen_sock = SRT_INVALID_SOCK; + + int m_pollid = 0; +}; + enum class RestrictionType { PREBIND = 0, @@ -121,9 +210,70 @@ enum class RestrictionType POST = 2 }; +// FLAGS +// - READABLE (R) +// : You can call srt_getsockflag +// - WRITABLE (W) +// : You can call srt_setsockflag +// - SOCKETWISE (S) +// : Can be set on a socket +// - GROUPWISE (G) +// : Can be set on a group +// - DERIVED (D) +// : TRUE: If it's set on the group, it will be derived by members +// : FALSE: It cannot be set on the group to be derived by members +// - GROUPUNIQUE (I) +// : TRUE: If set on the group, it's assigned to a group (not members) +// : FALSE: If set on the group, it's derived by members +// - MODIFIABLE (M) +// : TRUE: Can be set on individual member socket differently. +// : FALSE: Cannot be altered on the individual member socket. + +namespace Flags +{ +enum type: char +{ + O = 0, // Marker for an unset flag + + R = 1 << 0, // readable + W = 1 << 1, // writable + S = 1 << 2, // can be set on single socket + G = 1 << 3, // can be set on group + D = 1 << 4, // when set on group, derived by the socket + I = 1 << 5, // when set on group, it concerns group only + M = 1 << 6 // can be modified on individual member +}; + +inline type operator|(type f1, type f2) +{ + char val = char(f1) | char(f2); + return type(val); +} + +inline bool operator&(type ff, type mask) +{ + char val = char(ff) & char(mask); + return val == mask; +} + +const std::string str(type t) +{ + static const char names [] = "RWSGDI+"; + std::string out; + + for (int i = 0; i < 7; ++i) + if (int(t) & (1 << i)) + out += names[i]; + + if (out.empty()) + return "O"; + return out; +} +} + const char* RestrictionTypeStr(RestrictionType val) { - const std::map type_to_str = { + static const std::map type_to_str = { { RestrictionType::PREBIND, "PREBIND" }, { RestrictionType::PRE, "PRE" }, { RestrictionType::POST, "POST" } @@ -143,26 +293,35 @@ struct OptionTestEntry linb::any dflt_val; linb::any ndflt_val; vector invalid_vals; + Flags::type flags; }; static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }. static const size_t DFT_MTU_SIZE = 1500; // Default MTU size static const size_t SRT_PKT_SIZE = DFT_MTU_SIZE - UDP_HDR_SIZE; // MTU without UDP header +namespace Table +{ + // A trick to localize 1-letter flags without exposing + // them for the rest of the file. +using namespace Flags; + const OptionTestEntry g_test_matrix_options[] = { - // Option ID, Option Name | Restriction | optlen | min | max | default | nondefault | invalid vals | - //SRTO_BINDTODEVICE - //{ SRTO_CONGESTION, "SRTO_CONGESTION", RestrictionType::PRE, 4, "live", "file", "live", "file", {"liv", ""} }, - { SRTO_CONNTIMEO, "SRTO_CONNTIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 3000, 250, {-1} }, - { SRTO_DRIFTTRACER, "SRTO_DRIFTTRACER", RestrictionType::POST, sizeof(bool), false, true, true, false, {} }, - { SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, - //SRTO_EVENT - { SRTO_FC, "SRTO_FC", RestrictionType::PRE, sizeof(int), 32, INT32_MAX, 25600, 10000, {-1, 31} }, - //SRTO_GROUPCONNECT + // Place 'O' if not set. + // Option ID, Option Name | Restriction | optlen | min | max | default | nondefault | invalid vals | flags: R | W | G | S | D | I | M + + //SRTO_BINDTODEVICE R | W | G | S | D | I | M + //{ SRTO_CONGESTION, "SRTO_CONGESTION", RestrictionType::PRE, 4, "live", "file", "live", "file", {"liv", ""}, O | W | O | S | O | O | O }, + { SRTO_CONNTIMEO, "SRTO_CONNTIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 3000, 250, {-1}, O | W | G | S | D | O | M }, + { SRTO_DRIFTTRACER, "SRTO_DRIFTTRACER", RestrictionType::POST, sizeof(bool), false, true, true, false, {}, R | W | G | S | D | O | O }, + { SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", RestrictionType::PRE, sizeof(bool), false, true, true, false, {}, O | W | G | S | D | O | O }, + //SRTO_EVENT R | O | O | S | O | O | O + { SRTO_FC, "SRTO_FC", RestrictionType::PRE, sizeof(int), 32, INT32_MAX, 25600, 10000, {-1, 31}, R | W | G | S | D | O | O }, + //SRTO_GROUPCONNECT O | W | O | S | O | O | O #if ENABLE_BONDING // Max value can't exceed SRTO_PEERIDLETIMEO - { SRTO_GROUPMINSTABLETIMEO, "SRTO_GROUPMINSTABLETIMEO", RestrictionType::PRE, sizeof(int), 60, 5000, 60, 70, {0, -1, 50, 5001} }, + { SRTO_GROUPMINSTABLETIMEO, "SRTO_GROUPMINSTABLETIMEO", RestrictionType::PRE, sizeof(int), 60, 5000, 60, 70, {0, -1, 50, 5001}, O | W | G | O | D | I | M }, #endif //SRTO_GROUPTYPE //SRTO_INPUTBW @@ -170,56 +329,57 @@ const OptionTestEntry g_test_matrix_options[] = //SRTO_IPTTL //SRTO_IPV6ONLY //SRTO_ISN - { SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1} }, - { SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1} }, + { SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1}, R | W | G | S | D | O | O }, + { SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1}, R | W | G | S | D | O | O }, //SRTO_KMSTATE - { SRTO_LATENCY, "SRTO_LATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 200, {-1} }, + { SRTO_LATENCY, "SRTO_LATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 200, {-1}, R | W | G | S | D | O | O }, //SRTO_LINGER - { SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", RestrictionType::POST, sizeof(int), 0, INT32_MAX, 0, 10, {} }, - { SRTO_MAXBW, "SRTO_MAXBW", RestrictionType::POST, sizeof(int64_t), int64_t(-1), INT64_MAX, int64_t(-1), int64_t(200000), {int64_t(-2)}}, + { SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", RestrictionType::POST, sizeof(int), 0, INT32_MAX, 0, 10, {}, R | W | G | S | D | O | M }, + { SRTO_MAXBW, "SRTO_MAXBW", RestrictionType::POST, sizeof(int64_t), int64_t(-1), INT64_MAX, int64_t(-1), int64_t(200000), {int64_t(-2)}, R | W | G | S | D | O | O }, #ifdef ENABLE_MAXREXMITBW - { SRTO_MAXREXMITBW, "SRTO_MAXREXMITBW", RestrictionType::POST, sizeof(int64_t), int64_t(-1), INT64_MAX, int64_t(-1), int64_t(200000), {int64_t(-2)}}, + { SRTO_MAXREXMITBW, "SRTO_MAXREXMITBW", RestrictionType::POST, sizeof(int64_t), int64_t(-1), INT64_MAX, int64_t(-1), int64_t(200000), {int64_t(-2)}, R | W | G | S | D | O | O }, #endif - { SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, - { SRTO_MININPUTBW, "SRTO_MININPUTBW", RestrictionType::POST, sizeof(int64_t), int64_t(0), INT64_MAX, int64_t(0), int64_t(200000), {int64_t(-1)}}, - { SRTO_MINVERSION, "SRTO_MINVERSION", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0x010000, 0x010300, {} }, - { SRTO_MSS, "SRTO_MSS", RestrictionType::PREBIND, sizeof(int), 76, 65536, 1500, 1400, {-1, 0, 75} }, - { SRTO_NAKREPORT, "SRTO_NAKREPORT", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, - { SRTO_OHEADBW, "SRTO_OHEADBW", RestrictionType::POST, sizeof(int), 5, 100, 25, 20, {-1, 0, 4, 101} }, + { SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", RestrictionType::PRE, sizeof(bool), false, true, true, false, {}, O | W | G | S | D | O | O }, + { SRTO_MININPUTBW, "SRTO_MININPUTBW", RestrictionType::POST, sizeof(int64_t), int64_t(0), INT64_MAX, int64_t(0), int64_t(200000), {int64_t(-1)}, R | W | G | S | D | O | O }, + { SRTO_MINVERSION, "SRTO_MINVERSION", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0x010000, 0x010300, {}, R | W | G | S | D | O | O }, + { SRTO_MSS, "SRTO_MSS", RestrictionType::PREBIND, sizeof(int), 76, 65536, 1500, 1400, {-1, 0, 75}, R | W | G | S | D | O | O }, + { SRTO_NAKREPORT, "SRTO_NAKREPORT", RestrictionType::PRE, sizeof(bool), false, true, true, false, {}, R | W | G | S | D | O | M }, + { SRTO_OHEADBW, "SRTO_OHEADBW", RestrictionType::POST, sizeof(int), 5, 100, 25, 20, {-1, 0, 4, 101}, R | W | G | S | D | O | O }, //SRTO_PACKETFILTER //SRTO_PASSPHRASE - { SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", RestrictionType::PRE, sizeof(int), 0, 1456, 1316, 1400, {-1, 1500} }, + { SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", RestrictionType::PRE, sizeof(int), 0, 1456, 1316, 1400, {-1, 1500}, O | W | G | S | D | O | O }, //SRTO_PBKEYLEN - //SRTO_PEERIDLETIMEO - { SRTO_PEERIDLETIMEO, "SRTO_PEERIDLETIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 5000, 4500, {-1} }, - { SRTO_PEERLATENCY, "SRTO_PEERLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 180, {-1} }, + { SRTO_PEERIDLETIMEO, "SRTO_PEERIDLETIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 5000, 4500, {-1}, R | W | G | S | D | O | M }, + { SRTO_PEERLATENCY, "SRTO_PEERLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 180, {-1}, R | W | G | S | D | O | O }, //SRTO_PEERVERSION - { SRTO_RCVBUF, "SRTO_RCVBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} }, + { SRTO_RCVBUF, "SRTO_RCVBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1},R | W | G | S | D | O | M }, //SRTO_RCVDATA //SRTO_RCVKMSTATE - { SRTO_RCVLATENCY, "SRTO_RCVLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 1100, {-1} }, + { SRTO_RCVLATENCY, "SRTO_RCVLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 1100, {-1}, R | W | G | S | D | O | O }, //SRTO_RCVSYN - { SRTO_RCVTIMEO, "SRTO_RCVTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 2000, {-2} }, + { SRTO_RCVTIMEO, "SRTO_RCVTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 2000, {-2}, R | W | G | S | O | I | O }, //SRTO_RENDEZVOUS - { SRTO_RETRANSMITALGO, "SRTO_RETRANSMITALGO", RestrictionType::PRE, sizeof(int), 0, 1, 1, 0, {-1, 2} }, + { SRTO_RETRANSMITALGO, "SRTO_RETRANSMITALGO", RestrictionType::PRE, sizeof(int), 0, 1, 1, 0, {-1, 2}, R | W | G | S | D | O | O }, //SRTO_REUSEADDR //SRTO_SENDER - { SRTO_SNDBUF, "SRTO_SNDBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} }, + { SRTO_SNDBUF, "SRTO_SNDBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1},R | W | G | S | D | O | M }, //SRTO_SNDDATA - { SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY", RestrictionType::POST, sizeof(int), -1, INT32_MAX, 0, 1500, {-2} }, + { SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY", RestrictionType::POST, sizeof(int), -1, INT32_MAX, 0, 1500, {-2}, O | W | G | S | D | O | M }, //SRTO_SNDKMSTATE //SRTO_SNDSYN - { SRTO_SNDTIMEO, "SRTO_SNDTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 1400, {-2} }, + { SRTO_SNDTIMEO, "SRTO_SNDTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 1400, {-2}, R | W | G | S | O | I | O }, //SRTO_STATE //SRTO_STREAMID - { SRTO_TLPKTDROP, "SRTO_TLPKTDROP", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, + { SRTO_TLPKTDROP, "SRTO_TLPKTDROP", RestrictionType::PRE, sizeof(bool), false, true, true, false, {}, R | W | G | S | D | O | O }, //SRTO_TRANSTYPE //SRTO_TSBPDMODE //SRTO_UDP_RCVBUF //SRTO_UDP_SNDBUF //SRTO_VERSION }; +} // end namespace Table +using Table::g_test_matrix_options; template void CheckGetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueType& value, const char* desc) @@ -353,26 +513,46 @@ bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char return true; } -TEST_F(TestSocketOptions, DefaultVals) +void TestDefaultValues(SRTSOCKET s) { + const char* test_desc = "[Caller, default]"; for (const auto& entry : g_test_matrix_options) { - const char* test_desc = "[Caller, default]"; + // Check flags. An option must be RW to test default value + + if ( !(entry.flags & (Flags::R | Flags::W)) ) + { + cerr << "Skipping " << entry.optname << ": not read-write\n"; + continue; // The flag must be READABLE and WRITABLE for this. + } + + if ((s & SRTGROUP_MASK) != 0 && !(entry.flags & (Flags::G | Flags::I))) + { + cerr << "Skipping " << entry.optname << " on group: not a groupwise option\n"; + continue; // s is group && The option is not groupwise-individual option + } + + if ((s & SRTGROUP_MASK) == 0 && !(entry.flags & Flags::S)) + { + cerr << "Skipping " << entry.optname << " on socket: group-only option\n"; + continue; // s is socket && the option is group-only + } + if (entry.dflt_val.type() == typeid(bool)) { - EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + EXPECT_TRUE(CheckDefaultValue(entry, s, test_desc)); } else if (entry.dflt_val.type() == typeid(int)) { - EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + EXPECT_TRUE(CheckDefaultValue(entry, s, test_desc)); } else if (entry.dflt_val.type() == typeid(int64_t)) { - EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + EXPECT_TRUE(CheckDefaultValue(entry, s, test_desc)); } else if (entry.dflt_val.type() == typeid(const char*)) { - EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + EXPECT_TRUE(CheckDefaultValue(entry, s, test_desc)); } else { @@ -381,11 +561,31 @@ TEST_F(TestSocketOptions, DefaultVals) } } +TEST_F(TestSocketOptions, DefaultVals) +{ + TestDefaultValues(m_caller_sock); +} + +TEST_F(TestGroupOptions, DefaultVals) +{ + TestDefaultValues(m_caller_sock); +} + TEST_F(TestSocketOptions, MaxVals) { // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation for (const auto& entry : g_test_matrix_options) { + if (!(entry.flags & Flags::R)) + { + cerr << "Skipping " << entry.optname << ": option not readable\n"; + } + + if (!(entry.flags & Flags::W)) + { + cerr << "Skipping " << entry.optname << ": option not writable\n"; + } + if (entry.optid == SRTO_KMPREANNOUNCE || entry.optid == SRTO_KMREFRESHRATE) { cerr << "Skipping " << entry.optname << "\n"; @@ -419,6 +619,16 @@ TEST_F(TestSocketOptions, MinVals) // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation for (const auto& entry : g_test_matrix_options) { + if (!(entry.flags & Flags::R)) + { + cerr << "Skipping " << entry.optname << ": option not readable\n"; + } + + if (!(entry.flags & Flags::W)) + { + cerr << "Skipping " << entry.optname << ": option not writable\n"; + } + const char* test_desc = "[Caller, min val]"; if (entry.min_val.type() == typeid(bool)) { @@ -446,6 +656,11 @@ TEST_F(TestSocketOptions, InvalidVals) // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation for (const auto& entry : g_test_matrix_options) { + if (!(entry.flags & Flags::W)) + { + cerr << "Skipping " << entry.optname << ": option not writable\n"; + } + const char* desc = "[Caller, invalid val]"; if (entry.dflt_val.type() == typeid(bool)) { @@ -471,15 +686,15 @@ TEST_F(TestSocketOptions, InvalidVals) const char* StateToStr(SRT_SOCKSTATUS st) { std::map st_to_str = { - { SRTS_INIT, "SRTS_INIT" }, - { SRTS_OPENED, "SRTS_OPENED" }, - { SRTS_LISTENING, "SRTS_LISTENING" }, + { SRTS_INIT, "SRTS_INIT" }, + { SRTS_OPENED, "SRTS_OPENED" }, + { SRTS_LISTENING, "SRTS_LISTENING" }, { SRTS_CONNECTING, "SRTS_CONNECTING" }, - { SRTS_CONNECTED, "SRTS_CONNECTED" }, - { SRTS_BROKEN, "SRTS_BROKEN" }, - { SRTS_CLOSING, "SRTS_CLOSING" }, - { SRTS_CLOSED, "SRTS_CLOSED" }, - { SRTS_NONEXIST, "SRTS_NONEXIST" } + { SRTS_CONNECTED, "SRTS_CONNECTED" }, + { SRTS_BROKEN, "SRTS_BROKEN" }, + { SRTS_CLOSING, "SRTS_CLOSING" }, + { SRTS_CLOSED, "SRTS_CLOSED" }, + { SRTS_NONEXIST, "SRTS_NONEXIST" } }; return st_to_str.find(st) != st_to_str.end() ? st_to_str.at(st) : "INVALID"; @@ -871,7 +1086,7 @@ TEST_F(TestSocketOptions, StreamIDOdd) EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_odd.c_str(), (int)sid_odd.size()), SRT_SUCCESS); - array buffer; + std::array buffer; auto buffer_len = (int) buffer.size(); EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS); EXPECT_EQ(std::string(buffer.data()), sid_odd);