Skip to content

Commit

Permalink
Merge branch 'master' into dev-add-custom-fmt-for-logging
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikolaj Malecki committed Dec 6, 2024
2 parents a8dbce8 + cdbe5f5 commit 59435c2
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 162 deletions.
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1046,8 +1046,23 @@ macro(srt_set_stdcxx targetname spec)
endif()
endmacro()

macro(srt_set_stdc targetname spec)
set (stdcspec ${spec})
if (NOT "${stdcspec}" STREQUAL "")
if (CMAKE_VERSION VERSION_LESS "3.1")
target_compile_options(${targetname} PRIVATE -std=c${stdcspec})
message(STATUS "C STD: ${targetname}: forced C${stdcspec} standard - GNU option: -std=c${stdcspec}")
else()
set_target_properties(${targetname} PROPERTIES C_STANDARD ${stdcspec})
message(STATUS "C STD: ${targetname}: forced C${stdcspec} standard - portable way")
endif()
else()
message(STATUS "APP: ${targetname}: using default C standard")
endif()
endmacro()

srt_set_stdcxx(srt_virtual "${USE_CXX_STD_LIB}")
srt_set_stdc(srt_virtual "99")

set (VIRTUAL_srt $<TARGET_OBJECTS:srt_virtual>)

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ By contributing code to the SRT project, you agree to license your contribution
[Vcpkg-package]: https://repology.org/project/srt/versions
[Vcpkg-badge]: https://repology.org/badge/version-for-repo/vcpkg/srt.svg

[ConanCenter-package]: https://repology.org/project/srt/versions
[ConanCenter-badge]: https://repology.org/badge/version-for-repo/conancenter/srt.svg
[ConanCenter-package]: https://conan.io/center/recipes/srt
[ConanCenter-badge]: https://img.shields.io/conan/v/srt

[sonarcloud-project]: https://sonarcloud.io/project/overview?id=srt
[sonarcloud-badge]: https://sonarcloud.io/api/project_badges/measure?project=srt&metric=alert_status
Expand Down
2 changes: 1 addition & 1 deletion apps/verbose.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#define INC_SRT_VERBOSE_HPP

#include <iostream>
#include "atomic.h"
#include "sync.h"

namespace Verbose
{
Expand Down
6 changes: 6 additions & 0 deletions docs/API/API-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,9 @@ automatically created to handle the incoming connection on the listening socket
(and is about to be returned by [`srt_accept`](#srt_accept)), but before the
connection has been accepted.

Note the callback must be set before starting listening,
i.e. before `srt_listen` is called.

**Arguments**:

* `lsn`: Listening socket where you want to install the callback hook
Expand Down Expand Up @@ -1020,6 +1023,9 @@ mode ([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) option set to true).
It is guaranteed to be called when a socket is in non-blocking mode, or when you
use a group.

Note the callback must be set before starting the connection procedure,
i.e. before `srt_connect`, `srt_connect_bind`, etc. is called.

This function is mainly intended to be used with group connections. Note that even
if you use a group connection in blocking mode, after the group is considered
connected the member connections still continue in background. Also, when some
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
| [SRT API](API/API.md) | [API](API/) | [API.md](API/API.md) | Detailed description of the SRT C API. |
| [SRT API Functions](API/API-functions.md) | [API](API/) | [API-functions.md](API/API-functions.md) | Reference document for SRT API functions. |
| [SRT API Socket Options](API/API-socket-options.md) | [API](API/) | [API-socket-options.md](API/API-socket-options.md) | Instructions and list of socket options for SRT API. |
| [SRT Rejection Codes](API/rejections-codes.md) | [API](API/) | [rejection-codes.md](API/rejection-codes.md) | The list of SRT rejections codes. |
| [SRT Rejection Codes](API/rejection-codes.md) | [API](API/) | [rejection-codes.md](API/rejection-codes.md) | The list of SRT rejections codes. |
| [SRT Statistics](API/statistics.md) | [API](API/) | [statistics.md](API/statistics.md) | How to use SRT socket and socket group statistics. |
| [Configuration Guidelines](API/configuration-guidelines.md) | [API](API/) | [configuration-guidelines.md](API/configuration-guidelines.md) | How to configure SRT buffers. |
| <img width=200px height=1px/> | <img width=100px height=1px/> | <img width=200px height=1px/> | <img width=500px height=1px/> |
Expand Down
1 change: 1 addition & 0 deletions docs/build/build-macOS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Install [CMake](https://cmake.org/) and OpenSSL with development files from `bre
```shell
brew install cmake
brew install openssl
brew install pkgconfig
```

SRT can be now built with `cmake` or `make` on Mac.
Expand Down
2 changes: 1 addition & 1 deletion scripts/release-notes/generate_release_notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def define_area(msg):
if msg.startswith(f'[{area}] '):
return area

return np.NaN
return np.nan


def delete_prefix(msg):
Expand Down
92 changes: 61 additions & 31 deletions srtcore/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,21 +446,45 @@ static bool operator!=(const struct linger& l1, const struct linger& l2)
return l1.l_onoff != l2.l_onoff || l1.l_linger != l2.l_linger;
}

/// A function template to import socket option of a trivial type.
/// This includes linger, bool, int8_t, int32_t, int64_t, double, etc.
/// Potentially can be extended to trivially_copyable if needed.
template <class ValueType>
static void importOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const ValueType& field)
static void importTrivialOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const ValueType& optval, const int optsize = sizeof(ValueType))
{
ValueType default_opt = ValueType();
int default_opt_size = sizeof(ValueType);
ValueType opt = field;
if (!getOptDefault(optname, (&default_opt), (default_opt_size)) || default_opt != opt)
SRT_STATIC_ASSERT(std::is_trivial<ValueType>::value, "ValueType must be a trivial type.");
ValueType optval_dflt = ValueType();
int optsize_dflt = sizeof(ValueType);
if (!getOptDefault(optname, (&optval_dflt), (optsize_dflt)) || optval_dflt != optval)
{
SRT_ASSERT(optsize == sizeof(ValueType));
// Store the option when:
// - no default for this option is found
// - the option value retrieved from the field is different than default
storage.push_back(CUDTGroup::ConfigItem(optname, &opt, default_opt_size));
// - the option value retrieved from the field is different from the default one
#if HAVE_FULL_CXX11
storage.emplace_back(optname, &optval, optsize);
#else
storage.push_back(CUDTGroup::ConfigItem(optname, &optval, optsize));
#endif
}
}

/// A function template to import a StringStorage option.
template <size_t N>
static void importStringOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const StringStorage<N>& optval)
{
if (optval.empty())
return;

// Store the option when:
// - option has a value (default is empty).
#if HAVE_FULL_CXX11
storage.emplace_back(optname, optval.c_str(),(int) optval.size());
#else
storage.push_back(CUDTGroup::ConfigItem(optname, optval.c_str(), (int) optval.size()));
#endif
}

