From b53a091777719f9594efba9d6f0ed1582839f1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Wed, 1 Mar 2023 16:41:36 +0100 Subject: [PATCH 01/29] [FIX] Calculate correctly max payload size per UDP packet --- apps/srt-file-transmit.cpp | 7 +- apps/transmitmedia.cpp | 37 ++++++++++- srtcore/api.cpp | 17 +++-- srtcore/buffer_rcv.cpp | 9 ++- srtcore/buffer_snd.cpp | 3 +- srtcore/buffer_snd.h | 2 +- srtcore/buffer_tools.cpp | 5 +- srtcore/buffer_tools.h | 3 +- srtcore/channel.cpp | 9 +++ srtcore/common.cpp | 2 +- srtcore/common.h | 9 +++ srtcore/congctl.cpp | 5 +- srtcore/core.cpp | 97 +++++++++++++++++++++------ srtcore/core.h | 30 ++++++--- srtcore/group.cpp | 15 +++-- srtcore/group_backup.h | 1 + srtcore/packet.h | 18 +++-- srtcore/packetfilter_api.h | 2 +- srtcore/socketconfig.cpp | 89 +++++++++++++++---------- srtcore/socketconfig.h | 2 + srtcore/srt.h | 7 +- srtcore/stats.h | 83 ++++++++++++++++++----- srtcore/window.cpp | 8 +-- srtcore/window.h | 31 +++++++-- test/test_fec_rebuilding.cpp | 8 +-- test/test_file_transmission.cpp | 113 +++++++++++++++++++++++++++++++- testing/srt-test-mpbond.cpp | 2 +- testing/testmedia.cpp | 45 ++++++++++--- 28 files changed, 523 insertions(+), 136 deletions(-) diff --git a/apps/srt-file-transmit.cpp b/apps/srt-file-transmit.cpp index 327ad6809..e29ae3248 100644 --- a/apps/srt-file-transmit.cpp +++ b/apps/srt-file-transmit.cpp @@ -180,7 +180,7 @@ int parse_args(FileTransmitConfig &cfg, int argc, char** argv) return 2; } - cfg.chunk_size = stoul(Option(params, "1456", o_chunk)); + cfg.chunk_size = stoul(Option(params, "0", o_chunk)); cfg.skip_flushing = Option(params, false, o_no_flush); cfg.bw_report = stoi(Option(params, "0", o_bwreport)); cfg.stats_report = stoi(Option(params, "0", o_statsrep)); @@ -681,8 +681,11 @@ int main(int argc, char** argv) // // Set global config variables // - if (cfg.chunk_size != SRT_LIVE_MAX_PLSIZE) + if (cfg.chunk_size != 0) transmit_chunk_size = cfg.chunk_size; + else + transmit_chunk_size = SRT_MAX_PLSIZE_AF_INET; + transmit_stats_writer = SrtStatsWriterFactory(cfg.stats_pf); transmit_bw_report = cfg.bw_report; transmit_stats_report = cfg.stats_report; diff --git a/apps/transmitmedia.cpp b/apps/transmitmedia.cpp index 260323ef3..42970d92f 100644 --- a/apps/transmitmedia.cpp +++ b/apps/transmitmedia.cpp @@ -44,7 +44,7 @@ bool g_stats_are_printed_to_stdout = false; bool transmit_total_stats = false; unsigned long transmit_bw_report = 0; unsigned long transmit_stats_report = 0; -unsigned long transmit_chunk_size = SRT_LIVE_MAX_PLSIZE; +unsigned long transmit_chunk_size = SRT_MAX_PLSIZE_AF_INET6; class FileSource: public Source { @@ -179,6 +179,36 @@ void SrtCommon::InitParameters(string host, map par) m_adapter = host; } + int fam_to_limit_size = AF_INET6; // take the less one as default + + // Try to interpret host and adapter first + sockaddr_any host_sa, adapter_sa; + + if (host != "") + { + host_sa = CreateAddr(host); + fam_to_limit_size = host_sa.family(); + if (fam_to_limit_size == AF_UNSPEC) + Error("Failed to interpret 'host' spec: " + host); + } + + if (adapter != "" && adapter != host) + { + adapter_sa = CreateAddr(adapter); + fam_to_limit_size = adapter_sa.family(); + + if (fam_to_limit_size == AF_UNSPEC) + Error("Failed to interpret 'adapter' spec: " + adapter); + + if (host_sa.family() != AF_UNSPEC && host_sa.family() != adapter_sa.family()) + { + Error("Both host and adapter specified and they use different IP versions"); + } + } + + if (fam_to_limit_size != AF_INET) + fam_to_limit_size = AF_INET6; + if (par.count("tsbpd") && false_names.count(par.at("tsbpd"))) { m_tsbpdmode = false; @@ -195,8 +225,9 @@ void SrtCommon::InitParameters(string host, map par) if ((par.count("transtype") == 0 || par["transtype"] != "file") && transmit_chunk_size > SRT_LIVE_DEF_PLSIZE) { - if (transmit_chunk_size > SRT_LIVE_MAX_PLSIZE) - throw std::runtime_error("Chunk size in live mode exceeds 1456 bytes; this is not supported"); + size_t size_limit = (size_t)SRT_MAX_PLSIZE(fam_to_limit_size); + if (transmit_chunk_size > size_limit) + throw std::runtime_error(Sprint("Chunk size in live mode exceeds ", size_limit, " bytes; this is not supported")); par["payloadsize"] = Sprint(transmit_chunk_size); } diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 63dab3927..4a22cb8ec 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -618,7 +618,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, } // bind to the same addr of listening socket - ns->core().open(); + ns->core().open(peer.family()); if (!updateListenerMux(ns, ls)) { // This is highly unlikely if not impossible, but there's @@ -928,7 +928,7 @@ int srt::CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } - s->core().open(); + s->core().open(name.family()); updateMux(s, name); s->m_Status = SRTS_OPENED; @@ -957,7 +957,7 @@ int srt::CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) // Successfully extracted, so update the size name.len = namelen; - s->core().open(); + s->core().open(name.family()); updateMux(s, name, &udpsock); s->m_Status = SRTS_OPENED; @@ -1847,7 +1847,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i // same thing as bind() does, just with empty address so that // the binding parameters are autoselected. - s->core().open(); + s->core().open(target_addr.family()); sockaddr_any autoselect_sa(target_addr.family()); // This will create such a sockaddr_any that // will return true from empty(). @@ -3157,7 +3157,14 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons m.m_pSndQueue = new CSndQueue; m.m_pSndQueue->init(m.m_pChannel, m.m_pTimer); m.m_pRcvQueue = new CRcvQueue; - m.m_pRcvQueue->init(128, s->core().maxPayloadSize(), m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer); + + // We can't use maxPayloadSize() because this value isn't valid until the connection is established. + // We need to "think big", that is, allocate a size that would fit both IPv4 and IPv6. + size_t payload_size = s->core().m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(AF_INET); + + HLOGC(smlog.Debug, log << s->core().CONID() << "updateMux: config rcv queue qsize=" << 128 + << " plsize=" << payload_size << " hsize=" << 1024); + m.m_pRcvQueue->init(128, payload_size, m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer); // Rewrite the port here, as it might be only known upon return // from CChannel::open. diff --git a/srtcore/buffer_rcv.cpp b/srtcore/buffer_rcv.cpp index 3098407a6..a2a3d3d65 100644 --- a/srtcore/buffer_rcv.cpp +++ b/srtcore/buffer_rcv.cpp @@ -130,7 +130,7 @@ CRcvBuffer::CRcvBuffer(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool b , m_bMessageAPI(bMessageAPI) , m_iBytesCount(0) , m_iPktsCount(0) - , m_uAvgPayloadSz(SRT_LIVE_DEF_PLSIZE) + , m_uAvgPayloadSz(0) { SRT_ASSERT(size < size_t(std::numeric_limits::max())); // All position pointers are integers } @@ -751,7 +751,12 @@ void CRcvBuffer::countBytes(int pkts, int bytes) m_iBytesCount += bytes; // added or removed bytes from rcv buffer m_iPktsCount += pkts; if (bytes > 0) // Assuming one pkt when adding bytes - m_uAvgPayloadSz = avg_iir<100>(m_uAvgPayloadSz, (unsigned) bytes); + { + if (!m_uAvgPayloadSz) + m_uAvgPayloadSz = bytes; + else + m_uAvgPayloadSz = avg_iir<100>(m_uAvgPayloadSz, (unsigned) bytes); + } } void CRcvBuffer::releaseUnitInPos(int pos) diff --git a/srtcore/buffer_snd.cpp b/srtcore/buffer_snd.cpp index 26f885dd6..9f224a678 100644 --- a/srtcore/buffer_snd.cpp +++ b/srtcore/buffer_snd.cpp @@ -64,7 +64,7 @@ using namespace std; using namespace srt_logging; using namespace sync; -CSndBuffer::CSndBuffer(int size, int maxpld, int authtag) +CSndBuffer::CSndBuffer(int ip_family, int size, int maxpld, int authtag) : m_BufLock() , m_pBlock(NULL) , m_pFirstBlock(NULL) @@ -77,6 +77,7 @@ CSndBuffer::CSndBuffer(int size, int maxpld, int authtag) , m_iAuthTagSize(authtag) , m_iCount(0) , m_iBytesCount(0) + , m_rateEstimator(ip_family) { // initial physical buffer of "size" m_pBuffer = new Buffer; diff --git a/srtcore/buffer_snd.h b/srtcore/buffer_snd.h index 4440b9bfd..5da8c9631 100644 --- a/srtcore/buffer_snd.h +++ b/srtcore/buffer_snd.h @@ -87,7 +87,7 @@ class CSndBuffer /// @param size initial number of blocks (each block to store one packet payload). /// @param maxpld maximum packet payload (including auth tag). /// @param authtag auth tag length in bytes (16 for GCM, 0 otherwise). - CSndBuffer(int size = 32, int maxpld = 1500, int authtag = 0); + CSndBuffer(int ip_family, int size, int maxpld, int authtag); ~CSndBuffer(); public: diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 1cdc72d58..e0ecb81fb 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -102,11 +102,12 @@ void AvgBufSize::update(const steady_clock::time_point& now, int pkts, int bytes m_dTimespanMAvg = avg_iir_w<1000, double>(m_dTimespanMAvg, timespan_ms, elapsed_ms); } -CRateEstimator::CRateEstimator() +CRateEstimator::CRateEstimator(int family) : m_iInRatePktsCount(0) , m_iInRateBytesCount(0) , m_InRatePeriod(INPUTRATE_FAST_START_US) // 0.5 sec (fast start) , m_iInRateBps(INPUTRATE_INITIAL_BYTESPS) + , m_iFullHeaderSize(CPacket::udpHeaderSize(family) + CPacket::HDR_SIZE) {} void CRateEstimator::setInputRateSmpPeriod(int period) @@ -141,7 +142,7 @@ void CRateEstimator::updateInputRate(const time_point& time, int pkts, int bytes if (early_update || period_us > m_InRatePeriod) { // Required Byte/sec rate (payload + headers) - m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE); + m_iInRateBytesCount += (m_iInRatePktsCount * m_iFullHeaderSize); m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us); HLOGC(bslog.Debug, log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index a6d81a356..828690b95 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -93,7 +93,7 @@ class CRateEstimator typedef sync::steady_clock::time_point time_point; typedef sync::steady_clock::duration duration; public: - CRateEstimator(); + CRateEstimator(int family); public: uint64_t getInRatePeriod() const { return m_InRatePeriod; } @@ -125,6 +125,7 @@ class CRateEstimator time_point m_tsInRateStartTime; uint64_t m_InRatePeriod; // usec int m_iInRateBps; // Input Rate in Bytes/sec + int m_iFullHeaderSize; }; } diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 31a29092f..ec3c68beb 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -1005,6 +1005,15 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet if ((msg_flags & errmsgflg[i].first) != 0) flg << " " << errmsgflg[i].second; + if (msg_flags & MSG_TRUNC) + { + // Additionally show buffer information in this case + flg << " buffers: "; + for (size_t i = 0; i < CPacket::PV_SIZE; ++i) + { + flg << "[" << w_packet.m_PacketVector[i].iov_len << "] "; + } + } // This doesn't work the same way on Windows, so on Windows just skip it. #endif diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 53148136a..a39312ec3 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -209,7 +209,7 @@ void srt::CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const soc { // Check if the peer address is a model of IPv4-mapped-on-IPv6. // If so, it means that the `ip` array should be interpreted as IPv4. - const bool is_mapped_ipv4 = checkMappedIPv4((uint16_t*)peer.sin6.sin6_addr.s6_addr); + const bool is_mapped_ipv4 = checkMappedIPv4(peer.sin6); sockaddr_in6* a = (&w_addr.sin6); diff --git a/srtcore/common.h b/srtcore/common.h index 5f3dd7f18..7dc84ea14 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -1420,6 +1420,15 @@ inline std::string SrtVersionString(int version) bool SrtParseConfig(const std::string& s, SrtConfig& w_config); +bool checkMappedIPv4(const uint16_t* sa); + +inline bool checkMappedIPv4(const sockaddr_in6& sa) +{ + const uint16_t* addr = reinterpret_cast(&sa.sin6_addr.s6_addr); + return checkMappedIPv4(addr); +} + + } // namespace srt #endif diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 91c73d660..b9265c046 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -63,6 +63,7 @@ class LiveCC: public SrtCongestionControlBase int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec) srt::sync::atomic m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit size_t m_zMaxPayloadSize; + size_t m_zHeaderSize; // NAKREPORT stuff. int m_iMinNakInterval_us; // Minimum NAK Report Period (usec) @@ -81,6 +82,8 @@ class LiveCC: public SrtCongestionControlBase m_zMaxPayloadSize = parent->maxPayloadSize(); m_zSndAvgPayloadSize = m_zMaxPayloadSize; + m_zHeaderSize = parent->m_config.iMSS - parent->maxPayloadSize(); + m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec) m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2) @@ -173,7 +176,7 @@ class LiveCC: public SrtCongestionControlBase void updatePktSndPeriod() { // packet = payload + header - const double pktsize = (double) m_zSndAvgPayloadSize.load() + CPacket::SRT_DATA_HDR_SIZE; + const double pktsize = (double) m_zSndAvgPayloadSize.load() + m_zHeaderSize; m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW); HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod << " by avg pktsize=" << m_zSndAvgPayloadSize diff --git a/srtcore/core.cpp b/srtcore/core.cpp index e6da157a5..b4d6160cf 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -269,6 +269,7 @@ void srt::CUDT::construct() m_pSndQueue = NULL; m_pRcvQueue = NULL; + m_TransferIPVersion = AF_UNSPEC; // Will be set after connection m_pSNode = NULL; m_pRNode = NULL; @@ -305,7 +306,9 @@ void srt::CUDT::construct() // m_cbPacketArrival.set(this, &CUDT::defaultPacketArrival); } -srt::CUDT::CUDT(CUDTSocket* parent): m_parent(parent) +srt::CUDT::CUDT(CUDTSocket* parent) + : m_parent(parent) + , m_stats(&m_iMaxSRTPayloadSize) { construct(); @@ -328,7 +331,9 @@ srt::CUDT::CUDT(CUDTSocket* parent): m_parent(parent) } -srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor): m_parent(parent) +srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor) + : m_parent(parent) + , m_stats(&m_iMaxSRTPayloadSize) { construct(); @@ -468,13 +473,17 @@ void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) optlen = sizeof(int); break; + // For SNDBUF/RCVBUF values take the variant that uses more memory. + // It is not possible to make sure what "family" is in use without + // checking if the socket is bound. This will also be the exact size + // of the memory in use. case SRTO_SNDBUF: - *(int *)optval = m_config.iSndBufSize * (m_config.iMSS - CPacket::UDP_HDR_SIZE); + *(int *)optval = m_config.iSndBufSize * (m_config.iMSS - CPacket::udpHeaderSize(AF_INET)); optlen = sizeof(int); break; case SRTO_RCVBUF: - *(int *)optval = m_config.iRcvBufSize * (m_config.iMSS - CPacket::UDP_HDR_SIZE); + *(int *)optval = m_config.iRcvBufSize * (m_config.iMSS - CPacket::udpHeaderSize(AF_INET)); optlen = sizeof(int); break; @@ -756,7 +765,7 @@ void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) case SRTO_PAYLOADSIZE: optlen = sizeof(int); - *(int *)optval = (int) m_config.zExpPayloadSize; + *(int *)optval = (int) payloadSize(); break; case SRTO_KMREFRESHRATE: @@ -872,11 +881,15 @@ string srt::CUDT::getstreamid(SRTSOCKET u) // XXX REFACTOR: Make common code for CUDT constructor and clearData, // possibly using CUDT::construct. // Initial sequence number, loss, acknowledgement, etc. -void srt::CUDT::clearData() +void srt::CUDT::clearData(int family) { - m_iMaxSRTPayloadSize = m_config.iMSS - CPacket::UDP_HDR_SIZE - CPacket::HDR_SIZE; + const size_t full_hdr_size = CPacket::udpHeaderSize(family) + CPacket::HDR_SIZE; + m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; HLOGC(cnlog.Debug, log << CONID() << "clearData: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); + m_SndTimeWindow.initialize(full_hdr_size, m_iMaxSRTPayloadSize); + m_RcvTimeWindow.initialize(full_hdr_size, m_iMaxSRTPayloadSize); + m_iEXPCount = 1; m_iBandwidth = 1; // pkts/sec // XXX use some constant for this 16 @@ -919,11 +932,11 @@ void srt::CUDT::clearData() m_tsRcvPeerStartTime = steady_clock::time_point(); } -void srt::CUDT::open() +void srt::CUDT::open(int family) { ScopedLock cg(m_ConnectionLock); - clearData(); + clearData(family); // structures for queue if (m_pSNode == NULL) @@ -3025,7 +3038,9 @@ bool srt::CUDT::checkApplyFilterConfig(const std::string &confstr) m_config.sPacketFilterConfig.set(confstr); } - size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - cfg.extra_size; + // XXX Using less maximum payload size of IPv4 and IPv6; this is only about the payload size + // for live. + size_t efc_max_payload_size = SRT_MAX_PLSIZE_AF_INET6 - cfg.extra_size; if (m_config.zExpPayloadSize > efc_max_payload_size) { LOGC(cnlog.Warn, @@ -4659,10 +4674,19 @@ bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) AT return false; } + m_TransferIPVersion = m_PeerAddr.family(); + if (m_PeerAddr.family() == AF_INET6) + { + // Check if the m_PeerAddr's address is a mapped IPv4. If so, + // define Transfer IP version as 4 because this one will be used. + if (checkMappedIPv4(m_PeerAddr.sin6)) + m_TransferIPVersion = AF_INET; + } + // Re-configure according to the negotiated values. m_config.iMSS = m_ConnRes.m_iMSS; m_iFlowWindowSize = m_ConnRes.m_iFlightFlagSize; - const int udpsize = m_config.iMSS - CPacket::UDP_HDR_SIZE; + const int udpsize = m_config.iMSS - CPacket::udpHeaderSize(m_TransferIPVersion); m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE; m_iPeerISN = m_ConnRes.m_iISN; @@ -5508,7 +5532,7 @@ int srt::CUDT::rcvDropTooLateUpTo(int seqno) enterCS(m_StatsLock); // Estimate dropped bytes from average payload size. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize(); - m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); + m_stats.rcvr.dropped.count(stats::BytesPacketsCount(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); leaveCS(m_StatsLock); } return iDropCnt; @@ -5532,7 +5556,7 @@ void srt::CUDT::setInitialRcvSeq(int32_t isn) const int iDropCnt = m_pRcvBuffer->dropAll(); const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize(); sync::ScopedLock sl(m_StatsLock); - m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); + m_stats.rcvr.dropped.count(stats::BytesPacketsCount(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); } m_pRcvBuffer->setStartSeqNo(isn); @@ -5572,8 +5596,30 @@ bool srt::CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd try { + // XXX SND buffer may allocate more memory, but must set the size of a single + // packet that fits the transmission for the overall connection. For any mixed 4-6 + // connection it should be the less size, that is, for IPv6 + const int authtag = m_config.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM ? HAICRYPT_AUTHTAG_MAX : 0; - m_pSndBuffer = new CSndBuffer(32, m_iMaxSRTPayloadSize, authtag); + + SRT_ASSERT(m_iMaxSRTPayloadSize != 0); + SRT_ASSERT(m_TransferIPVersion != AF_UNSPEC); + // IMPORTANT: + // The m_iMaxSRTPayloadSize is the size of the payload in the "SRT packet" that can be sent + // over the current connection - which means that if any party is IPv6, then the maximum size + // is the one for IPv6 (1444). Only if both parties are IPv4, this maximum size is 1456. + // The family as the first argument is something different - it's for the header size in order + // to calculate rate and statistics. + + int snd_payload_size = m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(AF_INET); + SRT_ASSERT(m_iMaxSRTPayloadSize <= snd_payload_size); + + HLOGC(rslog.Debug, log << CONID() << "Creating buffers: snd-plsize=" << snd_payload_size + << " snd-bufsize=" << 32 << " TF-IPv" + << (m_TransferIPVersion == AF_INET6 ? "6" : m_TransferIPVersion == AF_INET ? "4" : "???") + << " authtag=" << authtag); + + m_pSndBuffer = new CSndBuffer(m_TransferIPVersion, 32, snd_payload_size, authtag); SRT_ASSERT(m_iISN != -1); m_pRcvBuffer = new srt::CRcvBuffer(m_iISN, m_config.iRcvBufSize, m_pRcvQueue->m_pUnitQueue, m_config.bMessageAPI); // after introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice space. @@ -5651,8 +5697,17 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& rewriteHandshakeData(peer, (w_hs)); - int udpsize = m_config.iMSS - CPacket::UDP_HDR_SIZE; - m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE; + m_TransferIPVersion = peer.family(); + if (peer.family() == AF_INET6) + { + // Check if the peer's address is a mapped IPv4. If so, + // define Transfer IP version as 4 because this one will be used. + if (checkMappedIPv4(peer.sin6)) + m_TransferIPVersion = AF_INET; + } + + const size_t full_hdr_size = CPacket::udpHeaderSize(m_TransferIPVersion) + CPacket::HDR_SIZE; + m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); // Prepare all structures @@ -7285,7 +7340,7 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) if (m_bBroken || m_bClosing) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); - const int pktHdrSize = CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE; + const int pktHdrSize = CPacket::HDR_SIZE + CPacket::udpHeaderSize(m_TransferIPVersion == AF_UNSPEC ? AF_INET : m_TransferIPVersion); { ScopedLock statsguard(m_StatsLock); @@ -8861,7 +8916,7 @@ void srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt) enterCS(m_StatsLock); // Estimate dropped bytes from average payload size. const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize(); - m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); + m_stats.rcvr.dropped.count(stats::BytesPacketsCount(iDropCnt * avgpayloadsz, (uint32_t) iDropCnt)); leaveCS(m_StatsLock); } } @@ -9956,8 +10011,8 @@ int srt::CUDT::handleSocketPacketReception(const vector& incoming, bool& const steady_clock::time_point tnow = steady_clock::now(); ScopedLock lg(m_StatsLock); - m_stats.rcvr.dropped.count(stats::BytesPackets(iDropCnt * rpkt.getLength(), iDropCnt)); - m_stats.rcvr.undecrypted.count(stats::BytesPackets(rpkt.getLength(), 1)); + m_stats.rcvr.dropped.count(stats::BytesPacketsCount(iDropCnt * rpkt.getLength(), iDropCnt)); + m_stats.rcvr.undecrypted.count(stats::BytesPacketsCount(rpkt.getLength(), 1)); if (frequentLogAllowed(tnow)) { LOGC(qrlog.Warn, log << CONID() << "Decryption failed (seqno %" << u->m_Packet.getSeqNo() << "), dropped " @@ -10158,7 +10213,7 @@ int srt::CUDT::processData(CUnit* in_unit) ScopedLock lg(m_StatsLock); const uint64_t avgpayloadsz = m_pRcvBuffer->getRcvAvgPayloadSize(); - m_stats.rcvr.lost.count(stats::BytesPackets(loss * avgpayloadsz, (uint32_t) loss)); + m_stats.rcvr.lost.count(stats::BytesPacketsCount(loss * avgpayloadsz, (uint32_t) loss)); HLOGC(qrlog.Debug, log << CONID() << "LOSS STATS: n=" << loss << " SEQ: [" << CSeqNo::incseq(m_iRcvCurrPhySeqNo) << " " diff --git a/srtcore/core.h b/srtcore/core.h index ce0e53958..67ee0dcb7 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -179,7 +179,7 @@ class CUDT private: // constructor and desctructor void construct(); - void clearData(); + void clearData(int family); CUDT(CUDTSocket* parent); CUDT(CUDTSocket* parent, const CUDT& ancestor); const CUDT& operator=(const CUDT&) {return *this;} // = delete ? @@ -328,6 +328,19 @@ class CUDT int peerIdleTimeout_ms() const { return m_config.iPeerIdleTimeout_ms; } size_t maxPayloadSize() const { return m_iMaxSRTPayloadSize; } size_t OPT_PayloadSize() const { return m_config.zExpPayloadSize; } + size_t payloadSize() const + { + // If payloadsize is set, it should already be checked that + // it is less than the possible maximum payload size. So return it + // if it is set to nonzero value. In case when the connection isn't + // yet established, return also 0, if the value wasn't set. + if (m_config.zExpPayloadSize || !m_bConnected) + return m_config.zExpPayloadSize; + + // If SRTO_PAYLOADSIZE was remaining with 0 (default for FILE mode) + // then return the maximum payload size per packet. + return m_iMaxSRTPayloadSize; + } int sndLossLength() { return m_pSndLossList->getLossLength(); } int32_t ISN() const { return m_iISN; } int32_t peerISN() const { return m_iPeerISN; } @@ -446,7 +459,7 @@ class CUDT private: /// initialize a UDT entity and bind to a local address. - void open(); + void open(int family); /// Start listening to any connection request. void setListenState(); @@ -728,13 +741,6 @@ class CUDT static loss_seqs_t defaultPacketArrival(void* vself, CPacket& pkt); static loss_seqs_t groupPacketArrival(void* vself, CPacket& pkt); - CRateEstimator getRateEstimator() const - { - if (!m_pSndBuffer) - return CRateEstimator(); - return m_pSndBuffer->getRateEstimator(); - } - void setRateEstimator(const CRateEstimator& rate) { if (!m_pSndBuffer) @@ -1134,6 +1140,11 @@ class CUDT int64_t sndDuration; // real time for sending time_point sndDurationCounter; // timers to record the sending Duration + + CoreStats(int* payloadsize_loc) + : sndr(payloadsize_loc) + , rcvr(payloadsize_loc) + {} } m_stats; public: @@ -1168,6 +1179,7 @@ class CUDT sockaddr_any m_PeerAddr; // peer address sockaddr_any m_SourceAddr; // override UDP source address with this one when sending uint32_t m_piSelfIP[4]; // local UDP IP address + int m_TransferIPVersion; // AF_INET/6 that should be used to determine common payload size CSNode* m_pSNode; // node information for UDT list used in snd queue CRNode* m_pRNode; // node information for UDT list used in rcv queue diff --git a/srtcore/group.cpp b/srtcore/group.cpp index f4dfba1ba..c411740cd 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -236,7 +236,7 @@ CUDTGroup::SocketData* CUDTGroup::add(SocketData data) log << "CUDTGroup::add: taking MAX payload size from socket @" << data.ps->m_SocketID << ": " << plsize << " " << (plsize ? "(explicit)" : "(unspecified = fallback to 1456)")); if (plsize == 0) - plsize = SRT_LIVE_MAX_PLSIZE; + plsize = CPacket::srtPayloadSize(data.agent.family()); // It is stated that the payload size // is taken from first, and every next one // will get the same. @@ -506,8 +506,8 @@ void CUDTGroup::deriveSettings(CUDT* u) 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)); + importOption(m_config, SRTO_SNDBUF, u->m_config.iSndBufSize * (u->m_config.iMSS - CPacket::udpHeaderSize(AF_INET))); + importOption(m_config, SRTO_RCVBUF, u->m_config.iRcvBufSize * (u->m_config.iMSS - CPacket::udpHeaderSize(AF_INET))); IM(SRTO_LINGER, Linger); IM(SRTO_UDP_SNDBUF, iUDPSndBufSize); @@ -639,7 +639,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::udpHeaderSize(AF_INET))); break; case SRTO_LINGER: @@ -3533,7 +3533,9 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc) } // Only live streaming is supported - if (len > SRT_LIVE_MAX_PLSIZE) + // Also - as the group may use potentially IPv4 and IPv6 connections + // in the same group, use the size that fits both + if (len > SRT_MAX_PLSIZE_AF_INET6) { LOGC(gslog.Error, log << "grp/send(backup): buffer size=" << len << " exceeds maximum allowed in live mode"); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -3968,7 +3970,8 @@ void CUDTGroup::internalKeepalive(SocketData* gli) } } -CUDTGroup::BufferedMessageStorage CUDTGroup::BufferedMessage::storage(SRT_LIVE_MAX_PLSIZE /*, 1000*/); +// Use the bigger size of SRT_MAX_PLSIZE to potentially fit both IPv4/6 +CUDTGroup::BufferedMessageStorage CUDTGroup::BufferedMessage::storage(SRT_MAX_PLSIZE_AF_INET /*, 1000*/); // Forwarder needed due to class definition order int32_t CUDTGroup::generateISN() diff --git a/srtcore/group_backup.h b/srtcore/group_backup.h index 790cf55ed..cecbc6d1b 100644 --- a/srtcore/group_backup.h +++ b/srtcore/group_backup.h @@ -79,6 +79,7 @@ namespace groups : m_stateCounter() // default init with zeros , m_activeMaxWeight() , m_standbyMaxWeight() + , m_rateEstimate(AF_INET6) // XXX Probably the whole solution is wrong { } diff --git a/srtcore/packet.h b/srtcore/packet.h index 027d5f0b3..b7399b925 100644 --- a/srtcore/packet.h +++ b/srtcore/packet.h @@ -364,16 +364,24 @@ class CPacket static const size_t HDR_SIZE = sizeof(HEADER_TYPE); // packet header size = SRT_PH_E_SIZE * sizeof(uint32_t) - // Can also be calculated as: sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr). - static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }. - - static const size_t SRT_DATA_HDR_SIZE = UDP_HDR_SIZE + HDR_SIZE; +private: // Do not disclose ingredients to the public + static const size_t UDP_HDR_SIZE = 8; // 8 bytes of UDP { u16 sport, dport, len, csum }. + static const size_t IPv4_HDR_SIZE = 20; // 20 bytes IPv4 + static const size_t IPv6_HDR_SIZE = 32; // 32 bytes IPv6 +public: + static inline size_t udpHeaderSize(int family) + { + return UDP_HDR_SIZE + (family == AF_INET ? IPv4_HDR_SIZE : IPv6_HDR_SIZE); + } + static inline size_t srtPayloadSize(int family) + { + return ETH_MAX_MTU_SIZE - (family == AF_INET ? IPv4_HDR_SIZE : IPv6_HDR_SIZE) - UDP_HDR_SIZE - HDR_SIZE; + } // Maximum transmission unit size. 1500 in case of Ethernet II (RFC 1191). static const size_t ETH_MAX_MTU_SIZE = 1500; // Maximum payload size of an SRT packet. - static const size_t SRT_MAX_PAYLOAD_SIZE = ETH_MAX_MTU_SIZE - SRT_DATA_HDR_SIZE; // Packet interface char* data() { return m_pcData; } diff --git a/srtcore/packetfilter_api.h b/srtcore/packetfilter_api.h index 3bfba7c76..ef0d8867f 100644 --- a/srtcore/packetfilter_api.h +++ b/srtcore/packetfilter_api.h @@ -66,7 +66,7 @@ struct SrtFilterInitializer struct SrtPacket { uint32_t hdr[SRT_PH_E_SIZE]; - char buffer[SRT_LIVE_MAX_PLSIZE]; + char buffer[SRT_MAX_PLSIZE_AF_INET]; // Using this as the bigger one (this for AF_INET6 is smaller) size_t length; SrtPacket(size_t size): length(size) diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 476162001..e72563c27 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -70,7 +70,7 @@ struct CSrtConfigSetter static void set(CSrtConfig& co, const void* optval, int optlen) { const int ival = cast_optval(optval, optlen); - if (ival < int(CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize)) + if (ival < int(CPacket::udpHeaderSize(AF_INET6) + CHandShake::m_iContentSize)) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); co.iMSS = ival; @@ -109,7 +109,7 @@ struct CSrtConfigSetter if (bs <= 0) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.iSndBufSize = bs / (co.iMSS - CPacket::UDP_HDR_SIZE); + co.iSndBufSize = bs / (co.iMSS - CPacket::udpHeaderSize(AF_INET)); } }; @@ -123,7 +123,7 @@ struct CSrtConfigSetter throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); // Mimimum recv buffer size is 32 packets - const int mssin_size = co.iMSS - CPacket::UDP_HDR_SIZE; + const int mssin_size = co.iMSS - CPacket::udpHeaderSize(AF_INET); if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT) co.iRcvBufSize = val / mssin_size; @@ -609,42 +609,20 @@ struct CSrtConfigSetter throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } - if (val > SRT_LIVE_MAX_PLSIZE) + // We don't know at this point, how bit the payloadsize can be set, + // so we limit it to the biggest value of the two. + // When this payloadsize would be then too big to be used with given MSS and IPv6, + // this problem should be reported appropriately from srt_connect and srt_bind calls. + if (val > SRT_MAX_PLSIZE_AF_INET) { - LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << ", maximum payload per MTU."); + LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_MAX_PLSIZE_AF_INET << ", maximum payload per MTU."); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } - if (!co.sPacketFilterConfig.empty()) + std::string errorlog; + if (!co.payloadSizeFits(size_t(val), AF_INET, (errorlog))) { - // This means that the filter might have been installed before, - // and the fix to the maximum payload size was already applied. - // This needs to be checked now. - SrtFilterConfig fc; - if (!ParseFilterConfig(co.sPacketFilterConfig.str(), fc)) - { - // Break silently. This should not happen - LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: IPE: failing filter configuration installed"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - const size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; - if (size_t(val) > efc_max_payload_size) - { - LOGC(aclog.Error, - log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << " bytes decreased by " << fc.extra_size - << " required for packet filter header"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - } - - // Not checking AUTO to allow defaul 1456 bytes. - if ((co.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM) - && (val > (SRT_LIVE_MAX_PLSIZE - HAICRYPT_AUTHTAG_MAX))) - { - LOGC(aclog.Error, - log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << " bytes decreased by " << HAICRYPT_AUTHTAG_MAX - << " required for AES-GCM."); + LOGP(aclog.Error, errorlog); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } @@ -840,7 +818,7 @@ struct CSrtConfigSetter throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } - size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; + size_t efc_max_payload_size = SRT_MAX_PLSIZE_AF_INET - fc.extra_size; if (co.zExpPayloadSize > efc_max_payload_size) { LOGC(aclog.Warn, @@ -1011,6 +989,47 @@ int CSrtConfig::set(SRT_SOCKOPT optName, const void* optval, int optlen) return dispatchSet(optName, *this, optval, optlen); } +bool CSrtConfig::payloadSizeFits(size_t val, int ip_family, std::string& w_errmsg) ATR_NOTHROW +{ + if (!this->sPacketFilterConfig.empty()) + { + // This means that the filter might have been installed before, + // and the fix to the maximum payload size was already applied. + // This needs to be checked now. + SrtFilterConfig fc; + if (!this->sPacketFilterConfig.empty() && !ParseFilterConfig(this->sPacketFilterConfig.str(), (fc))) + { + // Break silently. This should not happen + w_errmsg = "SRTO_PAYLOADSIZE: IPE: failing filter configuration installed"; + return false; + } + + const size_t efc_max_payload_size = CPacket::srtPayloadSize(ip_family) - fc.extra_size; + if (size_t(val) > efc_max_payload_size) + { + std::ostringstream log; + log << "SRTO_PAYLOADSIZE: value exceeds " << CPacket::srtPayloadSize(ip_family) << " bytes decreased by " << fc.extra_size + << " required for packet filter header"; + w_errmsg = log.str(); + return false; + } + } + + // Not checking AUTO to allow defaul 1456 bytes. + if ((this->iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM) + && (val > (CPacket::srtPayloadSize(ip_family) - HAICRYPT_AUTHTAG_MAX))) + { + std::ostringstream log; + log << "SRTO_PAYLOADSIZE: value exceeds " << CPacket::srtPayloadSize(ip_family) + << " bytes decreased by " << HAICRYPT_AUTHTAG_MAX + << " required for AES-GCM."; + w_errmsg = log.str(); + return false; + } + + return true; +} + #if ENABLE_BONDING bool SRT_SocketOptionObject::add(SRT_SOCKOPT optname, const void* optval, size_t optlen) { diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 488d12fb1..72ae9808f 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -326,6 +326,8 @@ struct CSrtConfig: CSrtMuxerConfig } int set(SRT_SOCKOPT optName, const void* val, int size); + + bool payloadSizeFits(size_t val, int ip_family, std::string& w_errmsg) ATR_NOTHROW; }; template diff --git a/srtcore/srt.h b/srtcore/srt.h index 39a90ce71..784274f86 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -299,7 +299,12 @@ static const int SRT_LIVE_DEF_PLSIZE = 1316; // = 188*7, recommended for MPEG TS // This is the maximum payload size for Live mode, should you have a different // payload type than MPEG TS. -static const int SRT_LIVE_MAX_PLSIZE = 1456; // MTU(1500) - UDP.hdr(28) - SRT.hdr(16) +SRT_ATR_DEPRECATED_PX static const int SRT_LIVE_MAX_PLSIZE SRT_ATR_DEPRECATED = 1456; // MTU(1500) - UDP.hdr(28) - SRT.hdr(16) + +static const int SRT_MAX_PLSIZE_AF_INET = 1456; // MTU(1500) - IPv4.hdr(20) - UDP.hdr(8) - SRT.hdr(16) +static const int SRT_MAX_PLSIZE_AF_INET6 = 1444; // MTU(1500) - IPv6.hdr(32) - UDP.hdr(8) - SRT.hdr(16) + +#define SRT_MAX_PLSIZE(famspec) ((famspec) == AF_INET ? SRT_MAX_PLSIZE_AF_INET : SRT_MAX_PLSIZE_AF_INET6) // Latency for Live transmission: default is 120 static const int SRT_LIVE_DEF_LATENCY_MS = 120; diff --git a/srtcore/stats.h b/srtcore/stats.h index bce60761b..2c0276665 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -22,6 +22,8 @@ namespace stats class Packets { public: + typedef Packets count_type; + Packets() : m_count(0) {} Packets(uint32_t num) : m_count(num) {} @@ -46,27 +48,20 @@ class Packets uint32_t m_count; }; -class BytesPackets +class BytesPacketsCount { public: - BytesPackets() + BytesPacketsCount() : m_bytes(0) , m_packets(0) {} - BytesPackets(uint64_t bytes, uint32_t n = 1) + BytesPacketsCount(uint64_t bytes, uint32_t n = 1) : m_bytes(bytes) , m_packets(n) {} - BytesPackets& operator+= (const BytesPackets& other) - { - m_bytes += other.m_bytes; - m_packets += other.m_packets; - return *this; - } -public: void reset() { m_packets = 0; @@ -89,28 +84,63 @@ class BytesPackets return m_packets; } - uint64_t bytesWithHdr() const + BytesPacketsCount& operator+= (const BytesPacketsCount& other) { - return m_bytes + m_packets * CPacket::SRT_DATA_HDR_SIZE; + m_bytes += other.m_bytes; + m_packets += other.m_packets; + return *this; } -private: +protected: uint64_t m_bytes; uint32_t m_packets; }; -template +class BytesPackets: public BytesPacketsCount +{ +public: + typedef BytesPacketsCount count_type; + + BytesPackets() + : m_pPayloadSizeLocation(NULL) + {} + +public: + + void bindPayloadSize(int* sizeloc) + { + m_pPayloadSizeLocation = sizeloc; + } + + uint64_t bytesWithHdr() const + { + SRT_ASSERT(m_pPayloadSizeLocation != NULL); + size_t header_size = CPacket::ETH_MAX_MTU_SIZE - *m_pPayloadSizeLocation; + return m_bytes + m_packets * header_size; + } + +private: + int* m_pPayloadSizeLocation; +}; + +template struct Metric { METRIC_TYPE trace; METRIC_TYPE total; - void count(METRIC_TYPE val) + void count(typename METRIC_TYPE::count_type val) { trace += val; total += val; } + void bindPayloadSize(int* loc) + { + trace.bindPayloadSize(loc); + total.bindPayloadSize(loc); + } + void reset() { trace.reset(); @@ -137,6 +167,16 @@ struct Sender Metric recvdAck; // The number of ACK packets received by the sender. Metric recvdNak; // The number of ACK packets received by the sender. + Sender(int* payloadsize_loc) + { +#define BIND(var) var.bindPayloadSize(payloadsize_loc) + BIND(sent); + BIND(sentUnique); + BIND(sentRetrans); + BIND(dropped); +#undef BIND + } + void reset() { sent.reset(); @@ -180,6 +220,19 @@ struct Receiver Metric sentAck; // The number of ACK packets sent by the receiver. Metric sentNak; // The number of NACK packets sent by the receiver. + Receiver(int* payloadsize_loc) + { +#define BIND(var) var.bindPayloadSize(payloadsize_loc) + BIND(recvd); + BIND(recvdUnique); + BIND(recvdRetrans); + BIND(lost); + BIND(dropped); + BIND(recvdBelated); + BIND(undecrypted); +#undef BIND + } + void reset() { recvd.reset(); diff --git a/srtcore/window.cpp b/srtcore/window.cpp index 46889ecb0..b038575e4 100644 --- a/srtcore/window.cpp +++ b/srtcore/window.cpp @@ -145,7 +145,7 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3 //////////////////////////////////////////////////////////////////////////////// -void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize) +void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize, size_t max_payload_size) { for (size_t i = 0; i < asize; ++ i) r_pktWindow[i] = 1000000; //1 sec -> 1 pkt/sec @@ -154,11 +154,11 @@ void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_p r_probeWindow[k] = 1000; //1 msec -> 1000 pkts/sec for (size_t i = 0; i < asize; ++ i) - r_bytesWindow[i] = srt::CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i] + r_bytesWindow[i] = max_payload_size; //based on 1 pkt/sec set in r_pktWindow[i] } -int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, int& bytesps) +int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, size_t hdr_size, int& bytesps) { // get median value, but cannot change the original value order in the window std::copy(window, window + asize, replica); @@ -191,7 +191,7 @@ int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, // claculate speed, or return 0 if not enough valid value if (count > (asize >> 1)) { - bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received + bytes += (hdr_size * count); //Add protocol headers to bytes received bytesps = (int)ceil(1000000.0 / (double(sum) / double(bytes))); return (int)ceil(1000000.0 / (sum / count)); } diff --git a/srtcore/window.h b/srtcore/window.h index ecc4a4947..3dfd94c3e 100644 --- a/srtcore/window.h +++ b/srtcore/window.h @@ -130,10 +130,10 @@ class CACKWindow class CPktTimeWindowTools { public: - static int getPktRcvSpeed_in(const int* window, int* replica, const int* bytes, size_t asize, int& bytesps); + static int getPktRcvSpeed_in(const int* window, int* replica, const int* bytes, size_t asize, size_t hsize, int& bytesps); static int getBandwidth_in(const int* window, int* replica, size_t psize); - static void initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize); + static void initializeWindowArrays(int* r_pktWindow, int* r_probeWindow, int* r_bytesWindow, size_t asize, size_t psize, size_t max_payload_size); }; template @@ -151,12 +151,13 @@ class CPktTimeWindow: CPktTimeWindowTools m_tsLastArrTime(sync::steady_clock::now()), m_tsCurrArrTime(), m_tsProbeTime(), - m_Probe1Sequence(SRT_SEQNO_NONE) + m_Probe1Sequence(SRT_SEQNO_NONE), + m_zPayloadSize(0), + m_zHeaderSize(0) { // Exception: up to CUDT ctor sync::setupMutex(m_lockPktWindow, "PktWindow"); sync::setupMutex(m_lockProbeWindow, "ProbeWindow"); - CPktTimeWindowTools::initializeWindowArrays(m_aPktWindow, m_aProbeWindow, m_aBytesWindow, ASIZE, PSIZE); } ~CPktTimeWindow() @@ -174,11 +175,12 @@ class CPktTimeWindow: CPktTimeWindowTools int getPktRcvSpeed(int& w_bytesps) const { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); // Lock access to the packet Window sync::ScopedLock cg(m_lockPktWindow); int pktReplica[ASIZE]; // packet information window (inter-packet time) - return getPktRcvSpeed_in(m_aPktWindow, pktReplica, m_aBytesWindow, ASIZE, (w_bytesps)); + return getPktRcvSpeed_in(m_aPktWindow, pktReplica, m_aBytesWindow, ASIZE, m_zHeaderSize, (w_bytesps)); } int getPktRcvSpeed() const @@ -192,6 +194,7 @@ class CPktTimeWindow: CPktTimeWindowTools int getBandwidth() const { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); // Lock access to the packet Window sync::ScopedLock cg(m_lockProbeWindow); @@ -204,6 +207,7 @@ class CPktTimeWindow: CPktTimeWindowTools void onPktSent(int currtime) { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); int interval = currtime - m_iLastSentTime; if ((interval < m_iMinPktSndInt) && (interval > 0)) @@ -216,6 +220,7 @@ class CPktTimeWindow: CPktTimeWindowTools void onPktArrival(int pktsz = 0) { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); sync::ScopedLock cg(m_lockPktWindow); m_tsCurrArrTime = sync::steady_clock::now(); @@ -236,6 +241,7 @@ class CPktTimeWindow: CPktTimeWindowTools /// Shortcut to test a packet for possible probe 1 or 2 void probeArrival(const CPacket& pkt, bool unordered) { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); const int inorder16 = pkt.m_iSeqNo & PUMASK_SEQNO_PROBE; // for probe1, we want 16th packet @@ -257,6 +263,7 @@ class CPktTimeWindow: CPktTimeWindowTools /// Record the arrival time of the first probing packet. void probe1Arrival(const CPacket& pkt, bool unordered) { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); if (unordered && pkt.m_iSeqNo == m_Probe1Sequence) { // Reset the starting probe into "undefined", when @@ -274,6 +281,7 @@ class CPktTimeWindow: CPktTimeWindowTools void probe2Arrival(const CPacket& pkt) { + SRT_ASSERT(m_zHeaderSize != 0 && m_zPayloadSize != 0); // Reject probes that don't refer to the very next packet // towards the one that was lately notified by probe1Arrival. // Otherwise the result can be stupid. @@ -302,7 +310,7 @@ class CPktTimeWindow: CPktTimeWindowTools // record the probing packets interval // Adjust the time for what a complete packet would have take const int64_t timediff = sync::count_microseconds(m_tsCurrArrTime - m_tsProbeTime); - const int64_t timediff_times_pl_size = timediff * CPacket::SRT_MAX_PAYLOAD_SIZE; + const int64_t timediff_times_pl_size = timediff * m_zPayloadSize; // Let's take it simpler than it is coded here: // (stating that a packet has never zero size) @@ -327,6 +335,14 @@ class CPktTimeWindow: CPktTimeWindowTools m_iProbeWindowPtr = 0; } + // Late initialization because these sizes aren't known at construction time of the parent CUDT class. + void initialize(size_t h, size_t s) + { + m_zHeaderSize = h; + m_zPayloadSize = s; + CPktTimeWindowTools::initializeWindowArrays(m_aPktWindow, m_aProbeWindow, m_aBytesWindow, ASIZE, PSIZE, s); + } + private: int m_aPktWindow[ASIZE]; // Packet information window (inter-packet time) int m_aBytesWindow[ASIZE]; @@ -345,6 +361,9 @@ class CPktTimeWindow: CPktTimeWindowTools sync::steady_clock::time_point m_tsProbeTime; // Arrival time of the first probing packet int32_t m_Probe1Sequence; // Sequence number for which the arrival time was notified + size_t m_zPayloadSize; + size_t m_zHeaderSize; + private: CPktTimeWindow(const CPktTimeWindow&); CPktTimeWindow &operator=(const CPktTimeWindow&); diff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp index 46afd8981..bd50c6ffb 100644 --- a/test/test_fec_rebuilding.cpp +++ b/test/test_fec_rebuilding.cpp @@ -58,7 +58,7 @@ class TestFECRebuilding: public testing::Test source.emplace_back(new CPacket); CPacket& p = *source.back(); - p.allocate(SRT_LIVE_MAX_PLSIZE); + p.allocate(SRT_MAX_PLSIZE_AF_INET); uint32_t* hdr = p.getHeader(); @@ -729,7 +729,7 @@ TEST_F(TestFECRebuilding, Prepare) seq = p.getSeqNo(); } - SrtPacket fec_ctl(SRT_LIVE_MAX_PLSIZE); + SrtPacket fec_ctl(SRT_MAX_PLSIZE_AF_INET); // Use the sequence number of the last packet, as usual. bool have_fec_ctl = fec->packControlPacket(fec_ctl, seq); @@ -750,7 +750,7 @@ TEST_F(TestFECRebuilding, NoRebuild) seq = p.getSeqNo(); } - SrtPacket fec_ctl(SRT_LIVE_MAX_PLSIZE); + SrtPacket fec_ctl(SRT_MAX_PLSIZE_AF_INET); // Use the sequence number of the last packet, as usual. const bool have_fec_ctl = fec->packControlPacket(fec_ctl, seq); @@ -827,7 +827,7 @@ TEST_F(TestFECRebuilding, Rebuild) seq = p.getSeqNo(); } - SrtPacket fec_ctl(SRT_LIVE_MAX_PLSIZE); + SrtPacket fec_ctl(SRT_MAX_PLSIZE_AF_INET); // Use the sequence number of the last packet, as usual. const bool have_fec_ctl = fec->packControlPacket(fec_ctl, seq); diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 5a646fb7d..48d790471 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -17,6 +17,7 @@ #endif #include "srt.h" +#include "netinet_any.h" #include #include @@ -27,7 +28,7 @@ //#pragma comment (lib, "ws2_32.lib") -TEST(Transmission, FileUpload) +TEST(FileTransmission, Upload) { srt_startup(); @@ -197,3 +198,113 @@ TEST(Transmission, FileUpload) (void)srt_cleanup(); } + +TEST(FileTransmission, Setup46) +{ + using namespace srt; + + srt_startup(); + + SRTSOCKET sock_lsn = srt_create_socket(), sock_clr = srt_create_socket(); + + const int tt = SRTT_FILE; + srt_setsockflag(sock_lsn, SRTO_TRANSTYPE, &tt, sizeof tt); + srt_setsockflag(sock_clr, SRTO_TRANSTYPE, &tt, sizeof tt); + + try + { + // Setup a connection with IPv6 caller and IPv4 listener, + // then send data of 1456 size and make sure two packets were used. + + // So first configure a caller for IPv6 socket, capable of + // using IPv4. As the IP version isn't specified now when + // creating a socket, force binding explicitly. + + // This creates the "any" spec for IPv6 with port = 0 + sockaddr_any sa(AF_INET6); + + int ipv4_and_ipv6 = 0; + ASSERT_NE(srt_setsockflag(sock_clr, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); + + // srt_setloglevel(LOG_DEBUG); + + ASSERT_NE(srt_bind(sock_clr, sa.get(), sa.size()), -1); + + int connect_port = 5555; + + // Configure listener + sockaddr_in sa_lsn = sockaddr_in(); + sa_lsn.sin_family = AF_INET; + sa_lsn.sin_addr.s_addr = INADDR_ANY; + sa_lsn.sin_port = htons(connect_port); + + + srt_setloglevel(LOG_DEBUG); + + + // Find unused a port not used by any other service. + // Otherwise srt_connect may actually connect. + int bind_res = -1; + for (connect_port = 5000; connect_port <= 5555; ++connect_port) + { + sa_lsn.sin_port = htons(connect_port); + bind_res = srt_bind(sock_lsn, (sockaddr*)&sa_lsn, sizeof sa_lsn); + if (bind_res == 0) + { + std::cout << "Running test on port " << connect_port << "\n"; + break; + } + + ASSERT_TRUE(bind_res == SRT_EINVOP) << "Bind failed not due to an occupied port. Result " << bind_res; + } + + ASSERT_GE(bind_res, 0); + + srt_listen(sock_lsn, 1); + + ASSERT_EQ(inet_pton(AF_INET6, "::FFFF:127.0.0.1", &sa.sin6.sin6_addr), 1); + + sa.hport(connect_port); + + ASSERT_EQ(srt_connect(sock_clr, sa.get(), sa.size()), 0); + + int sock_acp = -1; + ASSERT_NE(sock_acp = srt_accept(sock_lsn, sa.get(), &sa.len), -1); + + const size_t SIZE = 1454; // Max payload for IPv4 minus 2 - still more than 1444 for IPv6 + char buffer[SIZE]; + + unsigned int randseed = std::time(NULL); + + for (size_t i = 0; i < SIZE; ++i) + buffer[i] = rand_r(&randseed); + + EXPECT_EQ(srt_send(sock_acp, buffer, SIZE), SIZE) << srt_getlasterror_str(); + + char resultbuf[SIZE]; + EXPECT_EQ(srt_recv(sock_clr, resultbuf, SIZE), SIZE) << srt_getlasterror_str(); + + // It should use the maximum payload size per packet reported from the option. + int payloadsize_back = 0; + int payloadsize_back_size = sizeof (payloadsize_back); + EXPECT_EQ(srt_getsockflag(sock_clr, SRTO_PAYLOADSIZE, &payloadsize_back, &payloadsize_back_size), 0); + EXPECT_EQ(payloadsize_back, SRT_MAX_PLSIZE_AF_INET); + + SRT_TRACEBSTATS snd_stats, rcv_stats; + srt_bstats(sock_acp, &snd_stats, 0); + srt_bstats(sock_clr, &rcv_stats, 0); + + EXPECT_EQ(snd_stats.pktSentUniqueTotal, 1); + EXPECT_EQ(rcv_stats.pktRecvUniqueTotal, 1); + + } + catch (...) + { + srt_cleanup(); + throw; + } + + srt_cleanup(); +} + +// XXX Setup66 - establish an IPv6 to IPv6 connection and make sure max payload size is that of IPv6. diff --git a/testing/srt-test-mpbond.cpp b/testing/srt-test-mpbond.cpp index c23b262b7..90baae7f6 100644 --- a/testing/srt-test-mpbond.cpp +++ b/testing/srt-test-mpbond.cpp @@ -240,7 +240,7 @@ int main( int argc, char** argv ) return 2; } - size_t chunk = SRT_LIVE_MAX_PLSIZE; + size_t chunk = SRT_MAX_PLSIZE_AF_INET; // state the bigger size // Now run the loop try diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index 34d2bdc9b..b30d98a20 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -392,6 +392,37 @@ void SrtCommon::InitParameters(string host, string path, map par) { m_mode = par.at("mode"); } + + int fam_to_limit_size = AF_INET6; // take the less one as default + + // Try to interpret host and adapter first + sockaddr_any host_sa, adapter_sa; + + if (host != "") + { + host_sa = CreateAddr(host); + fam_to_limit_size = host_sa.family(); + if (fam_to_limit_size == AF_UNSPEC) + Error("Failed to interpret 'host' spec: " + host); + } + + if (adapter != "") + { + adapter_sa = CreateAddr(adapter); + fam_to_limit_size = adapter_sa.family(); + + if (fam_to_limit_size == AF_UNSPEC) + Error("Failed to interpret 'adapter' spec: " + adapter); + + if (host_sa.family() != AF_UNSPEC && host_sa.family() != adapter_sa.family()) + { + Error("Both host and adapter specified and they use different IP versions"); + } + } + + if (fam_to_limit_size != AF_INET) + fam_to_limit_size = AF_INET6; + SocketOption::Mode mode = SrtInterpretMode(m_mode, host, adapter); if (mode == SocketOption::FAILURE) { @@ -445,16 +476,14 @@ void SrtCommon::InitParameters(string host, string path, map par) // That's kinda clumsy, but it must rely on the defaults. // Default mode is live, so check if the file mode was enforced - if (par.count("transtype") == 0 || par["transtype"] != "file") + if ((par.count("transtype") == 0 || par["transtype"] != "file") + && transmit_chunk_size > SRT_LIVE_DEF_PLSIZE) { - // If the Live chunk size was nondefault, enforce the size. - if (transmit_chunk_size != SRT_LIVE_DEF_PLSIZE) - { - if (transmit_chunk_size > SRT_LIVE_MAX_PLSIZE) - throw std::runtime_error("Chunk size in live mode exceeds 1456 bytes; this is not supported"); + size_t size_limit = (size_t)SRT_MAX_PLSIZE(fam_to_limit_size); + if (transmit_chunk_size > size_limit) + throw std::runtime_error(Sprint("Chunk size in live mode exceeds ", size_limit, " bytes; this is not supported")); - par["payloadsize"] = Sprint(transmit_chunk_size); - } + par["payloadsize"] = Sprint(transmit_chunk_size); } // Assigning group configuration from a special "groupconfig" attribute. From a8b91042845744053fa339937b6f437973d46591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Fri, 3 Mar 2023 17:52:02 +0100 Subject: [PATCH 02/29] Applied verification of the payload size fit. Added tests. Updated documentation --- docs/API/API-functions.md | 16 +++ docs/API/API-socket-options.md | 256 +++++++++++++++++++++++---------- srtcore/api.cpp | 8 +- srtcore/core.cpp | 48 +++++-- srtcore/core.h | 17 ++- srtcore/socketconfig.cpp | 4 +- srtcore/socketconfig.h | 4 + srtcore/srt.h | 1 + srtcore/stats.h | 53 ++++--- test/test_ipv6.cpp | 144 ++++++++++++++++++- 10 files changed, 417 insertions(+), 134 deletions(-) diff --git a/docs/API/API-functions.md b/docs/API/API-functions.md index 4292a99b5..d4c4de970 100644 --- a/docs/API/API-functions.md +++ b/docs/API/API-functions.md @@ -172,6 +172,7 @@ Since SRT v1.5.0. | [SRT_REJ_GROUP](#SRT_REJ_GROUP) | 1.4.2 | The group type or some group settings are incompatible for both connection parties | | [SRT_REJ_TIMEOUT](#SRT_REJ_TIMEOUT) | 1.4.2 | The connection wasn't rejected, but it timed out | | [SRT_REJ_CRYPTO](#SRT_REJ_CRYPTO) | 1.6.0-dev | The connection was rejected due to an unsupported or mismatching encryption mode | +| [SRT_REJ_SETTINGS](#SRT_REJ_SETTINGS) | 1.6.0 | The connection was rejected because settings on both parties are in collision and cannot negotiate common values | | | | |

