123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095 |
- /*
- * SRT - Secure, Reliable, Transport
- * Copyright (c) 2018 Haivision Systems Inc.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- */
- /*****************************************************************************
- Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the
- above copyright notice, this list of conditions
- and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the University of Illinois
- nor the names of its contributors may be used to
- endorse or promote products derived from this
- software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- /*****************************************************************************
- written by
- Haivision Systems Inc.
- *****************************************************************************/
- #include <utility>
- #include "srt.h"
- #include "socketconfig.h"
- using namespace srt;
- extern const int32_t SRT_DEF_VERSION = SrtParseVersion(SRT_VERSION);
- namespace {
- typedef void setter_function(CSrtConfig& co, const void* optval, int optlen);
- template<SRT_SOCKOPT name>
- struct CSrtConfigSetter
- {
- static setter_function set;
- };
- template<>
- struct CSrtConfigSetter<SRTO_MSS>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int ival = cast_optval<int>(optval, optlen);
- if (ival < int(CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize))
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iMSS = ival;
- // Packet size cannot be greater than UDP buffer size
- if (co.iMSS > co.iUDPSndBufSize)
- co.iMSS = co.iUDPSndBufSize;
- if (co.iMSS > co.iUDPRcvBufSize)
- co.iMSS = co.iUDPRcvBufSize;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_FC>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- const int fc = cast_optval<int>(optval, optlen);
- if (fc < co.DEF_MIN_FLIGHT_PKT)
- {
- LOGC(kmlog.Error, log << "SRTO_FC: minimum allowed value is 32 (provided: " << fc << ")");
- throw CUDTException(MJ_NOTSUP, MN_INVAL);
- }
- co.iFlightFlagSize = fc;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_SNDBUF>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- int bs = cast_optval<int>(optval, optlen);
- if (bs <= 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iSndBufSize = bs / (co.iMSS - CPacket::UDP_HDR_SIZE);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_RCVBUF>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val <= 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- // Mimimum recv buffer size is 32 packets
- const int mssin_size = co.iMSS - CPacket::UDP_HDR_SIZE;
- if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT)
- co.iRcvBufSize = val / mssin_size;
- else
- co.iRcvBufSize = co.DEF_MIN_FLIGHT_PKT;
- // recv buffer MUST not be greater than FC size
- if (co.iRcvBufSize > co.iFlightFlagSize)
- co.iRcvBufSize = co.iFlightFlagSize;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_LINGER>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.Linger = cast_optval<linger>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_UDP_SNDBUF>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iUDPSndBufSize = std::max(co.iMSS, cast_optval<int>(optval, optlen));
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_UDP_RCVBUF>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iUDPRcvBufSize = std::max(co.iMSS, cast_optval<int>(optval, optlen));
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_RENDEZVOUS>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bRendezvous = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_SNDTIMEO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < -1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iSndTimeOut = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_RCVTIMEO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < -1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iRcvTimeOut = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_SNDSYN>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bSynSending = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_RCVSYN>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bSynRecving = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_REUSEADDR>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bReuseAddr = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_MAXBW>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int64_t val = cast_optval<int64_t>(optval, optlen);
- if (val < -1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.llMaxBW = val;
- }
- };
- #ifdef ENABLE_MAXREXMITBW
- template<>
- struct CSrtConfigSetter<SRTO_MAXREXMITBW>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int64_t val = cast_optval<int64_t>(optval, optlen);
- if (val < -1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.llMaxRexmitBW = val;
- }
- };
- #endif
- template<>
- struct CSrtConfigSetter<SRTO_IPTTL>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- int val = cast_optval<int>(optval, optlen);
- if (!(val == -1) && !((val >= 1) && (val <= 255)))
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iIpTTL = cast_optval<int>(optval);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_IPTOS>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iIpToS = cast_optval<int>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_BINDTODEVICE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- #ifdef SRT_ENABLE_BINDTODEVICE
- using namespace std;
- string val;
- if (optlen == -1)
- val = (const char *)optval;
- else
- val.assign((const char *)optval, optlen);
- if (val.size() >= IFNAMSIZ)
- {
- LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE: device name too long (max: IFNAMSIZ=" << IFNAMSIZ << ")");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- co.sBindToDevice = val;
- #else
- (void)co; // prevent warning
- (void)optval;
- (void)optlen;
- LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE is not supported on that platform");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- #endif
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_INPUTBW>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int64_t val = cast_optval<int64_t>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.llInputBW = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_MININPUTBW>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int64_t val = cast_optval<int64_t>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.llMinInputBW = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_OHEADBW>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int32_t val = cast_optval<int32_t>(optval, optlen);
- if (val < 5 || val > 100)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iOverheadBW = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_SENDER>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bDataSender = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_TSBPDMODE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const bool val = cast_optval<bool>(optval, optlen);
- #ifdef SRT_ENABLE_ENCRYPTION
- if (val == false && co.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM)
- {
- using namespace srt_logging;
- LOGC(aclog.Error, log << "Can't disable TSBPD as long as AES GCM is enabled.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- #endif
- co.bTSBPD = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_LATENCY>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iRcvLatency = val;
- co.iPeerLatency = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_RCVLATENCY>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iRcvLatency = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PEERLATENCY>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iPeerLatency = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_TLPKTDROP>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bTLPktDrop = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_SNDDROPDELAY>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < -1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iSndDropDelay = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PASSPHRASE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- #ifdef SRT_ENABLE_ENCRYPTION
- // Password must be 10-80 characters.
- // Or it can be empty to clear the password.
- if ((optlen != 0) && (optlen < 10 || optlen > HAICRYPT_SECRET_MAX_SZ))
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- memset(&co.CryptoSecret, 0, sizeof(co.CryptoSecret));
- co.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;
- co.CryptoSecret.len = (optlen <= (int)sizeof(co.CryptoSecret.str) ? optlen : (int)sizeof(co.CryptoSecret.str));
- memcpy((co.CryptoSecret.str), optval, co.CryptoSecret.len);
- #else
- (void)co; // prevent warning
- (void)optval;
- if (optlen == 0)
- return; // Allow to set empty passphrase if no encryption supported.
- LOGC(aclog.Error, log << "SRTO_PASSPHRASE: encryption not enabled at compile time");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- #endif
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PBKEYLEN>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- #ifdef SRT_ENABLE_ENCRYPTION
- const int v = cast_optval<int>(optval, optlen);
- int const allowed[4] = {
- 0, // Default value, if this results for initiator, defaults to 16. See below.
- 16, // AES-128
- 24, // AES-192
- 32 // AES-256
- };
- const int *const allowed_end = allowed + 4;
- if (std::find(allowed, allowed_end, v) == allowed_end)
- {
- LOGC(aclog.Error,
- log << "Invalid value for option SRTO_PBKEYLEN: " << v << "; allowed are: 0, 16, 24, 32");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- // Note: This works a little different in HSv4 and HSv5.
- // HSv4:
- // The party that is set SRTO_SENDER will send KMREQ, and it will
- // use default value 16, if SRTO_PBKEYLEN is the default value 0.
- // The responder that receives KMRSP has nothing to say about
- // PBKEYLEN anyway and it will take the length of the key from
- // the initiator (sender) as a good deal.
- //
- // HSv5:
- // The initiator (independently on the sender) will send KMREQ,
- // and as it should be the sender to decide about the PBKEYLEN.
- // Your application should do the following then:
- // 1. The sender should set PBKEYLEN to the required value.
- // 2. If the sender is initiator, it will create the key using
- // its preset PBKEYLEN (or default 16, if not set) and the
- // receiver-responder will take it as a good deal.
- // 3. Leave the PBKEYLEN value on the receiver as default 0.
- // 4. If sender is responder, it should then advertise the PBKEYLEN
- // value in the initial handshake messages (URQ_INDUCTION if
- // listener, and both URQ_WAVEAHAND and URQ_CONCLUSION in case
- // of rendezvous, as it is the matter of luck who of them will
- // eventually become the initiator). This way the receiver
- // being an initiator will set iSndCryptoKeyLen before setting
- // up KMREQ for sending to the sender-responder.
- //
- // Note that in HSv5 if both sides set PBKEYLEN, the responder
- // wins, unless the initiator is a sender (the effective PBKEYLEN
- // will be the one advertised by the responder). If none sets,
- // PBKEYLEN will default to 16.
- co.iSndCryptoKeyLen = v;
- #else
- (void)co; // prevent warning
- (void)optval;
- (void)optlen;
- LOGC(aclog.Error, log << "SRTO_PBKEYLEN: encryption not enabled at compile time");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- #endif
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_NAKREPORT>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bRcvNakReport = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_CONNTIMEO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- using namespace srt::sync;
- co.tdConnTimeOut = milliseconds_from(val);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_DRIFTTRACER>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bDriftTracer = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_LOSSMAXTTL>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iMaxReorderTolerance = cast_optval<int>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_VERSION>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.uSrtVersion = cast_optval<uint32_t>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_MINVERSION>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.uMinimumPeerSrtVersion = cast_optval<uint32_t>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_STREAMID>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- if (size_t(optlen) > CSrtConfig::MAX_SID_LENGTH)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.sStreamName.set((const char*)optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_CONGESTION>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- std::string val;
- if (optlen == -1)
- val = (const char*)optval;
- else
- val.assign((const char*)optval, optlen);
- // Translate alias
- if (val == "vod")
- val = "file";
- bool res = SrtCongestion::exists(val);
- if (!res)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.sCongestion.set(val);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_MESSAGEAPI>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bMessageAPI = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PAYLOADSIZE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- {
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- if (val > SRT_LIVE_MAX_PLSIZE)
- {
- LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << ", maximum payload per MTU.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- if (!co.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 (!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.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- co.zExpPayloadSize = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_TRANSTYPE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- // XXX Note that here the configuration for SRTT_LIVE
- // is the same as DEFAULT VALUES for these fields set
- // in CUDT::CUDT.
- switch (cast_optval<SRT_TRANSTYPE>(optval, optlen))
- {
- case SRTT_LIVE:
- // Default live options:
- // - tsbpd: on
- // - latency: 120ms
- // - linger: off
- // - congctl: live
- // - extraction method: message (reading call extracts one message)
- co.bTSBPD = true;
- co.iRcvLatency = SRT_LIVE_DEF_LATENCY_MS;
- co.iPeerLatency = 0;
- co.bTLPktDrop = true;
- co.iSndDropDelay = 0;
- co.bMessageAPI = true;
- co.bRcvNakReport = true;
- co.iRetransmitAlgo = 1;
- co.zExpPayloadSize = SRT_LIVE_DEF_PLSIZE;
- co.Linger.l_onoff = 0;
- co.Linger.l_linger = 0;
- co.sCongestion.set("live", 4);
- break;
- case SRTT_FILE:
- // File transfer mode:
- // - tsbpd: off
- // - latency: 0
- // - linger: on
- // - congctl: file (original UDT congestion control)
- // - extraction method: stream (reading call extracts as many bytes as available and fits in buffer)
- co.bTSBPD = false;
- co.iRcvLatency = 0;
- co.iPeerLatency = 0;
- co.bTLPktDrop = false;
- co.iSndDropDelay = -1;
- co.bMessageAPI = false;
- co.bRcvNakReport = false;
- co.iRetransmitAlgo = 0;
- co.zExpPayloadSize = 0; // use maximum
- co.Linger.l_onoff = 1;
- co.Linger.l_linger = CSrtConfig::DEF_LINGER_S;
- co.sCongestion.set("file", 4);
- break;
- default:
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- }
- };
- #if ENABLE_BONDING
- template<>
- struct CSrtConfigSetter<SRTO_GROUPCONNECT>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iGroupConnect = cast_optval<int>(optval, optlen);
- }
- };
- #endif
- template<>
- struct CSrtConfigSetter<SRTO_KMREFRESHRATE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- {
- LOGC(aclog.Error,
- log << "SRTO_KMREFRESHRATE=" << val << " can't be negative");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- // Changing the KMREFRESHRATE sets KMPREANNOUNCE to the maximum allowed value
- co.uKmRefreshRatePkt = (unsigned) val;
- if (co.uKmPreAnnouncePkt == 0 && co.uKmRefreshRatePkt == 0)
- return; // Both values are default
- const unsigned km_preanno = co.uKmPreAnnouncePkt == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : co.uKmPreAnnouncePkt;
- const unsigned km_refresh = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt;
- if (co.uKmPreAnnouncePkt == 0 || km_preanno > (km_refresh - 1) / 2)
- {
- co.uKmPreAnnouncePkt = (km_refresh - 1) / 2;
- LOGC(aclog.Warn,
- log << "SRTO_KMREFRESHRATE=0x" << std::hex << km_refresh << ": setting SRTO_KMPREANNOUNCE=0x"
- << std::hex << co.uKmPreAnnouncePkt);
- }
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_KMPREANNOUNCE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- {
- LOGC(aclog.Error,
- log << "SRTO_KMPREANNOUNCE=" << val << " can't be negative");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- const unsigned km_preanno = val == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : val;
- const unsigned kmref = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt;
- if (km_preanno > (kmref - 1) / 2)
- {
- LOGC(aclog.Error,
- log << "SRTO_KMPREANNOUNCE=0x" << std::hex << km_preanno << " exceeds KmRefresh/2, 0x" << ((kmref - 1) / 2)
- << " - OPTION REJECTED.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- co.uKmPreAnnouncePkt = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_ENFORCEDENCRYPTION>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.bEnforcedEnc = cast_optval<bool>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PEERIDLETIMEO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iPeerIdleTimeout_ms = val;
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_IPV6ONLY>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- co.iIpV6Only = cast_optval<int>(optval, optlen);
- }
- };
- template<>
- struct CSrtConfigSetter<SRTO_PACKETFILTER>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- std::string arg((const char*)optval, optlen);
- // Parse the configuration string prematurely
- SrtFilterConfig fc;
- PacketFilter::Factory* fax = 0;
- if (!ParseFilterConfig(arg, (fc), (&fax)))
- {
- LOGC(aclog.Error,
- log << "SRTO_PACKETFILTER: Incorrect syntax. Use: FILTERTYPE[,KEY:VALUE...]. "
- "FILTERTYPE ("
- << fc.type << ") must be installed (or builtin)");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- std::string error;
- if (!fax->verifyConfig(fc, (error)))
- {
- LOGC(aclog.Error, log << "SRTO_PACKETFILTER: Incorrect config: " << error);
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size;
- if (co.zExpPayloadSize > efc_max_payload_size)
- {
- LOGC(aclog.Warn,
- log << "Due to filter-required extra " << fc.extra_size << " bytes, SRTO_PAYLOADSIZE fixed to "
- << efc_max_payload_size << " bytes");
- co.zExpPayloadSize = efc_max_payload_size;
- }
- co.sPacketFilterConfig.set(arg);
- }
- };
- #if ENABLE_BONDING
- template<>
- struct CSrtConfigSetter<SRTO_GROUPMINSTABLETIMEO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- // This option is meaningless for the socket itself.
- // It's set here just for the sake of setting it on a listener
- // socket so that it is then applied on the group when a
- // group connection is configured.
- const int val_ms = cast_optval<int>(optval, optlen);
- const int min_timeo_ms = (int) CSrtConfig::COMM_DEF_MIN_STABILITY_TIMEOUT_MS;
- if (val_ms < min_timeo_ms)
- {
- LOGC(qmlog.Error,
- log << "group option: SRTO_GROUPMINSTABLETIMEO min allowed value is "
- << min_timeo_ms << " ms.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- const int idletmo_ms = co.iPeerIdleTimeout_ms;
- if (val_ms > idletmo_ms)
- {
- LOGC(aclog.Error, log << "group option: SRTO_GROUPMINSTABLETIMEO(" << val_ms
- << ") exceeds SRTO_PEERIDLETIMEO(" << idletmo_ms << ")");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- co.uMinStabilityTimeout_ms = val_ms;
- LOGC(smlog.Error, log << "SRTO_GROUPMINSTABLETIMEO set " << val_ms);
- }
- };
- #endif
- template<>
- struct CSrtConfigSetter<SRTO_RETRANSMITALGO>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- const int val = cast_optval<int>(optval, optlen);
- if (val < 0 || val > 1)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- co.iRetransmitAlgo = val;
- }
- };
- #ifdef ENABLE_AEAD_API_PREVIEW
- template<>
- struct CSrtConfigSetter<SRTO_CRYPTOMODE>
- {
- static void set(CSrtConfig& co, const void* optval, int optlen)
- {
- using namespace srt_logging;
- const int val = cast_optval<int>(optval, optlen);
- #ifdef SRT_ENABLE_ENCRYPTION
- if (val < CSrtConfig::CIPHER_MODE_AUTO || val > CSrtConfig::CIPHER_MODE_AES_GCM)
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- if (val == CSrtConfig::CIPHER_MODE_AES_GCM && !HaiCrypt_IsAESGCM_Supported())
- {
- LOGC(aclog.Error, log << "AES GCM is not supported by the crypto provider.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- if (val == CSrtConfig::CIPHER_MODE_AES_GCM && !co.bTSBPD)
- {
- LOGC(aclog.Error, log << "Enable TSBPD to use AES GCM.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- }
- co.iCryptoMode = val;
- #else
- LOGC(aclog.Error, log << "SRT was built without crypto module.");
- throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
- #endif
- }
- };
- #endif
- int dispatchSet(SRT_SOCKOPT optName, CSrtConfig& co, const void* optval, int optlen)
- {
- switch (optName)
- {
- #define DISPATCH(optname) case optname: CSrtConfigSetter<optname>::set(co, optval, optlen); return 0;
- DISPATCH(SRTO_MSS);
- DISPATCH(SRTO_FC);
- DISPATCH(SRTO_SNDBUF);
- DISPATCH(SRTO_RCVBUF);
- DISPATCH(SRTO_LINGER);
- DISPATCH(SRTO_UDP_SNDBUF);
- DISPATCH(SRTO_UDP_RCVBUF);
- DISPATCH(SRTO_RENDEZVOUS);
- DISPATCH(SRTO_SNDTIMEO);
- DISPATCH(SRTO_RCVTIMEO);
- DISPATCH(SRTO_SNDSYN);
- DISPATCH(SRTO_RCVSYN);
- DISPATCH(SRTO_REUSEADDR);
- DISPATCH(SRTO_MAXBW);
- DISPATCH(SRTO_IPTTL);
- DISPATCH(SRTO_IPTOS);
- DISPATCH(SRTO_BINDTODEVICE);
- DISPATCH(SRTO_INPUTBW);
- DISPATCH(SRTO_MININPUTBW);
- DISPATCH(SRTO_OHEADBW);
- DISPATCH(SRTO_SENDER);
- DISPATCH(SRTO_TSBPDMODE);
- DISPATCH(SRTO_LATENCY);
- DISPATCH(SRTO_RCVLATENCY);
- DISPATCH(SRTO_PEERLATENCY);
- DISPATCH(SRTO_TLPKTDROP);
- DISPATCH(SRTO_SNDDROPDELAY);
- DISPATCH(SRTO_PASSPHRASE);
- DISPATCH(SRTO_PBKEYLEN);
- DISPATCH(SRTO_NAKREPORT);
- DISPATCH(SRTO_CONNTIMEO);
- DISPATCH(SRTO_DRIFTTRACER);
- DISPATCH(SRTO_LOSSMAXTTL);
- DISPATCH(SRTO_VERSION);
- DISPATCH(SRTO_MINVERSION);
- DISPATCH(SRTO_STREAMID);
- DISPATCH(SRTO_CONGESTION);
- DISPATCH(SRTO_MESSAGEAPI);
- DISPATCH(SRTO_PAYLOADSIZE);
- DISPATCH(SRTO_TRANSTYPE);
- #if ENABLE_BONDING
- DISPATCH(SRTO_GROUPCONNECT);
- DISPATCH(SRTO_GROUPMINSTABLETIMEO);
- #endif
- DISPATCH(SRTO_KMREFRESHRATE);
- DISPATCH(SRTO_KMPREANNOUNCE);
- DISPATCH(SRTO_ENFORCEDENCRYPTION);
- DISPATCH(SRTO_PEERIDLETIMEO);
- DISPATCH(SRTO_IPV6ONLY);
- DISPATCH(SRTO_PACKETFILTER);
- DISPATCH(SRTO_RETRANSMITALGO);
- #ifdef ENABLE_AEAD_API_PREVIEW
- DISPATCH(SRTO_CRYPTOMODE);
- #endif
- #ifdef ENABLE_MAXREXMITBW
- DISPATCH(SRTO_MAXREXMITBW);
- #endif
- #undef DISPATCH
- default:
- return -1;
- }
- }
- } // anonymous namespace
- int CSrtConfig::set(SRT_SOCKOPT optName, const void* optval, int optlen)
- {
- return dispatchSet(optName, *this, optval, optlen);
- }
- #if ENABLE_BONDING
- bool SRT_SocketOptionObject::add(SRT_SOCKOPT optname, const void* optval, size_t optlen)
- {
- // Check first if this option is allowed to be set
- // as on a member socket.
- switch (optname)
- {
- case SRTO_BINDTODEVICE:
- case SRTO_CONNTIMEO:
- case SRTO_DRIFTTRACER:
- //SRTO_FC - not allowed to be different among group members
- case SRTO_GROUPMINSTABLETIMEO:
- //SRTO_INPUTBW - per transmission setting
- case SRTO_IPTOS:
- case SRTO_IPTTL:
- case SRTO_KMREFRESHRATE:
- case SRTO_KMPREANNOUNCE:
- //SRTO_LATENCY - per transmission setting
- //SRTO_LINGER - not for managed sockets
- case SRTO_LOSSMAXTTL:
- //SRTO_MAXBW - per transmission setting
- //SRTO_MESSAGEAPI - groups are live mode only
- //SRTO_MINVERSION - per group connection setting
- case SRTO_NAKREPORT:
- //SRTO_OHEADBW - per transmission setting
- //SRTO_PACKETFILTER - per transmission setting
- //SRTO_PASSPHRASE - per group connection setting
- //SRTO_PASSPHRASE - per transmission setting
- //SRTO_PBKEYLEN - per group connection setting
- case SRTO_PEERIDLETIMEO:
- case SRTO_RCVBUF:
- //SRTO_RCVSYN - must be always false in groups
- //SRTO_RCVTIMEO - must be always -1 in groups
- case SRTO_SNDBUF:
- case SRTO_SNDDROPDELAY:
- //SRTO_TLPKTDROP - per transmission setting
- //SRTO_TSBPDMODE - per transmission setting
- case SRTO_UDP_RCVBUF:
- case SRTO_UDP_SNDBUF:
- break;
- default:
- // Other options are not allowed
- return false;
- }
- // Header size will get the size likely aligned, but it won't
- // hurt if the memory size will be up to 4 bytes more than
- // needed - and it's better to not risk that alighment rules
- // will make these calculations result in less space than needed.
- const size_t headersize = sizeof(SingleOption);
- const size_t payload = std::min(sizeof(uint32_t), optlen);
- unsigned char* mem = new unsigned char[headersize + payload];
- SingleOption* option = reinterpret_cast<SingleOption*>(mem);
- option->option = optname;
- option->length = (uint16_t) optlen;
- memcpy(option->storage, optval, optlen);
- options.push_back(option);
- return true;
- }
- #endif
|