// This function is called by the same premises as the CUDT::CUDT(const CUDT&) (copy constructor).
// The intention is to rewrite the part that comprises settings from the socket
// into the group. Note that some of the settings concern group, some others concern
Expand Down Expand Up @@ -502,22 +526,27 @@ void CUDTGroup::deriveSettings(CUDT* u)
// to be potentially replicated on the socket. So both pre
// and post options apply.

#define IM(option, field) importOption(m_config, option, u->m_config.field)
#define IMF(option, field) importOption(m_config, option, u->field)
#define IM(option, field) importTrivialOption(m_config, option, u->m_config.field)
#define IMF(option, field) importTrivialOption(m_config, option, u->field)

IM(SRTO_MSS, iMSS);
IM(SRTO_FC, iFlightFlagSize);

// Nonstandard
importOption(m_config, SRTO_SNDBUF, u->m_config.iSndBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));
importOption(m_config, SRTO_RCVBUF, u->m_config.iRcvBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));
importTrivialOption(m_config, SRTO_SNDBUF, u->m_config.iSndBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));
importTrivialOption(m_config, SRTO_RCVBUF, u->m_config.iRcvBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));

IM(SRTO_LINGER, Linger);

IM(SRTO_UDP_SNDBUF, iUDPSndBufSize);
IM(SRTO_UDP_RCVBUF, iUDPRcvBufSize);
// SRTO_RENDEZVOUS: impossible to have it set on a listener socket.
// SRTO_SNDTIMEO/RCVTIMEO: groupwise setting
IM(SRTO_CONNTIMEO, tdConnTimeOut);

// SRTO_CONNTIMEO requires a special handling, because API stores the value in integer milliseconds,
// but the type of the variable is srt::sync::duration.
importTrivialOption(m_config, SRTO_CONNTIMEO, (int) count_milliseconds(u->m_config.tdConnTimeOut));

IM(SRTO_DRIFTTRACER, bDriftTracer);
// Reuseaddr: true by default and should only be true.
IM(SRTO_MAXBW, llMaxBW);
Expand All @@ -530,10 +559,12 @@ void CUDTGroup::deriveSettings(CUDT* u)
IM(SRTO_RCVLATENCY, iRcvLatency);
IM(SRTO_PEERLATENCY, iPeerLatency);
IM(SRTO_SNDDROPDELAY, iSndDropDelay);
IM(SRTO_PAYLOADSIZE, zExpPayloadSize);
// Special handling of SRTO_PAYLOADSIZE becuase API stores the value as int32_t,
// while the config structure stores it as size_t.
importTrivialOption(m_config, SRTO_PAYLOADSIZE, (int)u->m_config.zExpPayloadSize);
IMF(SRTO_TLPKTDROP, m_bTLPktDrop);