Error Codes

@@ -3064,6 +3065,21 @@ and above is reserved for "predefined codes" (`SRT_REJC_PREDEFINED` value plus adopted HTTP codes). Values above `SRT_REJC_USERDEFINED` are freely defined by the application. +#### SRT_REJ_CRYPTO + +Settings for `SRTO_CRYPTOMODE` on both parties are not compatible with one another. +See [`SRTO_CRYPTOMODE`](API-socket-options.md#SRTO_CRYPTOMODE) for details. + +#### SRT_REJ_SETTINGS + +Settings for various transmission parameters that are supposed to be negotiated +during the handshake (in order to agree upon a common value) are under restrictions +that make finding common values for them impossible. Cases include: + +* `SRTO_PAYLOADSIZE`, which is nonzero in live mode, is set to a value that +exceeds the free space in a single packet that results from the value of the +negotiated MSS value + [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 5d32db4ca..2730dcc92 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -264,7 +264,7 @@ The following table lists SRT API socket options in alphabetical order. Option d ### Option Descriptions -#### SRTO_BINDTODEVICE +#### `SRTO_BINDTODEVICE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir |Entity| | --------------------- | ----- | -------- | -------- | ------ | -------- | ------ |-----|------| @@ -287,7 +287,7 @@ for a process that runs as root. Otherwise the function that applies the setting --- -#### SRTO_CONGESTION +#### `SRTO_CONGESTION` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -309,7 +309,7 @@ rather change the whole set of options using the [`SRTO_TRANSTYPE`](#SRTO_TRANST --- -#### SRTO_CONNTIMEO +#### `SRTO_CONNTIMEO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -323,7 +323,7 @@ will be 10 times the value set with `SRTO_CONNTIMEO`. --- -#### SRTO_CRYPTOMODE +#### `SRTO_CRYPTOMODE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | --------- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -377,7 +377,7 @@ There is no way to check the crypto mode being requested by the SRT caller at th --- -#### SRTO_DRIFTTRACER +#### `SRTO_DRIFTTRACER` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -389,7 +389,7 @@ Enables or disables time drift tracer (receiver). --- -#### SRTO_ENFORCEDENCRYPTION +#### `SRTO_ENFORCEDENCRYPTION` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -434,7 +434,7 @@ on the caller side. --- -#### SRTO_EVENT +#### `SRTO_EVENT` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -449,7 +449,7 @@ Possible values are those defined in `SRT_EPOLL_OPT` enum (a combination of --- -#### SRTO_FC +#### `SRTO_FC` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -488,7 +488,7 @@ where `latency_sec` is the receiver buffering delay ([SRTO_RCVLATENCY](#SRTO_RCV --- -#### SRTO_GROUPCONNECT +#### `SRTO_GROUPCONNECT` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -514,7 +514,7 @@ function will return the group, not this socket ID. --- -#### SRTO_GROUPMINSTABLETIMEO +#### `SRTO_GROUPMINSTABLETIMEO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -548,7 +548,7 @@ Note that the value of this option is not allowed to exceed the value of --- -#### SRTO_GROUPTYPE +#### `SRTO_GROUPTYPE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -567,7 +567,7 @@ context than inside the listener callback handler, the value is undefined. --- -#### SRTO_INPUTBW +#### `SRTO_INPUTBW` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -588,7 +588,7 @@ and keep the default 25% value for `SRTO_OHEADBW`*. --- -#### SRTO_MININPUTBW +#### `SRTO_MININPUTBW` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -603,7 +603,7 @@ See [`SRTO_INPUTBW`](#SRTO_INPUTBW). --- -#### SRTO_IPTOS +#### `SRTO_IPTOS` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -621,7 +621,7 @@ and the actual value for connected sockets. --- -#### SRTO_IPTTL +#### `SRTO_IPTTL` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -639,7 +639,7 @@ and the actual value for connected sockets. --- -#### SRTO_IPV6ONLY +#### `SRTO_IPV6ONLY` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -661,7 +661,7 @@ reliable way). Possible values are: --- -#### SRTO_ISN +#### `SRTO_ISN` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -678,7 +678,7 @@ used in any regular development.* --- -#### SRTO_KMPREANNOUNCE +#### `SRTO_KMPREANNOUNCE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ----------------- | ------ | --- | ------ | @@ -712,7 +712,7 @@ The value of `SRTO_KMPREANNOUNCE must not exceed `(SRTO_KMREFRESHRATE - 1) / 2`. --- -#### SRTO_KMREFRESHRATE +#### `SRTO_KMREFRESHRATE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ---------------- | ------ | --- | ------ | @@ -734,7 +734,7 @@ might still be in flight, or packets that have to be retransmitted. --- -#### SRTO_KMSTATE +#### `SRTO_KMSTATE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -752,7 +752,7 @@ for more details. --- -#### SRTO_LATENCY +#### `SRTO_LATENCY` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -771,7 +771,7 @@ be sender and receiver at the same time, and `SRTO_SENDER` became redundant. --- -#### SRTO_LINGER +#### `SRTO_LINGER` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -789,7 +789,7 @@ The default value in [the file transfer configuration](./API.md#transmission-typ --- -#### SRTO_LOSSMAXTTL +#### `SRTO_LOSSMAXTTL` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -810,7 +810,7 @@ By default this value is set to 0, which means that this mechanism is off. --- -#### SRTO_MAXBW +#### `SRTO_MAXBW` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -834,7 +834,7 @@ therefore the default -1 remains even in live mode. --- -#### SRTO_MESSAGEAPI +#### `SRTO_MESSAGEAPI` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -873,7 +873,7 @@ SCTP protocol. --- -#### SRTO_MINVERSION +#### `SRTO_MINVERSION` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -889,30 +889,91 @@ The default value is 0x010000 (SRT v1.0.0). --- -#### SRTO_MSS +#### `SRTO_MSS` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_MSS` | | pre-bind | `int32_t` | bytes | 1500 | 76.. | RW | GSD | -Maximum Segment Size. Used for buffer allocation and rate calculation using -packet counter assuming fully filled packets. Each party can set its own MSS -value independently. During a handshake the parties exchange MSS values, and -the lowest is used. - -*Generally on the internet MSS is 1500 by default. This is the maximum -size of a UDP packet and can be only decreased, unless you have some unusual -dedicated network settings. MSS is not to be confused with the size of the UDP -payload or SRT payload - this size is the size of the IP packet, including the -UDP and SRT headers* - -THe value of `SRTO_MSS` must not exceed `SRTO_UDP_SNDBUF` or `SRTO_UDP_RCVBUF`. +Maximum Segment Size. This value represents the maximum size of a UDP packet +sent by the system. Therefore the value of `SRTO_MSS` must not exceed the +values of `SRTO_UDP_SNDBUF` or `SRTO_UDP_RCVBUF`. It is used for buffer +allocation and rate calculation using packet counter assuming fully filled +packets. + +This value is a sum of: + +* IP header (20 bytes for IPv4 or 32 bytes for IPv6) +* UDP header (8 bytes) +* SRT header (16 bytes) +* remaining space (as the maximum payload size available for a packet) + +For the default 1500 the "remaining space" part is effectively 1456 for IPv4 +and 1444 for IPv6. + +Note that the IP version used here is not the domain of the socket, but the +in-transmission IP version. This is IPv4 for a case when the current socket's +binding address is of IPv4 domain, or if it is IPv6, but the peer's address +is then an IPv6-mapped-IPv4 address. The in-transmission IPv6 is only if the +peer's address is a true IPv6 address. Hence it is not possible to deteremine +all these limitations until the connection is established. Parts of SRT that +must allocate any resources regarding this value are using the layout as per +IPv4 because this results in a greater size of "remaining space". + +This value can be set on both connection parties independently, but after +connection this option gets an effectively negotiated value, which is the less +one from both parties. + +This value then effectively controls: + +* The maximum size of the data in a single UDP packet ("remaining space"). + +* The size of the memory space allocated for a single packet in the sender +and receiver buffers. This value is equal to "SRT header" + "remaining space" +in the IPv4 layout case (1472 bytes per packet for MSS=1500). The reason for it +is that some buffer resources are allocated prior to the connection, so this +value must fit both IPv4 and IPv6 for buffer memory allocation. + +The default value 1500 matches the standard MTU size for network devices. It +is recommended that this value be set at maximum to the value of MTU size of +the network device that you will use for connection. + +Detailed recommendations for this value differ in the file and live mode. + +In the live mode a single call to `srt_send*` function may only send data +that fit in one packet. This size is defined by the `SRTO_PAYLOADSIZE` +option (defult: 1316) and it is also the size of the data in a single UDP +packet. To save memory space, you may want then to set MSS in live mode to +a value for which the "remaining space" matches `SRTO_PAYLOADSIZE` value (for +default 1316 it will be 1360 for IPv4 and 1372 for IPv6). This is not done by +default for security reasons: this may potentially lead to inability to read an +incoming UDP packet if its size is by some reason bigger than the negotiated MSS. +This may lead to misleading situations and hard to detect errors. You should +set such a value only if the peer is trusted (that is, you can be certain that +it will never come to a situation of having received an oversized UDP packet +over the link used for the connection). See also limitations for +`SRTO_PAYLOADSIZE`. + +In the file mode `SRTO_PAYLOADSIZE` has a special value 0 that means no limit +for one single packet sending, and therefore bigger portions of data are +internally split into smaller portions, each one using the maximum available +"remaining space". The best value for this case is then equal to the current +network device's MTU size. Setting a greater value is possible (maximum for the +system API is 65535), but it may lead to packet fragmentation on the system +level. This is highly unwanted in SRT because: + +* SRT does also its own fragmentation, so it would be counter-productive +* It would use more system resources with no advantage +* SRT is unaware of it, so the statistics will be slightly falsified + +The system-level packet fragmentation cannot be however reliably turned off; +the best approach is then to avoid it by using appropriate parameters. [Return to list](#list-of-options) --- -#### SRTO_NAKREPORT +#### `SRTO_NAKREPORT` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -929,7 +990,7 @@ The default is true for Live mode, and false for File mode (see [`SRTO_TRANSTYPE --- -#### SRTO_OHEADBW +#### `SRTO_OHEADBW` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -959,7 +1020,7 @@ and break quickly at any rise in packet loss. --- -#### SRTO_PACKETFILTER +#### `SRTO_PACKETFILTER` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1003,7 +1064,7 @@ Cases when negotiation succeeds: | fec,cols:10 | fec,cols:10,rows:20 | fec,cols:10,rows:20,arq:onreq,layout:even | fec,layout:staircase | fec,cols:10 | fec,cols:10,rows:1,arq:onreq,layout:staircase -In these cases the configuration is rejected with SRT_REJ_FILTER code: +In these cases the configuration is rejected with `SRT_REJ_FILTER` code: | Peer A | Peer B | Error reason |-----------------------|---------------------|-------------------------- @@ -1025,7 +1086,7 @@ For details, see [SRT Packet Filtering & FEC](../features/packet-filtering-and-f --- -#### SRTO_PASSPHRASE +#### `SRTO_PASSPHRASE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1054,18 +1115,57 @@ encrypted connection, they have to simply set the same passphrase. --- -#### SRTO_PAYLOADSIZE +#### `SRTO_PAYLOADSIZE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PAYLOADSIZE` | 1.3.0 | pre | `int32_t` | bytes | \* | 0.. \* | W | GSD | -Sets the maximum declared size of a single call to sending function in Live -mode. When set to 0, there's no limit for a single sending call. +Sets the data limitation mode and the maximum data size for sending at once. + +The default value is 0 in the file mode and 1316 in live mode (this is one of +the options modified together with `SRTO_TRANSTYPE`). + +If the value is 0, this means a "file mode", in which the call to `srt_send*` +is not limited to a size fitting in one single packet, that is, the supplied +data will be split into multiple pieces fitting in a single UDP packet, if +necessary, as well as every packet will use the maximum space available +in a UDP packet (except the last in the stream or in the message) according to +the `SRTO_MSS` setting and others that may influence this size (such as +`SRTO_PACKETFILTER` and `SRTO_CRYPTOMODE`). + +If the value is greater than 0, this means a "live mode", and the value +defines the maximum size of: + +* the single call to a sending function (`srt_send*`) +* the payload supplied in every single data packet + +This value can be set to a greater value than the default 1316, but the maximum +possible value is limited by the following factors: + +* 1500 is the default MSS (see `SRTO_MSS`), including headers, which are: + * 20 bytes for IPv4 or 32 bytes for IPv6 + * 8 bytes for UDP + * 16 bytes for SRT + +This alone gives the limit of 1456 for IPv4 and 1444 for IPv6. This limit may +be however further decreased in the following cases: + +* 4 bytes reserved for FEC, if you use the builtin FEC packet filter (see `SRTO_PACKETFILTER`) +* 16 bytes reserved for authentication tag, if you use AES GCM (see `SRTO_CRYPTOMODE`) + +**WARNING**: The option setter will reject the setting if this value is too +great, but note that not every limitation can be checked prior to connection. +This includes: + +* MSS defined for the peer, which may override MSS set in the agent +* The in-transmission IP version - see `SRTO_MSS` for details -For Live mode: Default value is 1316, but can be increased up to 1456. Note that -with the `SRTO_PACKETFILTER` option additional header space is usually required, -which decreases the maximum possible value for `SRTO_PAYLOADSIZE`. +These values also influence the "remaining space" in the packet to be used for +payload. If during the handshake it turns out that this "remaining space" is +less than the value set for `SRTO_PAYLOADSIZE` (including when it remains with +the default value), the connection will be rejected with the `SRT_REJ_SETTINGS` +code. For File mode: Default value is 0 and it's recommended not to be changed. @@ -1073,7 +1173,7 @@ For File mode: Default value is 0 and it's recommended not to be changed. --- -#### SRTO_PBKEYLEN +#### `SRTO_PBKEYLEN` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1160,7 +1260,7 @@ undefined behavior: --- -#### SRTO_PEERIDLETIMEO +#### `SRTO_PEERIDLETIMEO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1174,7 +1274,7 @@ considered broken on timeout. --- -#### SRTO_PEERLATENCY +#### `SRTO_PEERLATENCY` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1195,7 +1295,7 @@ See also [`SRTO_LATENCY`](#SRTO_LATENCY). --- -#### SRTO_PEERVERSION +#### `SRTO_PEERVERSION` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1209,7 +1309,7 @@ See [`SRTO_VERSION`](#SRTO_VERSION) for the version format. --- -#### SRTO_RCVBUF +#### `SRTO_RCVBUF` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1229,7 +1329,7 @@ than the Flight Flag size). --- -#### SRTO_RCVDATA +#### `SRTO_RCVDATA` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1241,7 +1341,7 @@ Size of the available data in the receive buffer. --- -#### SRTO_RCVKMSTATE +#### `SRTO_RCVKMSTATE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1255,7 +1355,7 @@ Values defined in enum [`SRT_KM_STATE`](#srt_km_state). --- -#### SRTO_RCVLATENCY +#### `SRTO_RCVLATENCY` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1297,7 +1397,7 @@ See also [`SRTO_LATENCY`](#SRTO_LATENCY). --- -#### SRTO_RCVSYN +#### `SRTO_RCVSYN` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1334,7 +1434,7 @@ derived from the socket of which the group is a member). --- -#### SRTO_RCVTIMEO +#### `SRTO_RCVTIMEO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1348,7 +1448,7 @@ it will behave as if in "non-blocking mode". The -1 value means no time limit. --- -#### SRTO_RENDEZVOUS +#### `SRTO_RENDEZVOUS` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1361,7 +1461,7 @@ procedure of `srt_bind` and then `srt_connect` (or `srt_rendezvous`) to one anot --- -#### SRTO_RETRANSMITALGO +#### `SRTO_RETRANSMITALGO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | --------- | ------ | ------- | ------ | --- | ------ | @@ -1389,7 +1489,7 @@ Periodic NAK reports. See [SRTO_NAKREPORT](#SRTO_NAKREPORT). --- -#### SRTO_REUSEADDR +#### `SRTO_REUSEADDR` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1416,7 +1516,7 @@ its address.* --- -#### SRTO_SENDER +#### `SRTO_SENDER` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1436,7 +1536,7 @@ parties simultaneously. --- -#### SRTO_SNDBUF +#### `SRTO_SNDBUF` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1448,7 +1548,7 @@ Sender Buffer Size. See [`SRTO_RCVBUF`](#SRTO_RCVBUF) for more information. --- -#### SRTO_SNDDATA +#### `SRTO_SNDDATA` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1460,7 +1560,7 @@ Size of the unacknowledged data in send buffer. --- -#### SRTO_SNDDROPDELAY +#### `SRTO_SNDDROPDELAY` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1487,7 +1587,7 @@ always when requested). --- -#### SRTO_SNDKMSTATE +#### `SRTO_SNDKMSTATE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1501,7 +1601,7 @@ Values defined in enum [`SRT_KM_STATE`](#srt_km_state). --- -#### SRTO_SNDSYN +#### `SRTO_SNDSYN` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1527,7 +1627,7 @@ but will have no effect on the listener socket itself. --- -#### SRTO_SNDTIMEO +#### `SRTO_SNDTIMEO` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1541,7 +1641,7 @@ if in "non-blocking mode". The -1 value means no time limit. --- -#### SRTO_STATE +#### `SRTO_STATE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1553,7 +1653,7 @@ Returns the current socket state, same as `srt_getsockstate`. --- -#### SRTO_STREAMID +#### `SRTO_STREAMID` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1582,7 +1682,7 @@ influence anything. --- -#### SRTO_TLPKTDROP +#### `SRTO_TLPKTDROP` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1601,7 +1701,7 @@ enabled in sender if receiver supports it. --- -#### SRTO_TRANSTYPE +#### `SRTO_TRANSTYPE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1617,7 +1717,7 @@ Values defined by enum `SRT_TRANSTYPE` (see above for possible values) --- -#### SRTO_TSBPDMODE +#### `SRTO_TSBPDMODE` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1635,7 +1735,7 @@ the application. --- -#### SRTO_UDP_RCVBUF +#### `SRTO_UDP_RCVBUF` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1648,7 +1748,7 @@ based on MSS value. Receive buffer must not be greater than FC size. --- -#### SRTO_UDP_SNDBUF +#### `SRTO_UDP_SNDBUF` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1661,7 +1761,7 @@ on `SRTO_MSS` value. --- -#### SRTO_VERSION +#### `SRTO_VERSION` | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 4a22cb8ec..e2dd288b7 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -618,7 +618,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, } // bind to the same addr of listening socket - ns->core().open(peer.family()); + ns->core().open(); if (!updateListenerMux(ns, ls)) { // This is highly unlikely if not impossible, but there's @@ -928,7 +928,7 @@ int srt::CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); } - s->core().open(name.family()); + s->core().open(); updateMux(s, name); s->m_Status = SRTS_OPENED; @@ -957,7 +957,7 @@ int srt::CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) // Successfully extracted, so update the size name.len = namelen; - s->core().open(name.family()); + s->core().open(); updateMux(s, name, &udpsock); s->m_Status = SRTS_OPENED; @@ -1847,7 +1847,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i // same thing as bind() does, just with empty address so that // the binding parameters are autoselected. - s->core().open(target_addr.family()); + s->core().open(); sockaddr_any autoselect_sa(target_addr.family()); // This will create such a sockaddr_any that // will return true from empty(). diff --git a/srtcore/core.cpp b/srtcore/core.cpp index b4d6160cf..c66492375 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -308,7 +308,6 @@ void srt::CUDT::construct() srt::CUDT::CUDT(CUDTSocket* parent) : m_parent(parent) - , m_stats(&m_iMaxSRTPayloadSize) { construct(); @@ -333,7 +332,6 @@ srt::CUDT::CUDT(CUDTSocket* parent) srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor) : m_parent(parent) - , m_stats(&m_iMaxSRTPayloadSize) { construct(); @@ -478,12 +476,12 @@ void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) // checking if the socket is bound. This will also be the exact size // of the memory in use. case SRTO_SNDBUF: - *(int *)optval = m_config.iSndBufSize * (m_config.iMSS - CPacket::udpHeaderSize(AF_INET)); + *(int *)optval = m_config.iSndBufSize * m_config.bytesPerPkt(); optlen = sizeof(int); break; case SRTO_RCVBUF: - *(int *)optval = m_config.iRcvBufSize * (m_config.iMSS - CPacket::udpHeaderSize(AF_INET)); + *(int *)optval = m_config.iRcvBufSize * m_config.bytesPerPkt(); optlen = sizeof(int); break; @@ -881,9 +879,9 @@ string srt::CUDT::getstreamid(SRTSOCKET u) // XXX REFACTOR: Make common code for CUDT constructor and clearData, // possibly using CUDT::construct. // Initial sequence number, loss, acknowledgement, etc. -void srt::CUDT::clearData(int family) +void srt::CUDT::clearData() { - const size_t full_hdr_size = CPacket::udpHeaderSize(family) + CPacket::HDR_SIZE; + const size_t full_hdr_size = CPacket::udpHeaderSize(AF_INET) + CPacket::HDR_SIZE; m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; HLOGC(cnlog.Debug, log << CONID() << "clearData: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); @@ -932,11 +930,11 @@ void srt::CUDT::clearData(int family) m_tsRcvPeerStartTime = steady_clock::time_point(); } -void srt::CUDT::open(int family) +void srt::CUDT::open() { ScopedLock cg(m_ConnectionLock); - clearData(family); + clearData(); // structures for queue if (m_pSNode == NULL) @@ -4185,7 +4183,7 @@ EConnectStatus srt::CUDT::processRendezvous( // This must be done before prepareConnectionObjects(), because it sets ISN and m_iMaxSRTPayloadSize needed to create buffers. if (!applyResponseSettings(pResponse)) { - LOGC(cnlog.Error, log << CONID() << "processRendezvous: rogue peer"); + LOGC(cnlog.Error, log << CONID() << "processRendezvous: peer settings rejected"); return CONN_REJECT; } @@ -4685,6 +4683,21 @@ bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) AT // Re-configure according to the negotiated values. m_config.iMSS = m_ConnRes.m_iMSS; + + const size_t full_hdr_size = CPacket::udpHeaderSize(m_TransferIPVersion) + CPacket::HDR_SIZE; + m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; + if (m_iMaxSRTPayloadSize < int(m_config.zExpPayloadSize)) + { + LOGC(cnlog.Error, log << CONID() << "applyResponseSettings: negotiated MSS=" << m_config.iMSS + << " leaves too little payload space " << m_iMaxSRTPayloadSize << " for configured payload size " + << m_config.zExpPayloadSize); + m_RejectReason = SRT_REJ_SETTINGS; + return false; + } + HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); + m_stats.setupHeaderSize(full_hdr_size); + + m_iFlowWindowSize = m_ConnRes.m_iFlightFlagSize; const int udpsize = m_config.iMSS - CPacket::udpHeaderSize(m_TransferIPVersion); m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE; @@ -5676,6 +5689,20 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& // Uses the smaller MSS between the peers m_config.iMSS = std::min(m_config.iMSS, w_hs.m_iMSS); + const size_t full_hdr_size = CPacket::udpHeaderSize(m_TransferIPVersion) + CPacket::HDR_SIZE; + m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; + if (m_iMaxSRTPayloadSize < int(m_config.zExpPayloadSize)) + { + LOGC(cnlog.Error, log << CONID() << "acceptAndRespond: negotiated MSS=" << m_config.iMSS + << " leaves too little payload space " << m_iMaxSRTPayloadSize << " for configured payload size " + << m_config.zExpPayloadSize); + m_RejectReason = SRT_REJ_SETTINGS; + throw CUDTException(MJ_SETUP, MN_REJECTED, 0); + } + + HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); + m_stats.setupHeaderSize(full_hdr_size); + // exchange info for maximum flow window size m_iFlowWindowSize = w_hs.m_iFlightFlagSize; m_iPeerISN = w_hs.m_iISN; @@ -5706,9 +5733,6 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& m_TransferIPVersion = AF_INET; } - const size_t full_hdr_size = CPacket::udpHeaderSize(m_TransferIPVersion) + CPacket::HDR_SIZE; - m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size; - HLOGC(cnlog.Debug, log << CONID() << "acceptAndRespond: PAYLOAD SIZE: " << m_iMaxSRTPayloadSize); // Prepare all structures if (!prepareConnectionObjects(w_hs, HSD_DRAW, 0)) diff --git a/srtcore/core.h b/srtcore/core.h index 67ee0dcb7..ee79e3442 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -179,7 +179,7 @@ class CUDT private: // constructor and desctructor void construct(); - void clearData(int family); + void clearData(); CUDT(CUDTSocket* parent); CUDT(CUDTSocket* parent, const CUDT& ancestor); const CUDT& operator=(const CUDT&) {return *this;} // = delete ? @@ -341,6 +341,7 @@ class CUDT // then return the maximum payload size per packet. return m_iMaxSRTPayloadSize; } + int sndLossLength() { return m_pSndLossList->getLossLength(); } int32_t ISN() const { return m_iISN; } int32_t peerISN() const { return m_iPeerISN; } @@ -459,7 +460,7 @@ class CUDT private: /// initialize a UDT entity and bind to a local address. - void open(int family); + void open(); /// Start listening to any connection request. void setListenState(); @@ -1137,14 +1138,16 @@ class CUDT time_point tsLastSampleTime; // last performance sample time int traceReorderDistance; double traceBelatedTime; - + int64_t sndDuration; // real time for sending time_point sndDurationCounter; // timers to record the sending Duration - CoreStats(int* payloadsize_loc) - : sndr(payloadsize_loc) - , rcvr(payloadsize_loc) - {} + void setupHeaderSize(int hsize) + { + sndr.setupHeaderSize(hsize); + rcvr.setupHeaderSize(hsize); + } + } m_stats; public: diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index e72563c27..27eda173b 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -109,7 +109,7 @@ struct CSrtConfigSetter if (bs <= 0) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.iSndBufSize = bs / (co.iMSS - CPacket::udpHeaderSize(AF_INET)); + co.iSndBufSize = bs / co.bytesPerPkt(); } }; @@ -123,7 +123,7 @@ struct CSrtConfigSetter throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); // Mimimum recv buffer size is 32 packets - const int mssin_size = co.iMSS - CPacket::udpHeaderSize(AF_INET); + const int mssin_size = co.bytesPerPkt(); if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT) co.iRcvBufSize = val / mssin_size; diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 72ae9808f..bd222b327 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -328,6 +328,10 @@ struct CSrtConfig: CSrtMuxerConfig int set(SRT_SOCKOPT optName, const void* val, int size); bool payloadSizeFits(size_t val, int ip_family, std::string& w_errmsg) ATR_NOTHROW; + + // This function returns the number of bytes that are allocated + // for a single packet in the sender and receiver buffer. + int bytesPerPkt() const { return iMSS - int(CPacket::udpHeaderSize(AF_INET)); } }; template diff --git a/srtcore/srt.h b/srtcore/srt.h index 784274f86..939f7f9d0 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -564,6 +564,7 @@ enum SRT_REJECT_REASON #ifdef ENABLE_AEAD_API_PREVIEW SRT_REJ_CRYPTO, // conflicting cryptographic configurations #endif + SRT_REJ_SETTINGS, // socket settings on both sides collide and can't be negotiated SRT_REJ_E_SIZE, }; diff --git a/srtcore/stats.h b/srtcore/stats.h index 2c0276665..14b0d131e 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -101,26 +101,25 @@ class BytesPackets: public BytesPacketsCount public: typedef BytesPacketsCount count_type; + // Set IPv4-based header size value as a fallback. This will be fixed upon connection. BytesPackets() - : m_pPayloadSizeLocation(NULL) + : m_iPacketHeaderSize(CPacket::udpHeaderSize(AF_INET) + CPacket::HDR_SIZE) {} public: - void bindPayloadSize(int* sizeloc) + void setupHeaderSize(int size) { - m_pPayloadSizeLocation = sizeloc; + m_iPacketHeaderSize = size; } uint64_t bytesWithHdr() const { - SRT_ASSERT(m_pPayloadSizeLocation != NULL); - size_t header_size = CPacket::ETH_MAX_MTU_SIZE - *m_pPayloadSizeLocation; - return m_bytes + m_packets * header_size; + return m_bytes + m_packets * m_iPacketHeaderSize; } private: - int* m_pPayloadSizeLocation; + int m_iPacketHeaderSize; }; template @@ -135,10 +134,10 @@ struct Metric total += val; } - void bindPayloadSize(int* loc) + void setupHeaderSize(int loc) { - trace.bindPayloadSize(loc); - total.bindPayloadSize(loc); + trace.setupHeaderSize(loc); + total.setupHeaderSize(loc); } void reset() @@ -167,14 +166,14 @@ struct Sender Metric recvdAck; // The number of ACK packets received by the sender. Metric recvdNak; // The number of ACK packets received by the sender. - Sender(int* payloadsize_loc) + void setupHeaderSize(int hdr_size) { -#define BIND(var) var.bindPayloadSize(payloadsize_loc) - BIND(sent); - BIND(sentUnique); - BIND(sentRetrans); - BIND(dropped); -#undef BIND +#define SETHSIZE(var) var.setupHeaderSize(hdr_size) + SETHSIZE(sent); + SETHSIZE(sentUnique); + SETHSIZE(sentRetrans); + SETHSIZE(dropped); +#undef SETHSIZE } void reset() @@ -220,17 +219,17 @@ struct Receiver Metric sentAck; // The number of ACK packets sent by the receiver. Metric sentNak; // The number of NACK packets sent by the receiver. - Receiver(int* payloadsize_loc) + void setupHeaderSize(int hdr_size) { -#define BIND(var) var.bindPayloadSize(payloadsize_loc) - BIND(recvd); - BIND(recvdUnique); - BIND(recvdRetrans); - BIND(lost); - BIND(dropped); - BIND(recvdBelated); - BIND(undecrypted); -#undef BIND +#define SETHSIZE(var) var.setupHeaderSize(hdr_size) + SETHSIZE(recvd); + SETHSIZE(recvdUnique); + SETHSIZE(recvdRetrans); + SETHSIZE(lost); + SETHSIZE(dropped); + SETHSIZE(recvdBelated); + SETHSIZE(undecrypted); +#undef SETHSIZE } void reset() diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 4dd235e06..f1ffceb29 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -1,10 +1,13 @@ #include "gtest/gtest.h" #include +#include #include #include "srt.h" +#include "sync.h" #include "netinet_any.h" using srt::sockaddr_any; +using namespace srt::sync; class TestIPv6 : public ::testing::Test @@ -36,6 +39,7 @@ class TestIPv6 m_listener_sock = srt_create_socket(); ASSERT_NE(m_listener_sock, SRT_ERROR); + m_CallerStarted = false; } void TearDown() @@ -48,7 +52,29 @@ class TestIPv6 } public: + + void SetupFileMode() + { + int val = SRTT_FILE; + ASSERT_NE(srt_setsockflag(m_caller_sock, SRTO_TRANSTYPE, &val, sizeof val), -1); + ASSERT_NE(srt_setsockflag(m_listener_sock, SRTO_TRANSTYPE, &val, sizeof val), -1); + } + + int m_CallerPayloadSize = 0; + int m_AcceptedPayloadSize = 0; + atomic m_CallerStarted; + + Condition m_ReadyToClose; + Mutex m_ReadyToCloseLock; + + // "default parameter" version. Can't use default parameters because this goes + // against binding parameters. Nor overloading. void ClientThread(int family, const std::string& address) + { + return ClientThreadFlex(family, address, true); + } + + void ClientThreadFlex(int family, const std::string& address, bool shouldwork) { sockaddr_any sa (family); sa.hport(m_listen_port); @@ -56,12 +82,38 @@ class TestIPv6 std::cout << "Calling: " << address << "(" << fam[family] << ")\n"; + CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); + + m_CallerStarted = true; + const int connect_res = srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa); - EXPECT_NE(connect_res, SRT_ERROR) << "srt_connect() failed with: " << srt_getlasterror_str(); - if (connect_res == SRT_ERROR) - srt_close(m_listener_sock); - PrintAddresses(m_caller_sock, "CALLER"); + if (shouldwork) + { + // Version with expected success + EXPECT_NE(connect_res, SRT_ERROR) << "srt_connect() failed with: " << srt_getlasterror_str(); + + int size = sizeof (int); + EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_CallerPayloadSize, &size), -1); + + if (connect_res == SRT_ERROR) + { + srt_close(m_listener_sock); + } + else + { + before_closing.wait(); + } + + PrintAddresses(m_caller_sock, "CALLER"); + } + else + { + // Version with expected failure + EXPECT_EQ(connect_res, SRT_ERROR); + EXPECT_EQ(srt_getrejectreason(m_caller_sock), SRT_REJ_SETTINGS); + srt_close(m_listener_sock); + } } std::map fam = { {AF_INET, "IPv4"}, {AF_INET6, "IPv6"} }; @@ -81,6 +133,8 @@ class TestIPv6 if (accepted_sock == SRT_INVALID_SOCK) { return sockaddr_any(); } + int size = sizeof (int); + EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_AcceptedPayloadSize, &size), -1); PrintAddresses(accepted_sock, "ACCEPTED"); @@ -95,6 +149,9 @@ class TestIPv6 << "EMPTY address in srt_getsockname"; } + CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); + before_closing.notify_one(); + srt_close(accepted_sock); return sn; } @@ -194,3 +251,82 @@ TEST_F(TestIPv6, v6_calls_v4) client.join(); } +TEST_F(TestIPv6, plsize_v6) +{ + SetupFileMode(); + + sockaddr_any sa (AF_INET6); + sa.hport(m_listen_port); + + // This time bind the socket exclusively to IPv6. + ASSERT_EQ(srt_setsockflag(m_listener_sock, SRTO_IPV6ONLY, &yes, sizeof yes), 0); + ASSERT_EQ(inet_pton(AF_INET6, "::1", sa.get_addr()), 1); + + ASSERT_NE(srt_bind(m_listener_sock, sa.get(), sa.size()), SRT_ERROR); + ASSERT_NE(srt_listen(m_listener_sock, SOMAXCONN), SRT_ERROR); + + std::thread client(&TestIPv6::ClientThread, this, AF_INET6, "::1"); + + DoAccept(); + + EXPECT_EQ(m_CallerPayloadSize, 1444); // == 1500 - 32[IPv6] - 8[UDP] - 16[SRT] + EXPECT_EQ(m_AcceptedPayloadSize, 1444); + + client.join(); +} + +TEST_F(TestIPv6, plsize_v4) +{ + SetupFileMode(); + + sockaddr_any sa (AF_INET); + sa.hport(m_listen_port); + + // This time bind the socket exclusively to IPv4. + ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", sa.get_addr()), 1); + + ASSERT_NE(srt_bind(m_listener_sock, sa.get(), sa.size()), SRT_ERROR); + ASSERT_NE(srt_listen(m_listener_sock, SOMAXCONN), SRT_ERROR); + + std::thread client(&TestIPv6::ClientThread, this, AF_INET6, "0::FFFF:127.0.0.1"); + + DoAccept(); + + EXPECT_EQ(m_CallerPayloadSize, 1456); // == 1500 - 20[IPv4] - 8[UDP] - 16[SRT] + EXPECT_EQ(m_AcceptedPayloadSize, 1456); + + client.join(); +} + +TEST_F(TestIPv6, plsize_faux_v6) +{ + using namespace std::literals; + SetupFileMode(); + + sockaddr_any sa (AF_INET6); + sa.hport(m_listen_port); + + // This time bind the socket exclusively to IPv6. + ASSERT_EQ(srt_setsockflag(m_listener_sock, SRTO_IPV6ONLY, &yes, sizeof yes), 0); + ASSERT_EQ(inet_pton(AF_INET6, "::1", sa.get_addr()), 1); + + ASSERT_NE(srt_bind(m_listener_sock, sa.get(), sa.size()), SRT_ERROR); + ASSERT_NE(srt_listen(m_listener_sock, SOMAXCONN), SRT_ERROR); + + int oversize = 1450; + ASSERT_NE(srt_setsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &oversize, sizeof (int)), -1); + + std::thread client(&TestIPv6::ClientThreadFlex, this, AF_INET6, "::1", false); + + // Set on sleeping to make sure that the thread started. + // Sleeping isn't reliable so do a dampened spinlock here. + // This flag also confirms that the caller acquired the mutex and will + // unlock it for CV waiting - so we can proceed to notifying it. + do std::this_thread::sleep_for(100ms); while (!m_CallerStarted); + + // Just in case of a test failure, kick CV to avoid deadlock + CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); + before_closing.notify_one(); + + client.join(); +} From 56fdfdb5f741423ff962ee48c4b5ea572be279ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Fri, 3 Mar 2023 18:04:03 +0100 Subject: [PATCH 03/29] Withdrawn quotes for option names --- docs/API/API-socket-options.md | 120 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 2730dcc92..68e22d7c8 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -264,7 +264,7 @@ The following table lists SRT API socket options in alphabetical order. Option d ### Option Descriptions -#### `SRTO_BINDTODEVICE` +#### SRTO_BINDTODEVICE | OptName | Since | Restrict | Type | Units | Default | Range | Dir |Entity| | --------------------- | ----- | -------- | -------- | ------ | -------- | ------ |-----|------| @@ -287,7 +287,7 @@ for a process that runs as root. Otherwise the function that applies the setting --- -#### `SRTO_CONGESTION` +#### SRTO_CONGESTION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -309,7 +309,7 @@ rather change the whole set of options using the [`SRTO_TRANSTYPE`](#SRTO_TRANST --- -#### `SRTO_CONNTIMEO` +#### SRTO_CONNTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -323,7 +323,7 @@ will be 10 times the value set with `SRTO_CONNTIMEO`. --- -#### `SRTO_CRYPTOMODE` +#### SRTO_CRYPTOMODE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | --------- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -377,7 +377,7 @@ There is no way to check the crypto mode being requested by the SRT caller at th --- -#### `SRTO_DRIFTTRACER` +#### SRTO_DRIFTTRACER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -389,7 +389,7 @@ Enables or disables time drift tracer (receiver). --- -#### `SRTO_ENFORCEDENCRYPTION` +#### SRTO_ENFORCEDENCRYPTION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -434,7 +434,7 @@ on the caller side. --- -#### `SRTO_EVENT` +#### SRTO_EVENT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -449,7 +449,7 @@ Possible values are those defined in `SRT_EPOLL_OPT` enum (a combination of --- -#### `SRTO_FC` +#### SRTO_FC | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -488,7 +488,7 @@ where `latency_sec` is the receiver buffering delay ([SRTO_RCVLATENCY](#SRTO_RCV --- -#### `SRTO_GROUPCONNECT` +#### SRTO_GROUPCONNECT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | @@ -514,7 +514,7 @@ function will return the group, not this socket ID. --- -#### `SRTO_GROUPMINSTABLETIMEO` +#### SRTO_GROUPMINSTABLETIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -548,7 +548,7 @@ Note that the value of this option is not allowed to exceed the value of --- -#### `SRTO_GROUPTYPE` +#### SRTO_GROUPTYPE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -567,7 +567,7 @@ context than inside the listener callback handler, the value is undefined. --- -#### `SRTO_INPUTBW` +#### SRTO_INPUTBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -588,7 +588,7 @@ and keep the default 25% value for `SRTO_OHEADBW`*. --- -#### `SRTO_MININPUTBW` +#### SRTO_MININPUTBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -603,7 +603,7 @@ See [`SRTO_INPUTBW`](#SRTO_INPUTBW). --- -#### `SRTO_IPTOS` +#### SRTO_IPTOS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -621,7 +621,7 @@ and the actual value for connected sockets. --- -#### `SRTO_IPTTL` +#### SRTO_IPTTL | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -639,7 +639,7 @@ and the actual value for connected sockets. --- -#### `SRTO_IPV6ONLY` +#### SRTO_IPV6ONLY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -661,7 +661,7 @@ reliable way). Possible values are: --- -#### `SRTO_ISN` +#### SRTO_ISN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -678,7 +678,7 @@ used in any regular development.* --- -#### `SRTO_KMPREANNOUNCE` +#### SRTO_KMPREANNOUNCE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ----------------- | ------ | --- | ------ | @@ -712,7 +712,7 @@ The value of `SRTO_KMPREANNOUNCE must not exceed `(SRTO_KMREFRESHRATE - 1) / 2`. --- -#### `SRTO_KMREFRESHRATE` +#### SRTO_KMREFRESHRATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ---------------- | ------ | --- | ------ | @@ -734,7 +734,7 @@ might still be in flight, or packets that have to be retransmitted. --- -#### `SRTO_KMSTATE` +#### SRTO_KMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -752,7 +752,7 @@ for more details. --- -#### `SRTO_LATENCY` +#### SRTO_LATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -771,7 +771,7 @@ be sender and receiver at the same time, and `SRTO_SENDER` became redundant. --- -#### `SRTO_LINGER` +#### SRTO_LINGER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | @@ -789,7 +789,7 @@ The default value in [the file transfer configuration](./API.md#transmission-typ --- -#### `SRTO_LOSSMAXTTL` +#### SRTO_LOSSMAXTTL | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -810,7 +810,7 @@ By default this value is set to 0, which means that this mechanism is off. --- -#### `SRTO_MAXBW` +#### SRTO_MAXBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -834,7 +834,7 @@ therefore the default -1 remains even in live mode. --- -#### `SRTO_MESSAGEAPI` +#### SRTO_MESSAGEAPI | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -873,7 +873,7 @@ SCTP protocol. --- -#### `SRTO_MINVERSION` +#### SRTO_MINVERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -889,7 +889,7 @@ The default value is 0x010000 (SRT v1.0.0). --- -#### `SRTO_MSS` +#### SRTO_MSS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -973,7 +973,7 @@ the best approach is then to avoid it by using appropriate parameters. --- -#### `SRTO_NAKREPORT` +#### SRTO_NAKREPORT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -990,7 +990,7 @@ The default is true for Live mode, and false for File mode (see [`SRTO_TRANSTYPE --- -#### `SRTO_OHEADBW` +#### SRTO_OHEADBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1020,7 +1020,7 @@ and break quickly at any rise in packet loss. --- -#### `SRTO_PACKETFILTER` +#### SRTO_PACKETFILTER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1086,7 +1086,7 @@ For details, see [SRT Packet Filtering & FEC](../features/packet-filtering-and-f --- -#### `SRTO_PASSPHRASE` +#### SRTO_PASSPHRASE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1115,7 +1115,7 @@ encrypted connection, they have to simply set the same passphrase. --- -#### `SRTO_PAYLOADSIZE` +#### SRTO_PAYLOADSIZE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1173,7 +1173,7 @@ For File mode: Default value is 0 and it's recommended not to be changed. --- -#### `SRTO_PBKEYLEN` +#### SRTO_PBKEYLEN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1260,7 +1260,7 @@ undefined behavior: --- -#### `SRTO_PEERIDLETIMEO` +#### SRTO_PEERIDLETIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1274,7 +1274,7 @@ considered broken on timeout. --- -#### `SRTO_PEERLATENCY` +#### SRTO_PEERLATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1295,7 +1295,7 @@ See also [`SRTO_LATENCY`](#SRTO_LATENCY). --- -#### `SRTO_PEERVERSION` +#### SRTO_PEERVERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | @@ -1309,7 +1309,7 @@ See [`SRTO_VERSION`](#SRTO_VERSION) for the version format. --- -#### `SRTO_RCVBUF` +#### SRTO_RCVBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1329,7 +1329,7 @@ than the Flight Flag size). --- -#### `SRTO_RCVDATA` +#### SRTO_RCVDATA | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1341,7 +1341,7 @@ Size of the available data in the receive buffer. --- -#### `SRTO_RCVKMSTATE` +#### SRTO_RCVKMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1355,7 +1355,7 @@ Values defined in enum [`SRT_KM_STATE`](#srt_km_state). --- -#### `SRTO_RCVLATENCY` +#### SRTO_RCVLATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1397,7 +1397,7 @@ See also [`SRTO_LATENCY`](#SRTO_LATENCY). --- -#### `SRTO_RCVSYN` +#### SRTO_RCVSYN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1434,7 +1434,7 @@ derived from the socket of which the group is a member). --- -#### `SRTO_RCVTIMEO` +#### SRTO_RCVTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1448,7 +1448,7 @@ it will behave as if in "non-blocking mode". The -1 value means no time limit. --- -#### `SRTO_RENDEZVOUS` +#### SRTO_RENDEZVOUS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1461,7 +1461,7 @@ procedure of `srt_bind` and then `srt_connect` (or `srt_rendezvous`) to one anot --- -#### `SRTO_RETRANSMITALGO` +#### SRTO_RETRANSMITALGO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | --------- | ------ | ------- | ------ | --- | ------ | @@ -1489,7 +1489,7 @@ Periodic NAK reports. See [SRTO_NAKREPORT](#SRTO_NAKREPORT). --- -#### `SRTO_REUSEADDR` +#### SRTO_REUSEADDR | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1516,7 +1516,7 @@ its address.* --- -#### `SRTO_SENDER` +#### SRTO_SENDER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | @@ -1536,7 +1536,7 @@ parties simultaneously. --- -#### `SRTO_SNDBUF` +#### SRTO_SNDBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1548,7 +1548,7 @@ Sender Buffer Size. See [`SRTO_RCVBUF`](#SRTO_RCVBUF) for more information. --- -#### `SRTO_SNDDATA` +#### SRTO_SNDDATA | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1560,7 +1560,7 @@ Size of the unacknowledged data in send buffer. --- -#### `SRTO_SNDDROPDELAY` +#### SRTO_SNDDROPDELAY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1587,7 +1587,7 @@ always when requested). --- -#### `SRTO_SNDKMSTATE` +#### SRTO_SNDKMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1601,7 +1601,7 @@ Values defined in enum [`SRT_KM_STATE`](#srt_km_state). --- -#### `SRTO_SNDSYN` +#### SRTO_SNDSYN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1627,7 +1627,7 @@ but will have no effect on the listener socket itself. --- -#### `SRTO_SNDTIMEO` +#### SRTO_SNDTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1641,7 +1641,7 @@ if in "non-blocking mode". The -1 value means no time limit. --- -#### `SRTO_STATE` +#### SRTO_STATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1653,7 +1653,7 @@ Returns the current socket state, same as `srt_getsockstate`. --- -#### `SRTO_STREAMID` +#### SRTO_STREAMID | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1682,7 +1682,7 @@ influence anything. --- -#### `SRTO_TLPKTDROP` +#### SRTO_TLPKTDROP | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1701,7 +1701,7 @@ enabled in sender if receiver supports it. --- -#### `SRTO_TRANSTYPE` +#### SRTO_TRANSTYPE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1717,7 +1717,7 @@ Values defined by enum `SRT_TRANSTYPE` (see above for possible values) --- -#### `SRTO_TSBPDMODE` +#### SRTO_TSBPDMODE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1735,7 +1735,7 @@ the application. --- -#### `SRTO_UDP_RCVBUF` +#### SRTO_UDP_RCVBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1748,7 +1748,7 @@ based on MSS value. Receive buffer must not be greater than FC size. --- -#### `SRTO_UDP_SNDBUF` +#### SRTO_UDP_SNDBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | @@ -1761,7 +1761,7 @@ on `SRTO_MSS` value. --- -#### `SRTO_VERSION` +#### SRTO_VERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | From d7f32d067bb0d1e15a805a72d3060cf161956729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Fri, 3 Mar 2023 18:07:04 +0100 Subject: [PATCH 04/29] Fixed links in the socket option table --- docs/API/API-socket-options.md | 120 ++++++++++++++++----------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 68e22d7c8..6a23aa349 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -201,66 +201,66 @@ The following table lists SRT API socket options in alphabetical order. Option d | Option Name | Since | Restrict | Type | Units | Default | Range | Dir |Entity | | :------------------------------------------------------ | :---: | :------: | :-------: | :-----: | :---------------: | :------: |:---:|:-----:| -| [`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.6.0-dev | 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 | -| [`SRTO_FC`](#SRTO_FC) | | pre | `int32_t` | pkts | 25600 | 32.. | RW | GSD | -| [`SRTO_GROUPCONNECT`](#SRTO_GROUPCONNECT) | 1.5.0 | pre | `int32_t` | | 0 | 0...1 | W | S | -| [`SRTO_GROUPMINSTABLETIMEO`](#SRTO_GROUPMINSTABLETIMEO) | 1.5.0 | pre | `int32_t` | ms | 60 | 60-... | W | GDI+ | -| [`SRTO_GROUPTYPE`](#SRTO_GROUPTYPE) | 1.5.0 | | `int32_t` | enum | | | R | S | -| [`SRTO_INPUTBW`](#SRTO_INPUTBW) | 1.0.5 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | -| [`SRTO_IPTOS`](#SRTO_IPTOS) | 1.0.5 | pre-bind | `int32_t` | | (system) | 0..255 | RW | GSD | -| [`SRTO_IPTTL`](#SRTO_IPTTL) | 1.0.5 | pre-bind | `int32_t` | hops | (system) | 1..255 | RW | GSD | -| [`SRTO_IPV6ONLY`](#SRTO_IPV6ONLY) | 1.4.0 | pre-bind | `int32_t` | | (system) | -1..1 | RW | GSD | -| [`SRTO_ISN`](#SRTO_ISN) | 1.3.0 | | `int32_t` | | | | R | S | -| [`SRTO_KMPREANNOUNCE`](#SRTO_KMPREANNOUNCE) | 1.3.2 | pre | `int32_t` | pkts | 0: 212 | 0.. \* | RW | GSD | -| [`SRTO_KMREFRESHRATE`](#SRTO_KMREFRESHRATE) | 1.3.2 | pre | `int32_t` | pkts | 0: 224 | 0.. | RW | GSD | -| [`SRTO_KMSTATE`](#SRTO_KMSTATE) | 1.0.2 | | `int32_t` | enum | | | R | S | -| [`SRTO_LATENCY`](#SRTO_LATENCY) | 1.0.2 | pre | `int32_t` | ms | 120 \* | 0.. | RW | GSD | -| [`SRTO_LINGER`](#SRTO_LINGER) | | post | `linger` | s | off \* | 0.. | RW | GSD | -| [`SRTO_LOSSMAXTTL`](#SRTO_LOSSMAXTTL) | 1.2.0 | post | `int32_t` | packets | 0 | 0.. | RW | GSD+ | -| [`SRTO_MAXBW`](#SRTO_MAXBW) | | post | `int64_t` | B/s | -1 | -1.. | RW | GSD | -| [`SRTO_MESSAGEAPI`](#SRTO_MESSAGEAPI) | 1.3.0 | pre | `bool` | | true | | W | GSD | -| [`SRTO_MININPUTBW`](#SRTO_MININPUTBW) | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | -| [`SRTO_MINVERSION`](#SRTO_MINVERSION) | 1.3.0 | pre | `int32_t` | version | 0x010000 | \* | RW | GSD | -| [`SRTO_MSS`](#SRTO_MSS) | | pre-bind | `int32_t` | bytes | 1500 | 76.. | RW | GSD | -| [`SRTO_NAKREPORT`](#SRTO_NAKREPORT) | 1.1.0 | pre | `bool` | | \* | | RW | GSD+ | -| [`SRTO_OHEADBW`](#SRTO_OHEADBW) | 1.0.5 | post | `int32_t` | % | 25 | 5..100 | RW | GSD | -| [`SRTO_PACKETFILTER`](#SRTO_PACKETFILTER) | 1.4.0 | pre | `string` | | "" | [512] | RW | GSD | -| [`SRTO_PASSPHRASE`](#SRTO_PASSPHRASE) | 0.0.0 | pre | `string` | | "" | [10..80] | W | GSD | -| [`SRTO_PAYLOADSIZE`](#SRTO_PAYLOADSIZE) | 1.3.0 | pre | `int32_t` | bytes | \* | 0.. \* | W | GSD | -| [`SRTO_PBKEYLEN`](#SRTO_PBKEYLEN) | 0.0.0 | pre | `int32_t` | bytes | 0 | \* | RW | GSD | -| [`SRTO_PEERIDLETIMEO`](#SRTO_PEERIDLETIMEO) | 1.3.3 | pre | `int32_t` | ms | 5000 | 0.. | RW | GSD+ | -| [`SRTO_PEERLATENCY`](#SRTO_PEERLATENCY) | 1.3.0 | pre | `int32_t` | ms | 0 | 0.. | RW | GSD | -| [`SRTO_PEERVERSION`](#SRTO_PEERVERSION) | 1.1.0 | | `int32_t` | * | | | R | GS | -| [`SRTO_RCVBUF`](#SRTO_RCVBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | -| [`SRTO_RCVDATA`](#SRTO_RCVDATA) | | | `int32_t` | pkts | | | R | S | -| [`SRTO_RCVKMSTATE`](#SRTO_RCVKMSTATE) | 1.2.0 | | `int32_t` | enum | | | R | S | -| [`SRTO_RCVLATENCY`](#SRTO_RCVLATENCY) | 1.3.0 | pre | `int32_t` | msec | \* | 0.. | RW | GSD | -| [`SRTO_RCVSYN`](#SRTO_RCVSYN) | | post | `bool` | | true | | RW | GSI | -| [`SRTO_RCVTIMEO`](#SRTO_RCVTIMEO) | | post | `int32_t` | ms | -1 | -1, 0.. | RW | GSI | -| [`SRTO_RENDEZVOUS`](#SRTO_RENDEZVOUS) | | pre | `bool` | | false | | RW | S | -| [`SRTO_RETRANSMITALGO`](#SRTO_RETRANSMITALGO) | 1.4.2 | pre | `int32_t` | | 1 | [0, 1] | RW | GSD | -| [`SRTO_REUSEADDR`](#SRTO_REUSEADDR) | | pre-bind | `bool` | | true | | RW | GSD | -| [`SRTO_SENDER`](#SRTO_SENDER) | 1.0.4 | pre | `bool` | | false | | W | S | -| [`SRTO_SNDBUF`](#SRTO_SNDBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | -| [`SRTO_SNDDATA`](#SRTO_SNDDATA) | | | `int32_t` | pkts | | | R | S | -| [`SRTO_SNDDROPDELAY`](#SRTO_SNDDROPDELAY) | 1.3.2 | post | `int32_t` | ms | \* | -1.. | W | GSD+ | -| [`SRTO_SNDKMSTATE`](#SRTO_SNDKMSTATE) | 1.2.0 | | `int32_t` | enum | | | R | S | -| [`SRTO_SNDSYN`](#SRTO_SNDSYN) | | post | `bool` | | true | | RW | GSI | -| [`SRTO_SNDTIMEO`](#SRTO_SNDTIMEO) | | post | `int32_t` | ms | -1 | -1.. | RW | GSI | -| [`SRTO_STATE`](#SRTO_STATE) | | | `int32_t` | enum | | | R | S | -| [`SRTO_STREAMID`](#SRTO_STREAMID) | 1.3.0 | pre | `string` | | "" | [512] | RW | GSD | -| [`SRTO_TLPKTDROP`](#SRTO_TLPKTDROP) | 1.0.6 | pre | `bool` | | \* | | RW | GSD | -| [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) | 1.3.0 | pre | `int32_t` | enum |`SRTT_LIVE` | \* | W | S | -| [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE) | 0.0.0 | pre | `bool` | | \* | | W | S | -| [`SRTO_UDP_RCVBUF`](#SRTO_UDP_RCVBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | -| [`SRTO_UDP_SNDBUF`](#SRTO_UDP_SNDBUF) | | pre-bind | `int32_t` | bytes | 65536 | \* | RW | GSD+ | -| [`SRTO_VERSION`](#SRTO_VERSION) | 1.1.0 | | `int32_t` | | | | R | S | +| [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.6.0-dev | 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 | +| [SRTO_FC](#SRTO_FC) | | pre | `int32_t` | pkts | 25600 | 32.. | RW | GSD | +| [SRTO_GROUPCONNECT](#SRTO_GROUPCONNECT) | 1.5.0 | pre | `int32_t` | | 0 | 0...1 | W | S | +| [SRTO_GROUPMINSTABLETIMEO](#SRTO_GROUPMINSTABLETIMEO) | 1.5.0 | pre | `int32_t` | ms | 60 | 60-... | W | GDI+ | +| [SRTO_GROUPTYPE](#SRTO_GROUPTYPE) | 1.5.0 | | `int32_t` | enum | | | R | S | +| [SRTO_INPUTBW](#SRTO_INPUTBW) | 1.0.5 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | +| [SRTO_IPTOS](#SRTO_IPTOS) | 1.0.5 | pre-bind | `int32_t` | | (system) | 0..255 | RW | GSD | +| [SRTO_IPTTL](#SRTO_IPTTL) | 1.0.5 | pre-bind | `int32_t` | hops | (system) | 1..255 | RW | GSD | +| [SRTO_IPV6ONLY](#SRTO_IPV6ONLY) | 1.4.0 | pre-bind | `int32_t` | | (system) | -1..1 | RW | GSD | +| [SRTO_ISN](#SRTO_ISN) | 1.3.0 | | `int32_t` | | | | R | S | +| [SRTO_KMPREANNOUNCE](#SRTO_KMPREANNOUNCE) | 1.3.2 | pre | `int32_t` | pkts | 0: 212 | 0.. \* | RW | GSD | +| [SRTO_KMREFRESHRATE](#SRTO_KMREFRESHRATE) | 1.3.2 | pre | `int32_t` | pkts | 0: 224 | 0.. | RW | GSD | +| [SRTO_KMSTATE](#SRTO_KMSTATE) | 1.0.2 | | `int32_t` | enum | | | R | S | +| [SRTO_LATENCY](#SRTO_LATENCY) | 1.0.2 | pre | `int32_t` | ms | 120 \* | 0.. | RW | GSD | +| [SRTO_LINGER](#SRTO_LINGER) | | post | `linger` | s | off \* | 0.. | RW | GSD | +| [SRTO_LOSSMAXTTL](#SRTO_LOSSMAXTTL) | 1.2.0 | post | `int32_t` | packets | 0 | 0.. | RW | GSD+ | +| [SRTO_MAXBW](#SRTO_MAXBW) | | post | `int64_t` | B/s | -1 | -1.. | RW | GSD | +| [SRTO_MESSAGEAPI](#SRTO_MESSAGEAPI) | 1.3.0 | pre | `bool` | | true | | W | GSD | +| [SRTO_MININPUTBW](#SRTO_MININPUTBW) | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | +| [SRTO_MINVERSION](#SRTO_MINVERSION) | 1.3.0 | pre | `int32_t` | version | 0x010000 | \* | RW | GSD | +| [SRTO_MSS](#SRTO_MSS) | | pre-bind | `int32_t` | bytes | 1500 | 76.. | RW | GSD | +| [SRTO_NAKREPORT](#SRTO_NAKREPORT) | 1.1.0 | pre | `bool` | | \* | | RW | GSD+ | +| [SRTO_OHEADBW](#SRTO_OHEADBW) | 1.0.5 | post | `int32_t` | % | 25 | 5..100 | RW | GSD | +| [SRTO_PACKETFILTER](#SRTO_PACKETFILTER) | 1.4.0 | pre | `string` | | "" | [512] | RW | GSD | +| [SRTO_PASSPHRASE](#SRTO_PASSPHRASE) | 0.0.0 | pre | `string` | | "" | [10..80] | W | GSD | +| [SRTO_PAYLOADSIZE](#SRTO_PAYLOADSIZE) | 1.3.0 | pre | `int32_t` | bytes | \* | 0.. \* | W | GSD | +| [SRTO_PBKEYLEN](#SRTO_PBKEYLEN) | 0.0.0 | pre | `int32_t` | bytes | 0 | \* | RW | GSD | +| [SRTO_PEERIDLETIMEO](#SRTO_PEERIDLETIMEO) | 1.3.3 | pre | `int32_t` | ms | 5000 | 0.. | RW | GSD+ | +| [SRTO_PEERLATENCY](#SRTO_PEERLATENCY) | 1.3.0 | pre | `int32_t` | ms | 0 | 0.. | RW | GSD | +| [SRTO_PEERVERSION](#SRTO_PEERVERSION) | 1.1.0 | | `int32_t` | * | | | R | GS | +| [SRTO_RCVBUF](#SRTO_RCVBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | +| [SRTO_RCVDATA](#SRTO_RCVDATA) | | | `int32_t` | pkts | | | R | S | +| [SRTO_RCVKMSTATE](#SRTO_RCVKMSTATE) | 1.2.0 | | `int32_t` | enum | | | R | S | +| [SRTO_RCVLATENCY](#SRTO_RCVLATENCY) | 1.3.0 | pre | `int32_t` | msec | \* | 0.. | RW | GSD | +| [SRTO_RCVSYN](#SRTO_RCVSYN) | | post | `bool` | | true | | RW | GSI | +| [SRTO_RCVTIMEO](#SRTO_RCVTIMEO) | | post | `int32_t` | ms | -1 | -1, 0.. | RW | GSI | +| [SRTO_RENDEZVOUS](#SRTO_RENDEZVOUS) | | pre | `bool` | | false | | RW | S | +| [SRTO_RETRANSMITALGO](#SRTO_RETRANSMITALGO) | 1.4.2 | pre | `int32_t` | | 1 | [0, 1] | RW | GSD | +| [SRTO_REUSEADDR](#SRTO_REUSEADDR) | | pre-bind | `bool` | | true | | RW | GSD | +| [SRTO_SENDER](#SRTO_SENDER) | 1.0.4 | pre | `bool` | | false | | W | S | +| [SRTO_SNDBUF](#SRTO_SNDBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | +| [SRTO_SNDDATA](#SRTO_SNDDATA) | | | `int32_t` | pkts | | | R | S | +| [SRTO_SNDDROPDELAY](#SRTO_SNDDROPDELAY) | 1.3.2 | post | `int32_t` | ms | \* | -1.. | W | GSD+ | +| [SRTO_SNDKMSTATE](#SRTO_SNDKMSTATE) | 1.2.0 | | `int32_t` | enum | | | R | S | +| [SRTO_SNDSYN](#SRTO_SNDSYN) | | post | `bool` | | true | | RW | GSI | +| [SRTO_SNDTIMEO](#SRTO_SNDTIMEO) | | post | `int32_t` | ms | -1 | -1.. | RW | GSI | +| [SRTO_STATE](#SRTO_STATE) | | | `int32_t` | enum | | | R | S | +| [SRTO_STREAMID](#SRTO_STREAMID) | 1.3.0 | pre | `string` | | "" | [512] | RW | GSD | +| [SRTO_TLPKTDROP](#SRTO_TLPKTDROP) | 1.0.6 | pre | `bool` | | \* | | RW | GSD | +| [SRTO_TRANSTYPE](#SRTO_TRANSTYPE) | 1.3.0 | pre | `int32_t` | enum |`SRTT_LIVE` | \* | W | S | +| [SRTO_TSBPDMODE](#SRTO_TSBPDMODE) | 0.0.0 | pre | `bool` | | \* | | W | S | +| [SRTO_UDP_RCVBUF](#SRTO_UDP_RCVBUF) | | pre-bind | `int32_t` | bytes | 8192 payloads | \* | RW | GSD+ | +| [SRTO_UDP_SNDBUF](#SRTO_UDP_SNDBUF) | | pre-bind | `int32_t` | bytes | 65536 | \* | RW | GSD+ | +| [SRTO_VERSION](#SRTO_VERSION) | 1.1.0 | | `int32_t` | | | | R | S | ### Option Descriptions From 70de76348d31adb8bbe572eda1c2d7d24a35eea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 14:43:01 +0100 Subject: [PATCH 05/29] Fixed minimum MSS to 116. Fixed some other bux --- docs/API/API-socket-options.md | 4 ++-- srtcore/socketconfig.cpp | 8 +++++++- srtcore/stats.h | 8 ++++---- test/test_file_transmission.cpp | 6 ------ test/test_socket_options.cpp | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 6a23aa349..ef83cf220 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -227,7 +227,7 @@ The following table lists SRT API socket options in alphabetical order. Option d | [SRTO_MESSAGEAPI](#SRTO_MESSAGEAPI) | 1.3.0 | pre | `bool` | | true | | W | GSD | | [SRTO_MININPUTBW](#SRTO_MININPUTBW) | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | | [SRTO_MINVERSION](#SRTO_MINVERSION) | 1.3.0 | pre | `int32_t` | version | 0x010000 | \* | RW | GSD | -| [SRTO_MSS](#SRTO_MSS) | | pre-bind | `int32_t` | bytes | 1500 | 76.. | RW | GSD | +| [SRTO_MSS](#SRTO_MSS) | | pre-bind | `int32_t` | bytes | 1500 | 116.. | RW | GSD | | [SRTO_NAKREPORT](#SRTO_NAKREPORT) | 1.1.0 | pre | `bool` | | \* | | RW | GSD+ | | [SRTO_OHEADBW](#SRTO_OHEADBW) | 1.0.5 | post | `int32_t` | % | 25 | 5..100 | RW | GSD | | [SRTO_PACKETFILTER](#SRTO_PACKETFILTER) | 1.4.0 | pre | `string` | | "" | [512] | RW | GSD | @@ -893,7 +893,7 @@ The default value is 0x010000 (SRT v1.0.0). | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | -| `SRTO_MSS` | | pre-bind | `int32_t` | bytes | 1500 | 76.. | RW | GSD | +| `SRTO_MSS` | | pre-bind | `int32_t` | bytes | 1500 | 116.. | RW | GSD | Maximum Segment Size. This value represents the maximum size of a UDP packet sent by the system. Therefore the value of `SRTO_MSS` must not exceed the diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 27eda173b..8ea2e19bb 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -69,9 +69,15 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { + using namespace srt_logging; const int ival = cast_optval(optval, optlen); - if (ival < int(CPacket::udpHeaderSize(AF_INET6) + CHandShake::m_iContentSize)) + const int handshake_size = CHandShake::m_iContentSize + (sizeof(uint32_t) * SRT_HS_E_SIZE); + const int minval = int(CPacket::udpHeaderSize(AF_INET6) + CPacket::HDR_SIZE + handshake_size); + if (ival < minval) + { + LOGC(kmlog.Error, log << "SRTO_MSS: minimum value allowed is " << minval << " = [IPv6][UDP][SRT] headers + minimum SRT handshake"); throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } co.iMSS = ival; diff --git a/srtcore/stats.h b/srtcore/stats.h index 14b0d131e..55d8d00d9 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -103,23 +103,23 @@ class BytesPackets: public BytesPacketsCount // Set IPv4-based header size value as a fallback. This will be fixed upon connection. BytesPackets() - : m_iPacketHeaderSize(CPacket::udpHeaderSize(AF_INET) + CPacket::HDR_SIZE) + : m_zPacketHeaderSize(CPacket::udpHeaderSize(AF_INET) + CPacket::HDR_SIZE) {} public: void setupHeaderSize(int size) { - m_iPacketHeaderSize = size; + m_zPacketHeaderSize = uint64_t(size); } uint64_t bytesWithHdr() const { - return m_bytes + m_packets * m_iPacketHeaderSize; + return m_bytes + m_packets * m_zPacketHeaderSize; } private: - int m_iPacketHeaderSize; + uint64_t m_zPacketHeaderSize; }; template diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 48d790471..50db5647a 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -226,8 +226,6 @@ TEST(FileTransmission, Setup46) int ipv4_and_ipv6 = 0; ASSERT_NE(srt_setsockflag(sock_clr, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); - // srt_setloglevel(LOG_DEBUG); - ASSERT_NE(srt_bind(sock_clr, sa.get(), sa.size()), -1); int connect_port = 5555; @@ -238,10 +236,6 @@ TEST(FileTransmission, Setup46) sa_lsn.sin_addr.s_addr = INADDR_ANY; sa_lsn.sin_port = htons(connect_port); - - srt_setloglevel(LOG_DEBUG); - - // Find unused a port not used by any other service. // Otherwise srt_connect may actually connect. int bind_res = -1; diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 9b6385344..f010d3aeb 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -193,7 +193,7 @@ const OptionTestEntry g_test_matrix_options[] = { SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, //SRTO_MININPUTBW { 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_MSS, "SRTO_MSS", RestrictionType::PREBIND, sizeof(int), 116, 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_PACKETFILTER From 2eb1159ae2116e82855951e7984df87db460d969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 15:21:41 +0100 Subject: [PATCH 06/29] Replaced rand_r with std c++ random --- test/test_file_transmission.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 50db5647a..de227cce3 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -268,10 +268,14 @@ TEST(FileTransmission, Setup46) const size_t SIZE = 1454; // Max payload for IPv4 minus 2 - still more than 1444 for IPv6 char buffer[SIZE]; - unsigned int randseed = std::time(NULL); + std::random_device rd; + std::mt19937 mtrd(rd()); + std::uniform_int_distribution dis(0, UINT8_MAX); for (size_t i = 0; i < SIZE; ++i) - buffer[i] = rand_r(&randseed); + { + buffer[i] = dis(mtrd); + } EXPECT_EQ(srt_send(sock_acp, buffer, SIZE), SIZE) << srt_getlasterror_str(); From 9f48d3ca05cde662e5ebf0e0c067f14567f19ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 15:32:39 +0100 Subject: [PATCH 07/29] Fixed usage of C++14 literals in the test (build failures) --- test/test_ipv6.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index f1ffceb29..a889851e5 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -300,7 +300,7 @@ TEST_F(TestIPv6, plsize_v4) TEST_F(TestIPv6, plsize_faux_v6) { - using namespace std::literals; + using namespace std::chrono; SetupFileMode(); sockaddr_any sa (AF_INET6); @@ -322,7 +322,7 @@ TEST_F(TestIPv6, plsize_faux_v6) // Sleeping isn't reliable so do a dampened spinlock here. // This flag also confirms that the caller acquired the mutex and will // unlock it for CV waiting - so we can proceed to notifying it. - do std::this_thread::sleep_for(100ms); while (!m_CallerStarted); + do std::this_thread::sleep_for(milliseconds(100)); while (!m_CallerStarted); // Just in case of a test failure, kick CV to avoid deadlock CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); From edbb608a98400a10a456ebd00f160c34ee4b8940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 15:46:18 +0100 Subject: [PATCH 08/29] [MAINT] Upgraded CI: ubuntu to version 20.04 --- .github/workflows/android.yaml | 2 +- .github/workflows/cxx11-ubuntu.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml index 713c3f331..0af85fda3 100644 --- a/.github/workflows/android.yaml +++ b/.github/workflows/android.yaml @@ -9,7 +9,7 @@ on: jobs: build: name: NDK-R23 - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - name: Setup Android NDK R23 diff --git a/.github/workflows/cxx11-ubuntu.yaml b/.github/workflows/cxx11-ubuntu.yaml index 751b3fda1..500ff1beb 100644 --- a/.github/workflows/cxx11-ubuntu.yaml +++ b/.github/workflows/cxx11-ubuntu.yaml @@ -9,7 +9,7 @@ on: jobs: build: name: ubuntu - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 From 26a7be6e45b452e0f238d9b195c054a6bfc76302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 16:18:07 +0100 Subject: [PATCH 09/29] Fixed test logics (printing after closing) --- test/test_ipv6.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index a889851e5..e1c5844c2 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -96,6 +96,8 @@ class TestIPv6 int size = sizeof (int); EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_CallerPayloadSize, &size), -1); + PrintAddresses(m_caller_sock, "CALLER"); + if (connect_res == SRT_ERROR) { srt_close(m_listener_sock); @@ -104,8 +106,6 @@ class TestIPv6 { before_closing.wait(); } - - PrintAddresses(m_caller_sock, "CALLER"); } else { From 3d387a2930784fa3fe95f46bf536cfd80c3a7925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 16:49:58 +0100 Subject: [PATCH 10/29] Attempted fix for a deadlock in test, added some tracking --- test/test_ipv6.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index e1c5844c2..6498b6551 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -80,7 +80,7 @@ class TestIPv6 sa.hport(m_listen_port); EXPECT_EQ(inet_pton(family, address.c_str(), sa.get_addr()), 1); - std::cout << "Calling: " << address << "(" << fam[family] << ")\n"; + std::cout << "Calling: " << address << "(" << fam[family] << ") [LOCK]\n"; CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); @@ -100,10 +100,13 @@ class TestIPv6 if (connect_res == SRT_ERROR) { + std::cout << "Connect failed - [UNLOCK]\n"; + before_closing.locker().unlock(); // We don't need this lock here and it may deadlock srt_close(m_listener_sock); } else { + std::cout << "Connect succeeded, [UNLOCK-WAIT-CV]\n"; before_closing.wait(); } } @@ -149,6 +152,7 @@ class TestIPv6 << "EMPTY address in srt_getsockname"; } + std::cout << "DoAccept: [LOCK-SIGNAL]\n"; CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); before_closing.notify_one(); From 3eef5922a61cd50b8888f22f74bfeb3356008993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 17:16:50 +0100 Subject: [PATCH 11/29] Added expect and tracking to close socket in ReuseAddr test (Travis problem) --- test/test_reuseaddr.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test_reuseaddr.cpp b/test/test_reuseaddr.cpp index 60532eb80..3fb2168cd 100644 --- a/test/test_reuseaddr.cpp +++ b/test/test_reuseaddr.cpp @@ -404,14 +404,15 @@ void testAccept(SRTSOCKET bindsock, std::string ip, int port, bool expect_succes char pattern[4] = {1, 2, 3, 4}; - ASSERT_EQ(srt_recvmsg(accepted_sock, buffer, sizeof buffer), + EXPECT_EQ(srt_recvmsg(accepted_sock, buffer, sizeof buffer), 1316); EXPECT_EQ(memcmp(pattern, buffer, sizeof pattern), 0); std::cout << "[T/S] closing sockets: ACP:@" << accepted_sock << " LSN:@" << bindsock << " CLR:@" << g_client_sock << " ...\n"; - ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); - ASSERT_NE(srt_close(g_client_sock), SRT_ERROR); // cannot close g_client_sock after srt_sendmsg because of issue in api.c:2346 + EXPECT_NE(srt_close(accepted_sock), SRT_ERROR) << "ERROR: " << srt_getlasterror_str(); + // cannot close g_client_sock after srt_sendmsg because of issue in api.c:2346 + EXPECT_NE(srt_close(g_client_sock), SRT_ERROR) << "ERROR: " << srt_getlasterror_str(); std::cout << "[T/S] joining client async...\n"; launched.get(); From e2ab5f61b5a6c1159d4b2c85920dee5815e2a36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 6 Mar 2023 18:16:47 +0100 Subject: [PATCH 12/29] Used relaxed signaling for the sake of Travis --- test/test_ipv6.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 6498b6551..472876ba8 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -153,8 +153,8 @@ class TestIPv6 } std::cout << "DoAccept: [LOCK-SIGNAL]\n"; - CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); - before_closing.notify_one(); + // XXX Deadlock here on Travis by unknown reason, hence do relaxed signaling. + CSync::notify_all_relaxed(m_ReadyToClose); srt_close(accepted_sock); return sn; From d081e507aa732e1b4f8221e99db6012ff161c740 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 7 Mar 2023 12:23:02 +0100 Subject: [PATCH 13/29] Lock debug fix for tests --- test/test_ipv6.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 472876ba8..959ace41b 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -80,10 +80,12 @@ class TestIPv6 sa.hport(m_listen_port); EXPECT_EQ(inet_pton(family, address.c_str(), sa.get_addr()), 1); - std::cout << "Calling: " << address << "(" << fam[family] << ") [LOCK]\n"; + std::cout << "Calling: " << address << "(" << fam[family] << ") [LOCK...]\n"; CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); + std::cout << "[LOCKED] Connecting\n"; + m_CallerStarted = true; const int connect_res = srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa); @@ -106,8 +108,9 @@ class TestIPv6 } else { - std::cout << "Connect succeeded, [UNLOCK-WAIT-CV]\n"; + std::cout << "Connect succeeded, [UNLOCK-WAIT-CV...]\n"; before_closing.wait(); + std::cout << "Connect: [SIGNALED-LOCK]\n"; } } else @@ -117,6 +120,7 @@ class TestIPv6 EXPECT_EQ(srt_getrejectreason(m_caller_sock), SRT_REJ_SETTINGS); srt_close(m_listener_sock); } + std::cout << "Connect: [UNLOCKING...]\n"; } std::map fam = { {AF_INET, "IPv4"}, {AF_INET6, "IPv6"} }; @@ -124,7 +128,10 @@ class TestIPv6 void ShowAddress(std::string src, const sockaddr_any& w) { EXPECT_NE(fam.count(w.family()), 0U) << "INVALID FAMILY"; - std::cout << src << ": " << w.str() << " (" << fam[w.family()] << ")" << std::endl; + // Printing may happen from different threads, avoid intelining. + std::ostringstream sout; + sout << src << ": " << w.str() << " (" << fam[w.family()] << ")" << std::endl; + std::cout << sout.str(); } sockaddr_any DoAccept() @@ -153,8 +160,8 @@ class TestIPv6 } std::cout << "DoAccept: [LOCK-SIGNAL]\n"; - // XXX Deadlock here on Travis by unknown reason, hence do relaxed signaling. - CSync::notify_all_relaxed(m_ReadyToClose); + CSync::lock_notify_all(m_ReadyToClose, m_ReadyToCloseLock); + std::cout << "DoAccept: [UNLOCKED]\n"; srt_close(accepted_sock); return sn; @@ -329,8 +336,9 @@ TEST_F(TestIPv6, plsize_faux_v6) do std::this_thread::sleep_for(milliseconds(100)); while (!m_CallerStarted); // Just in case of a test failure, kick CV to avoid deadlock - CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); - before_closing.notify_one(); + std::cout << "TEST: [LOCK-SIGNAL]\n"; + CSync::lock_notify_all(m_ReadyToClose, m_ReadyToCloseLock); + std::cout << "TEST: [UNLOCKED]\n"; client.join(); } From ba5f9620118a5754b71a92a6e4ae29661cd7c203 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 7 Mar 2023 12:53:03 +0100 Subject: [PATCH 14/29] Added timeout for lock-CV to avoid Travis problem --- test/test_ipv6.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 959ace41b..531f11526 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -109,8 +109,8 @@ class TestIPv6 else { std::cout << "Connect succeeded, [UNLOCK-WAIT-CV...]\n"; - before_closing.wait(); - std::cout << "Connect: [SIGNALED-LOCK]\n"; + bool signaled = before_closing.wait_for(seconds_from(10)); + std::cout << "Connect: [" << (signaled ? "SIGNALED" : "EXPIRED") << "-LOCK]\n"; } } else @@ -138,6 +138,8 @@ class TestIPv6 { sockaddr_any sc1; + using namespace std::chrono; + SRTSOCKET accepted_sock = srt_accept(m_listener_sock, sc1.get(), &sc1.len); EXPECT_NE(accepted_sock, SRT_INVALID_SOCK) << "accept() failed with: " << srt_getlasterror_str(); if (accepted_sock == SRT_INVALID_SOCK) { @@ -160,8 +162,23 @@ class TestIPv6 } std::cout << "DoAccept: [LOCK-SIGNAL]\n"; - CSync::lock_notify_all(m_ReadyToClose, m_ReadyToCloseLock); - std::cout << "DoAccept: [UNLOCKED]\n"; + + // Travis makes problems here by unknown reason. Try waiting up to 10s + // until it's possible, otherwise simply give up. The intention is to + // prevent from closing too soon before the caller thread has a chance + // to perform required verifications. After 10s we can consider it enough time. + + int nms = 10; + while (!m_ReadyToCloseLock.try_lock()) + { + this_thread::sleep_for(milliseconds_from(100)); + if (--nms == 0) + break; + } + + CSync::notify_all_relaxed(m_ReadyToClose); + m_ReadyToCloseLock.unlock(); + std::cout << "DoAccept: [UNLOCKED] " << nms << "\n"; srt_close(accepted_sock); return sn; From 320a79b8087442478bb268ad58565e72e14c6cd0 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 7 Mar 2023 14:07:40 +0100 Subject: [PATCH 15/29] Attempted more debug for test ipv6 for Travis --- test/test_ipv6.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 531f11526..70dfcd5dc 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -174,10 +174,14 @@ class TestIPv6 this_thread::sleep_for(milliseconds_from(100)); if (--nms == 0) break; + std::cout << "(lock failed, retrying " << nms << ")...\n"; } CSync::notify_all_relaxed(m_ReadyToClose); - m_ReadyToCloseLock.unlock(); + if (nms) + { + m_ReadyToCloseLock.unlock(); + } std::cout << "DoAccept: [UNLOCKED] " << nms << "\n"; srt_close(accepted_sock); From 1b3ccd78563935a69ffc8fc3d3f7863646470376 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 7 Mar 2023 14:23:23 +0100 Subject: [PATCH 16/29] More debug for Travis --- test/test_ipv6.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 70dfcd5dc..e103c2a51 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -172,14 +172,16 @@ class TestIPv6 while (!m_ReadyToCloseLock.try_lock()) { this_thread::sleep_for(milliseconds_from(100)); + std::cout << "(lock failed, retrying " << nms << ")...\n"; if (--nms == 0) break; - std::cout << "(lock failed, retrying " << nms << ")...\n"; } + std::cout << "(signaling...)\n"; CSync::notify_all_relaxed(m_ReadyToClose); if (nms) { + std::cout << "(unlocking...)\n"; m_ReadyToCloseLock.unlock(); } std::cout << "DoAccept: [UNLOCKED] " << nms << "\n"; From 90b13b1175492454ec86f10c306d2409ac372da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Tue, 7 Mar 2023 16:45:51 +0100 Subject: [PATCH 17/29] Fixed test ipv6 to use promise-future for synchronization --- test/test_ipv6.cpp | 73 +++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index e103c2a51..4a464f1c4 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "srt.h" #include "sync.h" #include "netinet_any.h" @@ -39,7 +40,11 @@ class TestIPv6 m_listener_sock = srt_create_socket(); ASSERT_NE(m_listener_sock, SRT_ERROR); - m_CallerStarted = false; + + m_CallerStarted.reset(new std::promise); + m_ReadyCaller.reset(new std::promise); + m_ReadyAccept.reset(new std::promise); + } void TearDown() @@ -62,10 +67,8 @@ class TestIPv6 int m_CallerPayloadSize = 0; int m_AcceptedPayloadSize = 0; - atomic m_CallerStarted; - Condition m_ReadyToClose; - Mutex m_ReadyToCloseLock; + std::unique_ptr> m_CallerStarted, m_ReadyCaller, m_ReadyAccept; // "default parameter" version. Can't use default parameters because this goes // against binding parameters. Nor overloading. @@ -76,17 +79,15 @@ class TestIPv6 void ClientThreadFlex(int family, const std::string& address, bool shouldwork) { + std::future ready_accepter = m_ReadyAccept->get_future(); + sockaddr_any sa (family); sa.hport(m_listen_port); EXPECT_EQ(inet_pton(family, address.c_str(), sa.get_addr()), 1); std::cout << "Calling: " << address << "(" << fam[family] << ") [LOCK...]\n"; - CUniqueSync before_closing(m_ReadyToCloseLock, m_ReadyToClose); - - std::cout << "[LOCKED] Connecting\n"; - - m_CallerStarted = true; + m_CallerStarted->set_value(); const int connect_res = srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa); @@ -98,19 +99,19 @@ class TestIPv6 int size = sizeof (int); EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_CallerPayloadSize, &size), -1); + m_ReadyCaller->set_value(); + PrintAddresses(m_caller_sock, "CALLER"); if (connect_res == SRT_ERROR) { std::cout << "Connect failed - [UNLOCK]\n"; - before_closing.locker().unlock(); // We don't need this lock here and it may deadlock srt_close(m_listener_sock); } else { - std::cout << "Connect succeeded, [UNLOCK-WAIT-CV...]\n"; - bool signaled = before_closing.wait_for(seconds_from(10)); - std::cout << "Connect: [" << (signaled ? "SIGNALED" : "EXPIRED") << "-LOCK]\n"; + std::cout << "Connect succeeded, [FUTURE-WAIT...]\n"; + ready_accepter.wait(); } } else @@ -120,7 +121,7 @@ class TestIPv6 EXPECT_EQ(srt_getrejectreason(m_caller_sock), SRT_REJ_SETTINGS); srt_close(m_listener_sock); } - std::cout << "Connect: [UNLOCKING...]\n"; + std::cout << "Connect: exit\n"; } std::map fam = { {AF_INET, "IPv4"}, {AF_INET6, "IPv6"} }; @@ -138,21 +139,24 @@ class TestIPv6 { sockaddr_any sc1; - using namespace std::chrono; + // Make sure the caller started + m_CallerStarted->get_future().wait(); + std::cout << "DoAccept: caller started, proceeding to accept\n"; SRTSOCKET accepted_sock = srt_accept(m_listener_sock, sc1.get(), &sc1.len); EXPECT_NE(accepted_sock, SRT_INVALID_SOCK) << "accept() failed with: " << srt_getlasterror_str(); if (accepted_sock == SRT_INVALID_SOCK) { return sockaddr_any(); } - int size = sizeof (int); - EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_AcceptedPayloadSize, &size), -1); - PrintAddresses(accepted_sock, "ACCEPTED"); sockaddr_any sn; EXPECT_NE(srt_getsockname(accepted_sock, sn.get(), &sn.len), SRT_ERROR); EXPECT_NE(sn.get_addr(), nullptr); + int size = sizeof (int); + EXPECT_NE(srt_getsockflag(m_caller_sock, SRTO_PAYLOADSIZE, &m_AcceptedPayloadSize, &size), -1); + + m_ReadyCaller->get_future().wait(); if (sn.get_addr() != nullptr) { @@ -161,30 +165,8 @@ class TestIPv6 << "EMPTY address in srt_getsockname"; } - std::cout << "DoAccept: [LOCK-SIGNAL]\n"; - - // Travis makes problems here by unknown reason. Try waiting up to 10s - // until it's possible, otherwise simply give up. The intention is to - // prevent from closing too soon before the caller thread has a chance - // to perform required verifications. After 10s we can consider it enough time. - - int nms = 10; - while (!m_ReadyToCloseLock.try_lock()) - { - this_thread::sleep_for(milliseconds_from(100)); - std::cout << "(lock failed, retrying " << nms << ")...\n"; - if (--nms == 0) - break; - } - - std::cout << "(signaling...)\n"; - CSync::notify_all_relaxed(m_ReadyToClose); - if (nms) - { - std::cout << "(unlocking...)\n"; - m_ReadyToCloseLock.unlock(); - } - std::cout << "DoAccept: [UNLOCKED] " << nms << "\n"; + std::cout << "DoAccept: ready accept - promise SET\n"; + m_ReadyAccept->set_value(); srt_close(accepted_sock); return sn; @@ -356,12 +338,11 @@ TEST_F(TestIPv6, plsize_faux_v6) // Sleeping isn't reliable so do a dampened spinlock here. // This flag also confirms that the caller acquired the mutex and will // unlock it for CV waiting - so we can proceed to notifying it. - do std::this_thread::sleep_for(milliseconds(100)); while (!m_CallerStarted); + m_CallerStarted->get_future().wait(); // Just in case of a test failure, kick CV to avoid deadlock - std::cout << "TEST: [LOCK-SIGNAL]\n"; - CSync::lock_notify_all(m_ReadyToClose, m_ReadyToCloseLock); - std::cout << "TEST: [UNLOCKED]\n"; + std::cout << "TEST: [PROMISE-SET]\n"; + m_ReadyAccept->set_value(); client.join(); } From bc4059c708fa846b193440ab3a844ce47e4c09c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Tue, 7 Mar 2023 17:11:17 +0100 Subject: [PATCH 18/29] Fixed filtering-out IPv6 tests for Travis --- .travis.yml | 2 +- test/test_ipv6.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index eaca3a571..26c6eaa41 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,7 +71,7 @@ matrix: - BUILD_TYPE=Release - BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON' script: - - TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*:ReuseAddr.ProtocolVersion:ReuseAddr.*6" ; # Tests to skip due to lack of IPv6 support + - TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.*6:ReuseAddr.ProtocolVersion:ReuseAddr.*6" ; # Tests to skip due to lack of IPv6 support - if [ "$TRAVIS_COMPILER" == "x86_64-w64-mingw32-g++" ]; then export CC="x86_64-w64-mingw32-gcc"; export CXX="x86_64-w64-mingw32-g++"; diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 4a464f1c4..7c9086c88 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -211,7 +211,7 @@ TEST_F(TestIPv6, v4_calls_v6_mapped) client.join(); } -TEST_F(TestIPv6, v6_calls_v6_mapped) +TEST_F(TestIPv6, v6_calls_mapped_v6) { sockaddr_any sa (AF_INET6); sa.hport(m_listen_port); From 11574a03d4446ba11e3cc72cd168435080c03d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Thu, 9 Mar 2023 11:04:43 +0100 Subject: [PATCH 19/29] Fixed wrong comment --- srtcore/core.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index c66492375..9d63586bf 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -5619,8 +5619,8 @@ bool srt::CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd SRT_ASSERT(m_TransferIPVersion != AF_UNSPEC); // IMPORTANT: // The m_iMaxSRTPayloadSize is the size of the payload in the "SRT packet" that can be sent - // over the current connection - which means that if any party is IPv6, then the maximum size - // is the one for IPv6 (1444). Only if both parties are IPv4, this maximum size is 1456. + // over the current connection - which means that if both parties are IPv6, then the maximum size + // is the one for IPv6 (1444). If any party is IPv4, this maximum size is 1456. // The family as the first argument is something different - it's for the header size in order // to calculate rate and statistics. From 76581458b1def63b6f89a169bfdf8c6aa7b2cfff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 11 Sep 2023 09:44:24 +0200 Subject: [PATCH 20/29] Fixed a bug introduced during upstream merge --- srtcore/core.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index eff90c51d..a4fe7559c 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -5678,6 +5678,7 @@ bool srt::CUDT::prepareBuffers(CUDTException* eout) << (m_TransferIPVersion == AF_INET6 ? "6" : m_TransferIPVersion == AF_INET ? "4" : "???") << " authtag=" << authtag); + m_pSndBuffer = new CSndBuffer(m_TransferIPVersion, 32, snd_payload_size, authtag); SRT_ASSERT(m_iPeerISN != -1); m_pRcvBuffer = new srt::CRcvBuffer(m_iPeerISN, m_config.iRcvBufSize, m_pRcvQueue->m_pUnitQueue, m_config.bMessageAPI); // After introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice a space. From 41a86bfc4252d67e560e4983265c0ee1802c9a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 11 Sep 2023 10:13:25 +0200 Subject: [PATCH 21/29] Fixed tests that should require IPv6 enabled --- docs/API/API-socket-options.md | 36 ++++++++++++++++++++-------------- test/test_ipv6.cpp | 4 ++++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index f6ca5caad..ec2f5400d 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -940,19 +940,25 @@ This value is a sum of: For the default 1500 the "remaining space" part is effectively 1456 for IPv4 and 1444 for IPv6. -Note that the IP version used here is not the domain of the socket, but the -in-transmission IP version. This is IPv4 for a case when the current socket's -binding address is of IPv4 domain, or if it is IPv6, but the peer's address -is then an IPv6-mapped-IPv4 address. The in-transmission IPv6 is only if the -peer's address is a true IPv6 address. Hence it is not possible to deteremine -all these limitations until the connection is established. Parts of SRT that -must allocate any resources regarding this value prior to connecting are using -the layout as per IPv4 because this results in a greater available space for -the "remaining space". +Note that the IP version used here is not the domain of the underlying UDP +socket, but the in-transmission IP version. This is effectively IPv4 in the +following cases: + +* when the current socket's binding address is of IPv4 domain +* when the peer's address is an IPv6-mapped-IPv4 address + +The IPv6 in-transmission IP version is assumed only if the peer's address +is a true IPv6 address (not IPv4 mapped). It is then not possible to determine +what the payload size limit until the connection is established. Parts of the +SRT facilities that must allocate any resources according to this value prior +to connecting are using the layout as per IPv4 because this way they allocate +more space than needed in the worst case. This value can be set on both connection parties independently, but after connection this option gets an effectively negotiated value, which is the less -one from both parties. +one from both parties. If this effective value is too small on any of the +connection peers, the connection is rejected (or late-rejected on the caller +side). This value then effectively controls: @@ -987,12 +993,12 @@ over the link used for the connection). See also limitations for In the file mode `SRTO_PAYLOADSIZE` has a special value 0 that means no limit for one single packet sending, and therefore bigger portions of data are internally split into smaller portions, each one using the maximum available -"remaining space". The best value for this case is then equal to the current -network device's MTU size. Setting a greater value is possible (maximum for the -system API is 65535), but it may lead to packet fragmentation on the system -level. This is highly unwanted in SRT because: +"remaining space". The best value of `SRTO_MSS` for this case is then equal to +the current network device's MTU size. Setting a greater value is possible +(maximum for the system API is 65535), but it may lead to packet fragmentation +on the system level. This is highly unwanted in SRT because: -* SRT does also its own fragmentation, so it would be counter-productive +* Here SRT does also its own fragmentation, so it would be counter-productive * It would use more system resources with no advantage * SRT is unaware of it, so the statistics will be slightly falsified diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index afc65e894..e8c14141d 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -272,6 +272,8 @@ TEST_F(TestIPv6, v6_calls_v4) TEST_F(TestIPv6, plsize_v6) { + SRTST_REQUIRES(IPv6); + SetupFileMode(); sockaddr_any sa (AF_INET6); @@ -319,6 +321,8 @@ TEST_F(TestIPv6, plsize_v4) TEST_F(TestIPv6, plsize_faux_v6) { + SRTST_REQUIRES(IPv6); + using namespace std::chrono; SetupFileMode(); From 45809bdbbdf3d979a3ecd7a4939653fb8a389554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 18 Sep 2023 13:08:01 +0200 Subject: [PATCH 22/29] Pre-refax of change-independent parts for 2677 --- srtcore/buffer_rcv.cpp | 9 +++++++-- srtcore/channel.cpp | 9 +++++++++ srtcore/common.cpp | 2 +- srtcore/common.h | 9 +++++++++ srtcore/congctl.cpp | 5 ++++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/srtcore/buffer_rcv.cpp b/srtcore/buffer_rcv.cpp index 1f46788aa..7ea0945bc 100644 --- a/srtcore/buffer_rcv.cpp +++ b/srtcore/buffer_rcv.cpp @@ -130,7 +130,7 @@ CRcvBuffer::CRcvBuffer(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool b , m_bMessageAPI(bMessageAPI) , m_iBytesCount(0) , m_iPktsCount(0) - , m_uAvgPayloadSz(SRT_LIVE_DEF_PLSIZE) + , m_uAvgPayloadSz(0) { SRT_ASSERT(size < size_t(std::numeric_limits::max())); // All position pointers are integers } @@ -758,7 +758,12 @@ void CRcvBuffer::countBytes(int pkts, int bytes) m_iBytesCount += bytes; // added or removed bytes from rcv buffer m_iPktsCount += pkts; if (bytes > 0) // Assuming one pkt when adding bytes - m_uAvgPayloadSz = avg_iir<100>(m_uAvgPayloadSz, (unsigned) bytes); + { + if (!m_uAvgPayloadSz) + m_uAvgPayloadSz = bytes; + else + m_uAvgPayloadSz = avg_iir<100>(m_uAvgPayloadSz, (unsigned) bytes); + } } void CRcvBuffer::releaseUnitInPos(int pos) diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 091adf115..38ce5b598 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -1016,6 +1016,15 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet if ((msg_flags & errmsgflg[i].first) != 0) flg << " " << errmsgflg[i].second; + if (msg_flags & MSG_TRUNC) + { + // Additionally show buffer information in this case + flg << " buffers: "; + for (size_t i = 0; i < CPacket::PV_SIZE; ++i) + { + flg << "[" << w_packet.m_PacketVector[i].iov_len << "] "; + } + } // This doesn't work the same way on Windows, so on Windows just skip it. #endif diff --git a/srtcore/common.cpp b/srtcore/common.cpp index b621c8025..dc60b3db7 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -205,7 +205,7 @@ void srt::CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const soc { // Check if the peer address is a model of IPv4-mapped-on-IPv6. // If so, it means that the `ip` array should be interpreted as IPv4. - const bool is_mapped_ipv4 = checkMappedIPv4((uint16_t*)peer.sin6.sin6_addr.s6_addr); + const bool is_mapped_ipv4 = checkMappedIPv4(peer.sin6); sockaddr_in6* a = (&w_addr.sin6); diff --git a/srtcore/common.h b/srtcore/common.h index 5021fa5a8..de42a7d83 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -1422,6 +1422,15 @@ inline std::string SrtVersionString(int version) bool SrtParseConfig(const std::string& s, SrtConfig& w_config); +bool checkMappedIPv4(const uint16_t* sa); + +inline bool checkMappedIPv4(const sockaddr_in6& sa) +{ + const uint16_t* addr = reinterpret_cast(&sa.sin6_addr.s6_addr); + return checkMappedIPv4(addr); +} + + } // namespace srt #endif diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 91c73d660..b9265c046 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -63,6 +63,7 @@ class LiveCC: public SrtCongestionControlBase int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec) srt::sync::atomic m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit size_t m_zMaxPayloadSize; + size_t m_zHeaderSize; // NAKREPORT stuff. int m_iMinNakInterval_us; // Minimum NAK Report Period (usec) @@ -81,6 +82,8 @@ class LiveCC: public SrtCongestionControlBase m_zMaxPayloadSize = parent->maxPayloadSize(); m_zSndAvgPayloadSize = m_zMaxPayloadSize; + m_zHeaderSize = parent->m_config.iMSS - parent->maxPayloadSize(); + m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec) m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2) @@ -173,7 +176,7 @@ class LiveCC: public SrtCongestionControlBase void updatePktSndPeriod() { // packet = payload + header - const double pktsize = (double) m_zSndAvgPayloadSize.load() + CPacket::SRT_DATA_HDR_SIZE; + const double pktsize = (double) m_zSndAvgPayloadSize.load() + m_zHeaderSize; m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW); HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod << " by avg pktsize=" << m_zSndAvgPayloadSize From 0c3abe051623e70ff0d2c51e383e48b745d3d657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 18 Sep 2023 15:15:51 +0200 Subject: [PATCH 23/29] A fix from code review --- srtcore/api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 8ce383d84..5646e3e79 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -3160,7 +3160,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons // We can't use maxPayloadSize() because this value isn't valid until the connection is established. // We need to "think big", that is, allocate a size that would fit both IPv4 and IPv6. - size_t payload_size = s->core().m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(AF_INET); + const size_t payload_size = s->core().m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(AF_INET); HLOGC(smlog.Debug, log << s->core().CONID() << "updateMux: config rcv queue qsize=" << 128 << " plsize=" << payload_size << " hsize=" << 1024); From ce2a043e86120b734d3ea98a13fe93d528700e29 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 19 Sep 2023 08:38:11 +0200 Subject: [PATCH 24/29] Apply SOME suggestions from the doc review (others pending) Co-authored-by: stevomatthews --- docs/API/API-socket-options.md | 62 ++++++++++++++++------------------ 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index ec2f5400d..cb6b88f2e 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -947,20 +947,19 @@ following cases: * when the current socket's binding address is of IPv4 domain * when the peer's address is an IPv6-mapped-IPv4 address -The IPv6 in-transmission IP version is assumed only if the peer's address -is a true IPv6 address (not IPv4 mapped). It is then not possible to determine -what the payload size limit until the connection is established. Parts of the -SRT facilities that must allocate any resources according to this value prior -to connecting are using the layout as per IPv4 because this way they allocate -more space than needed in the worst case. +The IPv6 transmission case is assumed only if the peer's address is a true IPv6 address +(not IPv4 mapped). It is then not possible to determine the payload size limit +until the connection is established. SRT operations that must allocate any +resources according to this value prior to connecting will assume IPv4 transmission +because this way, in the worst case, they allocate more space than needed . This value can be set on both connection parties independently, but after -connection this option gets an effectively negotiated value, which is the less -one from both parties. If this effective value is too small on any of the +connection `SRTO_MSS` gets a negotiated value, which is the lesser +of the two. If this effective value is too small for either of the connection peers, the connection is rejected (or late-rejected on the caller side). -This value then effectively controls: +This value then controls: * The maximum size of the payload in a single UDP packet ("remaining space"). @@ -970,24 +969,23 @@ in the IPv4 layout case (1472 bytes per packet for MSS=1500). The reason for it is that some buffer resources are allocated prior to the connection, so this value must fit both IPv4 and IPv6 for buffer memory allocation. -The default value 1500 matches the standard MTU size for network devices. It -is recommended that this value be set at maximum to the value of MTU size of -the network device that you will use for connection. - -Detailed recommendations for this value differ in the file and live mode. - -In the live mode a single call to `srt_send*` function may only send data -that fit in one packet. This size is defined by the `SRTO_PAYLOADSIZE` -option (defult: 1316) and it is also the size of the data in a single UDP -packet. To save memory space, you may want then to set MSS in live mode to -a value for which the "remaining space" matches `SRTO_PAYLOADSIZE` value (for -default 1316 it will be 1360 for IPv4 and 1372 for IPv6). This is not done by -default for security reasons: this may potentially lead to inability to read an -incoming UDP packet if its size is by some reason bigger than the negotiated MSS. -This may lead to misleading situations and hard to detect errors. You should -set such a value only if the peer is trusted (that is, you can be certain that -it will never come to a situation of having received an oversized UDP packet -over the link used for the connection). See also limitations for +The default value of 1500 corresponds to the standard MTU size for network devices. It +is recommended that this value be set to the maximum MTU size of +the network device that you will use for the connection. + +The recommendations for the value of `SRTO_MSS` differ between file and live modes. + +In live mode a single call to the `srt_send*` function may only send data +that fits in one packet. This size is defined by the `SRTO_PAYLOADSIZE` +option (defult: 1316), and it is also the size of the data in a single UDP +packet. To save memory space, you may want then to set `SRTO_MSS` in live mode to +a value for which the "remaining space" matches the `SRTO_PAYLOADSIZE` value (for +the default value of 1316 this will be 1360 for IPv4 and 1372 for IPv6). For security reasons, +this is not done by default: it may potentially lead to the inability to read an incoming UDP +packet if its size is for some reason bigger than the negotiated MSS, which may in turn lead +to unpredictable behaviour and hard-to-detect errors. You should set such a value only if +the peer is trusted (that is, you can be certain that you will never receive an oversized UDP +packet over the link used for the connection). You should also consider the limitations of `SRTO_PAYLOADSIZE`. In the file mode `SRTO_PAYLOADSIZE` has a special value 0 that means no limit @@ -998,12 +996,12 @@ the current network device's MTU size. Setting a greater value is possible (maximum for the system API is 65535), but it may lead to packet fragmentation on the system level. This is highly unwanted in SRT because: -* Here SRT does also its own fragmentation, so it would be counter-productive -* It would use more system resources with no advantage -* SRT is unaware of it, so the statistics will be slightly falsified +* SRT also performs its own fragmentation, so it would be counter-productive +* It would use more system resources to no advantage +* SRT is unaware of it, so the resulting statistics would be slightly misleading -The system-level packet fragmentation cannot be however reliably turned off; -the best approach is then to avoid it by using appropriate parameters. +System-level packet fragmentation cannot be reliably turned off, +so safest approach is to avoid it by using appropriate parameters. [Return to list](#list-of-options) From 5c2c876b530a25b5c80f0d70306bea54d9416045 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 19 Sep 2023 16:50:50 +0200 Subject: [PATCH 25/29] Apply suggestions from doc review (still pending) Co-authored-by: stevomatthews --- docs/API/API-socket-options.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index cb6b88f2e..21da9c2a3 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -927,17 +927,17 @@ The default value is 0x010000 (SRT v1.0.0). Maximum Segment Size. This value represents the maximum size of a UDP packet sent by the system. Therefore the value of `SRTO_MSS` must not exceed the values of `SRTO_UDP_SNDBUF` or `SRTO_UDP_RCVBUF`. It is used for buffer -allocation and rate calculation using packet counter assuming fully filled +allocation and rate calculation using a packet counter that assumes fully filled packets. This value is a sum of: -* IP header (20 bytes for IPv4 or 32 bytes for IPv6) +* IP header (20 bytes for IPv4, or 32 bytes for IPv6) * UDP header (8 bytes) * SRT header (16 bytes) * remaining space (as the maximum payload size available for a packet) -For the default 1500 the "remaining space" part is effectively 1456 for IPv4 +For the default 1500 the "remaining space" is effectively 1456 for IPv4 and 1444 for IPv6. Note that the IP version used here is not the domain of the underlying UDP @@ -951,7 +951,7 @@ The IPv6 transmission case is assumed only if the peer's address is a true IPv6 (not IPv4 mapped). It is then not possible to determine the payload size limit until the connection is established. SRT operations that must allocate any resources according to this value prior to connecting will assume IPv4 transmission -because this way, in the worst case, they allocate more space than needed . +because this way, in the worst case, they allocate more space than needed. This value can be set on both connection parties independently, but after connection `SRTO_MSS` gets a negotiated value, which is the lesser @@ -988,8 +988,8 @@ the peer is trusted (that is, you can be certain that you will never receive an packet over the link used for the connection). You should also consider the limitations of `SRTO_PAYLOADSIZE`. -In the file mode `SRTO_PAYLOADSIZE` has a special value 0 that means no limit -for one single packet sending, and therefore bigger portions of data are +In file mode `SRTO_PAYLOADSIZE` has a special value 0 that means no limit +for sending a single packet, and therefore bigger portions of data are internally split into smaller portions, each one using the maximum available "remaining space". The best value of `SRTO_MSS` for this case is then equal to the current network device's MTU size. Setting a greater value is possible From 0403820d6dbb1073dec6e0282d805526a0d7c838 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 19 Sep 2023 16:51:30 +0200 Subject: [PATCH 26/29] Update doc review (still pending) --- docs/API/API-socket-options.md | 55 +++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 21da9c2a3..f4581c358 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -1155,45 +1155,52 @@ encrypted connection, they have to simply set the same passphrase. | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PAYLOADSIZE` | 1.3.0 | pre | `int32_t` | bytes | \* | 0.. \* | W | GSD | -Sets the data limitation mode and the maximum data size for sending at once. +Sets the mode that determines the limitations on how data is sent, including the maximum +size of payload data sent within a single UDP packet. This option can be only set prior +to connecting, but it can be read also after the connection has been established. -The default value is 0 in the file mode and 1316 in live mode (this is one of -the options modified together with `SRTO_TRANSTYPE`). +The default value is 1316 in live mode (which is default) and 0 in file mode (when file +mode is set through the `SRTO_TRANSTYPE` option). -If the value is 0, this means a "file mode", in which the call to `srt_send*` -is not limited to a size fitting in one single packet, that is, the supplied -data will be split into multiple pieces fitting in a single UDP packet, if -necessary, as well as every packet will use the maximum space available -in a UDP packet (except the last in the stream or in the message) according to -the `SRTO_MSS` setting and others that may influence this size (such as -`SRTO_PACKETFILTER` and `SRTO_CRYPTOMODE`). +In file mode (`SRTO_PAYLOADSIZE` = 0) the call to `srt_send*` is not limited to the size +of a single packet. If necessary, the supplied data will be split into multiple pieces, +each fitting into a single UDP packet. Every data payload (except the last one in the +stream or in the message) will use the maximum space available in a UDP packet, +as determined by `SRTO_MSS` and other settings that may influence this size +(such as [`SRTO_PACKETFILTER`](#SRTO_PACKETFILTER) and +[`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE)). -If the value is greater than 0, this means a "live mode", and the value -defines the maximum size of: +Also when this option is set to 0 prior to connecting, then reading this option +from a connected socket will return the maximum size of the payload that fits +in a single packet according to the current connection parameters. -* the single call to a sending function (`srt_send*`) -* the payload supplied in every single data packet +In live mode (`SRTO_PAYLOADSIZE` > 0) the value defines the maximum size of: + +* a single call to a sending function (`srt_send*`) +* the payload supplied in each data packet + +as well as the minimum size of the buffer used for the `srt_recv*` call. This value can be set to a greater value than the default 1316, but the maximum possible value is limited by the following factors: -* 1500 is the default MSS (see `SRTO_MSS`), including headers, which are: - * 20 bytes for IPv4 or 32 bytes for IPv6 +* 1500 bytes is the default MSS (see [`SRTO_MSS`](#SRTO_MSS)), including headers, which occupy: + * 20 bytes for IPv4, or 32 bytes for IPv6 * 8 bytes for UDP * 16 bytes for SRT -This alone gives the limit of 1456 for IPv4 and 1444 for IPv6. This limit may -be however further decreased in the following cases: +This alone gives a limit of 1456 for IPv4 and 1444 for IPv6. This limit may +be further decreased in the following cases: -* 4 bytes reserved for FEC, if you use the builtin FEC packet filter (see `SRTO_PACKETFILTER`) -* 16 bytes reserved for the authentication tag, if you use AES GCM (see `SRTO_CRYPTOMODE`) +* 4 bytes reserved for FEC, if you use the built in FEC packet filter (see [`SRTO_PACKETFILTER`](#SRTO_PACKETFILTER)) +* 16 bytes reserved for the authentication tag, if you use AES GCM (see [`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE)) -**WARNING**: The option setter will reject the setting if this value is too -great, but note that not every limitation can be checked prior to connection. +**WARNING**: The party setting the options will reject a value that is too +large, but note that not every limitation can be checked prior to connection. This includes: -* MSS defined by the peer, which may override MSS set in the agent -* The in-transmission IP version - see `SRTO_MSS` for details +* the MSS value defined by a peer, which may override the MSS set by an agent +* the in-transmission IP version (see [SRTO_MSS](#SRTO_MSS) for details) These values also influence the "remaining space" in the packet to be used for payload. If during the handshake it turns out that this "remaining space" is From e02d85a886ad2ee1d4f093d6a259af828fc23ae2 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 19 Sep 2023 16:52:25 +0200 Subject: [PATCH 27/29] Apply suggestions from doc review (complete) Co-authored-by: stevomatthews --- docs/API/API-socket-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index f4581c358..4c0c9640b 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -1001,7 +1001,7 @@ on the system level. This is highly unwanted in SRT because: * SRT is unaware of it, so the resulting statistics would be slightly misleading System-level packet fragmentation cannot be reliably turned off, -so safest approach is to avoid it by using appropriate parameters. +so the safest approach is to avoid it by using appropriate parameters. [Return to list](#list-of-options) From 6074f219ef53432c8a5ff9c4d6242116a2e848e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Mon, 2 Oct 2023 11:25:05 +0200 Subject: [PATCH 28/29] Added extra v6-to-v6 test to check correct payload size --- srtcore/core.cpp | 2 +- test/test_file_transmission.cpp | 225 ++++++++++++++++++++++---------- 2 files changed, 157 insertions(+), 70 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 99e6df610..e3c29b651 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -5670,7 +5670,7 @@ bool srt::CUDT::prepareBuffers(CUDTException* eout) // The family as the first argument is something different - it's for the header size in order // to calculate rate and statistics. - int snd_payload_size = m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(AF_INET); + int snd_payload_size = m_config.iMSS - CPacket::HDR_SIZE - CPacket::udpHeaderSize(m_TransferIPVersion); SRT_ASSERT(m_iMaxSRTPayloadSize <= snd_payload_size); HLOGC(rslog.Debug, log << CONID() << "Creating buffers: snd-plsize=" << snd_payload_size diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index a81fb301b..d28532cc0 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -201,11 +201,9 @@ TEST(FileTransmission, Upload) TEST(FileTransmission, Setup46) { - SRTST_REQUIRES(IPv6); - using namespace srt; - - srt_startup(); + SRTST_REQUIRES(IPv6); + TestInit srtinit; SRTSOCKET sock_lsn = srt_create_socket(), sock_clr = srt_create_socket(); @@ -213,98 +211,187 @@ TEST(FileTransmission, Setup46) srt_setsockflag(sock_lsn, SRTO_TRANSTYPE, &tt, sizeof tt); srt_setsockflag(sock_clr, SRTO_TRANSTYPE, &tt, sizeof tt); - try - { - // Setup a connection with IPv6 caller and IPv4 listener, - // then send data of 1456 size and make sure two packets were used. + // Setup a connection with IPv6 caller and IPv4 listener, + // then send data of 1456 size and make sure two packets were used. - // So first configure a caller for IPv6 socket, capable of - // using IPv4. As the IP version isn't specified now when - // creating a socket, force binding explicitly. + // So first configure a caller for IPv6 socket, capable of + // using IPv4. As the IP version isn't specified now when + // creating a socket, force binding explicitly. - // This creates the "any" spec for IPv6 with port = 0 - sockaddr_any sa(AF_INET6); + // This creates the "any" spec for IPv6 with port = 0 + sockaddr_any sa(AF_INET6); - int ipv4_and_ipv6 = 0; - ASSERT_NE(srt_setsockflag(sock_clr, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); + int ipv4_and_ipv6 = 0; + ASSERT_NE(srt_setsockflag(sock_clr, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); - ASSERT_NE(srt_bind(sock_clr, sa.get(), sa.size()), -1); + ASSERT_NE(srt_bind(sock_clr, sa.get(), sa.size()), -1); - int connect_port = 5555; + int connect_port = 5555; - // Configure listener - sockaddr_in sa_lsn = sockaddr_in(); - sa_lsn.sin_family = AF_INET; - sa_lsn.sin_addr.s_addr = INADDR_ANY; - sa_lsn.sin_port = htons(connect_port); + // Configure listener + sockaddr_in sa_lsn = sockaddr_in(); + sa_lsn.sin_family = AF_INET; + sa_lsn.sin_addr.s_addr = INADDR_ANY; + sa_lsn.sin_port = htons(connect_port); - // Find unused a port not used by any other service. - // Otherwise srt_connect may actually connect. - int bind_res = -1; - for (connect_port = 5000; connect_port <= 5555; ++connect_port) + // Find unused a port not used by any other service. + // Otherwise srt_connect may actually connect. + int bind_res = -1; + for (connect_port = 5000; connect_port <= 5555; ++connect_port) + { + sa_lsn.sin_port = htons(connect_port); + bind_res = srt_bind(sock_lsn, (sockaddr*)&sa_lsn, sizeof sa_lsn); + if (bind_res == 0) { - sa_lsn.sin_port = htons(connect_port); - bind_res = srt_bind(sock_lsn, (sockaddr*)&sa_lsn, sizeof sa_lsn); - if (bind_res == 0) - { - std::cout << "Running test on port " << connect_port << "\n"; - break; - } - - ASSERT_TRUE(bind_res == SRT_EINVOP) << "Bind failed not due to an occupied port. Result " << bind_res; + std::cout << "Running test on port " << connect_port << "\n"; + break; } - ASSERT_GE(bind_res, 0); + ASSERT_TRUE(bind_res == SRT_EINVOP) << "Bind failed not due to an occupied port. Result " << bind_res; + } + + ASSERT_GE(bind_res, 0); - srt_listen(sock_lsn, 1); + srt_listen(sock_lsn, 1); - ASSERT_EQ(inet_pton(AF_INET6, "::FFFF:127.0.0.1", &sa.sin6.sin6_addr), 1); + ASSERT_EQ(inet_pton(AF_INET6, "::FFFF:127.0.0.1", &sa.sin6.sin6_addr), 1); - sa.hport(connect_port); + sa.hport(connect_port); - ASSERT_EQ(srt_connect(sock_clr, sa.get(), sa.size()), 0); + ASSERT_EQ(srt_connect(sock_clr, sa.get(), sa.size()), 0); - int sock_acp = -1; - ASSERT_NE(sock_acp = srt_accept(sock_lsn, sa.get(), &sa.len), -1); + int sock_acp = -1; + ASSERT_NE(sock_acp = srt_accept(sock_lsn, sa.get(), &sa.len), -1); - const size_t SIZE = 1454; // Max payload for IPv4 minus 2 - still more than 1444 for IPv6 - char buffer[SIZE]; + const size_t SIZE = 1454; // Max payload for IPv4 minus 2 - still more than 1444 for IPv6 + char buffer[SIZE]; - std::random_device rd; - std::mt19937 mtrd(rd()); - std::uniform_int_distribution dis(0, UINT8_MAX); + std::random_device rd; + std::mt19937 mtrd(rd()); + std::uniform_int_distribution dis(0, UINT8_MAX); + + for (size_t i = 0; i < SIZE; ++i) + { + buffer[i] = dis(mtrd); + } + + EXPECT_EQ(srt_send(sock_acp, buffer, SIZE), SIZE) << srt_getlasterror_str(); + + char resultbuf[SIZE]; + EXPECT_EQ(srt_recv(sock_clr, resultbuf, SIZE), SIZE) << srt_getlasterror_str(); + + // It should use the maximum payload size per packet reported from the option. + int payloadsize_back = 0; + int payloadsize_back_size = sizeof (payloadsize_back); + EXPECT_EQ(srt_getsockflag(sock_clr, SRTO_PAYLOADSIZE, &payloadsize_back, &payloadsize_back_size), 0); + EXPECT_EQ(payloadsize_back, SRT_MAX_PLSIZE_AF_INET); + + SRT_TRACEBSTATS snd_stats, rcv_stats; + srt_bstats(sock_acp, &snd_stats, 0); + srt_bstats(sock_clr, &rcv_stats, 0); + + EXPECT_EQ(snd_stats.pktSentUniqueTotal, 1); + EXPECT_EQ(rcv_stats.pktRecvUniqueTotal, 1); + +} - for (size_t i = 0; i < SIZE; ++i) +TEST(FileTransmission, Setup66) +{ + using namespace srt; + SRTST_REQUIRES(IPv6); + TestInit srtinit; + + SRTSOCKET sock_lsn = srt_create_socket(), sock_clr = srt_create_socket(); + + const int tt = SRTT_FILE; + srt_setsockflag(sock_lsn, SRTO_TRANSTYPE, &tt, sizeof tt); + srt_setsockflag(sock_clr, SRTO_TRANSTYPE, &tt, sizeof tt); + + // Setup a connection with IPv6 caller and IPv4 listener, + // then send data of 1456 size and make sure two packets were used. + + // So first configure a caller for IPv6 socket, capable of + // using IPv4. As the IP version isn't specified now when + // creating a socket, force binding explicitly. + + // This creates the "any" spec for IPv6 with port = 0 + sockaddr_any sa(AF_INET6); + + // Require that the connection allows both IP versions. + int ipv4_and_ipv6 = 0; + ASSERT_NE(srt_setsockflag(sock_clr, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); + ASSERT_NE(srt_setsockflag(sock_lsn, SRTO_IPV6ONLY, &ipv4_and_ipv6, sizeof ipv4_and_ipv6), -1); + + ASSERT_NE(srt_bind(sock_clr, sa.get(), sa.size()), -1); + + int connect_port = 5555; + + // Configure listener + sockaddr_any sa_lsn(AF_INET6); + + // Find unused a port not used by any other service. + // Otherwise srt_connect may actually connect. + int bind_res = -1; + for (connect_port = 5000; connect_port <= 5555; ++connect_port) + { + sa_lsn.hport(connect_port); + bind_res = srt_bind(sock_lsn, sa_lsn.get(), sa_lsn.size()); + if (bind_res == 0) { - buffer[i] = dis(mtrd); + std::cout << "Running test on port " << connect_port << "\n"; + break; } - EXPECT_EQ(srt_send(sock_acp, buffer, SIZE), SIZE) << srt_getlasterror_str(); + ASSERT_TRUE(bind_res == SRT_EINVOP) << "Bind failed not due to an occupied port. Result " << bind_res; + } + + ASSERT_GE(bind_res, 0); - char resultbuf[SIZE]; - EXPECT_EQ(srt_recv(sock_clr, resultbuf, SIZE), SIZE) << srt_getlasterror_str(); + srt_listen(sock_lsn, 1); - // It should use the maximum payload size per packet reported from the option. - int payloadsize_back = 0; - int payloadsize_back_size = sizeof (payloadsize_back); - EXPECT_EQ(srt_getsockflag(sock_clr, SRTO_PAYLOADSIZE, &payloadsize_back, &payloadsize_back_size), 0); - EXPECT_EQ(payloadsize_back, SRT_MAX_PLSIZE_AF_INET); + ASSERT_EQ(inet_pton(AF_INET6, "::1", &sa.sin6.sin6_addr), 1); - SRT_TRACEBSTATS snd_stats, rcv_stats; - srt_bstats(sock_acp, &snd_stats, 0); - srt_bstats(sock_clr, &rcv_stats, 0); + sa.hport(connect_port); - EXPECT_EQ(snd_stats.pktSentUniqueTotal, 1); - EXPECT_EQ(rcv_stats.pktRecvUniqueTotal, 1); + std::cout << "Connecting to: " << sa.str() << std::endl; - } - catch (...) + int connect_result = srt_connect(sock_clr, sa.get(), sa.size()); + ASSERT_EQ(connect_result, 0) << srt_getlasterror_str(); + + int sock_acp = -1; + ASSERT_NE(sock_acp = srt_accept(sock_lsn, sa.get(), &sa.len), SRT_ERROR); + + const size_t SIZE = 1454; // Max payload for IPv4 minus 2 - still more than 1444 for IPv6 + char buffer[SIZE]; + + std::random_device rd; + std::mt19937 mtrd(rd()); + std::uniform_int_distribution dis(0, UINT8_MAX); + + for (size_t i = 0; i < SIZE; ++i) { - srt_cleanup(); - throw; + buffer[i] = dis(mtrd); } - srt_cleanup(); -} + EXPECT_EQ(srt_send(sock_acp, buffer, SIZE), SIZE) << srt_getlasterror_str(); -// XXX Setup66 - establish an IPv6 to IPv6 connection and make sure max payload size is that of IPv6. + char resultbuf[SIZE]; + EXPECT_EQ(srt_recv(sock_clr, resultbuf, SIZE), SIZE) << srt_getlasterror_str(); + + // It should use the maximum payload size per packet reported from the option. + int payloadsize_back = 0; + int payloadsize_back_size = sizeof (payloadsize_back); + EXPECT_EQ(srt_getsockflag(sock_clr, SRTO_PAYLOADSIZE, &payloadsize_back, &payloadsize_back_size), 0); + EXPECT_EQ(payloadsize_back, SRT_MAX_PLSIZE_AF_INET6); + std::cout << "Payload size: " << payloadsize_back << std::endl; + + SRT_TRACEBSTATS snd_stats, rcv_stats; + srt_bstats(sock_acp, &snd_stats, 0); + srt_bstats(sock_clr, &rcv_stats, 0); + + // We use the same data size that fit in 1 payload IPv4, but not IPv6. + // Therefore sending should be here split into two packets. + EXPECT_EQ(snd_stats.pktSentUniqueTotal, 2); + EXPECT_EQ(rcv_stats.pktRecvUniqueTotal, 2); + +} From 9c6e5b53815efa76a296ef513b05e4cdae17c668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Fri, 6 Oct 2023 16:01:41 +0200 Subject: [PATCH 29/29] Added a test that demonstrates the bug --- test/test_file_transmission.cpp | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index d28532cc0..79f3ccb8c 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -395,3 +395,91 @@ TEST(FileTransmission, Setup66) EXPECT_EQ(rcv_stats.pktRecvUniqueTotal, 2); } + +TEST(FileTransmission, Message) +{ + using namespace srt; + + TestInit srtinit; + + SRTSOCKET client = srt_create_socket(), server = srt_create_socket(); + + int yes = 1; + int tt_file = SRTT_FILE; + + srt_setsockflag(client, SRTO_TRANSTYPE, &tt_file, sizeof tt_file); + srt_setsockflag(client, SRTO_MESSAGEAPI, &yes, sizeof yes); + + srt_setsockflag(server, SRTO_TRANSTYPE, &tt_file, sizeof tt_file); + srt_setsockflag(server, SRTO_MESSAGEAPI, &yes, sizeof yes); + + sockaddr_any sa(AF_INET); + sa.hport(5555); + + ASSERT_NE(srt_bind(server, sa.get(), sa.size()), SRT_ERROR); + ASSERT_NE(srt_listen(server, 1), SRT_ERROR); + + std::thread acceptor( [server]() { + // Accept the connection and try to read a message to + // a buffer of size 2000. + sockaddr_any sar(AF_INET); + SRTSOCKET acp = srt_accept(server, sar.get(), &sar.len); + + int recv_timeout = 5000; + srt_setsockflag(acp, SRTO_RCVTIMEO, &recv_timeout, sizeof recv_timeout); + EXPECT_NE(acp, -1); + + char recvm[4096]; + + // First try to read using a too small buffer + SRT_MSGCTRL mc = srt_msgctrl_default; + int size1 = srt_recvmsg2(acp, recvm, 2000, &mc); + int recverr = srt_getlasterror(NULL); + + EXPECT_EQ(size1, -1); + EXPECT_EQ(recverr, SRT_ELARGEMSG); + + // Still, even if the message wasn't retrieved, the msgno + // value should be returned. + int msgno_was = mc.msgno; + + // Moreover, after this failure the message should be + // still extractable, as long as you provide a large + // enough buffer. + mc = srt_msgctrl_default; + int size2 = srt_recvmsg2(acp, recvm, 4096, &mc); + + EXPECT_EQ(size2, 4096); + EXPECT_EQ(mc.msgno, msgno_was); + + srt_close(acp); + }); + + struct CloseThread + { + std::thread& c; + CloseThread(std::thread& cc): c(cc) {} + ~CloseThread() + { + if (c.joinable()) + c.join(); + } + }; + + char message[4096]; // large enough to exceed 2 packets + + memset(message, 'A', sizeof(message)-1); + message[sizeof(message)-1] = 0; + + ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin.sin_addr), 1); + + ASSERT_NE(srt_connect(client, sa.get(), sa.size()), -1); + + ASSERT_EQ(srt_send(client, message, 4096), 4096); + + acceptor.join(); + + srt_close(client); + srt_close(server); +} +