importOption(m_config, SRTO_STREAMID, u->m_config.sStreamName.str());
importStringOption(m_config, SRTO_STREAMID, u->m_config.sStreamName);

IM(SRTO_MESSAGEAPI, bMessageAPI);
IM(SRTO_NAKREPORT, bRcvNakReport);
Expand All @@ -542,22 +573,22 @@ void CUDTGroup::deriveSettings(CUDT* u)
IM(SRTO_IPV6ONLY, iIpV6Only);
IM(SRTO_PEERIDLETIMEO, iPeerIdleTimeout_ms);

importOption(m_config, SRTO_PACKETFILTER, u->m_config.sPacketFilterConfig.str());
importStringOption(m_config, SRTO_PACKETFILTER, u->m_config.sPacketFilterConfig);

importOption(m_config, SRTO_PBKEYLEN, u->m_pCryptoControl->KeyLen());
importTrivialOption(m_config, SRTO_PBKEYLEN, (int) u->m_pCryptoControl->KeyLen());

// Passphrase is empty by default. Decipher the passphrase and
// store as passphrase option
if (u->m_config.CryptoSecret.len)
{
string password((const char*)u->m_config.CryptoSecret.str, u->m_config.CryptoSecret.len);
m_config.push_back(ConfigItem(SRTO_PASSPHRASE, password.c_str(), (int)password.size()));
const StringStorage<HAICRYPT_SECRET_MAX_SZ> password((const char*)u->m_config.CryptoSecret.str, u->m_config.CryptoSecret.len);
importStringOption(m_config, SRTO_PASSPHRASE, password);
}

IM(SRTO_KMREFRESHRATE, uKmRefreshRatePkt);
IM(SRTO_KMPREANNOUNCE, uKmPreAnnouncePkt);

string cc = u->m_CongCtl.selected_name();
const string cc = u->m_CongCtl.selected_name();
if (cc != "live")
{
m_config.push_back(ConfigItem(SRTO_CONGESTION, cc.c_str(), (int)cc.size()));
Expand Down Expand Up @@ -586,16 +617,18 @@ bool CUDTGroup::applyFlags(uint32_t flags, HandshakeSide)
template <class Type>
struct Value
{
static int fill(void* optval, int, 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);
}
};

template <>
inline int Value<std::string>::fill(void* optval, int len, std::string value)
inline int Value<std::string>::fill(void* optval, int len, const std::string& value)
{
if (size_t(len) < value.size())
return 0;
Expand Down Expand Up @@ -642,7 +675,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<int>((pw_optval), w_optlen, CSrtConfig::DEF_BUFFER_SIZE * (CSrtConfig::DEF_MSS - CPacket::UDP_HDR_SIZE));
break;

case SRTO_LINGER:
Expand Down Expand Up @@ -800,11 +833,9 @@ void CUDTGroup::getOpt(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)

// Check if the option is in the storage, which means that
// it was modified on the group.
vector<ConfigItem>::const_iterator i = find_if(m_config.begin(), m_config.end(), FOptionValue(optname));

vector<ConfigItem>::const_iterator i = find_if(m_config.begin(), m_config.end(),
FOptionValue(optname));

if (i == m_config.end())
if (i == m_config.end() || i->value.empty())
{
// Already written to the target variable.
if (is_set_on_socket)
Expand All @@ -816,15 +847,14 @@ void CUDTGroup::getOpt(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)

return;
}
// NOTE: even if is_set_on_socket, if it was also found in the group
// settings, overwrite with the value from the group.

// Found, return the value from the storage.
// Found a value set on or derived by a group. Prefer returing it over the one taken from a member socket.
// Check the size first.
if (w_optlen < int(i->value.size()))
throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);

w_optlen = i->value.size();
SRT_ASSERT(!i->value.empty());
w_optlen = (int)i->value.size();
memcpy((pw_optval), &i->value[0], i->value.size());
}

Expand Down
6 changes: 6 additions & 0 deletions srtcore/socketconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ class StringStorage
memset(stor, 0, sizeof stor);
}

StringStorage(const char* s, size_t length)
: len(0)
{
set(s, length);
}

bool set(const char* s, size_t length)
{
if (length > SIZE)
Expand Down
55 changes: 52 additions & 3 deletions test/test_bonding.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <array>
#include <future>
#include <thread>
#include <chrono>
Expand All @@ -9,6 +10,7 @@

#include "srt.h"
#include "netinet_any.h"
#include "socketconfig.h"

TEST(Bonding, SRTConnectGroup)
{
Expand Down Expand Up @@ -330,6 +332,18 @@ TEST(Bonding, CloseGroupAndSocket)
listen_promise.wait();
}

// (void* opaq, SRTSOCKET ns, int hsversion, const struct sockaddr* peeraddr, const char* streamid);
int ListenCallbackFn(void* expected_sid, SRTSOCKET, int /*hsversion*/, const sockaddr* /*peer*/, const char* streamid)
{
const auto* p = (std::pair<const char*, int>*) expected_sid;
// Note: It is not safe to access the streamid pointer by the expected size,
// but there is no way to know the real size apart from finding the first null terminator.
// See FR #3073.
EXPECT_EQ(std::memcmp(streamid, p->first, p->second), 0);

return 0;
}

TEST(Bonding, Options)
{
using namespace std;
Expand All @@ -346,19 +360,48 @@ TEST(Bonding, Options)
//EXPECT_EQ(srt_setsockflag(grp, SRTO_RENDEZVOUS, &yes, sizeof yes), SRT_ERROR);

#ifdef SRT_ENABLE_ENCRYPTION
string pass = "longenoughpassword";
const string pass = "longenoughpassword";
// passphrase should be ok.
EXPECT_NE(srt_setsockflag(grp, SRTO_PASSPHRASE, pass.c_str(), pass.size()), SRT_ERROR);
EXPECT_NE(srt_setsockflag(grp, SRTO_PASSPHRASE, pass.c_str(), (int) pass.size()), SRT_ERROR);

uint32_t val = 16;
EXPECT_NE(srt_setsockflag(grp, SRTO_PBKEYLEN, &val, sizeof val), SRT_ERROR);
EXPECT_NE(srt_setsockflag(grp, SRTO_PBKEYLEN, &val, (int) sizeof val), SRT_ERROR);

#ifdef ENABLE_AEAD_API_PREVIEW
val = 1;
EXPECT_NE(srt_setsockflag(grp, SRTO_CRYPTOMODE, &val, sizeof val), SRT_ERROR);
#endif
#endif

// ================
// Linger is an option of a trivial type, but differes from other integer-typed options.
// Therefore checking it specifically.
const linger l = {1, 10};
srt_setsockflag(grp, SRTO_LINGER, &l, sizeof l);

{
linger l2;
int optsize = sizeof l2;
EXPECT_NE(srt_getsockflag(grp, SRTO_LINGER, &l2, &optsize), SRT_ERROR);
EXPECT_EQ(optsize, (int)sizeof l2);
EXPECT_EQ(l2.l_onoff, l.l_onoff);
EXPECT_EQ(l2.l_linger, l.l_linger);
}
// ================

const std::array<char, 10> streamid = { 's', 't', 'r', 'e', 0, 'm', 'i', 'd', '%', '&'};
EXPECT_NE(srt_setsockflag(grp, SRTO_STREAMID, &streamid, streamid.size()), SRT_ERROR);

auto check_streamid = [&streamid](SRTSOCKET sock) {
std::array<char, srt::CSrtConfig::MAX_SID_LENGTH> tmpbuf;
auto opt_len = (int)tmpbuf.size();
EXPECT_EQ(srt_getsockflag(sock, SRTO_STREAMID, tmpbuf.data(), &opt_len), SRT_SUCCESS);
EXPECT_EQ(size_t(opt_len), streamid.size());
EXPECT_EQ(std::memcmp(tmpbuf.data(), streamid.data(), opt_len), 0);
};

check_streamid(grp);

int lat = 500;
EXPECT_NE(srt_setsockflag(grp, SRTO_RCVLATENCY, &lat, sizeof lat), SRT_ERROR);

Expand All @@ -371,6 +414,10 @@ TEST(Bonding, Options)
unique_lock<mutex> ux(mx);

SRTSOCKET lsn = srt_create_socket();

auto expected_sid = std::make_pair<const char*, int>(streamid.data(), streamid.size());
srt_listen_callback(lsn, &ListenCallbackFn, (void*) &expected_sid);

#ifdef SRT_ENABLE_ENCRYPTION
EXPECT_NE(srt_setsockflag(lsn, SRTO_PASSPHRASE, pass.c_str(), pass.size()), SRT_ERROR);
#endif
Expand All @@ -388,6 +435,8 @@ TEST(Bonding, Options)
SRTSOCKET gs = srt_accept(lsn, revsa.get(), &revsa.len);
ASSERT_NE(gs, SRT_ERROR);

check_streamid(gs);

// Connected, wait to close
latch.wait(ux);

Expand Down
Loading

0 comments on commit 59435c2

Please sign in to comment.