pax_global_header00006660000000000000000000000064147131127540014517gustar00rootroot0000000000000052 comment=a8c6b65520f814c5bd8f801be48c33ceece7c4a6 srt-1.5.4/000077500000000000000000000000001471311275400123365ustar00rootroot00000000000000srt-1.5.4/.appveyor.yml000066400000000000000000000021611471311275400150040ustar00rootroot00000000000000configuration: - Release - Debug image: - Visual Studio 2022 - Visual Studio 2019 - Visual Studio 2015 platform: - x64 - x86 build_script: - ps: $VSIMG = $Env:APPVEYOR_BUILD_WORKER_IMAGE; $CNFG = $Env:CONFIGURATION # use a few differing arguments depending on VS version to exercise different options during builds - ps: if ($CNFG -eq "Release") { .\scripts\build-windows.ps1 -STATIC_LINK_SSL ON -BUILD_APPS ON -UNIT_TESTS ON -BONDING ON} - ps: if ($CNFG -eq "Debug") { if ($VSIMG -match '2015') { .\scripts\build-windows.ps1 -STATIC_LINK_SSL ON -BUILD_APPS OFF } else {.\scripts\build-windows.ps1 -STATIC_LINK_SSL ON -BUILD_APPS ON }} test_script: - ps: if ( $Env:RUN_UNIT_TESTS ) { cd ./_build; ctest -E "TestIPv6.v6_calls_v4" --extra-verbose -C $Env:CONFIGURATION; cd ../ } after_build: - cmd: >- scripts/gather-package.bat 7z a SRT-%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%-Win%PLATFORM%-%VS_VERSION%-%APPVEYOR_BUILD_VERSION%.zip %APPVEYOR_BUILD_FOLDER%\package\* appveyor PushArtifact SRT-%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%-Win%PLATFORM%-%VS_VERSION%-%APPVEYOR_BUILD_VERSION%.zip srt-1.5.4/.clang-format000066400000000000000000000055141471311275400147160ustar00rootroot00000000000000Language: Cpp BasedOnStyle: LLVM AccessModifierOffset: -4 # AlignAfterOpenBracket: Align AlignConsecutiveAssignments: true AlignConsecutiveDeclarations: true # AlignEscapedNewlinesLeft: false AlignOperands: true AlignTrailingComments: true # AllowAllArgumentsOnNextLine: true # Requires clang-format v9 and higher # AllowAllConstructorInitializersOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false # AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline # AllowShortIfStatementsOnASingleLine: false # AllowShortLoopsOnASingleLine: false # AlwaysBreakAfterDefinitionReturnType: None # AlwaysBreakAfterReturnType: None # AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: true BinPackArguments: false BinPackParameters: false # BraceWrapping: # AfterClass: false # AfterControlStatement: false # AfterEnum: false # AfterFunction: false # AfterNamespace: false # AfterObjCDeclaration: false # AfterStruct: false # AfterUnion: false # BeforeCatch: false # BeforeElse: false # IndentBraces: false # BreakBeforeBinaryOperators: None BreakBeforeBraces: Allman # BreakInheritanceList: BeforeComma # BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma # BreakAfterJavaFieldAnnotations: false # BreakStringLiterals: true ColumnLimit: 120 # CommentPragmas: '^ IWYU pragma:' # ConstructorInitializerAllOnOneLineOrOnePerLine: false # ConstructorInitializerIndentWidth: 4 # ContinuationIndentWidth: 4 # Cpp11BracedListStyle: true # DerivePointerAlignment: false # DisableFormat: false # ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true # ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] # IncludeIsMainRegex: '$' # IndentCaseLabels: false IndentWidth: 4 # IndentWrappedFunctionNames: false # JavaScriptQuotes: Leave # JavaScriptWrapImports: true # KeepEmptyLinesAtTheStartOfBlocks: true # MacroBlockBegin: '' # MacroBlockEnd: '' # MaxEmptyLinesToKeep: 1 # NamespaceIndentation: None # ObjCBlockIndentWidth: 2 # ObjCSpaceAfterProperty: false # ObjCSpaceBeforeProtocolList: true # PenaltyBreakBeforeFirstCallParameter: 19 # PenaltyBreakComment: 300 # PenaltyBreakFirstLessLess: 120 # PenaltyBreakString: 1000 # PenaltyExcessCharacter: 1000000 # PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left # ReflowComments: true SortIncludes: false # SpaceAfterCStyleCast: false # SpaceAfterTemplateKeyword: true # SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements # SpaceInEmptyParentheses: false # SpacesBeforeTrailingComments: 1 # SpacesInAngles: false # SpacesInContainerLiterals: true # SpacesInCStyleCastParentheses: false # SpacesInParentheses: false # SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 4 UseTab: Never srt-1.5.4/.github/000077500000000000000000000000001471311275400136765ustar00rootroot00000000000000srt-1.5.4/.github/ISSUE_TEMPLATE/000077500000000000000000000000001471311275400160615ustar00rootroot00000000000000srt-1.5.4/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000012101471311275400205450ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: "[BUG]" labels: 'Type: Bug' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Configure '...' 2. Run '....' 3. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please provide the following information):** - OS: [e.g. Windows, Linux, macOS,...] - SRT Version / commit ID: **Additional context** Add any other context about the problem here. srt-1.5.4/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000012261471311275400216070ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: "[FR]" labels: 'Type: Enhancement' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. For example: "When I try to do X, I am blocked by Y..." **Describe the solution you'd like** A clear and concise description of how you would like to see this feature implemented. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. srt-1.5.4/.github/ISSUE_TEMPLATE/question.md000066400000000000000000000005701471311275400202540ustar00rootroot00000000000000--- name: Question about: Ask a question regarding SRT title: '' labels: 'Type: Question' assignees: '' --- When asking a question please also include where you looked for an answer (so we can update the documentation if needed). You are encouraged to ask general questions regarding SRT in the [SRT Alliance Slack channel](https://slackin-srtalliance.azurewebsites.net/). srt-1.5.4/.github/workflows/000077500000000000000000000000001471311275400157335ustar00rootroot00000000000000srt-1.5.4/.github/workflows/abi.yml000066400000000000000000000034641471311275400172200ustar00rootroot00000000000000name: ABI checks on: push: branches: [ master ] pull_request: branches: [ master ] env: SRT_BASE: v1.5.0 jobs: build: name: ABI checks runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 with: path: pull_request - name: configure run: | cd pull_request mkdir _build && cd _build cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITTESTS=ON ../ - name: build run: | sudo apt install -y abi-dumper cd pull_request/_build && cmake --build ./ make install DESTDIR=./installdir SRT_TAG_VERSION=$(cat version.h |grep SRT_VERSION_MINOR |head -n1 |awk {'print $3'}) abi-dumper libsrt.so -o libsrt-pr.dump -public-headers installdir/usr/local/include/srt/ -lver 0 SRT_BASE="v1.$SRT_TAG_VERSION.0" echo "SRT_BASE=$SRT_BASE" >> "$GITHUB_ENV" - uses: actions/checkout@v3 with: path: tag ref: ${{ env.SRT_BASE }} - name: configure_tag run: | echo $SRT_TAG_VERSION cd tag mkdir _build && cd _build cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITTESTS=ON ../ - name: build_tag run: | cd tag cd _build && cmake --build ./ make install DESTDIR=./installdir abi-dumper libsrt.so -o libsrt-tag.dump -public-headers installdir/usr/local/include/srt/ -lver 1 - name: abi-check run: | git clone https://github.com/lvc/abi-compliance-checker.git cd abi-compliance-checker && sudo make install && cd ../ abi-compliance-checker -l libsrt -old tag/_build/libsrt-tag.dump -new pull_request/_build/libsrt-pr.dump RES=$? if (( $RES != 0 )) then echo "ABI/API Compatibility check failed with value $?" exit $RES fi srt-1.5.4/.github/workflows/android.yaml000066400000000000000000000010341471311275400202350ustar00rootroot00000000000000name: Android on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: name: NDK-R23 runs-on: ubuntu-20.04 steps: - name: Setup Android NDK R23 uses: nttld/setup-ndk@v1 id: setup-ndk with: ndk-version: r23 add-to-path: false - uses: actions/checkout@v3 - name: build run: | cd ./scripts/build-android/ echo ${{ steps.setup-ndk.outputs.ndk-path }} source ./build-android -n ${{ steps.setup-ndk.outputs.ndk-path }} srt-1.5.4/.github/workflows/codeql.yml000066400000000000000000000017011471311275400177240ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [ "master", "experimental/socket-groups" ] pull_request: branches: [ "master" ] jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ cpp ] steps: - name: Checkout uses: actions/checkout@v3 - name: Configure run: cmake -DENABLE_HEAVY_LOGGING=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-fpermissive -DENABLE_BONDING=1 . - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Build run: | make - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" srt-1.5.4/.github/workflows/cxx11-macos.yaml000066400000000000000000000011331471311275400206610ustar00rootroot00000000000000name: cxx11 on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: name: macos runs-on: macos-latest steps: - name: GoogleTest run: brew install googletest - uses: actions/checkout@v3 - name: configure run: | mkdir _build && cd _build cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DUSE_CXX_STD=14 - name: build run: cd _build && cmake --build ./ - name: test run: cd _build && ctest --extra-verbose srt-1.5.4/.github/workflows/cxx11-ubuntu.yaml000066400000000000000000000027321471311275400211070ustar00rootroot00000000000000name: cxx11 on: push: branches: [ master ] pull_request: branches: [ master ] types: [opened, synchronize, reopened] jobs: build: name: ubuntu runs-on: ubuntu-20.04 env: BUILD_WRAPPER_OUT_DIR: sonar-output # Directory where build-wrapper output will be placed steps: - uses: actions/checkout@v3 - name: Install sonar-scanner and build-wrapper uses: sonarsource/sonarcloud-github-c-cpp@v2 - name: configure run: | mkdir _build && cd _build cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=ON -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DENABLE_CODE_COVERAGE=ON - name: build run: cd _build && build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build . - name: test run: | cd _build && ctest --extra-verbose - name: codecov run: | source ./scripts/collect-gcov.sh bash <(curl -s https://codecov.io/bash) - name: Run SonarCloud Scan for C and C++ if: ${{ !github.event.pull_request.head.repo.fork }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} # Consult https://docs.sonarcloud.io/advanced-setup/ci-based-analysis/sonarscanner-cli/ for more information and options. run: sonar-scanner --define sonar.cfamily.build-wrapper-output=_build/"${{ env.BUILD_WRAPPER_OUT_DIR }}" srt-1.5.4/.github/workflows/cxx11-win.yaml000066400000000000000000000011451471311275400203570ustar00rootroot00000000000000name: cxx11 on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: name: windows runs-on: windows-latest steps: - uses: actions/checkout@v3 - name: configure run: | md _build && cd _build cmake ../ -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DUSE_CXX_STD=c++11 - name: build run: cd _build && cmake --build ./ --config Release --verbose - name: test run: cd _build && ctest -E "TestIPv6.v6_calls_v4|TestConnectionTimeout.BlockingLoop" --extra-verbose -C Release srt-1.5.4/.github/workflows/iOS.yaml000066400000000000000000000010671471311275400173150ustar00rootroot00000000000000name: iOS on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: strategy: matrix: cxxstdsync: [OFF, ON] name: iOS-cxxsync${{ matrix.cxxstdsync }} runs-on: macos-latest steps: - uses: actions/checkout@v3 - name: configure run: | mkdir _build && cd _build cmake ../ -DENABLE_ENCRYPTION=OFF -DENABLE_STDCXX_SYNC=${{matrix.cxxstdsync}} -DENABLE_UNITTESTS=OFF -DENABLE_BONDING=ON --toolchain scripts/iOS.cmake - name: build run: cd _build && cmake --build ./ srt-1.5.4/.github/workflows/s390x-focal.yaml000066400000000000000000000022361471311275400205720ustar00rootroot00000000000000name: QEMU to run s390x-focal on: push: branches: [ master ] pull_request: branches: [ master ] jobs: Tests: runs-on: ubuntu-latest steps: - name: Setup multiarch/qemu-user-static run: | docker run --rm --privileged multiarch/qemu-user-static:register --reset - name: ubuntu-core:s390x-focal uses: docker://multiarch/ubuntu-core:s390x-focal with: args: > bash -c "uname -a && lscpu | grep Endian " - name: Checkout uses: actions/checkout@v3 - name: configure uses: docker://multiarch/ubuntu-core:s390x-focal with: args: > bash -c "apt-get -y update && export DEBIAN_FRONTEND=noninteractive && export TZ=Etc/UTC && apt-get -y install tzdata && uname -a && lscpu | grep Endian && apt-get -y install cmake g++ libssl-dev git && mkdir _build && cd _build && cmake ../ -DENABLE_ENCRYPTION=ON -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON && cmake --build ./ && ./test-srt -disable-ipv6" srt-1.5.4/.gitignore000066400000000000000000000007741471311275400143360ustar00rootroot00000000000000# Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # Ignore any folder starting from underscore _*/ # Ignode Visual Studio Code temp folder .vs/ .vscode/ # Ignore vcpkg submodule vcpkg/ # LSP compile_commands.json # ignore files generated by clion and cmake .idea/ cmake-build-debug/ srt-1.5.4/.lgtm.yml000066400000000000000000000001551471311275400141030ustar00rootroot00000000000000extraction: cpp: configure: command: - cmake . -DENABLE_HEAVY_LOGGING=1 -DENABLE_BONDING=1 srt-1.5.4/.travis.yml000066400000000000000000000054111471311275400144500ustar00rootroot00000000000000language: cpp dist: xenial addons: apt: packages: - tclsh - pkg-config - cmake - libssl-dev - build-essential - libmbedtls-dev - gdb homebrew: update: false packages: - openssl matrix: include: - os: linux env: - BUILD_TYPE=Debug - BUILD_OPTS='-DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS="-Werror"' - env: - BUILD_TYPE=Debug - BUILD_OPTS='-DENABLE_LOGGING=OFF -DUSE_ENCLIB=mbedtls -DENABLE_MONOTONIC_CLOCK=ON -DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS="-Werror"' - os: linux env: BUILD_TYPE=Release - os: osx osx_image: xcode11.1 env: - BUILD_TYPE=Debug - BUILD_OPTS='-DCMAKE_CXX_FLAGS="-Werror"' - os: osx osx_image: xcode11.1 env: - BUILD_TYPE=Release - BUILD_OPTS='-DCMAKE_CXX_FLAGS="-Werror"' - os: linux compiler: x86_64-w64-mingw32-g++ addons: apt: packages: - gcc-mingw-w64-base - binutils-mingw-w64-x86-64 - gcc-mingw-w64-x86-64 - gcc-mingw-w64 - g++-mingw-w64-x86-64 before_script: - git clone -b OpenSSL_1_1_1g https://github.com/openssl/openssl.git openssl - cd openssl - ./Configure --cross-compile-prefix=x86_64-w64-mingw32- mingw64 - make - cd .. env: BUILD_TYPE=Release # Power jobs - os: linux arch: ppc64le env: - BUILD_TYPE=Debug - arch: ppc64le env: - BUILD_TYPE=Release - BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON' script: - if [ "$TRAVIS_COMPILER" == "x86_64-w64-mingw32-g++" ]; then export CC="x86_64-w64-mingw32-gcc"; export CXX="x86_64-w64-mingw32-g++"; cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS="OFF" -DUSE_OPENSSL_PC="OFF" -DOPENSSL_ROOT_DIR="$PWD/openssl" -DCMAKE_SYSTEM_NAME="Windows"; elif [ "$TRAVIS_OS_NAME" == "linux" ]; then cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS="ON"; elif [ "$TRAVIS_OS_NAME" == "osx" ]; then export PKG_CONFIG_PATH=$(brew --prefix openssl)"/lib/pkgconfig"; cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS="ON"; fi - make -j$(nproc); - if [ "$TRAVIS_COMPILER" != "x86_64-w64-mingw32-g++" ]; then ulimit -c unlimited; ./test-srt -disable-ipv6; SUCCESS=$?; if [ -f core ]; then gdb -batch ./test-srt -c core -ex bt -ex "info thread" -ex quit; else echo "NO CORE - NO CRY!"; fi; test $SUCCESS == 0; fi srt-1.5.4/CMakeLists.txt000066400000000000000000001510351471311275400151030ustar00rootroot00000000000000# # 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/. # cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR) set (SRT_VERSION 1.5.4) set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts") include(haiUtil) # needed for set_version_variables # CMake version 3.0 introduced the VERSION option of the project() command # to specify a project version as well as the name. if(${CMAKE_VERSION} VERSION_LESS "3.0.0") project(SRT C CXX) # Sets SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH set_version_variables(SRT_VERSION ${SRT_VERSION}) else() cmake_policy(SET CMP0048 NEW) # Also sets SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH project(SRT VERSION ${SRT_VERSION} LANGUAGES C CXX) endif() if (NOT ${CMAKE_VERSION} VERSION_LESS "3.28.1") cmake_policy(SET CMP0054 NEW) endif () include(FindPkgConfig) # XXX See 'if (MINGW)' condition below, may need fixing. include(FindThreads) include(CheckFunctionExists) # Platform shortcuts string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSNAME_LC) set_if(DARWIN (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") OR (${CMAKE_SYSTEM_NAME} MATCHES "iOS") OR (${CMAKE_SYSTEM_NAME} MATCHES "tvOS") OR (${CMAKE_SYSTEM_NAME} MATCHES "watchOS") OR (${CMAKE_SYSTEM_NAME} MATCHES "visionOS")) set_if(LINUX ${CMAKE_SYSTEM_NAME} MATCHES "Linux") set_if(BSD ${SYSNAME_LC} MATCHES "bsd$") set_if(MICROSOFT WIN32 AND (NOT MINGW AND NOT CYGWIN)) set_if(GNU ${CMAKE_SYSTEM_NAME} MATCHES "GNU") set_if(ANDROID ${SYSNAME_LC} MATCHES "android") set_if(SUNOS "${SYSNAME_LC}" MATCHES "sunos") set_if(POSIX LINUX OR DARWIN OR BSD OR SUNOS OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX)) set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR SUNOS OR CYGWIN OR GNU) set_if(NEED_DESTINATION ${CMAKE_VERSION} VERSION_LESS "3.14.0") include(GNUInstallDirs) # The CMAKE_BUILD_TYPE seems not to be always set, weird. if (NOT DEFINED ENABLE_DEBUG) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set (ENABLE_DEBUG ON) else() set (ENABLE_DEBUG OFF) endif() endif() # XXX This is a kind of workaround - this part to set the build # type and associated other flags should not be done for build # systems (cmake generators) that generate a multi-configuration # build definition. At least it is known that MSVC does it and it # sets _DEBUG and NDEBUG flags itself, so this shouldn't be done # at all in this case. if (NOT MICROSOFT) # Set CMAKE_BUILD_TYPE properly, now that you know # that ENABLE_DEBUG is set as it should. if (ENABLE_DEBUG EQUAL 2) set (CMAKE_BUILD_TYPE "RelWithDebInfo") if (ENABLE_ASSERT) # Add _DEBUG macro if explicitly requested, to enable SRT_ASSERT(). add_definitions(-D_DEBUG) else() add_definitions(-DNDEBUG) endif() elseif (ENABLE_DEBUG) # 1, ON, YES, TRUE, Y, or any other non-zero number set (CMAKE_BUILD_TYPE "Debug") # Add _DEBUG macro in debug mode only, to enable SRT_ASSERT(). add_definitions(-D_DEBUG) else() set (CMAKE_BUILD_TYPE "Release") add_definitions(-DNDEBUG) endif() endif() message(STATUS "BUILD TYPE: ${CMAKE_BUILD_TYPE}") getVarsWith(ENFORCE_ enforcers) foreach(ef ${enforcers}) set (val ${${ef}}) if (NOT val STREQUAL "") set(val =${val}) endif() string(LENGTH ENFORCE_ pflen) string(LENGTH ${ef} eflen) math(EXPR alen ${eflen}-${pflen}) string(SUBSTRING ${ef} ${pflen} ${alen} ef) message(STATUS "FORCED PP VARIABLE: ${ef}${val}") add_definitions(-D${ef}${val}) endforeach() # NOTE: Known options you can change using ENFORCE_ variables: # SRT_ENABLE_ECN 1 /* Early Congestion Notification (for source bitrate control) */ # SRT_DEBUG_TSBPD_OUTJITTER 1 /* Packet Delivery histogram */ # SRT_DEBUG_TRACE_DRIFT 1 /* Create a trace log for Encoder-Decoder Clock Drift */ # SRT_DEBUG_TSBPD_WRAP 1 /* Debug packet timestamp wraparound */ # SRT_DEBUG_TLPKTDROP_DROPSEQ 1 # SRT_DEBUG_SNDQ_HIGHRATE 1 # SRT_DEBUG_BONDING_STATES 1 # SRT_DEBUG_RTT 1 /* RTT trace */ # SRT_MAVG_SAMPLING_RATE 40 /* Max sampling rate */ # SRT_ENABLE_FREQUENT_LOG_TRACE 0 : set to 1 to enable printing reason for suppressed freq logs # option defaults set(ENABLE_HEAVY_LOGGING_DEFAULT OFF) # Always turn logging on if the build type is debug if (ENABLE_DEBUG) set(ENABLE_HEAVY_LOGGING_DEFAULT ON) endif() # Note that the IP_PKTINFO has a limited portability and may not work on some platforms # (Windows, FreeBSD, ...). set (ENABLE_PKTINFO_DEFAULT OFF) set(ENABLE_STDCXX_SYNC_DEFAULT OFF) set(ENABLE_MONOTONIC_CLOCK_DEFAULT OFF) set(MONOTONIC_CLOCK_LINKLIB "") if (MICROSOFT) set(ENABLE_STDCXX_SYNC_DEFAULT ON) elseif (POSIX) test_requires_clock_gettime(ENABLE_MONOTONIC_CLOCK_DEFAULT MONOTONIC_CLOCK_LINKLIB) endif() # options option(CYGWIN_USE_POSIX "Should the POSIX API be used for cygwin. Ignored if the system isn't cygwin." OFF) if (CMAKE_CXX_COMPILER_ID MATCHES "^GNU$" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) option(ENABLE_CXX11 "Should the c++11 parts (srt-live-transmit) be enabled" OFF) else() option(ENABLE_CXX11 "Should the c++11 parts (srt-live-transmit) be enabled" ON) endif() option(ENABLE_APPS "Should the Support Applications be Built?" ON) option(ENABLE_BONDING "Should the bonding functionality be enabled?" OFF) option(ENABLE_TESTING "Should the Developer Test Applications be Built?" OFF) option(ENABLE_PROFILE "Should instrument the code for profiling. Ignored for non-GNU compiler." $ENV{HAI_BUILD_PROFILE}) option(ENABLE_LOGGING "Should logging be enabled" ON) option(ENABLE_HEAVY_LOGGING "Should heavy debug logging be enabled" ${ENABLE_HEAVY_LOGGING_DEFAULT}) option(ENABLE_HAICRYPT_LOGGING "Should logging in haicrypt be enabled" 0) option(ENABLE_SHARED "Should libsrt be built as a shared library" ON) option(ENABLE_STATIC "Should libsrt be built as a static library" ON) option(ENABLE_PKTINFO "Enable using IP_PKTINFO to allow the listener extracting the target IP address from incoming packets" ${ENABLE_PKTINFO_DEFAULT}) option(ENABLE_RELATIVE_LIBPATH "Should application contain relative library paths, like ../lib" OFF) option(ENABLE_GETNAMEINFO "In-logs sockaddr-to-string should do rev-dns" OFF) option(ENABLE_UNITTESTS "Enable unit tests" OFF) option(ENABLE_ENCRYPTION "Enable encryption in SRT" ON) option(ENABLE_AEAD_API_PREVIEW "Enable AEAD API preview in SRT" Off) option(ENABLE_MAXREXMITBW "Enable SRTO_MAXREXMITBW (v1.6.0 API preview)" Off) option(ENABLE_CXX_DEPS "Extra library dependencies in srt.pc for the CXX libraries useful with C language" ON) option(USE_STATIC_LIBSTDCXX "Should use static rather than shared libstdc++" OFF) option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON) option(ENABLE_CODE_COVERAGE "Enable code coverage reporting" OFF) option(ENABLE_MONOTONIC_CLOCK "Enforced clock_gettime with monotonic clock on GC CV" ${ENABLE_MONOTONIC_CLOCK_DEFAULT}) option(ENABLE_STDCXX_SYNC "Use C++11 chrono and threads for timing instead of pthreads" ${ENABLE_STDCXX_SYNC_DEFAULT}) option(USE_OPENSSL_PC "Use pkg-config to find OpenSSL libraries" ON) option(OPENSSL_USE_STATIC_LIBS "Link OpenSSL libraries statically." OFF) option(USE_BUSY_WAITING "Enable more accurate sending times at a cost of potentially higher CPU load" OFF) option(USE_GNUSTL "Get c++ library/headers from the gnustl.pc" OFF) option(ENABLE_SOCK_CLOEXEC "Enable setting SOCK_CLOEXEC on a socket" ON) option(ENABLE_SHOW_PROJECT_CONFIG "Enable show Project Configuration" OFF) option(ENABLE_CLANG_TSA "Enable Clang Thread Safety Analysis" OFF) # NOTE: Use ATOMIC_USE_SRT_SYNC_MUTEX and will override the auto-detection of the # Atomic implemetation in srtcore/atomic.h. option(ATOMIC_USE_SRT_SYNC_MUTEX "Use srt::sync::Mutex to Implement Atomics" OFF) if (ATOMIC_USE_SRT_SYNC_MUTEX) add_definitions(-DATOMIC_USE_SRT_SYNC_MUTEX=1) endif() set(TARGET_srt "srt" CACHE STRING "The name for the SRT library") # Use application-defined group reader # (currently the only one implemented) add_definitions(-DSRT_ENABLE_APP_READER) # XXX This was added once as experimental, it is now in force for # write-blocking-mode sockets. Still unclear if all issues around # closing while data still not written are eliminated. add_definitions(-DSRT_ENABLE_CLOSE_SYNCH) if (NOT ENABLE_LOGGING) set (ENABLE_HEAVY_LOGGING OFF) message(STATUS "LOGGING: DISABLED") else() if (ENABLE_HEAVY_LOGGING) message(STATUS "LOGGING: HEAVY") else() message(STATUS "LOGGING: ENABLED") endif() endif() if (USE_BUSY_WAITING) message(STATUS "USE_BUSY_WAITING: ON") list(APPEND SRT_EXTRA_CFLAGS "-DUSE_BUSY_WAITING=1") else() message(STATUS "USE_BUSY_WAITING: OFF (default)") endif() # Reduce the frequency of some frequent logs, milliseconds set(SRT_LOG_SLOWDOWN_FREQ_MS_DEFAULT 1000) # 1s if (NOT DEFINED SRT_LOG_SLOWDOWN_FREQ_MS) if (ENABLE_HEAVY_LOGGING) set(SRT_LOG_SLOWDOWN_FREQ_MS 0) # Just show every log message. else() set(SRT_LOG_SLOWDOWN_FREQ_MS ${SRT_LOG_SLOWDOWN_FREQ_MS_DEFAULT}) endif() endif() if ( CYGWIN AND NOT CYGWIN_USE_POSIX ) set(WIN32 1) set(CMAKE_LEGACY_CYGWIN_WIN32 1) add_definitions(-DWIN32=1 -DCYGWIN=1) message(STATUS "HAVE CYGWIN. Setting backward compat CMAKE_LEGACY_CYGWIN_WIN32 and -DWIN32") endif() if (NOT USE_ENCLIB) if (USE_GNUTLS) message("NOTE: USE_GNUTLS is deprecated. Use -DUSE_ENCLIB=gnutls instead.") set (USE_ENCLIB gnutls) else() set (USE_ENCLIB openssl-evp) endif() endif() set(USE_ENCLIB "${USE_ENCLIB}" CACHE STRING "The crypto library that SRT uses") set_property(CACHE USE_ENCLIB PROPERTY STRINGS "openssl" "openssl-evp" "gnutls" "mbedtls" "botan") # Make sure DLLs and executabes go to the same path regardles of subdirectory set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) if (NOT DEFINED WITH_COMPILER_TYPE) # This is for a case when you provided the prefix, but you didn't # provide compiler type. This option is in this form predicted to work # only on POSIX systems. Just typical compilers for Linux and Mac are # included. if (DARWIN) set (WITH_COMPILER_TYPE clang) elseif (POSIX) # Posix, but not DARWIN set(WITH_COMPILER_TYPE gcc) else() get_filename_component(WITH_COMPILER_TYPE ${CMAKE_C_COMPILER} NAME) endif() set (USING_DEFAULT_COMPILER_PREFIX 1) endif() if (NOT USING_DEFAULT_COMPILER_PREFIX OR DEFINED WITH_COMPILER_PREFIX) message(STATUS "Handling compiler with PREFIX=${WITH_COMPILER_PREFIX} TYPE=${WITH_COMPILER_TYPE}") parse_compiler_type(${WITH_COMPILER_TYPE} COMPILER_TYPE COMPILER_SUFFIX) if (${COMPILER_TYPE} STREQUAL gcc) set (CMAKE_C_COMPILER ${WITH_COMPILER_PREFIX}gcc${COMPILER_SUFFIX}) set (CMAKE_CXX_COMPILER ${WITH_COMPILER_PREFIX}g++${COMPILER_SUFFIX}) set (HAVE_COMPILER_GNU_COMPAT 1) elseif (${COMPILER_TYPE} STREQUAL cc) set (CMAKE_C_COMPILER ${WITH_COMPILER_PREFIX}cc${COMPILER_SUFFIX}) set (CMAKE_CXX_COMPILER ${WITH_COMPILER_PREFIX}c++${COMPILER_SUFFIX}) set (HAVE_COMPILER_GNU_COMPAT 1) elseif (${COMPILER_TYPE} STREQUAL icc) set (CMAKE_C_COMPILER ${WITH_COMPILER_PREFIX}icc${COMPILER_SUFFIX}) set (CMAKE_CXX_COMPILER ${WITH_COMPILER_PREFIX}icpc${COMPILER_SUFFIX}) set (HAVE_COMPILER_GNU_COMPAT 1) else() # Use blindly for C compiler and ++ for C++. # At least this matches clang. set (CMAKE_C_COMPILER ${WITH_COMPILER_PREFIX}${WITH_COMPILER_TYPE}) set (CMAKE_CXX_COMPILER ${WITH_COMPILER_PREFIX}${COMPILER_TYPE}++${COMPILER_SUFFIX}) if (${COMPILER_TYPE} STREQUAL clang) set (HAVE_COMPILER_GNU_COMPAT 1) endif() endif() message(STATUS "Compiler type: ${WITH_COMPILER_TYPE}. C: ${CMAKE_C_COMPILER}; C++: ${CMAKE_CXX_COMPILER}") unset(USING_DEFAULT_COMPILER_PREFIX) else() message(STATUS "No WITH_COMPILER_PREFIX - using C++ compiler ${CMAKE_CXX_COMPILER}") endif() if (DEFINED WITH_SRT_TARGET) set (TARGET_haisrt ${WITH_SRT_TARGET}) endif() # When you use crosscompiling, you have to take care that PKG_CONFIG_PATH # and CMAKE_PREFIX_PATH are set properly. # symbol exists in win32, but function does not. if(WIN32) if(ENABLE_INET_PTON) set(CMAKE_REQUIRED_LIBRARIES ws2_32) check_function_exists(inet_pton HAVE_INET_PTON) try_compile(AT_LEAST_VISTA ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/scripts/test_vista.c") if(NOT AT_LEAST_VISTA) # force targeting Vista add_definitions(-D_WIN32_WINNT=0x0600) endif() else() add_definitions(-D_WIN32_WINNT=0x0501) endif() else() check_function_exists(inet_pton HAVE_INET_PTON) endif() if (DEFINED HAVE_INET_PTON) add_definitions(-DHAVE_INET_PTON=1) endif() # Defines HAVE_PTHREAD_GETNAME_* and HAVE_PTHREAD_SETNAME_* include(FindPThreadGetSetName) FindPThreadGetSetName() if (ENABLE_MONOTONIC_CLOCK) if (NOT ENABLE_MONOTONIC_CLOCK_DEFAULT) message(FATAL_ERROR "Your platform does not support CLOCK_MONOTONIC. Build with -DENABLE_MONOTONIC_CLOCK=OFF.") endif() set (WITH_EXTRALIBS "${WITH_EXTRALIBS} ${MONOTONIC_CLOCK_LINKLIB}") add_definitions(-DENABLE_MONOTONIC_CLOCK=1) endif() if (ENABLE_ENCRYPTION) if ("${USE_ENCLIB}" STREQUAL "gnutls") set (SSL_REQUIRED_MODULES "gnutls nettle") if (WIN32) if (MINGW) set (SSL_REQUIRED_MODULES "${SSL_REQUIRED_MODULES} zlib") endif() endif() pkg_check_modules (SSL REQUIRED ${SSL_REQUIRED_MODULES}) add_definitions( -DUSE_GNUTLS=1 ) link_directories( ${SSL_LIBRARY_DIRS} ) elseif ("${USE_ENCLIB}" STREQUAL "mbedtls") add_definitions(-DUSE_MBEDTLS=1) if ("${SSL_LIBRARY_DIRS}" STREQUAL "") set(MBEDTLS_PREFIX "${CMAKE_PREFIX_PATH}" CACHE PATH "The path of mbedtls") find_package(MbedTLS REQUIRED) set (SSL_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR}) set (SSL_LIBRARIES ${MBEDTLS_LIBRARIES}) endif() if (WIN32) set (SSL_LIBRARIES ${SSL_LIBRARIES} bcrypt) endif() if ("${SSL_LIBRARIES}" STREQUAL "") set (SSL_LIBRARIES mbedtls mbedcrypto) endif() message(STATUS "SSL enforced mbedtls: -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") foreach(LIB ${SSL_LIBRARIES}) if(IS_ABSOLUTE ${LIB} AND EXISTS ${LIB}) set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${LIB}) else() set(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} "-l${LIB}") endif() endforeach() elseif ("${USE_ENCLIB}" STREQUAL "openssl-evp") # Openssl-EVP requires CRYSPR2 add_definitions(-DUSE_OPENSSL_EVP=1 -DCRYSPR2) set (SSL_REQUIRED_MODULES "openssl libcrypto") # Try using pkg-config method first if enabled, # fall back to find_package method otherwise if (USE_OPENSSL_PC) pkg_check_modules(SSL ${SSL_REQUIRED_MODULES}) if (OPENSSL_USE_STATIC_LIBS) # use `pkg-config --static xxx` found libs set(SSL_LIBRARIES ${SSL_STATIC_LIBRARIES}) endif() endif() if (SSL_FOUND) # We have some cases when pkg-config is improperly configured # When it doesn't ship the -L and -I options, and the CMAKE_PREFIX_PATH # is set (also through `configure`), then we have this problem. If so, # set forcefully the -I and -L contents to prefix/include and # prefix/lib. if ("${SSL_LIBRARY_DIRS}" STREQUAL "") if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") message(STATUS "WARNING: pkg-config has incorrect prefix - enforcing target path prefix: ${CMAKE_PREFIX_PATH}") set (SSL_LIBRARY_DIRS ${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}) set (SSL_INCLUDE_DIRS ${CMAKE_PREFIX_PATH}/include) endif() endif() link_directories( ${SSL_LIBRARY_DIRS} ) message(STATUS "SSL via pkg-config: -L ${SSL_LIBRARY_DIRS} -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") else() find_package(OpenSSL REQUIRED) set (SSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR}) set (SSL_LIBRARIES ${OPENSSL_LIBRARIES}) message(STATUS "SSL via find_package(OpenSSL): -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") endif() elseif ("${USE_ENCLIB}" STREQUAL "botan") add_definitions(-DUSE_BOTAN=1 -DCRYSPR2) set (SSL_REQUIRED_MODULES "botan") find_package(Botan 3.0.0 REQUIRED) botan_generate( botan ffi nist_keywrap aes_armv8 aes_ni aes_power8 aes_vperm idea_sse2 serpent_avx2 shacal2_armv8 shacal2_avx2 shacal2_x86 sm4_armv8 rdseed sha1_armv8 sha1_sse2 sha1_x86 sha2_32_armv8 sha2_32_bmi2 sha2_32_x86 sha2_64_bmi2 sha3_bmi2 zfec_sse2 zfec_vperm argon2_avx2 argon2_ssse3 processor_rng chacha_avx2 ghash_cpu ghash_vperm simd simd_avx2) target_compile_features("botan" PRIVATE "cxx_std_20") set (SSL_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) set (SSL_LIBRARIES "botan") else() # openssl # Openssl (Direct-AES API) can use CRYSPR2 add_definitions(-DUSE_OPENSSL=1 -DCRYSPR2) set (SSL_REQUIRED_MODULES "openssl libcrypto") # Try using pkg-config method first if enabled, # fall back to find_package method otherwise if (USE_OPENSSL_PC) pkg_check_modules(SSL ${SSL_REQUIRED_MODULES}) endif() if (SSL_FOUND) # We have some cases when pkg-config is improperly configured # When it doesn't ship the -L and -I options, and the CMAKE_PREFIX_PATH # is set (also through `configure`), then we have this problem. If so, # set forcefully the -I and -L contents to prefix/include and # prefix/lib. if ("${SSL_LIBRARY_DIRS}" STREQUAL "") if (NOT "${CMAKE_PREFIX_PATH}" STREQUAL "") message(STATUS "WARNING: pkg-config has incorrect prefix - enforcing target path prefix: ${CMAKE_PREFIX_PATH}") set (SSL_LIBRARY_DIRS ${CMAKE_PREFIX_PATH}/${CMAKE_INSTALL_LIBDIR}) set (SSL_INCLUDE_DIRS ${CMAKE_PREFIX_PATH}/include) endif() endif() link_directories( ${SSL_LIBRARY_DIRS} ) message(STATUS "SSL via pkg-config: -L ${SSL_LIBRARY_DIRS} -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") else() find_package(OpenSSL REQUIRED) set (SSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR}) set (SSL_LIBRARIES ${OPENSSL_LIBRARIES}) message(STATUS "SSL via find_package(OpenSSL): -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}") endif() endif() add_definitions(-DSRT_ENABLE_ENCRYPTION) message(STATUS "ENCRYPTION: ENABLED, using: ${SSL_REQUIRED_MODULES}") message (STATUS "SSL libraries: ${SSL_LIBRARIES}") if (ENABLE_AEAD_API_PREVIEW) if (("${USE_ENCLIB}" STREQUAL "openssl-evp") OR ("${USE_ENCLIB}" STREQUAL "botan")) add_definitions(-DENABLE_AEAD_API_PREVIEW) message(STATUS "ENCRYPTION AEAD API: ENABLED") else() message(FATAL_ERROR "ENABLE_AEAD_API_PREVIEW is only available with USE_ENCLIB=[openssl-evp | botan]!") endif() else() message(STATUS "ENCRYPTION AEAD API: DISABLED") endif() else() message(STATUS "ENCRYPTION: DISABLED") message(STATUS "ENCRYPTION AEAD API: N/A") endif() if (USE_GNUSTL) pkg_check_modules (GNUSTL REQUIRED gnustl) link_directories(${GNUSTL_LIBRARY_DIRS}) include_directories(${GNUSTL_INCLUDE_DIRS}) set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) endif() if (ENABLE_MAXREXMITBW) add_definitions(-DENABLE_MAXREXMITBW) message(STATUS "MAXREXMITBW API: ENABLED") else() message(STATUS "MAXREXMITBW API: DISABLED") endif() if (USING_DEFAULT_COMPILER_PREFIX) # Detect if the compiler is GNU compatible for flags if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Intel|Clang|AppleClang") message(STATUS "COMPILER: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER}) - GNU compat") set(HAVE_COMPILER_GNU_COMPAT 1) # See https://gcc.gnu.org/projects/cxx-status.html # At the bottom there's information about C++98, which is default up to 6.1 version. # For all other compilers - including Clang - we state that the default C++ standard is AT LEAST 11. if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU AND ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 6.1) message(STATUS "NOTE: GCC ${CMAKE_CXX_COMPILER_VERSION} is detected with default C++98. Forcing C++11 on applications.") set (FORCE_CXX_STANDARD 1) elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang|AppleClang") message(STATUS "NOTE: CLANG ${CMAKE_CXX_COMPILER_VERSION} detected, unsure if >=C++11 is default, forcing C++11 on applications") set (FORCE_CXX_STANDARD 1) else() message(STATUS "NOTE: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION} - assuming default C++11.") endif() else() message(STATUS "COMPILER: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER}) - NOT GNU compat") set(HAVE_COMPILER_GNU_COMPAT 0) endif() else() # Compiler altered by WITH_COMPILER_TYPE/PREFIX - can't rely on CMAKE_CXX_* # Force the C++ standard as C++11 # HAVE_COMPILER_GNU_COMPAT was set in the handler of WITH_COMPILER_TYPE set (FORCE_CXX_STANDARD 1) message(STATUS "COMPILER CHANGED TO: ${COMPILER_TYPE} - forcing C++11 standard for apps") endif() # Check for GCC Atomic Intrinsics and C++11 Atomics. # Sets: # HAVE_LIBATOMIC # HAVE_LIBATOMIC_COMPILES # HAVE_LIBATOMIC_COMPILES_STATIC # HAVE_GCCATOMIC_INTRINSICS # HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC include(CheckGCCAtomicIntrinsics) CheckGCCAtomicIntrinsics() # HAVE_CXX_ATOMIC # HAVE_CXX_ATOMIC_STATIC include(CheckCXXAtomic) CheckCXXAtomic() # Check for std::put_time(): # Sets: # HAVE_CXX_STD_PUT_TIME include(CheckCXXStdPutTime) CheckCXXStdPutTime() if (HAVE_CXX_STD_PUT_TIME) add_definitions(-DHAVE_CXX_STD_PUT_TIME=1) endif() if (DISABLE_CXX11) set (ENABLE_CXX11 0) elseif( DEFINED ENABLE_CXX11 ) else() set (ENABLE_CXX11 1) endif() function (srt_check_cxxstd stdval OUT_STD OUT_PFX) set (STDPFX c++) if (stdval MATCHES "([^+]+\\++)([0-9]*)") set (STDPFX ${CMAKE_MATCH_1}) set (STDCXX ${CMAKE_MATCH_2}) elseif (stdval MATCHES "[0-9]*") set (STDCXX ${stdval}) else() set (STDCXX 0) endif() # Handle C++98 < C++11 # Please fix this around 2070 year. if (${STDCXX} GREATER 80) set (STDCXX 03) endif() # return set (${OUT_STD} ${STDCXX} PARENT_SCOPE) set (${OUT_PFX} ${STDPFX} PARENT_SCOPE) endfunction() if (NOT ENABLE_CXX11) message(WARNING "Parts that require C++11 support will be disabled (srt-live-transmit)") if (ENABLE_STDCXX_SYNC) message(FATAL_ERROR "ENABLE_STDCXX_SYNC is set, but C++11 is disabled by ENABLE_CXX11") endif() elseif (ENABLE_STDCXX_SYNC) add_definitions(-DENABLE_STDCXX_SYNC=1) if (DEFINED USE_CXX_STD) srt_check_cxxstd(${USE_CXX_STD} STDCXX STDPFX) # If defined, make sure it's at least C++11 if (${STDCXX} LESS 11) message(FATAL_ERROR "If ENABLE_STDCXX_SYNC, then USE_CXX_STD must specify at least C++11") endif() else() set (USE_CXX_STD 11) endif() endif() message(STATUS "STDCXX_SYNC: ${ENABLE_STDCXX_SYNC}") message(STATUS "MONOTONIC_CLOCK: ${ENABLE_MONOTONIC_CLOCK}") if (ENABLE_SOCK_CLOEXEC) add_definitions(-DENABLE_SOCK_CLOEXEC=1) endif() if (CMAKE_MAJOR_VERSION LESS 3) set (FORCE_CXX_STANDARD_GNUONLY 1) endif() if (DEFINED USE_CXX_STD) srt_check_cxxstd(${USE_CXX_STD} STDCXX STDPFX) if (${STDCXX} EQUAL 0) message(FATAL_ERROR "USE_CXX_STD: Must specify 03/11/14/17/20 possibly with c++/gnu++ prefix") endif() if (NOT STDCXX STREQUAL "") if (${STDCXX} LESS 11) if (ENABLE_STDCXX_SYNC) message(FATAL_ERROR "If ENABLE_STDCXX_SYNC, then you can't USE_CXX_STD less than 11") endif() # Set back to 98 because cmake doesn't understand 03. set (STDCXX 98) # This enforces C++03 standard on SRT. # Apps still use C++11 # Set this through independent flags set (USE_CXX_STD_LIB ${STDCXX}) set (FORCE_CXX_STANDARD 1) if (NOT ENABLE_APPS) set (USE_CXX_STD_APP ${STDCXX}) message(STATUS "C++ STANDARD: library: C++${STDCXX}, apps disabled (examples will follow C++${STDCXX})") else() set (USE_CXX_STD_APP "") message(STATUS "C++ STANDARD: library: C++${STDCXX}, but apps still at least C++11") endif() elseif (FORCE_CXX_STANDARD_GNUONLY) # CMake is too old to handle CMAKE_CXX_STANDARD, # use bare GNU options. set (FORCE_CXX_STANDARD 1) set (USE_CXX_STD_APP ${STDCXX}) set (USE_CXX_STD_LIB ${STDCXX}) message(STATUS "C++ STANDARD: using C++${STDCXX} for all - GNU only") else() # This enforces this standard on both apps and library, # so set this as global C++ standard option set (CMAKE_CXX_STANDARD ${STDCXX}) unset (FORCE_CXX_STANDARD) # Do not set variables to not duplicate flags set (USE_CXX_STD_LIB "") set (USE_CXX_STD_APP "") message(STATUS "C++ STANDARD: using C++${STDCXX} for all") endif() message(STATUS "C++: Setting C++ standard for gnu compiler: lib: ${USE_CXX_STD_LIB} apps: ${USE_CXX_STD_APP}") endif() else() set (USE_CXX_STD_LIB "") set (USE_CXX_STD_APP "") endif() if (FORCE_CXX_STANDARD) message(STATUS "C++ STD: Forcing C++11 on applications") if (USE_CXX_STD_APP STREQUAL "") set (USE_CXX_STD_APP 11) endif() if (USE_CXX_STD_LIB STREQUAL "" AND ENABLE_STDCXX_SYNC) message(STATUS "C++ STD: Forcing C++11 on library, as C++11 sync requested") set (USE_CXX_STD_LIB 11) endif() endif() # add extra warning flags for gccish compilers if (HAVE_COMPILER_GNU_COMPAT) set (SRT_GCC_WARN "-Wall -Wextra") if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set (SRT_GCC_WARN "${SRT_GCC_WARN} -Wshadow=local") endif() else() # cpp debugging on Windows :D #set (SRT_GCC_WARN "/showIncludes") endif() if (USE_STATIC_LIBSTDCXX) if (HAVE_COMPILER_GNU_COMPAT) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++") else() message(FATAL_ERROR "On non-GNU-compat compiler it's not known how to use static C++ standard library.") endif() endif() # This options is necessary on some systems; on a cross-ARM compiler it # has been detected, for example, that -lrt is necessary for some applications # because clock_gettime is needed by some functions and it is alternatively # provided by libc, but only in newer versions. This options is rarely necessary, # but may help in several corner cases in unusual platforms. if (WITH_EXTRALIBS) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WITH_EXTRALIBS}") endif() # CMake has only discovered in 3.3 version that some set-finder is # necessary. Using variables for shortcut to a clumsy check syntax. set (srt_libspec_shared ${ENABLE_SHARED}) set (srt_libspec_static ${ENABLE_STATIC}) set (srtpack_libspec_common) if (srt_libspec_shared) list(APPEND srtpack_libspec_common ${TARGET_srt}_shared) endif() if (srt_libspec_static) list(APPEND srtpack_libspec_common ${TARGET_srt}_static) endif() set (SRT_SRC_HAICRYPT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/haicrypt) set (SRT_SRC_SRTCORE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/srtcore) set (SRT_SRC_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) set (SRT_SRC_TOOLS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tools) set (SRT_SRC_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) if(WIN32) message(STATUS "DETECTED SYSTEM: WINDOWS; WIN32=1; PTW32_STATIC_LIB=1") add_definitions(-DWIN32=1 -DPTW32_STATIC_LIB=1) elseif(DARWIN) message(STATUS "DETECTED SYSTEM: DARWIN") elseif(BSD) message(STATUS "DETECTED SYSTEM: BSD; BSD=1") add_definitions(-DBSD=1) elseif(LINUX) add_definitions(-DLINUX=1) message(STATUS "DETECTED SYSTEM: LINUX; LINUX=1" ) elseif(ANDROID) add_definitions(-DLINUX=1) message(STATUS "DETECTED SYSTEM: ANDROID; LINUX=1" ) elseif(CYGWIN) add_definitions(-DCYGWIN=1) message(STATUS "DETECTED SYSTEM: CYGWIN (posix mode); CYGWIN=1") elseif(GNU) add_definitions(-DGNU=1) message(STATUS "DETECTED SYSTEM: GNU; GNU=1" ) elseif(SUNOS) add_definitions(-DSUNOS=1) message(STATUS "DETECTED SYSTEM: SunOS|Solaris; SUNOS=1" ) else() message(FATAL_ERROR "Unsupported system: ${CMAKE_SYSTEM_NAME}") endif() add_definitions( -D_GNU_SOURCE -DHAI_PATCH=1 -DHAI_ENABLE_SRT=1 -DSRT_VERSION="${SRT_VERSION}" ) if (LINUX) # This is an option supported only on Linux add_definitions(-DSRT_ENABLE_BINDTODEVICE) endif() # This is obligatory include directory for all targets. This is only # for private headers. Installable headers should be exclusively used DIRECTLY. include_directories(${SRT_SRC_COMMON_DIR} ${SRT_SRC_SRTCORE_DIR} ${SRT_SRC_HAICRYPT_DIR}) if (ENABLE_LOGGING) list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_LOGGING=1") if (ENABLE_HEAVY_LOGGING) list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_HEAVY_LOGGING=1") endif() if (ENABLE_HAICRYPT_LOGGING) if (ENABLE_HAICRYPT_LOGGING STREQUAL 2) # Allow value 2 for INSECURE DEBUG logging message(WARNING " *** ENABLED INSECURE HAICRYPT LOGGING - USE FOR TESTING ONLY!!! ***") list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_HAICRYPT_LOGGING=2") else() list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_HAICRYPT_LOGGING=1") endif() endif() endif() if (ENABLE_GETNAMEINFO) list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_GETNAMEINFO=1") endif() if (ENABLE_PKTINFO) if (WIN32 OR BSD) message(FATAL_ERROR "PKTINFO is not implemented on Windows or *BSD.") endif() list(APPEND SRT_EXTRA_CFLAGS "-DSRT_ENABLE_PKTINFO=1") endif() # ENABLE_EXPERIMENTAL_BONDING is deprecated. Use ENABLE_BONDING. ENABLE_EXPERIMENTAL_BONDING is be removed in v1.6.0. if (ENABLE_EXPERIMENTAL_BONDING) message(DEPRECATION "ENABLE_EXPERIMENTAL_BONDING is deprecated. Please use ENABLE_BONDING instead.") set (ENABLE_BONDING ON) endif() if (ENABLE_BONDING) list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_BONDING=1") message(STATUS "ENABLE_BONDING: ON") else() message(STATUS "ENABLE_BONDING: OFF") endif() if (ENABLE_THREAD_CHECK) add_definitions( -DSRT_ENABLE_THREADCHECK=1 -DFUGU_PLATFORM=1 -I${WITH_THREAD_CHECK_INCLUDEDIR} ) endif() if (ENABLE_CLANG_TSA) list(APPEND SRT_EXTRA_CFLAGS "-Wthread-safety") message(STATUS "Clang TSA: Enabled") endif() if (ENABLE_PROFILE) if (HAVE_COMPILER_GNU_COMPAT) # They are actually cflags, not definitions, but CMake is stupid enough. add_definitions(-g -pg) link_libraries(-g -pg) else() message(FATAL_ERROR "Profiling option is not supported on this platform") endif() endif() if (ENABLE_CODE_COVERAGE) if (HAVE_COMPILER_GNU_COMPAT) add_definitions(-g -O0 --coverage) link_libraries(--coverage) message(STATUS "ENABLE_CODE_COVERAGE: ON") else() message(FATAL_ERROR "ENABLE_CODE_COVERAGE: option is not supported on this platform") endif() endif() # On Linux pthreads have to be linked even when using C++11 threads if (ENABLE_STDCXX_SYNC AND NOT LINUX) message(STATUS "Pthread library: C++11") elseif (PTHREAD_LIBRARY AND PTHREAD_INCLUDE_DIR) message(STATUS "Pthread library: ${PTHREAD_LIBRARY}") message(STATUS "Pthread include dir: ${PTHREAD_INCLUDE_DIR}") elseif (MICROSOFT) find_package(pthreads QUIET) if (NOT PTHREAD_INCLUDE_DIR OR NOT PTHREAD_LIBRARY) #search package folders with GLOB to add as extra hint for headers file(GLOB PTHREAD_PACKAGE_INCLUDE_HINT ./_packages/cinegy.pthreads-win*/sources) if (PTHREAD_PACKAGE_INCLUDE_HINT) message(STATUS "PTHREAD_PACKAGE_INCLUDE_HINT value: ${PTHREAD_PACKAGE_INCLUDE_HINT}") endif() # find pthread header find_path(PTHREAD_INCLUDE_DIR pthread.h HINTS C:/pthread-win32/include ${PTHREAD_PACKAGE_INCLUDE_HINT}) if (PTHREAD_INCLUDE_DIR) message(STATUS "Pthread include dir: ${PTHREAD_INCLUDE_DIR}") else() message(FATAL_ERROR "Failed to find pthread.h. Specify PTHREAD_INCLUDE_DIR.") endif() #search package folders with GLOB to add as extra hint for libs file(GLOB PTHREAD_PACKAGE_LIB_HINT ./_packages/cinegy.pthreads-win*/runtimes/win-*/native/release) if (PTHREAD_PACKAGE_LIB_HINT) message(STATUS "PTHREAD_PACKAGE_LIB_HINT value: ${PTHREAD_PACKAGE_LIB_HINT}") endif() #find pthread library set(PTHREAD_LIB_SUFFIX "") if (ENABLE_DEBUG) set(PTHREAD_LIB_SUFFIX "d") endif () set(PTHREAD_COMPILER_FLAG "") if (MICROSOFT) set(PTHREAD_COMPILER_FLAG "V") elseif (MINGW) set(PTHREAD_COMPILER_FLAG "G") endif () foreach(EXHAND C CE SE) foreach(COMPAT 1 2) list(APPEND PTHREAD_W32_LIBRARY "pthread${PTHREAD_COMPILER_FLAG}${EXHAND}${PTHREAD_LIB_SUFFIX}${COMPAT}") endforeach() endforeach() find_library(PTHREAD_LIBRARY NAMES ${PTHREAD_W32_LIBRARY} pthread pthread_dll pthread_lib HINTS C:/pthread-win32/lib C:/pthread-win64/lib ${PTHREAD_PACKAGE_LIB_HINT}) if (PTHREAD_LIBRARY) message(STATUS "Pthread library: ${PTHREAD_LIBRARY}") else() message(FATAL_ERROR "Failed to find pthread library. Specify PTHREAD_LIBRARY.") endif() endif() else () find_package(Threads REQUIRED) set(PTHREAD_LIBRARY ${CMAKE_THREAD_LIBS_INIT}) endif() # This is required in some projects that add some other sources # to the SRT library to be compiled together (aka "virtual library"). if (DEFINED SRT_EXTRA_LIB_INC) include(${SRT_EXTRA_LIB_INC}.cmake) # Expected to provide variables: # - SOURCES_srt_extra # - EXTRA_stransmit endif() # --------------------------------------------------------------------------- # --- # Target: haicrypt. # Completing sources and installable headers. Flag settings will follow. # --- if (ENABLE_ENCRYPTION) set (HAICRYPT_FILELIST_MAF "filelist-${USE_ENCLIB}.maf") MafReadDir(haicrypt ${HAICRYPT_FILELIST_MAF} SOURCES SOURCES_haicrypt PUBLIC_HEADERS HEADERS_haicrypt PROTECTED_HEADERS HEADERS_haicrypt ) endif() if (WIN32) MafReadDir(common filelist_win32.maf SOURCES SOURCES_common PUBLIC_HEADERS HEADERS_srt_win32 PROTECTED_HEADERS HEADERS_srt_win32 ) message(STATUS "WINDOWS detected: adding compat sources: ${SOURCES_common}") endif() # Make the OBJECT library for haicrypt and srt. Then they'll be bound into # real libraries later, either one common, or separate. # This is needed for Xcode to properly handle CMake OBJECT Libraries # From docs (https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries): # # ... Some native build systems (such as Xcode) may not like targets that have only object files, # so consider adding at least one real source file to any target that references $. set(OBJECT_LIB_SUPPORT "${PROJECT_SOURCE_DIR}/cmake_object_lib_support.c") # NOTE: The "virtual library" is a library specification that cmake # doesn't support (the library of OBJECT type is something in kind of that, # but not fully supported - for example it doesn't support transitive flags, # so this can't be used desired way). It's a private-only dependency type, # where the project isn't compiled into any library file at all - instead, all # of its source files are incorporated directly to the source list of the # project that depends on it. In cmake this must be handled manually. # --- # Target: srt. DEFINITION ONLY. Haicrypt flag settings follow. # --- if (ENABLE_SHARED AND MICROSOFT) #add resource files to shared library, to set DLL metadata on Windows DLLs set (EXTRA_WIN32_SHARED 1) message(STATUS "WIN32: extra resource file will be added") endif() MafReadDir(srtcore filelist.maf SOURCES SOURCES_srt PUBLIC_HEADERS HEADERS_srt PROTECTED_HEADERS HEADERS_srt PRIVATE_HEADERS HEADERS_srt_private ) # Auto generated version file and add it to the HEADERS_srt list. if(DEFINED ENV{APPVEYOR_BUILD_NUMBER}) set(SRT_VERSION_BUILD ON) set(CI_BUILD_NUMBER_STRING $ENV{APPVEYOR_BUILD_NUMBER}) message(STATUS "AppVeyor build environment detected: Adding build number to version header") endif() if(DEFINED ENV{TEAMCITY_VERSION}) set(SRT_VERSION_BUILD ON) set(CI_BUILD_NUMBER_STRING $ENV{CI_BUILD_COUNTER}) message(STATUS "TeamCity build environment detected: Adding build counter to version header") endif() configure_file("srtcore/version.h.in" "version.h" @ONLY) list(INSERT HEADERS_srt 0 "${CMAKE_CURRENT_BINARY_DIR}/version.h") include_directories("${CMAKE_CURRENT_BINARY_DIR}") add_library(srt_virtual OBJECT ${SOURCES_srt} ${SOURCES_srt_extra} ${HEADERS_srt} ${SOURCES_haicrypt} ${SOURCES_common}) if (ENABLE_SHARED) # Set this to sources as well, as it won't be automatically handled set_target_properties(srt_virtual PROPERTIES POSITION_INDEPENDENT_CODE 1) endif() macro(srt_set_stdcxx targetname spec) set (stdcxxspec ${spec}) if (NOT "${stdcxxspec}" STREQUAL "") if (FORCE_CXX_STANDARD_GNUONLY) target_compile_options(${targetname} PRIVATE -std=c++${stdcxxspec}) message(STATUS "C++ STD: ${targetname}: forced C++${stdcxxspec} standard - GNU option: -std=c++${stdcxxspec}") else() set_target_properties(${targetname} PROPERTIES CXX_STANDARD ${stdcxxspec}) message(STATUS "C++ STD: ${targetname}: forced C++${stdcxxspec} standard - portable way") endif() else() message(STATUS "APP: ${targetname}: using default C++ standard") endif() endmacro() macro(srt_set_stdc targetname spec) set (stdcspec ${spec}) if (NOT "${stdcspec}" STREQUAL "") if (CMAKE_VERSION VERSION_LESS "3.1") target_compile_options(${targetname} PRIVATE -std=c${stdcspec}) message(STATUS "C STD: ${targetname}: forced C${stdcspec} standard - GNU option: -std=c${stdcspec}") else() set_target_properties(${targetname} PROPERTIES C_STANDARD ${stdcspec}) message(STATUS "C STD: ${targetname}: forced C${stdcspec} standard - portable way") endif() else() message(STATUS "APP: ${targetname}: using default C standard") endif() endmacro() srt_set_stdcxx(srt_virtual "${USE_CXX_STD_LIB}") srt_set_stdc(srt_virtual "99") set (VIRTUAL_srt $) if (srt_libspec_shared) add_library(${TARGET_srt}_shared SHARED ${OBJECT_LIB_SUPPORT} ${VIRTUAL_srt}) # shared libraries need PIC set (CMAKE_POSITION_INDEPENDENT_CODE ON) set_property(TARGET ${TARGET_srt}_shared PROPERTY OUTPUT_NAME ${TARGET_srt}) set_target_properties (${TARGET_srt}_shared PROPERTIES VERSION ${SRT_VERSION} SOVERSION ${SRT_VERSION_MAJOR}.${SRT_VERSION_MINOR}) list (APPEND INSTALL_TARGETS ${TARGET_srt}_shared) if (ENABLE_ENCRYPTION) target_link_libraries(${TARGET_srt}_shared PRIVATE ${SSL_LIBRARIES}) endif() if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PRIVATE ws2_32.lib) if (NOT (ENABLE_ENCRYPTION AND "${USE_ENCLIB}" STREQUAL "botan")) if (OPENSSL_USE_STATIC_LIBS) target_link_libraries(${TARGET_srt}_shared PRIVATE crypt32.lib) else() set_target_properties(${TARGET_srt}_shared PROPERTIES LINK_FLAGS "/DELAYLOAD:libeay32.dll") endif() endif() elseif (MINGW) target_link_libraries(${TARGET_srt}_shared PRIVATE wsock32 ws2_32) elseif (APPLE) set_property(TARGET ${TARGET_srt}_shared PROPERTY MACOSX_RPATH ON) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_shared PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) endif() endif() if (srt_libspec_static) add_library(${TARGET_srt}_static STATIC ${OBJECT_LIB_SUPPORT} ${VIRTUAL_srt}) # For Windows, leave the name to be "srt_static.lib". # Windows generates two different library files: # - a usual static library for static linkage # - a shared library exposer, which allows pre-resolution and later dynamic # linkage when running the executable # Both having unfortunately the same names created by MSVC compiler. # It's not the case of Cygwin/MINGW - they are named there libsrt.a and libsrt.dll.a if (MICROSOFT) # Keep _static suffix. By unknown reason, the name must still be set explicitly. set_property(TARGET ${TARGET_srt}_static PROPERTY OUTPUT_NAME ${TARGET_srt}_static) else() set_property(TARGET ${TARGET_srt}_static PROPERTY OUTPUT_NAME ${TARGET_srt}) endif() list (APPEND INSTALL_TARGETS ${TARGET_srt}_static) if (ENABLE_ENCRYPTION) target_link_libraries(${TARGET_srt}_static PRIVATE ${SSL_LIBRARIES}) endif() if (MICROSOFT) target_link_libraries(${TARGET_srt}_static PRIVATE ws2_32.lib) if (OPENSSL_USE_STATIC_LIBS) target_link_libraries(${TARGET_srt}_static PRIVATE crypt32.lib) endif() elseif (MINGW) target_link_libraries(${TARGET_srt}_static PRIVATE wsock32 ws2_32) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_static PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) endif() endif() target_include_directories(srt_virtual PRIVATE ${SSL_INCLUDE_DIRS}) if (MICROSOFT) if (OPENSSL_USE_STATIC_LIBS) set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ws2_32.lib crypt32.lib) else() set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ws2_32.lib) endif() elseif (MINGW) set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} -lwsock32 -lws2_32) endif() # Applying this to public includes is not transitive enough. # On Windows, apps require this as well, so it's safer to # spread this to all targets. if (PTHREAD_INCLUDE_DIR) include_directories(${PTHREAD_INCLUDE_DIR}) endif() # Link libraries must be applied directly to the derivatives # as virtual libraries (OBJECT-type) cannot have linkage declarations # transitive or not. foreach(tar ${srtpack_libspec_common}) message(STATUS "ADDING TRANSITIVE LINK DEP to:${tar} : ${PTHREAD_LIBRARY} ${dep}") target_link_libraries (${tar} PUBLIC ${PTHREAD_LIBRARY} ${dep}) endforeach() set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${PTHREAD_LIBRARY}) target_compile_definitions(srt_virtual PRIVATE -DSRT_EXPORTS ) if (ENABLE_SHARED) target_compile_definitions(srt_virtual PUBLIC -DSRT_DYNAMIC) endif() target_compile_definitions(srt_virtual PRIVATE -DSRT_LOG_SLOWDOWN_FREQ_MS=${SRT_LOG_SLOWDOWN_FREQ_MS}) if (ENABLE_ENCRYPTION AND "${USE_ENCLIB}" STREQUAL "botan") add_dependencies(srt_virtual botan) endif() if (srt_libspec_shared) if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib) if (OPENSSL_USE_STATIC_LIBS) target_link_libraries(${TARGET_srt}_shared PUBLIC crypt32.lib) endif() endif() endif() # Required by some toolchains when statically linking this library if the # GCC Atomic Intrinsics are being used. if (HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC AND HAVE_LIBATOMIC) if (srt_libspec_static) target_link_libraries(${TARGET_srt}_static PUBLIC atomic) endif() if (srt_libspec_shared) target_link_libraries(${TARGET_srt}_shared PUBLIC atomic) endif() elseif (HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES_STATIC) # This is a workaround for ANDROID NDK<17 builds, which need to link # to libatomic when linking statically to the SRT library. if (srt_libspec_static) target_link_libraries(${TARGET_srt}_static PUBLIC atomic) endif() elseif (LINUX AND HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES) # This is a workaround for some older Linux Toolchains. if (srt_libspec_static) target_link_libraries(${TARGET_srt}_static PUBLIC atomic) endif() endif() # Cygwin installs the *.dll libraries in bin directory and uses PATH. set (INSTALL_SHARED_DIR ${CMAKE_INSTALL_LIBDIR}) if (CYGWIN) set (INSTALL_SHARED_DIR ${CMAKE_INSTALL_BINDIR}) endif() message(STATUS "INSTALL DIRS: bin=${CMAKE_INSTALL_BINDIR} lib=${CMAKE_INSTALL_LIBDIR} shlib=${INSTALL_SHARED_DIR} include=${CMAKE_INSTALL_INCLUDEDIR}") if (NEED_DESTINATION) if (DEFINED CMAKE_INSTALL_BINDIR AND DEFINED CMAKE_INSTALL_LIBDIR AND NOT INSTALL_SHARED_DIR STREQUAL "") install(TARGETS ${INSTALL_TARGETS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${INSTALL_SHARED_DIR} ) else() message(WARNING "No location to install ${INSTALL_TARGETS}") endif() elseif (NOT INSTALL_SHARED_DIR STREQUAL "") install(TARGETS ${INSTALL_TARGETS} LIBRARY DESTINATION ${INSTALL_SHARED_DIR} ) else() install(TARGETS ${INSTALL_TARGETS}) endif() if (DEFINED CMAKE_INSTALL_INCLUDEDIR) install(FILES ${HEADERS_srt} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/srt) if (WIN32) install(FILES ${HEADERS_srt_win32} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/srt/win) endif() endif() # --- # That's all for target definition # --- join_arguments(SRT_EXTRA_CFLAGS ${SRT_EXTRA_CFLAGS}) #message(STATUS "Target srt: LIBSPEC: ${srtpack_libspec_common} SOURCES: {${SOURCES_srt}} HEADERS: {${HEADERS_srt}}") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SRT_DEBUG_OPT} ${SRT_EXTRA_CFLAGS} ${SRT_GCC_WARN}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SRT_DEBUG_OPT} ${SRT_EXTRA_CFLAGS} ${SRT_GCC_WARN}") # PC file generation. if (NOT DEFINED INSTALLDIR) set (INSTALLDIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(INSTALLDIR ${INSTALLDIR} ABSOLUTE) endif() # Required if linking a C application. # This may cause trouble when you want to compile your app with static libstdc++; # if your build requires it, you'd probably remove -lstdc++ from the list # obtained by `pkg-config --libs`. if(ENABLE_CXX_DEPS) foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}) if((IS_ABSOLUTE ${LIB} AND EXISTS ${LIB}) OR (${LIB} MATCHES "^-l")) set(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${LIB}) else() set(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} "-l${LIB}") endif() endforeach() endif() join_arguments(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE}) if (DEFINED CMAKE_INSTALL_LIBDIR) # haisrt.pc left temporarily for backward compatibility. To be removed in future! configure_file(scripts/srt.pc.in haisrt.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/haisrt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) configure_file(scripts/srt.pc.in srt.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/srt.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) endif() # Applications # If static is available, link apps against static one. # Otherwise link against shared one. if (srt_libspec_static) set (srt_link_library ${TARGET_srt}_static) if (ENABLE_RELATIVE_LIBPATH) message(STATUS "ENABLE_RELATIVE_LIBPATH=ON will be ignored due to static linking.") endif() elseif(srt_libspec_shared) set (srt_link_library ${TARGET_srt}_shared) else() message(FATAL_ERROR "Either ENABLE_STATIC or ENABLE_SHARED has to be ON!") endif() macro(srt_add_program_dont_install name) add_executable(${name} ${ARGN}) target_include_directories(${name} PRIVATE apps) target_include_directories(${name} PRIVATE common) endmacro() macro(srt_add_program name) srt_add_program_dont_install(${name} ${ARGN}) if(NOT NEED_DESTINATION) install(TARGETS ${name} RUNTIME) elseif (DEFINED CMAKE_INSTALL_BINDIR) install(TARGETS ${name} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) else() message(WARNING "No location to install program ${name}") endif() endmacro() macro(srt_make_application name) srt_set_stdcxx(${name} "${USE_CXX_STD_APP}") # This is recommended by cmake, but it doesn't work anyway. # What is needed is that this below CMAKE_INSTALL_RPATH (yes, relative) # is added as is. # set (CMAKE_SKIP_RPATH FALSE) # set (CMAKE_SKIP_BUILD_RPATH FALSE) # set (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) # set (CMAKE_INSTALL_RPATH "../${CMAKE_INSTALL_LIBDIR}") # set (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # set (FORCE_RPATH BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH_USE_LINK_PATH TRUE) if (LINUX AND ENABLE_RELATIVE_LIBPATH AND NOT srt_libspec_static) # This is only needed on Linux, on Windows (including Cygwin) the library file will # be placed into the binrary directory anyway. # XXX not sure about Mac. # See this name used already in install(${TARGET_srt} LIBRARY DESTINATION...). set(FORCE_RPATH LINK_FLAGS -Wl,-rpath,.,-rpath,../${CMAKE_INSTALL_LIBDIR} BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH_USE_LINK_PATH TRUE) set_target_properties(${name} PROPERTIES ${FORCE_RPATH}) endif() target_link_libraries(${name} ${srt_link_library}) if (USE_GNUSTL) target_link_libraries(${name} PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) endif() if (srt_libspec_static AND CMAKE_DL_LIBS) target_link_libraries(${name} ${CMAKE_DL_LIBS}) endif() endmacro() macro(srt_add_application name) # ARGN=sources... srt_add_program(${name} apps/${name}.cpp ${ARGN}) srt_make_application(${name}) if(NOT NEED_DESTINATION) install(TARGETS ${name} RUNTIME) elseif (DEFINED CMAKE_INSTALL_BINDIR) install(TARGETS ${name} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) else() message(WARNING "No location to install program ${name}") endif() endmacro() ## FIXME: transmitmedia.cpp does not build on OpenBSD ## Issue: https://github.com/Haivision/srt/issues/590 if (BSD AND ${SYSNAME_LC} MATCHES "^openbsd$") set(ENABLE_APPS OFF) endif() ## The applications currently require c++11. if (NOT ENABLE_CXX11) set(ENABLE_APPS OFF) endif() if (ENABLE_APPS) message(STATUS "APPS: ENABLED, std=${USE_CXX_STD_APP}") # Make a virtual library of all shared app files MafReadDir(apps support.maf SOURCES SOURCES_support ) # A special trick that makes the shared application sources # to be compiled once for all applications. Maybe this virtual # library should be changed into a static one and made useful # for users. add_library(srtsupport_virtual OBJECT ${SOURCES_support}) srt_set_stdcxx(srtsupport_virtual "${USE_CXX_STD_APP}") set (VIRTUAL_srtsupport $) # Applications srt_add_application(srt-live-transmit ${VIRTUAL_srtsupport}) if (DEFINED EXTRA_stransmit) set_target_properties(srt-live-transmit PROPERTIES COMPILE_FLAGS "${EXTRA_stransmit}") endif() srt_add_application(srt-file-transmit ${VIRTUAL_srtsupport}) if (MINGW) # FIXME: with MINGW, it fails to build apps that require C++11 # https://github.com/Haivision/srt/issues/177 message(WARNING "On MinGW, some C++11 apps are blocked due to lacking proper C++11 headers for . FIX IF POSSIBLE.") else() # srt-multiplex temporarily blocked #srt_add_application(srt-multiplex ${VIRTUAL_srtsupport}) srt_add_application(srt-tunnel ${VIRTUAL_srtsupport}) endif() if (ENABLE_TESTING) message(STATUS "DEVEL APPS (testing): ENABLED") macro(srt_add_testprogram name) # Variables in macros are not local. Clear them forcefully. set (SOURCES_app_indir "") set (SOURCES_app "") # Unlike Silvercat, in cmake you must know the full list # of source files at the moment when defining the target # and it can't be altered later. # # For testing applications, every application has its exclusive # list of source files in its own Manifest file. MafReadDir(testing ${name}.maf SOURCES SOURCES_app) srt_add_program_dont_install(${name} ${SOURCES_app}) endmacro() srt_add_testprogram(utility-test) srt_set_stdcxx(utility-test "${USE_CXX_STD_APP}") if (NOT WIN32) # This program is symlinked under git-cygwin. # Avoid misleading syntax error. srt_add_testprogram(uriparser-test) target_compile_options(uriparser-test PRIVATE -DTEST) srt_set_stdcxx(uriparser-test "${USE_CXX_STD_APP}") endif() srt_add_testprogram(srt-test-live) srt_make_application(srt-test-live) srt_add_testprogram(srt-test-file) srt_make_application(srt-test-file) srt_add_testprogram(srt-test-relay) srt_make_application(srt-test-relay) srt_add_testprogram(srt-test-multiplex) srt_make_application(srt-test-multiplex) if (ENABLE_BONDING) srt_add_testprogram(srt-test-mpbond) srt_make_application(srt-test-mpbond) endif() else() message(STATUS "DEVEL APPS (testing): DISABLED") endif() else() message(STATUS "APPS: DISABLED") endif() if (ENABLE_EXAMPLES) # No examples should need C++11 macro(srt_add_example mainsrc) get_filename_component(name ${mainsrc} NAME_WE) srt_add_program_dont_install(${name} examples/${mainsrc} ${ARGN}) target_link_libraries(${name} ${srt_link_library} ${DEPENDS_srt}) endmacro() srt_add_example(recvlive.cpp) srt_add_example(sendfile.cpp) srt_add_example(recvfile.cpp) srt_add_example(sendmsg.cpp) srt_add_example(recvmsg.cpp) srt_add_example(test-c-client.c) srt_add_example(example-client-nonblock.c) srt_add_example(test-c-server.c) if (ENABLE_BONDING) srt_add_example(test-c-client-bonding.c) srt_add_example(test-c-server-bonding.c) endif() srt_add_example(testcapi-connect.c) endif() if (ENABLE_UNITTESTS AND ENABLE_CXX11) if (${CMAKE_VERSION} VERSION_LESS "3.10.0") message(STATUS "VERSION < 3.10 -- adding test using the old method") set (USE_OLD_ADD_METHOD 1) else() message(STATUS "VERSION > 3.10 -- using NEW POLICY for in_list operator") cmake_policy(SET CMP0057 NEW) # Support the new IN_LIST operator. endif() set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Version ranges are only supported with CMake 3.19 or later. # Need GTest v1.10 or higher to support GTEST_SKIP. if (${CMAKE_VERSION} VERSION_LESS "3.19.0") find_package(GTest 1.10) else() find_package(GTest 1.10...1.12) endif() if (NOT GTEST_FOUND) message(STATUS "GTEST not found! Fetching from git.") include(googletest) fetch_googletest( ${PROJECT_SOURCE_DIR}/scripts ${PROJECT_BINARY_DIR}/googletest ) set(GTEST_BOTH_LIBRARIES "gtest_main" CACHE STRING "Add gtest_main target") endif() MafReadDir(test filelist.maf HEADERS SOURCES_unittests SOURCES SOURCES_unittests ) srt_add_program_dont_install(test-srt ${SOURCES_unittests}) srt_make_application(test-srt) target_include_directories(test-srt PRIVATE ${SSL_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}) target_link_libraries( test-srt ${GTEST_BOTH_LIBRARIES} ${srt_link_library} ${PTHREAD_LIBRARY} ) if (USE_OLD_ADD_METHOD) add_test( NAME test-srt COMMAND ${CMAKE_BINARY_DIR}/test-srt ) #set_tests_properties(test-srt PROPERTIES RUN_SERIAL TRUE) else() set_tests_properties(${tests_srt} PROPERTIES RUN_SERIAL TRUE) gtest_discover_tests(test-srt) endif() enable_testing() endif() if(NOT NEED_DESTINATION) install(PROGRAMS scripts/srt-ffplay TYPE BIN) elseif (DEFINED CMAKE_INSTALL_BINDIR) install(PROGRAMS scripts/srt-ffplay DESTINATION ${CMAKE_INSTALL_BINDIR}) else() message(WARNING "No location to install scripts/srt-ffplay") endif() if (DEFINED SRT_EXTRA_APPS_INC) include(${SRT_EXTRA_APPS_INC}.cmake) # No extra variables expected. Just use the variables # already provided and define additional targets. endif() if (ENABLE_SHOW_PROJECT_CONFIG) include(ShowProjectConfig) ShowProjectConfig() endif() srt-1.5.4/CONTRIBUTING.md000066400000000000000000000046271471311275400146000ustar00rootroot00000000000000## License By contributing code to the [SRT project](https://github.com/Haivision/srt/), you agree to license your contribution under the [MPLv2.0 License](LICENSE). ## Issues Open a GitHub issue for anything you find or any questions you have. ## Comments Comment on any GitHub issue, open or closed. The only guidelines here are to be friendly and welcoming. If you see that a question has been asked and you think you know the answer, don't wait! ## Pull Requests Submit a pull request at any time, whether an issue has been created or not. It may be helpful to discuss your goals in an issue first, though many things can best be shown with code. Also do not hesitate to ask other users for opinion and discuss the ideas using the ticketing system before you start making your changes. This is especially important in these areas: * the build system and its variables * the SRT library public API * command line tools and their call syntax * the reusable parts (such as utilities) * SRT protocol definitions * portability and platform-specific parts Please follow the [SRT Developer's Guide](docs/dev/developers-guide.md). ## Code Style Please follow existing style. ## Attribution This contributing guide is adapted from [VVV's guide](https://github.com/Varying-Vagrant-Vagrants/VVV/blob/develop/.github/CONTRIBUTING.md). ## Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: * (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or * (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or * (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. * (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. srt-1.5.4/LICENSE000066400000000000000000000405261471311275400133520ustar00rootroot00000000000000Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- 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/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. srt-1.5.4/README.md000066400000000000000000000444621471311275400136270ustar00rootroot00000000000000# Secure Reliable Transport (SRT) Protocol [About SRT](#what-is-srt) | [Features](#features) | [Getting Started](#getting-started-with-srt) | [Build Instructions](#build-instructions) | [Sample Apps and Tools](#sample-applications-and-tools) | [Contribute](#contributing) | [License](#license) | [Releases](#release-history)

SRT

[![License: MPLv2.0][license-badge]](./LICENSE) [![Latest release][release-badge]][github releases] [![Quality Gate Status][sonarcloud-badge]][sonarcloud-project] [![codecov][codecov-badge]][codecov-project] [![Build Status Linux and macOS][travis-badge]][travis] [![Build Status Windows][appveyor-badge]][appveyor] [![Ubuntu 23.04][Ubuntu-badge]][Ubuntu-package] [![Fedora 37][fedora-badge]][fedora-package] [![Debian][debian-badge]][debian-package] [![Homebrew][Homebrew-badge]][Homebrew-package] [![Vcpkg][Vcpkg-badge]][Vcpkg-package] [![ConanCenter][ConanCenter-badge]][ConanCenter-package] ## What is SRT? **Secure Reliable Transport (SRT)** is a transport protocol for ultra low (sub-second) latency live video and audio streaming, as well as for generic bulk data transfer[^1]. SRT is available as an open-source technology with the code on GitHub, a published [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01), and a growing [community of SRT users](https://www.srtalliance.org/). SRT is applied to contribution and distribution endpoints as part of a video stream workflow to deliver the best quality and lowest latency video at all times. | | | | ------------- | ------------------------------------------------- | | **S**ecure | Encrypts video streams | | **R**eliable | Recovers from severe packet loss | | **T**ransport | Dynamically adapts to changing network conditions | In live streaming configurations, the SRT protocol maintains a constant end-to-end latency. This allows the live stream's signal characteristics to be recreated on the receiver side, reducing the need for buffering. As packets are streamed from source to destination, SRT detects and adapts to real-time network conditions between the two endpoints. It helps compensate for jitter and bandwidth fluctuations due to congestion over noisy networks. [SRT implements AES encryption](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-6) to protect the payload of the media streams, and offers various error recovery mechanisms for minimizing the packet loss that is typical of Internet connections, of which Automatic Repeat reQuest (ARQ) is the primary method. With ARQ, when a receiver detects that a packet is missing it sends an alert to the sender requesting retransmission of this missing packet. [Forward Error Correction (FEC)](./docs/features/packet-filtering-and-fec.md) and [Connection Bonding](./docs/features/bonding-quick-start.md), which adds seamless stream protection and hitless failover, are also supported by the protocol.

To learn more about the protocol subscribe to the Innovation Labs Blog on  slack logo

To ask a question join the conversation in the #development channel on  slack logo

## Features > :point_down: Click on the ► button to expand a feature description.
Pristine Quality and Reliability

No matter how unreliable your network, SRT can recover from severe packet loss and jitter, ensuring the integrity and quality of your video streams.

Low Latency

SRT’s stream error correction is configurable to accommodate a user’s deployment conditions. Leveraging real-time IP communications development to extend traditional network error recovery practices, SRT delivers media with significantly lower latency than TCP/IP, while offering the speed of UDP transmission with greatly improved reliability.

Content Agnostic

Unlike some other streaming protocols that only support specific video and audio formats, SRT is payload agnostic. Because SRT operates at the network transport level, acting as a wrapper around your content, it can transport any type of video format, codec, resolution, or frame rate.

Easy Firewall Traversal with Rendezvous Mode

The handshaking process used by SRT supports outbound connections without the potential risks and dangers of permanent exterior ports being opened in a firewall, thereby maintaining corporate LAN security policies and minimizing the need for IT intervention.

AES Encryption

Using 128/192/256-bit AES encryption trusted by governments and organizations around the world, SRT ensures that valuable content is protected end-to-end from contribution to distribution so that no unauthorized parties can listen.

Forward Error Correction (FEC) and Packet Filter API

[SRT 1.4](https://github.com/Haivision/srt/releases/tag/v1.4.0) sees the introduction of the _packet filter API_. This mechanism allows custom processing to be performed on network packets on the sender side before they are sent, and on the receiver side once received from the network. The API allows users to write their own plugin, thereby extending the SRT protocol's capabilities even further with all kinds of different packet filtering. Users can manipulate the resulting packet filter data in any way, such as for custom encryption, packet inspection, or accessing data before it is sent. The first plugin created as an example of what can be achieved with the packet filter API is for Forward Error Correction (FEC) which, in certain use cases, can offer slightly lower latency than Automatic Repeat reQuest (ARQ). This plugin allows three different modes: - ARQ only – retransmits lost packets, - FEC only – provides the overhead needed for FEC recovery on the receiver side, - FEC and ARQ – retransmits lost packets that FEC fails to recover.

Connection Bonding

Similar to SMPTE-2022-7 over managed networks, Connection Bonding adds seamless stream protection and hitless failover to the SRT protocol. This technology relies on more than one IP network path to prevent disruption to live video streams in the event of network congestion or outages, maintaining continuity of service. This is accomplished using the [socket groups](./docs/features/socket-groups.md) introduced in [SRT v1.5](https://github.com/Haivision/srt/releases/tag/v1.5.0). The general concept of socket groups means having a group that contains multiple sockets, where one operation for sending one data signal is applied to the group. Single sockets inside the group will take over this operation and do what is necessary to deliver the signal to the receiver. Two modes are supported: - [Broadcast](./docs/features/socket-groups.md#1-broadcast) - In *Broadcast* mode, data is sent redundantly over all the member links in a group. If one of the links fails or experiences network jitter and/or packet loss, the missing data will be received over another link in the group. Redundant packets are simply discarded at the receiver side. - [Main/Backup](./docs/features/bonding-main-backup.md) - In *Main/Backup* mode, only one (main) link at a time is used for data transmission while other (backup) connections are on standby to ensure the transmission will continue if the main link fails. The goal of Main/Backup mode is to identify a potential link break before it happens, thus providing a time window within which to seamlessly switch to one of the backup links.

Access Control (Stream ID)

Access Control enables the upstream application to assign a Stream ID to individual SRT streams. By using a unique Stream ID, either automatically generated or customized, the upstream application can send multiple SRT streams to a single IP address and UDP port. The Stream IDs can then be used by a receiver to identify and differentiate between ingest streams, apply user password access methods, and in some cases even apply automation based on the naming of the Stream ID. For example, contribution could be sent to a video production workflow and monitoring to a monitoring service. For broadcasters, Stream ID is key to replacing RTMP for ingesting video streams, especially HEVC/H.265 content, into cloud service or CDNs that have a single IP socket (address + port) open for incoming video.

## Getting Started with SRT | | | | |:-----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------:| | [The SRT API](./docs#srt-api-documents) | [IETF Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) | [Sample Apps](./docs#sample-applications) | | Reference documentation for the SRT library API | The SRT Protocol Internet Draft | Instructions for using test apps (`srt-live-transmit`, `srt-file-transmit`, etc.) | | [SRT Technical Overview](https://github.com/Haivision/srt/files/2489142/SRT_Protocol_TechnicalOverview_DRAFT_2018-10-17.pdf) | [SRT Deployment Guide](https://www.srtalliance.org/srt-deployment-guide/) | [SRT CookBook](https://srtlab.github.io/srt-cookbook) | | Early draft technical overview (precursor to the Internet Draft) | A comprehensive overview of the protocol with deployment guidelines | Development notes on the SRT protocol | | [Innovation Labs Blog](https://medium.com/innovation-labs-blog/tagged/secure-reliable-transport) | [SRTLab YouTube Channel](https://www.youtube.com/channel/UCr35JJ32jKKWIYymR1PTdpA) | [Slack](https://srtalliance.slack.com) | | The blog on Medium with SRT-related technical articles | Technical YouTube channel with useful videos | Slack channels to get the latest updates and ask questions
[Join SRT Alliance on Slack](https://slackin-srtalliance.azurewebsites.net/) | ### Additional Documentation - [Why SRT?](./docs/misc/why-srt-was-created.md) - A brief history and rationale for SRT by Marc Cymontkowski. - [RTMP vs. SRT: Comparing Latency and Maximum Bandwidth](https://www.haivision.com/resources/white-paper/srt-versus-rtmp/) White Paper. - [Documentation on GitHub](./docs#documentation-overview) with SRT API documents, features decsriptions, etc. - The SRT Protocol Internet Draft: [Datatracker](https://datatracker.ietf.org/doc/draft-sharabayko-srt/) | [Latest Version](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) | [Latest Working Copy](https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html) | [GitHub Repo](https://github.com/Haivision/srt-rfc) ## Build Instructions [Linux (Ubuntu/CentOS)](./docs/build/build-linux.md) | [Windows](./docs/build/build-win.md) | [macOS](./docs/build/build-macOS.md) | [iOS](./docs/build/build-iOS.md) | [Android](./docs/build/build-android.md) | [Package Managers](./docs/build/package-managers.md) ### Requirements * C++03 or above compliant compiler. * CMake 2.8.12 or above as a build system. * OpenSSL 1.1 to enable encryption, otherwise build with [`-DENABLE_ENCRYPTION=OFF`](./docs/build/build-options.md#enable_encryption). * Multithreading is provided by either of the following: * C++11: standard library (`std` by [`-DENABLE_STDCXX_SYNC=ON`](./docs/build/build-options.md#enable_stdcxx_sync) CMake option), * C++03: Pthreads (for POSIX systems it's built in, for Windows there is a ported library). * Tcl 8.5 is optional and is used by `./configure` script. Otherwise, use CMake directly. ### Build Options For detailed descriptions of the build system and options, please read the [SRT Build Options](./docs/build/build-options.md) document. ## Sample Applications and Tools The current repo provides [sample applications](./apps) and [code examples](./examples) that demonstrate the usage of the SRT library API. Among them are [`srt-live-transmit`](./apps/srt-live-transmit.cpp), [`srt-file-transmit`](./apps/srt-file-transmit.cpp), and other applications. The respective documentation can be found [here](./docs#sample-applications). Note that all samples are provided for instructional purposes, and should not be used in a production environment. The [`srt-xtransmit`](https://github.com/maxsharabayko/srt-xtransmit) utility is actively used for internal testing and performance evaluation. Among other features it supports dummy payload generation, traffic routings, and connection bonding. Additional details are available in the [`srt-xtransmit`](https://github.com/maxsharabayko/srt-xtransmit) repo itself. Python tools that might be useful during development are: - [`srt-stats-plotting`](https://github.com/mbakholdina/srt-stats-plotting) - A script designed to plot graphs based on SRT `.csv` statistics. - [`lib-tcpdump-processing`](https://github.com/mbakholdina/lib-tcpdump-processing) - A library designed to process `.pcap(ng)` [tcpdump](https://www.tcpdump.org/) or [Wireshark](https://www.wireshark.org/) trace files and extract SRT packets of interest for further analysis. - [`lib-srt-utils`](https://github.com/mbakholdina/lib-srt-utils) - A Python library containing supporting code for running SRT tests based on an experiment configuration. ## Contributing Anyone is welcome to contribute. If you decide to get involved, please take a moment to review the guidelines: * [SRT Developer's Guide](docs/dev/developers-guide.md) * [Contributing](CONTRIBUTING.md) * [Reporting Issues](docs/dev/making-srt-better.md) For information on contributing to the [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) or to submit issues please go to the following [repo](https://github.com/Haivision/srt-rfc). The repo for contributing in [SRT CookBook](https://srtlab.github.io/srt-cookbook/) can be found [here](https://github.com/SRTLab/srt-cookbook/). ## License By contributing code to the SRT project, you agree to license your contribution under the [MPLv2.0 License](LICENSE). ## Release History - [Release notes](https://github.com/Haivision/srt/releases) - [SRT versioning](./docs/dev/developers-guide.md#versioning) [^1]: The term “live streaming†refers to continuous data transmission (MPEG-TS or equivalent) with latency management. Live streaming based on segmentation and transmission of files like in the HTTP Live Streaming (HLS) protocol (as described in RFC8216) is not part of this use case. File transmission in either message or buffer mode should be considered in this case. See [Section 7. Best Practices and Configuration Tips for Data Transmission via SRT](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-7) of the Internet Draft for details. Note that SRT is content agnostic, meaning that any type of data can be transmitted via its payload. [appveyor-badge]: https://img.shields.io/appveyor/ci/Haivision/srt/master.svg?label=Windows [appveyor]: https://ci.appveyor.com/project/Haivision/srt [travis-badge]: https://img.shields.io/travis/Haivision/srt/master.svg?label=Linux/macOS [travis]: https://travis-ci.org/Haivision/srt [license-badge]: https://img.shields.io/badge/License-MPLv2.0-blue [Vcpkg-package]: https://repology.org/project/srt/versions [Vcpkg-badge]: https://repology.org/badge/version-for-repo/vcpkg/srt.svg [ConanCenter-package]: https://repology.org/project/srt/versions [ConanCenter-badge]: https://repology.org/badge/version-for-repo/conancenter/srt.svg [sonarcloud-project]: https://sonarcloud.io/project/overview?id=srt [sonarcloud-badge]: https://sonarcloud.io/api/project_badges/measure?project=srt&metric=alert_status [codecov-project]: https://codecov.io/gh/haivision/srt [codecov-badge]: https://codecov.io/gh/haivision/srt/branch/master/graph/badge.svg [github releases]: https://github.com/Haivision/srt/releases [release-badge]: https://img.shields.io/github/release/Haivision/srt.svg [debian-badge]: https://badges.debian.net/badges/debian/testing/libsrt1.5-gnutls/version.svg [debian-package]: https://packages.debian.org/testing/libs/libsrt1.5-gnutls [fedora-package]: https://repology.org/project/srt/versions [fedora-badge]: https://repology.org/badge/version-for-repo/fedora_37/srt.svg [homebrew-package]: https://repology.org/project/srt/versions [homebrew-badge]: https://repology.org/badge/version-for-repo/homebrew/srt.svg [Ubuntu-package]: https://repology.org/project/srt/versions [Ubuntu-badge]: https://repology.org/badge/version-for-repo/ubuntu_23_04/srt.svg srt-1.5.4/apps/000077500000000000000000000000001471311275400133015ustar00rootroot00000000000000srt-1.5.4/apps/apputil.cpp000066400000000000000000000260541471311275400154720ustar00rootroot00000000000000/* * 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/. * */ #include #include #include #include #include #include #include #include "srt.h" // Required for SRT_SYNC_CLOCK_* definitions. #include "apputil.hpp" #include "netinet_any.h" #include "srt_compat.h" using namespace std; using namespace srt; // NOTE: MINGW currently does not include support for inet_pton(). See // http://mingw.5.n7.nabble.com/Win32API-request-for-new-functions-td22029.html // Even if it did support inet_pton(), it is only available on Windows Vista // and later. Since we need to support WindowsXP and later in ORTHRUS. Many // customers still use it, we will need to implement using something like // WSAStringToAddress() which is available on Windows95 and later. // Support for IPv6 was added on WindowsXP SP1. // Header: winsock2.h // Implementation: ws2_32.dll // See: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742214(v=vs.85).aspx // http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedInternet3b.html #if defined(_WIN32) && !defined(HAVE_INET_PTON) namespace // Prevent conflict in case when still defined { int inet_pton(int af, const char * src, void * dst) { struct sockaddr_storage ss; int ssSize = sizeof(ss); char srcCopy[INET6_ADDRSTRLEN + 1]; ZeroMemory(&ss, sizeof(ss)); // work around non-const API #ifdef _MSC_VER strncpy_s(srcCopy, INET6_ADDRSTRLEN + 1, src, _TRUNCATE); #else strncpy(srcCopy, src, INET6_ADDRSTRLEN); srcCopy[INET6_ADDRSTRLEN] = '\0'; #endif if (WSAStringToAddress( srcCopy, af, NULL, (struct sockaddr *)&ss, &ssSize) != 0) { return 0; } switch (af) { case AF_INET : { *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; return 1; } case AF_INET6 : { *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; return 1; } default : { // No-Op } } return 0; } } #endif // _WIN32 && !HAVE_INET_PTON sockaddr_any CreateAddr(const string& name, unsigned short port, int pref_family) { // Handle empty name. // If family is specified, empty string resolves to ANY of that family. // If not, it resolves to IPv4 ANY (to specify IPv6 any, use [::]). if (name == "") { sockaddr_any result(pref_family == AF_INET6 ? pref_family : AF_INET); result.hport(port); return result; } bool first6 = pref_family != AF_INET; int families[2] = {AF_INET6, AF_INET}; if (!first6) { families[0] = AF_INET; families[1] = AF_INET6; } for (int i = 0; i < 2; ++i) { int family = families[i]; sockaddr_any result (family); // Try to resolve the name by pton first if (inet_pton(family, name.c_str(), result.get_addr()) == 1) { result.hport(port); // same addr location in ipv4 and ipv6 return result; } } // If not, try to resolve by getaddrinfo // This time, use the exact value of pref_family sockaddr_any result; addrinfo fo = { 0, pref_family, 0, 0, 0, 0, NULL, NULL }; addrinfo* val = nullptr; int erc = getaddrinfo(name.c_str(), nullptr, &fo, &val); if (erc == 0) { result.set(val->ai_addr); result.len = result.size(); result.hport(port); // same addr location in ipv4 and ipv6 } freeaddrinfo(val); return result; } string Join(const vector& in, string sep) { if ( in.empty() ) return ""; ostringstream os; os << in[0]; for (auto i = in.begin()+1; i != in.end(); ++i) os << sep << *i; return os.str(); } // OPTION LIBRARY OptionScheme::Args OptionName::DetermineTypeFromHelpText(const std::string& helptext) { if (helptext.empty()) return OptionScheme::ARG_NONE; if (helptext[0] == '<') { // If the argument is , then it's ARG_NONE. // If it's , then it's ARG_VAR. // When closing angle bracket isn't found, fallback to ARG_ONE. size_t pos = helptext.find('>'); if (pos == std::string::npos) return OptionScheme::ARG_ONE; // mistake, but acceptable if (pos >= 4 && helptext.substr(pos-3, 4) == "...>") return OptionScheme::ARG_VAR; // We have < and > without ..., simply one argument return OptionScheme::ARG_ONE; } if (helptext[0] == '[') { // Argument in [] means it is optional; in this case // you should state that the argument can be given or not. return OptionScheme::ARG_VAR; } // Also as fallback return OptionScheme::ARG_NONE; } options_t ProcessOptions(char* const* argv, int argc, std::vector scheme) { using namespace std; string current_key; string extra_arg; size_t vals = 0; OptionScheme::Args type = OptionScheme::ARG_VAR; // This is for no-option-yet or consumed map> params; bool moreoptions = true; for (char* const* p = argv+1; p != argv+argc; ++p) { const char* a = *p; // cout << "*D ARG: '" << a << "'\n"; bool isoption = false; if (a[0] == '-') { isoption = true; // If a[0] isn't NUL - because it is dash - then // we can safely check a[1]. // An expression starting with a dash is not // an option marker if it is a single dash or // a negative number. if (!a[1] || isdigit(a[1])) isoption = false; } if (moreoptions && isoption) { bool arg_specified = false; size_t seppos; // (see goto, it would jump over initialization) current_key = a+1; if ( current_key == "-" ) { // The -- argument terminates the options. // The default key is restored to empty so that // it collects now all arguments under the empty key // (not-option-assigned argument). moreoptions = false; goto EndOfArgs; } // Maintain the backward compatibility with argument specified after : // or with one string separated by space inside. seppos = current_key.find(':'); if (seppos == string::npos) seppos = current_key.find(' '); if (seppos != string::npos) { // Old option specification. extra_arg = current_key.substr(seppos + 1); current_key = current_key.substr(0, 0 + seppos); arg_specified = true; // Prevent eating args from option list } params[current_key].clear(); vals = 0; if (extra_arg != "") { params[current_key].push_back(extra_arg); ++vals; extra_arg.clear(); } // Find the key in the scheme. If not found, treat it as ARG_NONE. for (const auto& s: scheme) { if (s.names().count(current_key)) { // cout << "*D found '" << current_key << "' in scheme type=" << int(s.type) << endl; // If argument was specified using the old way, like // -v:0 or "-v 0", then consider the argument specified and // treat further arguments as either no-option arguments or // new options. if (s.type == OptionScheme::ARG_NONE || arg_specified) { // Anyway, consider it already processed. break; } type = s.type; if ( vals == 1 && type == OptionScheme::ARG_ONE ) { // Argument for one-arg option already consumed, // so set to free args. goto EndOfArgs; } goto Found; } } // Not found: set ARG_NONE. // cout << "*D KEY '" << current_key << "' assumed type NONE\n"; EndOfArgs: type = OptionScheme::ARG_VAR; current_key = ""; Found: continue; } // Collected a value - check if full // cout << "*D COLLECTING '" << a << "' for key '" << current_key << "' (" << vals << " so far)\n"; params[current_key].push_back(a); ++vals; if ( vals == 1 && type == OptionScheme::ARG_ONE ) { // cout << "*D KEY TYPE ONE - resetting to empty key\n"; // Reset the key to "default one". current_key = ""; vals = 0; type = OptionScheme::ARG_VAR; } else { // cout << "*D KEY type VAR - still collecting until the end of options or next option.\n"; } } return params; } string OptionHelpItem(const OptionName& o) { string out = "\t-" + o.main_name; string hlp = o.helptext; string prefix; if (hlp == "") { hlp = " (Undocumented)"; } else if (hlp[0] != ' ') { size_t end = string::npos; if (hlp[0] == '<') { end = hlp.find('>'); } else if (hlp[0] == '[') { end = hlp.find(']'); } if (end != string::npos) { ++end; } else { end = hlp.find(' '); } if (end != string::npos) { prefix = hlp.substr(0, end); //while (hlp[end] == ' ') // ++end; hlp = hlp.substr(end); out += " " + prefix; } } out += " -" + hlp; return out; } const char* SRTClockTypeStr() { const int clock_type = srt_clock_type(); switch (clock_type) { case SRT_SYNC_CLOCK_STDCXX_STEADY: return "CXX11_STEADY"; case SRT_SYNC_CLOCK_GETTIME_MONOTONIC: return "GETTIME_MONOTONIC"; case SRT_SYNC_CLOCK_WINQPC: return "WIN_QPC"; case SRT_SYNC_CLOCK_MACH_ABSTIME: return "MACH_ABSTIME"; case SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY: return "POSIX_GETTIMEOFDAY"; default: break; } return "UNKNOWN VALUE"; } void PrintLibVersion() { cerr << "Built with SRT Library version: " << SRT_VERSION << endl; const uint32_t srtver = srt_getversion(); const int major = srtver / 0x10000; const int minor = (srtver / 0x100) % 0x100; const int patch = srtver % 0x100; cerr << "SRT Library version: " << major << "." << minor << "." << patch << ", clock type: " << SRTClockTypeStr() << endl; } srt-1.5.4/apps/apputil.hpp000066400000000000000000000227171471311275400155010ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_APPCOMMON_H #define INC_SRT_APPCOMMON_H #include #include #include #include #include #include "netinet_any.h" #include "utilities.h" #include "srt.h" #if _WIN32 // Keep this below commented out. // This is for a case when you need cpp debugging on Windows. //#ifdef _WINSOCKAPI_ //#error "You include somewhere, remove it. It causes conflicts" //#endif #include #include #include // WIN32 API does not have sleep() and usleep(), Although MINGW does. #ifdef __MINGW32__ #include #else extern "C" inline int sleep(int seconds) { Sleep(seconds * 1000); return 0; } #endif inline bool SysInitializeNetwork() { WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; return WSAStartup(wVersionRequested, &wsaData) == 0; } inline void SysCleanupNetwork() { WSACleanup(); } #else #include #include #include #include #include // Fixes Android build on NDK r16b and earlier. #if defined(__ANDROID__) && (__ANDROID__ == 1) #include #if !defined(__NDK_MAJOR__) || (__NDK_MAJOR__ <= 16) struct ip_mreq_sourceFIXED { struct in_addr imr_multiaddr; struct in_addr imr_interface; struct in_addr imr_sourceaddr; }; #define ip_mreq_source ip_mreq_sourceFIXED #endif #endif // Nothing needs to be done on POSIX; this is a Windows problem. inline bool SysInitializeNetwork() {return true;} inline void SysCleanupNetwork() {} #endif #ifdef _WIN32 inline int SysError() { return ::GetLastError(); } const int SysAGAIN = WSAEWOULDBLOCK; #else inline int SysError() { return errno; } const int SysAGAIN = EAGAIN; #endif srt::sockaddr_any CreateAddr(const std::string& name, unsigned short port = 0, int pref_family = AF_UNSPEC); std::string Join(const std::vector& in, std::string sep); template struct OnReturnSetter { VarType& var; ValType value; OnReturnSetter(VarType& target, ValType v): var(target), value(v) {} ~OnReturnSetter() { var = value; } }; template OnReturnSetter OnReturnSet(VarType& target, ValType v) { return OnReturnSetter(target, v); } // ---- OPTIONS MODULE inline bool CheckTrue(const std::vector& in) { if (in.empty()) return true; const std::set false_vals = { "0", "no", "off", "false" }; if (false_vals.count(in[0])) return false; return true; //if (in[0] != "false" && in[0] != "off") // return true; //return false; } template static inline Number StrToNumber(const std::string& ) { typename Number::incorrect_version wrong = Number::incorrect_version; return Number(); } #define STON(type, function) \ template<> inline type StrToNumber(const std::string& s) { return function (s, 0, 0); } STON(int, stoi); STON(unsigned long, stoul); STON(unsigned int, stoul); STON(long long, stoll); STON(unsigned long long, stoull); #undef STON typedef std::map> options_t; struct OutList { typedef std::vector type; static type process(const options_t::mapped_type& i) { return i; } }; struct OutString { typedef std::string type; static type process(const options_t::mapped_type& i) { return Join(i, " "); } }; struct NumberAutoConvert { std::string value; NumberAutoConvert(): NumberAutoConvert("") {} NumberAutoConvert(const std::string& arg): NumberAutoConvert(arg.c_str()) {} NumberAutoConvert(const char* arg): value(arg) { if (value.empty()) value = "0"; // Must convert to a default 0 number } template operator Number() { return StrToNumber(value); } }; struct OutNumber { typedef NumberAutoConvert type; static type process(const options_t::mapped_type& i) { // Numbers can't be joined, use the "last overrides" rule. if (i.empty()) return {"0"}; return type { i.back() }; } }; template struct OutNumberAs { typedef Number type; static type process(const options_t::mapped_type& i) { return OutNumber::process(i); } }; struct OutBool { typedef bool type; static type process(const options_t::mapped_type& i) { return CheckTrue(i); } }; struct OptionName; struct OptionScheme { const OptionName* pid; enum Args { ARG_NONE, ARG_ONE, ARG_VAR } type; OptionScheme(const OptionScheme&) = default; OptionScheme(OptionScheme&& src) : pid(src.pid) , type(src.type) { } OptionScheme(const OptionName& id, Args tp); const std::set& names() const; }; struct OptionName { std::string helptext; std::string main_name; std::set names; template OptionName(std::string ht, std::string first, Args... rest) : helptext(ht), main_name(first), names {first, rest...} { } template OptionName(std::vector& sc, OptionScheme::Args type, std::string ht, std::string first, Args... rest) : helptext(ht), main_name(first), names {first, rest...} { sc.push_back(OptionScheme(*this, type)); } template OptionName(std::vector& sc, std::string ht, std::string first, Args... rest) : helptext(ht), main_name(first), names {first, rest...} { OptionScheme::Args type = DetermineTypeFromHelpText(ht); sc.push_back(OptionScheme(*this, type)); } OptionName(std::initializer_list args): main_name(*args.begin()), names(args) {} operator std::set() { return names; } operator const std::set() const { return names; } private: static OptionScheme::Args DetermineTypeFromHelpText(const std::string& helptext); }; inline OptionScheme::OptionScheme(const OptionName& id, Args tp): pid(&id), type(tp) {} inline const std::set& OptionScheme::names() const { return pid->names; } template inline typename OutType::type Option(const options_t&, OutValue deflt=OutValue()) { return deflt; } template inline typename OutType::type Option(const options_t& options, OutValue deflt, std::string key, Args... further_keys) { auto i = options.find(key); if ( i == options.end() ) return Option(options, deflt, further_keys...); return OutType::process(i->second); } template struct OptionTrapType { static TrapType pass(TrapType v) { return v; } }; template<> struct OptionTrapType { static std::string pass(const char* v) { return v; } }; template inline typename OutType::type Option(const options_t& options, OutValue deflt, const OptionName& oname) { (void)OptionTrapType::pass(deflt); for (auto key: oname.names) { auto i = options.find(key); if ( i != options.end() ) { return OutType::process(i->second); } } return deflt; } template inline typename OutType::type Option(const options_t& options, const OptionName& oname) { typedef typename OutType::type out_t; for (auto key: oname.names) { auto i = options.find(key); if ( i != options.end() ) { return OutType::process(i->second); } } return out_t(); } inline bool OptionPresent(const options_t& options, const std::set& keys) { for (auto key: keys) { auto i = options.find(key); if ( i != options.end() ) return true; } return false; } options_t ProcessOptions(char* const* argv, int argc, std::vector scheme); std::string OptionHelpItem(const OptionName& o); const char* SRTClockTypeStr(); void PrintLibVersion(); namespace srt { struct OptionSetterProxy { SRTSOCKET s; int result = -1; OptionSetterProxy(SRTSOCKET ss): s(ss) {} struct OptionProxy { OptionSetterProxy& parent; SRT_SOCKOPT opt; #define SPEC(type) \ OptionProxy& operator=(const type& val)\ {\ parent.result = srt_setsockflag(parent.s, opt, &val, sizeof val);\ return *this;\ } SPEC(int32_t); SPEC(int64_t); SPEC(bool); #undef SPEC template OptionProxy& operator=(const char (&val)[N]) { parent.result = srt_setsockflag(parent.s, opt, val, N-1); return *this; } OptionProxy& operator=(const std::string& val) { parent.result = srt_setsockflag(parent.s, opt, val.c_str(), val.size()); return *this; } }; OptionProxy operator[](SRT_SOCKOPT opt) { return OptionProxy {*this, opt}; } operator int() { return result; } }; inline OptionSetterProxy setopt(SRTSOCKET socket) { return OptionSetterProxy(socket); } } #endif // INC_SRT_APPCOMMON_H srt-1.5.4/apps/logsupport.cpp000066400000000000000000000117021471311275400162240ustar00rootroot00000000000000/* * 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/. * */ #include #include #include #include #include #include #include "logsupport.hpp" #include "../srtcore/srt.h" #include "../srtcore/utilities.h" using namespace std; // This is based on codes taken from // This is POSIX standard, so it's not going to change. // Haivision standard only adds one more severity below // DEBUG named DEBUG_TRACE to satisfy all possible needs. map srt_level_names { { "alert", LOG_ALERT }, { "crit", LOG_CRIT }, { "debug", LOG_DEBUG }, { "emerg", LOG_EMERG }, { "err", LOG_ERR }, { "error", LOG_ERR }, /* DEPRECATED */ { "fatal", LOG_CRIT }, // XXX Added for SRT { "info", LOG_INFO }, // WTF? Undefined symbol? { "none", INTERNAL_NOPRI }, /* INTERNAL */ { "notice", LOG_NOTICE }, { "note", LOG_NOTICE }, // XXX Added for SRT { "panic", LOG_EMERG }, /* DEPRECATED */ { "warn", LOG_WARNING }, /* DEPRECATED */ { "warning", LOG_WARNING }, //{ "", -1 } }; srt_logging::LogLevel::type SrtParseLogLevel(string level) { using namespace srt_logging; if ( level.empty() ) return LogLevel::fatal; if ( isdigit(level[0]) ) { long lev = strtol(level.c_str(), 0, 10); if ( lev >= SRT_LOG_LEVEL_MIN && lev <= SRT_LOG_LEVEL_MAX ) return LogLevel::type(lev); cerr << "ERROR: Invalid loglevel number: " << level << " - fallback to FATAL\n"; return LogLevel::fatal; } int (*ToLower)(int) = &std::tolower; // manual overload resolution transform(level.begin(), level.end(), level.begin(), ToLower); auto i = srt_level_names.find(level); if ( i == srt_level_names.end() ) { cerr << "ERROR: Invalid loglevel spec: " << level << " - fallback to FATAL\n"; return LogLevel::fatal; } return LogLevel::type(i->second); } struct ToLowerFormat { char operator()(char in) { if (islower(in)) return in; if (isupper(in)) return tolower(in); if (in == '_') return '-'; throw std::invalid_argument("Wrong FA name - please check the definition in scripts/generate-logging-defs.tcl file"); } }; void LogFANames::Install(string upname, int value) { string id; transform(upname.begin(), upname.end(), back_inserter(id), ToLowerFormat()); namemap[id] = value; } // See logsupport_appdefs.cpp for log FA definitions LogFANames srt_transmit_logfa_names; const map SrtLogFAList() { return srt_transmit_logfa_names.namemap; } set SrtParseLogFA(string fa, set* punknown) { using namespace srt_logging; set fas; // The split algo won't work on empty string. if ( fa == "" ) return fas; auto& names = srt_transmit_logfa_names.namemap; if ( fa == "all" ) { for (auto entry: names) { // Skip "general", it's always on if (entry.first == "general") continue; fas.insert(entry.second); } return fas; } int (*ToLower)(int) = &std::tolower; transform(fa.begin(), fa.end(), fa.begin(), ToLower); vector xfas; size_t pos = 0, ppos = 0; for (;;) { if ( fa[pos] != ',' ) { ++pos; if ( pos < fa.size() ) continue; } size_t n = pos - ppos; if ( n != 0 ) xfas.push_back(fa.substr(ppos, n)); ++pos; if ( pos >= fa.size() ) break; ppos = pos; } for (size_t i = 0; i < xfas.size(); ++i) { fa = xfas[i]; int* pfa = map_getp(names, fa); if (!pfa) { if (punknown) punknown->insert(fa); // If requested, add it back silently else cerr << "ERROR: Invalid log functional area spec: '" << fa << "' - skipping\n"; continue; } fas.insert(*pfa); } return fas; } void ParseLogFASpec(const vector& speclist, string& w_on, string& w_off) { std::ostringstream son, soff; for (auto& s: speclist) { string name; bool on = true; if (s[0] == '+') name = s.substr(1); else if (s[0] == '~') { name = s.substr(1); on = false; } else name = s; if (on) son << "," << name; else soff << "," << name; } const string& sons = son.str(); const string& soffs = soff.str(); w_on = sons.empty() ? string() : sons.substr(1); w_off = soffs.empty() ? string() : soffs.substr(1); } srt-1.5.4/apps/logsupport.hpp000066400000000000000000000017451471311275400162370ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_LOGSUPPORT_HPP #define INC_SRT_LOGSUPPORT_HPP #include #include #include #include "../srtcore/srt.h" #include "../srtcore/logging_api.h" srt_logging::LogLevel::type SrtParseLogLevel(std::string level); std::set SrtParseLogFA(std::string fa, std::set* punknown = nullptr); void ParseLogFASpec(const std::vector& speclist, std::string& w_on, std::string& w_off); const std::map SrtLogFAList(); SRT_API extern std::map srt_level_names; struct LogFANames { std::map namemap; void Install(std::string upname, int value); LogFANames(); }; #endif srt-1.5.4/apps/logsupport_appdefs.cpp000066400000000000000000000026311471311275400177270ustar00rootroot00000000000000/* WARNING: Generated from ../scripts/generate-logging-defs.tcl DO NOT MODIFY. Copyright applies as per the generator script. */ #include "logsupport.hpp" LogFANames::LogFANames() { Install("GENERAL", SRT_LOGFA_GENERAL); Install("SOCKMGMT", SRT_LOGFA_SOCKMGMT); Install("CONN", SRT_LOGFA_CONN); Install("XTIMER", SRT_LOGFA_XTIMER); Install("TSBPD", SRT_LOGFA_TSBPD); Install("RSRC", SRT_LOGFA_RSRC); Install("CONGEST", SRT_LOGFA_CONGEST); Install("PFILTER", SRT_LOGFA_PFILTER); Install("API_CTRL", SRT_LOGFA_API_CTRL); Install("QUE_CTRL", SRT_LOGFA_QUE_CTRL); Install("EPOLL_UPD", SRT_LOGFA_EPOLL_UPD); Install("API_RECV", SRT_LOGFA_API_RECV); Install("BUF_RECV", SRT_LOGFA_BUF_RECV); Install("QUE_RECV", SRT_LOGFA_QUE_RECV); Install("CHN_RECV", SRT_LOGFA_CHN_RECV); Install("GRP_RECV", SRT_LOGFA_GRP_RECV); Install("API_SEND", SRT_LOGFA_API_SEND); Install("BUF_SEND", SRT_LOGFA_BUF_SEND); Install("QUE_SEND", SRT_LOGFA_QUE_SEND); Install("CHN_SEND", SRT_LOGFA_CHN_SEND); Install("GRP_SEND", SRT_LOGFA_GRP_SEND); Install("INTERNAL", SRT_LOGFA_INTERNAL); Install("QUE_MGMT", SRT_LOGFA_QUE_MGMT); Install("CHN_MGMT", SRT_LOGFA_CHN_MGMT); Install("GRP_MGMT", SRT_LOGFA_GRP_MGMT); Install("EPOLL_API", SRT_LOGFA_EPOLL_API); Install("HAICRYPT", SRT_LOGFA_HAICRYPT); Install("APPLOG", SRT_LOGFA_APPLOG); } srt-1.5.4/apps/socketoptions.cpp000066400000000000000000000071321471311275400167140ustar00rootroot00000000000000/* * 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/. * */ #include "socketoptions.hpp" #include "verbose.hpp" using namespace std; extern const set true_names = { "1", "yes", "on", "true" }; extern const set false_names = { "0", "no", "off", "false" }; extern const std::map enummap_transtype = { { "live", SRTT_LIVE }, { "file", SRTT_FILE } }; const char* const SocketOption::mode_names[3] = { "listener", "caller", "rendezvous" }; SocketOption::Mode SrtInterpretMode(const string& modestr, const string& host, const string& adapter) { SocketOption::Mode mode = SocketOption::FAILURE; if (modestr == "client" || modestr == "caller") { mode = SocketOption::CALLER; } else if (modestr == "server" || modestr == "listener") { mode = SocketOption::LISTENER; } else if (modestr == "rendezvous") { mode = SocketOption::RENDEZVOUS; } else if (modestr == "default") { // Use the following convention: // 1. Server for source, Client for target // 2. If host is empty, then always server. if ( host == "" ) mode = SocketOption::LISTENER; //else if ( !dir_output ) //mode = "server"; else { // Host is given, so check also "adapter" if (adapter != "") mode = SocketOption::RENDEZVOUS; else mode = SocketOption::CALLER; } } else { mode = SocketOption::FAILURE; } return mode; } SocketOption::Mode SrtConfigurePre(SRTSOCKET socket, string host, map options, vector* failures) { vector dummy; vector& fails = failures ? *failures : dummy; string modestr = "default", adapter; if (options.count("mode")) { modestr = options["mode"]; } if (options.count("adapter")) { adapter = options["adapter"]; } SocketOption::Mode mode = SrtInterpretMode(modestr, host, adapter); if (mode == SocketOption::FAILURE) { fails.push_back("mode"); } if (options.count("linger")) { linger lin; lin.l_linger = stoi(options["linger"]); lin.l_onoff = lin.l_linger > 0 ? 1 : 0; srt_setsockopt(socket, SocketOption::PRE, SRTO_LINGER, &lin, sizeof(linger)); } bool all_clear = true; for (const auto &o: srt_options) { if ( o.binding == SocketOption::PRE && options.count(o.name) ) { string value = options.at(o.name); bool ok = o.apply(socket, value); if ( !ok ) { fails.push_back(o.name); all_clear = false; } } } return all_clear ? mode : SocketOption::FAILURE; } void SrtConfigurePost(SRTSOCKET socket, map options, vector* failures) { vector dummy; vector& fails = failures ? *failures : dummy; for (const auto &o: srt_options) { if ( o.binding == SocketOption::POST && options.count(o.name) ) { string value = options.at(o.name); Verb() << "Setting option: " << o.name << " = " << value; bool ok = o.apply(socket, value); if ( !ok ) fails.push_back(o.name); } } } srt-1.5.4/apps/socketoptions.hpp000066400000000000000000000223201471311275400167150ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_SOCKETOPTIONS_HPP #define INC_SRT_SOCKETOPTIONS_HPP #include #include #include #include #include "../srtcore/srt.h" // Devel path #ifdef _WIN32 #include "winsock2.h" #endif struct OptionValue { std::string s; union { int i; int64_t l; bool b; }; const void* value = nullptr; size_t size = 0; }; extern const std::set false_names, true_names; struct SocketOption { enum Type { STRING = 0, INT, INT64, BOOL, ENUM }; enum Binding { PRE = 0, POST }; enum Domain { SYSTEM, SRT }; enum Mode {FAILURE = -1, LISTENER = 0, CALLER = 1, RENDEZVOUS = 2}; static const char* const mode_names [3]; std::string name; int protocol; int symbol; Binding binding; Type type; const std::map* valmap; template bool apply(Object socket, std::string value) const; template bool applyt(Object socket, std::string value) const; template static int setso(Object socket, int protocol, int symbol, const void* data, size_t size); template bool extract(std::string value, OptionValue& val) const; }; template<> inline int SocketOption::setso(int socket, int /*ignored*/, int sym, const void* data, size_t size) { return srt_setsockopt(socket, 0, SRT_SOCKOPT(sym), data, (int) size); } #if ENABLE_BONDING template<> inline int SocketOption::setso(SRT_SOCKOPT_CONFIG* obj, int /*ignored*/, int sym, const void* data, size_t size) { return srt_config_add(obj, SRT_SOCKOPT(sym), data, (int) size); } #endif template<> inline int SocketOption::setso(int socket, int proto, int sym, const void* data, size_t size) { return ::setsockopt(socket, proto, sym, (const char *)data, (int) size); } template<> inline bool SocketOption::extract(std::string value, OptionValue& o) const { o.s = value; o.value = o.s.data(); o.size = o.s.size(); return true; } template<> inline bool SocketOption::extract(std::string value, OptionValue& o) const { try { o.i = stoi(value, 0, 0); o.value = &o.i; o.size = sizeof o.i; return true; } catch (...) // stoi throws { return false; // do not change o } return false; } template<> inline bool SocketOption::extract(std::string value, OptionValue& o) const { try { long long vall = stoll(value); o.l = vall; // int64_t resolves to either 'long long', or 'long' being 64-bit integer o.value = &o.l; o.size = sizeof o.l; return true; } catch (...) // stoll throws { return false; } return false; } template<> inline bool SocketOption::extract(std::string value, OptionValue& o) const { bool val; if ( false_names.count(value) ) val = false; else if ( true_names.count(value) ) val = true; else return false; o.b = val; o.value = &o.b; o.size = sizeof o.b; return true; } template<> inline bool SocketOption::extract(std::string value, OptionValue& o) const { if (valmap) { // Search value in the map. If found, set to o. auto p = valmap->find(value); if ( p != valmap->end() ) { o.i = p->second; o.value = &o.i; o.size = sizeof o.i; return true; } } // Fallback: try interpreting it as integer. try { o.i = stoi(value, 0, 0); o.value = &o.i; o.size = sizeof o.i; return true; } catch (...) // stoi throws { return false; // do not change o } return false; } template inline bool SocketOption::applyt(Object socket, std::string value) const { OptionValue o; // common meet point int result = -1; if (extract(value, o)) result = setso(socket, protocol, symbol, o.value, o.size); return result != -1; } template inline bool SocketOption::apply(Object socket, std::string value) const { switch ( type ) { #define SRT_HANDLE_TYPE(ty) case ty: return applyt(socket, value) SRT_HANDLE_TYPE(STRING); SRT_HANDLE_TYPE(INT); SRT_HANDLE_TYPE(INT64); SRT_HANDLE_TYPE(BOOL); SRT_HANDLE_TYPE(ENUM); #undef SRT_HANDLE_TYPE } return false; } extern const std::map enummap_transtype; namespace { const SocketOption srt_options [] { { "transtype", 0, SRTO_TRANSTYPE, SocketOption::PRE, SocketOption::ENUM, &enummap_transtype }, { "maxbw", 0, SRTO_MAXBW, SocketOption::POST, SocketOption::INT64, nullptr}, { "pbkeylen", 0, SRTO_PBKEYLEN, SocketOption::PRE, SocketOption::INT, nullptr}, { "passphrase", 0, SRTO_PASSPHRASE, SocketOption::PRE, SocketOption::STRING, nullptr}, { "mss", 0, SRTO_MSS, SocketOption::PRE, SocketOption::INT, nullptr}, { "fc", 0, SRTO_FC, SocketOption::PRE, SocketOption::INT, nullptr}, { "sndbuf", 0, SRTO_SNDBUF, SocketOption::PRE, SocketOption::INT, nullptr}, { "rcvbuf", 0, SRTO_RCVBUF, SocketOption::PRE, SocketOption::INT, nullptr}, // linger option is handled outside of the common loop, therefore commented out. //{ "linger", 0, SRTO_LINGER, SocketOption::PRE, SocketOption::INT, nullptr}, { "ipttl", 0, SRTO_IPTTL, SocketOption::PRE, SocketOption::INT, nullptr}, { "iptos", 0, SRTO_IPTOS, SocketOption::PRE, SocketOption::INT, nullptr}, { "inputbw", 0, SRTO_INPUTBW, SocketOption::POST, SocketOption::INT64, nullptr}, { "mininputbw", 0, SRTO_MININPUTBW, SocketOption::POST, SocketOption::INT64, nullptr}, { "oheadbw", 0, SRTO_OHEADBW, SocketOption::POST, SocketOption::INT, nullptr}, { "latency", 0, SRTO_LATENCY, SocketOption::PRE, SocketOption::INT, nullptr}, { "tsbpdmode", 0, SRTO_TSBPDMODE, SocketOption::PRE, SocketOption::BOOL, nullptr}, { "tlpktdrop", 0, SRTO_TLPKTDROP, SocketOption::PRE, SocketOption::BOOL, nullptr}, { "snddropdelay", 0, SRTO_SNDDROPDELAY, SocketOption::POST, SocketOption::INT, nullptr}, { "nakreport", 0, SRTO_NAKREPORT, SocketOption::PRE, SocketOption::BOOL, nullptr}, { "conntimeo", 0, SRTO_CONNTIMEO, SocketOption::PRE, SocketOption::INT, nullptr}, { "drifttracer", 0, SRTO_DRIFTTRACER, SocketOption::POST, SocketOption::BOOL, nullptr}, { "lossmaxttl", 0, SRTO_LOSSMAXTTL, SocketOption::POST, SocketOption::INT, nullptr}, { "rcvlatency", 0, SRTO_RCVLATENCY, SocketOption::PRE, SocketOption::INT, nullptr}, { "peerlatency", 0, SRTO_PEERLATENCY, SocketOption::PRE, SocketOption::INT, nullptr}, { "minversion", 0, SRTO_MINVERSION, SocketOption::PRE, SocketOption::INT, nullptr}, { "streamid", 0, SRTO_STREAMID, SocketOption::PRE, SocketOption::STRING, nullptr}, { "congestion", 0, SRTO_CONGESTION, SocketOption::PRE, SocketOption::STRING, nullptr}, { "messageapi", 0, SRTO_MESSAGEAPI, SocketOption::PRE, SocketOption::BOOL, nullptr}, { "payloadsize", 0, SRTO_PAYLOADSIZE, SocketOption::PRE, SocketOption::INT, nullptr}, { "kmrefreshrate", 0, SRTO_KMREFRESHRATE, SocketOption::PRE, SocketOption::INT, nullptr }, { "kmpreannounce", 0, SRTO_KMPREANNOUNCE, SocketOption::PRE, SocketOption::INT, nullptr }, { "enforcedencryption", 0, SRTO_ENFORCEDENCRYPTION, SocketOption::PRE, SocketOption::BOOL, nullptr }, { "ipv6only", 0, SRTO_IPV6ONLY, SocketOption::PRE, SocketOption::INT, nullptr }, { "peeridletimeo", 0, SRTO_PEERIDLETIMEO, SocketOption::PRE, SocketOption::INT, nullptr }, { "packetfilter", 0, SRTO_PACKETFILTER, SocketOption::PRE, SocketOption::STRING, nullptr }, #if ENABLE_BONDING { "groupconnect", 0, SRTO_GROUPCONNECT, SocketOption::PRE, SocketOption::INT, nullptr}, { "groupminstabletimeo", 0, SRTO_GROUPMINSTABLETIMEO, SocketOption::PRE, SocketOption::INT, nullptr}, #endif #ifdef SRT_ENABLE_BINDTODEVICE { "bindtodevice", 0, SRTO_BINDTODEVICE, SocketOption::PRE, SocketOption::STRING, nullptr}, #endif { "retransmitalgo", 0, SRTO_RETRANSMITALGO, SocketOption::PRE, SocketOption::INT, nullptr } #ifdef ENABLE_AEAD_API_PREVIEW ,{ "cryptomode", 0, SRTO_CRYPTOMODE, SocketOption::PRE, SocketOption::INT, nullptr } #endif #ifdef ENABLE_MAXREXMITBW ,{ "maxrexmitbw", 0, SRTO_MAXREXMITBW, SocketOption::POST, SocketOption::INT64, nullptr } #endif }; } SocketOption::Mode SrtInterpretMode(const std::string& modestr, const std::string& host, const std::string& adapter); SocketOption::Mode SrtConfigurePre(SRTSOCKET socket, std::string host, std::map options, std::vector* failures = 0); void SrtConfigurePost(SRTSOCKET socket, std::map options, std::vector* failures = 0); #endif srt-1.5.4/apps/srt-file-transmit.cpp000066400000000000000000000541421471311275400173770ustar00rootroot00000000000000/* * 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/. * */ /***************************************************************************** written by Haivision Systems Inc. *****************************************************************************/ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "apputil.hpp" #include "uriparser.hpp" #include "logsupport.hpp" #include "socketoptions.hpp" #include "transmitmedia.hpp" #include "verbose.hpp" #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif using namespace std; static bool interrupt = false; void OnINT_ForceExit(int) { Verb() << "\n-------- REQUESTED INTERRUPT!\n"; interrupt = true; } struct FileTransmitConfig { unsigned long chunk_size; bool skip_flushing; bool quiet = false; srt_logging::LogLevel::type loglevel = srt_logging::LogLevel::error; set logfas; string logfile; int bw_report = 0; int stats_report = 0; string stats_out; SrtStatsPrintFormat stats_pf = SRTSTATS_PROFMAT_2COLS; bool full_stats = false; string source; string target; }; void PrintOptionHelp(const set &opt_names, const string &value, const string &desc) { cerr << "\t"; int i = 0; for (auto opt : opt_names) { if (i++) cerr << ", "; cerr << "-" << opt; } if (!value.empty()) cerr << ":" << value; cerr << "\t- " << desc << "\n"; } int parse_args(FileTransmitConfig &cfg, int argc, char** argv) { const OptionName o_chunk = { "c", "chunk" }, o_no_flush = { "sf", "skipflush" }, o_bwreport = { "r", "bwreport", "report", "bandwidth-report", "bitrate-report" }, o_statsrep = { "s", "stats", "stats-report-frequency" }, o_statsout = { "statsout" }, o_statspf = { "pf", "statspf" }, o_statsfull = { "f", "fullstats" }, o_loglevel = { "ll", "loglevel" }, o_logfa = { "logfa" }, o_logfile = { "logfile" }, o_quiet = { "q", "quiet" }, o_verbose = { "v", "verbose" }, o_help = { "h", "help" }, o_version = { "version" }; const vector optargs = { { o_chunk, OptionScheme::ARG_ONE }, { o_no_flush, OptionScheme::ARG_NONE }, { o_bwreport, OptionScheme::ARG_ONE }, { o_statsrep, OptionScheme::ARG_ONE }, { o_statsout, OptionScheme::ARG_ONE }, { o_statspf, OptionScheme::ARG_ONE }, { o_statsfull, OptionScheme::ARG_NONE }, { o_loglevel, OptionScheme::ARG_ONE }, { o_logfa, OptionScheme::ARG_ONE }, { o_logfile, OptionScheme::ARG_ONE }, { o_quiet, OptionScheme::ARG_NONE }, { o_verbose, OptionScheme::ARG_NONE }, { o_help, OptionScheme::ARG_NONE }, { o_version, OptionScheme::ARG_NONE } }; options_t params = ProcessOptions(argv, argc, optargs); bool print_help = Option(params, false, o_help); const bool print_version = Option(params, false, o_version); if (params[""].size() != 2 && !print_help && !print_version) { cerr << "ERROR. Invalid syntax. Specify source and target URIs.\n"; if (params[""].size() > 0) { cerr << "The following options are passed without a key: "; copy(params[""].begin(), params[""].end(), ostream_iterator(cerr, ", ")); cerr << endl; } print_help = true; // Enable help to print it further } if (print_help) { cout << "SRT sample application to transmit files.\n"; PrintLibVersion(); cerr << "Usage: srt-file-transmit [options] \n"; cerr << "\n"; PrintOptionHelp(o_chunk, "", "max size of data read in one step"); PrintOptionHelp(o_no_flush, "", "skip output file flushing"); PrintOptionHelp(o_bwreport, "", "bandwidth report frequency"); PrintOptionHelp(o_statsrep, "", "frequency of status report"); PrintOptionHelp(o_statsout, "", "output stats to file"); PrintOptionHelp(o_statspf, "", "stats printing format [json|csv|default]"); PrintOptionHelp(o_statsfull, "", "full counters in stats-report (prints total statistics)"); PrintOptionHelp(o_loglevel, "", "log level [fatal,error,info,note,warning]"); PrintOptionHelp(o_logfa, "", "log functional area [all,general,bstats,control,data,tsbpd,rexmit]"); PrintOptionHelp(o_logfile, "", "write logs to file"); PrintOptionHelp(o_quiet, "", "quiet mode (default off)"); PrintOptionHelp(o_verbose, "", "verbose mode (default off)"); cerr << "\n"; cerr << "\t-h,-help - show this help\n"; cerr << "\t-version - print SRT library version\n"; cerr << "\n"; cerr << "\t - URI specifying a medium to read from\n"; cerr << "\t - URI specifying a medium to write to\n"; cerr << "URI syntax: SCHEME://HOST:PORT/PATH?PARAM1=VALUE&PARAM2=VALUE...\n"; cerr << "Supported schemes:\n"; cerr << "\tsrt: use HOST, PORT, and PARAM for setting socket options\n"; cerr << "\tudp: use HOST, PORT and PARAM for some UDP specific settings\n"; cerr << "\tfile: file URI or file://con to use stdin or stdout\n"; return 2; } if (Option(params, false, o_version)) { PrintLibVersion(); return 2; } cfg.chunk_size = stoul(Option(params, "1456", 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)); cfg.stats_out = Option(params, "", o_statsout); const string pf = Option(params, "default", o_statspf); if (pf == "default") { cfg.stats_pf = SRTSTATS_PROFMAT_2COLS; } else if (pf == "json") { cfg.stats_pf = SRTSTATS_PROFMAT_JSON; } else if (pf == "csv") { cfg.stats_pf = SRTSTATS_PROFMAT_CSV; } else { cfg.stats_pf = SRTSTATS_PROFMAT_2COLS; cerr << "ERROR: Unsupported print format: " << pf << endl; return 1; } cfg.full_stats = Option(params, false, o_statsfull); cfg.loglevel = SrtParseLogLevel(Option(params, "error", o_loglevel)); cfg.logfas = SrtParseLogFA(Option(params, "", o_logfa)); cfg.logfile = Option(params, "", o_logfile); cfg.quiet = Option(params, false, o_quiet); if (Option(params, false, o_verbose)) Verbose::on = !cfg.quiet; cfg.source = params[""].at(0); cfg.target = params[""].at(1); return 0; } void ExtractPath(string path, string& w_dir, string& w_fname) { string directory = path; string filename = ""; struct stat state; stat(path.c_str(), &state); if (!S_ISDIR(state.st_mode)) { // Extract directory as a butlast part of path size_t pos = path.find_last_of("/"); if ( pos == string::npos ) { filename = path; directory = "."; } else { directory = path.substr(0, pos); filename = path.substr(pos+1); } } if (directory[0] != '/') { // Glue in the absolute prefix of the current directory // to make it absolute. This is needed to properly interpret // the fixed uri. static const size_t s_max_path = 4096; // don't care how proper this is char tmppath[s_max_path]; #ifdef _WIN32 const char* gwd = _getcwd(tmppath, s_max_path); #else const char* gwd = getcwd(tmppath, s_max_path); #endif if ( !gwd ) { // Don't bother with that now. We need something better for // that anyway. throw std::invalid_argument("Path too long"); } const string wd = gwd; directory = wd + "/" + directory; } w_dir = directory; w_fname = filename; } bool DoUpload(UriParser& ut, string path, string filename, const FileTransmitConfig &cfg, std::ostream &out_stats) { bool result = false; unique_ptr tar; SRTSOCKET s = SRT_INVALID_SOCK; bool connected = false; int pollid = -1; ifstream ifile(path, ios::binary); if ( !ifile ) { cerr << "Error opening file: '" << path << "'"; goto exit; } pollid = srt_epoll_create(); if ( pollid < 0 ) { cerr << "Can't initialize epoll"; goto exit; } while (!interrupt) { if (!tar.get()) { tar = Target::Create(ut.makeUri()); if (!tar.get()) { cerr << "Unsupported target type: " << ut.uri() << endl; goto exit; } int events = SRT_EPOLL_OUT | SRT_EPOLL_ERR; if (srt_epoll_add_usock(pollid, tar->GetSRTSocket(), &events)) { cerr << "Failed to add SRT destination to poll, " << tar->GetSRTSocket() << endl; goto exit; } srt::setstreamid(tar->GetSRTSocket(), filename); } s = tar->GetSRTSocket(); assert(s != SRT_INVALID_SOCK); SRTSOCKET efd; int efdlen = 1; if (srt_epoll_wait(pollid, 0, 0, &efd, &efdlen, 100, nullptr, nullptr, 0, 0) < 0) { continue; } assert(efd == s); assert(efdlen == 1); SRT_SOCKSTATUS status = srt_getsockstate(s); switch (status) { case SRTS_LISTENING: { if (!tar->AcceptNewClient()) { cerr << "Failed to accept SRT connection" << endl; goto exit; } srt_epoll_remove_usock(pollid, s); s = tar->GetSRTSocket(); int events = SRT_EPOLL_OUT | SRT_EPOLL_ERR; if (srt_epoll_add_usock(pollid, s, &events)) { cerr << "Failed to add SRT client to poll" << endl; goto exit; } cerr << "Target connected (listener)" << endl; connected = true; } break; case SRTS_CONNECTED: { if (!connected) { cerr << "Target connected (caller)" << endl; connected = true; } } break; case SRTS_BROKEN: case SRTS_NONEXIST: case SRTS_CLOSED: { cerr << "Target disconnected" << endl; goto exit; } default: { // No-Op } break; } if (connected) { vector buf(cfg.chunk_size); size_t n = ifile.read(buf.data(), cfg.chunk_size).gcount(); size_t shift = 0; while (n > 0) { int st = tar->Write(buf.data() + shift, n, 0, out_stats); Verb() << "Upload: " << n << " --> " << st << (!shift ? string() : "+" + Sprint(shift)); if (st == SRT_ERROR) { cerr << "Upload: SRT error: " << srt_getlasterror_str() << endl; goto exit; } n -= st; shift += st; } if (ifile.eof()) { cerr << "File sent" << endl; result = true; break; } if ( !ifile.good() ) { cerr << "ERROR while reading file\n"; goto exit; } } } if (result && !cfg.skip_flushing) { assert(s != SRT_INVALID_SOCK); // send-flush-loop result = false; while (!interrupt) { size_t bytes; size_t blocks; int st = srt_getsndbuffer(s, &blocks, &bytes); if (st == SRT_ERROR) { cerr << "Error in srt_getsndbuffer: " << srt_getlasterror_str() << endl; goto exit; } if (bytes == 0) { cerr << "Buffers flushed" << endl; result = true; break; } Verb() << "Sending buffer still: bytes=" << bytes << " blocks=" << blocks; srt::sync::this_thread::sleep_for(srt::sync::milliseconds_from(250)); } } exit: if (pollid >= 0) { srt_epoll_release(pollid); } return result; } bool DoDownload(UriParser& us, string directory, string filename, const FileTransmitConfig &cfg, std::ostream &out_stats) { bool result = false; unique_ptr src; SRTSOCKET s = SRT_INVALID_SOCK; bool connected = false; int pollid = -1; string id; ofstream ofile; SRT_SOCKSTATUS status; SRTSOCKET efd; int efdlen = 1; pollid = srt_epoll_create(); if ( pollid < 0 ) { cerr << "Can't initialize epoll"; goto exit; } while (!interrupt) { if (!src.get()) { src = Source::Create(us.makeUri()); if (!src.get()) { cerr << "Unsupported source type: " << us.uri() << endl; goto exit; } int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; if (srt_epoll_add_usock(pollid, src->GetSRTSocket(), &events)) { cerr << "Failed to add SRT source to poll, " << src->GetSRTSocket() << endl; goto exit; } } s = src->GetSRTSocket(); assert(s != SRT_INVALID_SOCK); if (srt_epoll_wait(pollid, &efd, &efdlen, 0, 0, 100, nullptr, nullptr, 0, 0) < 0) { continue; } assert(efd == s); assert(efdlen == 1); status = srt_getsockstate(s); Verb() << "Event with status " << status << "\n"; switch (status) { case SRTS_LISTENING: { if (!src->AcceptNewClient()) { cerr << "Failed to accept SRT connection" << endl; goto exit; } srt_epoll_remove_usock(pollid, s); s = src->GetSRTSocket(); int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; if (srt_epoll_add_usock(pollid, s, &events)) { cerr << "Failed to add SRT client to poll" << endl; goto exit; } id = srt::getstreamid(s); cerr << "Source connected (listener), id [" << id << "]" << endl; connected = true; continue; } break; case SRTS_CONNECTED: { if (!connected) { id = srt::getstreamid(s); cerr << "Source connected (caller), id [" << id << "]" << endl; connected = true; } } break; // No need to do any special action in case of broken. // The app will just try to read and in worst case it will // get an error. case SRTS_BROKEN: cerr << "Connection closed, reading buffer remains\n"; break; case SRTS_NONEXIST: case SRTS_CLOSED: { cerr << "Source disconnected" << endl; goto exit; } break; default: { // No-Op } break; } if (connected) { MediaPacket packet(cfg.chunk_size); if (!ofile.is_open()) { const char * fn = id.empty() ? filename.c_str() : id.c_str(); directory.append("/"); directory.append(fn); ofile.open(directory.c_str(), ios::out | ios::trunc | ios::binary); if (!ofile.is_open()) { cerr << "Error opening file [" << directory << "]" << endl; goto exit; } cerr << "Writing output to [" << directory << "]" << endl; } int n = src->Read(cfg.chunk_size, packet, out_stats); if (n == SRT_ERROR) { cerr << "Download: SRT error: " << srt_getlasterror_str() << endl; goto exit; } if (n == 0) { result = true; cerr << "Download COMPLETE.\n"; break; } // Write to file any amount of data received Verb() << "Download: --> " << n; ofile.write(packet.payload.data(), n); if (!ofile.good()) { cerr << "Error writing file" << endl; goto exit; } } } exit: if (pollid >= 0) { srt_epoll_release(pollid); } return result; } bool Upload(UriParser& srt_target_uri, UriParser& fileuri, const FileTransmitConfig &cfg, std::ostream &out_stats) { if ( fileuri.scheme() != "file" ) { cerr << "Upload: source accepted only as a file\n"; return false; } // fileuri is source-reading file // srt_target_uri is SRT target string path = fileuri.path(); string directory, filename; ExtractPath(path, (directory), (filename)); Verb() << "Extract path '" << path << "': directory=" << directory << " filename=" << filename; // Set ID to the filename. // Directory will be preserved. // Add some extra parameters. srt_target_uri["transtype"] = "file"; return DoUpload(srt_target_uri, path, filename, cfg, out_stats); } bool Download(UriParser& srt_source_uri, UriParser& fileuri, const FileTransmitConfig &cfg, std::ostream &out_stats) { if (fileuri.scheme() != "file" ) { cerr << "Download: target accepted only as a file\n"; return false; } string path = fileuri.path(), directory, filename; ExtractPath(path, (directory), (filename)); Verb() << "Extract path '" << path << "': directory=" << directory << " filename=" << filename; // Add some extra parameters. srt_source_uri["transtype"] = "file"; return DoDownload(srt_source_uri, directory, filename, cfg, out_stats); } int main(int argc, char** argv) { FileTransmitConfig cfg; const int parse_ret = parse_args(cfg, argc, argv); if (parse_ret != 0) return parse_ret == 1 ? EXIT_FAILURE : 0; // // Set global config variables // if (cfg.chunk_size != SRT_LIVE_MAX_PLSIZE) transmit_chunk_size = cfg.chunk_size; transmit_stats_writer = SrtStatsWriterFactory(cfg.stats_pf); transmit_bw_report = cfg.bw_report; transmit_stats_report = cfg.stats_report; transmit_total_stats = cfg.full_stats; // // Set SRT log levels and functional areas // srt_setloglevel(cfg.loglevel); for (set::iterator i = cfg.logfas.begin(); i != cfg.logfas.end(); ++i) srt_addlogfa(*i); // // SRT log handler // std::ofstream logfile_stream; // leave unused if not set if (!cfg.logfile.empty()) { logfile_stream.open(cfg.logfile.c_str()); if (!logfile_stream) { cerr << "ERROR: Can't open '" << cfg.logfile.c_str() << "' for writing - fallback to cerr\n"; } else { srt::setlogstream(logfile_stream); } } // // SRT stats output // std::ofstream logfile_stats; // leave unused if not set if (cfg.stats_out != "" && cfg.stats_out != "stdout") { logfile_stats.open(cfg.stats_out.c_str()); if (!logfile_stats) { cerr << "ERROR: Can't open '" << cfg.stats_out << "' for writing stats. Fallback to stdout.\n"; return 1; } } else if (cfg.bw_report != 0 || cfg.stats_report != 0) { g_stats_are_printed_to_stdout = true; } ostream &out_stats = logfile_stats.is_open() ? logfile_stats : cout; // File transmission code UriParser us(cfg.source), ut(cfg.target); Verb() << "SOURCE type=" << us.scheme() << ", TARGET type=" << ut.scheme(); signal(SIGINT, OnINT_ForceExit); signal(SIGTERM, OnINT_ForceExit); try { if (us.scheme() == "srt") { if (ut.scheme() != "file") { cerr << "SRT to FILE should be specified\n"; return 1; } Download(us, ut, cfg, out_stats); } else if (ut.scheme() == "srt") { if (us.scheme() != "file") { cerr << "FILE to SRT should be specified\n"; return 1; } Upload(ut, us, cfg, out_stats); } else { cerr << "SRT URI must be one of given media.\n"; return 1; } } catch (std::exception& x) { cerr << "ERROR: " << x.what() << endl; return 1; } return 0; } srt-1.5.4/apps/srt-live-transmit.cpp000066400000000000000000000754121471311275400174220ustar00rootroot00000000000000/* * 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/. * */ // NOTE: This application uses C++11. // This program uses quite a simple architecture, which is mainly related to // the way how it's invoked: srt-live-transmit (plus options). // // The media for and are filled by abstract classes // named Source and Target respectively. Most important virtuals to // be filled by the derived classes are Source::Read and Target::Write. // // For SRT please take a look at the SrtCommon class first. This contains // everything that is needed for creating an SRT medium, that is, making // a connection as listener, as caller, and as rendezvous. The listener // and caller modes are built upon the same philosophy as those for // BSD/POSIX socket API (bind/listen/accept or connect). // // The instance class is selected per details in the URI (usually scheme) // and then this URI is used to configure the medium object. Medium-specific // options are specified in the URI: SCHEME://HOST:PORT?opt1=val1&opt2=val2 etc. // // Options for connection are set by ConfigurePre and ConfigurePost. // This is a philosophy that exists also in BSD/POSIX sockets, just not // officially mentioned: // - The "PRE" options must be set prior to connecting and can't be altered // on a connected socket, however if set on a listening socket, they are // derived by accept-ed socket. // - The "POST" options can be altered any time on a connected socket. // They MAY have also some meaning when set prior to connecting; such // option is SRTO_RCVSYN, which makes connect/accept call asynchronous. // Because of that this option is treated special way in this app. // // See 'srt_options' global variable (common/socketoptions.hpp) for a list of // all options. // MSVS likes to complain about lots of standard C functions being unsafe. #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS 1 #endif #define REQUIRE_CXX11 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "srt_compat.h" #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" #include "logsupport.hpp" #include "transmitmedia.hpp" #include "verbose.hpp" // NOTE: This is without "haisrt/" because it uses an internal path // to the library. Application using the "installed" library should // use #include #include // This TEMPORARILY contains extra C++-only SRT API. #include using namespace std; struct ForcedExit: public std::runtime_error { ForcedExit(const std::string& arg): std::runtime_error(arg) { } }; struct AlarmExit: public std::runtime_error { AlarmExit(const std::string& arg): std::runtime_error(arg) { } }; srt::sync::atomic int_state; srt::sync::atomic timer_state; void OnINT_ForceExit(int) { Verb() << "\n-------- REQUESTED INTERRUPT!\n"; int_state = true; } void OnAlarm_Interrupt(int) { Verb() << "\n---------- INTERRUPT ON TIMEOUT!\n"; int_state = false; // JIC timer_state = true; if ((false)) { throw AlarmExit("Watchdog bites hangup"); } } extern "C" void TestLogHandler(void* opaque, int level, const char* file, int line, const char* area, const char* message); struct LiveTransmitConfig { int timeout = 0; int timeout_mode = 0; int chunk_size = -1; bool quiet = false; srt_logging::LogLevel::type loglevel = srt_logging::LogLevel::error; set logfas; bool log_internal; string logfile; int bw_report = 0; bool srctime = false; size_t buffering = 10; int stats_report = 0; string stats_out; SrtStatsPrintFormat stats_pf = SRTSTATS_PROFMAT_2COLS; bool auto_reconnect = true; bool full_stats = false; string source; string target; }; void PrintOptionHelp(const OptionName& opt_names, const string &value, const string &desc) { cerr << "\t"; int i = 0; for (auto opt : opt_names.names) { if (i++) cerr << ", "; cerr << "-" << opt; } if (!value.empty()) cerr << ":" << value; cerr << "\t- " << desc << "\n"; } int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) { const OptionName o_timeout = { "t", "to", "timeout" }, o_timeout_mode = { "tm", "timeout-mode" }, o_autorecon = { "a", "auto", "autoreconnect" }, o_chunk = { "c", "chunk" }, o_bwreport = { "r", "bwreport", "report", "bandwidth-report", "bitrate-report" }, o_srctime = {"st", "srctime", "sourcetime"}, o_buffering = {"buffering"}, o_statsrep = { "s", "stats", "stats-report-frequency" }, o_statsout = { "statsout" }, o_statspf = { "pf", "statspf" }, o_statsfull = { "f", "fullstats" }, o_loglevel = { "ll", "loglevel" }, o_logfa = { "lfa", "logfa" }, o_log_internal = { "loginternal"}, o_logfile = { "logfile" }, o_quiet = { "q", "quiet" }, o_verbose = { "v", "verbose" }, o_help = { "h", "help" }, o_version = { "version" }; const vector optargs = { { o_timeout, OptionScheme::ARG_ONE }, { o_timeout_mode, OptionScheme::ARG_ONE }, { o_autorecon, OptionScheme::ARG_ONE }, { o_chunk, OptionScheme::ARG_ONE }, { o_bwreport, OptionScheme::ARG_ONE }, { o_srctime, OptionScheme::ARG_ONE }, { o_buffering, OptionScheme::ARG_ONE }, { o_statsrep, OptionScheme::ARG_ONE }, { o_statsout, OptionScheme::ARG_ONE }, { o_statspf, OptionScheme::ARG_ONE }, { o_statsfull, OptionScheme::ARG_NONE }, { o_loglevel, OptionScheme::ARG_ONE }, { o_logfa, OptionScheme::ARG_ONE }, { o_log_internal, OptionScheme::ARG_NONE }, { o_logfile, OptionScheme::ARG_ONE }, { o_quiet, OptionScheme::ARG_NONE }, { o_verbose, OptionScheme::ARG_NONE }, { o_help, OptionScheme::ARG_VAR }, { o_version, OptionScheme::ARG_NONE } }; options_t params = ProcessOptions(argv, argc, optargs); bool print_help = OptionPresent(params, o_help); const bool print_version = OptionPresent(params, o_version); if (params[""].size() != 2 && !print_help && !print_version) { cerr << "ERROR. Invalid syntax. Specify source and target URIs.\n"; if (params[""].size() > 0) { cerr << "The following options are passed without a key: "; copy(params[""].begin(), params[""].end(), ostream_iterator(cerr, ", ")); cerr << endl; } print_help = true; // Enable help to print it further } if (print_help) { string helpspec = Option(params, o_help); if (helpspec == "logging") { cerr << "Logging options:\n"; cerr << " -ll - specify minimum log level\n"; cerr << " -lfa - specify functional areas\n"; cerr << "Where:\n\n"; cerr << " : fatal error note warning debug\n\n"; cerr << "Turns on logs that are at the given log level or any higher level\n"; cerr << "(all to the left in the list above from the selected level).\n"; cerr << "Names from syslog, like alert, crit, emerg, err, info, panic, are also\n"; cerr << "recognized, but they are aligned to those that lie close in the above hierarchy.\n\n"; cerr << " is a coma-separated list of areas to turn on.\n\n"; cerr << "The list may include 'all' to turn all FAs on.\n"; cerr << "Example: `-lfa:sockmgmt,chn-recv` enables only `sockmgmt` and `chn-recv` log FAs.\n"; cerr << "Default: all are on except haicrypt. NOTE: 'general' FA can't be disabled.\n\n"; cerr << "List of functional areas:\n"; map revmap; for (auto entry: SrtLogFAList()) revmap[entry.second] = entry.first; // Each group on a new line int en10 = 0; for (auto entry: revmap) { cerr << " " << entry.second; if (entry.first/10 != en10) { cerr << endl; en10 = entry.first/10; } } cerr << endl; return 1; } cout << "SRT sample application to transmit live streaming.\n"; PrintLibVersion(); cerr << "Usage: srt-live-transmit [options] \n"; cerr << "\n"; #ifndef _WIN32 PrintOptionHelp(o_timeout, "", "exit timer in seconds"); PrintOptionHelp(o_timeout_mode, "", "timeout mode (0 - since app start; 1 - like 0, but cancel on connect"); #endif PrintOptionHelp(o_autorecon, "", "auto-reconnect mode {yes, no}"); PrintOptionHelp(o_chunk, "", "max size of data read in one step, that can fit one SRT packet"); PrintOptionHelp(o_bwreport, "", "bandwidth report frequency"); PrintOptionHelp(o_srctime, "", "Pass packet time from source to SRT output {yes, no}"); PrintOptionHelp(o_buffering, "", "Buffer up to n incoming packets"); PrintOptionHelp(o_statsrep, "", "frequency of status report"); PrintOptionHelp(o_statsout, "", "output stats to file"); PrintOptionHelp(o_statspf, "", "stats printing format {json, csv, default}"); PrintOptionHelp(o_statsfull, "", "full counters in stats-report (prints total statistics)"); PrintOptionHelp(o_loglevel, "", "log level {fatal,error,warn,note,info,debug}"); PrintOptionHelp(o_logfa, "", "log functional area (see '-h logging' for more info)"); //PrintOptionHelp(o_log_internal, "", "use internal logger"); PrintOptionHelp(o_logfile, "", "write logs to file"); PrintOptionHelp(o_quiet, "", "quiet mode (default off)"); PrintOptionHelp(o_verbose, "", "verbose mode (default off)"); cerr << "\n"; cerr << "\t-h,-help - show this help (use '-h logging' for logging system)\n"; cerr << "\t-version - print SRT library version\n"; cerr << "\n"; cerr << "\t - URI specifying a medium to read from\n"; cerr << "\t - URI specifying a medium to write to\n"; cerr << "URI syntax: SCHEME://HOST:PORT/PATH?PARAM1=VALUE&PARAM2=VALUE...\n"; cerr << "Supported schemes:\n"; cerr << "\tsrt: use HOST, PORT, and PARAM for setting socket options\n"; cerr << "\tudp: use HOST, PORT and PARAM for some UDP specific settings\n"; cerr << "\tfile: only as file://con for using stdin or stdout\n"; return 2; } if (print_version) { PrintLibVersion(); return 2; } cfg.timeout = Option(params, o_timeout); cfg.timeout_mode = Option(params, o_timeout_mode); cfg.chunk_size = Option(params, "-1", o_chunk); cfg.srctime = Option(params, cfg.srctime, o_srctime); const int buffering = Option(params, "10", o_buffering); if (buffering <= 0) { cerr << "ERROR: Buffering value should be positive. Value provided: " << buffering << "." << endl; return 1; } else { cfg.buffering = (size_t) buffering; } cfg.bw_report = Option(params, o_bwreport); cfg.stats_report = Option(params, o_statsrep); cfg.stats_out = Option(params, o_statsout); const string pf = Option(params, "default", o_statspf); string pfext; cfg.stats_pf = ParsePrintFormat(pf, (pfext)); if (cfg.stats_pf == SRTSTATS_PROFMAT_INVALID) { cfg.stats_pf = SRTSTATS_PROFMAT_2COLS; cerr << "ERROR: Unsupported print format: " << pf << " -- fallback to default" << endl; return 1; } cfg.full_stats = OptionPresent(params, o_statsfull); cfg.loglevel = SrtParseLogLevel(Option(params, "warn", o_loglevel)); cfg.logfas = SrtParseLogFA(Option(params, "", o_logfa)); cfg.log_internal = OptionPresent(params, o_log_internal); cfg.logfile = Option(params, o_logfile); cfg.quiet = OptionPresent(params, o_quiet); if (OptionPresent(params, o_verbose)) Verbose::on = !cfg.quiet; cfg.auto_reconnect = Option(params, true, o_autorecon); cfg.source = params[""].at(0); cfg.target = params[""].at(1); return 0; } int main(int argc, char** argv) { srt_startup(); // This is mainly required on Windows to initialize the network system, // for a case when the instance would use UDP. SRT does it on its own, independently. if (!SysInitializeNetwork()) throw std::runtime_error("Can't initialize network!"); // Symmetrically, this does a cleanup; put into a local destructor to ensure that // it's called regardless of how this function returns. struct NetworkCleanup { ~NetworkCleanup() { srt_cleanup(); SysCleanupNetwork(); } } cleanupobj; LiveTransmitConfig cfg; const int parse_ret = parse_args(cfg, argc, argv); if (parse_ret != 0) return parse_ret == 1 ? EXIT_FAILURE : 0; // // Set global config variables // if (cfg.chunk_size > 0) transmit_chunk_size = cfg.chunk_size; transmit_stats_writer = SrtStatsWriterFactory(cfg.stats_pf); transmit_bw_report = cfg.bw_report; transmit_stats_report = cfg.stats_report; transmit_total_stats = cfg.full_stats; // // Set SRT log levels and functional areas // srt_setloglevel(cfg.loglevel); if (!cfg.logfas.empty()) { srt_resetlogfa(nullptr, 0); for (set::iterator i = cfg.logfas.begin(); i != cfg.logfas.end(); ++i) srt_addlogfa(*i); } // // SRT log handler // std::ofstream logfile_stream; // leave unused if not set char NAME[] = "SRTLIB"; if (cfg.log_internal) { srt_setlogflags(0 | SRT_LOGF_DISABLE_TIME | SRT_LOGF_DISABLE_SEVERITY | SRT_LOGF_DISABLE_THREADNAME | SRT_LOGF_DISABLE_EOL ); srt_setloghandler(NAME, TestLogHandler); } else if (!cfg.logfile.empty()) { logfile_stream.open(cfg.logfile.c_str()); if (!logfile_stream) { cerr << "ERROR: Can't open '" << cfg.logfile.c_str() << "' for writing - fallback to cerr\n"; } else { srt::setlogstream(logfile_stream); } } // // SRT stats output // std::ofstream logfile_stats; // leave unused if not set if (cfg.stats_out != "") { logfile_stats.open(cfg.stats_out.c_str()); if (!logfile_stats) { cerr << "ERROR: Can't open '" << cfg.stats_out << "' for writing stats. Fallback to stdout.\n"; logfile_stats.close(); } } else if (cfg.bw_report != 0 || cfg.stats_report != 0) { g_stats_are_printed_to_stdout = true; } ostream &out_stats = logfile_stats.is_open() ? logfile_stats : cout; #ifdef _WIN32 if (cfg.timeout != 0) { cerr << "ERROR: The -timeout option (-t) is not implemented on Windows\n"; return EXIT_FAILURE; } #else if (cfg.timeout > 0) { signal(SIGALRM, OnAlarm_Interrupt); if (!cfg.quiet) cerr << "TIMEOUT: will interrupt after " << cfg.timeout << "s\n"; alarm(cfg.timeout); } #endif signal(SIGINT, OnINT_ForceExit); signal(SIGTERM, OnINT_ForceExit); if (!cfg.quiet) { cerr << "Media path: '" << cfg.source << "' --> '" << cfg.target << "'\n"; } unique_ptr src; bool srcConnected = false; unique_ptr tar; bool tarConnected = false; int pollid = srt_epoll_create(); if (pollid < 0) { cerr << "Can't initialize epoll"; return 1; } size_t receivedBytes = 0; size_t wroteBytes = 0; size_t lostBytes = 0; size_t lastReportedtLostBytes = 0; std::time_t writeErrorLogTimer(std::time(nullptr)); try { // Now loop until broken while (!int_state && !timer_state) { if (!src.get()) { src = Source::Create(cfg.source); if (!src.get()) { cerr << "Unsupported source type" << endl; return 1; } int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; switch (src->uri.type()) { case UriParser::SRT: if (srt_epoll_add_usock(pollid, src->GetSRTSocket(), &events)) { cerr << "Failed to add SRT source to poll, " << src->GetSRTSocket() << endl; return 1; } break; case UriParser::UDP: case UriParser::RTP: if (srt_epoll_add_ssock(pollid, src->GetSysSocket(), &events)) { cerr << "Failed to add " << src->uri.proto() << " source to poll, " << src->GetSysSocket() << endl; return 1; } break; case UriParser::FILE: if (srt_epoll_add_ssock(pollid, src->GetSysSocket(), &events)) { cerr << "Failed to add FILE source to poll, " << src->GetSysSocket() << endl; return 1; } break; default: break; } receivedBytes = 0; } if (!tar.get()) { tar = Target::Create(cfg.target); if (!tar.get()) { cerr << "Unsupported target type" << endl; return 1; } // IN because we care for state transitions only // OUT - to check the connection state changes int events = SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR; switch(tar->uri.type()) { case UriParser::SRT: if (srt_epoll_add_usock(pollid, tar->GetSRTSocket(), &events)) { cerr << "Failed to add SRT destination to poll, " << tar->GetSRTSocket() << endl; return 1; } break; default: break; } wroteBytes = 0; lostBytes = 0; lastReportedtLostBytes = 0; } int srtrfdslen = 2; int srtwfdslen = 2; SRTSOCKET srtrwfds[4] = {SRT_INVALID_SOCK, SRT_INVALID_SOCK , SRT_INVALID_SOCK , SRT_INVALID_SOCK }; int sysrfdslen = 2; SYSSOCKET sysrfds[2]; if (srt_epoll_wait(pollid, &srtrwfds[0], &srtrfdslen, &srtrwfds[2], &srtwfdslen, 100, &sysrfds[0], &sysrfdslen, 0, 0) >= 0) { bool doabort = false; for (size_t i = 0; i < sizeof(srtrwfds) / sizeof(SRTSOCKET); i++) { SRTSOCKET s = srtrwfds[i]; if (s == SRT_INVALID_SOCK) continue; // Remove duplicated sockets for (size_t j = i + 1; j < sizeof(srtrwfds) / sizeof(SRTSOCKET); j++) { const SRTSOCKET next_s = srtrwfds[j]; if (next_s == s) srtrwfds[j] = SRT_INVALID_SOCK; } bool issource = false; if (src && src->GetSRTSocket() == s) { issource = true; } else if (tar && tar->GetSRTSocket() != s) { continue; } const char * dirstring = (issource) ? "source" : "target"; SRT_SOCKSTATUS status = srt_getsockstate(s); switch (status) { case SRTS_LISTENING: { const bool res = (issource) ? src->AcceptNewClient() : tar->AcceptNewClient(); if (!res) { cerr << "Failed to accept SRT connection" << endl; doabort = true; break; } srt_epoll_remove_usock(pollid, s); SRTSOCKET ns = (issource) ? src->GetSRTSocket() : tar->GetSRTSocket(); int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; if (srt_epoll_add_usock(pollid, ns, &events)) { cerr << "Failed to add SRT client to poll, " << ns << endl; doabort = true; } else { if (!cfg.quiet) { cerr << "Accepted SRT " << dirstring << " connection" << endl; } #ifndef _WIN32 if (cfg.timeout_mode == 1 && cfg.timeout > 0) { if (!cfg.quiet) cerr << "TIMEOUT: cancel\n"; alarm(0); } #endif if (issource) srcConnected = true; else tarConnected = true; } } break; case SRTS_BROKEN: case SRTS_NONEXIST: case SRTS_CLOSED: { if (issource) { if (srcConnected) { if (!cfg.quiet) { cerr << "SRT source disconnected" << endl; } srcConnected = false; } } else if (tarConnected) { if (!cfg.quiet) cerr << "SRT target disconnected" << endl; tarConnected = false; } if(!cfg.auto_reconnect) { doabort = true; } else { // force re-connection srt_epoll_remove_usock(pollid, s); if (issource) src.reset(); else tar.reset(); #ifndef _WIN32 if (cfg.timeout_mode == 1 && cfg.timeout > 0) { if (!cfg.quiet) cerr << "TIMEOUT: will interrupt after " << cfg.timeout << "s\n"; alarm(cfg.timeout); } #endif } } break; case SRTS_CONNECTED: { if (issource) { if (!srcConnected) { if (!cfg.quiet) cerr << "SRT source connected" << endl; srcConnected = true; } } else if (!tarConnected) { if (!cfg.quiet) cerr << "SRT target connected" << endl; tarConnected = true; if (tar->uri.type() == UriParser::SRT) { const int events = SRT_EPOLL_IN | SRT_EPOLL_ERR; // Disable OUT event polling when connected if (srt_epoll_update_usock(pollid, tar->GetSRTSocket(), &events)) { cerr << "Failed to add SRT destination to poll, " << tar->GetSRTSocket() << endl; return 1; } } #ifndef _WIN32 if (cfg.timeout_mode == 1 && cfg.timeout > 0) { if (!cfg.quiet) cerr << "TIMEOUT: cancel\n"; alarm(0); } #endif } } default: { // No-Op } break; } } if (doabort) { break; } // read a few chunks at a time in attempt to deplete // read buffers as much as possible on each read event // note that this implies live streams and does not // work for cached/file sources std::list> dataqueue; if (src.get() && src->IsOpen() && (srtrfdslen || sysrfdslen)) { while (dataqueue.size() < cfg.buffering) { std::shared_ptr pkt(new MediaPacket(transmit_chunk_size)); const int res = src->Read(transmit_chunk_size, *pkt, out_stats); if (res == SRT_ERROR && src->uri.type() == UriParser::SRT) { if (srt_getlasterror(NULL) == SRT_EASYNCRCV) break; throw std::runtime_error( string("error: recvmsg: ") + string(srt_getlasterror_str()) ); } if (res == 0 || pkt->payload.empty()) { break; } dataqueue.push_back(pkt); receivedBytes += pkt->payload.size(); } } // if there is no target, let the received data be lost while (!dataqueue.empty()) { std::shared_ptr pkt = dataqueue.front(); if (!tar.get() || !tar->IsOpen()) { lostBytes += pkt->payload.size(); } else if (!tar->Write(pkt->payload.data(), pkt->payload.size(), cfg.srctime ? pkt->time : 0, out_stats)) { lostBytes += pkt->payload.size(); } else { wroteBytes += pkt->payload.size(); } dataqueue.pop_front(); } if (!cfg.quiet && (lastReportedtLostBytes != lostBytes)) { std::time_t now(std::time(nullptr)); if (std::difftime(now, writeErrorLogTimer) >= 5.0) { cerr << lostBytes << " bytes lost, " << wroteBytes << " bytes sent, " << receivedBytes << " bytes received" << endl; writeErrorLogTimer = now; lastReportedtLostBytes = lostBytes; } } } } } catch (std::exception& x) { cerr << "ERROR: " << x.what() << endl; return 255; } return 0; } // Class utilities void TestLogHandler(void* opaque, int level, const char* file, int line, const char* area, const char* message) { char prefix[100] = ""; if ( opaque ) { #ifdef _MSC_VER strncpy_s(prefix, sizeof(prefix), (char*)opaque, _TRUNCATE); #else strncpy(prefix, (char*)opaque, sizeof(prefix) - 1); prefix[sizeof(prefix) - 1] = '\0'; #endif } time_t now; time(&now); char buf[1024]; struct tm local = SysLocalTime(now); size_t pos = strftime(buf, 1024, "[%c ", &local); #ifdef _MSC_VER // That's something weird that happens on Microsoft Visual Studio 2013 // Trying to keep portability, while every version of MSVS is a different plaform. // On MSVS 2015 there's already a standard-compliant snprintf, whereas _snprintf // is available on backward compatibility and it doesn't work exactly the same way. #define snprintf _snprintf #endif snprintf(buf+pos, 1024-pos, "%s:%d(%s)]{%d} %s", file, line, area, level, message); cerr << buf << endl; } srt-1.5.4/apps/srt-tunnel.cpp000066400000000000000000000735001471311275400161250ustar00rootroot00000000000000// MSVS likes to complain about lots of standard C functions being unsafe. #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS 1 #include #endif #include "platform_sys.h" #define REQUIRE_CXX11 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "srt_compat.h" #include "apputil.hpp" // CreateAddr #include "uriparser.hpp" // UriParser #include "socketoptions.hpp" #include "logsupport.hpp" #include "transmitbase.hpp" // bytevector typedef to avoid collisions #include "verbose.hpp" // NOTE: This is without "haisrt/" because it uses an internal path // to the library. Application using the "installed" library should // use #include #include // This TEMPORARILY contains extra C++-only SRT API. #include #include #include /* # MAF contents for this file. Note that not every file from the support # library is used, but to simplify the build definition it links against # the whole srtsupport library. SOURCES srt-test-tunnel.cpp testmedia.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp ../apps/logsupport.cpp */ using namespace std; using namespace srt; const srt_logging::LogFA SRT_LOGFA_APP = 10; namespace srt_logging { Logger applog(SRT_LOGFA_APP, srt_logger_config, "TUNNELAPP"); } using srt_logging::applog; class Medium { static int s_counter; int m_counter; public: enum ReadStatus { RD_DATA, RD_AGAIN, RD_EOF, RD_ERROR }; enum Mode { LISTENER, CALLER }; protected: UriParser m_uri; size_t m_chunk = 0; map m_options; Mode m_mode; bool m_listener = false; bool m_open = false; bool m_eof = false; bool m_broken = false; std::mutex access; // For closing template static Medium* CreateAcceptor(DerivedMedium* self, const sockaddr_any& sa, SocketType sock, size_t chunk) { string addr = sockaddr_any(sa.get(), sizeof sa).str(); DerivedMedium* m = new DerivedMedium(UriParser(self->type() + string("://") + addr), chunk); m->m_socket = sock; return m; } public: string uri() { return m_uri.uri(); } string id() { std::ostringstream os; os << type() << m_counter; return os.str(); } Medium(const UriParser& u, size_t ch): m_counter(s_counter++), m_uri(u), m_chunk(ch) {} Medium(): m_counter(s_counter++) {} virtual const char* type() = 0; virtual bool IsOpen() = 0; virtual void CloseInternal() = 0; void CloseState() { m_open = false; m_broken = true; } // External API for this class that allows to close // the entity on request. The CloseInternal should // redirect to a type-specific function, the same that // should be also called in destructor. void Close() { CloseState(); CloseInternal(); } virtual bool End() = 0; virtual int ReadInternal(char* output, int size) = 0; virtual bool IsErrorAgain() = 0; ReadStatus Read(bytevector& output); virtual void Write(bytevector& portion) = 0; virtual void CreateListener() = 0; virtual void CreateCaller() = 0; virtual unique_ptr Accept() = 0; virtual void Connect() = 0; static std::unique_ptr Create(const std::string& url, size_t chunk, Mode); virtual bool Broken() = 0; virtual size_t Still() { return 0; } class ReadEOF: public std::runtime_error { public: ReadEOF(const std::string& fn): std::runtime_error( "EOF while reading file: " + fn ) { } }; class TransmissionError: public std::runtime_error { public: TransmissionError(const std::string& fn): std::runtime_error( fn ) { } }; static void Error(const string& text) { throw TransmissionError("ERROR (internal): " + text); } virtual ~Medium() { CloseState(); } protected: void InitMode(Mode m) { m_mode = m; Init(); if (m_mode == LISTENER) { CreateListener(); m_listener = true; } else { CreateCaller(); } m_open = true; } virtual void Init() {} }; class Engine { Medium* media[2]; std::thread thr; class Tunnel* parent_tunnel; std::string nameid; int status = 0; Medium::ReadStatus rdst = Medium::RD_ERROR; UDT::ERRORINFO srtx; public: enum Dir { DIR_IN, DIR_OUT }; int stat() { return status; } Engine(Tunnel* p, Medium* m1, Medium* m2, const std::string& nid) : #ifdef HAVE_FULL_CXX11 media {m1, m2}, #endif parent_tunnel(p), nameid(nid) { #ifndef HAVE_FULL_CXX11 // MSVC is not exactly C++11 compliant and complains around // initialization of an array. // Leaving this method of initialization for clarity and // possibly more preferred performance. media[0] = m1; media[1] = m2; #endif } void Start() { Verb() << "START: " << media[DIR_IN]->uri() << " --> " << media[DIR_OUT]->uri(); const std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id(); srt::ThreadName tn(thrn); thr = thread([this]() { Worker(); }); } void Stop() { // If this thread is already stopped, don't stop. if (thr.joinable()) { LOGP(applog.Debug, "Engine::Stop: Closing media:"); // Close both media as a hanged up reading thread // will block joining. media[0]->Close(); media[1]->Close(); LOGP(applog.Debug, "Engine::Stop: media closed, joining engine thread:"); if (thr.get_id() == std::this_thread::get_id()) { // If this is this thread which called this, no need // to stop because this thread will exit by itself afterwards. // You must, however, detach yourself, or otherwise the thr's // destructor would kill the program. thr.detach(); LOGP(applog.Debug, "DETACHED."); } else { thr.join(); LOGP(applog.Debug, "Joined."); } } } void Worker(); }; struct Tunnelbox; class Tunnel { Tunnelbox* parent_box; std::unique_ptr med_acp, med_clr; Engine acp_to_clr, clr_to_acp; srt::sync::atomic running{true}; std::mutex access; public: string show() { return med_acp->uri() + " <-> " + med_clr->uri(); } Tunnel(Tunnelbox* m, std::unique_ptr&& acp, std::unique_ptr&& clr): parent_box(m), med_acp(std::move(acp)), med_clr(std::move(clr)), acp_to_clr(this, med_acp.get(), med_clr.get(), med_acp->id() + ">" + med_clr->id()), clr_to_acp(this, med_clr.get(), med_acp.get(), med_clr->id() + ">" + med_acp->id()) { } void Start() { acp_to_clr.Start(); clr_to_acp.Start(); } // This is to be called by an Engine from Engine::Worker // thread. // [[affinity = acp_to_clr.thr || clr_to_acp.thr]]; void decommission_engine(Medium* which_medium) { // which_medium is the medium that failed. // Upon breaking of one medium from the pair, // the other needs to be closed as well. Verb() << "Medium broken: " << which_medium->uri(); bool stop = true; /* { lock_guard lk(access); if (acp_to_clr.stat() == -1 && clr_to_acp.stat() == -1) { Verb() << "Tunnel: Both engine decommissioned, will stop the tunnel."; // Both engines are down, decommission the tunnel. // Note that the status -1 means that particular engine // is not currently running and you can safely // join its thread. stop = true; } else { Verb() << "Tunnel: Decommissioned one engine, waiting for the other one to report"; } } */ if (stop) { // First, stop all media. med_acp->Close(); med_clr->Close(); // Then stop the tunnel (this is only a signal // to a cleanup thread to delete it). Stop(); } } void Stop(); bool decommission_if_dead(bool forced); // [[affinity = g_tunnels.thr]] }; void Engine::Worker() { bytevector outbuf; Medium* which_medium = media[DIR_IN]; for (;;) { try { which_medium = media[DIR_IN]; rdst = media[DIR_IN]->Read((outbuf)); switch (rdst) { case Medium::RD_DATA: { which_medium = media[DIR_OUT]; // We get the data, write them to the output media[DIR_OUT]->Write((outbuf)); } break; case Medium::RD_EOF: status = -1; throw Medium::ReadEOF(""); case Medium::RD_AGAIN: // Theoreticall RD_AGAIN should not be reported // because it should be taken care of internally by // repeated sending - unless we get m_broken set. // If it is, however, it should be handled just like error. case Medium::RD_ERROR: status = -1; Medium::Error("Error while reading"); } } catch (Medium::ReadEOF&) { Verb() << "EOF. Exiting engine."; break; } catch (Medium::TransmissionError& er) { Verb() << er.what() << " - interrupting engine: " << nameid; break; } } // This is an engine thread and it should simply // tell the parent_box Tunnel that it is no longer // operative. It's not necessary to inform it which // of two engines is decommissioned - it should only // know that one of them got down. It will then check // if both are down here and decommission the whole // tunnel if so. parent_tunnel->decommission_engine(which_medium); } class SrtMedium: public Medium { SRTSOCKET m_socket = SRT_ERROR; friend class Medium; public: #ifdef HAVE_FULL_CXX11 using Medium::Medium; #else // MSVC and gcc 4.7 not exactly support C++11 SrtMedium(UriParser u, size_t ch): Medium(u, ch) {} #endif bool IsOpen() override { return m_open; } bool End() override { return m_eof; } bool Broken() override { return m_broken; } void CloseSrt() { Verb() << "Closing SRT socket for " << uri(); lock_guard lk(access); if (m_socket == SRT_ERROR) return; srt_close(m_socket); m_socket = SRT_ERROR; } // Forwarded in order to separate the implementation from // the virtual function so that virtual function is not // being called in destructor. void CloseInternal() override { return CloseSrt(); } const char* type() override { return "srt"; } int ReadInternal(char* output, int size) override; bool IsErrorAgain() override; void Write(bytevector& portion) override; void CreateListener() override; void CreateCaller() override; unique_ptr Accept() override; void Connect() override; protected: void Init() override; void ConfigurePre(); void ConfigurePost(SRTSOCKET socket); using Medium::Error; static void Error(UDT::ERRORINFO& ri, const string& text) { throw TransmissionError("ERROR: " + text + ": " + ri.getErrorMessage()); } ~SrtMedium() override { CloseState(); CloseSrt(); } }; class TcpMedium: public Medium { int m_socket = -1; friend class Medium; public: #ifdef HAVE_FULL_CXX11 using Medium::Medium; #else // MSVC not exactly supports C++11 TcpMedium(UriParser u, size_t ch): Medium(u, ch) {} #endif #ifdef _WIN32 static int tcp_close(int socket) { return ::closesocket(socket); } enum { DEF_SEND_FLAG = 0 }; #elif defined(LINUX) || defined(GNU) || defined(CYGWIN) static int tcp_close(int socket) { return ::close(socket); } enum { DEF_SEND_FLAG = MSG_NOSIGNAL }; #else static int tcp_close(int socket) { return ::close(socket); } enum { DEF_SEND_FLAG = 0 }; #endif bool IsOpen() override { return m_open; } bool End() override { return m_eof; } bool Broken() override { return m_broken; } void CloseTcp() { Verb() << "Closing TCP socket for " << uri(); lock_guard lk(access); if (m_socket == -1) return; tcp_close(m_socket); m_socket = -1; } void CloseInternal() override { return CloseTcp(); } const char* type() override { return "tcp"; } int ReadInternal(char* output, int size) override; bool IsErrorAgain() override; void Write(bytevector& portion) override; void CreateListener() override; void CreateCaller() override; unique_ptr Accept() override; void Connect() override; protected: void ConfigurePre() { #if defined(__APPLE__) int optval = 1; setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); #endif } void ConfigurePost(int) { } using Medium::Error; static void Error(int verrno, const string& text) { char rbuf[1024]; throw TransmissionError("ERROR: " + text + ": " + SysStrError(verrno, rbuf, 1024)); } virtual ~TcpMedium() { CloseState(); CloseTcp(); } }; void SrtMedium::Init() { // This function is required due to extra option // check need if (m_options.count("mode")) Error("No option 'mode' is required, it defaults to position of the argument"); if (m_options.count("blocking")) Error("Blocking is not configurable here."); // XXX // Look also for other options that should not be here. // Enforce the transtype = file m_options["transtype"] = "file"; } void SrtMedium::ConfigurePre() { vector fails; m_options["mode"] = "caller"; SrtConfigurePre(m_socket, "", m_options, &fails); if (!fails.empty()) { cerr << "Failed options: " << Printable(fails) << endl; } } void SrtMedium::ConfigurePost(SRTSOCKET so) { vector fails; SrtConfigurePost(so, m_options, &fails); if (!fails.empty()) { cerr << "Failed options: " << Printable(fails) << endl; } } void SrtMedium::CreateListener() { int backlog = 5; // hardcoded! m_socket = srt_create_socket(); ConfigurePre(); sockaddr_any sa = CreateAddr(m_uri.host(), m_uri.portno()); int stat = srt_bind(m_socket, sa.get(), sizeof sa); if ( stat == SRT_ERROR ) { srt_close(m_socket); Error(UDT::getlasterror(), "srt_bind"); } stat = srt_listen(m_socket, backlog); if ( stat == SRT_ERROR ) { srt_close(m_socket); Error(UDT::getlasterror(), "srt_listen"); } m_listener = true; }; void TcpMedium::CreateListener() { int backlog = 5; // hardcoded! sockaddr_any sa = CreateAddr(m_uri.host(), m_uri.portno()); m_socket = (int)socket(sa.get()->sa_family, SOCK_STREAM, IPPROTO_TCP); ConfigurePre(); int stat = ::bind(m_socket, sa.get(), sa.size()); if (stat == -1) { tcp_close(m_socket); Error(errno, "bind"); } stat = listen(m_socket, backlog); if ( stat == -1 ) { tcp_close(m_socket); Error(errno, "listen"); } m_listener = true; } unique_ptr SrtMedium::Accept() { sockaddr_any sa; SRTSOCKET s = srt_accept(m_socket, (sa.get()), (&sa.len)); if (s == SRT_ERROR) { Error(UDT::getlasterror(), "srt_accept"); } ConfigurePost(s); // Configure 1s timeout int timeout_1s = 1000; srt_setsockflag(m_socket, SRTO_RCVTIMEO, &timeout_1s, sizeof timeout_1s); unique_ptr med(CreateAcceptor(this, sa, s, m_chunk)); Verb() << "accepted a connection from " << med->uri(); return med; } unique_ptr TcpMedium::Accept() { sockaddr_any sa; int s = (int)::accept(m_socket, (sa.get()), (&sa.syslen())); if (s == -1) { Error(errno, "accept"); } // Configure 1s timeout timeval timeout_1s { 1, 0 }; int st SRT_ATR_UNUSED = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout_1s, sizeof timeout_1s); timeval re; socklen_t size = sizeof re; int st2 SRT_ATR_UNUSED = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&re, &size); LOGP(applog.Debug, "Setting SO_RCVTIMEO to @", m_socket, ": ", st == -1 ? "FAILED" : "SUCCEEDED", ", read-back value: ", st2 == -1 ? int64_t(-1) : (int64_t(re.tv_sec)*1000000 + re.tv_usec)/1000, "ms"); unique_ptr med(CreateAcceptor(this, sa, s, m_chunk)); Verb() << "accepted a connection from " << med->uri(); return med; } void SrtMedium::CreateCaller() { m_socket = srt_create_socket(); ConfigurePre(); // XXX setting up outgoing port not supported } void TcpMedium::CreateCaller() { m_socket = (int)::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ConfigurePre(); } void SrtMedium::Connect() { sockaddr_any sa = CreateAddr(m_uri.host(), m_uri.portno()); int st = srt_connect(m_socket, sa.get(), sizeof sa); if (st == SRT_ERROR) Error(UDT::getlasterror(), "srt_connect"); ConfigurePost(m_socket); // Configure 1s timeout int timeout_1s = 1000; srt_setsockflag(m_socket, SRTO_RCVTIMEO, &timeout_1s, sizeof timeout_1s); } void TcpMedium::Connect() { sockaddr_any sa = CreateAddr(m_uri.host(), m_uri.portno()); int st = ::connect(m_socket, sa.get(), sa.size()); if (st == -1) Error(errno, "connect"); ConfigurePost(m_socket); // Configure 1s timeout timeval timeout_1s { 1, 0 }; setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout_1s, sizeof timeout_1s); } int SrtMedium::ReadInternal(char* w_buffer, int size) { int st = -1; do { st = srt_recv(m_socket, (w_buffer), size); if (st == SRT_ERROR) { int syserr; if (srt_getlasterror(&syserr) == SRT_EASYNCRCV && !m_broken) continue; } break; } while (true); return st; } int TcpMedium::ReadInternal(char* w_buffer, int size) { int st = -1; LOGP(applog.Debug, "TcpMedium:recv @", m_socket, " - begin"); do { st = ::recv(m_socket, (w_buffer), size, 0); if (st == -1) { if ((errno == EAGAIN || errno == EWOULDBLOCK)) { if (!m_broken) { LOGP(applog.Debug, "TcpMedium: read:AGAIN, repeating"); continue; } LOGP(applog.Debug, "TcpMedium: read:AGAIN, not repeating - already broken"); } else { LOGP(applog.Debug, "TcpMedium: read:ERROR: ", errno); } } break; } while (true); LOGP(applog.Debug, "TcpMedium:recv @", m_socket, " - result: ", st); return st; } bool SrtMedium::IsErrorAgain() { return srt_getlasterror(NULL) == SRT_EASYNCRCV; } bool TcpMedium::IsErrorAgain() { return errno == EAGAIN; } // The idea of Read function is to get the buffer that // possibly contains some data not written to the output yet, // but the time has come to read. We can't let the buffer expand // more than the size of the chunk, so if the buffer size already // exceeds it, don't return any data, but behave as if they were read. // This will cause the worker loop to redirect to Write immediately // thereafter and possibly will flush out the remains of the buffer. // It's still possible that the buffer won't be completely purged Medium::ReadStatus Medium::Read(bytevector& w_output) { // Don't read, but fake that you read if (w_output.size() > m_chunk) { Verb() << "BUFFER EXCEEDED"; return RD_DATA; } // Resize to maximum first size_t shift = w_output.size(); if (shift && m_eof) { // You have nonempty buffer, but eof was already // encountered. Report as if something was read. // // Don't read anything because this will surely // result in error since now. return RD_DATA; } size_t pred_size = shift + m_chunk; w_output.resize(pred_size); int st = ReadInternal((w_output.data() + shift), (int)m_chunk); if (st == -1) { if (IsErrorAgain()) return RD_AGAIN; return RD_ERROR; } if (st == 0) { m_eof = true; if (shift) { // If there's 0 (eof), but you still have data // in the buffer, fake that they were read. Only // when the buffer was empty at entrance should this // result with EOF. // // Set back the size this buffer had before we attempted // to read into it. w_output.resize(shift); return RD_DATA; } w_output.clear(); return RD_EOF; } w_output.resize(shift+st); return RD_DATA; } void SrtMedium::Write(bytevector& w_buffer) { int st = srt_send(m_socket, w_buffer.data(), (int)w_buffer.size()); if (st == SRT_ERROR) { Error(UDT::getlasterror(), "srt_send"); } // This should be ==, whereas > is not possible, but // this should simply embrace this case as a sanity check. if (st >= int(w_buffer.size())) w_buffer.clear(); else if (st == 0) { Error("Unexpected EOF on Write"); } else { // Remove only those bytes that were sent w_buffer.erase(w_buffer.begin(), w_buffer.begin()+st); } } void TcpMedium::Write(bytevector& w_buffer) { int st = ::send(m_socket, w_buffer.data(), (int)w_buffer.size(), DEF_SEND_FLAG); if (st == -1) { Error(errno, "send"); } // This should be ==, whereas > is not possible, but // this should simply embrace this case as a sanity check. if (st >= int(w_buffer.size())) w_buffer.clear(); else if (st == 0) { Error("Unexpected EOF on Write"); } else { // Remove only those bytes that were sent w_buffer.erase(w_buffer.begin(), w_buffer.begin()+st); } } std::unique_ptr Medium::Create(const std::string& url, size_t chunk, Medium::Mode mode) { UriParser uri(url); std::unique_ptr out; // Might be something smarter, but there are only 2 types. if (uri.scheme() == "srt") { out.reset(new SrtMedium(uri, chunk)); } else if (uri.scheme() == "tcp") { out.reset(new TcpMedium(uri, chunk)); } else { Error("Medium not supported"); } out->InitMode(mode); return out; } struct Tunnelbox { list> tunnels; std::mutex access; condition_variable decom_ready; bool main_running = true; thread thr; void signal_decommission() { lock_guard lk(access); decom_ready.notify_one(); } void install(std::unique_ptr&& acp, std::unique_ptr&& clr) { lock_guard lk(access); Verb() << "Tunnelbox: Starting tunnel: " << acp->uri() << " <-> " << clr->uri(); tunnels.emplace_back(new Tunnel(this, std::move(acp), std::move(clr))); // Note: after this instruction, acp and clr are no longer valid! auto& it = tunnels.back(); it->Start(); } void start_cleaner() { thr = thread( [this]() { CleanupWorker(); } ); } void stop_cleaner() { if (thr.joinable()) thr.join(); } private: void CleanupWorker() { unique_lock lk(access); while (main_running) { decom_ready.wait(lk); // Got a signal, find a tunnel ready to cleanup. // We just get the signal, but we don't know which // tunnel has generated it. for (auto i = tunnels.begin(), i_next = i; i != tunnels.end(); i = i_next) { ++i_next; // Bound in one call the check if the tunnel is dead // and decommissioning because this must be done in // the one critical section - make sure no other thread // is accessing it at the same time and also make join all // threads that might have been accessing it. After // exiting as true (meaning that it was decommissioned // as expected) it can be safely deleted. if ((*i)->decommission_if_dead(main_running)) { tunnels.erase(i); } } } } }; void Tunnel::Stop() { // Check for running must be done without locking // because if the tunnel isn't running if (!running) return; // already stopped lock_guard lk(access); // Ok, you are the first to make the tunnel // not running and inform the tunnelbox. running = false; parent_box->signal_decommission(); } bool Tunnel::decommission_if_dead(bool forced) { lock_guard lk(access); if (running && !forced) return false; // working, not to be decommissioned // Join the engine threads, make sure nothing // is running that could use the data. acp_to_clr.Stop(); clr_to_acp.Stop(); // Done. The tunnelbox after calling this can // safely delete the decommissioned tunnel. return true; } int Medium::s_counter = 1; Tunnelbox g_tunnels; std::unique_ptr main_listener; size_t default_chunk = 4096; int OnINT_StopService(int) { g_tunnels.main_running = false; g_tunnels.signal_decommission(); // Will cause the Accept() block to exit. main_listener->Close(); return 0; } int main( int argc, char** argv ) { if (!SysInitializeNetwork()) { cerr << "Fail to initialize network module."; return 1; } size_t chunk = default_chunk; OptionName o_loglevel = { "ll", "loglevel" }, o_logfa = { "lf", "logfa" }, o_chunk = {"c", "chunk" }, o_verbose = {"v", "verbose" }, o_noflush = {"s", "skipflush" }; // Options that expect no arguments (ARG_NONE) need not be mentioned. vector optargs = { { o_loglevel, OptionScheme::ARG_ONE }, { o_logfa, OptionScheme::ARG_ONE }, { o_chunk, OptionScheme::ARG_ONE } }; options_t params = ProcessOptions(argv, argc, optargs); /* cerr << "OPTIONS (DEBUG)\n"; for (auto o: params) { cerr << "[" << o.first << "] "; copy(o.second.begin(), o.second.end(), ostream_iterator(cerr, " ")); cerr << endl; } */ vector args = params[""]; if ( args.size() < 2 ) { cerr << "Usage: " << argv[0] << " \n"; return 1; } string loglevel = Option(params, "error", o_loglevel); string logfa = Option(params, "", o_logfa); srt_logging::LogLevel::type lev = SrtParseLogLevel(loglevel); srt::setloglevel(lev); if (logfa == "") { srt::addlogfa(SRT_LOGFA_APP); } else { // Add only selected FAs set unknown_fas; set fas = SrtParseLogFA(logfa, &unknown_fas); srt::resetlogfa(fas); // The general parser doesn't recognize the "app" FA, we check it here. if (unknown_fas.count("app")) srt::addlogfa(SRT_LOGFA_APP); } string verbo = Option(params, "no", o_verbose); if ( verbo == "" || !false_names.count(verbo) ) { Verbose::on = true; Verbose::cverb = &std::cout; } string chunks = Option(params, "", o_chunk); if ( chunks!= "" ) { chunk = stoi(chunks); } string listen_node = args[0]; string call_node = args[1]; UriParser ul(listen_node), uc(call_node); // It is allowed to use both media of the same type, // but only srt and tcp are allowed. set allowed = {"srt", "tcp"}; if (!allowed.count(ul.scheme())|| !allowed.count(uc.scheme())) { cerr << "ERROR: only tcp and srt schemes supported"; return -1; } Verb() << "LISTEN type=" << ul.scheme() << ", CALL type=" << uc.scheme(); g_tunnels.start_cleaner(); main_listener = Medium::Create(listen_node, chunk, Medium::LISTENER); // The main program loop is only to catch // new connections and manage them. Also takes care // of the broken connections. for (;;) { try { Verb() << "Waiting for connection..."; std::unique_ptr accepted = main_listener->Accept(); if (!g_tunnels.main_running) { Verb() << "Service stopped. Exiting."; break; } Verb() << "Connection accepted. Connecting to the relay..."; // Now call the target address. std::unique_ptr caller = Medium::Create(call_node, chunk, Medium::CALLER); caller->Connect(); Verb() << "Connected. Establishing pipe."; // No exception, we are free to pass :) g_tunnels.install(std::move(accepted), std::move(caller)); } catch (...) { Verb() << "Connection reported, but failed"; } } g_tunnels.stop_cleaner(); return 0; } srt-1.5.4/apps/statswriter.cpp000066400000000000000000000257201471311275400164060ustar00rootroot00000000000000/* * 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/. * */ #include #include #include #include #include #include #include #include "statswriter.hpp" #include "netinet_any.h" #include "srt_compat.h" using namespace std; template inline SrtStatData* make_stat(SrtStatCat cat, const string& name, const string& longname, TYPE CBytePerfMon::*field) { return new SrtStatDataType(cat, name, longname, field); } #define STATX(catsuf, sname, lname, field) s.emplace_back(make_stat(SSC_##catsuf, #sname, #lname, &CBytePerfMon:: field)) #define STAT(catsuf, sname, field) STATX(catsuf, sname, field, field) vector> g_SrtStatsTable; struct SrtStatsTableInit { SrtStatsTableInit(vector>& s) { STATX(GEN, time, Time, msTimeStamp); STAT(WINDOW, flow, pktFlowWindow); STAT(WINDOW, congestion, pktCongestionWindow); STAT(WINDOW, flight, pktFlightSize); STAT(LINK, rtt, msRTT); STAT(LINK, bandwidth, mbpsBandwidth); STAT(LINK, maxBandwidth, mbpsMaxBW); STAT(SEND, packets, pktSent); STAT(SEND, packetsUnique, pktSentUnique); STAT(SEND, packetsLost, pktSndLoss); STAT(SEND, packetsDropped, pktSndDrop); STAT(SEND, packetsRetransmitted, pktRetrans); STAT(SEND, packetsFilterExtra, pktSndFilterExtra); STAT(SEND, bytes, byteSent); STAT(SEND, bytesUnique, byteSentUnique); STAT(SEND, bytesDropped, byteSndDrop); STAT(SEND, byteAvailBuf, byteAvailSndBuf); STAT(SEND, msBuf, msSndBuf); STAT(SEND, mbitRate, mbpsSendRate); STAT(SEND, sendPeriod, usPktSndPeriod); STAT(RECV, packets, pktRecv); STAT(RECV, packetsUnique, pktRecvUnique); STAT(RECV, packetsLost, pktRcvLoss); STAT(RECV, packetsDropped, pktRcvDrop); STAT(RECV, packetsRetransmitted, pktRcvRetrans); STAT(RECV, packetsBelated, pktRcvBelated); STAT(RECV, packetsFilterExtra, pktRcvFilterExtra); STAT(RECV, packetsFilterSupply, pktRcvFilterSupply); STAT(RECV, packetsFilterLoss, pktRcvFilterLoss); STAT(RECV, bytes, byteRecv); STAT(RECV, bytesUnique, byteRecvUnique); STAT(RECV, bytesLost, byteRcvLoss); STAT(RECV, bytesDropped, byteRcvDrop); STAT(RECV, byteAvailBuf, byteAvailRcvBuf); STAT(RECV, msBuf, msRcvBuf); STAT(RECV, mbitRate, mbpsRecvRate); STAT(RECV, msTsbPdDelay, msRcvTsbPdDelay); } } g_SrtStatsTableInit (g_SrtStatsTable); #undef STAT #undef STATX string srt_json_cat_names [] = { "", "window", "link", "send", "recv" }; #ifdef HAVE_CXX_STD_PUT_TIME // Follows ISO 8601 std::string SrtStatsWriter::print_timestamp() { using namespace std; using namespace std::chrono; const auto systime_now = system_clock::now(); const time_t time_now = system_clock::to_time_t(systime_now); std::ostringstream output; // SysLocalTime returns zeroed tm_now on failure, which is ok for put_time. const tm tm_now = SysLocalTime(time_now); output << std::put_time(&tm_now, "%FT%T.") << std::setfill('0') << std::setw(6); const auto since_epoch = systime_now.time_since_epoch(); const seconds s = duration_cast(since_epoch); output << duration_cast(since_epoch - s).count(); output << std::put_time(&tm_now, "%z"); return output.str(); } #else // This is a stub. The error when not defining it would be too // misleading, so this stub will work if someone mistakenly adds // the item to the output format without checking that HAVE_CXX_STD_PUT_TIME string SrtStatsWriter::print_timestamp() { return ""; } #endif // HAVE_CXX_STD_PUT_TIME class SrtStatsJson : public SrtStatsWriter { static string quotekey(const string& name) { if (name == "") return ""; return R"(")" + name + R"(":)"; } static string quote(const string& name) { if (name == "") return ""; return R"(")" + name + R"(")"; } public: string WriteStats(int sid, const CBytePerfMon& mon) override { std::ostringstream output; string pretty_cr, pretty_tab; if (Option("pretty")) { pretty_cr = "\n"; pretty_tab = "\t"; } SrtStatCat cat = SSC_GEN; // Do general manually output << quotekey(srt_json_cat_names[cat]) << "{" << pretty_cr; // SID is displayed manually output << pretty_tab << quotekey("sid") << sid; // Extra Timepoint is also displayed manually #ifdef HAVE_CXX_STD_PUT_TIME // NOTE: still assumed SSC_GEN category output << "," << pretty_cr << pretty_tab << quotekey("timepoint") << quote(print_timestamp()); #endif // Now continue with fields as specified in the table for (auto& i: g_SrtStatsTable) { if (i->category == cat) { output << ","; // next item in same cat output << pretty_cr; output << pretty_tab; if (cat != SSC_GEN) output << pretty_tab; } else { if (cat != SSC_GEN) { // DO NOT close if general category, just // enter the depth. output << pretty_cr << pretty_tab << "}"; } cat = i->category; output << ","; output << pretty_cr; if (cat != SSC_GEN) output << pretty_tab; output << quotekey(srt_json_cat_names[cat]) << "{" << pretty_cr << pretty_tab; if (cat != SSC_GEN) output << pretty_tab; } // Print the current field output << quotekey(i->name); i->PrintValue(output, mon); } // Close the previous subcategory if (cat != SSC_GEN) { output << pretty_cr << pretty_tab << "}" << pretty_cr; } // Close the general category entity output << "}" << pretty_cr << endl; return output.str(); } string WriteBandwidth(double mbpsBandwidth) override { std::ostringstream output; output << "{\"bandwidth\":" << mbpsBandwidth << '}' << endl; return output.str(); } }; class SrtStatsCsv : public SrtStatsWriter { private: bool first_line_printed; public: SrtStatsCsv() : first_line_printed(false) {} string WriteStats(int sid, const CBytePerfMon& mon) override { std::ostringstream output; // Header if (!first_line_printed) { #ifdef HAVE_CXX_STD_PUT_TIME output << "Timepoint,"; #endif output << "Time,SocketID"; for (auto& i: g_SrtStatsTable) { output << "," << i->longname; } output << endl; first_line_printed = true; } // Values #ifdef HAVE_CXX_STD_PUT_TIME // HDR: Timepoint output << print_timestamp() << ","; #endif // HAVE_CXX_STD_PUT_TIME // HDR: Time,SocketID output << mon.msTimeStamp << "," << sid; // HDR: the loop of all values in g_SrtStatsTable for (auto& i: g_SrtStatsTable) { output << ","; i->PrintValue(output, mon); } output << endl; return output.str(); } string WriteBandwidth(double mbpsBandwidth) override { std::ostringstream output; output << "+++/+++SRT BANDWIDTH: " << mbpsBandwidth << endl; return output.str(); } }; class SrtStatsCols : public SrtStatsWriter { public: string WriteStats(int sid, const CBytePerfMon& mon) override { std::ostringstream output; output << "======= SRT STATS: sid=" << sid << endl; output << "PACKETS SENT: " << setw(11) << mon.pktSent << " RECEIVED: " << setw(11) << mon.pktRecv << endl; output << "LOST PKT SENT: " << setw(11) << mon.pktSndLoss << " RECEIVED: " << setw(11) << mon.pktRcvLoss << endl; output << "REXMIT SENT: " << setw(11) << mon.pktRetrans << " RECEIVED: " << setw(11) << mon.pktRcvRetrans << endl; output << "DROP PKT SENT: " << setw(11) << mon.pktSndDrop << " RECEIVED: " << setw(11) << mon.pktRcvDrop << endl; output << "FILTER EXTRA TX: " << setw(11) << mon.pktSndFilterExtra << " RX: " << setw(11) << mon.pktRcvFilterExtra << endl; output << "FILTER RX SUPPL: " << setw(11) << mon.pktRcvFilterSupply << " RX LOSS: " << setw(11) << mon.pktRcvFilterLoss << endl; output << "RATE SENDING: " << setw(11) << mon.mbpsSendRate << " RECEIVING: " << setw(11) << mon.mbpsRecvRate << endl; output << "BELATED RECEIVED: " << setw(11) << mon.pktRcvBelated << " AVG TIME: " << setw(11) << mon.pktRcvAvgBelatedTime << endl; output << "REORDER DISTANCE: " << setw(11) << mon.pktReorderDistance << endl; output << "WINDOW FLOW: " << setw(11) << mon.pktFlowWindow << " CONGESTION: " << setw(11) << mon.pktCongestionWindow << " FLIGHT: " << setw(11) << mon.pktFlightSize << endl; output << "LINK RTT: " << setw(9) << mon.msRTT << "ms BANDWIDTH: " << setw(7) << mon.mbpsBandwidth << "Mb/s " << endl; output << "BUFFERLEFT: SND: " << setw(11) << mon.byteAvailSndBuf << " RCV: " << setw(11) << mon.byteAvailRcvBuf << endl; return output.str(); } string WriteBandwidth(double mbpsBandwidth) override { std::ostringstream output; output << "+++/+++SRT BANDWIDTH: " << mbpsBandwidth << endl; return output.str(); } }; shared_ptr SrtStatsWriterFactory(SrtStatsPrintFormat printformat) { switch (printformat) { case SRTSTATS_PROFMAT_JSON: return make_shared(); case SRTSTATS_PROFMAT_CSV: return make_shared(); case SRTSTATS_PROFMAT_2COLS: return make_shared(); default: break; } return nullptr; } SrtStatsPrintFormat ParsePrintFormat(string pf, string& w_extras) { size_t havecomma = pf.find(','); if (havecomma != string::npos) { w_extras = pf.substr(havecomma+1); pf = pf.substr(0, havecomma); } if (pf == "default") return SRTSTATS_PROFMAT_2COLS; if (pf == "json") return SRTSTATS_PROFMAT_JSON; if (pf == "csv") return SRTSTATS_PROFMAT_CSV; return SRTSTATS_PROFMAT_INVALID; } srt-1.5.4/apps/statswriter.hpp000066400000000000000000000046771471311275400164230ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_APPS_STATSWRITER_H #define INC_SRT_APPS_STATSWRITER_H #include #include #include #include #include "srt.h" #include "utilities.h" enum SrtStatsPrintFormat { SRTSTATS_PROFMAT_INVALID = -1, SRTSTATS_PROFMAT_2COLS = 0, SRTSTATS_PROFMAT_JSON, SRTSTATS_PROFMAT_CSV }; SrtStatsPrintFormat ParsePrintFormat(std::string pf, std::string& w_extras); enum SrtStatCat { SSC_GEN, //< General SSC_WINDOW, // flow/congestion window SSC_LINK, //< Link data SSC_SEND, //< Sending SSC_RECV //< Receiving }; struct SrtStatData { SrtStatCat category; std::string name; std::string longname; SrtStatData(SrtStatCat cat, std::string n, std::string l): category(cat), name(n), longname(l) {} virtual ~SrtStatData() {} virtual void PrintValue(std::ostream& str, const CBytePerfMon& mon) = 0; }; template struct SrtStatDataType: public SrtStatData { typedef TYPE CBytePerfMon::*pfield_t; pfield_t pfield; SrtStatDataType(SrtStatCat cat, const std::string& name, const std::string& longname, pfield_t field) : SrtStatData (cat, name, longname), pfield(field) { } void PrintValue(std::ostream& str, const CBytePerfMon& mon) override { str << mon.*pfield; } }; class SrtStatsWriter { public: virtual std::string WriteStats(int sid, const CBytePerfMon& mon) = 0; virtual std::string WriteBandwidth(double mbpsBandwidth) = 0; virtual ~SrtStatsWriter() {} // Only if HAS_PUT_TIME. Specified in the imp file. std::string print_timestamp(); void Option(const std::string& key, const std::string& val) { options[key] = val; } bool Option(const std::string& key, std::string* rval = nullptr) { const std::string* out = map_getp(options, key); if (!out) return false; if (rval) *rval = *out; return true; } protected: std::map options; }; extern std::vector> g_SrtStatsTable; std::shared_ptr SrtStatsWriterFactory(SrtStatsPrintFormat printformat); #endif srt-1.5.4/apps/support.maf000066400000000000000000000012451471311275400155040ustar00rootroot00000000000000# IMPORTANT! # # This file contains information about ALL files existing in this directory # and belonging to the shared file between official applications # so that the build definition file can take them all to link against the app. # Applications in the 'apps' directory will use them all. # Appliecaions in the 'testing' directory may use some of them and they will # take selectively whichever parts they need. SOURCES apputil.cpp statswriter.cpp logsupport.cpp logsupport_appdefs.cpp socketoptions.cpp transmitmedia.cpp uriparser.cpp verbose.cpp PRIVATE HEADERS apputil.hpp logsupport.hpp socketoptions.hpp transmitbase.hpp transmitmedia.hpp uriparser.hpp verbose.hpp srt-1.5.4/apps/transmitbase.hpp000066400000000000000000000051321471311275400165070ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_COMMON_TRANMITBASE_HPP #define INC_SRT_COMMON_TRANMITBASE_HPP #include #include #include #include #include #include "srt.h" #include "uriparser.hpp" #include "apputil.hpp" #include "statswriter.hpp" typedef std::vector bytevector; extern bool transmit_total_stats; extern bool g_stats_are_printed_to_stdout; extern unsigned long transmit_bw_report; extern unsigned long transmit_stats_report; extern unsigned long transmit_chunk_size; struct MediaPacket { bytevector payload; int64_t time = 0; MediaPacket(bytevector&& src) : payload(std::move(src)) {} MediaPacket(bytevector&& src, int64_t stime) : payload(std::move(src)), time(stime) {} MediaPacket(size_t payload_size) : payload(payload_size), time(0) {} MediaPacket(const bytevector& src) : payload(src) {} MediaPacket(const bytevector& src, int64_t stime) : payload(src), time(stime) {} MediaPacket() {} }; extern std::shared_ptr transmit_stats_writer; class Location { public: UriParser uri; Location() {} }; class Source: public Location { public: virtual int Read(size_t chunk, MediaPacket& pkt, std::ostream &out_stats = std::cout) = 0; virtual bool IsOpen() = 0; virtual bool End() = 0; static std::unique_ptr Create(const std::string& url); virtual void Close() {} virtual ~Source() {} class ReadEOF: public std::runtime_error { public: ReadEOF(const std::string& fn): std::runtime_error( "EOF while reading file: " + fn ) { } }; virtual SRTSOCKET GetSRTSocket() const { return SRT_INVALID_SOCK; } virtual int GetSysSocket() const { return -1; } virtual bool AcceptNewClient() { return false; } }; class Target: public Location { public: virtual int Write(const char* data, size_t size, int64_t src_time, std::ostream &out_stats = std::cout) = 0; virtual bool IsOpen() = 0; virtual bool Broken() = 0; virtual void Close() {} virtual size_t Still() { return 0; } static std::unique_ptr Create(const std::string& url); virtual ~Target() {} virtual SRTSOCKET GetSRTSocket() const { return SRT_INVALID_SOCK; } virtual int GetSysSocket() const { return -1; } virtual bool AcceptNewClient() { return false; } }; #endif srt-1.5.4/apps/transmitmedia.cpp000066400000000000000000001066601471311275400166570ustar00rootroot00000000000000/* * 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/. * */ // Just for formality. This file should be used #include #include #include #include #include #include #include #include #include #include #if !defined(_WIN32) #include #else #include #include #endif #if defined(SUNOS) #include #endif #include "netinet_any.h" #include "apputil.hpp" #include "socketoptions.hpp" #include "uriparser.hpp" #include "transmitmedia.hpp" #include "srt_compat.h" #include "verbose.hpp" using namespace std; using namespace srt; 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; class FileSource: public Source { ifstream ifile; string filename_copy; public: FileSource(const string& path): ifile(path, ios::in | ios::binary), filename_copy(path) { if ( !ifile ) throw std::runtime_error(path + ": Can't open file for reading"); } int Read(size_t chunk, MediaPacket& pkt, ostream & ignored SRT_ATR_UNUSED = cout) override { if (pkt.payload.size() < chunk) pkt.payload.resize(chunk); pkt.time = 0; ifile.read(pkt.payload.data(), chunk); size_t nread = ifile.gcount(); if (nread < pkt.payload.size()) pkt.payload.resize(nread); if (pkt.payload.empty()) { return 0; } return (int) nread; } bool IsOpen() override { return bool(ifile); } bool End() override { return ifile.eof(); } }; class FileTarget: public Target { ofstream ofile; public: FileTarget(const string& path): ofile(path, ios::out | ios::trunc | ios::binary) {} int Write(const char* data, size_t size, int64_t time SRT_ATR_UNUSED, ostream & ignored SRT_ATR_UNUSED = cout) override { ofile.write(data, size); return !(ofile.bad()) ? (int) size : 0; } bool IsOpen() override { return !!ofile; } bool Broken() override { return !ofile.good(); } //~FileTarget() { ofile.close(); } void Close() override { ofile.close(); } }; template struct File; template <> struct File { typedef FileSource type; }; template <> struct File { typedef FileTarget type; }; template Iface* CreateFile(const string& name) { return new typename File::type (name); } shared_ptr transmit_stats_writer; void SrtCommon::InitParameters(string host, map par) { // Application-specific options: mode, blocking, timeout, adapter if (Verbose::on && !par.empty()) { Verb() << "SRT parameters specified:\n"; for (map::iterator i = par.begin(); i != par.end(); ++i) { cerr << "\t" << i->first << " = '" << i->second << "'\n"; } } if (par.count("bind")) { string bindspec = par.at("bind"); UriParser u (bindspec, UriParser::EXPECT_HOST); if ( u.scheme() != "" || u.path() != "" || !u.parameters().empty() || u.portno() == 0) { Error("Invalid syntax in 'bind' option"); } if (u.host() != "") par["adapter"] = u.host(); par["port"] = u.port(); par.erase("bind"); } string adapter; if (par.count("adapter")) { adapter = par.at("adapter"); } m_mode = "default"; if (par.count("mode")) { m_mode = par.at("mode"); } SocketOption::Mode mode = SrtInterpretMode(m_mode, host, adapter); if (mode == SocketOption::FAILURE) { Error("Invalid mode"); } // Fix the mode name after successful interpretation m_mode = SocketOption::mode_names[mode]; par.erase("mode"); if (par.count("timeout")) { m_timeout = stoi(par.at("timeout"), 0, 0); par.erase("timeout"); } if (par.count("adapter")) { m_adapter = par.at("adapter"); par.erase("adapter"); } else if (m_mode == "listener") { // For listener mode, adapter is taken from host, // if 'adapter' parameter is not given m_adapter = host; } if (par.count("tsbpd") && false_names.count(par.at("tsbpd"))) { m_tsbpdmode = false; } if (par.count("port")) { m_outgoing_port = stoi(par.at("port"), 0, 0); par.erase("port"); } // 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") && 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"); par["payloadsize"] = Sprint(transmit_chunk_size); } // Assign the others here. m_options = par; } void SrtCommon::PrepareListener(string host, int port, int backlog) { m_bindsock = srt_create_socket(); if ( m_bindsock == SRT_ERROR ) Error("srt_create_socket"); int stat = ConfigurePre(m_bindsock); if ( stat == SRT_ERROR ) Error("ConfigurePre"); sockaddr_any sa = CreateAddr(host, port); sockaddr* psa = sa.get(); Verb() << "Binding a server on " << host << ":" << port << " ..."; stat = srt_bind(m_bindsock, psa, sizeof sa); if ( stat == SRT_ERROR ) { srt_close(m_bindsock); Error("srt_bind"); } Verb() << " listen..."; stat = srt_listen(m_bindsock, backlog); if ( stat == SRT_ERROR ) { srt_close(m_bindsock); Error("srt_listen"); } } void SrtCommon::StealFrom(SrtCommon& src) { // This is used when SrtCommon class designates a listener // object that is doing Accept in appropriate direction class. // The new object should get the accepted socket. m_output_direction = src.m_output_direction; m_timeout = src.m_timeout; m_tsbpdmode = src.m_tsbpdmode; m_options = src.m_options; m_bindsock = SRT_INVALID_SOCK; // no listener m_sock = src.m_sock; src.m_sock = SRT_INVALID_SOCK; // STEALING } bool SrtCommon::AcceptNewClient() { sockaddr_any scl; Verb() << " accept... "; m_sock = srt_accept(m_bindsock, scl.get(), &scl.len); if ( m_sock == SRT_INVALID_SOCK ) { srt_close(m_bindsock); m_bindsock = SRT_INVALID_SOCK; Error("srt_accept"); } // we do one client connection at a time, // so close the listener. srt_close(m_bindsock); m_bindsock = SRT_INVALID_SOCK; Verb() << " connected."; // ConfigurePre is done on bindsock, so any possible Pre flags // are DERIVED by sock. ConfigurePost is done exclusively on sock. int stat = ConfigurePost(m_sock); if ( stat == SRT_ERROR ) Error("ConfigurePost"); return true; } void SrtCommon::Init(string host, int port, map par, bool dir_output) { m_output_direction = dir_output; InitParameters(host, par); Verb() << "Opening SRT " << (dir_output ? "target" : "source") << " " << m_mode << " on " << host << ":" << port; if ( m_mode == "caller" ) OpenClient(host, port); else if ( m_mode == "listener" ) OpenServer(m_adapter, port); else if ( m_mode == "rendezvous" ) OpenRendezvous(m_adapter, host, port); else { throw std::invalid_argument("Invalid 'mode'. Use 'client' or 'server'"); } } int SrtCommon::ConfigurePost(SRTSOCKET sock) { bool no = false; int result = 0; if ( m_output_direction ) { result = srt_setsockopt(sock, 0, SRTO_SNDSYN, &no, sizeof no); if ( result == -1 ) return result; if ( m_timeout ) return srt_setsockopt(sock, 0, SRTO_SNDTIMEO, &m_timeout, sizeof m_timeout); } else { result = srt_setsockopt(sock, 0, SRTO_RCVSYN, &no, sizeof no); if ( result == -1 ) return result; if ( m_timeout ) return srt_setsockopt(sock, 0, SRTO_RCVTIMEO, &m_timeout, sizeof m_timeout); } SrtConfigurePost(sock, m_options); for (const auto &o: srt_options) { if ( o.binding == SocketOption::POST && m_options.count(o.name) ) { string value = m_options.at(o.name); bool ok = o.apply(sock, value); if ( !ok ) Verb() << "WARNING: failed to set '" << o.name << "' (post, " << (m_output_direction? "target":"source") << ") to " << value; else Verb() << "NOTE: SRT/post::" << o.name << "=" << value; } } return 0; } int SrtCommon::ConfigurePre(SRTSOCKET sock) { int result = 0; bool no = false; if ( !m_tsbpdmode ) { result = srt_setsockopt(sock, 0, SRTO_TSBPDMODE, &no, sizeof no); if ( result == -1 ) return result; } result = srt_setsockopt(sock, 0, SRTO_RCVSYN, &no, sizeof no); if ( result == -1 ) return result; // host is only checked for emptiness and depending on that the connection mode is selected. // Here we are not exactly interested with that information. vector failures; // NOTE: here host = "", so the 'connmode' will be returned as LISTENER always, // but it doesn't matter here. We don't use 'connmode' for anything else than // checking for failures. SocketOption::Mode conmode = SrtConfigurePre(sock, "", m_options, &failures); if ( conmode == SocketOption::FAILURE ) { if ( Verbose::on ) { cerr << "WARNING: failed to set options: "; copy(failures.begin(), failures.end(), ostream_iterator(cerr, ", ")); cerr << endl; } return SRT_ERROR; } return 0; } void SrtCommon::SetupAdapter(const string& host, int port) { sockaddr_any localsa = CreateAddr(host, port); sockaddr* psa = localsa.get(); int stat = srt_bind(m_sock, psa, sizeof localsa); if ( stat == SRT_ERROR ) Error("srt_bind"); } void SrtCommon::OpenClient(string host, int port) { PrepareClient(); if (m_outgoing_port || m_adapter != "") { SetupAdapter(m_adapter, m_outgoing_port); } ConnectClient(host, port); } void SrtCommon::PrepareClient() { m_sock = srt_create_socket(); if ( m_sock == SRT_ERROR ) Error("srt_create_socket"); int stat = ConfigurePre(m_sock); if ( stat == SRT_ERROR ) Error("ConfigurePre"); } void SrtCommon::ConnectClient(string host, int port) { sockaddr_any sa = CreateAddr(host, port); sockaddr* psa = sa.get(); Verb() << "Connecting to " << host << ":" << port; int stat = srt_connect(m_sock, psa, sizeof sa); if ( stat == SRT_ERROR ) { srt_close(m_sock); Error("srt_connect"); } stat = ConfigurePost(m_sock); if ( stat == SRT_ERROR ) Error("ConfigurePost"); } void SrtCommon::Error(string src) { int errnov = 0; int result = srt_getlasterror(&errnov); string message = srt_getlasterror_str(); Verb() << "\nERROR #" << result << "." << errnov << ": " << message; throw TransmissionError("error: " + src + ": " + message); } void SrtCommon::OpenRendezvous(string adapter, string host, int port) { m_sock = srt_create_socket(); if ( m_sock == SRT_ERROR ) Error("srt_create_socket"); bool yes = true; srt_setsockopt(m_sock, 0, SRTO_RENDEZVOUS, &yes, sizeof yes); int stat = ConfigurePre(m_sock); if ( stat == SRT_ERROR ) Error("ConfigurePre"); sockaddr_any sa = CreateAddr(host, port); if (sa.family() == AF_UNSPEC) { Error("OpenRendezvous: invalid target host specification: " + host); } const int outport = m_outgoing_port ? m_outgoing_port : port; sockaddr_any localsa = CreateAddr(adapter, outport, sa.family()); Verb() << "Binding a server on " << adapter << ":" << outport; stat = srt_bind(m_sock, localsa.get(), sizeof localsa); if ( stat == SRT_ERROR ) { srt_close(m_sock); Error("srt_bind"); } Verb() << "Connecting to " << host << ":" << port; stat = srt_connect(m_sock, sa.get(), sizeof sa); if ( stat == SRT_ERROR ) { srt_close(m_sock); Error("srt_connect"); } stat = ConfigurePost(m_sock); if ( stat == SRT_ERROR ) Error("ConfigurePost"); } void SrtCommon::Close() { Verb() << "SrtCommon: DESTROYING CONNECTION, closing sockets (rt%" << m_sock << " ls%" << m_bindsock << ")..."; if ( m_sock != SRT_INVALID_SOCK ) { srt_close(m_sock); m_sock = SRT_INVALID_SOCK; } if ( m_bindsock != SRT_INVALID_SOCK ) { srt_close(m_bindsock); m_bindsock = SRT_INVALID_SOCK ; } Verb() << "SrtCommon: ... done."; } SrtCommon::~SrtCommon() { Close(); } SrtSource::SrtSource(string host, int port, const map& par) { Init(host, port, par, false); ostringstream os; os << host << ":" << port; hostport_copy = os.str(); } int SrtSource::Read(size_t chunk, MediaPacket& pkt, ostream &out_stats) { static unsigned long counter = 1; if (pkt.payload.size() < chunk) pkt.payload.resize(chunk); SRT_MSGCTRL ctrl; const int stat = srt_recvmsg2(m_sock, pkt.payload.data(), (int) chunk, &ctrl); if (stat <= 0) { pkt.payload.clear(); return stat; } pkt.time = ctrl.srctime; chunk = size_t(stat); if (chunk < pkt.payload.size()) pkt.payload.resize(chunk); const bool need_bw_report = transmit_bw_report && (counter % transmit_bw_report) == transmit_bw_report - 1; const bool need_stats_report = transmit_stats_report && (counter % transmit_stats_report) == transmit_stats_report - 1; if (need_bw_report || need_stats_report) { CBytePerfMon perf; srt_bstats(m_sock, &perf, need_stats_report && !transmit_total_stats); if (transmit_stats_writer != nullptr) { if (need_bw_report) cerr << transmit_stats_writer->WriteBandwidth(perf.mbpsBandwidth) << std::flush; if (need_stats_report) out_stats << transmit_stats_writer->WriteStats(m_sock, perf) << std::flush; } } ++counter; return stat; } int SrtTarget::ConfigurePre(SRTSOCKET sock) { int result = SrtCommon::ConfigurePre(sock); if ( result == -1 ) return result; int yes = 1; // This is for the HSv4 compatibility; if both parties are HSv5 // (min. version 1.2.1), then this setting simply does nothing. // In HSv4 this setting is obligatory; otherwise the SRT handshake // extension will not be done at all. result = srt_setsockopt(sock, 0, SRTO_SENDER, &yes, sizeof yes); if ( result == -1 ) return result; return 0; } int SrtTarget::Write(const char* data, size_t size, int64_t src_time, ostream &out_stats) { static unsigned long counter = 1; SRT_MSGCTRL ctrl = srt_msgctrl_default; ctrl.srctime = src_time; int stat = srt_sendmsg2(m_sock, data, (int) size, &ctrl); if (stat == SRT_ERROR) { return stat; } const bool need_bw_report = transmit_bw_report && (counter % transmit_bw_report) == transmit_bw_report - 1; const bool need_stats_report = transmit_stats_report && (counter % transmit_stats_report) == transmit_stats_report - 1; if (need_bw_report || need_stats_report) { CBytePerfMon perf; srt_bstats(m_sock, &perf, need_stats_report && !transmit_total_stats); if (transmit_stats_writer != nullptr) { if (need_bw_report) cerr << transmit_stats_writer->WriteBandwidth(perf.mbpsBandwidth) << std::flush; if (need_stats_report) out_stats << transmit_stats_writer->WriteStats(m_sock, perf) << std::flush; } } ++counter; return stat; } SrtModel::SrtModel(string host, int port, map par) { InitParameters(host, par); if (m_mode == "caller") is_caller = true; else if (m_mode != "listener") throw std::invalid_argument("Only caller and listener modes supported"); m_host = host; m_port = port; } void SrtModel::Establish(std::string& w_name) { // This does connect or accept. // When this returned true, the caller should create // a new SrtSource or SrtTaget then call StealFrom(*this) on it. // If this is a connector and the peer doesn't have a corresponding // medium, it should send back a single byte with value 0. This means // that agent should stop connecting. if (is_caller) { // Establish a connection PrepareClient(); if (w_name != "") { Verb() << "Connect with requesting stream [" << w_name << "]"; srt::setstreamid(m_sock, w_name); } else { Verb() << "NO STREAM ID for SRT connection"; } if (m_outgoing_port) { Verb() << "Setting outgoing port: " << m_outgoing_port; SetupAdapter("", m_outgoing_port); } ConnectClient(m_host, m_port); if (m_outgoing_port == 0) { // Must rely on a randomly selected one. Extract the port // so that it will be reused next time. sockaddr_any s(AF_INET); int namelen = s.size(); if ( srt_getsockname(Socket(), s.get(), &namelen) == SRT_ERROR ) { Error("srt_getsockname"); } m_outgoing_port = s.hport(); Verb() << "Extracted outgoing port: " << m_outgoing_port; } } else { // Listener - get a socket by accepting. // Check if the listener is already created first if (Listener() == SRT_INVALID_SOCK) { Verb() << "Setting up listener: port=" << m_port << " backlog=5"; PrepareListener(m_adapter, m_port, 5); } Verb() << "Accepting a client..."; AcceptNewClient(); // This rewrites m_sock with a new SRT socket ("accepted" socket) w_name = srt::getstreamid(m_sock); Verb() << "... GOT CLIENT for stream [" << w_name << "]"; } } template struct Srt; template <> struct Srt { typedef SrtSource type; }; template <> struct Srt { typedef SrtTarget type; }; template Iface* CreateSrt(const string& host, int port, const map& par) { return new typename Srt::type (host, port, par); } class ConsoleSource: public Source { public: ConsoleSource() { #ifdef _WIN32 // The default stdin mode on windows is text. // We have to set it to the binary mode _setmode(_fileno(stdin), _O_BINARY); #endif } int Read(size_t chunk, MediaPacket& pkt, ostream & ignored SRT_ATR_UNUSED = cout) override { if (pkt.payload.size() < chunk) pkt.payload.resize(chunk); bool st = cin.read(pkt.payload.data(), chunk).good(); chunk = cin.gcount(); if (chunk == 0 || !st) { pkt.payload.clear(); return 0; } // Save this time to potentially use it for SRT target. pkt.time = srt_time_now(); if (chunk < pkt.payload.size()) pkt.payload.resize(chunk); return (int) chunk; } bool IsOpen() override { return cin.good(); } bool End() override { return cin.eof(); } int GetSysSocket() const override { return 0; }; }; class ConsoleTarget: public Target { public: ConsoleTarget() { #ifdef _WIN32 // The default stdout mode on windows is text. // We have to set it to the binary mode _setmode(_fileno(stdout), _O_BINARY); #endif } virtual ~ConsoleTarget() { cout.flush(); } int Write(const char* data, size_t len, int64_t src_time SRT_ATR_UNUSED, ostream & ignored SRT_ATR_UNUSED = cout) override { cout.write(data, len); return (int) len; } bool IsOpen() override { return cout.good(); } bool Broken() override { return cout.eof(); } int GetSysSocket() const override { return 0; }; }; template struct Console; template <> struct Console { typedef ConsoleSource type; }; template <> struct Console { typedef ConsoleTarget type; }; template Iface* CreateConsole() { return new typename Console::type (); } // More options can be added in future. SocketOption udp_options [] { { "iptos", IPPROTO_IP, IP_TOS, SocketOption::PRE, SocketOption::INT, nullptr }, // IP_TTL and IP_MULTICAST_TTL are handled separately by a common option, "ttl". { "mcloop", IPPROTO_IP, IP_MULTICAST_LOOP, SocketOption::PRE, SocketOption::INT, nullptr }, { "sndbuf", SOL_SOCKET, SO_SNDBUF, SocketOption::PRE, SocketOption::INT, nullptr}, { "rcvbuf", SOL_SOCKET, SO_RCVBUF, SocketOption::PRE, SocketOption::INT, nullptr} }; static inline bool IsMulticast(in_addr adr) { unsigned char* abytes = (unsigned char*)&adr.s_addr; unsigned char c = abytes[0]; return c >= 224 && c <= 239; } class UdpCommon { protected: int m_sock = -1; sockaddr_any sadr; string adapter; map m_options; void Setup(string host, int port, map attr) { m_sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (m_sock == -1) Error(SysError(), "UdpCommon::Setup: socket"); int yes = 1; ::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof yes); // set non-blocking mode #if defined(_WIN32) unsigned long ulyes = 1; if (ioctlsocket(m_sock, FIONBIO, &ulyes) == SOCKET_ERROR) #else if (ioctl(m_sock, FIONBIO, (const char *)&yes) < 0) #endif { Error(SysError(), "UdpCommon::Setup: ioctl FIONBIO"); } sadr = CreateAddr(host, port); bool is_multicast = false; if (attr.count("multicast")) { // XXX: Here provide support for IPv6 multicast #1479 if (sadr.family() != AF_INET) { throw std::runtime_error("UdpCommon: Multicast on IPv6 is not yet supported"); } if (!IsMulticast(sadr.sin.sin_addr)) { throw std::runtime_error("UdpCommon: requested multicast for a non-multicast-type IP address"); } is_multicast = true; } else if (sadr.family() == AF_INET && IsMulticast(sadr.sin.sin_addr)) { is_multicast = true; } if (is_multicast) { ip_mreq mreq; sockaddr_any maddr (AF_INET); int opt_name; void* mreq_arg_ptr; socklen_t mreq_arg_size; adapter = attr.count("adapter") ? attr.at("adapter") : string(); if ( adapter == "" ) { Verb() << "Multicast: home address: INADDR_ANY:" << port; maddr.sin.sin_family = AF_INET; maddr.sin.sin_addr.s_addr = htonl(INADDR_ANY); maddr.sin.sin_port = htons(port); // necessary for temporary use } else { Verb() << "Multicast: home address: " << adapter << ":" << port; maddr = CreateAddr(adapter, port); } if (attr.count("source")) { #ifdef IP_ADD_SOURCE_MEMBERSHIP ip_mreq_source mreq_ssm; /* this is an ssm. we need to use the right struct and opt */ opt_name = IP_ADD_SOURCE_MEMBERSHIP; mreq_ssm.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr; mreq_ssm.imr_interface.s_addr = maddr.sin.sin_addr.s_addr; inet_pton(AF_INET, attr.at("source").c_str(), &mreq_ssm.imr_sourceaddr); mreq_arg_size = sizeof(mreq_ssm); mreq_arg_ptr = &mreq_ssm; #else throw std::runtime_error("UdpCommon: source-filter multicast not supported by OS"); #endif } else { opt_name = IP_ADD_MEMBERSHIP; mreq.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr; mreq.imr_interface.s_addr = maddr.sin.sin_addr.s_addr; mreq_arg_size = sizeof(mreq); mreq_arg_ptr = &mreq; } #ifdef _WIN32 const char* mreq_arg = (const char*)mreq_arg_ptr; const auto status_error = SOCKET_ERROR; #else const void* mreq_arg = mreq_arg_ptr; const auto status_error = -1; #endif #if defined(_WIN32) || defined(__CYGWIN__) // On Windows it somehow doesn't work when bind() // is called with multicast address. Write the address // that designates the network device here. // Also, sets port sharing when working with multicast sadr = maddr; int reuse = 1; int shareAddrRes = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&reuse), sizeof(reuse)); if (shareAddrRes == status_error) { throw runtime_error("marking socket for shared use failed"); } Verb() << "Multicast(Windows): will bind to home address"; #else Verb() << "Multicast(POSIX): will bind to IGMP address: " << host; #endif int res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg, mreq_arg_size); if ( res == status_error ) { Error(errno, "adding to multicast membership failed"); } attr.erase("multicast"); attr.erase("adapter"); } // The "ttl" options is handled separately, it maps to both IP_TTL // and IP_MULTICAST_TTL so that TTL setting works for both uni- and multicast. if (attr.count("ttl")) { int ttl = stoi(attr.at("ttl")); int res = setsockopt(m_sock, IPPROTO_IP, IP_TTL, (const char*)&ttl, sizeof ttl); if (res == -1) Verb() << "WARNING: failed to set 'ttl' (IP_TTL) to " << ttl; res = setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&ttl, sizeof ttl); if (res == -1) Verb() << "WARNING: failed to set 'ttl' (IP_MULTICAST_TTL) to " << ttl; attr.erase("ttl"); } m_options = attr; for (auto o: udp_options) { // Ignore "binding" - for UDP there are no post options. if ( m_options.count(o.name) ) { string value = m_options.at(o.name); bool ok = o.apply(m_sock, value); if ( !ok ) Verb() << "WARNING: failed to set '" << o.name << "' to " << value; } } } void Error(int err, string src) { char buf[512]; string message = SysStrError(err, buf, 512u); cerr << "\nERROR #" << err << ": " << message << endl; throw TransmissionError("error: " + src + ": " + message); } ~UdpCommon() { #ifdef _WIN32 if (m_sock != -1) { shutdown(m_sock, SD_BOTH); closesocket(m_sock); m_sock = -1; } #else close(m_sock); #endif } }; class UdpSource: public Source, public UdpCommon { protected: bool eof = true; public: UdpSource(string host, int port, const map& attr) { Setup(host, port, attr); int stat = ::bind(m_sock, sadr.get(), sadr.size()); if ( stat == -1 ) Error(SysError(), "Binding address for UDP"); eof = false; } int Read(size_t chunk, MediaPacket& pkt, ostream & ignored SRT_ATR_UNUSED = cout) override { if (pkt.payload.size() < chunk) pkt.payload.resize(chunk); sockaddr_any sa(sadr.family()); socklen_t si = sa.size(); int stat = recvfrom(m_sock, pkt.payload.data(), (int) chunk, 0, sa.get(), &si); if (stat < 1) { if (SysError() != EWOULDBLOCK) eof = true; pkt.payload.clear(); return stat; } sa.len = si; // Save this time to potentially use it for SRT target. pkt.time = srt_time_now(); chunk = size_t(stat); if (chunk < pkt.payload.size()) pkt.payload.resize(chunk); return stat; } bool IsOpen() override { return m_sock != -1; } bool End() override { return eof; } int GetSysSocket() const override { return m_sock; }; }; class UdpTarget: public Target, public UdpCommon { public: UdpTarget(string host, int port, const map& attr ) { if (host.empty()) cerr << "\nWARN Host for UDP target is not provided. Will send to localhost:" << port << ".\n"; Setup(host, port, attr); if (adapter != "") { sockaddr_any maddr = CreateAddr(adapter, 0); if (maddr.family() != AF_INET) { Error(0, "UDP/target: IPv6 multicast not supported in the application"); } in_addr addr = maddr.sin.sin_addr; int res = setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_IF, reinterpret_cast(&addr), sizeof(addr)); if (res == -1) { Error(SysError(), "setsockopt/IP_MULTICAST_IF: " + adapter); } } } int Write(const char* data, size_t len, int64_t src_time SRT_ATR_UNUSED, ostream & ignored SRT_ATR_UNUSED = cout) override { int stat = sendto(m_sock, data, (int) len, 0, sadr.get(), sadr.size()); if ( stat == -1 ) { if ((false)) Error(SysError(), "UDP Write/sendto"); return stat; } return stat; } bool IsOpen() override { return m_sock != -1; } bool Broken() override { return false; } int GetSysSocket() const override { return m_sock; }; }; template struct Udp; template <> struct Udp { typedef UdpSource type; }; template <> struct Udp { typedef UdpTarget type; }; template Iface* CreateUdp(const string& host, int port, const map& par) { return new typename Udp::type (host, port, par); } class RtpSource: public UdpSource { // for now, make no effort to parse the header, just assume it is always // fixed length and either a user-configurable value, or twelve bytes. const int MINIMUM_RTP_HEADER_SIZE = 12; int bytes_to_skip = MINIMUM_RTP_HEADER_SIZE; public: RtpSource(string host, int port, const map& attr) : UdpSource { host, port, attr } { if (attr.count("rtpheadersize")) { const int header_size = stoi(attr.at("rtpheadersize"), 0, 0); if (header_size < MINIMUM_RTP_HEADER_SIZE) { cerr << "Invalid RTP header size provided: " << header_size << ", minimum allowed is " << MINIMUM_RTP_HEADER_SIZE << endl; throw invalid_argument("Invalid RTP header size"); } bytes_to_skip = header_size; } } int Read(size_t chunk, MediaPacket& pkt, ostream & ignored SRT_ATR_UNUSED = cout) override { const int length = UdpSource::Read(chunk, pkt); if (length < 1 || !bytes_to_skip) { // something went wrong, or we're not skipping bytes for some // reason, just return the length read via the base method return length; } // we got some data and we're supposed to skip some of it // check there's enough bytes for our intended skip if (length < bytes_to_skip) { // something went wrong here cerr << "RTP packet too short (" << length << " bytes) to remove headers (needed " << bytes_to_skip << ")" << endl; throw std::runtime_error("Unexpected RTP packet length"); } pkt.payload.erase( pkt.payload.begin(), pkt.payload.begin() + bytes_to_skip ); return length - bytes_to_skip; } }; class RtpTarget : public UdpTarget { public: RtpTarget(string host, int port, const map& attr ) : UdpTarget { host, port, attr } {} }; template struct Rtp; template <> struct Rtp { typedef RtpSource type; }; template <> struct Rtp { typedef RtpTarget type; }; template Iface* CreateRtp(const string& host, int port, const map& par) { return new typename Rtp::type (host, port, par); } template inline bool IsOutput() { return false; } template<> inline bool IsOutput() { return true; } template extern unique_ptr CreateMedium(const string& uri) { unique_ptr ptr; UriParser u(uri); int iport = 0; switch ( u.type() ) { default: break; // do nothing, return nullptr case UriParser::FILE: if (u.host() == "con" || u.host() == "console") { if (IsOutput() && ( (Verbose::on && Verbose::cverb == &cout) || g_stats_are_printed_to_stdout)) { cerr << "ERROR: file://con with -v or -r or -s would result in mixing the data and text info.\n"; cerr << "ERROR: HINT: you can stream through a FIFO (named pipe)\n"; throw invalid_argument("incorrect parameter combination"); } ptr.reset(CreateConsole()); } // Disable regular file support for the moment #if 0 else ptr.reset( CreateFile(u.path())); #endif break; case UriParser::SRT: iport = atoi(u.port().c_str()); if ( iport < 1024 ) { cerr << "Port value invalid: " << iport << " - must be >=1024\n"; throw invalid_argument("Invalid port number"); } ptr.reset( CreateSrt(u.host(), iport, u.parameters()) ); break; case UriParser::UDP: iport = atoi(u.port().c_str()); if ( iport < 1024 ) { cerr << "Port value invalid: " << iport << " - must be >=1024\n"; throw invalid_argument("Invalid port number"); } ptr.reset( CreateUdp(u.host(), iport, u.parameters()) ); break; case UriParser::RTP: if (IsOutput()) { cerr << "RTP not supported as an output\n"; throw invalid_argument("Invalid output protocol: RTP"); } iport = atoi(u.port().c_str()); if ( iport < 1024 ) { cerr << "Port value invalid: " << iport << " - must be >=1024\n"; throw invalid_argument("Invalid port number"); } ptr.reset( CreateRtp(u.host(), iport, u.parameters()) ); break; } if (ptr.get()) ptr->uri = std::move(u); return ptr; } std::unique_ptr Source::Create(const std::string& url) { return CreateMedium(url); } std::unique_ptr Target::Create(const std::string& url) { return CreateMedium(url); } srt-1.5.4/apps/transmitmedia.hpp000066400000000000000000000125371471311275400166630ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_COMMON_TRANSMITMEDIA_HPP #define INC_SRT_COMMON_TRANSMITMEDIA_HPP #include #include #include #include "transmitbase.hpp" #include // Needs access to CUDTException using namespace std; // Trial version of an exception. Try to implement later an official // interruption mechanism in SRT using this. struct TransmissionError: public std::runtime_error { TransmissionError(const std::string& arg): std::runtime_error(arg) { } }; class SrtCommon { protected: bool m_output_direction = false; //< Defines which of SND or RCV option variant should be used, also to set SRT_SENDER for output int m_timeout = 0; //< enforces using SRTO_SNDTIMEO or SRTO_RCVTIMEO, depending on @a m_output_direction bool m_tsbpdmode = true; int m_outgoing_port = 0; string m_mode; string m_adapter; map m_options; // All other options, as provided in the URI SRTSOCKET m_sock = SRT_INVALID_SOCK; SRTSOCKET m_bindsock = SRT_INVALID_SOCK; bool IsUsable() { SRT_SOCKSTATUS st = srt_getsockstate(m_sock); return st > SRTS_INIT && st < SRTS_BROKEN; } bool IsBroken() { return srt_getsockstate(m_sock) > SRTS_CONNECTED; } public: void InitParameters(string host, map par); void PrepareListener(string host, int port, int backlog); void StealFrom(SrtCommon& src); bool AcceptNewClient(); SRTSOCKET Socket() const { return m_sock; } SRTSOCKET Listener() const { return m_bindsock; } void Close(); protected: void Error(string src); void Init(string host, int port, map par, bool dir_output); virtual int ConfigurePost(SRTSOCKET sock); virtual int ConfigurePre(SRTSOCKET sock); void OpenClient(string host, int port); void PrepareClient(); void SetupAdapter(const std::string& host, int port); void ConnectClient(string host, int port); void OpenServer(string host, int port) { PrepareListener(host, port, 1); } void OpenRendezvous(string adapter, string host, int port); virtual ~SrtCommon(); }; class SrtSource: public Source, public SrtCommon { std::string hostport_copy; public: SrtSource(std::string host, int port, const std::map& par); SrtSource() { // Do nothing - create just to prepare for use } int Read(size_t chunk, MediaPacket& pkt, ostream& out_stats = cout) override; /* In this form this isn't needed. Unblock if any extra settings have to be made. virtual int ConfigurePre(UDTSOCKET sock) override { int result = SrtCommon::ConfigurePre(sock); if ( result == -1 ) return result; return 0; } */ bool IsOpen() override { return IsUsable(); } bool End() override { return IsBroken(); } SRTSOCKET GetSRTSocket() const override { SRTSOCKET socket = SrtCommon::Socket(); if (socket == SRT_INVALID_SOCK) socket = SrtCommon::Listener(); return socket; } bool AcceptNewClient() override { return SrtCommon::AcceptNewClient(); } }; class SrtTarget: public Target, public SrtCommon { public: SrtTarget(std::string host, int port, const std::map& par) { Init(host, port, par, true); } SrtTarget() {} int ConfigurePre(SRTSOCKET sock) override; int Write(const char* data, size_t size, int64_t src_time, ostream &out_stats = cout) override; bool IsOpen() override { return IsUsable(); } bool Broken() override { return IsBroken(); } size_t Still() override { size_t bytes; int st = srt_getsndbuffer(m_sock, nullptr, &bytes); if (st == -1) return 0; return bytes; } SRTSOCKET GetSRTSocket() const override { SRTSOCKET socket = SrtCommon::Socket(); if (socket == SRT_INVALID_SOCK) socket = SrtCommon::Listener(); return socket; } bool AcceptNewClient() override { return SrtCommon::AcceptNewClient(); } }; // This class is used when we don't know yet whether the given URI // designates an effective listener or caller. So we create it, initialize, // then we know what mode we'll be using. // // When caller, then we will do connect() using this object, then clone out // a new object - of a direction specific class - which will steal the socket // from this one and then roll the data. After this, this object is ready // to connect again, and will create its own socket for that occasion, and // the whole procedure repeats. // // When listener, then this object will be doing accept() and with every // successful acceptation it will clone out a new object - of a direction // specific class - which will steal just the connection socket from this // object. This object will still live on and accept new connections and // so on. class SrtModel: public SrtCommon { public: bool is_caller = false; string m_host; int m_port = 0; SrtModel(string host, int port, map par); void Establish(std::string& name); }; #endif srt-1.5.4/apps/uriparser.cpp000066400000000000000000000243501471311275400160250ustar00rootroot00000000000000/* * 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/. * */ // STL includes #include #include #include #include "uriparser.hpp" #ifdef TEST #define TEST1 1 #endif #ifdef TEST1 #include #endif using namespace std; map g_types; // Map construction using the initializer list is only available starting from C++11. // This dummy structure is used instead. struct UriParserInit { UriParserInit() { g_types["file"] = UriParser::FILE; g_types["udp"] = UriParser::UDP; g_types["tcp"] = UriParser::TCP; g_types["srt"] = UriParser::SRT; g_types["rtmp"] = UriParser::RTMP; g_types["http"] = UriParser::HTTP; g_types["rtp"] = UriParser::RTP; g_types[""] = UriParser::UNKNOWN; } } g_uriparser_init; UriParser::UriParser(const string& strUrl, DefaultExpect exp) : m_uriType(UNKNOWN) { m_expect = exp; Parse(strUrl, exp); } UriParser::~UriParser(void) { } string UriParser::makeUri() { // Reassemble parts into the URI string prefix = ""; if (m_proto != "") { prefix = m_proto + "://"; } std::ostringstream out; out << prefix << m_host; if ((m_port == "" || m_port == "0") && m_expect == EXPECT_FILE) { // Do not add port } else { out << ":" << m_port; } if (m_path != "") { if (m_path[0] != '/') out << "/"; out << m_path; } if (!m_mapQuery.empty()) { out << "?"; query_it i = m_mapQuery.begin(); for (;;) { out << i->first << "=" << i->second; ++i; if (i == m_mapQuery.end()) break; out << "&"; } } m_origUri = out.str(); return m_origUri; } string UriParser::proto(void) const { return m_proto; } UriParser::Type UriParser::type() const { return m_uriType; } string UriParser::host(void) const { return m_host; } string UriParser::port(void) const { return m_port; } unsigned short int UriParser::portno(void) const { // This returns port in numeric version. Fallback to 0. try { int i = atoi(m_port.c_str()); if ( i <= 0 || i > 65535 ) return 0; return i; } catch (...) { return 0; } } string UriParser::path(void) const { return m_path; } string UriParser::queryValue(const string& strKey) const { return m_mapQuery.at(strKey); } // NOTE: handles percent encoded single byte ASCII / Latin-1 characters but not unicode characters and encodings static string url_decode(const string& str) { string ret; ret.reserve(str.size()); size_t end_idx = 0; for (;;) { size_t idx = str.find('%', end_idx); if (idx == string::npos) break; if (idx + 2 >= str.size()) // bad percent encoding at the end break; ret += str.substr(end_idx, idx - end_idx); // make a "string" out of only two characters following % char tmp[3] = { str[idx+1], str[idx+2], '\0' }; char* endptr = 0; unsigned val = strtoul(tmp, &endptr, 16); if (endptr != &tmp[2]) { // Processing was not correct. Skip these and proceed. ret += str[idx]; end_idx = idx + 1; } else { ret += char(val); end_idx = idx + 3; } // And again search anew since end_idx. } // Copy the rest of the string that wasn't processed. ret += str.substr(end_idx, str.size() - end_idx); return ret; } void UriParser::Parse(const string& strUrl, DefaultExpect exp) { int iQueryStart = -1; size_t idx = strUrl.find("?"); if (idx != string::npos) { m_host = strUrl.substr(0, idx); iQueryStart = (int)(idx + 1); } else { m_host = strUrl; } idx = m_host.find("://"); if (idx != string::npos) { m_proto = m_host.substr(0, idx); transform(m_proto.begin(), m_proto.end(), m_proto.begin(), [](char c){ return tolower(c); }); m_host = m_host.substr(idx + 3, m_host.size() - (idx + 3)); } // Handle the IPv6 specification in square brackets. // This actually handles anything specified in [] so potentially // you can also specify the usual hostname here as well. If the // whole host results to have [] at edge positions, they are stripped, // otherwise they remain. In both cases the search for the colon // separating the port specification starts only after ]. const size_t i6pos = m_host.find("["); size_t i6end = string::npos; // Search for the "path" part only behind the closed bracket, // if both open and close brackets were found size_t path_since = 0; if (i6pos != string::npos) { i6end = m_host.find("]", i6pos); if (i6end != string::npos) path_since = i6end; } idx = m_host.find("/", path_since); if (idx != string::npos) { m_path = m_host.substr(idx, m_host.size() - idx); m_host = m_host.substr(0, idx); } // Check special things in the HOST entry. size_t atp = m_host.find('@'); if (atp != string::npos) { string realhost = m_host.substr(atp+1); string prehost; if ( atp > 0 ) { prehost = m_host.substr(0, atp-0); size_t colon = prehost.find(':'); if ( colon != string::npos ) { string pw = prehost.substr(colon+1); string user; if ( colon > 0 ) user = prehost.substr(0, colon-0); m_mapQuery["user"] = user; m_mapQuery["password"] = pw; } else { m_mapQuery["user"] = prehost; } } else { m_mapQuery["multicast"] = "1"; } m_host = realhost; } bool stripbrackets = false; size_t hostend = 0; if (i6pos != string::npos) { // IPv6 IP address. Find the terminating ] hostend = m_host.find("]", i6pos); idx = m_host.rfind(":"); if (hostend != string::npos) { // Found the end. But not necessarily it was // at the beginning. If it was at the beginning, // strip them from the host name. size_t lasthost = idx; if (idx != string::npos && idx < hostend) { idx = string::npos; lasthost = m_host.size(); } if (i6pos == 0 && hostend == lasthost - 1) { stripbrackets = true; } } } else { idx = m_host.rfind(":"); } if (idx != string::npos) { m_port = m_host.substr(idx + 1, m_host.size() - (idx + 1)); // Extract host WITHOUT stripping brackets m_host = m_host.substr(0, idx); } if (stripbrackets) { if (!hostend) hostend = m_host.size() - 1; m_host = m_host.substr(1, hostend - 1); } if ( m_port == "" && m_host != "" ) { // Check if the host-but-no-port has specified // a single integer number. If so // We need to use C86 strtol, cannot use C++11 const char* beg = m_host.c_str(); const char* end = m_host.c_str() + m_host.size(); char* eos = 0; long val = strtol(beg, &eos, 10); if ( val > 0 && eos == end ) { m_port = m_host; m_host = ""; } } string strQueryPair; while (iQueryStart > -1) { idx = strUrl.find("&", iQueryStart); if (idx != string::npos) { strQueryPair = strUrl.substr(iQueryStart, idx - iQueryStart); iQueryStart = (int)(idx + 1); } else { strQueryPair = strUrl.substr(iQueryStart, strUrl.size() - iQueryStart); iQueryStart = (int)idx; } idx = strQueryPair.find("="); if (idx != string::npos) { m_mapQuery[url_decode(strQueryPair.substr(0, idx))] = url_decode(strQueryPair.substr(idx + 1, strQueryPair.size() - (idx + 1))); } } if (m_proto == "file") { if ( m_path.size() > 3 && m_path.substr(0, 3) == "/./" ) m_path = m_path.substr(3); } // Post-parse fixes // Treat empty protocol as a file. In this case, merge the host and path. if (exp == EXPECT_FILE && m_proto == "" && m_port == "") { m_proto = "file"; m_path = m_host + m_path; m_host = ""; } const auto proto_it = g_types.find(m_proto); // Default-constructed UNKNOWN will be used if not found. if (proto_it != g_types.end()) { m_uriType = proto_it->second; } m_origUri = strUrl; } #ifdef TEST #include using namespace std; int main( int argc, char** argv ) { if ( argc < 2 ) { return 0; } UriParser parser (argv[1], UriParser::EXPECT_HOST); std::vector args; if (argc > 2) { copy(argv+2, argv+argc, back_inserter(args)); } (void)argc; cout << "PARSING URL: " << argv[1] << endl; cout << "SCHEME INDEX: " << int(parser.type()) << endl; cout << "PROTOCOL: " << parser.proto() << endl; cout << "HOST: " << parser.host() << endl; cout << "PORT (string): " << parser.port() << endl; cout << "PORT (numeric): " << parser.portno() << endl; cout << "PATH: " << parser.path() << endl; cout << "PARAMETERS:\n"; for (auto& p: parser.parameters()) { cout << "\t" << p.first << " = " << p.second << endl; } if (!args.empty()) { for (string& s: args) { vector keyval; Split(s, '=', back_inserter(keyval)); if (keyval.size() < 2) keyval.push_back(""); parser[keyval[0]] = keyval[1]; } cout << "REASSEMBLED: " << parser.makeUri() << endl; } return 0; } #endif srt-1.5.4/apps/uriparser.hpp000066400000000000000000000037141471311275400160330ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_URL_PARSER_H #define INC_SRT_URL_PARSER_H #include #include #include #include "utilities.h" //++ // UriParser //-- class UriParser { // Construction public: enum DefaultExpect { EXPECT_FILE, EXPECT_HOST }; enum Type { UNKNOWN, FILE, UDP, TCP, SRT, RTMP, HTTP, RTP }; UriParser(const std::string& strUrl, DefaultExpect exp = EXPECT_FILE); UriParser(): m_uriType(UNKNOWN) {} virtual ~UriParser(void); // Some predefined types Type type() const; typedef MapProxy ParamProxy; // Operations public: std::string uri() const { return m_origUri; } std::string proto() const; std::string scheme() const { return proto(); } std::string host() const; std::string port() const; unsigned short int portno() const; std::string hostport() const { return host() + ":" + port(); } std::string path() const; std::string queryValue(const std::string& strKey) const; std::string makeUri(); ParamProxy operator[](const std::string& key) { return ParamProxy(m_mapQuery, key); } const std::map& parameters() const { return m_mapQuery; } typedef std::map::const_iterator query_it; private: void Parse(const std::string& strUrl, DefaultExpect); // Overridables public: // Overrides public: // Data private: std::string m_origUri; std::string m_proto; std::string m_host; std::string m_port; std::string m_path; Type m_uriType; DefaultExpect m_expect; std::map m_mapQuery; }; //#define TEST1 1 #endif // INC_SRT_URL_PARSER_H srt-1.5.4/apps/verbose.cpp000066400000000000000000000037671471311275400154670ustar00rootroot00000000000000/* * 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/. * */ #include "verbose.hpp" #include "sync.h" // srt::sync namespace Verbose { bool on = false; std::ostream* cverb = &std::cerr; srt::sync::Mutex vlock; Log& Log::operator<<(LogNoEol) { noeol = true; if (on) { (*cverb) << std::flush; } return *this; } Log& Log::operator<<(LogLock) { lockline = true; return *this; } Log::~Log() { if (on && !noeol) { if (lockline) { // Lock explicitly, as requested, and wait for the opportunity. vlock.lock(); } else if (vlock.try_lock()) { // Successfully locked, so unlock immediately, locking wasn't requested. vlock.unlock(); } else { // Failed to lock, which means that some other thread has locked it first. // This means that some other thread wants to print the whole line and doesn't // want to be disturbed during this process. Lock the thread then as this is // the only way to wait until it's unlocked. However, do not block your printing // with locking, because you were not requested to lock (treat this mutex as // an entry semaphore, which may only occasionally block the whole line). vlock.lock(); vlock.unlock(); } (*cverb) << std::endl; // If lockline is set, the lock was requested and WAS DONE, so unlock. // Otherwise locking WAS NOT DONE. if (lockline) vlock.unlock(); } } } srt-1.5.4/apps/verbose.hpp000066400000000000000000000037721471311275400154700ustar00rootroot00000000000000/* * 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/. * */ #ifndef INC_SRT_VERBOSE_HPP #define INC_SRT_VERBOSE_HPP #include #include "sync.h" namespace Verbose { extern bool on; extern std::ostream* cverb; struct LogNoEol { LogNoEol() {} }; struct LogLock { LogLock() {} }; class Log { bool noeol = false; srt::sync::atomic lockline; // Disallow creating dynamic objects void* operator new(size_t) = delete; public: Log() {} Log(const Log& ) {} template Log& operator<<(const V& arg) { // Template - must be here; extern template requires // predefined specializations. if (on) (*cverb) << arg; return *this; } Log& operator<<(LogNoEol); Log& operator<<(LogLock); ~Log(); }; class ErrLog: public Log { public: template ErrLog& operator<<(const V& arg) { // Template - must be here; extern template requires // predefined specializations. if (on) (*cverb) << arg; else std::cerr << arg; return *this; } }; // terminal inline void Print(Log& ) {} template inline void Print(Log& out, Arg1&& arg1, Args&&... args) { out << arg1; Print(out, args...); } } inline Verbose::Log Verb() { return Verbose::Log(); } inline Verbose::ErrLog Verror() { return Verbose::ErrLog(); } template inline void Verb(Args&&... args) { Verbose::Log log; Verbose::Print(log, args...); } template inline void Verror(Args&&... args) { Verbose::ErrLog log; Verbose::Print(log, args...); } // Manipulator tags static const Verbose::LogNoEol VerbNoEOL; static const Verbose::LogLock VerbLock; #endif srt-1.5.4/cmake_object_lib_support.c000066400000000000000000000007351471311275400175370ustar00rootroot00000000000000// DO NOT DELETE // This file is needed for Xcode to properly handle CMake OBJECT Libraries // From docs (https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries): // // ... Some native build systems (such as Xcode) may not like targets that have only object files, // so consider adding at least one real source file to any target that references $. // Just a dummy symbol to avoid compiler warnings int srt_object_lib_dummy = 0; srt-1.5.4/codecov.yml000066400000000000000000000002561471311275400145060ustar00rootroot00000000000000coverage: status: project: default: target: 40% threshold: null patch: false changes: false ignore: - "testing" - "apps" - "example"srt-1.5.4/common/000077500000000000000000000000001471311275400136265ustar00rootroot00000000000000srt-1.5.4/common/filelist_win32.maf000066400000000000000000000002341471311275400171470ustar00rootroot00000000000000 PUBLIC HEADERS win/syslog_defs.h # # These are included by platform_sys.h header contained in ../srtcore/filelist.maf # win/unistd.h SOURCES win_time.cpp srt-1.5.4/common/win/000077500000000000000000000000001471311275400144235ustar00rootroot00000000000000srt-1.5.4/common/win/syslog_defs.h000066400000000000000000000023001471311275400171100ustar00rootroot00000000000000#ifndef INC_SRT_WINDOWS_SYSLOG_DEFS_H #define INC_SRT_WINDOWS_SYSLOG_DEFS_H #define LOG_EMERG 0 #define LOG_ALERT 1 #define LOG_CRIT 2 #define LOG_ERR 3 #define LOG_WARNING 4 #define LOG_NOTICE 5 #define LOG_INFO 6 #define LOG_DEBUG 7 #define LOG_PRIMASK 0x07 #define LOG_PRI(p) ((p) & LOG_PRIMASK) #define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) #define LOG_KERN (0<<3) #define LOG_USER (1<<3) #define LOG_MAIL (2<<3) #define LOG_DAEMON (3<<3) #define LOG_AUTH (4<<3) #define LOG_SYSLOG (5<<3) #define LOG_LPR (6<<3) #define LOG_NEWS (7<<3) #define LOG_UUCP (8<<3) #define LOG_CRON (9<<3) #define LOG_AUTHPRIV (10<<3) #define LOG_FTP (11<<3) /* Codes through 15 are reserved for system use */ #define LOG_LOCAL0 (16<<3) #define LOG_LOCAL1 (17<<3) #define LOG_LOCAL2 (18<<3) #define LOG_LOCAL3 (19<<3) #define LOG_LOCAL4 (20<<3) #define LOG_LOCAL5 (21<<3) #define LOG_LOCAL6 (22<<3) #define LOG_LOCAL7 (23<<3) #define LOG_NFACILITIES 24 #define LOG_FACMASK 0x03f8 #define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3) #endif srt-1.5.4/common/win/unistd.h000066400000000000000000000032321471311275400161020ustar00rootroot00000000000000#ifndef _UNISTD_H #define _UNISTD_H 1 /* This file intended to serve as a drop-in replacement for * unistd.h on Windows * Please add functionality as neeeded */ #include #include //#include /* getopt at: https://gist.github.com/ashelly/7776712*/ #include /* for getpid() and the exec..() family */ #include /* for _getcwd() and _chdir() */ #define srandom srand #define random rand /* Values for the second argument to access. These may be OR'd together. */ #define R_OK 4 /* Test for read permission. */ #define W_OK 2 /* Test for write permission. */ //#define X_OK 1 /* execute permission - unsupported in windows*/ #define F_OK 0 /* Test for existence. */ #define access _access #define dup2 _dup2 #define execve _execve #define ftruncate _chsize #define unlink _unlink #define fileno _fileno #define getcwd _getcwd #define chdir _chdir #define isatty _isatty #define lseek _lseek /* read, write, and close are NOT being #defined here, because while there are file handle specific versions for Windows, they probably don't work for sockets. You need to look at your app and consider whether to call e.g. closesocket(). */ #define ssize_t int #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 /* should be in some equivalent to */ typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; #endif /* unistd.h */ srt-1.5.4/common/win/wintime.h000066400000000000000000000026431471311275400162550ustar00rootroot00000000000000#ifndef INC_SRT_WIN_WINTIME #define INC_SRT_WIN_WINTIME #include #include // HACK: This include is a workaround for a bug in the MinGW headers // where pthread.h, which defines _POSIX_THREAD_SAFE_FUNCTIONS, // has to be included before time.h so that time.h defines // localtime_r correctly #include #ifdef __cplusplus extern "C" { #endif #if !defined(_MSC_VER) #define SRTCOMPAT_WINTIME_STATIC_INLINE_DECL static inline #else // NOTE: MVC Does not like static inline for C functions in some versions. // so just use static for MVC. #define SRTCOMPAT_WINTIME_STATIC_INLINE_DECL static #endif #ifndef _TIMEZONE_DEFINED /* also in sys/time.h */ #define _TIMEZONE_DEFINED struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; #endif void SRTCompat_timeradd( struct timeval *a, struct timeval *b, struct timeval *result); SRTCOMPAT_WINTIME_STATIC_INLINE_DECL void timeradd( struct timeval *a, struct timeval *b, struct timeval *result) { SRTCompat_timeradd(a, b, result); } int SRTCompat_gettimeofday( struct timeval* tp, struct timezone* tz); SRTCOMPAT_WINTIME_STATIC_INLINE_DECL int gettimeofday( struct timeval* tp, struct timezone* tz) { return SRTCompat_gettimeofday(tp, tz); } #undef SRTCOMPAT_WINTIME_STATIC_INLINE_DECL #ifdef __cplusplus } #endif #endif // INC_SRT_WIN_WINTIME srt-1.5.4/common/win_time.cpp000066400000000000000000000020031471311275400161400ustar00rootroot00000000000000/* * 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/. * */ /***************************************************************************** written by Haivision Systems Inc. *****************************************************************************/ #include "win/wintime.h" #include void SRTCompat_timeradd(struct timeval *a, struct timeval *b, struct timeval *result) { result->tv_sec = a->tv_sec + b->tv_sec; result->tv_usec = a->tv_usec + b->tv_usec; if (result->tv_usec >= 1000000) { result->tv_sec++; result->tv_usec -= 1000000; } } int SRTCompat_gettimeofday(struct timeval* tp, struct timezone*) { struct timeb tb; ftime(&tb); tp->tv_sec = (long)tb.time; tp->tv_usec = 1000*tb.millitm; return 0; } srt-1.5.4/configure000077500000000000000000000145041471311275400142510ustar00rootroot00000000000000#!/usr/bin/tclsh # # 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/. # # This is a general-purpose configure script, which is a user-friendly # wrapper to call the "cmake" command. # There are two options that are handled specifically: # # --help: show the list of official options # --prefix: alias to --cmake-install-prefix # The processing done automatically on all options by default is: # Every option like: # --long-c++-option # --cmake-special-option=ON # Turns into: # -DLONG_CXX_OPTION=1 # -DCMAKE_SPECIAL_OPTION=ON # # In the configuration file, "configure-data.tcl", you can add # special processing for options and define explicit options # in the "::options" dictionary. Explicit options (in contrast # to "blind" options) have additional properties: # # - only those options are mentioned with --help # - you can pass a value for this option without = character # - you can specify --disable-option instead of --enable-option=0 # # In "configure-data.tcl", beside ::options, you can define "preprocess" and # "postprocess" procedures. In "preprocess", use ::optval array to modify the # list of options to be processed further. Additionally in "postprocess" # procedure you can influence directly the options for "cmake" command in # ::cmakeopt variable (modifying ::optval in "postprocess" is useless). # The idea is that CMakeLists.txt contains things that are highly # customizable, but no system or option autodetection AWA "sensible # defaults" are provided. This is done by this script. set here [file dirname $argv0] set options "" set toolchain_changers "" source $here/configure-data.tcl # Update alias with default alias dict set alias --prefix --cmake-install-prefix= proc resolve opt { set type arg set pos [string first $opt =] if { $pos == -1 } { set type bool set mark "" } else { set type arg set mark [string range $opt $pos+1 end] set opt [string range $opt 0 $pos-1] } set var [string toupper [string map {- _ + x} $opt]] return [list --$opt $var $type $mark] } # Check if a --disable option has its --enable counterpart. If so, # then just invert the option. proc resolve_disablers {} { set enablers "" set optkeys_len [llength $::optkeys] for {set pos 0} {$pos < $optkeys_len} {incr pos} { set opt [lindex $::optkeys $pos] if { [string match --disable-* $opt] } { set inverted enable-[string range $opt 10 end] if { $inverted in [dict keys $::options] } { lset ::optkeys $pos --$inverted set val $::optval($opt) unset ::optval($opt) if { $val == "" || ![string is boolean $val] } { set ::optval(--$inverted) 0 } else { set ::optval(--$inverted) [expr {!$val}] } puts "NOTE: $opt changed into --$inverted=$::optval(--$inverted)" } } } } foreach {o desc} $options { lassign [resolve $o] optname optvar opttype optmark set opt($optname) [list $optvar $opttype $optmark] set info($optname) $desc } if { $argv == "--help" || $argv == "-h" } { puts stderr "Usage: ./configure \[options\]" puts stderr "OPTIONS:" foreach o [lsort [array names opt]] { lassign $opt($o) unu type mark set imark "" if { $mark != "" } { set imark "=$mark" } puts stderr "\t$o$imark - $info($o)" } puts stderr "NOTE1: Option list may be incomplete. Refer to variables in CMakeLists.txt" puts stderr "NOTE2: Non-internal options turn e.g. --enable-c++11 into cmake -DENABLE_CXX11=1" puts stderr "NOTE3: You can use --disable-x instead of --enable-x=0 for the above options." exit 1 } if { [info proc init] != "" } { init } #parray opt set saveopt "" set optkeys "" set dryrun 0 set type "" foreach a $argv { if { [info exists val] } { unset val } if { $saveopt != "" } { set optval($saveopt) $a set saveopt "" continue } if { [string range $a 0 1] != "--" } { error "Unexpected argument '$a'. Options must start with --" } if { $a == "--dryrun" } { set dryrun 1 continue } set type "" if { [set a1 [string first = $a]] != -1 } { # Do not split. Options may include =. set val [string range $a $a1+1 end] set a [string range $a 0 $a1-1] } if { [dict exists $::alias $a] } { set aname [dict get $::alias $a] if { [string first = $aname] != -1 } { lassign [split $aname =] a aval set type arg } } if { ![info exists opt($a)] } { #puts stderr "WARNING: Unknown option: $a" # But still, simply turn the option to assign-based use. lassign [resolve [string range $a 2 end]] oname var if { ![info exists val] && $type == "" } { set type bool } } else { lassign $opt($a) var type } if { $type == "bool" } { if { ![info exists val] } { set val 1 } set optval($a) $val } elseif { [info exists val] } { set optval($a) $val } else { set saveopt $a } lappend optkeys $a } if { $saveopt != "" } { error "Extra unhandled argument: $saveopt" } # Save the original call into config-status.sh set ofd [open config-status.sh w] puts $ofd "#!/bin/bash" puts -nonewline $ofd "$argv0 " foreach a $argv { set len 1 if {[catch {llength $a} len] || $len > 1 } { puts -nonewline $ofd "'$a' " } else { puts -nonewline $ofd "$a " } } puts $ofd "" close $ofd file attributes config-status.sh -permissions +x set cmakeopt "" resolve_disablers if { [info proc preprocess] != "" } { preprocess } # Check if there were new values added not added to optkeys foreach a [array names optval] { if { $a ni $optkeys } { lappend optkeys $a } } foreach a $optkeys { if { ![info exists optval($a)] } { continue ;# user action might have removed it. } if { ![info exists opt($a)] } { #puts stderr "WARNING: Unknown option: $a" # But still, simply turn the option to assign-based use. lassign [resolve [string range $a 2 end]] oname var if { ![info exists val] && $type == "" } { set type bool } } else { lassign $opt($a) var type } set val $optval($a) lappend cmakeopt "-D$var=$val" } if { [info proc postprocess] != "" } { postprocess } #puts "VARSPEC: $cmakeopt" set cmd [list cmake $here {*}$cmakeopt] puts "Running: $cmd" if { !$dryrun} { if { [catch {exec 2>@stderr >@stdout {*}$cmd} result] } { puts "CONFIGURE: cmake reported error: $result" } } else { puts "(not really - dry run)" } srt-1.5.4/configure-data.tcl000066400000000000000000000363541471311275400157450ustar00rootroot00000000000000# # 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/. # # API description: # Expected variables: # - options: dictionary "option-name" : "description" # if there's '=' in option name, it expects an argument. Otherwise it's boolean. # - alias: optional, you can make shortcuts to longer named options. Remember to use = in target name. # # Optional procedures: # - preprocess: run before command-line arguments ($argv) are reviewed # - postprocess: run after options are reviewed and all data filled in # # Available variables in postprocess: # # - optval (array): contains all option names with their assigned values # - cmakeopt (scalar): a list of all options for "cmake" command line # Options processed here internally, not passed to cmake set internal_options { with-compiler-prefix= "set C/C++ toolchains gcc and g++" with-compiler-type= "compiler type: gcc(default), cc, others simply add ++ for C++" with-srt-name= "Override srt library name" with-haicrypt-name= "Override haicrypt library name (if compiled separately)" with-atomic= "Select implementation for atomics (compiler-intrinsics or sync-mutex)" } # Options that refer directly to variables used in CMakeLists.txt set cmake_options { cygwin-use-posix "Should the POSIX API be used for cygwin. Ignored if the system isn't cygwin. (default: OFF)" enable-c++11 "Should the c++11 parts (srt-live-transmit) be enabled (default: ON, with gcc < 4.7 OFF)" enable-apps "Should the Support Applications be Built? (default: ON)" enable-bonding "Enable 'bonding' SRT feature (default: OFF)" enable-testing "Should developer testing applications be built (default: OFF)" enable-profile "Should instrument the code for profiling. Ignored for non-GNU compiler. (default: OFF)" enable-logging "Should logging be enabled (default: ON)" enable-heavy-logging "Should heavy debug logging be enabled (default: OFF)" enable-haicrypt-logging "Should logging in haicrypt be enabled (default: OFF)" enable-pktinfo "Should pktinfo reading and using be enabled (POSIX only) (default: OFF)" enable-shared "Should libsrt be built as a shared library (default: ON)" enable-static "Should libsrt be built as a static library (default: ON)" enable-relative-libpath "Should applications contain relative library paths, like ../lib (default: OFF)" enable-getnameinfo "In-logs sockaddr-to-string should do rev-dns (default: OFF)" enable-unittests "Enable Unit Tests (will download Google UT) (default: OFF)" enable-encryption "Should encryption features be enabled (default: ON)" enable-c++-deps "Extra library dependencies in srt.pc for C language (default: ON)" use-static-libstdc++ "Should use static rather than shared libstdc++ (default: OFF)" enable-inet-pton "Set to OFF to prevent usage of inet_pton when building against modern SDKs (default: ON)" enable-code-coverage "Enable code coverage reporting (default: OFF)" enable-monotonic-clock "Enforced clock_gettime with monotonic clock on GC CV /temporary fix for #729/ (default: OFF)" enable-thread-check "Enable #include that implements THREAD_* macros" enable-stdc++-sync "Use standard C++11 chrono/threads instead of pthread wrapper (default: OFF, on Windows: ON)" use-openssl-pc "Use pkg-config to find OpenSSL libraries (default: ON)" openssl-use-static-libs "Link OpenSSL statically (default: OFF)." use-busy-waiting "Enable more accurate sending times at a cost of potentially higher CPU load (default: OFF)" use-gnustl "Get c++ library/headers from the gnustl.pc" enable-sock-cloexec "Enable setting SOCK_CLOEXEC on a socket (default: ON)" enable-show-project-config "Enables use of ShowProjectConfig() in cmake (default: OFF)" enable-new-rcvbuffer "Enables the new receiver buffer implementation (default: ON)" enable-clang-tsa "Enable Clang's Thread-Safety-Analysis (default: OFF)" atomic-use-srt-sync-mutex "Use mutex to implement atomics (alias: --with-atomic=sync-mutex) (default: OFF)" use-enclib "Encryption library to be used: openssl(default), gnutls, mbedtls, botan" enable-debug=<0,1,2> "Enable debug mode (0=disabled, 1=debug, 2=rel-with-debug)" pkg-config-executable= "pkg-config executable" openssl-crypto-library= "OpenSSL: Path to a libcrypto library." openssl-include-dir= "OpenSSL: Path to includes." openssl-ssl-library= "OpenSSL: Path to a libssl library." pthread-include-dir= "PThread: Path to includes" pthread-library= "PThread: Path to the pthread library." } set options $internal_options$cmake_options # Just example. Available in the system. set alias { --prefix --cmake-install-prefix= } proc pkg-config args { return [string trim [exec pkg-config {*}$args]] } proc flagval v { set out "" foreach o $v { lappend out [string trim [string range $o 2 en]] } return $out } set haicrypt_name "" set srt_name "" proc preprocess {} { # Prepare windows basic path info set ::CYGWIN 0 set e [catch {exec uname -o} res] # We have Cygwin, if uname -o returns "cygwin" and does not fail. if { !$e && $res == "Cygwin" } { set ::CYGWIN 1 puts "CYGWIN DETECTED" } set ::HAVE_LINUX [expr {$::tcl_platform(os) == "Linux"}] set ::HAVE_DARWIN [expr {$::tcl_platform(os) == "Darwin"}] set ::CYGWIN_USE_POSIX 0 if { "--cygwin-use-posix" in $::optkeys } { set ::CYGWIN_USE_POSIX 1 } set ::HAVE_WINDOWS 0 if { $::tcl_platform(platform) == "windows" } { puts "WINDOWS PLATFORM detected" set ::HAVE_WINDOWS 1 } if { $::CYGWIN && !$::CYGWIN_USE_POSIX } { puts "CYGWIN - MINGW enforced" # Make Cygwin tools see it right, to compile for MinGW if { "--with-compiler-prefix" ni $::optkeys } { set ::optval(--with-compiler-prefix) /bin/x86_64-w64-mingw32- } # Extract drive C: information set drive_path [exec mount -p | tail -1 | cut {-d } -f 1] set ::DRIVE_C $drive_path/c set ::HAVE_WINDOWS 1 } else { # Don't check for Windows, non-Windows parts will not use it. set ::DRIVE_C C: } # Alias to old name --with-gnutls, which enforces using gnutls instead of openssl if { [info exists ::optval(--with-gnutls)] } { unset ::optval(--with-gnutls) set ::optval(--use-enclib) gnutls puts "WARNING: --with-gnutls is a deprecated alias to --use-enclib=gnutls, please use the latter one" } # Alias to old name --use-gnutls, which enforces using gnutls instead of openssl if { [info exists ::optval(--use-gnutls)] } { unset ::optval(--use-gnutls) set ::optval(--use-enclib) gnutls puts "WARNING: --use-gnutls is a deprecated alias to --use-enclib=gnutls, please use the latter one" } if { [info exists ::optval(--with-target-path)] } { set ::target_path $::optval(--with-target-path) unset ::optval(--with-target-path) puts "NOTE: Explicit target path: $::target_path" } if { "--with-srt-name" in $::optkeys } { set ::srt_name $::optval(--with-srt-name) unset ::optval(--with-srt-name) } if { "--with-haicrypt-name" in $::optkeys } { set ::haicrypt_name $::optval(--with-haicrypt-name) unset ::optval(--with-haicrypt-name) } if { "--with-atomic" in $::optkeys } { switch -- $::optval(--with-atomic) { compiler-intrinsics { } sync-mutex { set ::optval(--atomic-use-srt-sync-mutex) 1 } default { puts "ERROR: --with-atomic option accepts two values: compiler-intrinsics (default) or sync-mutex" exit 1 } } unset ::optval(--with-atomic) } } # Added also the Intel compiler names, just in case. set compiler_map { cc c++ gcc g++ icc icpc icx icpx } proc SplitCompilerVersionSuffix {cmd} { # If there's no version suffix, return just $cmd. # Otherwise return a list with cmd cut and version suffix set parts [split $cmd -] if {[llength $parts] == 1} { return $cmd } set last [lindex $parts end] if {![regexp {[0-9]+.*} $last]} { return $cmd } # Got the version if {[llength $parts] == 2} { set first [lindex $parts 0] } else { set first [join [lrange $parts 0 end-1] -] } return [list $first -$last] } # This uses 'compiler' in the form of the C compiler # command line. For C++ it returns the C++ command line, # which is normally the C compiler command with ++. proc GetCompilerCmdName {compiler lang} { lassign [SplitCompilerVersionSuffix $compiler] compiler suffix if {$lang == "c++"} { if { [dict exists $::compiler_map $compiler] } { return [dict get $::compiler_map $compiler]$suffix } return ${compiler}++${suffix} } return $compiler${suffix} } proc GetCompilerCommand { {lang {}} } { # Expect that the compiler was set through: # --with-compiler-prefix # --cmake-c[++]-compiler # (cmake-toolchain-file will set things up without the need to check things here) set compiler gcc if { [info exists ::optval(--with-compiler-type)] } { set compiler $::optval(--with-compiler-type) } if { [info exists ::optval(--with-compiler-prefix)] } { set prefix $::optval(--with-compiler-prefix) return ${prefix}[GetCompilerCmdName $compiler $lang] } else { return [GetCompilerCmdName $compiler $lang] } if { $lang != "c++" } { if { [info exists ::optval(--cmake-c-compiler)] } { return $::optval(--cmake-c-compiler) } } if { $lang != "c" } { if { [info exists ::optval(--cmake-c++-compiler)] } { return $::optval(--cmake-c++-compiler) } if { [info exists ::optval(--cmake-cxx-compiler)] } { return $::optval(--cmake-cxx-compiler) } } puts "NOTE: Cannot obtain compiler, assuming toolchain file will do what's necessary" return "" } proc postprocess {} { set iscross 0 # Check if there was any option that changed the toolchain. If so, don't apply any autodetection-based toolchain change. set all_options [array names ::optval] set toolchain_changed no foreach changer { --with-compiler-prefix --with-compiler-type --cmake-c-compiler --cmake-c++-compiler --cmake-cxx-compiler --cmake-toolchain-file } { if { $changer in $all_options } { puts "NOTE: toolchain changed by '$changer' option" set toolchain_changed yes break } } set cygwin_posix 0 if { "--cygwin-use-posix" in $all_options } { # Will enforce OpenSSL autodetection set cygwin_posix 1 } if { $toolchain_changed } { # Check characteristics of the compiler - in particular, whether the target is different # than the current target. set compiler_path "" set target_platform "" set cmd [GetCompilerCommand] if { $cmd != "" } { set gcc_version [exec $cmd -v 2>@1] set target "" set compiler_path [file dirname $cmd] foreach l [split $gcc_version \n] { if { [string match Target:* $l] } { set target [lindex $l 1] ;# [0]Target: [1]x86_64-some-things-further set target_platform [lindex [split $target -] 0] ;# [0]x86_64 [1]redhat [2]linux break } } if { $target_platform == "" } { puts "NOTE: can't obtain target from '[file tail $cmd] -v': $l - ASSUMING HOST compiler" } else { if { $target_platform != $::tcl_platform(machine) } { puts "NOTE: foreign target type detected ($target)" ;# - setting CROSSCOMPILING flag" #lappend ::cmakeopt "-DHAVE_CROSSCOMPILER=1" set iscross 1 } } } else { puts "CONFIGURE: default compiler used" } # Complete the variables before calling cmake, otherwise it might not work if { [info exists ::optval(--with-compiler-type)] } { if { ![info exists ::optval(--cmake-c-compiler)] } { lappend ::cmakeopt "-DCMAKE_C_COMPILER=[GetCompilerCommand c]" } if { ![info exists ::optval(--cmake-c++-compiler)] } { lappend ::cmakeopt "-DCMAKE_CXX_COMPILER=[GetCompilerCommand c++]" } } } if { $::srt_name != "" } { lappend ::cmakeopt "-DTARGET_srt=$::srt_name" } if { $::haicrypt_name != "" } { lappend ::cmakeopt "-DTARGET_haicrypt=$::haicrypt_name" } set have_openssl 0 if { [lsearch -glob $::optkeys --openssl*] != -1 } { set have_openssl 1 } set have_gnutls 0 if { [lsearch -glob $::optkeys --use-gnutls] != -1 } { set have_gnutls 1 } if { $have_openssl && $have_gnutls } { puts "NOTE: SSL library is exclusively selectable. Thus, --use-gnutls option will be ignored" set have_gnutls 0 } if { $have_gnutls } { lappend ::cmakeopt "-DUSE_GNUTLS=ON" } if {$iscross} { proc check-target-path {path} { puts "Checking path '$path'" if { [file isdir $path] && [file isdir $path/bin] && [file isdir $path/include] && ([file isdir $path/lib] || [file isdir $path/lib64]) } { return yes } return no } if { ![info exists ::target_path] } { # Try to autodetect the target path by having the basic 3 directories. set target_path "" set compiler_prefix [file dirname $compiler_path] ;# strip 'bin' directory puts "NOTE: no --with-target-path found, will try to autodetect at $compiler_path" foreach path [list $compiler_path $compiler_prefix/$target] { if { [check-target-path $path] } { set target_path $path puts "NOTE: target path detected: $target_path" break } } if { $target_path == "" } { puts "ERROR: Can't determine compiler's platform files root path (using compiler command path). Specify --with-target-path." exit 1 } } else { set target_path $::target_path # Still, check if correct. if { ![check-target-path $target_path] } { puts "ERROR: path in --with-target-path does not contain typical subdirectories" exit 1 } puts "NOTE: Using explicit target path: $target_path" } # Add this for cmake, should it need for something lappend ::cmakeopt "-DCMAKE_PREFIX_PATH=$target_path" # Add explicitly the path for pkg-config # which lib if { [file isdir $target_path/lib64/pkgconfig] } { set ::env(PKG_CONFIG_PATH) $target_path/lib64/pkgconfig puts "PKG_CONFIG_PATH: Found pkgconfig in lib64 for '$target_path' - using it" } elseif { [file isdir $target_path/lib/pkgconfig] } { set ::env(PKG_CONFIG_PATH) $target_path/lib/pkgconfig puts "PKG_CONFIG_PATH: Found pkgconfig in lib for '$target_path' - using it" } else { puts "PKG_CONFIG_PATH: NOT changed, no pkgconfig in '$target_path'" } # Otherwise don't set PKG_CONFIG_PATH and we'll see. } set use_brew 0 if { $::HAVE_DARWIN && !$toolchain_changed } { set use_brew 1 } if { [info exists ::optval(--use-enclib)] && $::optval(--use-enclib) == "botan"} { set use_brew 0 } if { $use_brew } { foreach item $::cmakeopt { if { [string first "Android" $item] != -1 } { set use_brew 0 break } } } if { $use_brew } { if { $have_gnutls } { # Use gnutls explicitly, as found in brew set er [catch {exec brew info gnutls} res] if { $er } { error "Cannot find gnutls in brew" } } else { # ON Darwin there's a problem with linking against the Mac-provided OpenSSL. # This must use brew-provided OpenSSL. # if { !$have_openssl } { set er [catch {exec brew info openssl} res] if { $er } { error "You must have OpenSSL installed from 'brew' tool. The standard Mac version is inappropriate." } lappend ::cmakeopt "-DOPENSSL_INCLUDE_DIR=/usr/local/opt/openssl/include" lappend ::cmakeopt "-DOPENSSL_LIBRARIES=/usr/local/opt/openssl/lib/libcrypto.a" } } } } srt-1.5.4/docs/000077500000000000000000000000001471311275400132665ustar00rootroot00000000000000srt-1.5.4/docs/API/000077500000000000000000000000001471311275400136775ustar00rootroot00000000000000srt-1.5.4/docs/API/API-functions.md000066400000000000000000005552541471311275400166600ustar00rootroot00000000000000# SRT API Functions

Library Initialization

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_startup](#srt_startup) | Called at the start of an application that uses the SRT library | | [srt_cleanup](#srt_cleanup) | Cleans up global SRT resources before exiting an application | | | |

Creating and Configuring Sockets

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_socket](#srt_socket) | Deprecated | | [srt_create_socket](#srt_create_socket) | Creates an SRT socket | | [srt_bind](#srt_bind) | Binds a socket to a local address and port | | [srt_bind_acquire](#srt_bind_acquire) | Acquires a given UDP socket instead of creating one | | [srt_getsockstate](#srt_getsockstate) | Gets the current status of the socket | | [srt_getsndbuffer](#srt_getsndbuffer) | Retrieves information about the sender buffer | | [srt_close](#srt_close) | Closes the socket or group and frees all used resources | | | |

Connecting

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_listen](#srt_listen) | Sets up the listening state on a socket | | [srt_accept](#srt_accept) | Accepts a connection; creates/returns a new socket or group ID | | [srt_accept_bond](#srt_accept_bond) | Accepts a connection pending on any sockets passed in the `listeners` array
of `nlisteners` size | | [srt_listen_callback](#srt_listen_callback) | Installs/executes a callback hook on a socket created to handle the incoming connection
on a listening socket | | [srt_connect](#srt_connect) | Connects a socket or a group to a remote party with a specified address and port | | [srt_connect_bind](#srt_connect_bind) | Same as [`srt_bind`](#srt_bind) then [`srt_connect`](#srt_connect) if called with socket [`u`](#u) | | [srt_connect_debug](#srt_connect_debug) | Same as [`srt_connect`](#srt_connect)but allows specifying ISN (developers only) | | [srt_rendezvous](#srt_rendezvous) | Performs a rendezvous connection | | [srt_connect_callback](#srt_connect_callback) | Installs/executes a callback hook on socket/group [`u`](#u) after connection resolution/failure | | | |

Socket Group Management

Since SRT v1.5.0. | *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [SRT_GROUP_TYPE](#SRT_GROUP_TYPE) | Group types collected in an [`SRT_GROUP_TYPE`](#SRT_GROUP_TYPE) enum | | [SRT_SOCKGROUPCONFIG](#SRT_SOCKGROUPCONFIG) | Structure used to define entry points for connections for [`srt_connect_group`](#srt_connect_group) | | [SRT_SOCKGROUPDATA](#SRT_SOCKGROUPDATA) | Most important structure for group member status | | [SRT_MEMBERSTATUS](#SRT_MEMBERSTATUS) | Enumeration type that defines the state of a member connection in the group | | [srt_create_group](#srt_create_group) | Creates a new group of type `type` | | [srt_groupof](#srt_groupof) | Returns the group ID of a socket, or `SRT_INVALID_SOCK` | | [srt_group_data](#srt_group_data) | Obtains the current member state of the group specified in `socketgroup` | | [srt_connect_group](#srt_connect_group) | Similar to calling [`srt_connect`](#srt_connect) or [`srt_connect_bind`](#srt_connect_bind)
in a loop for every item in an array. | | [srt_prepare_endpoint](#srt_prepare_endpoint) | Prepares a default [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG) object as an element of
an array for [`srt_connect_group`](#srt_connect_group) | | [srt_create_config](#srt_create_config) | Creates a dynamic object for specifying socket options | | [srt_delete_config](#srt_delete_config) | Deletes the configuration object | | [srt_config_add](#srt_config_add) | Adds a configuration option to the configuration object | | | |

Options and Properties

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_getpeername](#srt_getpeername) | Retrieves the remote address to which the socket is connected | | [srt_getsockname](#srt_getsockname) | Extracts the address to which the socket was bound | | [srt_getsockopt](#srt_getsockopt) | Gets the value of the given socket option (from a socket or a group) | | [srt_getsockflag](#srt_getsockflag) | Gets the value of the given socket option (from a socket or a group) | | [srt_setsockopt](#srt_setsockopt) | Sets a value for a socket option in the socket or group | | [srt_setsockflag](#srt_setsockflag) | Sets a value for a socket option in the socket or group | | [srt_getversion](#srt_getversion) | Get SRT version value | | | |

Helper Data Types for Transmission

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [SRT_MSGCTRL](#SRT_MSGCTRL) | Used in [`srt_sendmsg2`](#srt_sendmsg) and [`srt_recvmsg2`](#srt_recvmsg2) calls;
specifies some extra parameters | | | |

Transmission

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_send](#srt_send) | Sends a payload to a remote party over a given socket | | [srt_sendmsg](#srt_sendmsg) | Sends a payload to a remote party over a given socket | | [srt_sendmsg2](#srt_sendmsg2) | Sends a payload to a remote party over a given socket | | [srt_recv](#srt_recv) | Extracts the payload waiting to be received | | [srt_recvmsg](#srt_recvmsg) | Extracts the payload waiting to be received | | [srt_recvmsg2](#srt_recvmsg2) | Extracts the payload waiting to be received | | [srt_sendfile](#srt_sendfile) | Function dedicated to sending a file | | [srt_recvfile](#srt_recvfile) | Function dedicated to receiving a file | | | |

Performance Tracking

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_bstats](#srt_bstats) | Reports the current statistics | | [srt_bistats](#srt_bistats) | Reports the current statistics | | | |

Asynchronous Operations (Epoll)

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_epoll_create](#srt_epoll_create) | Creates a new epoll container | | [srt_epoll_add_usock](#srt_epoll_add_usock) | Adds a user socket to a container, or updates an existing socket subscription | | [srt_epoll_add_ssock](#srt_epoll_add_ssock) | Adds a system socket to a container, or updates an existing socket subscription | | [srt_epoll_update_usock](#srt_epoll_update_usock) | Adds a user socket to a container, or updates an existing socket subscription | | [srt_epoll_update_ssock](#srt_epoll_update_ssock) | Adds a system socket to a container, or updates an existing socket subscription | | [srt_epoll_remove_usock](#srt_epoll_remove_usock) | Removes a specified user socket from an epoll container; clears all readiness states for that socket | | [srt_epoll_remove_ssock](#srt_epoll_remove_ssock) | Removes a specified system socket from an epoll container; clears all readiness states for that socket | | [srt_epoll_wait](#srt_epoll_wait) | Blocks the call until any readiness state occurs in the epoll container | | [srt_epoll_uwait](#srt_epoll_uwait) | Blocks a call until any readiness state occurs in the epoll container | | [srt_epoll_clear_usocks](#srt_epoll_clear_usocks) | removes all SRT ("user") socket subscriptions from the epoll container identified by [`eid`](#eid) | | [srt_epoll_set](#srt_epoll_set) | Allows setting or retrieving flags that change the default behavior of the epoll functions | | [srt_epoll_release](#srt_epoll_release) | Deletes the epoll container | | | |

Logging Control

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_setloglevel](#srt_setloglevel) | Sets the minimum severity for logging | | [srt_addlogfa](#srt_addlogfa) | Add a functional area (FA), which is an additional filtering mechanism for logging | | [srt_dellogfa](#srt_dellogfa) | Delete a functional area (FA), which is an additional filtering mechanism for logging | | [srt_resetlogfa](#srt_resetlogfa) | Reset a functional area (FA), which is an additional filtering mechanism for logging | | [srt_setloghandler](#srt_setloghandler) | Replaces default standard stream for error logging | | [srt_setlogflags](#srt_setlogflags) | Allows configuring parts of log information that are not to be passed | | | |

Time Access

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_time_now](#srt_time_now) | Get time in microseconds elapsed since epoch using SRT internal clock
(steady or monotonic clock) | | [srt_connection_time](#srt_connection_time) | Get connection time in microseconds elapsed since epoch using SRT internal clock
(steady or monotonic clock) | | [srt_clock_type](#srt_clock_type) | Get the type of clock used internally by SRT | | | |

Diagnostics

| *Function / Structure* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | | [srt_getlasterror](#srt_getlasterror) | Get the numeric code of the last error | | [srt_strerror](#srt_strerror) | Returns a string message that represents a given SRT error code and possibly
the `errno` value, if not 0 | | [srt_getlasterror_str](#srt_getlasterror_str) | Gets the text message for the last error | | [srt_clearlasterror](#srt_clearlasterror) | Clears the last error | | [srt_rejectreason_str](#srt_rejectreason_str) | Returns a constant string for the reason of the connection rejected, as per given code ID | | [srt_setrejectreason](#srt_setrejectreason) | Sets the rejection code on the socket | | [srt_getrejectreason](#srt_getrejectreason) | Provides a detailed reason for a failed connection attempt | | | |

Rejection Reasons

| *Rejection Reason* | *Since* | *Description* | |:-------------------------------------------- |:--------- |:-------------------------------------------------------------------------------------------------------------- | | [SRT_REJ_UNKNOWN](#SRT_REJ_UNKNOWN) | 1.3.4 | A fallback value for cases when there was no connection rejected | | [SRT_REJ_SYSTEM](#SRT_REJ_SYSTEM) | 1.3.4 | A system function reported a failure | | [SRT_REJ_PEER](#SRT_REJ_PEER) | 1.3.4 | The connection has been rejected by peer, but no further details are available | | [SRT_REJ_RESOURCE](#SRT_REJ_RESOURCE) | 1.3.4 | A problem with resource allocation (usually memory) | | [SRT_REJ_ROGUE](#SRT_REJ_ROGUE) | 1.3.4 | The data sent by one party to another cannot be properly interpreted | | [SRT_REJ_BACKLOG](#SRT_REJ_BACKLOG) | 1.3.4 | The listener's backlog has exceeded | | [SRT_REJ_IPE](#SRT_REJ_IPE) | 1.3.4 | Internal Program Error | | [SRT_REJ_CLOSE](#SRT_REJ_CLOSE) | 1.3.4 | The listener socket received a request as it is being closed | | [SRT_REJ_VERSION](#SRT_REJ_VERSION) | 1.3.4 | A party did not satisfy the minimum version requirement that had been set up for a connection | | [SRT_REJ_RDVCOOKIE](#SRT_REJ_RDVCOOKIE) | 1.3.4 | Rendezvous cookie collision | | [SRT_REJ_BADSECRET](#SRT_REJ_BADSECRET) | 1.3.4 | Both parties have defined a passphrase for connection and they differ | | [SRT_REJ_UNSECURE](#SRT_REJ_UNSECURE) | 1.3.4 | Only one connection party has set up a password | | [SRT_REJ_MESSAGEAPI](#SRT_REJ_MESSAGEAPI) | 1.3.4 | The value for [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag is different on both connection parties | | [SRT_REJ_FILTER](#SRT_REJ_FILTER) | 1.3.4 | The [`SRTO_PACKETFILTER`](API-socket-options.md#SRTO_PACKETFILTER) option has been set differently on both connection parties | | [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.5.2 | The connection was rejected due to an unsupported or mismatching encryption mode | | | | | See the full list in [Rejection Reason Codes](./rejection-codes.md).

Error Codes

| *Error Code* | *Description* | |:------------------------------------------------- |:-------------------------------------------------------------------------------------------------------------- | [`SRT_EUNKNOWN`](#srt_eunknown) | Internal error when setting the right error code | [`SRT_SUCCESS`](#srt_success) | The value set when the last error was cleared and no error has occurred since then | [`SRT_ECONNSETUP`](#srt_econnsetup) | General setup error resulting from internal system state | [`SRT_ENOSERVER`](#srt_enoserver) | Connection timed out while attempting to connect to the remote address | [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected | [`SRT_ESOCKFAIL`](#srt_esockfail) | An error occurred when trying to call a system function on an internally used UDP socket | [`SRT_ESECFAIL`](#srt_esecfail) | A possible tampering with the handshake packets was detected, or encryption request
wasn't properly fulfilled. | [`SRT_ESCLOSED`](#srt_esclosed) | A socket that was vital for an operation called in blocking mode has been closed
during the operation | [`SRT_ECONNFAIL`](#srt_econnfail) | General connection failure of unknown details | [`SRT_ECONNLOST`](#srt_econnlost) | The socket was properly connected, but the connection has been broken | [`SRT_ENOCONN`](#srt_enoconn) | The socket is not connected | [`SRT_ERESOURCE`](#srt_eresource) | System or standard library error reported unexpectedly for unknown purpose | [`SRT_ETHREAD`](#srt_ethread) | System was unable to spawn a new thread when required | [`SRT_ENOBUF`](#srt_enobuf) | System was unable to allocate memory for buffers | [`SRT_ESYSOBJ`](#srt_esysobj) | System was unable to allocate system specific objects | [`SRT_EFILE`](#srt_efile) | General filesystem error (for functions operating with file transmission) | [`SRT_EINVRDOFF`](#srt_einvrdoff) | Failure when trying to read from a given position in the file | [`SRT_ERDPERM`](#srt_erdperm) | Read permission was denied when trying to read from file | [`SRT_EINVWROFF`](#srt_einvwroff) | Failed to set position in the written file | [`SRT_EWRPERM`](#srt_ewrperm) | Write permission was denied when trying to write to a file | [`SRT_EINVOP`](#srt_einvop) | Invalid operation performed for the current state of a socket | [`SRT_EBOUNDSOCK`](#srt_eboundsock) | The socket is currently bound and the required operation cannot be performed in this state | [`SRT_ECONNSOCK`](#srt_econnsock) | The socket is currently connected and therefore performing the required operation is not possible | [`SRT_EINVPARAM`](#srt_einvparam) | Call parameters for API functions have some requirements that were not satisfied | [`SRT_EINVSOCK`](#srt_einvsock) | The API function required an ID of an entity (socket or group) and it was invalid | [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) | The operation to be performed on a socket requires that it first be explicitly bound | [`SRT_ENOLISTEN`](#srt_enolisten) | The socket passed for the operation is required to be in the listen state | [`SRT_ERDVNOSERV`](#srt_erdvnoserv) | The required operation cannot be performed when the socket is set to rendezvous mode | [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | An attempt was made to connect to a socket set to rendezvous mode that was not first bound | [`SRT_EINVALMSGAPI`](#srt_einvalmsgapi) | The function was used incorrectly in the message API | [`SRT_EINVALBUFFERAPI`](#srt_einvalbufferapi) | The function was used incorrectly in the stream (buffer) API | [`SRT_EDUPLISTEN`](#srt_eduplisten) | The port tried to be bound for listening is already busy | [`SRT_ELARGEMSG`](#srt_elargemsg) | Size exceeded | [`SRT_EINVPOLLID`](#srt_einvpollid) | The epoll ID passed to an epoll function is invalid | [`SRT_EPOLLEMPTY`](#srt_epollempty) | The epoll container currently has no subscribed sockets | [`SRT_EASYNCFAIL`](#srt_easyncfail) | General asynchronous failure (not in use currently) | [`SRT_EASYNCSND`](#srt_easyncsnd) | Sending operation is not ready to perform | [`SRT_EASYNCRCV`](#srt_easyncrcv) | Receiving operation is not ready to perform | [`SRT_ETIMEOUT`](#srt_etimeout) | The operation timed out | [`SRT_ECONGEST`](#srt_econgest) | With [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) and [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP) set to true,
some packets were dropped by sender | [`SRT_EPEERERR`](#srt_epeererr) | Receiver peer is writing to a file that the agent is sending | | | | ## Library Initialization * [srt_startup](#srt_startup) * [srt_cleanup](#srt_cleanup) ### srt_startup ``` int srt_startup(void); ``` This function shall be called at the start of an application that uses the SRT library. It provides all necessary platform-specific initializations, sets up global data, and starts the SRT GC thread. If this function isn't explicitly called, it will be called automatically when creating the first socket. However, relying on this behavior is strongly discouraged. | Returns | | |:----------------------------- |:--------------------------------------------------------------- | | 0 | Successfully run, or already started | | 1 | This is the first startup, but the GC thread is already running | | -1 | Failed | | | | | Errors | | |:----------------------------- |:--------------------------------------------------------------- | | [`SRT_ECONNSETUP`](#srt_econnsetup) | With error code set, reported when required system resource(s) failed to initialize.
This is currently used only on Windows to report a failure from `WSAStartup`. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_cleanup ``` int srt_cleanup(void); ``` This function cleans up all global SRT resources and shall be called just before exiting the application that uses the SRT library. This cleanup function will still be called from the C++ global destructor, if not called by the application, although relying on this behavior is strongly discouraged. | Returns | | |:----------------------------- |:--------------------------------------------------------------- | | 0 | A possibility to return other values is reserved for future use | | | | **IMPORTANT**: Note that the startup/cleanup calls have an instance counter. This means that if you call [`srt_startup`](#srt_startup) multiple times, you need to call the `srt_cleanup` function exactly the same number of times. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Creating and Configuring Sockets * [srt_socket](#srt_socket) * [srt_create_socket](#srt_create_socket) * [srt_bind](#srt_bind) * [srt_bind_acquire](#srt_bind_acquire) * [srt_getsockstate](#srt_getsockstate) * [srt_getsndbuffer](#srt_getsndbuffer) * [srt_close](#srt_close) ### srt_socket ``` SRTSOCKET srt_socket(int af, int type, int protocol); ``` Old and deprecated version of [`srt_create_socket`](#srt_create_socket). All arguments are ignored. **NOTE** changes with respect to UDT version: * In UDT (and SRT versions before 1.4.2) the `af` parameter was specifying the socket family (`AF_INET` or `AF_INET6`). This is now not required; this parameter is decided at the call of [`srt_connect`](#srt_connect) or [`srt_bind`](#srt_bind). * In UDT the `type` parameter was used to specify the file or message mode using `SOCK_STREAM` or `SOCK_DGRAM` symbols (with the latter being misleading, as the message mode has nothing to do with UDP datagrams and it's rather similar to the SCTP protocol). In SRT these two modes are available by setting [`SRTO_TRANSTYPE`](API-socket-options.md#SRTO_TRANSTYPE). The default is `SRTT_LIVE`. If, however, you set [`SRTO_TRANSTYPE`](API-socket-options.md#SRTO_TRANSTYPE) to `SRTT_FILE` for file mode, you can then leave the [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) option as false (default), which corresponds to "stream" mode (TCP-like), or set it to true, which corresponds to "message" mode (SCTP-like). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_create_socket ``` SRTSOCKET srt_create_socket(); ``` Creates an SRT socket. Note that socket IDs always have the `SRTGROUP_MASK` bit clear. | Returns | | |:----------------------------- |:------------------------------------------------------- | | Socket ID | A valid socket ID on success | | `SRT_INVALID_SOCK` | (`-1`) on error | | | | | Errors | | |:----------------------------- |:------------------------------------------------------------ | | [`SRT_ENOBUF`](#srt_enobuf) | Not enough memory to allocate required resources . | | | | **NOTE:** This is probably a design flaw (:warning:   **BUG?**). Usually underlying system errors are reported by [`SRT_ECONNSETUP`](#srt_econnsetup). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_bind ``` int srt_bind(SRTSOCKET u, const struct sockaddr* name, int namelen); ``` Binds a socket to a local address and port. Binding specifies the local network interface and the UDP port number to be used for the socket. When the local address is a wildcard (`INADDR_ANY` for IPv4 or `in6addr_any` for IPv6), then it's bound to all interfaces. **IMPORTANT**: When you bind an IPv6 wildcard address, note that the `SRTO_IPV6ONLY` option must be set on the socket explicitly to 1 or 0 prior to calling this function. See [`SRTO_IPV6ONLY`](API-socket-options.md#SRTO_IPV6ONLY) for more details. Binding is necessary for every socket to be used for communication. If the socket is to be used to initiate a connection to a listener socket, which can be done, for example, by the [`srt_connect`](#srt_connect) function, the socket is bound implicitly to the wildcard address according to the IP family (`INADDR_ANY` for `AF_INET` or `in6addr_any` for `AF_INET6`) and port number 0. In all other cases, a socket must be bound explicitly by using the functionality of this function first. When the port number parameter is 0, then the effective port number will be system-allocated. To obtain this effective port number you can use [`srt_getsockname`](#srt_getsockname). This call is obligatory for a listening socket before calling [`srt_listen`](#srt_listen) and for rendezvous mode before calling [`srt_connect`](#srt_connect); otherwise it's optional. For a listening socket it defines the network interface and the port where the listener should expect a call request. In the case of rendezvous mode there are two parties that connect to one another. For every party there must be chosen a local binding endpoint (local address and port) to which they expect connection from the peer. Let's say, we have a Party 1 that selects an endpoint A and a Party 2 that selects an endpoint B. In this case the Party 1 binds the socket to the endpoint A and then connects to the endpoint B, and the Party 2 the other way around. Both sockets must be set [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) to *true* to make this connection possible. For a connecting socket the call to `srt_bind` is optional, but can be used to set up the outgoing port for communication as well as the local interface through which it should reach out to the remote endpoint, should that be necessary. Whether binding is possible depends on some runtime conditions, in particular: * No socket in the system has been bound to this port ("free binding"), or * A socket bound to this port is bound to a certain address, and this binding is using a different non-wildcard address ("side binding"), or * A socket bound to this port is bound to a wildcard address for a different IP version than the version requested for this binding ("side wildcard binding", see also `SRTO_IPV6ONLY` socket option). It is also possible to bind to the already busy port as long as the existing binding ("shared binding") is possessed by an SRT socket created in the same application, and: * Its binding address and UDP-related socket options match the socket to be bound. * Its [`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS) is set to *true* (default). If none of the free, side and shared binding options is currently possible, this function will fail. If the socket blocking the requested endpoint is an SRT socket in the current application, it will report the `SRT_EBINDCONFLICT` error, while if it was another socket in the system, or the problem was in the system in general, it will report `SRT_ESOCKFAIL`. Here is the table that shows possible situations: | Requested binding | vs. Existing bindings... | | | | | |---------------------|------------------------------|-----------|-----------------------------|---------------|---------------| | | A.B.C.D | 0.0.0.0 | ::X | :: / V6ONLY=1 | :: / V6ONLY=0 | | 1.2.3.4 | 1.2.3.4 shareable, else free | blocked | free | free | blocked | | 0.0.0.0 | blocked | shareable | free | free | blocked | | 8080::1 | free | free | 8080::1 sharable, else free | blocked | blocked | | :: / V6ONLY=1 | free | free | blocked | sharable | blocked | | :: / V6ONLY=0 | blocked | blocked | blocked | blocked | sharable | Where: * free: This binding can coexist with the requested binding. * blocked: This binding conflicts with the requested binding. * shareable: This binding can be shared with the requested binding if it's compatible. * (ADDRESS) shareable, else free: this binding is shareable if the existing binding address is equal to the requested ADDRESS. Otherwise it's free. If the binding is shareable, then the operation will succeed if the socket that currently occupies the binding has the `SRTO_REUSEADDR` option set to true (default) and all UDP settings are the same as in the current socket. Otherwise it will fail. Shared binding means sharing the underlying UDP socket and communication queues between SRT sockets. If all existing bindings on the same port are "free" then the requested binding will allocate a distinct UDP socket for this SRT socket ("side binding"). **NOTE**: This function cannot be called on a socket group. If you need to have the group-member socket bound to the specified source address before connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose or set the appropriate source address using [`srt_prepare_endpoint`](#srt_prepare_endpoint). **IMPORTANT information about IPv6**: If you are going to bind to the `in6addr_any` IPv6 wildcard address (known as `::`), the `SRTO_IPV6ONLY` option must be first set explicitly to 0 or 1, otherwise the binding will fail. In all other cases this option is meaningless. See `SRTO_IPV6ONLY` option for more information. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) on error, otherwise 0 | | | | | Errors | | |:---------------------------------------- |:-------------------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket | | [`SRT_EINVOP`](#srt_einvop) | Socket already bound | | [`SRT_EINVPARAM`](#srt_einvparam) | Invalid `name`/`namelen` or invalid `SRTO_IPV6ONLY` flag in `u` | | [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed | | [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed | | [`SRT_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_bind_acquire ``` int srt_bind_acquire(SRTSOCKET u, UDPSOCKET udpsock); ``` A version of [`srt_bind`](#srt_bind) that acquires a given UDP socket instead of creating one. The UDP socket being acquired MUST NOT be a [connected socket](https://man7.org/linux/man-pages/man2/connect.2.html) (not associated with the socket name of a peer), because SRT needs to be able to set the destination address by itself. See [#2178](https://github.com/Haivision/srt/issues/2178) for more information. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getsockstate ``` SRT_SOCKSTATUS srt_getsockstate(SRTSOCKET u); ``` Gets the current status of the socket. Possible states are: | State | Description | |:----------------------------------------------- |:----------------------------------------------------------------- | | `SRTS_INIT` | Created, but not bound. | | `SRTS_OPENED` | Created and bound, but not in use yet. | | `SRTS_LISTENING` | Socket is in listening state. | | `SRTS_CONNECTING` | The connect operation was initiated, but not yet finished. This may also mean that it has timed out;
you can only know that after getting a socket error report from [`srt_epoll_wait`](#srt_epoll_wait). In blocking mode
it's not possible because [`srt_connect`](#srt_connect) does not return until the socket is connected or failed due
to timeout or interrupted call. | | `SRTS_CONNECTED` | The socket is connected and ready for transmission. | | `SRTS_BROKEN` | The socket was connected, but the connection was broken. | | `SRTS_CLOSING` | The socket may still be open and active, but closing is requested, so no further operations will
be accepted (active operations will be completed before closing) | | `SRTS_CLOSED` | The socket has been closed, but not yet removed by the GC thread. | | `SRTS_NONEXIST` | The specified number does not correspond to a valid socket. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getsndbuffer ``` int srt_getsndbuffer(SRTSOCKET sock, size_t* blocks, size_t* bytes); ``` Retrieves information about the sender buffer. **Arguments**: * `sock`: Socket to test * `blocks`: Written information about buffer blocks in use * `bytes`: Written information about bytes in use This function can be used for diagnostics. It is especially useful when the socket needs to be closed asynchronously. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_close ``` int srt_close(SRTSOCKET u); ``` Closes the socket or group and frees all used resources. Note that underlying UDP sockets may be shared between sockets, so these are freed only with the last user closed. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:------------------------------- |:----------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Connecting * [srt_listen](#srt_listen) * [srt_accept](#srt_accept) * [srt_accept_bond](#srt_accept_bond) * [srt_listen_callback](#srt_listen_callback) * [srt_connect](#srt_connect) * [srt_connect_bind](#srt_connect_bind) * [srt_connect_debug](#srt_connect_debug) * [srt_rendezvous](#srt_rendezvous) * [srt_connect_callback](#srt_connect_callback) ### srt_listen ``` int srt_listen(SRTSOCKET u, int backlog); ``` This sets up the listening state on a socket with a backlog setting that defines how many sockets may be allowed to wait until they are accepted (excessive connection requests are rejected in advance). The following important options may change the behavior of the listener socket and the [`srt_accept`](#srt_accept) function: * [`srt_listen_callback`](#srt_listen_callback) installs a user function that will be called before [`srt_accept`](#srt_accept) can happen * [`SRTO_GROUPCONNECT`](API-socket-options.md#SRTO_GROUPCONNECT) option allows the listener socket to accept group connections | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0. | | | | | Errors | | |:--------------------------------------- |:-------------------------------------------------------------------------------------------- | | [`SRT_EINVPARAM`](#srt_einvparam) | Value of `backlog` is 0 or negative. | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid SRT socket. | | [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) | [`srt_bind`](#srt_bind) has not yet been called on that socket. | | [`SRT_ERDVNOSERV`](#srt_erdvnoserv) | [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) flag is set to true on specified socket. | | [`SRT_EINVOP`](#srt_einvop) | Internal error (should not happen when [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) is reported). | | [`SRT_ECONNSOCK`](#srt_econnsock) | The socket is already connected. | | [`SRT_EDUPLISTEN`](#srt_eduplisten) | The address used in [`srt_bind`](#srt_bind) by this socket is already occupied by another listening socket.
Binding multiple sockets to one IP address and port is allowed, as long as
[`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS) is set to true, but only one of these sockets can be set up as a listener. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_accept ``` SRTSOCKET srt_accept(SRTSOCKET lsn, struct sockaddr* addr, int* addrlen); ``` Accepts a pending connection, then creates and returns a new socket or group ID that handles this connection. The group and socket can be distinguished by checking the `SRTGROUP_MASK` bit on the returned ID. * `lsn`: the listener socket previously configured by [`srt_listen`](#srt_listen) * `addr`: the IP address and port specification for the remote party * `addrlen`: INPUT: size of `addr` pointed object. OUTPUT: real size of the returned object **NOTE:** `addr` is allowed to be NULL, in which case it's understood that the application is not interested in the address from which the connection originated. Otherwise `addr` should specify an object into which the address will be written, and `addrlen` must also specify a variable to contain the object size. Note also that in the case of group connection only the initial connection that establishes the group connection is returned, together with its address. As member connections are added or broken within the group, you can obtain this information through [`srt_group_data`](#srt_group_data) or the data filled by [`srt_sendmsg2`](#srt_sendmsg) and [`srt_recvmsg2`](#srt_recvmsg2). If the `lsn` listener socket is configured for blocking mode ([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) set to true, default), the call will block until the incoming connection is ready. Otherwise, the call always returns immediately. The `SRT_EPOLL_IN` epoll event should be checked on the `lsn` socket prior to calling this function in that case. If the pending connection is a group connection (initiated on the peer side by calling the connection function using a group ID, and permitted on the listener socket by the [`SRTO_GROUPCONNECT`](API-socket-options.md#SRTO_GROUPCONNECT) flag), then the value returned is a group ID. This function then creates a new group, as well as a new socket for this connection, that will be added to the group. Once the group is created this way, further connections within the same group, as well as sockets for them, will be created in the background. The [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) event is raised on the `lsn` socket when a new background connection is attached to the group, although it's usually for internal use only. | Returns | | |:----------------------------- |:----------------------------------------------------------------------- | | socket/group ID | On success, a valid SRT socket or group ID to be used for transmission. | | `SRT_INVALID_SOCK` | (-1) on failure | | | | | Errors | | |:--------------------------------- |:----------------------------------------------------------------------- | | [`SRT_EINVPARAM`](#srt_einvparam) | NULL specified as `addrlen`, when `addr` is not NULL | | [`SRT_EINVSOCK`](#srt_einvsock) | `lsn` designates no valid socket ID. | | [`SRT_ENOLISTEN`](#srt_enolisten) | `lsn` is not set up as a listener ([`srt_listen`](#srt_listen) not called). | | [`SRT_EASYNCRCV`](#srt_easyncrcv) | No connection reported so far. This error is reported only in the non-blocking mode | | [`SRT_ESCLOSED`](#srt_esclosed) | The `lsn` socket has been closed while the function was blocking the call. Including when the socket was closed just at the
moment when a connection was made (i.e., the socket got closed during processing) | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_accept_bond ``` SRTSOCKET srt_accept_bond(const SRTSOCKET listeners[], int nlisteners, int msTimeOut); ``` Accepts a pending connection, like [`srt_accept`](#srt_accept), but pending on any of the listener sockets passed in the `listeners` array of `nlisteners` size. **Arguments**: * `listeners`: array of listener sockets (all must be setup by [`srt_listen`](#srt_listen)) * `nlisteners`: size of the `listeners` array * `msTimeOut`: timeout in [ms] or -1 to block forever This function is for blocking mode only - for non-blocking mode you should simply call [`srt_accept`](#srt_accept) on the first listener socket that reports readiness, and this function is actually a friendly shortcut that uses waiting on epoll and [`srt_accept`](#srt_accept) internally. This function supports an important use case for accepting a group connection, for which every member connection is expected to be established over a different listener socket. Note that there's no special set of settings required or rejected for this function. Group-member connections for the same group can always be established over various different listener sockets when all those listeners are hosted by the same application. The group management is global for the application, so a connection reporting in for an already connected group gets discovered, and the connection will be handled in the background. This occurs regardless of which listener socket the call was made to, as long as the connection is accepted according to any additional conditions. This function has nothing to do with the groups. You can use it in any case when you have one service that accepts connections to multiple endpoints. Note also that the settings as to whether listeners should accept or reject socket or group connections should be applied to the listener sockets appropriately prior to calling this function. | Returns | | |:----------------------------- |:---------------------------------------------------------------------- | | SRT socket
group ID | On success, a valid SRT socket or group ID to be used for transmission | | `SRT_INVALID_SOCK` | (-1) on failure | | | | | Errors | | |:--------------------------------- |:------------------------------------------------------------ | | [`SRT_EINVPARAM`](#srt_einvparam) | NULL specified as `listeners` or `nlisteners` < 1 | | [`SRT_EINVSOCK`](#srt_einvsock) | Any socket in `listeners` designates no valid socket ID. Can also mean *Internal Error* when
an error occurred while creating an accepted socket (:warning:   **BUG?**) | | [`SRT_ENOLISTEN`](#srt_enolisten) | Any socket in `listeners` is not set up as a listener ([`srt_listen`](#srt_listen) not called, or the listener socket
has already been closed) | | [`SRT_ETIMEOUT`](#srt_etimeout) | No connection reported on any listener socket as the timeout has been reached. This error is only
reported when `msTimeOut` is not -1 | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_listen_callback ``` int srt_listen_callback(SRTSOCKET lsn, srt_listen_callback_fn* hook_fn, void* hook_opaque); ``` This call installs a callback hook, which will be executed on a socket that is automatically created to handle the incoming connection on the listening socket (and is about to be returned by [`srt_accept`](#srt_accept)), but before the connection has been accepted. Note the callback must be set before starting listening, i.e. before `srt_listen` is called. **Arguments**: * `lsn`: Listening socket where you want to install the callback hook * `hook_fn`: The callback hook function pointer (or NULL to remove the callback) * `hook_opaque`: The pointer value that will be passed to the callback function | Returns | | |:----------------------------- |:---------------------------------------------------------- | | 0 | Successful | | -1 | Error | | | | | Errors | | |:--------------------------------- |:----------------------------------------- | | [`SRT_ECONNSOCK`](#srt_econnsock) | It can't be modified in a connected socket| | | | The callback function has the signature as per this type definition: ``` typedef int srt_listen_callback_fn(void* opaque, SRTSOCKET ns, int hs_version const struct sockaddr* peeraddr, const char* streamid); ``` The callback function gets the following parameters passed: * `opaque`: The pointer passed as `hook_opaque` when registering * `ns`: The freshly created socket to handle the incoming connection * `hs_version`: The handshake version (usually 5, pre-1.3 versions of SRT use 4) * `peeraddr`: The address of the incoming connection * `streamid`: The value set to [`SRTO_STREAMID`](API-socket-options.md#SRTO_STREAMID) option set on the peer side Note that SRT versions that use handshake version 4 are incapable of using any extensions, such as `streamid`. However they do support encryption. Note also that the SRT version isn't extracted at this point. However you can prevent connections with versions that are too old by using the [`SRTO_MINVERSION`](API-socket-options.md#SRTO_MINVERSION) option. The callback function is given an opportunity to: * use the passed information (`streamid` and peer address) to decide what to do with this connection * alter any options on the socket, which could not be set properly beforehand on the listening socket to be derived by the accepted socket, and won't be allowed to be altered after the socket is returned by [`srt_accept`](#srt_accept) Note that normally the returned socket has already set all derived options from the listener socket. The moment when this callback is called is when the conclusion handshake has been already received from the caller party, but not yet interpreted (the `streamid` field is extracted from it prematurely). When, for example, you set a passphrase on the socket at this point, the Key Material processing will happen against this passphrase, after the callback function is finished. The callback function shall return 0, if the connection is to be accepted. If you return -1, **or** if the function throws an exception, this will be understood as a request to reject the incoming connection. In this case the about-to-be-accepted socket will be silently deleted and [`srt_accept`](#srt_accept) will not report it. Note that in case of non-blocking mode the epoll bits for read-ready on the listener socket will not be set if the connection is rejected, including when rejected from this user function. **IMPORTANT**: This function is called in the receiver worker thread, which means that it must do its checks and operations as quickly as possible. Every delay you create in this function will burden the processing of the incoming data on the associated UDP socket. In the case of a listener socket this means the listener socket itself and every socket accepted off this listener socket. Avoid any extensive search operations. It is best to cache in memory whatever database you have to check against the data received in `streamid` or `peeraddr`. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_connect ``` int srt_connect(SRTSOCKET u, const struct sockaddr* name, int namelen); ``` Connects a socket or a group to a remote party with a specified address and port. **Arguments**: * [`u`](#u): can be an SRT socket or SRT group, both freshly created and not yet used for any connection, except possibly [`srt_bind`](#srt_bind) on the socket * `name`: specification of the remote address and port * `namelen`: size of the object passed by `name` **NOTES:** 1. The socket used here may be [bound by `srt_bind`](#srt_bind) before connecting, or binding and connection can be done in one function ([`srt_connect_bind`](#srt_connect_bind)), such that it uses a predefined network interface or local outgoing port. This is optional in the case of a caller-listener arrangement, but obligatory for a rendezvous arrangement. If not used, the binding will be done automatically to `INADDR_ANY` (which binds on all interfaces) and port 0 (which makes the system assign the port automatically). 2. This function is used for both connecting to the listening peer in a caller-listener arrangement, and calling the peer in rendezvous mode. For the latter, the [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) flag must be set to true prior to calling this function, and binding, as described in #1, is in this case obligatory (see `SRT_ERDVUNBOUND` below). 3. When [`u`](#u) is a group, then this call can be done multiple times, each time for another member connection, and a new member SRT socket will be created automatically for every call of this function. 4. If you want to connect a group to multiple links at once and use blocking mode, you might want to use [`srt_connect_group`](#srt_connect_group) instead. This function also allows you to use additional settings, available only for groups. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error | | 0 | In case when used for [`u`](#u) socket | | Socket ID | Created for connection for [`u`](#u) group | | | | | Errors | | |:------------------------------------- |:----------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | Socket [`u`](#u) is in rendezvous mode, but it wasn't bound (see note #2) | | [`SRT_ECONNSOCK`](#srt_econnsock) | Socket [`u`](#u) is already connected | | [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected | | [`SRT_ENOSERVER`](#srt_enoserver) | Connection has been timed out (see [`SRTO_CONNTIMEO`](API-socket-options.md#SRTO_CONNTIMEO)) | | [`SRT_ESCLOSED`](#srt_esclosed) | The socket [`u`](#u) has been closed while the function was blocking the call | | | | If the `u` socket is configured for blocking mode (when [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) is set to true, default), the call will block until the connection succeeds or fails. The "early" errors [`SRT_EINVSOCK`](#srt_einvsock), [`SRT_ERDVUNBOUND`](#srt_erdvunbound) and [`SRT_ECONNSOCK`](#srt_econnsock) are reported in both modes immediately. Other errors are "late" failures and can only be reported in blocking mode. In non-blocking mode, a successful connection can be recognized by the `SRT_EPOLL_OUT` epoll event flag and a "late" failure by the `SRT_EPOLL_ERR` flag. Note that the socket state in the case of a failed connection remains `SRTS_CONNECTING` in that case. In the case of "late" failures you can additionally call [`srt_getrejectreason`](#srt_getrejectreason) to get detailed error information. Note that in blocking mode only for the `SRT_ECONNREJ` error this function may return any additional information. In non-blocking mode a detailed "late" failure cannot be distinguished, and therefore it can also be obtained from this function. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_connect_bind ``` int srt_connect_bind(SRTSOCKET u, const struct sockaddr* source, const struct sockaddr* target, int len); ``` This function does the same as first [`srt_bind`](#srt_bind) then [`srt_connect`](#srt_connect), if called with [`u`](#u) being a socket. If [`u`](#u) is a group, then it will execute [`srt_bind`](#srt_bind) first on the automatically created socket for the connection. **Arguments**: * [`u`](#u): Socket or group to connect * `source`: Address to bind [`u`](#u) to * `target`: Address to connect * `len`: size of the original structure of `source` and `target` | Returns | | |:----------------------------- |:-------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error | | 0 | In case when used for [`u`](#u) socket | | Socket ID | Created for connection for [`u`](#u) group | | | | | Errors | | |:---------------------------------------- |:-------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket | | [`SRT_EINVOP`](#srt_einvop) | Socket already bound | | [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed | | [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed | | [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | Internal error ([`srt_connect`](#srt_connect) should not report it after [`srt_bind`](#srt_bind) was called) | | [`SRT_ECONNSOCK`](#srt_econnsock) | Socket [`u`](#u) is already connected | | [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected | | [`SRT_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one | | | | **IMPORTANT**: It's not allowed to bind and connect the same socket to two different families (that is, both `source` and `target` must be `AF_INET` or `AF_INET6`), although you may mix links over IPv4 and IPv6 in one group. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_connect_debug ``` int srt_connect_debug(SRTSOCKET u, const struct sockaddr* name, int namelen, int forced_isn); ``` This function is for developers only and can be used for testing. It does the same thing as [`srt_connect`](#srt_connect), with the exception that it allows specifying the Initial Sequence Number for data transmission. Normally this value is generated randomly. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_rendezvous ``` int srt_rendezvous(SRTSOCKET u, const struct sockaddr* local_name, int local_namelen, const struct sockaddr* remote_name, int remote_namelen); ``` Performs a rendezvous connection. This is a shortcut for doing bind locally, setting the [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) option to true, and doing [`srt_connect`](#srt_connect). **Arguments**: * [`u`](#u): socket to connect * `local_name`: specifies the local network interface and port to bind * `remote_name`: specifies the remote party's IP address and port | Returns | | |:----------------------------- |:-------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:------------------------------------- |:-------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket passed as [`u`](#u) designates no valid socket | | [`SRT_EINVOP`](#srt_einvop) | Socket already bound | | [`SRT_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed | | [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed | | [`SRT_ERDVUNBOUND`](#srt_erdvunbound) | Internal error ([`srt_connect`](#srt_connect) should not report it after [`srt_bind`](#srt_bind) was called) | | [`SRT_ECONNSOCK`](#srt_econnsock) | Socket [`u`](#u) is already connected | | [`SRT_ECONNREJ`](#srt_econnrej) | Connection has been rejected | | | | **IMPORTANT**: Establishing a rendezvous connection to two different families is not allowed (that is, both `local_name` and `remote_name` must be `AF_INET` or `AF_INET6`). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_connect_callback ``` int srt_connect_callback(SRTSOCKET u, srt_connect_callback_fn* hook_fn, void* hook_opaque); ``` This call installs a callback hook, which will be executed on a given [`u`](#u) socket or all member sockets of a [`u`](#u) group, just after a pending connection in the background has been resolved and the connection has failed. Note that this function is not guaranteed to be called if the [`u`](#u) socket is set to blocking mode ([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) option set to true). It is guaranteed to be called when a socket is in non-blocking mode, or when you use a group. Note the callback must be set before starting the connection procedure, i.e. before `srt_connect`, `srt_connect_bind`, etc. is called. This function is mainly intended to be used with group connections. Note that even if you use a group connection in blocking mode, after the group is considered connected the member connections still continue in background. Also, when some connections are still pending and others have failed, the blocking call for [`srt_connect_group`](#srt_connect_group) will not exit until at least one of them succeeds or all fail - in such a case those failures also happen only in the background, while the connecting function blocks until all connections are resolved. When all links fail, you will only get a general error code for the group. This mechanism allows you to get individual errors for particular member connection failures. **Arguments**: * [`u`](#u): Socket or group that will be used for connecting and for which the hook is installed * `hook_fn`: The callback hook function pointer (or NULL to remove the callback) * `hook_opaque`: The pointer value that will be passed to the callback function | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Successful | | -1 | Error | | | | | Errors | | |:---------------------------------- |:------------------------------------------| | [`SRT_ECONNSOCK`](#srt_econnsock) | It can't be modified in a connected socket| | | | The callback function signature has the following type definition: ``` typedef void srt_connect_callback_fn(void* opaq, SRTSOCKET ns, int errorcode, const struct sockaddr* peeraddr, int token); ``` **Arguments**: * `opaq`: The pointer passed as `hook_opaque` when registering * `ns`: The socket for which the connection process was resolved * [`errorcode`](#error-codes): The error code, same as for [`srt_connect`](#srt_connect) for blocking mode * `peeraddr`: The target address passed to [`srt_connect`](#srt_connect) call * `token`: The token value, if it was used for group connection, otherwise -1 [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Socket Group Management * [SRT_GROUP_TYPE](#SRT_GROUP_TYPE) * [SRT_SOCKGROUPCONFIG](#SRT_SOCKGROUPCONFIG) * [SRT_SOCKGROUPDATA](#SRT_SOCKGROUPDATA) * [SRT_MEMBERSTATUS](#SRT_MEMBERSTATUS) ### SRT_GROUP_TYPE The following group types are collected in an [`SRT_GROUP_TYPE`](#SRT_GROUP_TYPE) enum: * `SRT_GTYPE_BROADCAST`: broadcast type, all links are actively used at once; * `SRT_GTYPE_BACKUP`: backup type, idle links take over connection on disturbance. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### SRT_SOCKGROUPCONFIG This structure is used to define entry points for connections for the [`srt_connect_group`](#srt_connect_group) function: ``` typedef struct SRT_GroupMemberConfig_ { SRTSOCKET id; struct sockaddr_storage srcaddr; struct sockaddr_storage peeraddr; uint16_t weight; SRT_SOCKOPT_CONFIG* config; int errorcode; int token; } SRT_SOCKGROUPCONFIG; ``` where: * `id`: member socket ID (filled back as output) * `srcaddr`: address to which `id` should be bound * `peeraddr`: address to which `id` should be connected * `weight`: the weight parameter for the link (group-type dependent) * `config`: the configuration object, if used (see [`srt_create_config()`](#srt_create_config)) * [`errorcode`](#error-codes): status of the connecting operation * `token`: An integer value unique for every connection, or -1 if unused The `srt_prepare_endpoint` sets these fields to default values. After that you can change the value of `weight` and `config` and `token` fields. The `weight` parameter's meaning is dependent on the group type: * BROADCAST: not used * BACKUP: positive value of link priority (the greater, the more preferred) In any case, the allowed value for `weight` is between 0 and 32767. The `config` parameter is used to provide options to be set separately on a socket for a particular connection (see [`srt_create_config()`](#srt_create_config)). The `token` value is intended to allow the application to more easily identify a particular connection. If you don't use it and leave the default value of -1, the library will set a unique value for the next connection (a 32-bit unsigned number that will overflow by itself; the default value will be skipped). The application can also set a unique value by itself and keep the same value for the same connection. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### SRT_SOCKGROUPDATA The most important structure for the group member status is [`SRT_SOCKGROUPDATA`](#SRT_SOCKGROUPDATA): ```c++ typedef struct SRT_SocketGroupData_ { SRTSOCKET id; struct sockaddr_storage peeraddr; SRT_SOCKSTATUS sockstate; uint16_t weight; SRT_MEMBERSTATUS memberstate; int result; int token; } SRT_SOCKGROUPDATA; ``` where: * `id`: member socket ID * `peeraddr`: address to which `id` should be connected * `sockstate`: current connection status (see [`srt_getsockstate`](#srt_getsockstate) * `weight`: current weight value set on the link * `memberstate`: current state of the member (see below) * `result`: result of the operation (if this operation recently updated this structure) * `token`: A token value set for that connection (see [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG)) [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### SRT_MEMBERSTATUS The enumeration type that defines the state of a member connection in a group: * `SRT_GST_PENDING`: The connection is in progress, so the socket is not currently being used for transmission, even potentially, and still has a chance to fail and transit into `SRT_GST_BROKEN` without turning into `SRT_GST_IDLE` * `SRT_GST_IDLE`: The connection is established and ready to take over transmission, but it's not used for transmission at the moment. This state may last for a short moment in the case of broadcast group. In backup group this state defines a backup link that is ready to take over when the currently active (running) link becomes unstable. * `SRT_GST_RUNNING`: The connection is established and at least one packet has already been sent or received over it. * `SRT_GST_BROKEN`: The connection was broken. Broken connections are not to be revived. Note also that it is only possible to see this state if it is read by [`srt_sendmsg2`](#srt_sendmsg) or [`srt_recvmsg2`](#srt_recvmsg2) just after the link failure has been detected. Otherwise, the broken link simply disappears from the member list. Note that internally the member state is separate for sending and receiving. If the `memberstate` field of [`SRT_SOCKGROUPDATA`](#SRT_SOCKGROUPDATA) is `SRT_GST_RUNNING`, it means that this is the state in at least one direction, while in the other direction it may be `SRT_GST_IDLE`. In all other cases the states should be the same in both directions. States should normally start with `SRT_GST_PENDING` and then turn into `SRT_GST_IDLE`. Once a new link is used for sending data, the state becomes `SRT_GST_RUNNING`. In the case of the `SRT_GTYPE_BACKUP` type group, if a link is in the `SRT_GST_RUNNING` state, but another link is chosen to remain as the only active one, this link will be "silenced" (its state will become `SRT_GST_IDLE`). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### Functions to Be Used on Groups * [srt_create_group](#srt_create_group) * [srt_groupof](#srt_groupof) * [srt_group_data](#srt_group_data) * [srt_connect_group](#srt_connect_group) * [srt_prepare_endpoint](#srt_prepare_endpoint) * [srt_create_config](#srt_create_config) * [srt_delete_config](#srt_delete_config) * [srt_config_add](#srt_config_add) #### srt_create_group ``` SRTSOCKET srt_create_group(SRT_GROUP_TYPE type); ``` Creates a new group of type `type`. Is typically called on the caller side to be next used for connecting to a remote SRT listener. The group ID is of the same domain as the socket ID, with the exception that the `SRTGROUP_MASK` bit is set on it, unlike for socket ID. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRTSOCKET` | Group SRT socket ID. | | `SRT_INVALID_SOCK` | On error or if bonding API is disabled. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_groupof ``` SRTSOCKET srt_groupof(SRTSOCKET member); ``` Retrieves the group SRT socket ID that corresponds to the member socket ID `member`. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRTSOCKET` | Corresponding group SRT socket ID of the member socket. | | `SRT_INVALID_SOCK` | The socket doesn't exist, it is not a member of any group, or bonding API is disabled. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_group_data ``` int srt_group_data(SRTSOCKET socketgroup, SRT_SOCKGROUPDATA output[], size_t* inoutlen); ``` **Arguments**: * `socketgroup` an existing socket group ID * `output` points to an output array * `inoutlen` points to a variable that stores the size of the `output` array, and is set to the filled array's size This function obtains the current member state of the group specified in `socketgroup`. The `output` should point to an array large enough to hold all the elements. The `inoutlen` should point to a variable initially set to the size of the `output` array. The current number of members will be written back to `inoutlen`. If the size of the `output` array is enough for the current number of members, the `output` array will be filled with group data and the function will return the number of elements filled. Otherwise the array will not be filled and `SRT_ERROR` will be returned. This function can be used to get the group size by setting `output` to `NULL`, and providing `socketgroup` and `inoutlen`. | Returns | | |:----------------------------- |:-------------------------------------------------- | | # of elements | The number of data elements filled, on success | | -1 | Error | | | | | Errors | | |:---------------------------------- |:--------------------------------------------------------- | | [`SRT_EINVPARAM`](#srt_einvparam) | Reported if `socketgroup` is not an existing group ID. Or if bonding API is disabled. | | [`SRT_ELARGEMSG`](#srt_elargemsg) | Reported if `inoutlen` if less than the size of the group | | | | | in:output | in:inoutlen | returns | out:output | out:inoutlen | Error | |:---------:|:--------------:|:------------:|:----------:|:------------:|:---------------------------------:| | NULL | NULL | -1 | NULL | NULL | [`SRT_EINVPARAM`](#srt_einvparam) | | NULL | ptr | 0 | NULL | group.size() | âœ–ï¸ | | ptr | NULL | -1 | âœ–ï¸ | NULL | [`SRT_EINVPARAM`](#srt_einvparam) | | ptr | ≥ group.size | group.size() | group.data | group.size | âœ–ï¸ | | ptr | < group.size | -1 | âœ–ï¸ | group.size | [`SRT_ELARGEMSG`](#srt_elargemsg) | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_connect_group ``` int srt_connect_group(SRTSOCKET group, SRT_SOCKGROUPCONFIG name [], int arraysize); ``` This function does almost the same as calling [`srt_connect`](#srt_connect) or [`srt_connect_bind`](#srt_connect_bind) (when the source was specified for [`srt_prepare_endpoint`](#srt_prepare_endpoint)) in a loop for every item specified in the `name` array. However if blocking mode is being used, the first call to [`srt_connect`](#srt_connect) would block until the connection is established, whereas this function blocks until any of the specified connections is established. If the group nonblocking mode is set ([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) option), there's no difference, except that the [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG) structure allows adding extra configuration data used by groups. Note also that this function accepts only groups, not sockets. The elements of the `name` array need to be prepared with the use of the [`srt_prepare_endpoint`](#srt_prepare_endpoint) function. Note that it is **NOT** required that every target address specified is of the same family. Return value and errors in this function are the same as in [`srt_connect`](#srt_connect), although this function reports success when at least one connection has succeeded. If none has succeeded, this function reports an [`SRT_ECONNLOST`](#srt_econnlost) error. Particular connection states can be obtained from the `name` array upon return from the [`errorcode`](#error-codes) field. The fields of [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG) structure have the following meaning: **Input**: * `id`: unused, should be -1 (default when created by [`srt_prepare_endpoint`](#srt_prepare_endpoint)) * `srcaddr`: address to bind before connecting, if specified (see below for details) * `peeraddr`: target address to connect * `weight`: weight value to be set on the link * `config`: socket options to be set on the socket before connecting * [`errorcode`](#error-codes): unused, should be [`SRT_SUCCESS`](#srt_success) (default) * `token`: An integer value unique for every connection, or -1 if unused **Output**: * `id`: The socket created for that connection (-1 if failed to create) * `srcaddr`: unchanged * `peeraddr`: unchanged * `weight`: unchanged * `config`: unchanged (the object should be manually deleted upon return) * [`errorcode`](#error-codes): status of connection for that link ([`SRT_SUCCESS`](#srt_success) if succeeded) * `token`: same as in input, or a newly created token value if input was -1 | Returns | | |:----------------------------- |:-------------------------------------------------- | | `SRT_SOCKET` | The socket ID of the first connected member. | | -1 | Error | | | | | Errors | | |:---------------------------------- |:--------------------------------------------------------- | | [`SRT_EINVPARAM`](#srt_einvparam) | Reported if `socketgroup` is not an existing group ID. Or if bonding API is disabled. | | [`SRT_ECONNLOST`](#srt_econnlost) | Reported if none of member sockets has connected. | | | | The procedure of connecting for every connection definition specified in the `name` array is performed the following way: 1. The socket for this connection is first created 2. Socket options derived from the group are set on that socket. 3. If `config` is not NULL, configuration options stored there are set on that socket. 4. If source address is specified (that is `srcaddr` value is **not** default empty, as described in [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG), then the binding operation is done on the socket (see [`srt_bind`](#srt_bind)). 5. The socket is added to the group as a member. 6. The socket is connected to the target address, as specified in the `peeraddr` field. During this process there can be errors at any stage. There are two possibilities as to what may happen in this case: 1. If creation of a new socket has failed, which may only happen due to problems with system resources, then the whole loop is interrupted and no further items in the array are processed. All sockets that got created until then, and for which the connection attempt has at least successfully started, remain group members, although the function will return immediately with an error status (that is, without waiting for the first successful connection). If your application wants to do any partial recovery from this situation, it can only use the epoll mechanism to wait for readiness. 2. In any other case, if an error occurs at any stage of the above process, the processing is interrupted for this very array item only, the socket used for it is immediately closed, and the processing of the next elements continues. In the case of a connection process, it also passes two stages - parameter check and the process itself. Failure at the parameter check breaks this process, while if the check passes, this item is considered correctly processed, even if the connection attempt is going to fail later. If this function is called in blocking mode, it then blocks until at least one connection reports success, or if all of them fail. The status of connections that continue in the background after this function exits can then be checked by [`srt_group_data`](#srt_group_data). As member socket connections are running in the background, for determining if a particular connection has succeeded or failed it is recommended to use [`srt_connect_callback`](#srt_connect_callback). In this case the `token` callback function parameter will be the same as the `token` value used for the particular item in the `name` connection table. The `token` value doesn't have any limitations except that the -1 value is a "trap representation", that is, when set on input it will make the internals define a unique value for the `token`. Your application can also set unique values, in which case the `token` value will be preserved. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_prepare_endpoint ``` SRT_SOCKGROUPCONFIG srt_prepare_endpoint(const struct sockaddr* src /*nullable*/, const struct sockaddr* dst, int namelen); ``` This function prepares a default [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG) object as an element of the array you can prepare for [`srt_connect_group`](#srt_connect_group) function, filled with additional data: **Arguments**: * `src`: address to which the newly created socket should be bound * `dst`: address to which the newly created socket should connect * `namelen`: size of both `src` and `dst` The following fields are set by this function: * `id`: -1 (unused for input) * `srcaddr`: default empty (see below) or copied from `src` * `peeraddr`: copied from `dst` * `weight`: 0 * `config`: `NULL` * [`errorcode`](#error-codes): [`SRT_SUCCESS`](#srt_success) The default empty `srcaddr` is set the following way: * `ss_family` set to the same value as `dst->sa_family` * empty address (`INADDR_ANY` for IPv4 and `in6addr_any` for IPv6) * port number 0 If `src` is not NULL, then `srcaddr` is copied from `src`. Otherwise it will remain as default empty. The `dst` parameter is obligatory. If `src` parameter is not NULL, then both `dst` and `src` must have the same value of `sa_family`. Note though that this function has no possibility of reporting errors - these would be reported only by [`srt_connect_group`](#srt_connect_group), separately for every individual connection, and the status can be obtained from the [`errorcode`](#error-codes) field. Note that the `errorcode` field of the `SRT_SOCKGROUPCONFIG` returned would be set to `SRT_EINVOP` if the bonding API is disabled (`ENABLE_BONDING=OFF`). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_create_config ``` SRT_SOCKOPT_CONFIG* srt_create_config(); ``` Creates a dynamic object for specifying the socket options. You can add options to be set on the socket by [`srt_config_add`](#srt_config_add) and then mount this object into the `config` field in [`SRT_SOCKGROUPCONFIG`](#SRT_SOCKGROUPCONFIG) object for that particular connection. After the object is no longer needed, you should delete it using [`srt_delete_config`](#srt_delete_config). | Returns | | |:----------------------------- |:------------------------------------------------------------------ | | Pointer | The pointer to the created object (memory allocation errors apply) | | NULL | If bonding API is disabled. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_delete_config ``` void srt_delete_config(SRT_SOCKOPT_CONFIG* c); ``` Deletes the configuration object. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- #### srt_config_add ``` int srt_config_add(SRT_SOCKOPT_CONFIG* c, SRT_SOCKOPT opt, void* val, int len); ``` Adds a configuration option to the configuration object. Parameters have meanings similar to [`srt_setsockflag`](#srt_setsockflag). Note that not every option is allowed to be set this way. However, the option (if allowed) isn't checked if it doesn't violate other preconditions. This will be checked when the option is being set on the socket, which may fail as a part of the connection process done by [`srt_connect_group`](#srt_connect_group). This function should be used when this option must be set individually on a socket and differently for a particular link. If you need to set some option the same way on every socket, you should instead set this option on the whole group. The following options are allowed to be set on the member socket: * [`SRTO_BINDTODEVICE`](API-socket-options.md#SRTO_BINDTODEVICE): If you want to limit binding for this link (Linux only) * [`SRTO_CONNTIMEO`](API-socket-options.md#SRTO_CONNTIMEO): If you want to give more time to connect on this link * [`SRTO_GROUPMINSTABLETIMEO`](API-socket-options.md#SRTO_GROUPMINSTABLETIMEO): To set ACK jitter tolerance per individual link * [`SRTO_LOSSMAXTTL`](API-socket-options.md#SRTO_LOSSMAXTTL): If this link tends to suffer from UDP reordering * [`SRTO_NAKREPORT`](API-socket-options.md#SRTO_NAKREPORT): If you don't want NAKREPORT to work for this link * [`SRTO_PEERIDLETIMEO`](API-socket-options.md#SRTO_PEERIDLETIMEO): If you want to be more tolerant for temporary outages * [`SRTO_RCVBUF`](API-socket-options.md#SRTO_RCVBUF): Allows for larger receiver buffer for longer recovery * [`SRTO_SNDBUF`](API-socket-options.md#SRTO_SNDBUF): Allows for larger sender buffer for slower links * [`SRTO_SNDDROPDELAY`](API-socket-options.md#SRTO_SNDDROPDELAY): When particular link tends to drop too eagerly * [`SRTO_UDP_RCVBUF`](API-socket-options.md#SRTO_UDP_RCVBUF): UDP receiver buffer, if this link has a big flight window * [`SRTO_UDP_SNDBUF`](API-socket-options.md#SRTO_UDP_SNDBUF): UDP sender buffer, if this link has a big flight window | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Success | | -1 | Failure | | | | | Errors | | |:---------------------------------- |:--------------------------------------------------------------------- | | [`SRT_EINVPARAM`](#srt_einvparam) | This option is not allowed to be set on a socket being a group member. Or if bonding API is disabled. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Options and Properties * [srt_getpeername](#srt_getpeername) * [srt_getsockname](#srt_getsockname) * [srt_getsockopt, srt_getsockflag](#srt_getsockopt-srt_getsockflag) * [srt_setsockopt, srt_setsockflag](#srt_setsockopt-srt_setsockflag) * [srt_getversion](#srt_getversion) **NOTE**: For more information, see [SRT API Socket Options, Getting and Setting Options](API-socket-options.md#getting-and-setting-options). ### srt_getpeername ``` int srt_getpeername(SRTSOCKET u, struct sockaddr* name, int* namelen); ``` Retrieves the remote address to which the socket is connected. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:------------------------------- |:------------------------------------------------------------------------ | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | [`SRT_ENOCONN`](#srt_enoconn) | Socket [`u`](#u) isn't connected, so there's no remote address to return | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getsockname ``` int srt_getsockname(SRTSOCKET u, struct sockaddr* name, int* namelen); ``` Extracts the address to which the socket was bound. Although you should know the address(es) that you have used for binding yourself, this function can be useful for extracting the local outgoing port number when it was specified as 0 with binding for system autoselection. With this function you can extract the port number after it has been autoselected. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:------------------------------- |:---------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | [`SRT_ENOCONN`](#srt_enoconn) | Socket [`u`](#u) isn't bound, so there's no local address to return
(:warning:   **BUG?** It should rather be [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock)) | | | | Example ```c++ sockaddr_storage name; int namelen = sizeof sockaddr_storage; int res = srt_getsockname(m_listener_sock, (sockaddr*) &name, &namelen); // IPv4: namelen == sockaddr_in. // IPv6: namelen == sockaddr_in6. if (res < 0) { std::cerr << "Error " << srt_getlasterror_str() << '\n'; } ``` [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getsockopt ### srt_getsockflag ```c++ int srt_getsockopt(SRTSOCKET u, int level /*ignored*/, SRT_SOCKOPT opt, void* optval, int* optlen); int srt_getsockflag(SRTSOCKET u, SRT_SOCKOPT opt, void* optval, int* optlen); ``` Gets the value of the given socket option (from a socket or a group). The first version ([`srt_getsockopt`](#srt_getsockopt)) follows the BSD socket API convention, although the "level" parameter is ignored. The second version ([`srt_getsockflag`](#srt_getsockflag)) omits the "level" parameter completely. Options correspond to various data types (see [API-socket-options.md](./API-socket-options.md)). A variable `optval` of the appropriate data type has to be passed. The integer value of `optlen` should originally contain the size of the `optval` type provided; on return, it will be set to the size of the value returned. For most options, it will be the size of an integer. Some options, however, use types `bool`, `int64_t`, `C string`, etc. (see [API-socket-options.md](./API-socket-options.md#sockopt_types)). The application is responsible for allocating sufficient memory space as defined and pointed to by `optval`. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:-------------------------------- |:---------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | [`SRT_EINVOP`](#srt_einvop) | Option `opt` indicates no valid option | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_setsockopt ### srt_setsockflag ```c++ int srt_setsockopt(SRTSOCKET u, int level /*ignored*/, SRT_SOCKOPT opt, const void* optval, int optlen); int srt_setsockflag(SRTSOCKET u, SRT_SOCKOPT opt, const void* optval, int optlen); ``` Sets a value for a socket option in the socket or group. The first version ([`srt_setsockopt`](#srt_setsockopt)) follows the BSD socket API convention, although the "level" parameter is ignored. The second version ([`srt_setsockflag`](#srt_setsockflag)) omits the "level" parameter completely. Options correspond to various data types, so you need to know what data type is assigned to a particular option, and to pass a variable of the appropriate data type with the option value to be set. Please note that some of the options can only be set on sockets or only on groups, although most of the options can be set on the groups so that they are then derived by the member sockets. | Returns | | |:----------------------------- |:----------------------------------------------- | | `SRT_ERROR` | (-1) in case of error, otherwise 0 | | | | | Errors | | |:----------------------------------- |:--------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket [`u`](#u) indicates no valid socket ID | | [`SRT_EINVPARAM`](#srt_einvparam) | Option `opt` indicates no valid option | | [`SRT_EBOUNDSOCK`](#srt_eboundsock) | Tried to set an option with PRE_BIND restriction on a bound socket. | | [`SRT_ECONNSOCK`](#srt_econnsock) | Tried to set an option with PRE_BIND or PRE restriction on a socket in connecting/listening/connected state. | | | | **NOTE*: Various other errors may result from problems when setting a specific option (see option description in [API-socket-options.md](./API-socket-options.md) for details). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getversion ``` uint32_t srt_getversion(); ``` Get SRT version value. The version format in hex is 0xXXYYZZ for x.y.z in human readable form, where x = ("%d", (version>>16) & 0xff), etc. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | SRT Version | Unsigned 32-bit integer | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Helper Data Types for Transmission * [SRT_MSGCTRL](#SRT_MSGCTRL) **NOTE:** There might be a difference in terminology used in [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) and current documentation. Please consult [Data Transmission Modes](https://tools.ietf.org/html/draft-sharabayko-srt-01#section-4.2) and [Best Practices and Configuration Tips for Data Transmission via SRT](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-7) sections of the Internet Draft additionally. The current section is going to be reworked accordingly. ### SRT_MSGCTRL The [`SRT_MSGCTRL`](#SRT_MSGCTRL) structure: ```c++ typedef struct SRT_MsgCtrl_ { int flags; // Left for future int msgttl; // TTL for a message, default -1 (no TTL limitation) int inorder; // Whether a message is allowed to supersede a partially lost one. Unused in stream and live mode int boundary; // 0:mid pkt, 1(01b):end of frame, 2(11b):complete frame, 3(10b): start of frame int64_t srctime; // Source time, in microseconds since SRT internal clock epoch int32_t pktseq; // Sequence number of the first packet in received message (unused for sending) int32_t msgno; // Message number (output value for both sending and receiving) SRT_SOCKGROUPDATA* grpdata; // Pointer to group data array size_t grpdata_size; // Size of the group array } SRT_MSGCTRL; ``` The [`SRT_MSGCTRL`](#SRT_MSGCTRL) structure is used in [`srt_sendmsg2`](#srt_sendmsg) and [`srt_recvmsg2`](#srt_recvmsg2) calls and specifies some special extra parameters: - `flags`: [IN, OUT]. RESERVED FOR FUTURE USE (should be 0). This is intended to specify some special options controlling the details of how the called function should work. - `msgttl`: [IN]. In **message** and **live mode** only, specifies the TTL for sending messages (in `[ms]`). Not used for receiving messages. If this value is not negative, it defines the maximum time up to which this message should stay scheduled for sending. If TTL has expired, the message sending and further retransmissions are discarded, even if it has never been sent so far. - `inorder`: [IN]. In **message mode** only, specifies that sent messages should be extracted by the receiver in the order of sending. This can be meaningful if a packet loss has happened, and a particular message must wait for retransmission so that it can be reassembled and then delivered. When this flag is false, the message can be delivered even if there are any previous messages still waiting for completion. - `boundary`: RESERVED FOR FUTURE USE. Intended to be used in a special mode when you are allowed to send or retrieve a part of the message. - `srctime`: - [OUT] Receiver only. Specifies the time when the packet was intended to be delivered to the receiving application (in microseconds since SRT clock epoch). - [IN] Sender only. Specifies the application-provided timestamp to be associated with the packet. If not provided (specified as 0), the current time of SRT internal clock is used. - For details on how to use `srctime` please refer to the [Time Access](#time-access) section. - `pktseq`: Receiver only. Reports the sequence number for the packet carrying out the payload being returned. If the payload is carried out by more than one UDP packet, only the sequence of the first one is reported. Note that in **live mode** there's always one UDP packet per message. - `msgno`: Message number that can be sent by both sender and receiver, although it is required that this value remain monotonic in subsequent send calls. Normally message numbers start with 1 and increase with every message sent. - `grpdata` and `grpdata_size`: Pointer and size of the group array. For single socket connections these values should remain NULL and 0 respectively. When you call [`srt_sendmsg2`](#srt_sendmsg) or [`srt_recvmsg2`](#srt_recvmsg2) function for a group, you should pass an array here so that you can retrieve the status of particular member sockets. If you pass an array that is too small, your `grpdata_size` field will be rewritten with the current number of members, but without filling in the array; otherwise both fields are updated to reflect the current connection state of the group. For details, see the [SRT Connection Bonding: Quick Start](../features/bonding-intro.md) and [SRT Connection Bonding: Socket Groups](../features/socket-groups.md) documents. **Helpers for [`SRT_MSGCTRL`](#SRT_MSGCTRL):** ``` void srt_msgctrl_init(SRT_MSGCTRL* mctrl); const SRT_MSGCTRL srt_msgctrl_default; ``` Helpers for getting an object of [`SRT_MSGCTRL`](#SRT_MSGCTRL) type ready to use. The first is a function that fills the object with default values. The second is a constant object and can be used as a source for assignment. Note that you cannot pass this constant object into any of the API functions because they require it to be mutable, as they use some fields to output values. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Transmission * [srt_send, srt_sendmsg, srt_sendmsg2](#srt_send-srt_sendmsg-srt_sendmsg2) * [srt_recv, srt_recvmsg, srt_recvmsg2](#srt_recv-srt_recvmsg-srt_recvmsg2) * [srt_sendfile, srt_recvfile](#srt_sendfile-srt_recvfile) **NOTE:** There might be a difference in terminology used in [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) and current documentation. Please consult [Data Transmission Modes](https://tools.ietf.org/html/draft-sharabayko-srt-01#section-4.2) and [Best Practices and Configuration Tips for Data Transmission via SRT](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-7) sections of the Internet Draft additionally. The current section is going to be reworked accordingly. ### srt_send ### srt_sendmsg ### srt_sendmsg2 ``` int srt_send(SRTSOCKET u, const char* buf, int len); int srt_sendmsg(SRTSOCKET u, const char* buf, int len, int ttl/* = -1*/, int inorder/* = false*/); int srt_sendmsg2(SRTSOCKET u, const char* buf, int len, SRT_MSGCTRL *mctrl); ``` Sends a payload to a remote party over a given socket. **Arguments**: * [`u`](#u): Socket used to send. The socket must be connected for this operation. * `buf`: Points to the buffer containing the payload to send. * `len`: Size of the payload specified in `buf`. * `ttl`: Time (in `[ms]`) to wait for a successful delivery. See description of the [`SRT_MSGCTRL::msgttl`](#SRT_MSGCTRL) field. * `inorder`: Required to be received in the order of sending. See [`SRT_MSGCTRL::inorder`](#SRT_MSGCTRL). * `mctrl`: An object of [`SRT_MSGCTRL`](#SRT_MSGCTRL) type that contains extra parameters, including `ttl` and `inorder`. The way this function works is determined by the mode set in options, and it has specific requirements: 1. In **file/stream mode**, the payload is byte-based. You are not required to know the size of the data, although they are only guaranteed to be received in the same byte order. 2. In **file/message mode**, the payload that you send using this function is a single message that you intend to be received as a whole. In other words, a single call to this function determines a message's boundaries. 3. In **live mode**, you are only allowed to send up to the length of `SRTO_PAYLOADSIZE`, which can't be larger than 1456 bytes (1316 default). | Returns | | |:----------------------------- |:--------------------------------------------------------- | | Size | Size of the data sent, if successful | | `SRT_ERROR` | In case of error (-1) | | | | **NOTE**: Note that in **file/stream mode** the returned size may be less than `len`, which means that it didn't send the whole contents of the buffer. You would need to call this function again with the rest of the buffer next time to send it completely. In both **file/message** and **live mode** the successful return is always equal to `len`. | Errors | | |:--------------------------------------------- |:------------------------------------------------------------------------------------------------------------------- | | [`SRT_ENOCONN`](#srt_enoconn) | Socket [`u`](#u) used when the operation is not connected. | | [`SRT_ECONNLOST`](#srt_econnlost) | Socket [`u`](#u) used for the operation has lost its connection. | | [`SRT_EINVALMSGAPI`](#srt_einvalmsgapi) | Incorrect API usage in **message mode**:
**live mode**: trying to send more bytes at once than `SRTO_PAYLOADSIZE` or wrong source time
was provided. | | [`SRT_EINVALBUFFERAPI`](#srt_einvalbufferapi) | Incorrect API usage in **stream mode** (reserved for future use):
The congestion controller object used for this mode doesn't use any restrictions on this call,
but this may change. | | [`SRT_ELARGEMSG`](#srt_elargemsg) | Message to be sent can't fit in the sending buffer (that is, it exceeds the current total space in the
sending buffer in bytes). This means that the sender buffer is too small, or the application is
trying to send a larger message than initially predicted. | | [`SRT_EASYNCSND`](#srt_easyncsnd) | There's no free space currently in the buffer to schedule the payload. This is only reported in
non-blocking mode ([`SRTO_SNDSYN`](API-socket-options.md#SRTO_SNDSYN) set to false); in blocking mode the call is blocked until
enough free space in the sending buffer becomes available. | | [`SRT_ETIMEOUT`](#srt_etimeout) | The condition described above still persists and the timeout has passed. This is only reported in
blocking mode when [`SRTO_SNDTIMEO`](API-socket-options.md#SRTO_SNDTIMEO) is set to a value other than -1. | | [`SRT_EPEERERR`](#srt_epeererr) | This is reported only in the case where, as a stream is being received by a peer, the
[`srt_recvfile`](#srt_recvfile) function encounters an error during a write operation on a file. This is reported by
a `UMSG_PEERERROR` message from the peer, and the agent sets the appropriate flag internally.
This flag persists up to the moment when the connection is broken or closed. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_recv ### srt_recvmsg ### srt_recvmsg2 ``` int srt_recv(SRTSOCKET u, char* buf, int len); int srt_recvmsg(SRTSOCKET u, char* buf, int len); int srt_recvmsg2(SRTSOCKET u, char *buf, int len, SRT_MSGCTRL *mctrl); ``` Extracts the payload waiting to be received. Note that [`srt_recv`](#srt_recv) and [`srt_recvmsg`](#srt_recvmsg) are identical functions, two different names being kept for historical reasons. In the UDT predecessor the application was required to use either the `UDT::recv` version for **stream mode** and `UDT::recvmsg` for **message mode**. In SRT this distinction is resolved internally by the [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag. **Arguments**: * [`u`](#u): Socket used to send. The socket must be connected for this operation. * `buf`: Points to the buffer to which the payload is copied. * `len`: Size of the payload specified in `buf`. * `mctrl`: An object of [`SRT_MSGCTRL`](#SRT_MSGCTRL) type that contains extra parameters. The way this function works is determined by the mode set in options, and it has specific requirements: 1. In **file/stream mode**, as many bytes as possible are retrieved, that is, only so many bytes that fit in the buffer and are currently available. Any data that is available but not extracted this time will be available next time. 2. In **file/message mode**, exactly one message is retrieved, with the boundaries defined at the moment of sending. If some parts of the messages are already retrieved, but not the whole message, nothing will be received (the function blocks or returns [`SRT_EASYNCRCV`](#srt_easyncrcv)). If the message to be returned does not fit in the buffer, nothing will be received and the error is reported. 3. In **live mode**, the function behaves as in **file/message mode**, although the number of bytes retrieved will be at most the maximum payload of one MTU. The [`SRTO_PAYLOADSIZE`](API-socket-options.md#SRTO_PAYLOADSIZE) value configured by the sender is not negotiated, and not known to the receiver. The [`SRTO_PAYLOADSIZE`](API-socket-options.md#SRTO_PAYLOADSIZE) value set on the SRT receiver is mainly used for heuristics. However, the receiver is prepared to receive the whole MTU as configured with [`SRTO_MSS`](API-socket-options.md#SRTO_MSS). In this mode, however, with default settings of [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) and [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP), the message will be received only when its time to play has come, and until then it will be kept in the receiver buffer. Also, when the time to play has come for a message that is next to the currently lost one, it will be delivered and the lost one dropped. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | Size | Size (\>0) of the data received, if successful. | | 0 | If the connection has been closed | | `SRT_ERROR` | (-1) when an error occurs | | | | | Errors | | |:--------------------------------------------- |:--------------------------------------------------------- | | [`SRT_ENOCONN`](#srt_enoconn) | Socket [`u`](#u) used for the operation is not connected. | | [`SRT_ECONNLOST`](#srt_econnlost) | Socket [`u`](#u) used for the operation has lost connection (this is reported only if the connection
was unexpectedly broken, not when it was closed by the foreign host). | | [`SRT_EINVALMSGAPI`](#srt_einvalmsgapi) | Incorrect API usage in **message mode**:
-- **live mode**: size of the buffer is less than [`SRTO_PAYLOADSIZE`](API-socket-options.md#SRTO_PAYLOADSIZE) | | [`SRT_EINVALBUFFERAPI`](#srt_einvalbufferapi) | Incorrect API usage in **stream mode**:
• Currently not in use. File congestion control used for **stream mode** does not restrict
the parameters. :warning:   **???** | | [`SRT_ELARGEMSG`](#srt_elargemsg) | Message to be sent can't fit in the sending buffer (that is, it exceeds the current total space in
the sending buffer in bytes). This means that the sender buffer is too small, or the application
is trying to send a larger message than initially intended. | | [`SRT_EASYNCRCV`](#srt_easyncrcv) | There are no data currently waiting for delivery. This happens only in non-blocking mode
(when [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) is set to false). In blocking mode the call is blocked until the data are ready.
How this is defined, depends on the mode:
• In **live mode** (with [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) on), at least one packet must be present in the receiver
buffer and its time to play be in the past
• In **file/message mode**, one full message must be available, the next one waiting if there are no
messages with `inorder` = false, or possibly the first message ready with `inorder` = false
• In **file/stream mode**, it is expected to have at least one byte of data still not extracted | | [`SRT_ETIMEOUT`](#srt_etimeout) | The readiness condition described above is still not achieved and the timeout has passed.
This is only reported in blocking mode when[`SRTO_RCVTIMEO`](API-socket-options.md#SRTO_RCVTIMEO) is set to a value other than -1. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_sendfile ### srt_recvfile ``` int64_t srt_sendfile(SRTSOCKET u, const char* path, int64_t* offset, int64_t size, int block); int64_t srt_recvfile(SRTSOCKET u, const char* path, int64_t* offset, int64_t size, int block); ``` These are functions dedicated to sending and receiving a file. You need to call this function just once for the whole file, although you need to know the size of the file prior to sending, and also define the size of a single block that should be internally retrieved and written into a file in a single step. This influences only the performance of the internal operations; from the application perspective you just have one call that exits only when the transmission is complete. **Arguments**: * [`u`](#u): Socket used for transmission. The socket must be connected. * `path`: Path to the file that should be read or written. * `offset`: Needed to pass or retrieve the offset used to read or write to a file * `size`: Size of transfer (file size, if offset is at 0) * `block`: Size of the single block to read at once before writing it to a file The following values are recommended for the `block` parameter: ``` #define SRT_DEFAULT_SENDFILE_BLOCK 364000 #define SRT_DEFAULT_RECVFILE_BLOCK 7280000 ``` You need to pass them to the [`srt_sendfile`](#srt_sendfile) or [`srt_recvfile`](#srt_recvfile) function if you don't know what value to chose. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | Size | The size (\>0) of the transmitted data of a file. It may be less than `size`, if the size was greater
than the free space in the buffer, in which case you have to send rest of the file next time. | | -1 | in case of error | | | | | Errors | | |:--------------------------------------------- |:----------------------------------------------------------------------------- | | [`SRT_ENOCONN`](#srt_enoconn) | Socket [`u`](#u) used for the operation is not connected. | | [`SRT_ECONNLOST`](#srt_econnlost) | Socket [`u`](#u) used for the operation has lost its connection. | | [`SRT_EINVALBUFFERAPI`](#srt_einvalbufferapi) | When socket has [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) = true or [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) = true.
(:warning:   **BUG?**: Looxlike MESSAGEAPI isn't checked) | | [`SRT_EINVRDOFF`](#srt_einvrdoff) | There is a mistake in `offset` or `size` parameters, which should match the index availability
and size of the bytes available since `offset` index. This is actually reported for [`srt_sendfile`](#srt_sendfile)
when the `seekg` or `tellg` operations resulted in error. | | [`SRT_EINVWROFF`](#srt_einvwroff) | Like above, reported for [`srt_recvfile`](#srt_recvfile) and `seekp`/`tellp`. | | [`SRT_ERDPERM`](#srt_erdperm) | The read from file operation has failed ([`srt_sendfile`](#srt_sendfile)). | | [`SRT_EWRPERM`](#srt_ewrperm) | The write to file operation has failed ([`srt_recvfile`](#srt_recvfile)). | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Performance Tracking * [srt_bstats, srt_bistats](#srt_bstats-srt_bistats) **Sequence Numbers:** The sequence numbers used in SRT are 32-bit "circular numbers" with the most significant bit not included. For example 0x7FFFFFFF shifted forward by 3 becomes 2. As far as any comparison is concerned, it can be thought of as a "distance" which is an integer value expressing an offset to be added to one sequence number in order to get the second one. This distance is only valid as long as the threshold value isn't exceeded, so it's understood that all sequence numbers that are anywhere taken into account are systematically updated and kept in the range between 0 and half of the maximum 0x7FFFFFFF. Hence, the distance counting procedure always assumes that the sequence number are in the required range already, so for a numbers like 0x7FFFFFF0 and 0x10, for which the "numeric difference" would be 0x7FFFFFE0, the "distance" is 0x20. ### srt_bstats ### srt_bistats ``` // Performance monitor with Byte counters for better bitrate estimation. int srt_bstats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear); // Performance monitor with Byte counters and instantaneous stats instead of moving averages for Snd/Rcvbuffer sizes. int srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous); ``` Reports the current statistics **Arguments**: * [`u`](#u): Socket from which to get statistics * `perf`: Pointer to an object to be written with the statistics * `clear`: 1 if the statistics should be cleared after retrieval * `instantaneous`: 1 if the statistics should use instant data, not moving averages `SRT_TRACEBSTATS` is an alias to `struct CBytePerfMon`. For a complete description of the fields please refer to [SRT Statistics](statistics.md). | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Success | | -1 | Failure | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Invalid socket ID provided. | [`SRT_ECONNLOST`](#srt_econnlost) | Connection lost (group socket). | [`SRT_ENOCONN`](#srt_enoconn) | Not connected (group socket). | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Asynchronous Operations (Epoll) * [srt_epoll_create](#srt_epoll_create) * [srt_epoll_add_usock, srt_epoll_add_ssock, srt_epoll_update_usock, srt_epoll_update_ssock](#srt_epoll_add_usock-srt_epoll_add_ssock-srt_epoll_update_usock-srt_epoll_update_ssock) * [srt_epoll_remove_usock, srt_epoll_remove_ssock](#srt_epoll_remove_usock-srt_epoll_remove_ssock) * [srt_epoll_wait](#srt_epoll_wait) * [srt_epoll_uwait](#srt_epoll_uwait) * [srt_epoll_clear_usocks](#srt_epoll_clear_usocks) * [srt_epoll_set](#srt_epoll_set) * [srt_epoll_release](#srt_epoll_release) The epoll system is currently the only method for using multiple sockets in one thread with having the blocking operation moved to epoll waiting so that it can block on multiple sockets at once. That is, instead of blocking a single reading or writing operation, as it's in blocking mode, it blocks until at least one of the sockets subscribed for a single waiting call in given operation mode is ready to do this operation without blocking. It's usually combined with setting the nonblocking mode on a socket. In SRT this is set separately for reading and writing ([`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) and [`SRTO_SNDSYN`](API-socket-options.md#SRTO_SNDSYN) respectively). This is to ensure that if there is internal error in the application (or even possibly a bug in SRT that has reported a spurious readiness report) the operation will end up with an error rather than cause blocking, which would be more dangerous for the application ([`SRT_EASYNCRCV`](#srt_easyncrcv) and [`SRT_EASYNCSND`](#srt_easyncsnd) respectively). The epoll system, similar to the one on Linux, relies on [`eid`](#eid) objects managed internally in SRT, which can be subscribed to particular sockets and the readiness status of particular operations. The [`srt_epoll_wait`](#srt_epoll_wait) function can then be used to block until any readiness status in the whole [`eid`](#eid) is set. ### srt_epoll_create ``` int srt_epoll_create(void); ``` Creates a new epoll container. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | valid EID | Success | | -1 | Failure | | | | | Errors | | |:----------------------------------- |:--------------------------------------------------------------------- | | [`SRT_ECONNSETUP`](#srt_econnsetup) | System operation failed or not enough space to create a new epoll. System error might happen on
systems that use a special method for the system part of epoll (`epoll_create()`, `kqueue()`),
and therefore associated resources, like epoll on Linux. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_add_usock ### srt_epoll_add_ssock ### srt_epoll_update_usock ### srt_epoll_update_ssock ``` int srt_epoll_add_usock(int eid, SRTSOCKET u, const int* events); int srt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events); int srt_epoll_update_usock(int eid, SRTSOCKET u, const int* events); int srt_epoll_update_ssock(int eid, SYSSOCKET s, const int* events); ``` Adds a socket to a container, or updates an existing socket subscription. The `_usock` suffix refers to a user socket (SRT socket). The `_ssock` suffix refers to a system socket. The `_add_` functions add new sockets. The `_update_` functions act on a socket that is in the container already and just allow changes in the subscription details. For example, if you have already subscribed a socket with [`SRT_EPOLL_OUT`](#SRT_EPOLL_OUT) to wait until it's connected, to change it into poll for read-readiness, you use this function on that same socket with a variable set to [`SRT_EPOLL_IN`](#SRT_EPOLL_IN). This will not only change the event type which is polled on the socket, but also remove any readiness status for flags that are no longer set. It is discouraged to perform socket removal and adding back (instead of using `_update_`) because this way you may miss an event that could happen in the brief moment between these two calls. **Arguments**: * `eid`: epoll container id * `u`: SRT socket * `s`(#s): system socket * `events`: points to * a variable set to epoll flags (see below) to use only selected events * NULL if you want to subscribe a socket for all events in level-triggered mode Possible epoll flags are the following: * `SRT_EPOLL_IN`: report readiness for reading or incoming connection on a listener socket * `SRT_EPOLL_OUT`: report readiness for writing or a successful connection * `SRT_EPOLL_ERR`: report errors on the socket * `SRT_EPOLL_UPDATE`: an important event has happened that requires attention * `SRT_EPOLL_ET`: the event will be edge-triggered All flags except [`SRT_EPOLL_ET`](#SRT_EPOLL_ET) are event type flags (important for functions that expect only event types and not other flags). The [`SRT_EPOLL_IN`](#SRT_EPOLL_IN), [`SRT_EPOLL_OUT`](#SRT_EPOLL_OUT) and [`SRT_EPOLL_ERR`](#SRT_EPOLL_ERR) events are by default **level-triggered**. With [`SRT_EPOLL_ET`](#SRT_EPOLL_ET) flag they become **edge-triggered**. The [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) flag is always edge-triggered. It designates a special event that happens on a group, or on a listener socket that has the [`SRTO_GROUPCONNECT`](API-socket-options.md#SRTO_GROUPCONNECT) flag set to allow group connections. This flag is triggered in the following situations: * for group connections, when a new link has been established for a group that is already connected (that is, has at least one connection established), [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) is reported for the listener socket accepting the connection. This is intended for internal use only. An initial connection results in reporting the group connection on that listener. But when the group is already connected, [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) is reported instead. * when one of a group's member connection has been broken Note that at this time the edge-triggered mode is supported only for SRT sockets, not for system sockets. In the **edge-triggered** mode the function will only return socket states that have changed since the last call of the waiting function. All events reported in a particular call of the waiting function will be cleared in the internal flags and will not be reported until the internal signalling logic clears this state and raises it again. In the **level-triggered** mode the function will always return the readiness state as long as it lasts, until the internal signalling logic clears it. Note that when you use [`SRT_EPOLL_ET`](#SRT_EPOLL_ET) flag in one subscription call, it defines edge-triggered mode for all events passed together with it. However, if you want to have some events reported as edge-triggered and others as level-triggered, you can do two separate subscriptions for the same socket. **IMPORTANT**: The [`srt_epoll_wait`](#srt_epoll_wait) function does not report [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) events. If you need the ability to get any possible flag, you must use [`srt_epoll_uwait`](#srt_epoll_uwait). Note that this function doesn't work with system file descriptors. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Success | | -1 | Failure | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | | | :warning:   **BUG?**: for `add_ssock` the system error results in an empty `CUDTException()` call which actually results in [`SRT_SUCCESS`](#srt_success). For cases like that the [`SRT_ECONNSETUP`](#srt_econnsetup) code is predicted. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_remove_usock ### srt_epoll_remove_ssock ``` int srt_epoll_remove_usock(int eid, SRTSOCKET u); int srt_epoll_remove_ssock(int eid, SYSSOCKET s); ``` Removes a specified socket from an epoll container and clears all readiness states recorded for that socket. The `_usock` suffix refers to a user socket (SRT socket). The `_ssock` suffix refers to a system socket. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Success | | -1 | Failure | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_wait ``` int srt_epoll_wait(int eid, SRTSOCKET* readfds, int* rnum, SRTSOCKET* writefds, int* wnum, int64_t msTimeOut, SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum); ``` Blocks the call until any readiness state occurs in the epoll container. Readiness can be on a socket in the container for the event type as per subscription. Note that in the case when a particular event was subscribed with [`SRT_EPOLL_ET`](#SRT_EPOLL_ET) flag, this event, once reported in this function, will be cleared internally. The first readiness state causes this function to exit, but all ready sockets are reported. This function blocks until the timeout specified in the `msTimeOut` parameter. If timeout is 0, it exits immediately after checking. If timeout is -1, it blocks indefinitely until a readiness state occurs. **Arguments**: * `eid`: epoll container * `readfds` and `rnum`: A pointer and length of an array to write SRT sockets that are read-ready * `writefds` and `wnum`: A pointer and length of an array to write SRT sockets that are write-ready * `msTimeOut`: Timeout specified in milliseconds, or special values (0 or -1) * `lwfds` and `lwnum`: A pointer and length of an array to write system sockets that are read-ready * `lwfds` and `lwnum`: A pointer and length of an array to write system sockets that are write-ready Note that the following flags are reported: * [`SRT_EPOLL_IN`](#SRT_EPOLL_IN) as read-ready (also a listener socket ready to accept) * [`SRT_EPOLL_OUT`](#SRT_EPOLL_OUT) as write-ready (also a connected socket) * [`SRT_EPOLL_ERR`](#SRT_EPOLL_ERR) as both read-ready and write-ready * [`SRT_EPOLL_UPDATE`](#SRT_EPOLL_UPDATE) is not reported There is no space here to report sockets for which it's already known that the operation will end up with error (although such a state is known internally). If an error occurred on a socket then that socket is reported in both read-ready and write-ready arrays, regardless of what event types it was subscribed for. Usually then you subscribe the given socket for only read readiness, for example ([`SRT_EPOLL_IN`](#SRT_EPOLL_IN)), but pass both arrays for read and write readiness.This socket will not be reported in the write readiness array even if it's write ready (because this isn't what it was subscribed for), but it will be reported there, if the next operation on this socket is about to be erroneous. On such sockets you can still perform an operation, just you should expect that it will always report an error. On the other hand that's the only way to know what kind of error has occurred on the socket. | Returns | | |:----------------------------- |:------------------------------------------------------------ | | Number | The number (\>0) of ready sockets, of whatever kind (if any) | | -1 | Error | | | | | Errors | | |:----------------------------------- |:------------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | [`SRT_ETIMEOUT`](#srt_etimeout) | Up to `msTimeOut` no sockets subscribed in [`eid`](#eid) were ready. This is reported only if `msTimeOut`
was \>=0, otherwise the function waits indefinitely. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_uwait ``` int srt_epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut); ``` This function blocks a call until any readiness state occurs in the epoll container. Unlike [`srt_epoll_wait`](#srt_epoll_wait), it can only be used with [`eid`](#eid) subscribed to user sockets (SRT sockets), not system sockets. This function blocks until the timeout specified in `msTimeOut` parameter. If timeout is 0, it exits immediately after checking. If timeout is -1, it blocks indefinitely until a readiness state occurs. **Arguments**: * `eid`: epoll container * `fdsSet` : A pointer to an array of `SRT_EPOLL_EVENT` * `fdsSize` : The size of the fdsSet array * `msTimeOut` : Timeout specified in milliseconds, or special values (0 or -1): * 0: Don't wait, return immediately (report any sockets currently ready) * -1: Wait indefinitely. | Returns | | |:----------------------------- |:-------------------------------------------------------------------------------------------------------------------------------------- | | Number | The number of user socket (SRT socket) state changes that have been reported in `fdsSet`,
if this number isn't greater than `fdsSize` | | `fdsSize` + 1 | This means that there was not enough space in the output array to report all events.
For events subscribed with the [`SRT_EPOLL_ET`](#SRT_EPOLL_ET) flag only those will be cleared that were reported.
Others will wait for the next call. | | 0 | If no readiness state was found on any socket and the timeout has passed
(this is not possible when waiting indefinitely) | | -1 | Error | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | [`SRT_EINVPARAM`](#srt_einvparam) | One of possible usage errors:
* `fdsSize` is < 0
* `fdsSize` is > 0 and `fdsSet` is a null pointer
* [`eid`](#eid) was subscribed to any system socket | | | | **IMPORTANT**: This function reports timeout by returning 0, not by [`SRT_ETIMEOUT`](#srt_etimeout) error. The `SRT_EPOLL_EVENT` structure: ``` typedef struct SRT_EPOLL_EVENT_ { SRTSOCKET fd; int events; } SRT_EPOLL_EVENT; ``` * `fd`: the user socket (SRT socket) * [`events`](#events): event flags that report readiness of this socket - a combination of [`SRT_EPOLL_IN`](#SRT_EPOLL_IN), [`SRT_EPOLL_OUT`](#SRT_EPOLL_OUT) and [`SRT_EPOLL_ERR`](#SRT_EPOLL_ERR). See [srt_epoll_add_usock](#srt_epoll_add_usock) for details. Note that when [`SRT_EPOLL_ERR`](#SRT_EPOLL_ERR) is set, the underlying socket error can't be retrieved with `srt_getlasterror()`. The socket will be automatically closed and its state can be verified with a call to [`srt_getsockstate`](#srt_getsockstate). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_clear_usocks ``` int srt_epoll_clear_usocks(int eid); ``` This function removes all SRT ("user") socket subscriptions from the epoll container identified by [`eid`](#eid). | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Success | | -1 | Failure | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_set ``` int32_t srt_epoll_set(int eid, int32_t flags); ``` This function allows setting or retrieving flags that change the default behavior of the epoll functions. All default values for these flags are 0. The following flags are available: * `SRT_EPOLL_ENABLE_EMPTY`: allows the [`srt_epoll_wait`](#srt_epoll_wait) and [`srt_epoll_uwait`](#srt_epoll_uwait) functions to be called with the EID not subscribed to any socket. The default behavior of these function is to report error in this case. * `SRT_EPOLL_ENABLE_OUTPUTCHECK`: Forces the [`srt_epoll_wait`](#srt_epoll_wait) and [`srt_epoll_uwait`](#srt_epoll_uwait) functions to check if the output array is not empty. For [`srt_epoll_wait`](#srt_epoll_wait) it is still allowed that either system or user array is empty, as long as EID isn't subscribed to this type of socket/fd. [`srt_epoll_uwait`](#srt_epoll_uwait) only checks if the general output array is not empty. **Arguments**: * `eid`: the epoll container id * `flags`: a nonzero set of the above flags, or special values: * 0: clear all flags (set all defaults) * -1: do not modify any flags | Returns | | |:----------------------------- |:-------------------------------------------------------------------------- | | | This function returns the state of the flags at the time before the call | | -1 | Special value in case when an error occurred | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_epoll_release ``` int srt_epoll_release(int eid); ``` Deletes the epoll container. | Returns | | |:----------------------------- |:-------------------------------------------------------------- | | | The number (\>0) of ready sockets, of whatever kind (if any) | | -1 | Error | | | | | Errors | | |:----------------------------------- |:----------------------------------------------------------------- | | [`SRT_EINVPOLLID`](#srt_einvpollid) | [`eid`](#eid) parameter doesn't refer to a valid epoll container | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Logging Control * [srt_setloglevel](#srt_setloglevel) * [srt_addlogfa, srt_dellogfa, srt_resetlogfa](#srt_addlogfa-srt_dellogfa-srt_resetlogfa) * [srt_setloghandler](#srt_setloghandler) * [srt_setlogflags](#srt_setlogflags) SRT has a widely used system of logs, as this is usually the only way to determine how the internals are working without changing the rules by the act of tracing. Logs are split into levels (5 levels out of those defined by syslog are in use) and additional filtering is possible on an FA (functional area). By default only entries up to the *Note* log level are displayed and from all FAs. Logging can only be manipulated globally, with no regard to a specific socket. This is because lots of operations in SRT are not dedicated to any particular socket, and some are shared between sockets. ### srt_setloglevel ``` void srt_setloglevel(int ll); ``` Sets the minimum severity for logging. A particular log entry is displayed only if it has a severity greater than or equal to the minimum. Setting this value to `LOG_DEBUG` turns on all levels. The constants for this value are those from `` (for Windows, refer to `common/win/syslog_defs.h`). The only meaningful ones are: * `LOG_DEBUG`: Highly detailed and very frequent messages * `LOG_NOTICE`: Occasionally displayed information * `LOG_WARNING`: Unusual behavior * `LOG_ERR`: Abnormal behavior * `LOG_CRIT`: Error that makes the current socket unusable [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_addlogfa ### srt_dellogfa ### srt_resetlogfa ```c++ void srt_addlogfa(int fa); void srt_dellogfa(int fa); void srt_resetlogfa(const int* fara, size_t fara_size); ``` A functional area (FA) is an additional filtering mechanism for logging. You can set up logging to display logs only from selected FAs. The list of FAs is collected in the `srt.h` file, as identified by the `SRT_LOGFA_` prefix. They are not enumerated here because they may be changed very often. All FAs are turned on by default, except potentially dangerous ones (such as `SRT_LOGFA_HAICRYPT`). The reason is that they may display either some security information that shall remain in memory only (so, only if strictly required for development), or some duplicated information (so you may want to turn one FA on, while turning off the others). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_setloghandler ```c++ void srt_setloghandler(void* opaque, SRT_LOG_HANDLER_FN* handler); typedef void SRT_LOG_HANDLER_FN(void* opaque, int level, const char* file, int line, const char* area, const char* message); ``` By default logs are printed to standard error stream. This function replaces the sending to a stream with a handler function that will receive them. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_setlogflags ```c++ void srt_setlogflags(int flags); ``` When you set a log handler with [`srt_setloghandler`](#srt_setloghandler), you may also want to configure which parts of the log information you do not wish to be passed in the log line (the `message` parameter). A user's logging facility may, for example, not wish to get the current time or log level marker, as it will provide this information on its own. The following flags are available, as collected in the `logging_api.h` public header: - `SRT_LOGF_DISABLE_TIME`: Do not provide the time in the header - `SRT_LOGF_DISABLE_THREADNAME`: Do not provide the thread name in the header - `SRT_LOGF_DISABLE_SEVERITY`: Do not provide severity information in the header - `SRT_LOGF_DISABLE_EOL`: Do not add the end-of-line character to the log line [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Time Access * [srt_time_now](#srt_time_now) * [srt_connection_time](#srt_connection_time) The following set of functions is intended to retrieve timestamps from the clock used by SRT. The sender can pass the timestamp in `MSGCTRL::srctime` of the `srt_sendmsg2(..)` function together with the packet being submitted to SRT. If the `srctime` value is not provided (the default value of 0 is set), SRT will use the internal clock and assign packet submission time as the packet timestamp. If the sender wants to explicitly assign a timestamp to a certain packet this timestamp MUST be taken from SRT Time Access functions. The time value provided MUST equal or exceed the connection start time (`srt_connection_time(..)`) of the SRT socket passed to `srt_sendmsg2(..)`. The current time value of the SRT internal clock can be retrieved using the `srt_time_now()` function. There are two known cases where you might want to use `srctime`: 1. SRT passthrough (for stream gateways). You may wish to simply retrieve packets from an SRT source and pass them transparently to an SRT output (possibly re-encrypting). In that case, every packet you read should preserve the original value of `srctime` as obtained from [`srt_recvmsg2`](#srt_recvmsg2), and the original `srctime` for each packet should be then passed to [`srt_sendmsg2`](#srt_sendmsg). This mechanism could be used to avoid jitter resulting from varying differences between the time of receiving and sending the same packet. 2. Stable timing source. In the case of a live streaming procedure, when spreading packets evenly into the stream, you might want to predefine times for every single packet to keep time intervals perfectly equal. Or, if you believe that your input signal delivers packets at the exact times that should be assigned to them, you might want to preserve these times at the SRT receiving side to avoid jitter that may result from varying time differences between the packet arrival and the moment when sending it over SRT. In such cases you might do the following: - At the packet arrival time, grab the current time at that moment using `srt_time_now()`. - When you want a pre-calculated packet time, use a private relative time counter set at the moment when the connection was made. From the moment when your first packet is ready, start pre-calculating packet times relative to the connection start time obtained from `srt_connection_time()`. Although you still have to synchronize sending times with these predefined times, by explicitly specifying the source time you avoid the jitter resulting from a lost accuracy due to waiting time and unfortunate thread scheduling. Note that `srctime` uses an internally defined clock that is intended to be monotonic (the definition depends on the build flags, see below). Because of that **the application should not define this time basing on values obtained from the system functions for getting the current system time** (such as `time`, `ftime` or `gettimeofday`). To avoid problems and misunderstanding you should rely exclusively on time values provided by the `srt_time_now()` and `srt_connection_time()` functions. The clock used by the SRT internal clock is determined by the following build flags: - `ENABLE_MONOTONIC` makes use of `CLOCK_MONOTONIC` with `clock_gettime` function. - `ENABLE_STDXXX_SYNC` makes use of `std::chrono::steady_clock`. The default is currently to use the system clock as the internal SRT clock, although it's highly recommended to use one of the above monotonic clocks, as system clock is vulnerable to time modifications during transmission. ### srt_time_now ```c++ int64_t srt_time_now(); ``` Get time in microseconds elapsed since epoch using SRT internal clock (steady or monotonic clock). | Returns | | |:----------------------------- |:------------------------------------------------------------------------ | | | Current time in microseconds elapsed since epoch of SRT internal clock. | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_connection_time ```c++ int64_t srt_connection_time(SRTSOCKET sock); ``` Get connection time in microseconds elapsed since epoch using SRT internal clock (steady or monotonic clock). The connection time represents the time when SRT socket was open to establish a connection. Milliseconds elapsed since connection start time can be determined using [**Performance tracking**](#Performance-tracking) functions and `msTimeStamp` value of the `SRT_TRACEBSTATS` (see [SRT Statistics](statistics.md)). | Returns | | |:----------------------------- |:--------------------------------------------------------------------------- | | | Connection time in microseconds elapsed since epoch of SRT internal clock | | -1 | Error | | | | | Errors | | |:--------------------------------- |:---------------------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket `sock` is not an ID of a valid SRT socket | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_clock_type ```c int srt_clock_type(void); ``` Get the type of clock used internally by SRT to be used only for informational purposes. Using any time source except for [`srt_time_now()`](#srt_time_now) and [`srt_connection_time(SRTSOCKET)`](#srt_connection_time) to timestamp packets submitted to SRT is not recommended and must be done with awareness and at your own risk. | Returns | Clock Type | Description | | :------ | :---------------------------------- | :------------------------------------------| | 0 | `SRT_SYNC_CLOCK_STDCXX_STEADY` | C++11 `std::chrono::steady_clock` | | 1 | `SRT_SYNC_CLOCK_GETTIME_MONOTONIC` | `clock_gettime` with `CLOCK_MONOTONIC` | | 2 | `SRT_SYNC_CLOCK_WINQPC` | Windows `QueryPerformanceCounter(..)` | | 3 | `SRT_SYNC_CLOCK_MACH_ABSTIME` | `mach_absolute_time()` | | 4 | `SRT_SYNC_CLOCK_POSIX_GETTIMEOFDAY` | POSIX `gettimeofday(..)` | | 5 | `SRT_SYNC_CLOCK_AMD64_RDTSC` | `asm("rdtsc" ..)` | | 6 | `SRT_SYNC_CLOCK_IA32_RDTSC` | `asm volatile("rdtsc" ..)` | | 7 | `SRT_SYNC_CLOCK_IA64_ITC` | `asm("mov %0=ar.itc" ..)` | | Errors | | |:--------------------------------- |:---------------------------------------------------------- | | None | | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ## Diagnostics * [srt_getlasterror_str](#srt_getlasterror_str) * [srt_getlasterror](#srt_getlasterror) * [srt_strerror](#srt_strerror) * [srt_clearlasterror](#srt_clearlasterror) * [srt_getrejectreason](#srt_getrejectreason) * [srt_rejectreason_str](#srt_rejectreason_str) * [srt_setrejectreason](#srt_setrejectreason) General notes concerning the `getlasterror` diagnostic functions: when an API function ends up with error, this error information is stored in a thread-local storage. This means that you'll get the error of the operation that was last performed as long as you call this diagnostic function just after the failed function has returned. In any other situation the information provided by the diagnostic function is undefined. **NOTE**: There are lists of rejection reasons and error codes at the bottom of this section. ### srt_getlasterror ``` int srt_getlasterror(int* errno_loc); ``` Get the numeric code of the last error. Additionally, in the variable passed as `errno_loc` the system error value is returned, or 0 if there was no system error associated with the last error. The system error is: * On POSIX systems, the value from `errno` * On Windows, the result from `GetLastError()` call [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_strerror ``` const char* srt_strerror(int code, int errnoval); ``` Returns a string message that represents a given SRT error code and possibly the `errno` value, if not 0. **NOTE:** *This function isn't thread safe. It uses a static variable to hold the error description. There's no problem with using it in a multithreaded environment, as long as only one thread in the whole application calls this function at the moment* [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getlasterror_str ``` const char* srt_getlasterror_str(void); ``` Get the text message for the last error. It's a shortcut to calling first `srt_getlasterror` and then passing the returned value into [`srt_strerror`](#srt_strerror). Note that, contrary to [`srt_strerror`](#srt_strerror), this function is thread safe. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_clearlasterror ``` void srt_clearlasterror(void); ``` This function clears the last error. After this call, `srt_getlasterror` will report a "successful" code. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_rejectreason_str ``` const char* srt_rejectreason_str(enum SRT_REJECT_REASON id); ``` Returns a constant string for the reason of the connection rejected, as per given code ID. It provides a system-defined message for values below `SRT_REJ_E_SIZE`. For other values below `SRT_REJC_PREDEFINED` it returns the string for [`SRT_REJ_UNKNOWN`](#SRT_REJ_UNKNOWN). For values since `SRT_REJC_PREDEFINED` on, returns "Application-defined rejection reason". The actual messages assigned to the internal rejection codes, that is, less than `SRT_REJ_E_SIZE`, can be also obtained from the `srt_rejectreason_msg` array. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_setrejectreason ``` int srt_setrejectreason(SRTSOCKET sock, int value); ``` Sets the rejection code on the socket. This call is only useful in the listener callback. The code from `value` set this way will be set as a rejection reason for the socket. After the callback rejects the connection, the code will be passed back to the caller peer with the handshake response. Note that allowed values for this function begin with `SRT_REJC_PREDEFINED` (that is, you cannot set a system rejection code). For example, your application can inform the calling side that the resource specified under the `r` key in the StreamID string (see [`SRTO_STREAMID`](API-socket-options.md#SRTO_STREAMID)) is not available - it then sets the value to `SRT_REJC_PREDEFINED + 404`. | Returns | | |:----------------------------- |:--------------------------------------------------------- | | 0 | Error | | -1 | Success | | | | | Errors | | |:--------------------------------- |:-------------------------------------------- | | [`SRT_EINVSOCK`](#srt_einvsock) | Socket `sock` is not an ID of a valid socket | | [`SRT_EINVPARAM`](#srt_einvparam) | `value` is less than `SRT_REJC_PREDEFINED` | | | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### srt_getrejectreason ``` int srt_getrejectreason(SRTSOCKET sock); ``` This function provides a more detailed reason for a failed connection attempt. It shall be called after a connecting function (such as [`srt_connect`](#srt_connect)) has returned an error, the code for which is [`SRT_ECONNREJ`](#srt_econnrej). If [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) has been set on the socket used for the connection, the function should also be called when the [`SRT_EPOLL_ERR`](#SRT_EPOLL_ERR) event is set for this socket. It returns a numeric code, which can be translated into a message by [`srt_rejectreason_str`](#srt_rejectreason_str). [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### Rejection Reasons #### SRT_REJ_UNKNOWN A fallback value for cases when there was no connection rejected. #### SRT_REJ_SYSTEM One system function reported a failure. Usually this means some system error or lack of system resources to complete the task. #### SRT_REJ_PEER The connection has been rejected by peer, but no further details are available. This usually means that the peer doesn't support rejection reason reporting. #### SRT_REJ_RESOURCE A problem with resource allocation (usually memory). #### SRT_REJ_ROGUE The data sent by one party to another cannot be properly interpreted. This should not happen during normal usage, unless it's a bug, or some weird events are happening on the network. #### SRT_REJ_BACKLOG The listener's backlog has exceeded its queue limit (there are many other callers waiting for the opportunity of being connected and wait in the queue, which has reached its limit). #### SRT_REJ_IPE Internal Program Error. This should not happen during normal usage and it usually means a bug in the software (although this can be reported by both local and foreign host). #### SRT_REJ_CLOSE The listener socket was able to receive your request, but at this moment it is being closed. It's likely that your next attempt will result in a timeout. #### SRT_REJ_VERSION One party of the connection has set up a minimum version that is required for that connection, but the other party didn't satisfy this requirement. #### SRT_REJ_RDVCOOKIE Rendezvous cookie collision. This normally should never happen, or the probability that it will happen is negligible. However this can also be a result of a misconfiguration in that you are trying to make a rendezvous connection where both parties try to bind to the same IP address, or both are local addresses of the same host. In such a case the sent handshake packets are returning to the same host as if they were sent by the peer (i.e. a party is sending to itself). When this happens, this reject reason will be reported by every attempt. #### SRT_REJ_BADSECRET Both parties have defined a passphrase for connection, but they differ. #### SRT_REJ_UNSECURE Only one connection party has set up a password. See also the [`SRTO_ENFORCEDENCRYPTION`](API-socket-options.md#SRTO_ENFORCEDENCRYPTION) flag. #### SRT_REJ_MESSAGEAPI The value of the [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag is different on both connection parties. #### SRT_REJ_CONGESTION The [`SRTO_CONGESTION`](API-socket-options.md#SRTO_CONGESTION)option has been set up differently on both connection parties. #### SRT_REJ_FILTER The [`SRTO_PACKETFILTER`](API-socket-options.md#SRTO_PACKETFILTER) option has been set differently on both connection parties. #### SRT_REJ_GROUP The group type or some group settings are incompatible for both connection parties. While every connection within a bonding group may have different target addresses, they should all designate the same endpoint and the same SRT application. If this condition isn't satisfied, then the peer will respond with a different peer group ID for the connection that is trying to contact a machine/application that is completely different from the existing connections in the bonding group. #### SRT_REJ_TIMEOUT The connection wasn't rejected, but it timed out. This code is always set on connection timeout, but this is the only way to get this state in non-blocking mode (see [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN)). There may also be server and user rejection codes, as defined by the `SRT_REJC_INTERNAL`, `SRT_REJC_PREDEFINED` and `SRT_REJC_USERDEFINED` constants. Note that the number space from the value of `SRT_REJC_PREDEFINED` 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. [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) --- ### Error Codes All functions that return the status via `int` value return -1 (designated as `SRT_ERROR`) always when the call has failed (in case of resource creation functions an appropriate symbol is defined, like `SRT_INVALID_SOCK` for `SRTSOCKET`). When this happens, the error code can be obtained from the `srt_getlasterror` function. The values for the error are collected in an `SRT_ERRNO` enum: #### SRT_EUNKNOWN Internal error when setting the right error code. #### SRT_SUCCESS The value set when the last error was cleared and no error has occurred since then. #### SRT_ECONNSETUP General setup error resulting from internal system state. #### SRT_ENOSERVER Connection timed out while attempting to connect to the remote address. Note that when this happens, [`srt_getrejectreason`](#srt_getrejectreason) also reports the timeout reason. #### SRT_ECONNREJ Connection has been rejected. Additional reject reason can be obtained through [`srt_getrejectreason`](#srt_getrejectreason) (see above). #### SRT_ESOCKFAIL An error occurred when trying to call a system function on an internally used UDP socket. Note that the detailed system error is available in the extra variable passed by pointer to `srt_getlasterror`. #### SRT_ESECFAIL A possible tampering with the handshake packets was detected, or an encryption request wasn't properly fulfilled. #### SRT_ESCLOSED A socket that was vital for an operation called in blocking mode has been closed during the operation. Please note that this situation is handled differently than the system calls for `connect` and `accept` functions for TCP, which simply block indefinitely (or until the standard timeout) when the key socket was closed during an operation. When this error is reported, it usually means that the socket passed as the first parameter to [`srt_connect*`](#srt_connect) or [`srt_accept`](#srt_accept) is no longer usable. #### SRT_ECONNFAIL General connection failure of unknown details. #### SRT_ECONNLOST The socket was properly connected, but the connection has been broken. This specialization is reported from the transmission functions. #### SRT_ENOCONN The socket is not connected. This can be reported also when the connection was broken for a function that checks some characteristic socket data. #### SRT_ERESOURCE System or standard library error reported unexpectedly for unknown purpose. Usually it means some internal error. #### SRT_ETHREAD System was unable to spawn a new thread when required. #### SRT_ENOBUF System was unable to allocate memory for buffers. #### SRT_ESYSOBJ System was unable to allocate system specific objects (such as sockets, mutexes or condition variables). #### SRT_EFILE General filesystem error (for functions operating with file transmission). #### SRT_EINVRDOFF Failure when trying to read from a given position in the file (file could be modified while it was read from). #### SRT_ERDPERM Read permission was denied when trying to read from file. #### SRT_EINVWROFF Failed to set position in the written file. #### SRT_EWRPERM Write permission was denied when trying to write to a file. #### SRT_EINVOP Invalid operation performed for the current state of a socket. This mainly concerns performing `srt_bind*` operations on a socket that is already bound. Once a socket has been been bound, it cannot be bound again. #### SRT_EBOUNDSOCK The socket is currently bound and the required operation cannot be performed in this state. Usually it's about an option that can only be set on the socket before binding (`srt_bind*`). Note that a socket that is currently connected is also considered bound. #### SRT_ECONNSOCK The socket is currently connected and therefore performing the required operation is not possible. Usually concerns setting an option that must be set before connecting (although it is allowed to be altered after binding), or when trying to start a connecting operation ([`srt_connect*`](#srt_connect)) while the socket isn't in a state that allows it (only [`SRTS_INIT`](#SRTS_INIT) or [`SRTS_OPENED`](#SRTS_OPENED) are allowed). #### SRT_EINVPARAM This error is reported in a variety of situations when call parameters for API functions have some requirements defined and these were not satisfied. This error should be reported after an initial check of the parameters of the call before even performing any operation. This error can be easily avoided if you set the values correctly. #### SRT_EINVSOCK The API function required an ID of an entity (socket or group) and it was invalid. Note that some API functions work only with socket or only with group, so they would also return this error if inappropriate type of entity was passed, even if it was valid. #### SRT_EUNBOUNDSOCK The operation to be performed on a socket requires that it first be explicitly bound (using [`srt_bind*`](#srt_bind) functions). Currently it applies when calling [`srt_listen`](#srt_listen), which cannot work with an implicitly bound socket. #### SRT_ENOLISTEN The socket passed for the operation is required to be in the listen state ([`srt_listen`](#srt_listen) must be called first). #### SRT_ERDVNOSERV The required operation cannot be performed when the socket is set to rendezvous mode ([`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) set to true). Usually applies when trying to call [`srt_listen`](#srt_listen) on such a socket. #### SRT_ERDVUNBOUND An attempt was made to connect to a socket set to rendezvous mode ([`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) set to true) that was not first bound. A rendezvous connection requires setting up two addresses and ports on both sides of the connection, then setting the local one with [`srt_bind`](#srt_bind) and using the remote one with [`srt_connect`](#srt_connect) (or you can simply use [`srt_rendezvous`](#srt_rendezvous)). Calling [`srt_connect*`](#srt_connect) on an unbound socket (in [`SRTS_INIT`](#SRTS_INIT) state) that is to be bound implicitly is only allowed for regular caller sockets (not rendezvous). #### SRT_EINVALMSGAPI The function was used incorrectly in the message API. This can happen if: * The parameters specific for the message API in [`SRT_MSGCTRL`](#SRT_MSGCTRL) type parameter were incorrectly specified. * The extra parameter check performed by the congestion controller has failed. * The socket is a member of a self-managing group, therefore you should perform the operation on the group, not on this socket. #### SRT_EINVALBUFFERAPI The function was used incorrectly in the stream (buffer) API, that is, either the stream-only functions were used with set message API ([`srt_sendfile`](#srt_sendfile)/[`srt_recvfile`](#srt_recvfile)) or TSBPD mode was used with buffer API ([`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) set to true) or the congestion controller has failed to check call parameters. #### SRT_EDUPLISTEN The port tried to be bound for listening is already busy. Note that binding to the same port is allowed in general (when [`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS) is true on every socket that has bound it), but only one such socket can be a listener. #### SRT_ELARGEMSG Size exceeded. This is reported in the following situations: * Trying to receive a message, but the read-ready message is larger than the buffer passed to the receiving function. * Trying to send a message, but the size of this message exceeds the size of the preset sender buffer, so it cannot be stored in the sender buffer. * When getting group data, the array to be filled is too small. #### SRT_EINVPOLLID The epoll ID passed to an epoll function is invalid. #### SRT_EPOLLEMPTY The epoll container currently has no subscribed sockets. This is reported by an epoll waiting function that would in this case block forever. This problem might be reported both in a situation where you have created a new epoll container and didn't subscribe any sockets to it, or you did, but these sockets have been closed (including when closed in a separate thread while the waiting function was blocking). Note that this situation can be prevented by setting the `SRT_EPOLL_ENABLE_EMPTY` flag, which may be useful when you use multiple threads and start waiting without subscribed sockets, so that you can subscribe them later from another thread. #### `SRT_EBINDCONFLICT` The binding you are attempting to set up a socket with cannot be completed because it conflicts with another existing binding. This is because an intersecting binding was found that cannot be reused according to the specification in `srt_bind` call. A binding is considered intersecting if the existing binding has the same port and covers at least partially the range as that of the attempted binding. These ranges can be split in three groups: 1. An explicitly specified IP address (both IPv4 and IPv6) covers this address only. 2. An IPv4 wildcard 0.0.0.0 covers all IPv4 addresses (but not IPv6). 3. An IPv6 wildcard :: covers: * if `SRTO_IPV6ONLY` is true - all IPv6 addresses (but not IPv4) * if `SRTO_IPV6ONLY` is false - all IP addresses. Example 1: * Socket 1: bind to IPv4 0.0.0.0 * Socket 2: bind to IPv6 :: with `SRTO_IPV6ONLY` = true * Result: NOT intersecting Example 2: * Socket 1: bind to IPv4 1.2.3.4 * Socket 2: bind to IPv4 0.0.0.0 * Result: intersecting (and conflicting) Example 3: * Socket 1: bind to IPv4 1.2.3.4 * Socket 2: bind to IPv6 :: with `SRTO_IPV6ONLY` = false * Result: intersecting (and conflicting) If any common range coverage is found between the attempted binding specification (in `srt_bind` call) and the found existing binding with the same port number, then all of the following conditions must be satisfied between them: 1. The `SRTO_REUSEADDR` must be true (default) in both. 2. The IP address specification (in case of IPv6, also including the value of `SRTO_IPV6ONLY` flag) must be exactly identical. 3. The UDP-specific settings must be identical. If any of these conditions isn't satisfied, the `srt_bind` function results in conflict and report this error. #### SRT_EASYNCFAIL General asynchronous failure (not in use currently). #### SRT_EASYNCSND Sending operation is not ready to perform. This error is reported when trying to perform a sending operation on a socket that is not ready for sending, but [`SRTO_SNDSYN`](API-socket-options.md#SRTO_SNDSYN) was set to false (when true, the function would block the call otherwise). #### SRT_EASYNCRCV Receiving operation is not ready to perform. This error is reported when trying to perform a receiving operation or accept a new socket from the listener socket, when the socket is not ready for that operation, but [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN) was set to false (when true, the function would block the call otherwise). #### SRT_ETIMEOUT The operation timed out. This can happen if you have a timeout set by an option ([`SRTO_RCVTIMEO`](API-socket-options.md#SRTO_RCVTIMEO) or [`SRTO_SNDTIMEO`](API-socket-options.md#SRTO_SNDTIMEO)), or passed as an extra argument ([`srt_epoll_wait`](#srt_epoll_wait) or [`srt_accept_bond`](#srt_accept_bond)) and the function call was blocking, but the required timeout time has passed. #### SRT_ECONGEST **NOTE**: This error is used only in an experimental version that requires setting the `SRT_ENABLE_ECN` macro at compile time. Otherwise the situation described below results in the usual successful report. This error should be reported by the sending function when, with [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) and [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP) set to true, some packets were dropped at the sender side (see the description of [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP) for details). This doesn't concern the data that were passed for sending by the sending function (these data are placed at the back of the sender buffer, while the dropped packets are at the front). In other words, the operation done by the sending function is successful, but the application might want to slow down the sending rate to avoid congestion. #### SRT_EPEERERR This error is reported when a receiver peer is writing to a file that an agent is sending. When the peer encounters an error when writing the received data to a file, it sends the `UMSG_PEERERROR` message back to the sender, and the sender reports this error from the API sending function. [Return to Top of Page](#SRT-API-Functions) srt-1.5.4/docs/API/API-socket-options.md000066400000000000000000002564541471311275400176310ustar00rootroot00000000000000# SRT API Socket Options There is a general method of setting options on a socket in the SRT C API, similar to the system `setsockopt/getsockopt` functions. - [Types Used in Socket Options](#types-used-in-socket-options) - [Getting and Setting Options](#getting-and-setting-options) - [List of Options](#list-of-options) ## Types Used in Socket Options Possible types of socket options are: - `int32_t` - a 32-bit integer. On most systems similar to `int`. In some cases the value is expressed using an enumeration type (see [Enumeration types...](#enumeration_types) section below). - `int64_t` - a 64-bit integer. - `bool` - a Boolean type (`` for C, or built-in for C++). When *setting* an option, passing the value through an `int` type is also properly recognized. When *getting* an option, however, the`bool` type should be used. It is also possible to pass a variable of `int` type initialized with 0 and then comparing the resulting value with 0 (just don't compare the result with 1 or `true`). - `string` - a C string. When *setting* an option, a `const char*` character array pointer is expected to be passed in `optval` and the array length in `optlen` **without the terminating NULL character**. When *getting*, an array is expected to be passed in `optval` with a sufficient size **with an extra space for the terminating NULL character** provided in `optlen`. The return value of `optlen` does not count the terminating NULL character. - `linger` - Linger structure. Used exclusively with `SRTO_LINGER`. ### Enumeration Types Used in Options #### `SRT_TRANSTYPE` Used by `SRTO_TRANSTYPE` option: - `SRTT_LIVE`: Live mode. - `SRTT_FILE`: File mode. See [Transmission Types](API.md#transmission-types) for details. #### `SRT_KM_STATE` The defined encryption state as performed by the Key Material Exchange, used by `SRTO_RCVKMSTATE`, `SRTO_SNDKMSTATE` and `SRTO_KMSTATE` options: - `SRT_KM_S_UNSECURED` (`0`): no encryption/decryption. If this state is only on the receiver, received encrypted packets will be dropped. - `SRT_KM_S_SECURING`(`1`): pending security (HSv4 only). This is a temporary state used only if the connection uses HSv4 and the Key Material Exchange is not finished yet. On HSv5 this is not possible because the Key Material Exchange for the initial key is done in the handshake. - `SRT_KM_S_SECURED` (`2`): KM exchange was successful and the data will be sent encrypted and will be decrypted by the receiver. This state is only possible on both sides in both directions simultaneously. Any unencrypted packet will be dropped by the receiver. - `SRT_KM_S_NOSECRET` (`3`): If this state is in the sending direction (`SRTO_SNDKMSTATE`), then it means that the sending party has set a passphrase, but the peer did not. In this case the sending party can receive unencrypted packets from the peer, but packets it sends to the peer will be encrypted and the peer will not be able to decrypt them. This state is only possible in HSv5. - `SRT_KM_S_BADSECRET` (`4`): The password is wrong (set differently on each party); encrypted payloads won't be decrypted in either direction. - `SRT_KM_S_BADCRYPTOMODE` (`5`): The crypto mode mode configuration is either not supported or mismatches the configuration of the peer. Note that with the default value of `SRTO_ENFORCEDENCRYPTION` option (true), the state is equal on both sides in both directions, and it can be only `SRT_KM_S_UNSECURED` or `SRT_KM_S_SECURED` (in other cases the connection is rejected). Otherwise it may happen that either both sides have different passwords and the state is `SRT_KM_S_BADSECRET` in both directions, or only one party has set a password, in which case the KM state is as follows: | | `SRTO_RCVKMSTATE` | `SRTO_SNDKMSTATE` | |--------------------------|----------------------|----------------------| | Party with no password: | `SRT_KM_S_NOSECRET` | `SRT_KM_S_UNSECURED` | | Party with password: | `SRT_KM_S_UNSECURED` | `SRT_KM_S_NOSECRET` | ## Getting and Setting Options Legacy version: int srt_getsockopt(SRTSOCKET socket, int level, SRT_SOCKOPT optName, void* optval, int& optlen); int srt_setsockopt(SRTSOCKET socket, int level, SRT_SOCKOPT optName, const void* optval, int optlen); New version: int srt_getsockflag(SRTSOCKET socket, SRT_SOCKOPT optName, void* optval, int& optlen); int srt_setsockflag(SRTSOCKET socket, SRT_SOCKOPT optName, const void* optval, int optlen); In the legacy version, there's an additional unused `level` parameter. It was there in the original UDT API just to mimic the system `setsockopt` function, but it's ignored. Some options require a value of type `bool` while others require type `integer`, which is not the same -- they differ in size, and mistaking them may end up causing a crash. This must be kept in mind especially in any C wrapper. For convenience, the *setting* option function may accept both `int32_t` and `bool` types, but this is not so in the case of *getting* an option value. **UDT project legacy note**: Almost all options from the UDT library are derived (there are a few deleted, including some deprecated already in UDT). Many new SRT options have been added. All options are available exclusively with the `SRTO_` prefix. Old names are provided as alias names in the `udt.h` legacy/C++ API file. Note the translation rules: * `UDT_` prefix from UDT options was changed to the prefix `SRTO_` * `UDP_` prefix from UDT options was changed to the prefix `SRTO_UDP_` * `SRT_` prefix in older SRT versions was changed to `SRTO_` The [table below](#list-of-options) provides a complete list of SRT options and their characteristics according to the following legend: 1. **Since**: Defines the SRT version when this option was first introduced. If this field is empty, it's an option derived from UDT. "Version 0.0.0" is the oldest version of SRT ever created and put into use. 2. **Restrict**: Defines restrictions on setting the option. The field is empty if the option is not settable (see **Dir** column): - `pre-bind`: The option cannot be altered on a socket that is already bound (by calling `srt_bind()` or any other function doing this, including automatic binding when trying to connect, as well as accepted sockets). In other words, once an SRT socket has transitioned from `SRTS_INIT` to `SRTS_OPENED` socket state. - `pre`: The option cannot be altered on a socket that is in `SRTS_LISTENING`, `SRTS_CONNECTING` or `SRTS_CONNECTED` state. If an option was set on a listener socket, it will be inherited by a socket returned by `srt_accept()` (except for `SRTO_STREAMID`). - `post`: The option is unrestricted and can be altered at any time, including when the socket is connected, as well as on an accepted socket. The setting of this flag on a listening socket is usually derived by the accepted socket, but this isn't a rule for all options. Note though that there are some unrestricted options that have an important meaning when set prior to connecting (different one than for a connected socket). **NOTE**: The `pre-bind` characteristic applies exclusively to options that: - Change the behavior and functionality of the `srt_bind` call - Concern or set an option on the internally used UDP socket - Concern any kind of resource used by the multiplexer 3. **Type**: The data type of the option (see above). 4. **Units**: Roughly specified unit, if the value defines things like length or time. It can also define more precisely what kind of specialization can be used when the type is integer: - `enum`: the possible values are defined in an enumeration type - `flags`: the integer value is a collection of bit flags - `B/s` - bytes per second. 5. **Default**: The exact default value, if it can be easily specified. A more complicated default state of a particular option will be explained in the [description](#option-descriptions) (when marked by asterisk). For non-settable options this field is empty. 6. **Range**: If a value of an integer type has a limited range, or only a certain value allowed, it will be specified here (otherwise empty). A range value can be specified as: - `X-... `: specifies only a minimum value - `X-Y,Z `: values between X and Y are allowed, and additionally Z - If the value is of `string` type, this field will contain its maximum size in square brackets. - If the range contains additionally an asterisk, it means that more elaborate restrictions on the value apply, as explained in the [description](#option-descriptions). 7. **Dir**: Option direction: W if can be set, R if can be retrieved, RW if both. 8. **Entity**: This describes whether the option can be set on the socket or the group. The G and S options may appear together, in which case both possibilities apply. The D and I options, mutually exclusive, appear always with G. The + marker can only coexist with GS. Possible specifications are: - S: This option can be set on a single socket (exclusively, if not GS) - G: This option can be set on a group (exclusively, if not GS) - D: If set on a group, it will be derived by the member socket - I: If set on a group, it will be taken and managed exclusively by the group - +: This option is also allowed to be set individually on a group member socket through a configuration object in `SRT_SOCKGROUPCONFIG` prepared by `srt_create_config`. Note that this setting may override the setting derived from the group. ## List of Options The following table lists SRT API socket options in alphabetical order. Option details are given further below. | 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.5.2 | pre | `int32_t` | | 0 (Auto) | [0, 2] | W | GSD | | [`SRTO_DRIFTTRACER`](#SRTO_DRIFTTRACER) | 1.4.2 | post | `bool` | | true | | RW | GSD | | [`SRTO_ENFORCEDENCRYPTION`](#SRTO_ENFORCEDENCRYPTION) | 1.3.2 | pre | `bool` | | true | | W | GSD | | [`SRTO_EVENT`](#SRTO_EVENT) | | | `int32_t` | flags | | | R | S | | [`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_MAXREXMITBW`](#SRTO_MAXREXMITBW) | 1.5.3 | 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 #### SRTO_BINDTODEVICE | OptName | Since | Restrict | Type | Units | Default | Range | Dir |Entity| | --------------------- | ----- | -------- | -------- | ------ | -------- | ------ |-----|------| | `SRTO_BINDTODEVICE` | 1.4.2 | pre-bind | `string` | | | | RW | GSD+ | Refers to the `SO_BINDTODEVICE` system socket option for `SOL_SOCKET` level. This effectively limits the packets received by this socket to only those that are targeted to that device. The device is specified by name passed as string. The setting becomes effective after binding the socket (including default-binding when connecting). NOTE: This option is only available on Linux and available there by default. On all other platforms setting this option will always fail. NOTE: With the default system configuration, this option is only available for a process that runs as root. Otherwise the function that applies the setting (`srt_bind`, `srt_connect` etc.) will fail. [Return to list](#list-of-options) --- #### SRTO_CONGESTION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_CONGESTION` | 1.3.0 | pre | `string` | | "live" | * | W | S | The type of congestion controller used for the transmission for that socket. Its type must be exactly the same on both connecting parties, otherwise the connection is rejected - **however** you may also change the value of this option for the accepted socket in the listener callback (see `srt_listen_callback`) if an appropriate instruction was given in the Stream ID. Currently supported congestion controllers are designated as "live" and "file", which correspond to the Live and File modes. Note that it is not recommended to change this option manually, but you should rather change the whole set of options using the [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) option. [Return to list](#list-of-options) --- #### SRTO_CONNTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_CONNTIMEO` | 1.1.2 | pre | `int32_t` | msec | 3000 | 0.. | W | GSD+ | Connect timeout. This option applies to the caller and rendezvous connection modes. For the rendezvous mode (see `SRTO_RENDEZVOUS`) the effective connection timeout will be 10 times the value set with `SRTO_CONNTIMEO`. [Return to list](#list-of-options) --- #### SRTO_CRYPTOMODE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ------------------ | --------- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_CRYPTOMODE` | 1.5.2 | pre | `int32_t` | | 0 (Auto) | [0, 2] | RW | GSD | The encryption mode to be used if the [`SRTO_PASSPHRASE`](#SRTO_PASSPHRASE) is set. The feature is a part of the AEAD Preview API of SRT v1.5.2, and is disabled by default. To enable use [`ENABLE_AEAD_API_PREVIEW`](../build/build-options.md#enable_aead_api_preview) build option. Crypto modes: - `0`: SRT listener accepts any mode from the caller. SRT Caller or SRT Rendezvous effectively negotiate AES-CTR (1). - `1`: regular AES-CTR (without message integrity authentication). - `2`: AES-GCM mode with message integrity authentication (AEAD). The AES-GCM mode (2) is only allowed if TSBPD is enabled ([`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE)). Auto (0) is equivalent to AES-CTR (1) in Rendezvous and for a Caller. Once a connection is established, reading `SRTO_CRYPTOMODE` shows the negotiated crypto mode: AES-CTR (1) or AES-GCM (2). When [Listener callback](./API-functions.md##srt_listen_callback) is used, the value of `SRTO_CRYPTOMODE` read on the new SRT socket to be accepted is not yet the negotiated one. It is the value to be negotiated, and is inherited from the listener SRT socket. If a specific behavior for each individual connection request is desired based on [the user ID or anything else](../features/access-control.md), the intended behavior can be achieved by setting the `SRTO_CRYPTOMODE` on the new SRT socket to a specific value. For example, let's say the initial value set on the listener socket is Auto (0). The listener callback is called, signalling the new connection request. The user ID is extracted, and the server wants to force AES-GCM only for the connection from this specific user. In this case AES-GCM (2) can be set on the new socket. There is no way to check the crypto mode being requested by the SRT caller at this point. | Caller | Listener | Negotiated | | Rdv In-tor | Rdv Res-der | Negotiated | | ----------- | ----------- | ----------- |-| ----------- | ----------- | ----------- | | 0 (auto) | 0 (auto) | AES-CTR (1) | | 0 (auto) | 0 (auto) | AES-CTR (1) | | 0 (auto) | AES-CTR (1) | AES-CTR (1) | | 0 (auto) | AES-CTR (1) | AES-CTR (1) | | 0 (auto) | AES-GCM (2) | reject | | 0 (auto) | AES-GCM (2) | reject | | AES-CTR (1) | 0 (auto) | AES-CTR (1) | | AES-CTR (1) | 0 (auto) | AES-CTR (1) | | AES-CTR (1) | AES-CTR (1) | AES-CTR (1) | | AES-CTR (1) | AES-CTR (1) | AES-CTR (1) | | AES-CTR (1) | AES-GCM (2) | reject | | AES-CTR (1) | AES-GCM (2) | reject | | AES-GCM (2) | 0 (auto) | AES-GCM (2) | | AES-GCM (2) | 0 (auto) | reject | | AES-GCM (2) | AES-CTR (1) | reject | | AES-GCM (2) | AES-CTR (1) | reject | | AES-GCM (2) | AES-GCM (2) | AES-GCM (2) | | AES-GCM (2) | AES-GCM (2) | AES-GCM (2) | * Rdv - Rendezvous; In-tor - initiator; Res-der - responder. [Return to list](#list-of-options) --- #### SRTO_DRIFTTRACER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_DRIFTTRACER`| 1.4.2 | post | `bool` | | true | | RW | GSD | Enables or disables time drift tracer (receiver). [Return to list](#list-of-options) --- #### SRTO_ENFORCEDENCRYPTION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_ENFORCEDENCRYPTION` | 1.3.2 | pre | `bool` | | true | | W | GSD | This option enforces that both connection parties have the same passphrase set, or both do not set the passphrase, otherwise the connection is rejected. When this option is set to FALSE **on both connection parties**, the connection is allowed even if the passphrase differs on both parties, or it was set only on one party. Note that the party that has set a passphrase is still allowed to send data over the network. However, the receiver will not be able to decrypt that data and will not deliver it to the application. The party that has set no passphrase can send (unencrypted) data that will be successfully received by its peer. This option can be used in some specific situations when the user knows both parties of the connection, so there's no possible situation of a rogue sender and can be useful in situations where it is important to know whether a connection is possible. The inability to decrypt an incoming transmission can be then reported as a different kind of problem. **IMPORTANT**: There is unusual and unobvious behavior when this flag is TRUE on the caller and FALSE on the listener, and the passphrase was mismatched. On the listener side the connection will be established and broken right after, resulting in a short-lived "spurious" connection report on the listener socket. This way, a socket will be available for retrieval from an `srt_accept` call for a very short time, after which it will be removed from the listener backlog just as if no connection attempt was made at all. If the application is fast enough to react on an incoming connection, it will retrieve it, only to learn that it is already broken. This also makes possible a scenario where `SRT_EPOLL_IN` is reported on a listener socket, but then an `srt_accept` call reports an `SRT_EASYNCRCV` error. How fast the connection gets broken depends on the network parameters -- in particular, whether the `UMSG_SHUTDOWN` message sent by the caller is delivered (which takes one RTT in this case) or missed during the interval from its creation up to the connection timeout (default = 5 seconds). It is therefore strongly recommended that you only set this flag to FALSE on the listener when you are able to ensure that it is also set to FALSE on the caller side. [Return to list](#list-of-options) --- #### SRTO_EVENT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_EVENT` | | | `int32_t` | flags | | | R | S | Returns bit flags set according to the current active events on the socket. Possible values are those defined in `SRT_EPOLL_OPT` enum (a combination of `SRT_EPOLL_IN`, `SRT_EPOLL_OUT` and `SRT_EPOLL_ERR`). [Return to list](#list-of-options) --- #### SRTO_FC | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_FC` | | pre | `int32_t` | pkts | 25600 | 32.. | RW | GSD | Flow Control limits the maximum number of packets "in flight" - payload (data) packets that were sent but reception is not yet acknowledged with an ACK control packet. It also includes data packets already received, but that can't be acknowledged due to loss of preceding data packet(s). In other words, if a data packet with sequence number `A` was lost, then acknowledgement of the following `SRTO_FC` packets is blocked until packet `A` is either successfully retransmitted or dropped by the [Too-Late Packet Drop mechanism](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-00#section-4.6). Thus the sender will have `SRTO_FC` packets in flight, and will not be allowed to send further data packets. Therefore, when establishing the value of `SRTO_FC`, it is recommend taking into consideration possible delays due to packet loss and retransmission. There is a restriction that the receiver buffer size ([SRTO_RCVBUF](#SRTO_RCVBUF)) must not be greater than `SRTO_FC` ([#700](https://github.com/Haivision/srt/issues/700)). Therefore, it is recommended to set the value of `SRTO_FC` first, and then the value of `SRTO_RCVBUF`. The default flow control window size is 25600 packets. It is approximately: - 270 Mbits of payload in the default live streaming configuration with an SRT payload size of 1316 bytes; - 300 Mbits of payload with an SRT payload size of 1456 bytes. The minimum number of packets in flight should be (assuming max payload size): `FCmin = bps / 8 × RTTsec / (MSS - 44)`, where - `bps` - is the payload bitrate of the stream in bits per second; - `RTTsec` - RTT of the network connection in seconds; - `MSS` - Maximum segment size (aka MTU), see [SRTO_MSS](#SRTO_MSS); - 44 - size of headers (20 bytes IPv4 + 8 bytes of UDP + 16 bytes of SRT packet header). To avoid blocking the sending of further packets in case of packet loss, the recommended flow control window is `FC = bps / 8 × (RTTsec + latency_sec) / (MSS - 44)`, where `latency_sec` is the receiver buffering delay ([SRTO_RCVLATENCY](#SRTO_RCVLATENCY)) **in seconds**. [Return to list](#list-of-options) --- #### SRTO_GROUPCONNECT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ | | `SRTO_GROUPCONNECT` | 1.5.0 | pre | `int32_t` | | 0 | 0...1 | W | S | When this flag is set to 1 on a listener socket, it allows this socket to accept group connections. When set to the default 0, group connections will be rejected. Keep in mind that if the `SRTO_GROUPCONNECT` flag is set to 1 (i.e. group connections are allowed) `srt_accept` may return a socket **or** a group ID. A call to `srt_accept` on a listener socket that has group connections allowed must take this into consideration. It's up to the caller of this function to make this distinction and to take appropriate action depending on the type of entity returned. When this flag is set to 1 on an accepted socket that is passed to the listener callback handler, it means that this socket is created for a group connection and it will become a member of a group. Note that in this case only the first connection within the group will result in reporting from `srt_accept` (further connections are handled in the background), and this function will return the group, not this socket ID. [Return to list](#list-of-options) --- #### SRTO_GROUPMINSTABLETIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_GROUPMINSTABLETIMEO` | 1.5.0 | pre | `int32_t` | ms | 60 | 60-... | W | GDI+ | The option is used for groups of type `SRT_GTYPE_BACKUP`. It defines the **minimum** value of the stability timeout for all active member sockets in a group. The actual timeout value is determined in runtime based on the RTT estimate of an individual member socket. If there is no response from the peer for the calculated timeout, the member is considered unstable, triggering activation of an idle backup member. The smaller the value is, the earlier a backup member might be activated to prepare transition to that path. However, it may also lead to spurious activations of backup paths. The higher the value is, the later the backup link would be activated. All unacknowledged payload packets have to be retransmitted through the backup path. If they don't reach the receiver in time, they would be dropped. Therefore, an appropriate adjustment of the SRT buffering delay (`SRTO_PEERLATENCY` on sender, `SRTO_RCVLATENCY` on receiver) should also be considered. Normally the receiver should send an ACK back to the sender every 10 ms. In the case of congestion, in the live streaming configuration of SRT a loss report is expected to be sent every RTT/2. The network jitter and increase of RTT on the public internet causes these intervals to be stretched. The default minimum value of 60 ms is selected as a general fit for most of the use cases. Please refer to the [SRT Connection Bonding: Main/Backup](../features/bonding-main-backup.md) document for more details. Note that the value of this option is not allowed to exceed the value of `SRTO_PEERIDLETIMEO`, which determines the timeout to actually break an idle (irresponsive) connection. [Return to list](#list-of-options) --- #### SRTO_GROUPTYPE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_GROUPTYPE` | 1.5.0 | | `int32_t` | enum | | | R | S | This option is read-only and it is intended to be called inside the listener callback handler (see `srt_listen_callback`). Possible values are defined in the `SRT_GROUP_TYPE` enumeration type. This option returns the group type that is declared in the incoming connection. If the incoming connection is not going to make a group-member connection, then the value returned is `SRT_GTYPE_UNDEFINED`. If this option is read in any other context than inside the listener callback handler, the value is undefined. [Return to list](#list-of-options) --- #### SRTO_INPUTBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_INPUTBW` | 1.0.5 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | This option is effective only if [`SRTO_MAXBW`](#SRTO_MAXBW) is set to 0 (relative). It controls the maximum bandwidth together with [`SRTO_OHEADBW`](#SRTO_OHEADBW) option according to the formula: `MAXBW = INPUTBW * (100 + OHEADBW) / 100`. When this option is set to 0 (automatic) then the real INPUTBW value will be estimated from the rate of the input (cases when the application calls the `srt_send*` function) during transmission. The minimum allowed estimate value is restricted by [`SRTO_MININPUTBW`](#SRTO_MININPUTBW), meaning `INPUTBW = MAX(INPUTBW_ESTIMATE; MININPUTBW)`. *Recommended: set this option to the anticipated bitrate of your live stream and keep the default 25% value for `SRTO_OHEADBW`*. [Return to list](#list-of-options) --- #### SRTO_MININPUTBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_MININPUTBW` | 1.4.3 | post | `int64_t` | B/s | 0 | 0.. | RW | GSD | This option is effective only if both `SRTO_MAXBW` and `SRTO_INPUTBW` are set to 0. It controls the minimum allowed value of the input bitrate estimate. See [`SRTO_INPUTBW`](#SRTO_INPUTBW). [Return to list](#list-of-options) --- #### SRTO_IPTOS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_IPTOS` | 1.0.5 | pre-bind | `int32_t` | | (system) | 0..255 | RW | GSD | IPv4 Type of Service (see `IP_TOS` option for IP) or IPv6 Traffic Class (see `IPV6_TCLASS` of IPv6) depending on socket address family. Applies to sender only. When *getting*, the returned value is the user preset for non-connected sockets and the actual value for connected sockets. *Sender*: user configurable, default: `0xB8`. [Return to list](#list-of-options) --- #### SRTO_IPTTL | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_IPTTL` | 1.0.5 | pre-bind | `int32_t` | hops | (system) | 1..255 | RW | GSD | IPv4 Time To Live (see `IP_TTL` option for IP) or IPv6 unicast hops (see `IPV6_UNICAST_HOPS` for IPv6) depending on socket address family. Applies to sender only. When *getting*, the returned value is the user preset for non-connected sockets and the actual value for connected sockets. *Sender*: user configurable, default: 64 [Return to list](#list-of-options) --- #### SRTO_IPV6ONLY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_IPV6ONLY` | 1.4.0 | pre-bind | `int32_t` | | (system) | -1..1 | RW | GSD | Set system socket option level `IPPROTO_IPV6` named `IPV6_V6ONLY`. This is meaningful only when the socket is going to be bound to the IPv6 wildcard address `in6addr_any` (known also as `::`). If you bind to a wildcard address, you have the following possibilities: * IPv4 only: bind to an IPv4 wildcard address * IPv6 only: bind to an IPv6 wildcard address and set this option to 1 * IPv4 and IPv6: bind to an IPv6 wildcard address and set this option to 0 This option's default value is -1 because it is not possible to determine the default value on the current platform, and if you bind to an IPv6 wildcard address, this value is required prior to binding. When you bind implicitly by calling `srt_connect` on the socket, this isn't a problem -- binding will be done using the system-default value and then extracted afterwards. But if you want to bind explicitly using `srt_bind`, this option must be set explicitly to 0 or 1 because this information is vital for determining any potential bind conflicts with other sockets. Possible values are: * -1: (default) use system-default value (can be used when not binding to IPv6 wildcard `::`) * 0: The binding to `in6addr_any` will bind to both IPv6 and IPv4 wildcard address * 1: The binding to `in6addr_any` will bind only to IPv6 and not IPv4 wildcard address [Return to list](#list-of-options) --- #### SRTO_ISN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ---------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_ISN` | 1.3.0 | | `int32_t` | | | | R | S | The value of the ISN (Initial Sequence Number), which is the first sequence number put on the first UDP packets sent that are carrying an SRT data payload. *This value is useful for developers of some more complicated methods of flow control, possibly with multiple SRT sockets at a time. It is not intended to be used in any regular development.* [Return to list](#list-of-options) --- #### SRTO_KMPREANNOUNCE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ----------------- | ------ | --- | ------ | | `SRTO_KMPREANNOUNCE` | 1.3.2 | pre | `int32_t` | pkts | 0: 212 | 0.. * | RW | GSD | The interval (defined in packets) between when a new Stream Encrypting Key (SEK) is sent and when switchover occurs. This value also applies to the subsequent interval between when switchover occurs and when the old SEK is decommissioned. At `SRTO_KMPREANNOUNCE` packets before switchover the new key is sent (repeatedly, if necessary, until it is confirmed by the receiver). At the switchover point (see `SRTO_KMREFRESHRATE`), the sender starts encrypting and sending packets using the new key. The old key persists in case it is needed to decrypt packets that were in the flight window, or retransmitted packets. The old key is decommissioned at `SRTO_KMPREANNOUNCE` packets after switchover. **The allowed range** for this value is between 1 and half of the current value of `SRTO_KMREFRESHRATE`. The minimum value should never be less than the flight window [`SRTO_FC`](#SRTO_FC) (i.e. the number of packets that have already left the sender but have not yet arrived at the receiver). The value of `SRTO_KMPREANNOUNCE must not exceed `(SRTO_KMREFRESHRATE - 1) / 2`. **Default value:** `0` - corresponds to 4096 packets (212 or 0x1000). [Return to list](#list-of-options) --- #### SRTO_KMREFRESHRATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | ---------------- | ------ | --- | ------ | | `SRTO_KMREFRESHRATE` | 1.3.2 | pre | `int32_t` | pkts | 0: 224| 0.. | RW | GSD | The number of packets to be transmitted after which the Stream Encryption Key (SEK), used to encrypt packets, will be switched to the new one. Note that the old and new keys live in parallel for a certain period of time (see `SRTO_KMPREANNOUNCE`) before and after the switchover. Having a preannounce period before switchover ensures the new SEK is installed at the receiver before the first packet encrypted with the new SEK is received. The old key remains active after switchover in order to decrypt packets that might still be in flight, or packets that have to be retransmitted. **Default value:** `0` - corresponds to 16777216 packets (224 or 0x1000000). [Return to list](#list-of-options) --- #### SRTO_KMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_KMSTATE` | 1.0.2 | | `int32_t` | enum | | | R | S | Keying Material state. This is a legacy option that is equivalent to `SRTO_SNDKMSTATE`, if the socket has set `SRTO_SENDER` to true, and `SRTO_RCVKMSTATE` otherwise. This option is then equal to `SRTO_RCVKMSTATE` always if your application disregards possible cooperation with a peer older than 1.3.0, but then with the default value of `SRTO_ENFORCEDENCRYPTION` the value returned by both options is always the same. See [`SRT_KM_STATE`](#srt_km_state) for more details. [Return to list](#list-of-options) --- #### SRTO_LATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_LATENCY` | 1.0.2 | pre | `int32_t` | ms | 120 * | 0.. | RW | GSD | This option sets both [`SRTO_RCVLATENCY`](#SRTO_RCVLATENCY) and [`SRTO_PEERLATENCY`](#SRTO_PEERLATENCY) to the same value specified. Note that the default value for `SRTO_RCVLATENCY` is modified by the [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) option. Prior to SRT version 1.3.0 `SRTO_LATENCY` was the only option to set the latency. However it is effectively equivalent to setting `SRTO_PEERLATENCY` in the sending direction (see [`SRTO_SENDER`](#SRTO_SENDER)), and `SRTO_RCVLATENCY` in the receiving direction. SRT version 1.3.0 and higher support bidirectional transmission, so that each side can be sender and receiver at the same time, and `SRTO_SENDER` became redundant. [Return to list](#list-of-options) --- #### SRTO_LINGER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------ | -------- | ------ | --- | ------ | | `SRTO_LINGER` | | pre | `linger` | s | off \* | 0.. | RW | GSD | SRT socket linger time on close (similar to [SO\_LINGER](http://man7.org/linux/man-pages/man7/socket.7.html)). The default value in [the live streaming configuration](./API.md#transmission-types) is OFF. In this type of workflow there is no point for wait for all the data to be delivered after a connection is closed. The default value in [the file transfer configuration](./API.md#transmission-types) is 180 s. *SRT recommended value*: off (0). [Return to list](#list-of-options) --- #### SRTO_LOSSMAXTTL | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_LOSSMAXTTL` | 1.2.0 | post | `int32_t` | packets | 0 | 0.. | RW | GSD+ | The value up to which the *Reorder Tolerance* may grow. The *Reorder Tolerance* is the number of packets that must follow the experienced "gap" in sequence numbers of incoming packets so that the loss report is sent (in the hope that the gap is due to packet reordering rather than because of loss). The value of *Reorder Tolerance* starts from 0 and is set to a greater value when packet reordering is detected This happens when a "belated" packet, with sequence number older than the latest received, has been received, but without retransmission flag. When this is detected the *Reorder Tolerance* is set to the value of the interval between latest sequence and this packet's sequence, but not more than the value set by `SRTO_LOSSMAXTTL`. By default this value is set to 0, which means that this mechanism is off. [Return to list](#list-of-options) --- #### SRTO_MAXBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_MAXBW` | 1.0.5 | post | `int64_t` | B/s | -1 | -1.. | RW | GSD | Maximum send bandwidth: - `-1`: infinite (the limit in Live Mode is 1 Gbps); - `0`: relative to input rate (see [`SRTO_INPUTBW`](#SRTO_INPUTBW)); - `>0`: absolute limit in B/s. **NOTE**: This option has a default value of -1, regardless of the mode. For live streams it is typically recommended to set the value 0 here and rely on `SRTO_INPUTBW` and `SRTO_OHEADBW` options. However, if you want to do so, you should make sure that your stream has a fairly constant bitrate, or that changes are not abrupt, as high bitrate changes may work against the measurement. SRT cannot ensure that this is always the case for a live stream, therefore the default -1 remains even in live mode. [Return to list](#list-of-options) --- #### SRTO_MAXREXMITBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_MAXREXMITBW` | 1.5.3 | post | `int64_t` | B/s | -1 | -1.. | RW | GSD | Maximum BW limit for retransmissions: - `-1`: unlimited; - `0`: do not allow retransmissions. - `>0`: BW usage limit in Bytes/sec for packet retransmissions (including 16 bytes of SRT header). [Return to list](#list-of-options) --- #### SRTO_MESSAGEAPI | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_MESSAGEAPI` | 1.3.0 | pre | `bool` | | true | | W | GSD | When set, this socket uses the Message API[\*], otherwise it uses the Stream API. Note that in live mode (see [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) option) only the Message API is available. In File mode you can chose to use one of two modes (note that the default for this option is changed with `SRTO_TRANSTYPE` option): - **Stream API** (default for file mode): In this mode you may send as many data as you wish with one sending instruction, or even use dedicated functions that operate directly on a file. The internal facility will take care of any speed and congestion control. When receiving, you can also receive as many data as desired. The data not extracted will be waiting for the next call. There is no boundary between data portions in Stream mode. - **Message API**: In this mode your single sending instruction passes exactly one piece of data that has boundaries (a message). Contrary to Live mode, this message may span multiple UDP packets, and the only size limitation is that it shall fit as a whole in the sending buffer. The receiver shall use as large a buffer as necessary to receive the message, otherwise reassembling and delivering the message might not be possible. When the message is not complete (not all packets received or there was a packet loss) it will not be copied to the application's buffer. Messages that are sent later, but were earlier reassembled by the receiver, will be delivered once ready, if the `inorder` flag was set to false. See [`srt_sendmsg`](API.md#sending-and-receiving). As a comparison to the standard system protocols, the Stream API does transmission similar to TCP, whereas the Message API functions like the SCTP protocol. [Return to list](#list-of-options) --- #### SRTO_MINVERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_MINVERSION` | 1.3.0 | pre | `int32_t` | version | 0x010000 | * | RW | GSD | The minimum SRT version that is required from the peer. A connection to a peer that does not satisfy the minimum version requirement will be rejected. See [`SRTO_VERSION`](#SRTO_VERSION) for the version format. The default value is 0x010000 (SRT v1.0.0). [Return to list](#list-of-options) --- #### 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`. [Return to list](#list-of-options) --- #### SRTO_NAKREPORT | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_NAKREPORT` | 1.1.0 | pre | `bool` | | * | | RW | GSD+ | When set to true, every report for a detected loss will be repeated when the timeout for the expected retransmission of this loss has expired and the missing packet still wasn't recovered, or wasn't conditionally dropped (see [`SRTO_TLPKTDROP`](#SRTO_TLPKTDROP)). The default is true for Live mode, and false for File mode (see [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE)). [Return to list](#list-of-options) --- #### SRTO_OHEADBW | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_OHEADBW` | 1.0.5 | post | `int32_t` | % | 25 | 5..100 | RW | GSD | Recovery bandwidth overhead above input rate (see [`SRTO_INPUTBW`](#SRTO_INPUTBW)), in percentage of the input rate. It is effective only if `SRTO_MAXBW` is set to 0. *Sender*: user configurable, default: 25%. Recommendations: - Overhead is intended to give you extra bandwidth for the case when a packet has taken part of the bandwidth, but then was lost and has to be retransmitted. Therefore the effective maximum bandwidth should be appropriately higher than your stream's bitrate so that there's some room for retransmission, but still limited so that the retransmitted packets don't cause the bandwidth usage to skyrocket when larger groups of packets are lost - Don't configure it too low and avoid 0 in the case when you have the `SRTO_INPUTBW` option set to 0 (automatic). Otherwise your stream will choke and break quickly at any rise in packet loss. - ***To do: set-only; get should be supported.*** [Return to list](#list-of-options) --- #### SRTO_PACKETFILTER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PACKETFILTER` | 1.4.0 | pre | `string` | | "" | [512] | RW | GSD | Set up the packet filter. The string must match appropriate syntax for packet filter setup. Note also that: * The configuration is case-sentitive (e.g. "FEC,Cols:20" is not valid). * Setting this option will fail if you use an unknown filter type. An empty value for this option means that for this connection the filter isn't required, but it will accept any filter settings if provided by the peer. If this option is changed by both parties simultaneously, the result will be a configuration integrating parameters from both parties, that is: * parameters provided by both parties are accepted, if they are identical * parameters that are set only on one side will have the value defined by that side * parameters not set in either side will be set as default The connection will be rejected with `SRT_REJ_FILTER` code in the following cases: * both sides define a different packet filter type * for the same key two different values were provided by both sides * mandatory parameters weren't provided by either side In case of the built-in `fec` filter, the mandatory parameter is `cols`, all others have their default values. For example, the configuration specified as `fec,cols:10` is `fec,cols:10,rows:1,arq:onreq,layout:even`. See how to configure the FEC filter in [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md#configuring-the-fec-filter). Below in the table are examples for the built-in `fec` filter. Note that the negotiated config need not have parameters in the given order. Cases when negotiation succeeds: | Peer A | Peer B | Negotiated Config |----------------------|---------------------|------------------------------------------------------ | (no filter) | (no filter) | | fec,cols:10 | fec | fec,cols:10,rows:1,arq:onreq,layout:even | 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: | Peer A | Peer B | Error reason |-----------------------|---------------------|-------------------------- | fec | (no filter) | missing `cols` parameter | fec,rows:20,arq:never | fec,layout:even | missing `cols` parameter | fec,cols:20 | fec,cols:10 | `cols` parameter value conflict | fec,cols:20,rows:20 | fec,cols:20,rows:10 | `rows` parameter value conflict In general it is recommended that one party defines the full configuration, while the other keeps this value empty. Reading this option after the connection is established will return the full configuration that has been agreed upon by both parties (including default values). For details, see [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md). [Return to list](#list-of-options) --- #### SRTO_PASSPHRASE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PASSPHRASE` | 0.0.0 | pre | `string` | | "" |[10..80]| W | GSD | Sets the passphrase for encryption. This enables encryption on this party (or disables it, if an empty passphrase is passed). The password must be minimum 10 and maximum 79 characters long. The passphrase is the shared secret between the sender and the receiver. It is used to generate the Key Encrypting Key using [PBKDF2](http://en.wikipedia.org/wiki/PBKDF2) (Password-Based Key Derivation Function 2). When a socket with configured passphrase is being connected, the peer must have the same password set, or the connection is rejected. This behavior can be changed by [`SRTO_ENFORCEDENCRYPTION`](#SRTO_ENFORCEDENCRYPTION). Note that since the introduction of bidirectional support, there's only one initial encryption key to encrypt the stream (new keys after refreshing will be updated independently), and there's no distinction between "service party that defines the password" and "client party that is required to set matching password" - both parties are equivalent, and in order to have a working encrypted connection, they have to simply set the same passphrase. [Return to list](#list-of-options) --- #### 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. 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`. For File mode: Default value is 0 and it's recommended not to be changed. [Return to list](#list-of-options) --- #### SRTO_PBKEYLEN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PBKEYLEN` | 0.0.0 | pre | `int32_t` | bytes | 0 | * | RW | GSD | Encryption key length. Possible values: - 0 =`PBKEYLEN` (default value) - 16 = AES-128 (effective value) - 24 = AES-192 - 32 = AES-256 The use is slightly different in 1.2.0 (HSv4), and since 1.3.0 (HSv5): - **HSv4**: This is set on the sender and enables encryption, if not 0. The receiver shall not set it and will agree on the length as defined by the sender. Being a sender is defined by the `SRTO_SENDER` socket option set to true; otherwise the party is a receiver. - **HSv5**: The "default value" for `PBKEYLEN` is 0, which means that the `PBKEYLEN` won't be advertised. The "effective value" for `PBKEYLEN` is 16, but this applies only when neither party has set the value explicitly (i.e. when both are initially at the default value of 0). If any party *has* set an explicit value (16, 24, 32) it will be advertised in the handshake. If the other party remains at the default 0, it will accept the peer's value. The situation where both parties set a value should be treated carefully. Actually there are three intended methods of defining it, and all other uses are considered undefined behavior: - **Unidirectional**: the sender shall set `PBKEYLEN` and the receiver shall not alter the default value 0. The effective `PBKEYLEN` will be the one set on the sender. The receiver need not know the sender's `PBKEYLEN`, just the passphrase, `PBKEYLEN` will be correctly passed. - **Bidirectional in Caller-Listener arrangement**: it is recommended to use a rule whereby you will be setting the `PBKEYLEN` exclusively either on the Listener (the service defines the encryption rules strictly) or on the Caller (the service allows all clients to freely decide about encryption, or the server uses more elaborate rules for encryption). - **Bidirectional in Rendezvous mode**: In Rendezvous mode it is assumed that the settings (including `PBKEYLEN`) are known at both ends. as it is with Listener mode, so both parties should set the same passphrase and the same key length, or both should leave the `SRTO_PBKEYLEN` option unchanged (which results in default 16). - **Unwanted behavior cases**: if both parties set `PBKEYLEN` and the value on both sides is different, this is considered a conflict. It is resolved by the Initiator party, which takes its own value, if the `SRTO_SENDER` option is set to true. Otherwise, it takes the value from the Responder party. The assignment of Initiator-Responder roles matches the Caller-Listener layout. In the case of Rendezvous this assignment depends on the result of the cookie comparison. **It is highly recommended to never allow this to happen**, as this may result in having one party's setting of length = 32 be overridden by the other party's setting of length = 16. | Initiator | | Responder | | Result | |---------------|-------------|---------------|-------------|---------| | SRTO_PBKEYLEN | SRTO_SENDER | SRTO_PBKEYLEN | SRTO_SENDER | | | 0 | any | 0 | any | AES-128 | | 0 | any | AES-128 | any | AES-128 | | 0 | any | AES-192 | any | AES-192 | | 0 | any | AES-256 | any | AES-256 | | AES-128 | any | 0 | any | AES-128 | | AES-128 | any | AES-128 | any | AES-128 | | AES-128 | 0 | AES-192 | any | AES-192 | | AES-128 | 0 | AES-256 | any | AES-256 | | AES-128 | 1 | AES-192 | any | AES-128 | | AES-128 | 1 | AES-256 | any | AES-128 | | AES-192 | any | 0 | any | AES-192 | | AES-192 | 0 | AES-128 | any | AES-128 | | AES-192 | any | AES-192 | any | AES-192 | | AES-192 | 0 | AES-256 | any | AES-256 | | AES-192 | 1 | AES-128 | any | AES-192 | | AES-192 | 1 | AES-256 | any | AES-192 | | AES-256 | any | 0 | any | AES-256 | | AES-256 | 0 | AES-128 | any | AES-128 | | AES-256 | 0 | AES-192 | any | AES-192 | | AES-256 | any | AES-256 | any | AES-256 | | AES-256 | 1 | AES-128 | any | AES-256 | | AES-256 | 1 | AES-192 | any | AES-256 | [Return to list](#list-of-options) --- #### SRTO_PEERIDLETIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PEERIDLETIMEO` | 1.3.3 | pre | `int32_t` | ms | 5000 | 0.. | RW | GSD+ | The maximum time in `[ms]` to wait until another packet is received from a peer since the last such packet reception. If this time is passed, the connection is considered broken on timeout. [Return to list](#list-of-options) --- #### SRTO_PEERLATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PEERLATENCY` | 1.3.0 | pre | `int32_t` | ms | 0 | 0.. | RW | GSD | The latency value (as described in [`SRTO_RCVLATENCY`](#SRTO_RCVLATENCY)) provided by the sender side as a minimum value for the receiver. This value is only significant when [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE) is enabled. Reading the value of the option on an unconnected socket reports the configured value. Reading the value on a connected socket reports the effective receiver buffering latency of the peer. **The `SRTO_PEERLATENCY` option in versions prior to 1.3.0 is only available as** [`SRTO_LATENCY`](#SRTO_LATENCY). See also [`SRTO_LATENCY`](#SRTO_LATENCY). [Return to list](#list-of-options) --- #### SRTO_PEERVERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | -------- | ------ | --- | ------ | | `SRTO_PEERVERSION` | 1.1.0 | | `int32_t` | * | | | R | GS | SRT version used by the peer. The value 0 is returned if not connected, SRT handshake not yet performed (HSv4 only), or if peer is not SRT. See [`SRTO_VERSION`](#SRTO_VERSION) for the version format. [Return to list](#list-of-options) --- #### SRTO_RCVBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVBUF` | | pre-bind | `int32_t` | bytes | 8192 bufs | * | RW | GSD+ | Receive Buffer Size, in bytes. Note, however, that the internal setting of this value is in the number of buffers, each one of size equal to SRT payload size, which is the value of `SRTO_MSS` decreased by UDP and SRT header sizes (28 and 16). The value set here will be effectively aligned to the multiple of payload size. - **Minimum value**: 32 buffers (46592 with default value of `SRTO_MSS`). - **Maximum value**: [`SRTO_FC`](#SRTO_FC) number of buffers (receiver buffer must not be greater than the Flight Flag size). [Return to list](#list-of-options) --- #### SRTO_RCVDATA | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVDATA` | | | `int32_t` | pkts | | | R | S | Size of the available data in the receive buffer. [Return to list](#list-of-options) --- #### SRTO_RCVKMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVKMSTATE` | 1.2.0 | | `int32_t` | enum | | | R | S | KM state on the agent side when it's a receiver. Values defined in enum [`SRT_KM_STATE`](#srt_km_state). [Return to list](#list-of-options) --- #### SRTO_RCVLATENCY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVLATENCY` | 1.3.0 | pre | `int32_t` | ms | * | 0.. | RW | GSD | The latency value in the receiving direction of the socket. This value is only significant when [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE) is enabled. **Default value**: 120 ms in Live mode, 0 in File mode (see [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE)). The latency value defines the **minimum** receiver buffering delay before delivering an SRT data packet from a receiving SRT socket to a receiving application. The actual value of the receiver buffering delay `Ln` (the negotiated latency) used on a connection is determined by the negotiation in the connection establishment (handshake exchange) phase as the maximum of the `SRTO_RCVLATENCY` value and the value of [`SRTO_PEERLATENCY`](#SRTO_PEERLATENCY) set by the peer. The general idea for the latency mechanism is to keep the time distance between two consecutive received packets the same as the time when these same packets were scheduled for sending by the sender application (or per the time explicitly declared when sending - see [`srt_sendmsg2`](API-functions.md#srt_sendmsg2) for details). This keeps any packets that have arrived earlier than their delivery time in the receiver buffer until their delivery time comes. This should compensate for any jitter in the network and provides an extra delay needed for a packet retransmission. For detailed information on how the latency setting influences the actual packet delivery time and how this time is defined, refer to the [latency documentation](../features/latency.md). Reading the `SRTO_RCVLATENCY` value on a socket after the connection is established provides the actual (negotiated) latency value `Ln`. The receiver's buffer must be large enough to store the `L` segment of the stream, i.e. `L × Bitrate` bytes. Refer to [`SRTO_RCVBUF`](#SRTO_RCVBUF). The sender's buffer must be large enough to store a packet up until it is either delivered (and acknowledged) or dropped by the sender due to it becoming too late to be delivered. In other words, `D × Bitrate` bytes, where `D` is the sender's drop delay value configured with [`SRTO_SNDDROPDELAY`](#SRTO_SNDDROPDELAY). Buffering of data packets on the receiving side makes it possible to recover from packet losses using the ARQ (Automatic Repeat Request) technique, and to deal with varying RTT times (network jitter) in the network, providing a (close to) **constant end-to-end latency of the transmission**. See also [`SRTO_LATENCY`](#SRTO_LATENCY). [Return to list](#list-of-options) --- #### SRTO_RCVSYN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVSYN` | | post | `bool` | | true | | RW | GSI | When true, sets blocking mode on reading function when it's not ready to perform the operation. When false ("non-blocking mode"), the reading function will in this case report error `SRT_EASYNCRCV` and return immediately. Details depend on the tested entity: On a connected socket or group this applies to a receiving function (`srt_recv` and others) and a situation when there are no data available for reading. The readiness state for this operation can be tested by checking the `SRT_EPOLL_IN` flag on the aforementioned socket or group. On a freshly created socket or group that is about to be connected to a peer listener this applies to any `srt_connect` call (and derived), which in "non-blocking mode" always returns immediately. The connected state for that socket or group can be tested by checking the `SRT_EPOLL_OUT` flag. Note that a socket that failed to connect doesn't change the `SRTS_CONNECTING` state and can be found out only by testing the `SRT_EPOLL_ERR` flag. On a listener socket this applies to `srt_accept` call. The readiness state for this operation can be tested by checking the `SRT_EPOLL_IN` flag on this listener socket. This flag is also derived from the listener socket by the accepted socket or group, although the meaning of this flag is effectively different. Note that when this flag is set only on a group, it applies to a specific receiving operation being done on that group (i.e. it is not derived from the socket of which the group is a member). [Return to list](#list-of-options) --- #### SRTO_RCVTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RCVTIMEO` | | post | `int32_t` | ms | -1 | -1, 0..| RW | GSI | Limits the time up to which the receiving operation will block (see [`SRTO_RCVSYN`](#SRTO_RCVSYN) for details), such that when this time is exceeded, it will behave as if in "non-blocking mode". The -1 value means no time limit. [Return to list](#list-of-options) --- #### SRTO_RENDEZVOUS | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_RENDEZVOUS` | | pre | `bool` | | false | | RW | S | Use Rendezvous connection mode (both sides must set this and both must use the procedure of `srt_bind` and then `srt_connect` (or `srt_rendezvous`) to one another. [Return to list](#list-of-options) --- #### SRTO_RETRANSMITALGO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | --------- | ------ | ------- | ------ | --- | ------ | | `SRTO_RETRANSMITALGO` | 1.4.2 | pre | `int32_t` | | 1 | [0, 1] | RW | GSD | An SRT sender option to choose between two retransmission algorithms: - 0 - aggressive retransmission algorithm (default until SRT v1.4.4), and - 1 - efficient retransmission algorithm (introduced in SRT v1.4.2; default since SRT v1.4.4). The aggressive retransmission algorithm causes the SRT sender to schedule a packet for retransmission each time it receives a negative acknowledgement (NAK). On a network characterized by low packet loss levels and link capacity high enough to accommodate extra retransmission overhead, this algorithm increases the chances of recovering from packet loss with a minimum delay, and may better suit end-to-end latency constraints. The new efficient algorithm optimizes the bandwidth usage by producing fewer retransmissions per lost packet. It takes SRT statistics into account to determine if a retransmitted packet is still in flight and could reach the receiver in time, so that some of the NAK reports are ignored by the sender. This algorithm better fits general use cases, as well as cases where channel bandwidth is limited. To learn more about the algorithms, read ["Improving SRT Retransmissions — Experiments with Simulated Live Streaming (Part 1)"](https://medium.com/innovation-labs-blog/improving-srt-retransmissions-experiments-with-simulated-live-streaming-part-1-7d192483bba4) article. NOTE: This option is effective only on the sending side. It influences the decision as to whether a particular reported lost packet should be retransmitted at a certain time or not. NOTE: The efficient retransmission algorithm can only be used when a receiver sends Periodic NAK reports. See [SRTO_NAKREPORT](#SRTO_NAKREPORT). [Return to list](#list-of-options) --- #### SRTO_REUSEADDR | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_REUSEADDR` | | pre-bind | `bool` | | true | | RW | GSD | When true, allows the SRT socket to use the binding address used already by another SRT socket in the same application. Note that SRT socket uses an intermediate object called Multiplexer to access the underlying UDP sockets, so multiple SRT sockets may share one UDP socket, and the packets received by this UDP socket will be correctly dispatched to the SRT socket to which they are currently destined. This has some similarities to the `SO_REUSEADDR` system socket option, although it's only used inside SRT. *TODO: This option weirdly only allows the socket used in **bind()** to use the local address that another socket is already using, but not to disallow another socket in the same application to use the binding address that the current socket is already using. What it actually changes is that when given an address in **bind()** is already used by another socket, this option will make the binding fail instead of adding the socket to the shared group of that socket that already has bound this address - but it will not disallow another socket to reuse its address.* [Return to list](#list-of-options) --- #### SRTO_SENDER | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | ---------- | ------ | --- | ------ | | `SRTO_SENDER` | 1.0.4 | pre | `bool` | | false | | W | S | Set sender side. The side that sets this flag is expected to be a sender. This flag is only required when communicating with a receiver that uses SRT version less than 1.3.0 (and hence *HSv4* handshake), in which case if not set properly, the TSBPD mode (see [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE)) or encryption will not work. Setting `SRTO_MINVERSION` to 1.3.0 is therefore recommended. This flag in versions above 1.3.0 also influences the conflict resolution for `SRTO_PBKEYLEN` in the case where this flag is forcefully set on both connection parties simultaneously. [Return to list](#list-of-options) --- #### SRTO_SNDBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDBUF` | | pre-bind | `int32_t` | bytes |8192 bufs | * | RW | GSD+ | Sender Buffer Size. See [`SRTO_RCVBUF`](#SRTO_RCVBUF) for more information. [Return to list](#list-of-options) --- #### SRTO_SNDDATA | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDDATA` | | | `int32_t` | pkts | | | R | S | Size of the unacknowledged data in send buffer. [Return to list](#list-of-options) --- #### SRTO_SNDDROPDELAY | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDDROPDELAY` | 1.3.2 | post | `int32_t` | ms | * | -1.. | W | GSD+ | Sets an extra delay before `TLPKTDROP` is triggered on the data sender. This delay is added to the default drop delay time interval value. Keep in mind that the longer the delay, the more probable it becomes that packets would be retransmitted uselessly because they will be dropped by the receiver anyway. `TLPKTDROP` discards packets reported as lost if it is already too late to send them (the receiver would discard them even if received). The delay before the `TLPKTDROP` mechanism is triggered consists of the SRT latency (`SRTO_PEERLATENCY`), plus `SRTO_SNDDROPDELAY`, plus `2 * interval between sending ACKs` (where the default `interval between sending ACKs` is 10 milliseconds). The minimum delay is `1000 + 2 * interval between sending ACKs` milliseconds. **Special value -1**: Do not drop packets on the sender at all (retransmit them always when requested). **Default:** 0 in Live mode, -1 in File mode. [Return to list](#list-of-options) --- #### SRTO_SNDKMSTATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDKMSTATE` | 1.2.0 | | `int32_t` | enum | | | R | S | Peer KM state on receiver side for `SRTO_KMSTATE` Values defined in enum [`SRT_KM_STATE`](#srt_km_state). [Return to list](#list-of-options) --- #### SRTO_SNDSYN | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDSYN` | | post | `bool` | | true | | RW | GSI | When true, sets blocking mode on writing function when it's not ready to perform the operation. When false ("non-blocking mode"), the writing function will in this case report error `SRT_EASYNCSND` and return immediately. On a connected socket or group this applies to a sending function (`srt_send` and others) and a situation when there's no free space in the sender buffer, caused by inability to send all the scheduled data over the network. Readiness for this operation can be tested by checking the `SRT_EPOLL_OUT` flag. On a freshly created socket or group it will have no effect until the socket enters a connected state. On a listener socket it will be derived by the accepted socket or group, but will have no effect on the listener socket itself. [Return to list](#list-of-options) --- #### SRTO_SNDTIMEO | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_SNDTIMEO` | | post | `int32_t` | ms | -1 | -1.. | RW | GSI | limit the time up to which the sending operation will block (see `SRTO_SNDSYN` for details), so when this time is exceeded, it will behave as if in "non-blocking mode". The -1 value means no time limit. [Return to list](#list-of-options) --- #### SRTO_STATE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_STATE` | | | `int32_t` | enum | | | R | S | Returns the current socket state, same as `srt_getsockstate`. [Return to list](#list-of-options) --- #### SRTO_STREAMID | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | -------------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_STREAMID` | 1.3.0 | pre | `string` | | "" | [512] | RW | GSD | - A string that can be set on the socket prior to connecting. The listener side will be able to retrieve this stream ID from the socket that is returned from `srt_accept` (for a connected socket with that stream ID). You usually use SET on the socket used for `srt_connect`, and GET on the socket retrieved from `srt_accept`. This string can be used completely free-form. However, it's highly recommended to follow the [SRT Access Control (Stream ID) Guidlines](../features/access-control.md). - As this uses internally the `std::string` type, there are additional functions for it in the legacy/C++ API (udt.h): `srt::setstreamid` and `srt::getstreamid`. - This option is not useful for a Rendezvous connection, since one side would override the value from the other side resulting in an arbitrary winner. Also in this connection both peers are known to one another and both have equivalent roles in the connection. - **IMPORTANT**: This option is not derived by the accepted socket from the listener socket, and setting it on a listener socket (see `srt_listen` function) doesn't influence anything. [Return to list](#list-of-options) --- #### SRTO_TLPKTDROP | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_TLPKTDROP` | 1.0.6 | pre | `bool` | | * | | RW | GSD | Too-late Packet Drop. When enabled on receiver, it skips missing packets that have not been delivered in time and delivers the subsequent packets to the application when their time-to-play has come. It also sends a fake ACK to the sender. When enabled on sender and enabled on the receiving peer, sender drops the older packets that have no chance to be delivered in time. It is automatically enabled in sender if receiver supports it. **Default:** true in Live mode, false in File mode (see [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE)) [Return to list](#list-of-options) --- #### SRTO_TRANSTYPE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_TRANSTYPE` | 1.3.0 | pre | `int32_t` | enum |`SRTT_LIVE`| \* | W | S | Sets the transmission type for the socket, in particular, setting this option sets multiple other parameters to their default values as required for a particular transmission type. This sets the following options to their defaults in particular mode: * [`SRTO_CONGESTION`](#SRTO_CONGESTION) * [`SRTO_MESSAGEAPI`](#SRTO_MESSAGEAPI) * [`SRTO_NAKREPORT`](#SRTO_NAKREPORT) * [`SRTO_RCVLATENCY`](#SRTO_RCVLATENCY), also set as [`SRTO_LATENCY`](#SRTO_LATENCY) * [`SRTO_TLPKTDROP`](#SRTO_TLPKTDROP) * [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE) Values defined by enum [`SRT_TRANSTYPE`](#SRT_TRANSTYPE). [Return to list](#list-of-options) --- #### SRTO_TSBPDMODE | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_TSBPDMODE` | 0.0.0 | pre | `bool` | | \* | | W | S | When true, use Timestamp-based Packet Delivery mode. In this mode the packet's time is assigned at the sending time (or allowed to be predefined), transmitted in the packet's header, and then restored on the receiver side so that the time intervals between consecutive packets are preserved when delivering to the application. **Default:** true in Live mode, false in File mode (see [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE)). [Return to list](#list-of-options) --- #### SRTO_UDP_RCVBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_UDP_RCVBUF` | | pre-bind | `int32_t` | bytes | 8192 bufs | * | RW | GSD+ | UDP Socket Receive Buffer Size. Configured in bytes, maintained in packets based on MSS value. Receive buffer must not be greater than FC size. [Return to list](#list-of-options) --- #### SRTO_UDP_SNDBUF | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_UDP_SNDBUF` | | pre-bind | `int32_t` | bytes | 65536 | * | RW | GSD+ | UDP Socket Send Buffer Size. Configured in bytes, maintained in packets based on `SRTO_MSS` value. [Return to list](#list-of-options) --- #### SRTO_VERSION | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | ----------------- | ----- | -------- | ---------- | ------- | --------- | ------ | --- | ------ | | `SRTO_VERSION` | 1.1.0 | | `int32_t` | | | | R | S | Local SRT version. This is the highest local version supported if not connected, or the highest version supported by the peer if connected. The version format in hex is `0x00XXYYZZ` for x.y.z in human readable form. For example, version 1.4.2 is encoded as `0x010402`. [Return to list](#list-of-options) --- srt-1.5.4/docs/API/API.md000066400000000000000000001032621471311275400146360ustar00rootroot00000000000000# SRT API The SRT C API (defined in `srt.h` file) is largely based in design on the legacy UDT API, with some important changes. The `udt.h` file contains the legacy UDT API plus some minor optional functions that require the C++ standard library to be used. There are a few optional C++ API functions stored there, as there is no real C++ API for SRT. These functions may be useful in certain situations. There are some example applications so that you can see how the API is being used, including `srt-live-transmit` and `srt-file-transmit`. All SRT related material is contained in `transmitmedia.*` files in the `apps` directory which is used by all applications. See `SrtSource::Read` and `SrtTarget::Write` as examples of how data are read and written in SRT. - [Setup and Teardown](#setup-and-teardown) - [Creating and Destroying a Socket](#creating-and-destroying-a-socket) - [Binding and Connecting](#binding-and-connecting) - [Sending and Receiving](#sending-and-receiving) - [Blocking and Non-blocking Modes](#blocking-and-non-blocking-modes) - [EPoll (Non-blocking Mode Events)](#epoll-non-blocking-mode-events) - [Transmission Types](#transmission-types) - [Transmission Method: Live](#transmission-method-live) - [Transmission Method: Buffer](#transmission-method-buffer) - [Transmission Method: Message](#transmission-method-message) ## Setup and Teardown Before any part of the SRT C API can be used, the user should call the `srt_startup()` function. Likewise, before the application exits, the `srt_cleanup()` function should be called. Note that one of the things the startup function does is to create a new thread, so choose the point of execution for these functions carefully. ## Creating and Destroying a Socket To do anything with SRT, you first have to create an SRT socket. The term "socket" in this case is used because of its logical similarity to system-wide sockets. An SRT socket is not directly related to system sockets, but like a system socket it is used to define a point of communication. ### Synopsis ```c++ SRTSOCKET srt_create_socket(); int srt_close(SRTSOCKET s); ``` Note that `SRTSOCKET` is just an alias for `int`; this is a legacy naming convention from UDT, which is here only for clarity. ### Usage ```c++ sock = srt_create_socket(); ``` This creates a socket, which can next be configured and then used for communication. ```c++ srt_close(sock); ``` This closes the socket and frees all its resources. Note that the true life of the socket does not end exactly after this function exits - some details are being finished in a separate "SRT GC" thread. Still, at least all shared system resources (such as listener port) should be released after this function exits. ### Important Remarks 1. SRT uses the system UDP protocol as an underlying communication layer, and so it uses also UDP sockets. The underlying communication layer is used only instrumentally, and SRT manages UDP sockets as its own system resource as it pleases - so in some cases it may be reasonable for multiple SRT sockets to share one UDP socket, or for one SRT socket to use multiple UDP sockets. 2. The term "port" used in SRT is occasionally identical to the term "UDP port". However SRT offers more flexibility than UDP (or TCP, the more logical similarity) because it manages ports as its own resources. For example, one port may be shared between various services. ## Binding and Connecting Connections are established using the same philosophy as TCP, using functions with names and signatures similar to the BSD Socket API. What is new here is the _rendezvous_ mode. ### Synopsis ```c++ int srt_bind(SRTSOCKET u, const struct sockaddr* name, int namelen); int srt_bind_acquire(SRTSOCKET u, UDPSOCKET udpsock); ``` This function sets up the "sockname" for the socket, that is, the local IP address of the network device (use `INADDR_ANY` for using any device) and port. Note that this can be done on both listening and connecting sockets; for the latter it will define the outgoing port. If you don't set up the outgoing port by calling this function (or use port number 0), a unique port number will be selected automatically. The `*_acquire` version simply takes over the given UDP socket and copies the bound address setting from it. ```c++ int srt_listen(SRTSOCKET u, int backlog); ``` This sets the backlog (maximum allowed simultaneously pending connections) and puts the socket into a listening state -- that is, incoming connections will be accepted in the call `srt_accept`. ```c++ SRTSOCKET srt_accept(SRTSOCKET u, struct sockaddr* addr, int* addrlen); ``` This function accepts the incoming connection (the peer should do `srt_connect`) and returns a socket that is exclusively bound to an opposite socket at the peer. The peer's address is returned in the `addr` argument. ```c++ int srt_connect(SRTSOCKET u, const struct sockaddr* name, int namelen); int srt_connect_debug(SRTSOCKET u, const struct sockaddr* name, int namelen, int forced_isn); ``` This function initiates the connection of a given socket with its peer's counterpart (the peer gets the new socket for this connection from `srt_accept`). The address for connection is passed in 'name'. The `connect_debug` version allows for enforcing the ISN (initial sequence number); this is used only for debugging or unusual experiments. ```c++ int srt_rendezvous(SRTSOCKET u, const struct sockaddr* local_name, int local_namelen, const struct sockaddr* remote_name, int remote_namelen); ``` A convenience function that combines the calls to bind, setting the `SRTO_RENDEZVOUS` flag, and connecting to the rendezvous counterpart. For simplest usage, the `local_name` should be set to `INADDR_ANY` (or a specified adapter's IP) and port. Note that both `local_name` and `remote_name` must use the same port. The peer to which this is going to connect should call the same function, with appropriate local and remote addresses. A rendezvous connection means that both parties connect to one another simultaneously. **IMPORTANT**: The connection may fail, but the socket that was used for connecting is not automatically closed and it's also not in broken state (broken state can be only if a socket was first successfully connected and then broken). When using blocking mode, the connection failure will result in reporting an error from this function call. In non-blocking mode the connection failure is designated by the `SRT_EPOLL_ERR` flag set for this socket in the epoll container. After that failure you can read an extra information from the socket using `srt_getrejectreason` function, and then you should close the socket. ### Listener (Server) Example ```c++ sockaddr_in sa = { ... }; // set local listening port and possibly interface's IP int st = srt_bind(sock, (sockaddr*)&sa, sizeof sa); srt_listen(sock, 5); while ( !finish ) { int sa_len = sizeof sa; newsocket = srt_accept(sock, (sockaddr*)&sa, &sa_len); HandleNewClient(newsocket, sa); } ``` ### Caller (Client) Example ```c++ sockaddr_in sa = { ... }; // set target IP and port int st = srt_connect(sock, (sockaddr*)&sa, sizeof sa); HandleConnection(sock); ``` ### Rendezvous Example ```c++ sockaddr_in lsa = { ... }; // set local listening IP/port sockaddr_in rsa = { ... }; // set remote IP/port srt_setsockopt(m_sock, 0, SRTO_RENDEZVOUS, &yes, sizeof yes); int stb = srt_bind(sock, (sockaddr*)&lsa, sizeof lsa); int stc = srt_connect(sock, (sockaddr*)&rsa, sizeof rsa); HandleConnection(sock); ``` or simpler ```c++ sockaddr_in lsa = { ... }; // set local listening IP/port sockaddr_in rsa = { ... }; // set remote IP/port int stc = srt_rendezvous(sock, (sockaddr*)&lsa, sizeof lsa, (sockaddr*)&rsa, sizeof rsa); HandleConnection(sock); ``` ## Sending and Receiving The SRT API for sending and receiving is split into three categories: *simple*, *rich*, and *for files only*. The **simple API** includes: `srt_send` and `srt_recv` functions. They need only the socket and the buffer to send from or receive to, just like system `read` and `write` functions. The **rich API** includes the `srt_sendmsg` and `srt_recvmsg` functions. Actually `srt_recvmsg` is provided for convenience and backward compatibility, as it is identical to `srt_recv`. The `srt_sendmsg` receives more parameters, specifically for messages. The `srt_sendmsg2` and `srt_recvmsg2` functions receive the socket, buffer, and the `SRT_MSGCTRL` object, which is an input-output object specifying extra data for the operation. Functions with the `msg2` suffix use the `SRT_MSGCTRL` object, and have the following interpretation (except `flags` and `boundary` which are reserved for future use and should be 0): - `srt_sendmsg2`: - `msgttl`: [IN] maximum time (in ms) to wait for successful delivery (-1: indefinitely) - `inorder`: [IN] if false, the later sent message is allowed to be delivered earlier - `srctime`: [IN] timestamp to be used for sending (0 if current time) - `pktseq`: unused - `msgno`: [OUT] message number assigned to the currently sent message - `srt_recvmsg2` - `msgttl`: unused - `inorder`: unused - `srctime`: [OUT] timestamp set for this dataset when sending - `pktseq`: [OUT] packet sequence number (first packet from the message, if it spans multiple UDP packets) - `msgno`: [OUT] message number assigned to the currently received message Please note that the `msgttl` and `inorder` arguments and fields in `SRT_MSGCTRL` are meaningful only when you use the message API in file mode (this will be explained later). In live mode, which is the SRT default, packets are always delivered when the time comes (always in order), where you don't want a packet to be dropped before sending (so -1 should be passed here). The `srctime` parameter is an SRT addition for applications (i.e. gateways) forwarding SRT streams. It permits pulling and pushing of the sender's original time stamp, converted to local time and drift adjusted. The `srctime` parameter is the number of usec (since epoch) in local SRT clock time. If the connection is not between SRT peers or if **Timestamp-Based Packet Delivery mode (TSBPDMODE)** is not enabled (see [SRT API Socket Options](API-socket-options.md)), the extracted `srctime` will be 0. Passing `srctime = 0` in `sendmsg` is like using the API without `srctime` and the local send time will be used (if TSBPDMODE is enabled and receiver supports it). ### Synopsis ```c++ int srt_send(SRTSOCKET s, const char* buf, int len); int srt_sendmsg(SRTSOCKET s, const char* buf, int len, int msgttl, bool inorder, uint64_t srctime); int srt_sendmsg2(SRTSOCKET s, const char* buf, int len, SRT_MSGCTRL* msgctrl); int srt_recv(SRTSOCKET s, char* buf, int len); int srt_recvmsg(SRTSOCKET s, char* buf, int len); int srt_recvmsg2(SRTSOCKET s, char* buf, int len, SRT_MSGCTRL* msgctrl); ``` ### Usage Sending a payload: ```c++ nb = srt_sendmsg(u, buf, nb, -1, true); nb = srt_send(u, buf, nb); SRT_MSGCTRL mc = srt_msgctrl_default; nb = srt_sendmsg2(u, buf, nb, &mc); ``` Receiving a payload: ```c++ nb = srt_recvmsg(u, buf, nb); nb = srt_recv(u, buf, nb); SRT_MSGCTRL mc = srt_msgctrl_default; nb = srt_recvmsg2(u, buf, nb, &mc); ``` ### Transmission Types Available in SRT Mode settings determine how the sender and receiver functions work. The main SRT [socket options](API-socket-options.md) that control it are: - `SRTO_TRANSTYPE`. Sets several parameters in accordance with the selected mode: - `SRTT_LIVE` (default) the Live mode (for live stream transmissions) - `SRTT_FILE` the File mode (for "no time controlled" fastest data transmission) - `SRTO_MESSAGEAPI` - true: (default in Live mode): use Message API - false: (default in File mode): use Buffer API See [Transmission types](#transmission-types) below. ## Blocking and Non-blocking Modes SRT functions can also work in blocking and non-blocking modes, for which there are two separate options for sending and receiving: `SRTO_SNDSYN` and `SRTO_RCVSYN`. When blocking mode is used, a function will not exit until the availability condition is satisfied. In non-blocking mode the function always exits immediately, and in case of lack of resource availability, it returns an error with an appropriate code. The use of non-blocking mode usually requires using some polling mechanism, which in SRT is **EPoll**. Note also that the blocking and non-blocking modes apply not only for sending and receiving. For example, `SNDSYN` defines blocking for `srt_connect` and `RCVSYN` defines blocking for `srt_accept`. The `SNDSYN` also makes `srt_close` exit only after the sending buffer is completely empty. ### EPoll (Non-blocking Mode Events) EPoll is a mechanism to track the events happening on the sockets, both "system sockets" (see `SYSSOCKET` type) and SRT Sockets. Note that `SYSSOCKET` is also an alias for `int`, used only for clarity. #### Synopsis ```c++ int srt_epoll_update_usock(int eid, SRTSOCKET u, const int* events = NULL); int srt_epoll_update_ssock(int eid, SYSSOCKET s, const int* events = NULL); int srt_epoll_wait(int eid, SRTSOCKET* readfds, int* rnum, SRTSOCKET* writefds, int* wnum, int64_t msTimeOut, SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum); int srt_epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut); int srt_epoll_clear_usocks(int eid); ``` #### Usage SRT socket being a user level concept, the system epoll (or other select) cannot be used to handle SRT non-blocking mode events. Instead, SRT provides a user-level epoll that supports both SRT and system sockets. The `srt_epoll_update_{u|s}sock()` API functions described here are SRT additions to the UDT-derived `srt_epoll_add_{u|s}sock()` and `epoll_remove_{u|s}sock()` functions to atomically change the events of interest. For example, to remove `SRT_EPOLL_OUT` but keep `SRT_EPOLL_IN` for a given socket with the existing API, the socket must be removed from epoll and re-added. This cannot be done atomically, the thread protection (against the epoll thread) being applied within each function but unprotected between the two calls. It is then possible to lose an `SRT_EPOLL_IN` event if it fires while the socket is not in the epoll list. Event flags are of various categories: `IN`, `OUT` and `ERR` are events, which are level-triggered by default and become edge-triggered if combined with `SRT_EPOLL_ET` flag. The latter is only an edge-triggered flag, not an event. There's also an `SRT_EPOLL_UPDATE` flag, which is an edge-triggered only event, and it reports an event on the listener socket that handles socket group new connections for an already connected group - this is for internal use only, and it's used in the internal code for socket groups. Once the subscriptions are made, you can call an SRT polling function (`srt_epoll_wait` or `srt_epoll_uwait`) that will block until an event is raised on any of the subscribed sockets. This function will exit as soon as at least one event is detected or a timeout occurs. The timeout is specified in `[ms]`, with two special values: - 0: check and report immediately (don't wait) - -1: wait indefinitely (not interruptible, even by a system signal) There are some differences in the synopsis between these two: #### `srt_epoll_wait` Both system and SRT sockets can be subscribed. This function reports events on both socket types according to subscriptions, in these arrays: - `readfds` and `lrfds`: subscribed for `IN` and `ERR` - `writefds` and `lwfds`: subscribed for `OUT` and `ERR` where: - `readfds` and `writefds` report SRT sockets ("user" socket) - `lrfds` and `lwfds` report system sockets **NOTE**: this function provides no straightforward possibility to report sockets with an error. If you want to distinguish a report of readiness for operation from an error report, the only way is to subscribe the socket in only one direction (either `SRT_EPOLL_IN` or `SRT_EPOLL_OUT`, but not both) and `SRT_EPOLL_ERR`, and then check the socket's presence in the array in the direction for which the socket wasn't subscribed. For example, when an SRT socket is subscribed for `SRT_EPOLL_OUT | SRT_EPOLL_ERR`, its presence in `readfds` means that an error is reported for it. This need not be a big problem, because when an error is reported on a socket, making it appear as if it were ready for an operation, then when that operation occurs it will simply result in an error. You can use this as an alternative error check method. This function also reports an error of type `SRT_ETIMEOUT` when no socket is ready as the timeout elapses (including 0). This behavior is different in `srt_epoll_uwait`. Note that in this function there's a loop that checks for socket readiness every 10ms. Thus, the minimum poll timeout the function can reliably support, when system sockets are involved, is also 10ms. The return time from a poll function can only be quicker when there is an event raised on one of the active SRT sockets. #### `srt_epoll_uwait` In this function only the SRT sockets can be subscribed (it reports error if you pass an epoll id that is subscribed to system sockets). This function waits for the first event on subscribed SRT sockets and reports all events collected at that moment in an array with the following structure: ```c++ typedef struct SRT_EPOLL_EVENT_ { SRTSOCKET fd; int events; } SRT_EPOLL_EVENT; ``` Every item reports a single socket with all events as flags. When the timeout is not -1, and no sockets are ready until the timeout time passes, this function returns 0. This behavior is different in `srt_epoll_wait`. The extra `srt_epoll_clear_usocks` function removes all subscriptions from the epoll container. The SRT EPoll system does not supports all features of Linux epoll. For example, it only supports level-triggered events for system sockets. ## Transmission Types **NOTE:** There might be a difference in terminology used in [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) and current documentation. Please consult [Data Transmission Modes](https://tools.ietf.org/html/draft-sharabayko-srt-01#section-4.2) and [Best Practices and Configuration Tips for Data Transmission via SRT](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-7) sections of the Internet Draft additionally. The current section is going to be reworked accordingly. SRT was originally intended to be used for Live Streaming and therefore its main and default transmission type is "live". However, SRT supports the modes that the original UDT library supported, that is, *file* and *message* transmission. There are two general modes: **Live** and **File** transmission. Inside File transmission mode, there are also two possibilities: **Buffer API** and **Message API**. The Live mode uses Message API. However it doesn't exactly match the description of the Message API because it uses a maximum single sending buffer up to the size that fits in one UDP packet. There are two options to set a particular type: - `SRTO_TRANSTYPE`: uses the enum value with `SRTT_LIVE` for live mode and `SRTT_FILE` for file mode. This option actually changes several parameters to their default values for that mode. After this is done, additional parameters, including those that are set here, can be further changed. - `SRTO_MESSAGEAPI`: This sets the Message API (true) or Buffer API (false) This makes possible a total of three data transmission methods: - [Live](#transmission-method-live) - [Buffer](#transmission-method-buffer) - [Message](#transmission-method-message) ### Terminology The following terms are used in the description of transmission types: **HANGUP / RESUME**: These terms have different meanings depending on the blocking state. They describe how a particular function behaves when performing an operation requires a specific readiness condition to be satisfied. In blocking mode HANGUP means that the function blocks until a condition is satisfied. RESUME means that the condition is satisfied and the function performs the required operation. In non-blocking mode the only difference is that HANGUP, instead of blocking, makes the function exit immediately with an appropriate error code (such as SRT_EASYNC*, SRT_ETIMEOUT or SRT_ECONGEST) explaining why the function is not ready to perform the operation. Refer to the error descriptions in [API-functions.md](API-functions.md) for details. The following types of operations are involved: 1. Reading data: `srt_recv`, `srt_recvmsg`, `srt_recvmsg2`, `srt_recvfile`. The function HANGS UP if there are no available data to read, and RESUMES when readable data become available (`SRT_EPOLL_IN` flag set in epoll). Use `SRTO_RCVSYN` to control blocking mode here. 2. Writing data: `srt_send`, `srt_sendmsg`, `srt_sendmsg2`, `srt_sendfile`. The function HANGS UP if the sender buffer becomes full and unable to store any additional data, and RESUMES if the data scheduled for sending have been removed from the sender buffer (after being sent and acknowledged) and there is enough free space in the sender buffer to store data (`SRT_EPOLL_OUT` flag set in epoll). Use `SRTO_SNDSYN` to control blocking mode here. 3. Accepting an incoming connection: `srt_accept` The function HANGS UP if there are no new connections reporting in, and RESUMES when a new connection has been processed and a new socket or group has been created to handle it. Note that this function requires the listener socket to get the connection (the flag `SRTO_RCVSYN` set on the listener socket controls the blocking mode for this operation). Note also that the blocking mode for a similar `srt_accept_bond` function is controlled exclusively by its timeout parameter because it can work with multiple listener sockets, potentially with different settings. 4. Connecting: `srt_connect` and its derivatives The function HANGS UP in the beginning, and RESUMES when the socket used for connecting is either ready to perform transmission operations or has failed to connect. It behaves a little differently in non-blocking mode -- the function should be called only once, and it simply returns a success result as a "HANGUP". Calling it again with the same socket would be an error. Calling it with a group would start a completely new connection. It is only possible to determine whether an operation has finished ("has RESUMED") from epoll flags. The socket, when successfully connected, would have `SRT_EPOLL_OUT` set, that is, becomes ready to send data, and `SRT_EPOLL_ERR` when it failed to connect. **BLIND / FAST / LATE REXMIT**: BLIND REXMIT is a situation where packets that were sent are still not acknowledged, either in the expected time frame, or when another ACK has come for the same number, but no packets have been reported as lost, or at least not for all still unacknowledged packets. The congestion control class is responsible for the algorithm for taking care of this situation, which is either `FASTREXMIT` or `LATEREXMIT`. This will be explained below. ### Transmission Method: Live Setting `SRTO_TRANSTYPE` to `SRTT_LIVE` sets the following [socket options](API-socket-options.md): - [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) = true - [`SRTO_RCVLATENCY`](API-socket-options.md#SRTO_RCVLATENCY) = 120 - [`SRTO_PEERLATENCY`](API-socket-options.md#SRTO_PEERLATENCY) = 0 - [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP) = true - [`SRTO_LINGER`](API-socket-options.md#SRTO_LINGER) = 0 - [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) = true - [`SRTO_NAKREPORT`](API-socket-options.md#SRTO_NAKREPORT) = true - [`SRTO_RETRANSMITALGO`](API-socket-options.md#SRTO_RETRANSMITALGO) = 1 - [`SRTO_PAYLOADSIZE`](API-socket-options.md#SRTO_PAYLOADSIZE) = 1316 - [`SRTO_CONGESTION`](API-socket-options.md#SRTO_CONGESTION) = "live" In this mode, every call to a sending function is allowed to send only so much data, as declared by `SRTO_PAYLOADSIZE`, whose value is still limited to a maximum of 1456 bytes. The application that does the sending is by itself responsible for calling the sending function in appropriate time intervals between subsequent calls. By default, this implies that the receiver uses 120 ms of latency, which is the declared time interval between the moment when the packet is scheduled for sending at the sender side, and when it is received by the receiver application (that is, the data are kept in the buffer and declared as not received, until the time comes for the packet to "play"). This mode uses the `LiveCC` congestion control class, which puts only a slight limitation on the bandwidth, if needed (i.e. by adding extra time if the interval between two consecutive packets would otherwise be too short for the defined speed limit). Note that it is not intended to work with "virtually infinite" ingest speeds (such as, for example, reading directly from a file). Therefore the application is not allowed to stream data with maximum speed -- it must take care that the speed of data being sent is in rhythm with timestamps in the live stream. Otherwise the behavior is undefined and might be surprisingly disappointing. The reading function will always return only a payload that was sent, and it will HANGUP until the time to play has come for this packet (if TSBPD mode is on) or when it is available without gaps of lost packets (if TSBPD mode is off - see [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE)). You may wish to tweak some of the parameters below: - `SRTO_TSBPDMODE`: You can turn off controlled latency if your application uses its own method of latency control. - `SRTO_RCVLATENCY`: You can increase the latency time, if this is too short. Setting a shorter latency than the default is strongly discouraged, although in some very specific and dedicated networks this may still be reasonable. Note that `SRTO_PEERLATENCY` is an option for the sending party, which is the minimum possible value for a receiver. - `SRTO_TLPKTDROP`: When true (default), this will drop the packets that haven't been retransmitted on time, that is, before the next packet that is already received becomes ready to play. You can turn this off to always ensure a clean delivery. However, a lost packet can simply pause a delivery for some longer, potentially undefined time, and cause even worse tearing for the player. Setting higher latency will help much more in the case when TLPKTDROP causes packet drops too often. - `SRTO_NAKREPORT`: Turns on repeated sending of loss reports, when the lost packet was not recovered quickly enough, which raises suspicions that the loss report itself was lost. Without it, the loss report will be always reported just once and never repeated again, and then the lost payload packet will be probably dropped by the TLPKTDROP mechanism. - `SRTO_RETRANSMITALGO`: Given the receiver sends periodic NAK reports, the sender can reduce the retransmission overhead by not retransmitting a loss more often than once per RTT (value 1). - `SRTO_PAYLOADSIZE`: Default value is for MPEG TS. If you are going to use SRT to send any different kind of payload, such as, for example, wrapping a live stream in very small frames, then you can use a bigger maximum frame size, though not greater than 1456 bytes. Parameters from the modified for transmission type list, not mentioned in the list above, are crucial for Live mode and shall not be changed. The BLIND REXMIT situation is resolved using the FASTREXMIT algorithm by LiveCC: sending non-acknowledged packets blindly on the premise that the receiver lingers too long before acknowledging them. This mechanism isn't used (i.e. the BLIND REXMIT situation isn't handled at all) when `SRTO_NAKREPORT` is set by the peer -- the NAKREPORT method is considered so effective that FASTREXMIT isn't necessary. ### Transmission Method: Buffer Setting `SRTO_TRANSTYPE` to `SRTT_FILE` sets the following [socket options](API-socket-options.md): - [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) = false - [`SRTO_RCVLATENCY`](API-socket-options.md#SRTO_RCVLATENCY) = 0 - [`SRTO_PEERLATENCY`](API-socket-options.md#SRTO_PEERLATENCY) = 0 - [`SRTO_TLPKTDROP`](API-socket-options.md#SRTO_TLPKTDROP) = false - [`SRTO_LINGER`](API-socket-options.md#SRTO_LINGER) = 180 s - [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) = false - [`SRTO_NAKREPORT`](API-socket-options.md#SRTO_NAKREPORT) = false - [`SRTO_RETRANSMITALGO`](API-socket-options.md#SRTO_RETRANSMITALGO) = 0 - [`SRTO_PAYLOADSIZE`](API-socket-options.md#SRTO_PAYLOADSIZE) = 0 - [`SRTO_CONGESTION`](API-socket-options.md#SRTO_CONGESTION) = "file" In this mode, calling a sending function is allowed to potentially send virtually any size of data. The sending function will HANGUP only if the sending buffer is completely filled, and RESUME if the sending buffers are available for at least one smallest portion of data passed for sending. The sending function need not send everything in this call, and the caller must be aware that the sending function might return sent data of smaller size than was actually requested. From the receiving function there will be retrieved as many data as the minimum of the passed buffer size and available data; data still available and not retrieved by this call will be available for retrieval in the next call. There is also a dedicated pair of functions that can only be used in this mode: `srt_sendfile` and `srt_recvfile`. These functions can be used to transmit the whole file, or a fragment of it, based on the offset and size. This mode uses the `FileCC` congestion control class, which is a direct copy of UDT's `CUDTCC` congestion control class, adjusted to the needs of SRT's congestion control framework. This class generally sends the data with maximum speed in the beginning, until the flight window is full, and then keeps the speed at the edge of the flight window, only slowing down in the case where packet loss was detected. The bandwidth usage can be directly limited by the `SRTO_MAXBW` option. The BLIND REXMIT situation is resolved in FileCC using the LATEREXMIT algorithm: when the repeated ACK was received for the same packet, or when the loss list is empty and the flight window is full, all packets since the last ACK are sent again (that's more or less the TCP behavior, but in contrast to TCP, this is done as a very low probability fallback). Most of the parameters described above have `false` or `0` values as they usually designate features used in Live mode. None are used with File mode. The only option that makes sense to modify after the `SRTT_FILE` type was set is `SRTO_MESSAGEAPI`, which is described below. ### Transmission Method: Message Setting `SRTO_TRANSTYPE` to `SRTT_FILE` and then setting `SRTO_MESSAGEAPI` to `true` implies usage of the Message transmission method. Parameters are set as described above for the Buffer method, with the exception of `SRTO_MESSAGEAPI`. The "file" congestion controller is also used in this mode. It differs from the Buffer method, however, in terms of the rules concerning sending and receiving. **HISTORICAL INFO**: The library on which SRT was based (UDT) somewhat misleadingly used the terms `STREAM` and `DGRAM`, and used the system symbols `SOCK_STREAM` and `SOCK_DGRAM` in the socket creation function. A "datagram" in the UDT terminology has nothing to do with the "datagram" term in networking terminology, where its size is limited to as much it can fit in one MTU. In UDT it is actually a message, which may span multiple UDP packets and has clearly defined boundaries. It's rather similar to the **SCTP** protocol. Also, in UDP the API functions were strictly bound to `DGRAM` or `STREAM` mode: `UDT::send/UDT::recv` were only for `STREAM` and `UDT::sendmsg/UDT::recvmsg` only for `DGRAM`. In SRT this is changed: all functions can be used in all modes, except `srt_sendfile/srt_recvfile`, and how the functions actually work is controlled by the `SRTO_MESSAGEAPI` flag. In message mode, every sending function sends **exactly** as much data as it is passed in a single sending function call. The receiver also receives not less than **exactly** the number of bytes that was sent (although every message may have a different size). Every message may also have extra parameters: - **TTL** defines how much time (in ms) the message should wait in the sending buffer for the opportunity to be picked up by the sender thread and sent over the network; otherwise it is dropped. Note that this TTL only applies to packets that have been lost and should be retransmitted. - **INORDER**, when true, means the messages must be read by the receiver in exactly the same order in which they were sent. In the situation where a message suffers a packet loss, this prevents any subsequent messages from achieving completion status prior to recovery of the preceding message. The sending function will HANGUP when the free space in the sending buffer does not exactly fit the whole message, and it will only RESUME if the free space in the sending buffer grows up to this size. The call to the sending function also returns with an error when the size of the message exceeds the total size of the buffer (this can be modified by the `SRTO_SNDBUF` option). In other words, it is not designed to send just a part of the message -- either the whole message is sent, or nothing at all. The receiving function will HANGUP until the whole message is available for reading; if the message spans multiple UDP packets, then the function RESUMES only when every single packet from the message has been received, including recovered packets, if any. When the INORDER flag is set to false and parts of multiple messages are currently available, the first message that is complete (possibly recovered) is returned. Otherwise the function does a HANGUP until the next message is complete. The call to the receiving function is rejected if the buffer size is too small for a single message to fit in it. Note that you can use any of the sending and receiving functions for sending and receiving messages, except `sendfile/recvfile`, which are dedicated exclusively for Buffer API. For more information, see [SRT API Socket Options](API-socket-options.md). [Return to Top of Page](#srt-api) srt-1.5.4/docs/API/configuration-guidelines.md000066400000000000000000000110721471311275400212170ustar00rootroot00000000000000# Configuration Guidelines ## Receiver Buffer Size The receiver buffer can be configured with the [`SRTO_RCVBUF`](./API-socket-options.md#SRTO_RCVBUF) socket option. Buffer size in bytes is expected to be passed in the `optval` argument of the `srt_setsockopt(..)` function. However, internally the value will be converted into the number of packets stored in the receiver buffer. The allowed value of `SRTO_RCVBUF` is also limited by the value of the flow control window size [`SRTO_FC`](./API-socket-options.md#SRTO_FC) socket option. See issue [#700](https://github.com/Haivision/srt/issues/700). The default flow control window size is 25600 packets. It is approximately: - **270 Mbits** of payload in the default live streaming configuration with an SRT payload size of **1316 bytes**; - **300 Mbits** of payload in the default file transfer configuration with an SRT payload size of **1456 bytes**. The default receiver buffer size is 8192 packets. It is approximately: - **86 Mbits** of payload with the effective SRT payload size of **1316 bytes**. ### Setting Receiver Buffer Size When the `SRTO_RCVBUF` option value is set using the `srt_setsockopt(..)` function, the provided size in bytes is internally converted to the corresponding size in packets. The size of a cell for a single packet in the buffer is defined by the `SRTO_MSS` option, which is 1500 by default. This value, decreased by 28 in the case of IPv4 (20 bytes for the IPv4 header and 8 bytes for the UDP header), gives 1472 bytes per packet to be allocated. The actual memory occupied by the receiver buffer will be a multiple of that value. For the default 8192 packets it will be 11776 kB (11.5 MB). Note that every cell has 16 bytes for the SRT header. The remaining space is for the payload. As already mentioned, the maximum allowed size of the receiver buffer is limited by the value of `SRTO_FC`. The following function returns the configured buffer size in packets depending on the SRTO_RCVBUF, SRTO_MSS and SRTO_FC values set: ```c++ int getRbufSizePkts(int SRTO_RCVBUF, int SRTO_MSS, int SRTO_FC) { // UDP/IPv4 header size is assumed to be 28 bytes // 20 bytes IPv4 + 8 bytes of UDP const int UDP_IPv4_HDR= 28; const int pkts = (rbuf_size / (SRTO_MSS - UDP_IPv4_HDR)); return min(pkts, SRTO_FC); } ``` If the value of `SRTO_RCVBUF` in packets exceeds `SRTO_FC`, then it is silently set to the value in bytes corresponding to `SRTO_FC`. Therefore, to set higher values of `SRTO_RCVBUF` the value of `SRTO_FC` must be increased first. ### Calculating Target Size in Packets The minimum size of the receiver buffer in packets can be calculated as follows: `pktsRBufSize = bps / 8 × (RTTsec + latency_sec) / bytePayloadSize` where - `bps` is the payload bitrate of the stream in bits per second; - `RTTsec` is the RTT of the network connection in seconds; - `bytePayloadSize` is the expected size of the payload of the SRT data packet. If the whole remainder of the MTU is expected to be used, payload size is calculated as follows: `bytePayloadSize = MSS - UDP_IPv4_HDR - SRT_HDR` where - `MSS`: Maximum Segment Size (size of the MTU); see `SRTO_MSS` (default: 1500) - `UDP_IPv4_HDR`: 20 bytes for IPv4 + 8 bytes for UDP - `SRT_HDR`: 16 bytes of SRT header (belonging to the user space) ### Calculating Target Size to Set To determine the value to pass in `srt_setsockopt(..)` with `SRTO_RCVBUF` the size in packets `pktsRBufSize` must be converted to the size in bytes assuming the internal conversion of the `srt_setsockopt(..)` function. The target size of the payload stored by the receiver buffer would be: `SRTO_RCVBUF = pktsRBufSize × (SRTO_MSS - UDPHDR_SIZE)` where - `UDPHDR_SIZE` = 28 (20 bytes IPv4, 8 bytes of UDP) - `SRTO_MSS` is the corresponding socket option value at the moment of setting `SRTO_RCVBUF`. ### Summing Up ```c++ auto CalculateTargetRBufSize(int msRTT, int bpsRate, int bytesPayloadSize, int msLatency, int SRTO_MSS) { const int UDPHDR_SIZE = 28; const long long targetPayloadBytes = static_cast(msLatency + msRTT / 2) * bpsRate / 1000 / 8; const long long targetNumPackets = targetPayloadBytes / bytesPayloadSize; const long long targetSizeValue = targetNumPackets * (SRTO_MSS - UDPHDR_SIZE); return {targetNumPackets, targetSizeValue}; } // Configuring const auto [fc, rcvbuf] = CalculateTargetRBufSize(msRTT, bpsRate, bytesPayloadSize, SRTO_RCVLATENCY, SRTO_MSS); int optval = fc; int optlen = sizeof optval; srt_setsockopt(sock, 0, SRTO_FC, (void*) &optval, optlen); optval = rcvbuf; srt_setsockopt(sock, 0, SRTO_RCVBUF, (void*) &optval, optlen); ``` srt-1.5.4/docs/API/rejection-codes.md000066400000000000000000000636511471311275400173110ustar00rootroot00000000000000# SRT Rejection Codes This document provides an overview of the rejection (error) codes used by and supported within SRT and SRT-based applications. For information on other types of error codes refer to the [API Socket Options](./docs/API/API-socket-options.md) document. [:arrow_down:   Jump to list of rejection codes](#api-function-rejection-codes) ## Summary of Rejection Codes Rejection codes are used in the SRT API, and are transferred on the wire as a part of a Handshake packet (refer to the `Handshake Type` field of the [Handshake](./docs/features/handshake.md) packet). The rejection codes are divided into several ranges: - SRT internal - Predefined application level codes - User defined (custom) codes In the SRT API these ranges are marked with the following constants (preprocessor definitions): - `SRT_REJC_INTERNAL` = 0 - `SRT_REJC_PREDEFINED` = 1000 - `SRT_REJC_USERDEFINED` = 2000 When transferred on the wire, the API value is incremented by 1000 to become the `Handshake Type` field value. In the following sections the values of rejection reason codes are given in accordance with the API values. ### SRT Internal Rejection Codes Defined in [**srt.h**](srtcore/srt.h), these codes provide the reason why a connection is rejected by SRT. They cover the reserved range 0 - 999 (below `SRT_REJC_PREDEFINED`). These codes cannot be used by applications to report a rejection reason. Naming: `SRT_REJ_*` - `SRT_REJ_UNKNOWN` = 0 - `SRT_REJ_SYSTEM` = 1 - ... - `SRT_REJ_CRYPTO` = 17 See [the list below](#api-function-rejection-codes) for details. ### Extended Rejection Codes As defined in [**access_control.h**](srtcore/access_control.h), these are standard server error codes including those adopted from HTTP. They provide the reason why an application rejects a connection. The value is expected to be set by an application via the listener callback if it wants to reject an incoming connection request. These codes cover the reserved range 1000 - 1999 (`SRT_REJC_PREDEFINED` - `SRT_REJC_USERDEFINED`). Subranges (1000 + value): - **0 - 99**: Reserved for unique SRT-specific codes (unused by HTTP) - **100 - 399**: Info, Success, and Redirection in HTTP (unused by SRT) - **400 - 599**: Client and server errors in HTTP (adopted by SRT) Naming: `SRT_REJX_*` Example: - `SRT_REJX_KEY_NOTSUP` (1001): The key used in the StreamID keyed string is not supported by the service. - `SRT_REJX_BAD_REQUEST` (1400) - ... ### User Defined Rejection Codes These codes can be freely defined by an application. They can be custom codes, not adopted by other vendors. For example, `2005: “Makito license expiredâ€`. They cover the reserved range 2000 - 2999 (higher than `SRT_REJC_USERDEFINED`). ## API Function Rejection Codes SRT's API function rejection codes refer to system-level error conditions caused by SRT-specific settings or operating conditions. They are uninfluenced by application-related events, and applications are not permitted to use or simulate these codes. The table below lists the rejection codes as defined in [**srt.h**](srtcore/srt.h) (click the *Rejection Reason* link to view a complete description). | *Code* | *Rejection Reason* | *Since* | *Description* | |:------:|:-------------------------------------------------- |:-------:|:-------------------------------------------------------------------------------------------------------------- | | 0 | [SRT_REJ_UNKNOWN](#SRT_REJ_UNKNOWN) | 1.3.4 | Fallback value for cases where connection is not rejected. | | 1 | [SRT_REJ_SYSTEM](#SRT_REJ_SYSTEM) | 1.3.4 | System function reported a failure. | | 2 | [SRT_REJ_PEER](#SRT_REJ_PEER) | 1.3.4 | Connection rejected by peer, with no additional details. | | 3 | [SRT_REJ_RESOURCE](#SRT_REJ_RESOURCE) | 1.3.4 | Problem with resource allocation (usually memory). | | 4 | [SRT_REJ_ROGUE](#SRT_REJ_ROGUE) | 1.3.4 | Data sent by one party cannot be interpreted. | | 5 | [SRT_REJ_BACKLOG](#SRT_REJ_BACKLOG) | 1.3.4 | Listener's backlog has been exceeded. | | 6 | [SRT_REJ_IPE](#SRT_REJ_IPE) | 1.3.4 | Internal Program Error. | | 7 | [SRT_REJ_CLOSE](#SRT_REJ_CLOSE) | 1.3.4 | Listener socket received a request as it is being closed. | | 8 | [SRT_REJ_VERSION](#SRT_REJ_VERSION) | 1.3.4 | Minimum version requirement for a connection not satisfied by one party. | | 9 | [SRT_REJ_RDVCOOKIE](#SRT_REJ_RDVCOOKIE) | 1.3.4 | Rendezvous cookie collision. | | 10 | [SRT_REJ_BADSECRET](#SRT_REJ_BADSECRET) | 1.3.4 | Both parties have defined connection passphrases that differ. | | 11 | [SRT_REJ_UNSECURE](#SRT_REJ_UNSECURE) | 1.3.4 | Only one party has set up a connection password. | | 12 | [SRT_REJ_MESSAGEAPI](#SRT_REJ_MESSAGEAPI) | 1.3.4 | [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag is different on both connection parties. | | 13 | [SRT_REJ_CONGESTION](#SRT_REJ_CONGESTION) | 1.3.4 | Incompatible congestion-controller type. | | 14 | [SRT_REJ_FILTER](#SRT_REJ_FILTER) | 1.3.4 | [`SRTO_PACKETFILTER`](API-socket-options.md#SRTO_PACKETFILTER) option is different on both connection parties. | | 15 | [SRT_REJ_GROUP](#SRT_REJ_GROUP) | 1.4.2 | Group type or group settings are incompatible between connection parties. | | 16 | [SRT_REJ_TIMEOUT](#SRT_REJ_TIMEOUT) | 1.4.2 | Connection not rejected, but timed out. | | 17 | [SRT_REJ_CRYPTO](#SRT_REJ_CRYPTO) | 1.5.2 | Connection rejected due to unsupported or mismatching encryption mode. | | | | | | ## Access Control Rejection Codes SRT's access control rejection codes are intended for use by applications to forcefully reject connections in SRT listener callbacks. They are intended only as a guide to promote standardization. If they are used in an application, a description of their specific implementation should be published (the descriptions in this documentation are not definitive). The table below lists the rejection codes as defined in [**access_control.h**](srtcore/access_control.h) (click the *Rejection Reason* link to view a complete description). | *Code* | *Rejection Reason* | *Since* | *Description* | |:------:|:------------------------------------------------- |:-------:|:-------------------------------------------------------------------------------------------------------------- | | 1000 | [SRT_REJX_FALLBACK](#SRT_REJX_FALLBACK) | 1.4.2 | Callback handler has interrupted an incoming connection. | | 1001 | [SRT_REJX_KEY_NOTSUP](#SRT_REJX_KEY_NOTSUP) | 1.4.2 | Key specified in StreamID string not supported by application. | | 1002 | [SRT_REJX_FILEPATH](#SRT_REJX_FILEPATH) | 1.4.2 | Resource type designates file where path has wrong syntax or is not found. | | 1003 | [SRT_REJX_HOSTNOTFOUND](#SRT_REJX_HOSTNOTFOUND) | 1.4.2 | The host specified in the `h` key cannot be identified. | | 1400 | [SRT_REJX_BAD_REQUEST](#SRT_REJX_BAD_REQUEST) | 1.4.2 | General syntax error. | | 1401 | [SRT_REJX_UNAUTHORIZED](#SRT_REJX_UNAUTHORIZED) | 1.4.2 | Authentication failed; client unauthorized to access the resource. | | 1402 | [SRT_REJX_OVERLOAD](#SRT_REJX_OVERLOAD) | 1.4.2 | Server load too heavy to process request, or credit limit exceeded. | | 1403 | [SRT_REJX_FORBIDDEN](#SRT_REJX_FORBIDDEN) | 1.4.2 | Access denied to the resource for any reason. | | 1404 | [SRT_REJX_NOTFOUND](#SRT_REJX_NOTFOUND) | 1.4.2 | Resource specified by `r` and `h` keys cannot be found. | | 1405 | [SRT_REJX_BAD_MODE](#SRT_REJX_BAD_MODE) | 1.4.2 | Mode specified in the `m` key in StreamID is not supported for this request. | | 1406 | [SRT_REJX_UNACCEPTABLE](#SRT_REJX_UNACCEPTABLE) | 1.4.2 | Unavailable parameters in `StreamID`, or `m=publish` data format not supported. | | 1409 | [SRT_REJX_CONFLICT](#SRT_REJX_CONFLICT) | 1.4.2 | Resource specified by `r` and `h` keys is locked for modification. | | 1415 | [SRT_REJX_NOTSUP_MEDIA](#SRT_REJX_NOTSUP_MEDIA) | 1.4.2 | Media type not supported by the application. | | 1423 | [SRT_REJX_LOCKED](#SRT_REJX_LOCKED) | 1.4.2 | Resource is locked against any access. | | 1424 | [SRT_REJX_FAILED_DEPEND](#SRT_REJX_FAILED_DEPEND) | 1.4.2 | Dependent entity for the request is not present. | | 1500 | [SRT_REJX_ISE](#SRT_REJX_ISE) | 1.4.2 | Internal server error. | | 1501 | [SRT_REJX_UNIMPLEMENTED](#SRT_REJX_UNIMPLEMENTED) | 1.4.2 | Request not supported by current version of the service. | | 1502 | [SRT_REJX_GW](#SRT_REJX_GW) | 1.4.2 | Target endpoint rejected connection from gateway server | | 1503 | [SRT_REJX_DOWN](#SRT_REJX_DOWN) | 1.4.2 | Service is down for maintenance. | | 1505 | [SRT_REJX_VERSION](#SRT_REJX_VERSION) | 1.4.2 | SRT application version not supported. | | 1507 | [SRT_REJX_NOROOM](#SRT_REJX_NOROOM) | 1.4.2 | Data stream cannot be archived due to lack of storage space. | | | | | | **NOTE**: SRT rejection codes follow this prefix convention: - `SRT_REJ`: standard rejection codes from SRT API functions (0 - 99) - `SRT_REJC`: mark the border values between ranges. - `SRT_REJX`: extended rejection codes (code values above 1000).above)?* ## API Function Rejection Reasons #### SRT_REJ_UNKNOWN A fallback value for cases when there was no connection rejected. #### SRT_REJ_SYSTEM One system function reported a failure. Usually this means some system error or lack of system resources to complete the task. #### SRT_REJ_PEER The connection has been rejected by the peer, but no further details are available. This usually means that the peer doesn't support rejection reason reporting. #### SRT_REJ_RESOURCE A problem with resource allocation (usually memory). #### SRT_REJ_ROGUE The data sent by one party to another cannot be properly interpreted. This should not happen during normal usage, unless it's a bug, or some weird events are happening on the network. #### SRT_REJ_BACKLOG The listener's backlog has exceeded its queue limit (there are many other callers waiting for the opportunity to be connected and the "wait queue" has reached its limit). #### SRT_REJ_IPE Internal Program Error. This should not happen during normal usage. It usually indicates a bug in the software (although this can be reported by both local and foreign hosts). #### SRT_REJ_CLOSE The listener socket was able to receive the request, but is currently being closed. It's likely that the next request will result in a timeout. #### SRT_REJ_VERSION One party in the connection has set up a minimum version that is required for that connection, but the other party doesn't satisfy this requirement. #### SRT_REJ_RDVCOOKIE Rendezvous cookie collision. Normally, the probability that this will happen is negligible. However, it *can* result from a misconfiguration when, in attempting to make a rendezvous connection, both parties try to bind to the same IP address, or both are local addresses of the same host. In such a case the sent handshake packets are returned to the same host as if they were sent by the peer (i.e. a party is sending to itself). In such situations, this reject reason will be reported for every attempt. #### SRT_REJ_BADSECRET Both parties have defined a passphrase for a connection, but they differ. #### SRT_REJ_UNSECURE Only one connection party has set up a password. See also the [`SRTO_ENFORCEDENCRYPTION`](API-socket-options.md#SRTO_ENFORCEDENCRYPTION) flag. #### SRT_REJ_MESSAGEAPI The value of the [`SRTO_MESSAGEAPI`](API-socket-options.md#SRTO_MESSAGEAPI) flag is different on both parties in a connection. #### SRT_REJ_CONGESTION The [`SRTO_CONGESTION`](API-socket-options.md#SRTO_CONGESTION)option has been set up differently on both parties in a connection. #### SRT_REJ_FILTER The [`SRTO_PACKETFILTER`](API-socket-options.md#SRTO_PACKETFILTER) option has been set differently on both parties in a connection. #### SRT_REJ_GROUP The group type or some group settings are incompatible between connection parties. While every connection within a bonding group may have different target addresses, they should all designate the same endpoint and the same SRT application. If this condition isn't satisfied, then the peer will respond with a different peer group ID for the connection that is trying to contact a machine/application that is completely different from the existing connections in the bonding group. #### SRT_REJ_TIMEOUT The connection wasn't rejected, but it timed out. This code is always sent on a connection timeout, but this is the only way to get this state in non-blocking mode (see [`SRTO_RCVSYN`](API-socket-options.md#SRTO_RCVSYN)). There may also be server and user rejection codes, as defined by the `SRT_REJC_INTERNAL`, `SRT_REJC_PREDEFINED`, and `SRT_REJC_USERDEFINED` constants. Note that the number space from the value of `SRT_REJC_PREDEFINED` 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 The connection was rejected due to a mismatch in crypto modes. See `SRTO_CRYPTOMODE`. [:arrow_up:   Back to top](#srt-rejection-codes) ## Access Control Rejection Reasons An SRT listener callback handler can decide to reject an incoming connection. Under normal circumstances, the rejection code is predefined as `SRT_REJ_RESOURCE`. The handler can, however, set its own rejection code. There are two numbered spaces intended for this purpose (as the range below `SRT_REJC_PREDEFINED` is reserved for internal codes): - `SRT_REJC_PREDEFINED` and above: These are predefined errors. Errors from this range (that is, below `SRT_REJC_USERDEFINED`) have their definitions provided in the `access_control.h` public header file. The intention is that applications using these codes understand the situations they describe in a standard way. - `SRT_REJC_USERDEFINED` and above: These are errors that are freely defined by the application. Codes from this range can be only understood if each application knows the code definitions of the other. These codes should be used only after making sure that the applications at either end of a connection understand them. The intention here is for the predefined codes to be consistent with the HTTP standard codes. Such code can be set by using the [`srt_setrejectreason`](docs/api/api-functions.md#srt-setrejectreason) function. The SRT-specific codes are: #### SRT_REJX_FALLBACK This code should be set by the callback handler in the beginning in case the application needs to be informed that the callback handler actually has interpreted the incoming connection, but hasn't set a more appropriate code describing the situation. #### SRT_REJX_KEY_NOTSUP Indicates there was a key specified in the StreamID string that this application doesn't support. Note that it's not obligatory for the application to react this way - it may chose to ignore unknown keys completely, or to have some keys in the ignore list (which it won't interpret, but tolerate) while rejecting any others. It is also up to the application to decide to return this specific error, or more generally report the syntax error with `SRT_REJX_BAD_REQUEST`. #### SRT_REJX_FILEPATH The resource type designates a file, and the path either has the wrong syntax or is not found. In the case where `t=file`, the path should be specified under the `r` key, and the file specified there must be able to be saved this way. It's up to the application to decide how to treat this path, how to parse it, and what this path specifically means. For the `r` key, the application should at least handle the single filename, and have storage space available to save it (provided a file of the same name does not already exist there). The application should decide whether and how to handle all other situations (like directory path, special markers in the path to be interpreted by the application, etc.), or to report this error. #### SRT_REJX_HOSTNOTFOUND The host specified in the `h` key cannot be identified. The `h` key is generally for a situation when you have multiple DNS names for a host, so an application may want to extract the name from the URI and set it to the `h` key so that the application can distinguish the request also by the target host name. The application may, however, limit the number of recognized services by host name to some predefined names and not handle the others, even if this is properly resolved by DNS. In this case it should report this error. The other error codes are HTTP codes adapted for SRT: #### SRT_REJX_BAD_REQUEST General syntax error. This can be reported in any case when parsing the StreamID contents failed, or it cannot be properly interpreted. #### SRT_REJX_UNAUTHORIZED Authentication failed, which makes the client unauthorized to access the resource. This error, however, confirms that the syntax is correct and the resource has been properly identified. Note that this cannot be reported when you use a simple user-password authentication method because in this case the password is verified only after the listener callback handler accepts the connection. This error is rather intended to be reported in the case of `t=auth` when the authentication process has generated some valid session ID, but then the session connection has specified a resource that is not within the frames of that authentication. #### SRT_REJX_OVERLOAD The server is too heavily loaded to process the request, or the credit limit for accessing the service and the resource has been exceeded. In HTTP the description mentions payment for a service, but it is also used by some services for general "credit" management for a client. In SRT it should be used when the service is doing any kind of credit management to limit access to selected clients that "have" enough credit, even if the credit is something the client can recharge itself, or that can be granted depending on available service resources. #### SRT_REJX_FORBIDDEN Access denied to the resource for any reason. This error is independent of an authorization or authentication error (as reported by `SRT_REJX_UNAUTHORIZED`). The application can decide which is more appropriate. This error is usually intended for a resource that should only be accessed after a successful authorization over a separate auth-only connection, where the query in StreamID has correctly specified the resource identity and mode, but the session ID (in the `s` key) is either (a) not specified, or (b) specifies a valid session, but the authorization region for this session does not include the specified resource. #### SRT_REJX_NOTFOUND The resource specified in the `r` key (in combination with the `h` key) is not found at this time. This error should be only reported if the information about resource accessibility is allowed to be publicly visible. Otherwise, the application might report authorization errors. #### SRT_REJX_BAD_MODE The mode specified in the `m` key in StreamID is not supported for this request. This may apply to read-only or write-only resources, as well when interactive (bidirectional) access is not valid for a resource. #### SRT_REJX_UNACCEPTABLE Applies when the parameters specified in StreamID cannot be satisfied for the requested resource, or when `m=publish` but the data format is not acceptable. This is a general error reporting an unsupported format for data that appears to be wrong when sending, or a restriction on the data format (as specified in the details of the resource specification) such that it cannot be provided when receiving. #### SRT_REJX_CONFLICT The resource being accessed (as specified by `r` and `h` keys) is locked for modification. This error should only be reported for `m=publish` when the resource being accessed is read-only because another client (not necessarily connected through SRT): - is currently publishing into this resource - has reserved this resource ID for publishing Note that this error should be reported when there is no other reason for having a problem accessing the resource. #### SRT_REJX_NOTSUP_MEDIA The media type is not supported by the application. The media type is specified in the `t` key. The currently standard types are `stream`, `file` and `auth`. An application may extend this list, and is not obliged to support all of the standard types. #### SRT_REJX_LOCKED The resource being accessed is locked against any access. This is similar to `SRT_REJX_CONFLICT`, but in this case the resource is locked for reading and writing. This is for when the resource should be shown as existing and available to the client, but access is temporarily blocked. #### SRT_REJX_FAILED_DEPEND The dependent entity for the request is not present. In this case the dependent entity is the session, which should be specified in the `s` key. This means that the specified session ID is nonexistent, or it has already expired. #### SRT_REJX_ISE Internal server error. This is for a general case when a request has been correctly verified, with no related problems found, but an unexpected error occurs after the processing of the request has started. #### SRT_REJX_UNIMPLEMENTED The request was correctly recognized, but the current software version of the service (be it SRT or any other software component) doesn't support it. This should be reported for a case where some features to be specified in the StreamID request are supposed to be supported in a predictable future, but the current version of the server does not support it, or the support for this feature in this version has been temporarily blocked. This shouldn't be reported for existing features that are being deprecated, or older features that are no longer supported (for this case the general `SRT_REJX_BAD_REQUEST` is more appropriate). #### SRT_REJX_GW The server acts as a gateway and the target endpoint rejected the connection. The reason the connection was rejected is unspecified. The gateway cannot forward the original rejection code from the target endpoint because this would suggest the error was on the gateway itself. Use this error with some other mechanism to report the original target error, if possible. #### SRT_REJX_DOWN The service is down for maintenance. This can only be reported when the service has been temporarily replaced by a stub that is only reporting this error, while the real service is down for maintenance. #### SRT_REJX_VERSION Application version not supported. This can refer to an application feature that is unsupported (possibly from an older SRT version), or to a feature that is no longer supported because of backward compatibility requirements. #### SRT_REJX_NOROOM The data stream cannot be archived due to a lack of storage space. This is reported when a request to send a file or a live stream to be archived is unsuccessful. Note that the length of a file transmission is usually pre-declared, so this error can be reported early. It can also be reported when the stream is of undefined length, and there is no more storage space available. [:arrow_up:   Back to top](#srt-rejection-codes) srt-1.5.4/docs/API/statistics.md000066400000000000000000001502411471311275400164160ustar00rootroot00000000000000 # SRT Statistics 1. [SRT Socket Statistics](#srt-socket-statistics) - [Summary Table](#summary-table) - [Accumulated Statistics](#accumulated-statistics) - [Interval-Based Statistics](#interval-based-statistics) - [Instantaneous Statistics](#instantaneous-statistics) 2. [SRT Group Statistics](#srt-group-statistics) - [Summary Table](#group-summary-table) - [Accumulated Statistics](#group-accumulated-statistics) - [Interval-Based Statistics](#group-interval-based-statistics) - [Formulas](#group-formulas) ## SRT Socket Statistics SRT provides a powerful set of statistical data on a socket. This data can be used to keep an eye on a socket's health and track faulty behavior. Statistics are calculated independently on each side (receiver and sender) and are not exchanged between peers unless explicitly stated. The following API functions can be used to retrieve statistics on an SRT socket: * `int srt_bstats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear)` * `int srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous)` Refer to the documentation of the [SRT API Functions](API-functions.md) for usage instructions. ### Summary Table The table below provides a summary of SRT socket statistics: name, type, unit of measurement, data type, and whether it is calculated by the sender or receiver. There are three types of statistics: - **Accumulated:** the statistic is accumulated since the time an SRT socket has been created (after the successful call to `srt_connect(...)` or `srt_bind(...)` function), e.g., [pktSentTotal](#pktSentTotal), etc., - **Interval-based:** the statistic is accumulated during a specified time interval (e.g., 100 milliseconds if SRT statistics is collected each 100 milliseconds) from the time an SRT socket has been created, e.g., [pktSent](#pktSent), etc. The value of the statistic can be reset by calling the `srt_bstats(..., int clear)` function with `clear = 1`, - **Instantaneous:** the statistic is obtained at the moment the `srt_bistats()` function is called, e.g., [msRTT](#msRTT), etc. See sections [Accumulated Statistics](#accumulated-statistics), [Interval-Based Statistics](#interval-based-statistics), and [Instantaneous Statistics](#instantaneous-statistics) for a detailed description of each statistic. | Statistic | Type of Statistic | Unit of Measurement | Available for Sender | Available for Receiver | Data Type | | --------------------------------------------------- | ----------------- | ------------------- | -------------------- | ---------------------- | --------- | | [msTimeStamp](#msTimeStamp) | accumulated | ms (milliseconds) | ✓ | ✓ | int64_t | | [pktSentTotal](#pktSentTotal) | accumulated | packets | ✓ | - | int64_t | | [pktRecvTotal](#pktRecvTotal) | accumulated | packets | - | ✓ | int64_t | | [pktSentUniqueTotal](#pktSentUniqueTotal) | accumulated | packets | ✓ | - | int64_t | | [pktRecvUniqueTotal](#pktRecvUniqueTotal) | accumulated | packets | - | ✓ | int64_t | | [pktSndLossTotal](#pktSndLossTotal) | accumulated | packets | ✓ | - | int32_t | | [pktRcvLossTotal](#pktRcvLossTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRetransTotal](#pktRetransTotal) | accumulated | packets | ✓ | - | int32_t | | [pktRcvRetransTotal](#pktRcvRetransTotal) | accumulated | packets | - | ✓ | int32_t | | [pktSentACKTotal](#pktSentACKTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRecvACKTotal](#pktRecvACKTotal) | accumulated | packets | ✓ | - | int32_t | | [pktSentNAKTotal](#pktSentNAKTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRecvNAKTotal](#pktRecvNAKTotal) | accumulated | packets | ✓ | - | int32_t | | [usSndDurationTotal](#usSndDurationTotal) | accumulated | us (microseconds) | ✓ | - | int64_t | | [pktSndDropTotal](#pktSndDropTotal) | accumulated | packets | ✓ | - | int32_t | | [pktRcvDropTotal](#pktRcvDropTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) | accumulated | packets | - | ✓ | int32_t | | [pktSndFilterExtraTotal](#pktSndFilterExtraTotal) | accumulated | packets | ✓ | - | int32_t | | [pktRcvFilterExtraTotal](#pktRcvFilterExtraTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRcvFilterSupplyTotal](#pktRcvFilterSupplyTotal) | accumulated | packets | - | ✓ | int32_t | | [pktRcvFilterLossTotal](#pktRcvFilterLossTotal) | accumulated | packets | - | ✓ | int32_t | | [byteSentTotal](#byteSentTotal) | accumulated | bytes | ✓ | - | uint64_t | | [byteRecvTotal](#byteRecvTotal) | accumulated | bytes | - | ✓ | uint64_t | | [byteSentUniqueTotal](#byteSentUniqueTotal) | accumulated | bytes | ✓ | - | uint64_t | | [byteRecvUniqueTotal](#byteRecvUniqueTotal) | accumulated | bytes | - | ✓ | uint64_t | | [byteRcvLossTotal](#byteRcvLossTotal) | accumulated | bytes | - | ✓ | uint64_t | | [byteRetransTotal](#byteRetransTotal) | accumulated | bytes | ✓ | - | uint64_t | | [byteSndDropTotal](#byteSndDropTotal) | accumulated | bytes | ✓ | - | uint64_t | | [byteRcvDropTotal](#byteRcvDropTotal) | accumulated | bytes | - | ✓ | uint64_t | | [byteRcvUndecryptTotal](#byteRcvUndecryptTotal) | accumulated | bytes | - | ✓ | uint64_t | | [pktSent](#pktSent) | interval-based | packets | ✓ | - | int64_t | | [pktRecv](#pktRecv) | interval-based | packets | - | ✓ | int64_t | | [pktSentUnique](#pktSentUnique) | interval-based | packets | ✓ | - | int64_t | | [pktRecvUnique](#pktRecvUnique) | interval-based | packets | - | ✓ | int64_t | | [pktSndLoss](#pktSndLoss) | interval-based | packets | ✓ | - | int32_t | | [pktRcvLoss](#pktRcvLoss) | interval-based | packets | - | ✓ | int32_t | | [pktRetrans](#pktRetrans) | interval-based | packets | ✓ | - | int32_t | | [pktRcvRetrans](#pktRcvRetrans) | interval-based | packets | - | ✓ | int32_t | | [pktSentACK](#pktSentACK) | interval-based | packets | - | ✓ | int32_t | | [pktRecvACK](#pktRecvACK) | interval-based | packets | ✓ | - | int32_t | | [pktSentNAK](#pktSentNAK) | interval-based | packets | - | ✓ | int32_t | | [pktRecvNAK](#pktRecvNAK) | interval-based | packets | ✓ | - | int32_t | | [pktSndFilterExtra](#pktSndFilterExtra) | interval-based | packets | ✓ | - | int32_t | | [pktRcvFilterExtra](#pktRcvFilterExtra) | interval-based | packets | - | ✓ | int32_t | | [pktRcvFilterSupply](#pktRcvFilterSupply) | interval-based | packets | - | ✓ | int32_t | | [pktRcvFilterLoss](#pktRcvFilterLoss) | interval-based | packets | - | ✓ | int32_t | | [mbpsSendRate](#mbpsSendRate) | interval-based | Mbps | ✓ | - | double | | [mbpsRecvRate](#mbpsRecvRate) | interval-based | Mbps | - | ✓ | double | | [usSndDuration](#usSndDuration) | interval-based | us (microseconds) | ✓ | - | int64_t | | [pktReorderDistance](#pktReorderDistance) | interval-based | packets | - | ✓ | int32_t | | [pktRcvBelated](#pktRcvBelated) | interval-based | packets | - | ✓ | int64_t | | [pktSndDrop](#pktSndDrop) | interval-based | packets | ✓ | - | int32_t | | [pktRcvDrop](#pktRcvDrop) | interval-based | packets | - | ✓ | int32_t | | [pktRcvUndecrypt](#pktRcvUndecrypt) | interval-based | packets | - | ✓ | int32_t | | [byteSent](#byteSent) | interval-based | bytes | ✓ | - | uint64_t | | [byteRecv](#byteRecv) | interval-based | bytes | - | ✓ | uint64_t | | [byteSentUnique](#byteSentUnique) | interval-based | bytes | ✓ | - | uint64_t | | [byteRecvUnique](#byteRecvUnique) | interval-based | bytes | - | ✓ | uint64_t | | [byteRcvLoss](#byteRcvLoss) | interval-based | bytes | - | ✓ | uint64_t | | [byteRetrans](#byteRetrans) | interval-based | bytes | ✓ | - | uint64_t | | [byteSndDrop](#byteSndDrop) | interval-based | bytes | ✓ | - | uint64_t | | [byteRcvDrop](#byteRcvDrop) | interval-based | bytes | - | ✓ | uint64_t | | [byteRcvUndecrypt](#byteRcvUndecrypt) | interval-based | bytes | - | ✓ | uint64_t | | [usPktSndPeriod](#usPktSndPeriod) | instantaneous | us (microseconds) | ✓ | - | double | | [pktFlowWindow](#pktFlowWindow) | instantaneous | packets | ✓ | - | int32_t | | [pktCongestionWindow](#pktCongestionWindow) | instantaneous | packets | ✓ | - | int32_t | | [pktFlightSize](#pktFlightSize) | instantaneous | packets | ✓ | - | int32_t | | [msRTT](#msRTT) | instantaneous | ms (milliseconds) | ✓ | ✓ | double | | [mbpsBandwidth](#mbpsBandwidth) | instantaneous | Mbps | ✓ | ✓ | double | | [byteAvailSndBuf](#byteAvailSndBuf) | instantaneous | bytes | ✓ | - | int32_t | | [byteAvailRcvBuf](#byteAvailRcvBuf) | instantaneous | bytes | - | ✓ | int32_t | | [mbpsMaxBW](#mbpsMaxBW) | instantaneous | Mbps | ✓ | - | double | | [byteMSS](#byteMSS) | instantaneous | bytes | ✓ | ✓ | int32_t | | [pktSndBuf](#pktSndBuf) | instantaneous | packets | ✓ | - | int32_t | | [byteSndBuf](#byteSndBuf) | instantaneous | bytes | ✓ | - | int32_t | | [msSndBuf](#msSndBuf) | instantaneous | ms (milliseconds) | ✓ | - | int32_t | | [msSndTsbPdDelay](#msSndTsbPdDelay) | instantaneous | ms (milliseconds) | ✓ | - | int32_t | | [pktRcvBuf](#pktRcvBuf) | instantaneous | packets | - | ✓ | int32_t | | [byteRcvBuf](#byteRcvBuf) | instantaneous | bytes | - | ✓ | int32_t | | [msRcvBuf](#msRcvBuf) | instantaneous | ms (milliseconds) | - | ✓ | int32_t | | [msRcvTsbPdDelay](#msRcvTsbPdDelay) | instantaneous | ms (milliseconds) | - | ✓ | int32_t | | [pktReorderTolerance](#pktReorderTolerance) | instantaneous | packets | - | ✓ | int32_t | | [pktRcvAvgBelatedTime](#pktRcvAvgBelatedTime) | instantaneous | ms (milliseconds) | - | ✓ | double | ### Accumulated Statistics #### msTimeStamp The time elapsed, in milliseconds, since the SRT socket has been created (after successful call to `srt_connect(...)` or `srt_bind(...)` function). Available both for sender and receiver. #### pktSentTotal The total number of sent DATA packets, including retransmitted packets ([pktRetransTotal](#pktRetransTotal)). Available for sender. If the `SRTO_PACKETFILTER` socket option is enabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic counts sent packet filter control packets ([pktSndFilterExtraTotal](#pktSndFilterExtraTotal)) as well. Introduced in SRT v1.4.0. #### pktRecvTotal The total number of received DATA packets, including retransmitted packets ([pktRcvRetransTotal](#pktRcvRetransTotal)). Available for receiver. If the `SRTO_PACKETFILTER` socket option is enabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic counts received packet filter control packets ([pktRcvFilterExtraTotal](#pktRcvFilterExtraTotal)) as well. Introduced in SRT v1.4.0. #### pktSentUniqueTotal The total number of *unique* DATA packets sent by the SRT sender. Available for sender. This value contains only *unique* *original* DATA packets. Retransmitted DATA packets ([pktRetransTotal](#pktRetransTotal)) are not taken into account. If the `SRTO_PACKETFILTER` socket option is enabled (refer to [SRT API Socket Options](API-socket-options.md)), packet filter control packets ([pktSndFilterExtraTotal](#pktSndFilterExtraTotal)) are also not taken into account. This value corresponds to the number of original DATA packets sent by the SRT sender. It counts every packet sent over the network for the first time, and can be calculated as follows: `pktSentUniqueTotal = pktSentTotal – pktRetransTotal`, or by `pktSentUniqueTotal = pktSentTotal – pktRetransTotal - pktSndFilterExtraTotal` if the `SRTO_PACKETFILTER` socket option is enabled. The original DATA packets are sent only once. #### pktRecvUniqueTotal The total number of *unique* original, retransmitted or recovered by the packet filter DATA packets *received in time*, *decrypted without errors* and, as a result, scheduled for delivery to the upstream application by the SRT receiver. Available for receiver. Unique means "first arrived" DATA packets. There is no difference whether a packet is original or, in case of loss, retransmitted or recovered by the packet filter. Whichever packet comes first is taken into account. This statistic doesn't count - duplicate packets (retransmitted or sent several times by defective hardware/software), - arrived too late packets (retransmitted or original packets arrived out of order) that were already dropped by the TLPKTDROP mechanism (see [pktRcvDropTotal](#pktRcvDropTotal) statistic), - arrived in time packets, but decrypted with errors (see [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) statistic), and, as a result, dropped by the TLPKTDROP mechanism (see [pktRcvDropTotal](#pktRcvDropTotal) statistic). DATA packets recovered by the packet filter ([pktRcvFilterSupplyTotal](#pktRcvFilterSupplyTotal)) are taken into account if the `SRTO_PACKETFILTER` socket option is enabled (refer to [SRT API Socket Options](API-socket-options.md)). Do not mix up with the control packets received by the packet filter ([pktRcvFilterExtraTotal](#pktRcvFilterExtraTotal)). #### pktSndLossTotal The total number of data packets considered or reported as lost at the sender side. Does not correspond to the packets detected as lost at the receiver side. Available for sender. A packet is considered lost in two cases: 1. Sender receives a loss report from a receiver, 2. Sender initiates retransmission after not receiving an ACK packet for a certain timeout. Refer to `FASTREXMIT` and `LATEREXMIT` algorithms. #### pktRcvLossTotal The total number of SRT DATA packets detected as presently missing (either reordered or lost) at the receiver side. Available for receiver. The detection of presently missing packets is triggered by a newly received DATA packet with the sequence number `s`. If `s` is greater than the sequence number `next_exp` of the next expected packet (`s > next_exp`), the newly arrived packet `s` is considered in-order and there is a sequence discontinuity of size `s - next_exp` associated with this packet. The presence of sequence discontinuity means that some packets of the original sequence have not yet arrived (presently missing), either reordered or lost. Once the sequence discontinuity is detected, its size `s - next_exp` is added to `pktRcvLossTotal` statistic. Refer to [RFC 4737 - Packet Reordering Metrics](https://tools.ietf.org/html/rfc4737) for details. If the packet `s` is received out of order (`s < next_exp`), the statistic is not affected. Note that only original (not retransmitted) SRT DATA packets are taken into account. Refer to [pktRcvRetransTotal](#pktRcvRetransTotal) for the formula for obtaining the total number of lost retransmitted packets. In SRT v1.4.0, v1.4.1, the `pktRcvLossTotal` statistic includes packets that failed to be decrypted. To receive the number of presently missing packets, substract [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) from the current one. This is going to be fixed in SRT v.1.5.0. #### pktRetransTotal The total number of retransmitted packets sent by the SRT sender. Available for sender. This statistic is not interchangeable with the receiver [pktRcvRetransTotal](#pktRcvRetransTotal) statistic. #### pktRcvRetransTotal The total number of retransmitted packets registered at the receiver side. Available for receiver. This statistic is not interchangeable with the sender [pktRetransTotal](#pktRetransTotal) statistic. Note that the total number of lost retransmitted packets can be calculated as the total number of retransmitted packets sent by receiver minus the total number of retransmitted packets registered at the receiver side: `pktRetransTotal - pktRcvRetransTotal`. This is going to be implemented in SRT v1.5.0, see issue [#1208](https://github.com/Haivision/srt/issues/1208). #### pktSentACKTotal The total number of sent ACK (Acknowledgement) control packets. Available for receiver. #### pktRecvACKTotal The total number of received ACK (Acknowledgement) control packets. Available for sender. #### pktSentNAKTotal The total number of sent NAK (Negative Acknowledgement) control packets. Available for receiver. #### pktRecvNAKTotal The total number of received NAK (Negative Acknowledgement) control packets. Available for sender. #### usSndDurationTotal The total accumulated time in microseconds, during which the SRT sender has some data to transmit, including packets that have been sent, but not yet acknowledged. In other words, the total accumulated duration in microseconds when there was something to deliver (non-empty senders' buffer). Available for sender. #### pktSndDropTotal The total number of _dropped_ by the SRT sender DATA packets that have no chance to be delivered in time (refer to [Too-Late Packet Drop](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-4.6) mechanism). Available for sender. Packets may be dropped conditionally when both `SRTO_TSBPDMODE` and `SRTO_TLPKTDROP` socket options are enabled, refer to [SRT API Socket Options](API-socket-options.md). The delay before TLPKTDROP mechanism is triggered is calculated as follows `SRTO_PEERLATENCY + SRTO_SNDDROPDELAY + 2 * interval between sending ACKs`, where `SRTO_PEERLATENCY` is the configured SRT latency, `SRTO_SNDDROPDELAY` adds an extra to `SRTO_PEERLATENCY` delay, the default `interval between sending ACKs` is 10 milliseconds. The minimum delay is `1000 + 2 * interval between sending ACKs` milliseconds. Refer to `SRTO_PEERLATENCY`, `SRTO_SNDDROPDELAY` socket options in [SRT API Socket Options](API-socket-options.md). #### pktRcvDropTotal The total number of _dropped_ by the SRT receiver and, as a result, not delivered to the upstream application DATA packets (refer to [Too-Late Packet Drop](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-4.6) mechanism). Available for receiver. This statistic counts - not arrived packets including those signalled for dropping by the sender, that were dropped in favor of the subsequent existing packets, - arrived too late packets (retransmitted or original packets arrived out of order), - arrived in time packets, but decrypted with errors (see also [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) statistic). Packets may be dropped conditionally when both `SRTO_TSBPDMODE` and `SRTO_TLPKTDROP` socket options are enabled, refer to [SRT API Socket Options](API-socket-options.md). #### pktRcvUndecryptTotal The total number of packets that failed to be decrypted at the receiver side. Available for receiver. The statistic also counts unencrypted packets that were expected to be uncrypted on a secured connection (see [SRTO_KM_S_SECURED](API-socket-options.md#srt_km_state)) and hence dropped as not encrypted (undecrypted). #### pktSndFilterExtraTotal The total number of packet filter control packets generated by the packet filter (refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md)). Available for sender. Packet filter control packets contain only control information necessary for the packet filter. The type of these packets is DATA. If the `SRTO_PACKETFILTER` socket option is disabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic is equal to 0. Introduced in SRT v1.4.0. #### pktRcvFilterExtraTotal The total number of packet filter control packets received by the packet filter (refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md)). Available for receiver. Packet filter control packets contain only control information necessary for the packet filter. The type of these packets is DATA. If the `SRTO_PACKETFILTER` socket option is disabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic is equal to 0. Introduced in SRT v1.4.0. #### pktRcvFilterSupplyTotal The total number of lost DATA packets recovered by the packet filter at the receiver side (e.g., FEC rebuilt packets; refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md)). Available for receiver. If the `SRTO_PACKETFILTER` socket option is disabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic is equal to 0. Introduced in SRT v1.4.0. #### pktRcvFilterLossTotal The total number of lost DATA packets **not** recovered by the packet filter at the receiver side (refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md)). Available for receiver. If the `SRTO_PACKETFILTER` socket option is disabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic is equal to 0. Introduced in SRT v1.4.0. #### byteSentTotal Same as [pktSentTotal](#pktSentTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for sender. #### byteRecvTotal Same as [pktRecvTotal](#pktRecvTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for receiver. #### byteSentUniqueTotal Same as [pktSentUniqueTotal](#pktSentUniqueTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for sender. #### byteRecvUniqueTotal Same as [pktRecvUniqueTotal](#pktRecvUniqueTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for receiver. #### byteRcvLossTotal Same as [pktRcvLossTotal](#pktRcvLossTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Bytes for the presently missing (either reordered or lost) packets' payloads are estimated based on the average packet size. Available for receiver. #### byteRetransTotal Same as [pktRetransTotal](#pktRetransTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for sender. #### byteSndDropTotal Same as [pktSndDropTotal](#pktSndDropTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for sender. #### byteRcvDropTotal Same as [pktRcvDropTotal](#pktRcvDropTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Bytes for the dropped packets' payloads are estimated based on the average packet size. Available for receiver. #### byteRcvUndecryptTotal Same as [pktRcvUndecryptTotal](#pktRcvUndecryptTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for receiver. ### Interval-Based Statistics #### pktSent Same as [pktSentTotal](#pktSentTotal), but for a specified interval. #### pktRecv Same as [pktRecvTotal](#pktRecvTotal), but for a specified interval. #### pktSentUnique Same as [pktSentUniqueTotal](#pktSentUniqueTotal), but for a specified interval. #### pktRecvUnique Same as [pktRecvUniqueTotal](#pktRecvUniqueTotal), but for a specified interval. #### pktSndLoss Same as [pktSndLossTotal](#pktSndLossTotal), but for a specified interval. #### pktRcvLoss Same as [pktRcvLossTotal](#pktRcvLossTotal), but for a specified interval. #### pktRetrans Same as [pktRetransTotal](#pktRetransTotal), but for a specified interval. #### pktRcvRetrans Same as [pktRcvRetransTotal](#pktRcvRetransTotal), but for a specified interval. #### pktSentACK Same as [pktSentACKTotal](#pktSentACKTotal), but for a specified interval. #### pktRecvACK Same as [pktRecvACKTotal](#pktRecvACKTotal), but for a specified interval. #### pktSentNAK Same as [pktSentNAKTotal](#pktSentNAKTotal), but for a specified interval. #### pktRecvNAK Same as [pktRecvNAKTotal](#pktRecvNAKTotal), but for a specified interval. #### pktSndFilterExtra Same as [pktSndFilterExtraTotal](#pktSndFilterExtraTotal), but for a specified interval. Introduced in v1.4.0. Refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md). #### pktRcvFilterExtra Same as [pktRcvFilterExtraTotal](#pktRcvFilterExtraTotal), but for a specified interval. Introduced in v1.4.0. Refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md). #### pktRcvFilterSupply Same as [pktRcvFilterSupplyTotal](#pktRcvFilterSupplyTotal), but for a specified interval. Introduced in v1.4.0. Refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md). #### pktRcvFilterLoss Same as [pktRcvFilterLossTotal](#pktRcvFilterLossTotal), but for a specified interval. Introduced in v1.4.0. Refer to [SRT Packet Filtering & FEC](../features/packet-filtering-and-fec.md). #### mbpsSendRate Sending rate in Mbps. Sender side. #### mbpsRecvRate Receiving rate in Mbps. Receiver side. #### usSndDuration Same as [usSndDurationTotal](#usSndDurationTotal), but measured on a specified interval. #### pktReorderDistance The distance in sequence numbers between the two original (not retransmitted) packets, that were received out of order. Receiver only. The traceable distance values are limited by the maximum reorder tolerance set by  `SRTO_LOSSMAXTTL`. #### pktRcvBelated The number of packets received but IGNORED due to having arrived too late. Makes sense only if TSBPD and TLPKTDROP are enabled. An offset between sequence numbers of the newly arrived DATA packet and latest acknowledged DATA packet is calculated. If the offset is negative, the packet is considered late, meaning that it was either already acknowledged or dropped by TSBPD as too late to be delivered. Retransmitted packets can also be considered late. #### pktSndDrop Same as [pktSndDropTotal](#pktSndDropTotal), but for a specified interval. #### pktRcvDrop Same as [pktRcvDropTotal](#pktRcvDropTotal), but for a specified interval. #### pktRcvUndecrypt Same as [pktRcvUndecryptTotal](#pktRcvUndecryptTotal), but for a specified interval. #### byteSent Same as [byteSentTotal](#byteSentTotal), but for a specified interval. #### byteRecv Same as [byteRecvTotal](#byteRecvTotal), but for a specified interval. #### byteSentUnique Same as [byteSentUniqueTotal](#byteSentUniqueTotal), but for a specified interval. #### byteRecvUnique Same as [byteRecvUniqueTotal](#byteRecvUniqueTotal), but for a specified interval. #### byteRcvLoss Same as [byteRcvLossTotal](#byteRcvLossTotal), but for a specified interval. #### byteRetrans Same as [byteRetransTotal](#byteRetransTotal), but for a specified interval. #### byteSndDrop Same as [byteSndDropTotal](#byteSndDropTotal), but for a specified interval. #### byteRcvDrop Same as [byteRcvDropTotal](#byteRcvDropTotal), but for a specified interval. #### byteRcvUndecrypt Same as [byteRcvUndecryptTotal](#byteRcvUndecryptTotal), but for a specified interval. ### Instantaneous Statistics #### usPktSndPeriod Current minimum time interval between which consecutive packets are sent, in microseconds. Sender only. Note that several sockets sharing one outgoing port use the same sending queue. They may have different pacing of the outgoing packets, but all the packets will be placed in the same sending queue, which may affect the send timing. `usPktSndPeriod` is the minimum time (sending period) that must be kept between two packets sent consecutively over the link used by an SRT socket. It is not the EXACT time interval between two consecutive packets. In the case where the time spent by an application between sending two consecutive packets exceeds `usPktSndPeriod`, the next packet will be sent faster, or even immediately, to preserve the average sending rate. **Note**: Does not apply to probing packets. #### pktFlowWindow The maximum number of packets that can be "in flight". Sender only. See also [pktFlightSize](#pktFlightSize). The value retrieved on the sender side represents an estimation of the amount of free space in the buffer of the peer receiver. The actual amount of available space is periodically reported back by the receiver in ACK packets. When this value drops to zero, the next packet sent will be dropped by the receiver without processing. In **file mode** this may cause a slowdown of sending in order to wait until the receiver has more space available, after it eventually extracts the packets waiting in its receiver buffer; in **live mode** the receiver buffer contents should normally occupy not more than half of the buffer size (default 8192). If `pktFlowWindow` value is less than that and becomes even less in the next reports, it means that the receiver application on the peer side cannot process the incoming stream fast enough and this may lead to a dropped connection. #### pktCongestionWindow Congestion window size, in number of packets. Sender only. Dynamically limits the maximum number of packets that can be in flight. Congestion control module dynamically changes the value. In **file mode** this value starts at 16 and is increased to the number of reported acknowledged packets. This value is also updated based on the delivery rate, reported by the receiver. It represents the maximum number of packets that can be safely sent without causing network congestion. The higher this value is, the faster the packets can be sent. In **live mode** this field is not used. #### pktFlightSize The number of packets in flight. Sender only. `pktFlightSize <= pktFlowWindow` and `pktFlightSize <= pktCongestionWindow` This is the distance between the packet sequence number that was last reported by an ACK message and the sequence number of the latest packet sent (at the moment when the statistics are being read). **NOTE:** ACKs are received periodically (at least every 10 ms). This value is most accurate just after receiving an ACK and becomes a little exaggerated over time until the next ACK arrives. This is because with a new packet sent, while the ACK number stays the same for a moment, the value of `pktFlightSize` increases. But the exact number of packets arrived since the last ACK report is unknown. A new statistic might be added which only reports the distance between the ACK sequence and the sent sequence at the moment when an ACK arrives, and isn't updated until the next ACK arrives. The difference between this value and `pktFlightSize` would then reveal the number of packets with an unknown state at that moment. #### msRTT Smoothed round-trip time (SRTT), an exponentially-weighted moving average (EWMA) of an endpoint's RTT samples, in milliseconds. Available both for sender and receiver. See [Section 4.10. Round-Trip Time Estimation](https://tools.ietf.org/html/draft-sharabayko-srt-01#section-4.10) of the [Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) and [[RFC6298] Paxson, V., Allman, M., Chu, J., and M. Sargent, "Computing TCP's Retransmission Timer"](https://datatracker.ietf.org/doc/html/rfc6298) for more details. #### mbpsBandwidth Estimated bandwidth of the network link, in Mbps. Sender only. The bandwidth is estimated at the receiver. The estimation is based on the time between two probing DATA packets. Every 16th data packet is sent immediately after the previous data packet. By measuring the delay between probe packets on arrival, it is possible to estimate the maximum available transmission rate, which is interpreted as the bandwidth of the link. The receiver then sends back a running average calculation to the sender with an ACK message. #### byteAvailSndBuf The available space in the sender's buffer, in bytes. Sender only. This value decreases with data scheduled for sending by the application, and increases with every ACK received from the receiver, after the packets are sent over the UDP link. #### byteAvailRcvBuf The available space in the receiver's buffer, in bytes. Receiver only. This value increases after the application extracts the data from the socket (uses one of `srt_recv*` functions) and decreases with every packet received from the sender over the UDP link. #### mbpsMaxBW Transmission bandwidth limit, in Mbps. Sender only. Usually this is the setting from the `SRTO_MAXBW` option, which may include the value 0 (unlimited). Under certain conditions a nonzero value might be be provided by a congestion control module, although none of the built-in congestion control modules currently use it. Refer to `SRTO_MAXBW` and `SRTO_INPUTBW` in [SRT API Socket Options](API-socket-options.md). #### byteMSS Maximum Segment Size (MSS), in bytes. Same as the value from the `SRTO_MSS` socket option. Should not exceed the size of the maximum transmission unit (MTU), in bytes. Sender and Receiver. The default size of the UDP packet used for transport, including all possible headers (Ethernet, IP and UDP), is 1500 bytes. Refer to `SRTO_MSS` in [SRT API Socket Options](API-socket-options.md). #### pktSndBuf The number of packets in the sender's buffer that are already scheduled for sending or even possibly sent, but not yet acknowledged. Sender only. Once the receiver acknowledges the receipt of a packet, or the TL packet drop is triggered, the packet is removed from the sender's buffer. Until this happens, the packet is considered as unacknowledged. A moving average value is reported when the value is retrieved by calling `srt_bstats(...)` or `srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous)` with `instantaneous=false`. The current state is returned if `srt_bistats(...)` is called with `instantaneous=true`. #### byteSndBuf Instantaneous (current) value of `pktSndBuf`, but expressed in bytes, including payload and all headers (SRT+UDP+IP). \ 20 bytes IPv4 + 8 bytes of UDP + 16 bytes SRT header. Sender side. #### msSndBuf The timespan (msec) of packets in the sender's buffer (unacknowledged packets). Sender only. A moving average value is reported when the value is retrieved by calling `srt_bstats(...)` or `srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous)` with `instantaneous=false`. The current state is returned if `srt_bistats(...)` is called with `instantaneous=true`. #### msSndTsbPdDelay Timestamp-based Packet Delivery Delay value of the peer. If `SRTO_TSBPDMODE` is on (default for **live mode**), it returns the value of `SRTO_PEERLATENCY`, otherwise 0. The sender reports the TSBPD delay value of the receiver. The receiver reports the TSBPD delay of the sender. #### pktRcvBuf The number of acknowledged packets in receiver's buffer. Receiver only. This measurement does not include received but not acknowledged packets, stored in the receiver's buffer. A moving average value is reported when the value is retrieved by calling `srt_bstats(...)` or `srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous)` with `instantaneous=false`. The current state is returned if `srt_bistats(...)` is called with `instantaneous=true`. #### byteRcvBuf Instantaneous (current) value of `pktRcvBuf`, expressed in bytes, including payload and all headers (SRT+UDP+IP). \ 20 bytes IPv4 + 8 bytes of UDP + 16 bytes SRT header. Receiver side. #### msRcvBuf The timespan (msec) of acknowledged packets in the receiver's buffer. Receiver side. If TSBPD mode is enabled (defualt for **live mode**), a packet can be acknowledged, but not yet ready to play. This range includes all packets regardless of whether they are ready to play or not. A moving average value is reported when the value is retrieved by calling `srt_bstats(...)` or `srt_bistats(SRTSOCKET u, SRT_TRACEBSTATS * perf, int clear, int instantaneous)` with `instantaneous=false`. The current state is returned if `srt_bistats(...)` is called with `instantaneous=true`. Instantaneous value is only reported if TSBPD mode is enabled, otherwise 0 is reported (see #900). #### msRcvTsbPdDelay Timestamp-based Packet Delivery Delay value set on the socket via `SRTO_RCVLATENCY` or `SRTO_LATENCY`. The value is used to apply TSBPD delay for reading the received data on the socket. Receiver side. If `SRTO_TSBPDMODE` is off (default for **file mode**), 0 is returned. #### pktReorderTolerance Instant value of the packet reorder tolerance. Receiver side. Refer to [pktReorderDistance](#pktReorderDistance). `SRTO_LOSSMAXTTL` sets the maximum reorder tolerance value. The value defines the maximum time-to-live for the original packet, that was received after with a gap in the sequence of incoming packets. Those missing packets are expected to come out of order, therefore no loss is reported. The actual TTL value (**pktReorderTolerance**) specifies the number of packets to receive further, before considering the preceding packets lost, and sending the loss report. The internal algorithm checks the order of incoming packets and adjusts the tolerance based on the reorder distance (**pktReorderTolerance**), but not to a value higher than the maximum (`SRTO_LOSSMAXTTL`). SRT starts from tolerance value set in `SRTO_LOSSMAXTTL` (initial tolerance is set to 0 in SRT v1.4.0 and prior versions). Once the receiver receives the first reordered packet, it increases the tolerance to the distance in the sequence discontinuity of the two packets. \ After 10 consecutive original (not retransmitted) packets come in order, the reorder distance is decreased by 1 for every such packet. For example, assume packets with the following sequence numbers are being received: \ 1, 2, 4, 3, 5, 7, 6, 10, 8, 9 SRT starts from 0 tolerance. Receiving packet with sequence number 4 has a discontinuity equal to one packet. The loss is reported to the sender. With the next packet (sequence number 3) a reordering is detected. Reorder tolerance is increased to 1. \ The next sequence discontinuity is detected when the packet with sequence number 7 is received. The current tolerance value is 1, which is equal to the gap (between 5 and 7). No loss is reported. \ Next packet with sequence number 10 has a higher sequence discontinuity equal to 2. Missing packets with sequence numbers 8 and 9 will be reported lost with the next received packet (reorder distance is still at 1). The next received packet has sequence number 8. Reorder tolerance value is increased to 2. The packet with sequence number 9 is reported lost. #### pktRcvAvgBelatedTime Accumulated difference between the current time and the time-to-play of a packet that is received late. ## SRT Group Statistics SRT group statistics are implemented for [SRT Connection Bonding](../features/bonding-quick-start.md) feature and available since SRT v1.5.0. The `srt_bistats(SRTSOCKET u, ...)` function can be used with a socket group ID as the first argument to get statistics for a group. `SRT_TRACEBSTATS` values will mostly be zeros, except for the fields listed in the [Summary Table](#group-summary-table) below. Refer to the [SRT API Functions](../API/API-functions.md#socket-group-management) documentation for usage instructions. ### Summary Table The table below provides a summary of SRT group statistics: name, type, unit of measurement, data type, and whether it is calculated by the sender or receiver. See sections [Accumulated Statistics](#group-accumulated-statistics) and [Interval-Based Statistics](#group-interval-based-statistics) for a detailed description of each statistic. | Statistic | Type of Statistic | Unit of Measurement | Available for Sender | Available for Receiver | Data Type | | ------------------------------------------------- | ----------------- | ------------------- | -------------------- | ---------------------- | --------- | | [msTimeStamp](#group-msTimeStamp) | accumulated | ms (milliseconds) | ✓ | ✓ | int64_t | | [pktSentUniqueTotal](#group-pktSentUniqueTotal) | accumulated | packets | ✓ | - | int64_t | | [pktRecvUniqueTotal](#group-pktRecvUniqueTotal) | accumulated | packets | - | ✓ | int64_t | | [pktRcvDropTotal](#group-pktRcvDropTotal) | accumulated | packets | - | ✓ | int32_t | | [byteSentUniqueTotal](#group-byteSentUniqueTotal) | accumulated | packets | ✓ | - | int64_t | | [byteRecvUniqueTotal](#group-byteRecvUniqueTotal) | accumulated | packets | - | ✓ | int64_t | | [byteRcvDropTotal](#group-byteRcvDropTotal) | accumulated | packets | - | ✓ | int32_t | | [pktSentUnique](#group-pktSentUnique) | interval-based | packets | ✓ | - | int64_t | | [pktRecvUnique](#group-pktRecvUnique) | interval-based | packets | - | ✓ | int64_t | | [pktRcvDrop](#group-pktRcvDrop) | interval-based | packets | - | ✓ | int32_t | | [byteSentUnique](#group-byteSentUnique) | interval-based | packets | ✓ | - | int64_t | | [byteRecvUnique](#group-byteRecvUnique) | interval-based | packets | - | ✓ | int64_t | | [byteRcvDrop](#group-byteRcvDrop) | interval-based | packets | - | ✓ | int32_t | ### Accumulated Statistics #### msTimeStamp The time elapsed, in milliseconds, since the time ("connection" time) when the initial group connection has been initiated (the time when the first connection in the group has been made and therefore made the group connected). This "connection" time will be then set in this statistic in every next socket that will become a member of the group as the new connections are established. A new connection to an already connected group doesn’t change the value of "connection" time. Available both for sender and receiver. #### pktSentUniqueTotal The number of *unique original* DATA packets sent by the socket group. Available for sender. This value counts every *original* DATA packet sent over the network for the first time by the socket group. There is no difference between Connection Bonding modes (broadcast, backup and balancing). For example, sending the packet with a particular sequence number over multiple links in case of broadcast mode (it means sending this packet multiple times) does not affect the statistic and this very packet is taken into account only once. This statistic does not count retransmitted DATA packets that are individual per socket connection within the group. See the corresponding [pktRetransTotal](#pktRetransTotal) socket statistic. If the `SRTO_PACKETFILTER` socket option is enabled (refer to [SRT API Socket Options](API-socket-options.md)), this statistic does not count packet filter control packets that are individual per socket connection within the group. See the corresponding [pktSndFilterExtraTotal](#pktSndFilterExtraTotal) socket statistic. #### pktRecvUniqueTotal The number of *unique* DATA packets *received in time* by the socket group and, as a result, scheduled for delivery to the upstream application. Available for receiver. Unique means "first arrived over multiple links" DATA packets. Whichever packet comes first over whichever link is taken into account. This statistic doesn't count - discarded as duplicate by the group reader packets, see [pktRcvDiscardTotal](#group-pktRcvDiscardTotal) statistic, - dropped by the socket group packets, see [pktRcvDropTotal](#group-pktRcvDropTotal) statistic. #### pktRcvDropTotal The number of *dropped* and, as a result, *not delivered* to the upstream application by the socket group DATA packets. Available for receiver. A packet is considered dropped by the socket group if it has been dropped by the TLPKTDROP mechanism over all the links from the group. See the corresponding socket [pktRcvDropTotal](#pktRcvDropTotal) statistic. For example, if a packet with a particular sequence number has been dropped over one or several links, but has not been dropped over at least one link, it is *not* considered dropped by the socket group and can be delivered to the upstream application. Only if a packet has been dropped over all the links from the group, it is considered dropped by the socket group and can not be delivered to the upstream application. In fact, only sockets can drop the packets and the group is simply responsible for delivering received over multiple sockets packets to the application. #### byteSentUniqueTotal Same as [pktSentUniqueTotal](#group-pktSentUniqueTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for sender. #### byteRecvUniqueTotal Same as [pktRecvUniqueTotal](#group-pktRecvUniqueTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for receiver. #### byteRcvDropTotal Same as [pktRcvDropTotal](#group-pktRcvDropTotal), but expressed in bytes, including payload and all the headers (20 bytes IPv4 + 8 bytes UDP + 16 bytes SRT). Available for receiver. ### Interval-Based Statistics #### pktSentUnique Same as [pktSentUniqueTotal](#group-pktSentUniqueTotal), but for a specified interval. #### pktRecvUnique Same as [pktRecvUniqueTotal](#group-pktRecvUniqueTotal), but for a specified interval. #### pktRcvDrop Same as [pktRcvDropTotal](#group-pktRcvDropTotal), but for a specified interval. #### byteSentUnique Same as [byteSentUniqueTotal](#group-byteSentUniqueTotal), but for a specified interval. #### byteRecvUnique Same as [byteRecvUniqueTotal](#group-byteRecvUniqueTotal), but for a specified interval. #### byteRcvDrop Same as [byteRcvDropTotal](#group-byteRcvDropTotal), but for a specified interval. ### Formulas The ratio of unrecovered by the socket group packets `Dropped Packets Ratio` can be calculated as follows: ``` Dropped Packets Ratio = pktRcvDropTotal / pktSentUniqueTotal; in case both sender and receiver statistics is available Dropped Packets Ratio = pktRcvDropTotal / (pktRecvUniqueTotal + pktRcvDropTotal); in case receiver only statistics is available ``` srt-1.5.4/docs/README.md000066400000000000000000000301061471311275400145450ustar00rootroot00000000000000# Documentation Overview ## SRT API Documents | Document Title | Folder | File Name | Description | | :---------------------------------------------------------- | :---------------------------- | :------------------------------------------------------------- | :--------------------------------------------------- | | [SRT API](API/API.md) | [API](API/) | [API.md](API/API.md) | Detailed description of the SRT C API. | | [SRT API Functions](API/API-functions.md) | [API](API/) | [API-functions.md](API/API-functions.md) | Reference document for SRT API functions. | | [SRT API Socket Options](API/API-socket-options.md) | [API](API/) | [API-socket-options.md](API/API-socket-options.md) | Instructions and list of socket options for SRT API. | | [SRT Rejection Codes](API/rejections-codes.md) | [API](API/) | [rejection-codes.md](API/rejection-codes.md) | The list of SRT rejections codes. | | [SRT Statistics](API/statistics.md) | [API](API/) | [statistics.md](API/statistics.md) | How to use SRT socket and socket group statistics. | | [Configuration Guidelines](API/configuration-guidelines.md) | [API](API/) | [configuration-guidelines.md](API/configuration-guidelines.md) | How to configure SRT buffers. | | | | | | ## Build Instructions | Document Title | Folder | File Name | Description | | :------------------------------------------------------------ | :---------------------------- | :----------------------------------------------- | :---------------------------------------------------------------------- | | [SRT Build Options](build/build-options.md) | [build](build/) | [build-options.md](build/build-options.md) | Description of CMake build system, configure script, and build options. | | [Building SRT on Linux (Ubuntu/CentOS)](build/build-linux.md) | [build](build/) | [build-linux.md](build/build-linux.md) | Build instructions for Linux (Ubuntu/CentOS). | | [Building SRT on Windows](build/build-win.md) | [build](build/) | [build-win.md](build/build-win.md) | Build instructions for Windows. | | [Building SRT on macOS](build/build-macOS.md) | [build](build/) | [build-macOS.md](build/build-macOS.md) | Build instructions for macOS. | | [Building SRT on iOS](build/build-iOS.md) | [build](build/) | [build-iOS.md](build/build-iOS.md) | Build instructions for iOS. | | [Building SRT on Android](build/build-android.md) | [build](build/) | [build-android.md](build/build-android.md) | Build instructions for Android. | | [Package Managers](build/package-managers.md) | [build](build/) | [package-managers.md](build/package-managers.md) | Package managers supporting SRT library. | | | | | | ## Development Documents | Document Title | Folder | File Name | Description | | :----------------------------------------------- | :---------------------------- | :----------------------------------------------- | :------------------------------------------------------------------------------------- | | [SRT Developer's Guide](dev/developers-guide.md) | [dev](dev/) | [developers-guide.md](dev/developers-guide.md) | Development setup, project structure, coding rules,
submitting issues & PRs, etc. | | [Low Level Info](dev/low-level-info.md) | [dev](dev/) | [low-level-info.md](dev/low-level-info.md) | Low level information for the SRT project (only
mutex locking). | | [Making SRT Better](dev/making-srt-better.md) | [dev](dev/) | [making-srt-better.md](dev/making-srt-better.md) | Guidelines for problem reporting, collecting debug logs
and pcaps. | | | | | | ## Features | Document Title | Folder | File Name | Description | | :----------------------------------------------------------- | :---------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | | [SRT Access Control
(Stream ID) Guidelines](features/access-control.md) | [features](features/) | [access-control.md](features/access-control.md) | Access Control (Stream ID) guidelines. | | [SRT Connection Bonding: Quick Start](features/bonding-quick-start.md) | [features](features/) | [bonding-quick-start.md](features/bonding-quick-start.md) | SRT Connection Bonding Quick Start. | | [SRT Connection Bonding: Introduction](features/bonding-intro.md) | [features](features/) | [bonding-intro.md](features/bonding-intro.md) | Introduction to Connection Bonding. Description
of group (bonded) connections. | | [SRT Connection Bonding: Socket Groups](features/socket-groups.md) | [features](features/) | [socket-groups.md](features/socket-groups.md) | Description of socket groups in SRT (Connection
Bonding). Here you will also find information
regarding the `srt-test-live` application for testing
Connection Bonding. | | [SRT Connection Bonding: Main/Backup][main-backup] | [features](features/) | [bonding-main-backup.md][main-backup] | Main/Backup mode description. | | [SRT Encryption](features/encryption.md) | [features](features/) | [encryption.md](features/encryption.md) | Description of SRT encryption mechanism. This
document might be outdated, please consult
[Section 6. Encryption][srt-internet-draft-sec-6] of the [Internet Draft][srt-internet-draft] additionally. | | [SRT Handshake](features/handshake.md) | [features](features/) | [handshake.md](features/handshake.md) | Description of SRT handshake mechanism. This
document might be outdated, please consult
[Section 3.2.1 Handshake][srt-internet-draft-sec-3-2-1] and
[Section 4.3 Handshake Messages](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-4.3) of the
[Internet Draft][srt-internet-draft] additionally. | | [Live Streaming
Guidelines](features/live-streaming.md) | [features](features/) | [live-streaming.md](features/live-streaming.md) | Guidelines for live streaming with SRT. See also
best practices and configuration tips in
[Section 7.1 Live Streaming](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-7.1) of the [Internet Draft][srt-internet-draft]. | | [SRT Packet
Filtering & FEC][packet-filter] | [features](features/) | [packet-filtering-and-fec.md][packet-filter] | Description of SRT packet filtering mechanism,
including FEC. | | | | | | ## Sample Applications | Document Title | Folder | File Name | Description | | :--------------------------------------------------------------------- | :-------------------- | :-------------------------------------------------- | :------------------------------------------------------------ | | [Using the
`srt-live-transmit` App](apps/srt-live-transmit.md) | [apps](apps/) | [srt-live-transmit.md](apps/srt-live-transmit.md) | A sample application to transmit a live stream from
source medium (UDP/SRT/`stdin`) to the target medium
(UDP/SRT/`stdout`). | | [Using the
`srt-file-transmit` App](apps/srt-file-transmit.md) | [apps](apps/) | [srt-file-transmit.md](apps/srt-file-transmit.md) | A sample application to transmit a file over SRT | | [Using the
`srt-tunnel` App](apps/srt-tunnel.md) | [apps](apps/) | [srt-tunnel.md](apps/srt-tunnel.md) | A sample application to set up an SRT tunnel for TCP traffic. | | [Using the
`srt-test-multiplex` App](apps/srt-test-multiplex.md) | [apps](apps/) | [srt-test-multiplex.md](apps/srt-test-multiplex.md) | Testing application that allows to send multiple streams over one UDP link. | | [Using the
`srt-test-relay` App](apps/srt-test-relay.md) | [apps](apps/) | [srt-test-relay.md](apps/srt-test-relay.md) | Testing application for bidirectional stream sending over one connection. | | | | | | ## Miscellaneous | Document Title | Folder | File Name | Description | | :------------------------------------------------- | :---------------------------- | :---------------------------------------------------- | :----------------------------------------------------------- | | [Why SRT Was Created](misc/why-srt-was-created.md) | [misc](misc/) | [why-srt-was-created.md](misc/why-srt-was-created.md) | Background and history of SRT. See also
[Section 1. Introduction][srt-internet-draft-sec-1] of the [Internet Draft][srt-internet-draft]. | | | | | | [srt-internet-draft]: https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01 [srt-internet-draft-sec-1]: https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-1 [srt-internet-draft-sec-3-2-1]: https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-3.2.1 [srt-internet-draft-sec-6]: https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01#section-6 [main-backup]: features/bonding-main-backup.md [packet-filter]: features/packet-filtering-and-fec.md srt-1.5.4/docs/apps/000077500000000000000000000000001471311275400142315ustar00rootroot00000000000000srt-1.5.4/docs/apps/srt-file-transmit.md000066400000000000000000000040341471311275400201400ustar00rootroot00000000000000# srt-file-transmit The `srt-file-transmit` tool is a tool for transmitting files over SRT. You need: - a file to transmit - a destination to store it into - this application run on both sides, one sending, one receiving ## Introduction The `srt-file-transmit` application will transmit your file over the SRT connection, the application on the other side will receive it and store to the desired location. Both caller-listener and rendezvous arrangement of the connection are possible and in whatever direction. The `streamid` socket option will be used to pass the filename to the other side so that it is either written with this name or matched with the filename internally. The application the will be sending a file should use the file path as source and SRT URI as a destination, and vice versa for receiving. ## Caller mode If you use sender in caller mode, then the caller SRT URI destination should be specified, and the "root name" from the file path will be set to `streamid`. This will allow the listener to use it when writing. If a receiver is used as a caller, then the destination filepath's rootname will be also passed as `streamid` so that the listener receiver can pick up the file by name. In caller mode you must specify the full filename path of the received or sent file. ## Listener mode If you use sender in listener mode, then you start it with specifying either the full filename path, or only the directory where the file is located; in the latter case the filename will be tried from the `streamid` option extracted from the connected socket (as set by the other side's caller). If the full filename was specified, it must match the rootname extraced from this option, or otherwise transmission will not be done. If you use receiver in listener mode, then you start it with specifying either the full filename path, or just the directory. In the latter case the root name will be extracted from `streamid` socket option, and this one will be transmitted. ## Usage ``` srt-file-transmit [options] ``` srt-1.5.4/docs/apps/srt-live-transmit.md000066400000000000000000000630761471311275400201730ustar00rootroot00000000000000# srt-live-transmit The `srt-live-transmit` tool is a universal data transport tool with a purpose to transport data between SRT and other medium. At the same time it is just a sample application to show some of the powerful features of SRT. We encourage you to use SRT library itself integrated into your products. ## Introduction The `srt-live-transmit` can be both used as a universal SRT-to-something-else flipper, as well as a testing tool for SRT. The general usage is the following: ```shell srt-live-transmit [options] ``` The following medium types are handled by `srt-live-transmit`: - SRT - use SRT for reading or writing, in listener, caller or rendezvous mode, with possibly additional parameters - UDP - read or write the given UDP address (also multicast) - RTP - read RTP from the given address (also multicast) - Local file - read or store the stream into the file - Process's pipeline - use the process's `stdin` and `stdout` standard streams Any medium can be used with any direction, although some of them may have special direction-dependent cases. Mind that the URI has a standard syntax: ```yaml scheme://HOST:PORT/PATH?PARAM1=VALUE1&PARAM2=VALUE2&... ``` The first parameter is introduced with a `?` and all following can be appended with an `&` character. If you specify only the path (no **://** specified), then the scheme defaults to **file**. The path can be also specified as relative this way. Note also that empty host (`scheme://:PORT`) defaults to 0.0.0.0, and an empty port (when there's no `:PORT` part) defaults to port number 0. Special options for particular medium may be specified in **PARAM** items. All options are medium-specific, although there may happen some options common for multiple media types. Note also that the **HOST** part is always tried to be resolved as a name, if its form is not directly the IPv4 address. ### Example for Smoke Testing First we need to start up the `srt-live-transmit` app, listening for unicast UDP TS input on port 1234 and making SRT available on port 4201. Note, these are randomly chosen ports. We also open the app in verbose mode for debugging: ```shell srt-live-transmit udp://:1234 srt://:4201 -v ``` Now we need to generate a UDP stream. ffmpeg can be used to generate bars and tone as follows, doing a simple unicast push to our listening `srt-live-transmit` application: ```shell ffmpeg -f lavfi -re -i smptebars=duration=300:size=1280x720:rate=30 -f lavfi -re -i sine=frequency=1000:duration=60:sample_rate=44100 -pix_fmt yuv420p -c:v libx264 -b:v 1000k -g 30 -keyint_min 120 -profile:v baseline -preset veryfast -f mpegts "udp://127.0.0.1:1234?pkt_size=1316" ``` You should see the stream connect in `srt-live-transmit`. Now you can test in VLC (make sure you're using the latest version!) - just go to file -> open network stream and enter `srt://127.0.0.1:4201` and you should see bars and tone right away. Or you can test using ffplay or ffprobe to inspect the stream: ```shell ffplay srt://127.0.0.1:4201 ``` -or- ```shell ffprobe srt://127.0.0.1:4201 ``` If you're having trouble, make sure this works, then add complexity one step at a time (multicast, push vs listen, etc.). ## URI Syntax Transmission mediums are specified as the standard URI format: ```yaml SCHEME://HOST:PORT?PARAM1=VALUE1&PARAM2=VALUE2&... ``` The applications supports the following schemes: - `file` - for file or standard input and output - `udp` - UDP output (unicast and multicast) - `rtp` - RTP input (unicast and multicast) - `srt` - SRT connection Note that this application doesn't support file as a medium, but this can be handled by other applications from this project. ### Medium: FILE (including standard process pipes) **NB!** File mode, except `file://con`, is not supported in the `srt-file-transmit` tool! The general syntax is: `file:///global/path/to/the/file`. No parameters in the URL are extracted. There's one (non-standard!) special case, though: ```yaml file://con ``` That is, **con** is used as a *HOST* part of the URI. If you use this URI for \, then the data will be read from the standard input. If \, the data will be send to the standard output. Be careful with options being specified together with having standard output as output URI - some of them are not allowed as the extra output controlled by options might interfere with the data output. ## Medium: UDP UDP can only be used in listening mode for input, and in calling mode for output. Multicast Streaming is also possible, without any special declaration. Just use an IP address from the multicast range. The specification and meaning of the fields in the URI depend on the mode. The **PORT** part is always mandatory and it designates either the port number for the target host or the port number to be bound to read from. The following options are available through URI parameters: - **iptos**: sets the `IP_TOS` socket option - **ttl**: sets the `IP_TTL` or `IP_MULTICAST_TTL` option, depending on mode - **mcloop**: sets the `IP_MULTICAST_LOOP` option (multicast mode only) - **rcvbuf**: sets the `SO_RCVBUF` socket option - **sndbuf**: sets the `SO_SNDBUF` socket option - **adapter**: sets the local binding address - **source**: uses `IP_ADD_SOURCE_MEMBERSHIP`, see below for details For sending to unicast: ```yaml udp://TARGET:PORT?parameters... ``` - The **HOST** part (here: TARGET) is mandatory and designates the target host - The **iptos** parameter designates the Type-Of-Service (TOS) field for outgoing packets via `IP_TOS` socket option. - The **ttl** parameter will set time-to-live value for outgoing packets via `IP_TTL` socket options. For receiving from unicast: ```yaml udp://LOCALADDR:PORT?parameters... ``` - The **HOST** part (here: LOCALADDR) designates the local interface to bind. It's optional (can be empty) and defaults to 0.0.0.0 (`INADDR_ANY`). For multicast the scheme is: ```yaml udp://GROUPADDR:PORT?parameters... ``` - The **HOST** part (here: GROUPADDR) is mandatory always and designates the target multicast group. The `@` character is handled in this case, but it's not necessary, as the IGMP addresses are recognized by their mask. For sending to a multicast group: - The **iptos** parameter designates the Type-Of-Service (TOS) field for outgoing packets via `IP_TOS` socket option. - The **ttl** parameter will set time-to-live value for outgoing packets via `IP_MULTICAST_TTL` socket options. - The **adapter** parameter can be used to specify the adapter to be set through `IP_MULTICAST_IF` option to override the default device used for sending For receiving from a multicast group: - The **adapter** parameter can be used to specify the adapter through which the given multicast group can be reached (it's used to bind the socket) - The **source** parameter enforces the use of `IP_ADD_SOURCE_MEMBERSHIP` instead of `IP_ADD_MEMBERSHIP` and the value is set to `imr_sourceaddr` field. Explanations for the symbols and terms used above can be found in POSIX manual pages, like `ip(7)` and on Microsoft docs pages under `IPPROTO_IP`. ### Medium: RTP RTP is supported for input only. All URI parameters described in the [Medium: UDP](#medium-udp) section above also apply to RTP. A further RTP-specific option is available as an URI parameter: - **rtpheadersize**: sets the number of bytes to drop from the beginning of each received packet. Defaults to 12 if not provided. Minimum value is 12. A length of **rtpheadersize** bytes will always be dropped. If you wish to pass the entire packet, including RTP header, to the output medium, you should instead specify UDP as the input medium. > NOTE: No effort is made in the initial implementation to attempt to parse the RTP headers in any way eg for validation, reordering, extracting timing, length detection of checking. ### Medium: SRT Most important about SRT is that it can be either input or output and in both these cases it can work in listener, caller and rendezvous mode. SRT also handles several parameters special way, in addition to standard SRT options that can be set through the parameters. SRT can be connected using one of three connection modes: - **caller**: the "agent" (this application) sends the connection request to the peer, which must be **listener**, and this way it initiates the connection. - **listener**: the "agent" waits to be contacted by any peer **caller**. Note that a listener can accept multiple callers, but *srt-live-transmit* does not use this ability; after the first connection, it no longer accepts new connections. - **rendezvous**: A one-to-one only connection where both parties are equivalent and both attempt to initiate a connection simultaneously. Whichever party happens to start first (or succeeds in punching through the firewall first) is considered to have initiated the connection. This mode can be specified explicitly using the **mode** parameter. When it's not specified, then it is derived based on the *host* part in the URI and the presence of the **adapter** parameter: * Listener mode: if you leave the *host* part empty (**adapter** may be specified): - `srt://:1234` * Caller mode: if you specify *host* part, but not **adapter** parameter: - `srt://remote.host.com:1234` * Rendezvous mode: if you specify *host* AND **adapter** parameter: - `srt://remote.host.com:1234&adapter=my.remote.addr` Sometimes the required parameter specification results in a different mode than desired; in this case you should specify the mode explicitly. The interpretation of the *host* and *port* parts is the following: - In **LISTENER** mode: - *host* part: the local IP address to bind (default: 0.0.0.0 - "all devices") - *port* part: the local port to bind (mandatory) - **adapter** parameter: alternative for *host* part, e.g.: ```yaml srt://10.10.10.100:5001?mode=listener ``` or ```yaml srt://:5001?adapter=10.10.10.100 ``` - In **CALLER** mode: - *host* part: remote IP address to connect to (mandatory) - *port* part: remote port to connect to (mandatory) - **port** parameter: the local port to bind (default: 0 - "system autoselection") - **adapter** parameter: the local IP address to bind (default: 0.0.0.0 - "system selected device") - **bind** parameter: a shortcut to set adapter or port by specifying ADAPTER:PORT ```yaml srt://remote.host.com:5001 ``` ```yaml srt://remote.host.com:5001?adapter=local1&port=4001&mode=caller ``` - In **RENDEZVOUS** mode: same as **CALLER** except that the local port, if not specified by the **port** parameter, defaults to the value of the remote port (specified in the *port* part in the URI). ```yaml srt://remote.host.com:5001?mode=rendezvous ``` (uses `remote.host.com` port 5001 for a remote host and the default network device for routing to this host; the connection from the peer is expected on that device and port 5001) ```yaml srt://remote.host.com:5001?port=4001&adapter=local1 ``` (uses `remote.host.com` port 5001 for a remote host and the peer is expected to connect to `local1` address and port 4001) **IMPORTANT** information about IPv6. This application can also use an address specified as IPv6 with the following restrictions: 1. The IPv6 address in the URI is specified in square brackets: e.g. `srt://[::1]:5000`. 2. In listener mode, if you leave the host empty, the socket is bound to `INADDR_ANY` for IPv4 only. If you want to make it listen on IPv6, you need to specify the host as `::`. NOTE: Don't use square brackets syntax in the **adapter** parameter specification, as in this case only the host is expected. 3. If you bind to an IPv6 wildcard address (with listener mode, or when using the `bind` option), setting the `ipv6only` option to 0 or 1 is obligatory, as it is a part of the binding definition. If you set it to 1, the binding will apply only to IPv6 local addresses, and if you set it to 0, it will apply to both IPv4 and IPv6 local addresses. See the [`SRTO_IPV6ONLY`](../API/API-socket-options.md#SRTO_IPV6ONLY) option description for details. 4. In rendezvous mode you may only interconnect both parties using IPv4, or both using IPv6. Unlike listener mode, if you want to leave the socket default-bound (you don't specify `adapter`), the socket will be bound with the same IP version as the target address. If you do specify `adapter`, then both this address and the target address must be of the same family. Examples: * `srt://:5000` defines listener mode with IPv4. * `srt://[::]:5000` defines caller mode (!) with IPv6. * `srt://[::]:5000?mode=listener&ipv6only=1` defines listener mode with IPv6. Only connections from IPv6 callers will be accepted. * `srt://192.168.0.5:5000?mode=rendezvous` will make a rendezvous connection with local address `INADDR_ANY` (IPv4) and port 5000 to a destination with port 5000. * `srt://[::1]:5000?mode=rendezvous&port=4000` will make a rendezvous connection with local address `inaddr6_any` (IPv6) and port 4000 to a destination with port 5000. * `srt://[::1]:5000?adapter=127.0.0.1` - this URI is invalid (different IP versions for binding and target address in rendezvous mode) Some parameters handled for SRT medium are specific, all others are socket options. The following parameters are handled in a special way by `srt-live-transmit`: - **mode**: enforce caller, listener or rendezvous mode - **port**: enforce the **outgoing** port (the port number that will be set in the UDP packet as a source port when sent from this host). Not used in **listener** mode. - **blocking**: sets the `SRTO_RCVSYN` for input medium or `SRTO_SNDSYN` for output medium - **timeout**: sets `SRTO_RCVTIMEO` for input medium or `SRTO_SNDTIMEO` for output medium - **adapter**: sets the local IP address to bind All other parameters are SRT socket options. The Values column uses the following type specification: - `bool`. Possible values: `yes`/`no`, `on`/`off`, `true`/`false`, `1`/`0`. - `bytes` positive integer `[1; INT32_MAX]`. - `ms` - positive integer value of milliseconds. | URI param | Values | SRT Option | Description | | -------------------- | ---------------- | ------------------------- | ----------- | | `congestion` | {`live`, `file`} | `SRTO_CONGESTION` | Type of congestion control. | | `conntimeo` | `ms` | `SRTO_CONNTIMEO` | Connection timeout. | | `cryptomode` | 0..2 | `SRTO_CRYPTOMODE` | Cryptographic mode. | | `drifttracer` | `bool` | `SRTO_DRIFTTRACER` | Enable drift tracer. | | `enforcedencryption` | `bool` | `SRTO_ENFORCEDENCRYPTION` | Reject connection if parties set different passphrase. | | `fc` | `bytes` | `SRTO_FC` | Flow control window size. | | `groupconnect` | {`0`, `1`} | `SRTO_GROUPCONNECT` | Accept group connections. | | `groupminstabletimeo`| 60.. `ms` | `SRTO_GROUPMINSTABLETIMEO`| Group minimum stability timeout. | | `inputbw` | `bytes` | `SRTO_INPUTBW` | Input bandwidth. | | `iptos` | 0..255 | `SRTO_IPTOS` | IP socket type of service | | `ipttl` | 1..255 | `SRTO_IPTTL` | Defines IP socket "time to live" option. | | `ipv6only` | -1..1 | `SRTO_IPV6ONLY` | Allow only IPv6. | | `kmpreannounce` | 0.. | `SRTO_KMPREANNOUNCE` | Duration of Stream Encryption key switchover (in packets). | | `kmrefreshrate` | 0.. | `SRTO_KMREFRESHRATE` | Stream encryption key refresh rate (in packets). | | `latency` | 0.. | `SRTO_LATENCY` | Defines the maximum accepted transmission latency. | | `linger` | 0.. | `SRTO_LINGER` | Link linger value | | `lossmaxttl` | 0.. | `SRTO_LOSSMAXTTL` | Packet reorder tolerance. | | `maxbw` | 0.. | `SRTO_MAXBW` | Bandwidth limit in bytes | | `mininputbw` | 0.. | `SRTO_MININPUTBW` | Minimum allowed estimate of `SRTO_INPUTBW` | | `messageapi` | `bool` | `SRTO_MESSAGEAPI` | Enable SRT message mode. | | `minversion` | maj.min.rev | `SRTO_MINVERSION` | Minimum SRT library version of a peer. | | `mss` | 76.. | `SRTO_MSS` | MTU size | | `nakreport` | `bool` | `SRTO_NAKREPORT` | Enables/disables periodic NAK reports | | `oheadbw` | 5..100 | `SRTO_OHEADBW` | limits bandwidth overhead, percents | | `packetfilter` | `string` | `SRTO_PACKETFILTER` | Set up the packet filter. | | `passphrase` | `string` | `SRTO_PASSPHRASE` | Password for the encrypted transmission. (must be 10 to 79 characters) | | `payloadsize` | 0.. | `SRTO_PAYLOADSIZE` | Maximum payload size. | | `pbkeylen` | {16, 24, 32} | `SRTO_PBKEYLEN` | Crypto key length in bytes. | | `peeridletimeo` | `ms` | `SRTO_PEERIDLETIMEO` | Peer idle timeout. | | `peerlatency` | `ms` | `SRTO_PEERLATENCY` | Minimum receiver latency to be requested by sender. | | `rcvbuf` | `bytes` | `SRTO_RCVBUF` | Receiver buffer size | | `rcvlatency` | `ms` | `SRTO_RCVLATENCY` | Receiver-side latency. | | `retransmitalgo` | {`0`, `1`} | `SRTO_RETRANSMITALGO` | Packet retransmission algorithm to use. | | `sndbuf` | `bytes` | `SRTO_SNDBUF` | Sender buffer size. | | `snddropdelay` | `ms` | `SRTO_SNDDROPDELAY` | Sender's delay before dropping packets. | | `streamid` | `string` | `SRTO_STREAMID` | Stream ID (settable in caller mode only, visible on the listener peer). | | `tlpktdrop` | `bool` | `SRTO_TLPKTDROP` | Drop too late packets. | | `transtype` | {`live`, `file`} | `SRTO_TRANSTYPE` | Transmission type | | `tsbpdmode` | `bool` | `SRTO_TSBPDMODE` | Timestamp-based packet delivery mode. | The list of socket options can also be found in SRT header file `srt.h` (`SRT_SOCKOPT` enum type). Please note that the set of available options may be version dependent. All options are available under the lowercase name of the option without the `SRTO_` prefix. For example, `SRTO_PASSPHRASE` can be set using a **passphrase** parameter. The mapping table `srt_options` can be found in `common/socketoptions.hpp` file. Important thing about the options (which holds true also for options for TCP and UDP, even though it's not described anywhere explicitly) is that there are two categories of options: - PRE options: these options must be set to the socket prior to connecting and they cannot be altered after the connection is made. A PRE option set to a listening socket will be also derived by the socket returned by `srt_accept()`. - POST options: these options can be set to a socket at any time. The option set to a listening socket will not be derived by an accepted socket. You don't have to worry about that actually - the application is aware of this and it sets these options at appropriate time. Note also that **blocking** option has no practical use for users. Normally the non-blocking mode is used only when you have an event-driven application that needs a common signal bar for multiple event sources, or you prefer fibers to threads, when working with multiple SRT sockets in one application. The *srt-live-transmit* application isn't defined this way. This makes that the practical result of non-blocking mode here is that it uses polling on exactly one socket with infinite timeout. Every reading and writing operation will then return always without blocking, but when they report the "again" situation the application will stall on `srt_epoll_wait()` call. This option then exists for the testing purposes, as well as educational, to serve as an example of how your application should use the non-blocking mode. ## Command-Line Options The following options are available in the application. Note that some may affect specifically only selected type of medium. Options usually have values and they are set using **colon**: for example, **-t:60**. Alternatively you can also separate them by a space, but this space must be part of the parameter and not extracted by a shell (using **"** **"** quotes or backslash). - **-timeout, -t, -to** - Sets the timeout for any activity from any medium (in seconds). Default is 0 for infinite (that is, turn this mechanism off). The mechanism is such that the SIGALRM is set up to be called after the given time and it's reset after every reading succeeded. When the alarm expires due to no reading activity in defined time, it will break the application. **Notes:** - The alarm is set up after the reading loop has started, **not when the application has started**. That is, a caller will still wait the standard timeout to connect, and a listener may wait infinitely until some peer connects; only after the connection is established is the alarm counting started. - **The timeout mechanism doesn't work on Windows at all.** It behaves as if the timeout was set to **-1** and it's not modifiable. - **-timeout-mode, -tm** - Timeout mode used. Default is 0 - timeout will happen after the specified time. Mode 1 cancels the timeout if the connection was established. - **-st, -srctime, -sourcetime** - Enable source time passthrough. Default: disabled. It is recommended to build SRT with monotonic (`-DENABLE_MONOTONIC_CLOCK=ON`) or C++ 11 steady (`-DENABLE_STDCXX_SYNC=ON`) clock to use this feature. - **-buffering** - Enable source buffering up to the specified number of packets. Default: 10. Minimum: 1 (no buffering). - **-chunk, -c** - use given size of the buffer. The default size is 1456 bytes, which is the maximum payload size for a single SRT packet. - **-verbose, -v** - Display additional information on the standard output. Note that it's not allowed to be combined with output specified as **file://con**. - **-statsout** - SRT statistics output: filename. Without this option specified, the statistics will be printed to the standard output. - **-pf**, **-statspf** - SRT statistics print format. Values: json, csv, default. After a comma, options can be specified (e.g. "json,pretty"). - **-s**, **-stats**, **-stats-report-frequency** - The frequency of SRT statistics collection, based on the number of packets. - **-loglevel** - lowest logging level for SRT, one of: *fatal, error, warn, note, debug* (default: *warn*) - **-logfa, -lfa** - selected FAs in SRT to be logged (default: all are enabled). See the list of FAs running `-help:logging`. - **-logfile:logs.txt** - Output of logs is written to file logs.txt instead of being printed to `stderr`. - **-help, -h** - Show help. - **-version** - Show version info. ## Testing Considerations Before starting any test with `srt-live-transmit` please make sure your video source works properly. For example: if you use VLC as a test player, send a UDP stream directly to it before routing it through `srt-live-transmit`. For any MPEG-TS UDP based source make sure it has packet sizes of 1316 bytes. When using `ffmpeg` like in the "Example for Smoke Testing" section above set the `pkt_size=1316` parameter in case your input is a continuous data stream like from a file, camera or data-generator. When leaving the LAN for testing, please keep an eye on statistics and make sure your round-trip-time (RTT) is not drifting. It's recommended to set the latency 3 to 4 times higher than RTT. Especially on wireless links such as WLAN, Line-of-Sight Radio (LOS) and mobile links such as LTE/4G or 5G the RTT can vary a lot. If you perform tests on the public Internet, consider checking your firewall rules. The **SRT listener** must be reachable on the chosen UDP port. Same applies to routers using NAT. Please set a port forwarding rule with protocol UDP to the local IP address of the **SRT listener**. The initiation of an SRT connection (handshake) is decoupled from the stream direction. The sender of a stream can be an **SRT listener** or an **SRT caller**, as long as the receiving end uses the opposite connection mode. Typically you use the **SRT listener** on the receiving end, since it is easier to configure in terms of firewall/router setup. It also makes sense to leave the Sender in listener mode when trying to connect from various end points with possibly unknown IP addresses. ### UDP Performance Performance issues concerning reading from UDP medium were reported in [#933](https://github.com/Haivision/srt/issues/933) and [#762](https://github.com/Haivision/srt/issues/762). The dedicated research showed that at high and bursty data rates (~60 Mbps) the `epoll_wait(udp_socket)` is not fast enough to signal about the possibility of reading from a socket. It results in losing data when the input bitrate is very high (above 20 Mbps). PR [#1152](https://github.com/Haivision/srt/pull/1152) (SRT v1.4.2 and above) adds the possibility of setting the buffer size of the UDP socket in `srt-live-transmit`. Having a bigger buffer of UDP socket to store incoming data, `srt-live-transmit` handles higher bitrates. The following steps have to be performed to use the bigger UDP buffer size. ### Increase the system-default max rcv buffer size ```bash $ cat /proc/sys/net/core/rmem_max 212992 $ sudo sysctl -w net.core.rmem_max=26214400 net.core.rmem_max = 26214400 $ cat /proc/sys/net/core/rmem_max 26214400 ``` ### Specify the size of the UDP socket buffer via the URI Example URI: ```bash "udp://:4200?rcvbuf=67108864" ``` Example full URI: ```bash ./srt-live-transmit "udp://:4200?rcvbuf=67108864" srt://192.168.0.10:4200 -v ``` srt-1.5.4/docs/apps/srt-test-multiplex.md000066400000000000000000000107641471311275400203710ustar00rootroot00000000000000# srt-test-multiplex **srt-test-multiplex** (formerly called "SIPLEX") is a sample program that can send multiple streams in one direction. This tool demonstrates two SRT features: - the ability to use a single UDP link (a source and destination pair specified by IP address and port) for multiple SRT connections - the use of the `streamid` socket option to identify multiplexed resources NOTE: To make this application compiled, you need the `-DENABLE_TESTING=1` cmake option. Note also that this application is intended for demonstration only. It can simply exit with error message in case of wrong usage or broken connection. ## Usage `srt-test-multiplex -i [id1] [id2]...` - Reads all given input streams and sends them each one over a separate SRT connection, all using the same remote address and source port (hence using the same UDP link). `srt-test-multiplex -o [id] [id]...` - Transmits data from a multiplexed SRT stream to the specified output URI(s). An `` can be identified as input or output using the **-i** or **-o** options. When `-i` is specified, the URIs provided are used as input, and will be output over the `` socket. The reverse is true for any output URIs specified by `-o`. If SRT-URI is caller mode, then for every declared input or output medium a separate connection will be made, each one using the same source port (if specified, the same will be used for all connections, otherwise the first one will be automatically selected and then reused for all next ones) and with the `streamid` socket option set to the value extracted from the medium's `id` specified parameter: ``` URI1?id=a --> s1(streamid=a).connect(remhost:2000) URI2?id=b --> s2(streamid=b).connect(remhost:2000) URI3?id=c --> s3(streamid=c).connect(remhost:2000) ``` If SRT-URI is listener mode, then it will extract the value from `streamid` socket option and every accepted connection will be matched against the `id` parameter of the specified input or output medium. ``` (remhost:2000) -> accept --> s(SRT socket) --> in URI array find such that uri.id == s.streamid ``` Note that the rendezvous mode is not supported because you cannot make multiple connections over the same UDP link in rendezvous mode. This `streamid` is the SRT socket option (`SRTO_STREAMID` in the API). The idea is that it can be set on a socket used for connecting. When a listener is getting an accepted socket for that connection, the `streamid` socket option can be read from it, with the result that it will be the same as was set on the caller side. ## Examples - **Sender:** - `srt-test-multiplex srt://remhost:2000 -i udp://:5000?id=low udp://:6000?id=high` - **Receiver:** - `srt-test-multiplex srt://:2000 -o output-high.ts?id=high output-low.ts?id=low` In this example a Sender is created which will connect to `remhost` port 2000 using multiple SRT sockets, all of which will be using the same outgoing port. Here the outgoing port is automatically selected when connecting. Subsequent sockets will reuse that port. Alternatively you can enforce the outgoing port using the `port` parameter with the ``. - **Sender:** - `srt-test-multiplex srt://remhost:2000?port=5555 ...` A separate connection is made for every input resource. An appropriate resource ID will be set to each socket assigned to that resource according to the `id` parameter. ``` +-- --+ | id=1 id=1 | | ------ ------- | | \ -----> / | | id=2 \ ---------------------------- / id=2 | port=5555 -| --------- ( multiplexed UDP stream ) ---------- |- port=2000 | / ---------------------------- \ | | id=3 / \ id=3 | | ------ ------ | +-- --+ ``` When a socket is accepted on the listener side (the Receiver in this example), srt-test-multiplex will search for the resource ID among the registered resources (input/output URIs) and set an ID that matches the one on the caller side. If the resource is not found, the connection is closed immediately. The srt-test-multiplex program works the same way for connections initiated by a caller or a listener. srt-1.5.4/docs/apps/srt-test-relay.md000066400000000000000000000024701471311275400174550ustar00rootroot00000000000000# srt-test-relay **srt-test-relay** is a sample program that can utilize SRT connection for bidirectional traffic. Hence beside the SRT connection you can specify both input and output media to and from which the traffic will be flipped. Effectively the specified input will be sent through the SRT connection as output, and the input read from the SRT connection will be redirected to the given output media. NOTE: To make this application compiled, you need the `-DENABLE_TESTING=1` cmake option. Note also that this application is intended for demonstration only. It can simply exit with error message in case of wrong usage or broken connection. ## Usage `srt-test-relay -i -o ` Establish a connection, send to it the stream received from INPUT URI and write the data read from the SRT connection to OUTPUT URI. `srt-test-relay -e -o ` Establish a connection, read the data from the SRT connection, and write them back over the SRT connection, and additionally write them as well to OUTPUT URI and OUTPUT URI2. Note that you can also control the single portion of data to be sent at once by one sending call by `-c` option and you can use both live and file mode for the connection (the latter should be simply enforced by `transtype` socket option). srt-1.5.4/docs/apps/srt-tunnel.md000066400000000000000000000022201471311275400166620ustar00rootroot00000000000000# srt-tunnel ## Purpose SRT Tunnel is a typical tunnelling application, that is, it simply passes the transmission from a given endpoint to another endpoint in both directions. Tunnels can be also "chained", that is, there can be more than one tunnel on the way between the real peers. This tunnel application can use both TCP and SRT as endpoint type and the typically predicted use case is to hand over the transmission for SRT for a longer distance, leaving TCP close to the caller and listener locations: ``` --> SRT> --> ... .... (long distance) .... --> TCP> --> ``` ## Usage The `srt-tunnel` command line accepts two argument, beside the options: * Listener: the URI at which this tunnel should await connections * Caller: where this tunnel should connect when its Listener connected Options: * -ll, -loglevel: logging level, default:error * -lf, -logfa: logging Functional Area enabled * -c, -chunk: piece of data amount read at once, default=4096 bytes * -v, -verbose: display transmission details * -s, -skipflush: exit without waiting for data to complete srt-1.5.4/docs/build/000077500000000000000000000000001471311275400143655ustar00rootroot00000000000000srt-1.5.4/docs/build/build-android.md000066400000000000000000000015731471311275400174320ustar00rootroot00000000000000# Building SRT on Android **NOTE:** The scripts have been moved to [scripts/build-android](../../scripts/build-android/) folder. ## Install the NDK and CMake The Android NDK is required to build native modules for Android. [Install and configure the NDK](https://developer.android.com/studio/projects/install-ndk) Consider installing the latest version of cmake. The higher version of cmake the better. As of writing the current version of CMake is 3.18.4 You can download Cmake from the following website: [https://cmake.org/download](https://cmake.org/download/) ## Build SRT for Android Run ```./build-android -n /path/to/ndk```. E.g. ```./build-android -n /home/username/Android/Sdk/ndk/21.4.7075529``` [Include prebuilt native libraries](https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs) from ```prebuilt``` folder into Android Studio project. srt-1.5.4/docs/build/build-iOS.md000066400000000000000000000051521471311275400165010ustar00rootroot00000000000000# Building SRT on iOS ## Prerequisites * Xcode should be installed. Check in terminal whether `xcode-select -p` points to **/Applications/Xcode.app/Contents/Developer** * Install Homebrew according to instructions on [https://brew.sh/](https://brew.sh/) * Install CMake and pkg-config with Homebrew: ``` brew install cmake brew install pkg-config ``` ## Building OpenSSL There is [OpenSSL for iPhone](https://github.com/x2on/OpenSSL-for-iPhone) project which have all necessary to build OpenSSL for our needs. It fetches OpenSSL code by itself, so you don't need to download it separately. So simply clone it and build with command: ``` ./build-libssl.sh --archs="arm64" ``` Results (both libraries and headers) will be placed in bin/<SDK_VERSION>-<ARCH>.sdk directory (for example, *bin/iPhoneOS11.2-arm64.sdk*). We assume you set **IOS_OPENSSL** variable to this path (e.g. `export IOS_OPENSSL="/Users/johndoe/sources/OpenSSL-for-iPhone/bin/iPhoneOS11.2-arm64.sdk"`). ## Building SRT code Now you can build SRT providing path to OpenSSL library and toolchain file for iOS ``` ./configure --cmake-prefix-path=$IOS_OPENSSL --use-openssl-pc=OFF --cmake-toolchain-file=scripts/iOS.cmake make ``` Optionally you may add following iOS-specifc settings to configure: * `--ios-disable-bitcode=1` - disable embedding bitcode to library. * `--ios-arch=armv7|armv7s|arm64` - specify if you want to build for specific architecture (arm64 by default) * `--ios-platform=OS|SIMULATOR|SIMULATOR64` - specify for build simulator code * `--cmake-ios-developer-root=<path>`- specify path for platform directory; {XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer by default * `--cmake-ios-sdk-root=` - by default searches for latest SDK version within {CMAKE_IOS_DEVELOPER_ROOT}/SDKs, set if you want to use another SDK version Note that resulting .dylib file has install path @executable_path/Frameworks/libsrt.1.dylib, so if you need to place it in some other place with your application, you may change it with *install_name_tool* command: ``install_name_tool -id "" ``, for example ``install_name_tool -id "@executable_path/Frameworks/libsrt.1.3.0.dylib" libsrt.1.3.0.dylib`` ## Adding to Xcode project In Xcode project settings in General tab, add libsrt to **Linked Frameworks and Libraries** section - click Plus sign, then click "Add Other" and find libsrt.1.dylib Click plus sign in **Embedded binaries** section and choose Frameworks/libsrt.1.dylib In **Build settings** tab find **Header Search Paths** setting and add paths to SRT library sources (you should add srt, srt/common and srt/common directories). srt-1.5.4/docs/build/build-linux.md000066400000000000000000000024261471311275400171470ustar00rootroot00000000000000# Building SRT on Linux Install `cmake` and `openssl-devel` (or equivalent) packages. For `pthreads`, add the `-lpthreads` linker flag. Default installation path prefix of `make install` is `/usr/local`. To define a different installation path prefix, use the `--prefix` option with `configure` or the [`-DCMAKE_INSTALL_PREFIX`](https://cmake.org/cmake/help/v3.0/variable/CMAKE_INSTALL_PREFIX.html) CMake option. To uninstall, call `make -n install` to list all the dependencies, and then pass the list to `rm`. Here is a link to a demo showing how CMake can be used to build SRT: [Quickstart: Running SRT and FFmpeg on Ubuntu](https://www.youtube.com/watch?v=XOtUOVhussc&t=5s). ## Ubuntu 14 ```shell sudo apt-get update sudo apt-get upgrade sudo apt-get install tclsh pkg-config cmake libssl-dev build-essential ./configure make ``` ## CentOS 7 ```shell sudo yum update sudo yum install tcl pkgconfig openssl-devel cmake gcc gcc-c++ make automake ./configure make ``` ## CentOS 6 ```shell sudo yum update sudo yum install tcl pkgconfig openssl-devel cmake gcc gcc-c++ make automake sudo yum install centos-release-scl-rh devtoolset-3-gcc devtoolset-3-gcc-c++ scl enable devtoolset-3 bash ./configure --use-static-libstdc++ --with-compiler-prefix=/opt/rh/devtoolset-3/root/usr/bin/ make ``` srt-1.5.4/docs/build/build-macOS.md000066400000000000000000000015501471311275400170070ustar00rootroot00000000000000# Building SRT on macOS [Homebrew](https://brew.sh/) supports the [`srt`](https://formulae.brew.sh/formula/srt) formula. ```shell brew update brew install srt ``` If you prefer using a head commit of `master` branch, add the `--HEAD` option to `brew` command. ```shell brew install --HEAD srt ``` Install [CMake](https://cmake.org/) and OpenSSL with development files from `brew`. It is recommended to install the latest version of OpenSSL from the `brew` system rather than relying on the version that is presently installed in the system. ```shell brew install cmake brew install openssl brew install pkgconfig ``` SRT can be now built with `cmake` or `make` on Mac. ```shell export OPENSSL_ROOT_DIR=$(brew --prefix openssl) export OPENSSL_LIB_DIR=$(brew --prefix openssl)"/lib" export OPENSSL_INCLUDE_DIR=$(brew --prefix openssl)"/include" ./configure make ``` srt-1.5.4/docs/build/build-options.md000066400000000000000000001132611471311275400175030ustar00rootroot00000000000000# Build System The SRT build system uses [`CMake`](https://cmake.org/) 2.8.12 or above. A wrapper script named [`configure`](https://github.com/Haivision/srt/blob/master/configure) is also available. The `configure` script can simplify the build process, such as by trying to automatically detect the OpenSSL path in a system. Note that you must have the Tcl interpreter installed to use this script. Here is a link to a demo showing how CMake can be used to build SRT: [Quickstart: Running SRT and FFmpeg on Ubuntu](https://www.youtube.com/watch?v=XOtUOVhussc&t=5s). Additional information on building for Windows is available in the [Building SRT for Windows](https://github.com/Haivision/srt/blob/master/docs/build/build-win.md) document and in the [SRT CookBook](https://srtlab.github.io/srt-cookbook/getting-started/build-on-windows/). ## List of Build Options The following table lists available build options in alphabetical order. Option details are given further below. | Option Name | Since | Type | Default | Short Description | | :----------------------------------------------------------- | :---: | :-------: | :--------: | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | [`CMAKE_INSTALL_PREFIX`](#cmake_install_prefix) | 1.3.0 | `STRING` | OFF | Standard CMake variable that establishes the root directory for installation, inside of which a GNU/POSIX compatible directory layout will be used. | | [`CYGWIN_USE_POSIX`](#cygwin_use_posix) | 1.2.0 | `BOOL` | OFF | Determines when to compile on Cygwin using POSIX API. | | [`ENABLE_APPS`](#enable_apps) | 1.3.3 | `BOOL` | ON | Enables compiling sample applications (`srt-live-transmit`, etc.). | | [`ENABLE_BONDING`](#enable_bonding) | 1.5.0 | `BOOL` | OFF | Enables the [Connection Bonding](../features/bonding-quick-start.md) feature. | | [`ENABLE_CXX_DEPS`](#enable_cxx_deps) | 1.3.2 | `BOOL` | OFF | The `pkg-confg` file (`srt.pc`) will be generated with the `libstdc++` library as a dependency. | | [`ENABLE_CXX11`](#enable_cxx11) | 1.2.0 | `BOOL` | ON | Enable compiling in C++11 mode for those parts that may require it. Default: ON except for GCC<4.7 | | [`ENABLE_CODE_COVERAGE`](#enable_code_coverage) | 1.4.0 | `BOOL` | OFF | Enables instrumentation for code coverage. | | [`ENABLE_DEBUG`](#enable_debug) | 1.2.0 | `INT` | ON | Allows release/debug control through the `CMAKE_BUILD_TYPE` variable. | | [`ENABLE_ENCRYPTION`](#enable_encryption) | 1.3.3 | `BOOL` | ON | Enables encryption feature, with dependency on an external encryption library. | | [`ENABLE_AEAD_API_PREVIEW`](#enable_aead_api_preview) | 1.5.2 | `BOOL` | OFF | Enables AEAD preview API (encryption with integrity check). | | [`ENABLE_MAXREXMITBW`](#enable_maxrexmitbw) | 1.5.3 | `BOOL` | OFF | Enables SRTO_MAXREXMITBW (v1.6.0 API). | | [`ENABLE_GETNAMEINFO`](#enable_getnameinfo) | 1.3.0 | `BOOL` | OFF | Enables the use of `getnameinfo` to allow using reverse DNS to resolve an internal IP address into a readable internet domain name. | | [`ENABLE_HAICRYPT_LOGGING`](#enable_haicrypt_logging) | 1.3.1 | `BOOL` | OFF | Enables logging in the *haicrypt* module, which serves as a connector to an encryption library. | | [`ENABLE_HEAVY_LOGGING`](#enable_heavy_logging) | 1.3.0 | `BOOL` | OFF | Enables heavy logging instructions in the code that occur often and cover many detailed aspects of library behavior. Default: OFF in release mode. | | [`ENABLE_INET_PTON`](#enable_inet_pton) | 1.3.2 | `BOOL` | ON | Enables usage of the `inet_pton` function used to resolve the network endpoint name into an IP address. | | [`ENABLE_LOGGING`](#enable_logging) | 1.2.0 | `BOOL` | ON | Enables normal logging, including errors. | | [`ENABLE_MONOTONIC_CLOCK`](#enable_monotonic_clock) | 1.4.0 | `BOOL` | ON\* | Enforces the use of `clock_gettime` with a monotonic clock that is independent of the currently set time in the system. | | [`ENABLE_PROFILE`](#enable_profile) | 1.2.0 | `BOOL` | OFF | Enables code instrumentation for profiling (only for GNU-compatible compilers). | | [`ENABLE_RELATIVE_LIBPATH`](#enable_relative_libpath) | 1.3.2 | `BOOL` | OFF | Enables adding a relative path to a library for linking against a shared SRT library by reaching out to a sibling directory. | | [`ENABLE_SHARED`](#enable_shared--enable_static) | 1.2.0 | `BOOL` | ON | Enables building SRT as a shared library. | | [`ENABLE_SHOW_PROJECT_CONFIG`](#enable_show_project_config) | 1.5.0 | `BOOL` | OFF | When ON, the project configuration is displayed at the end of the CMake Configuration Step. | | [`ENABLE_STATIC`](#enable_shared--enable_static) | 1.3.0 | `BOOL` | ON | Enables building SRT as a static library. | | [`ENABLE_STDCXX_SYNC`](#enable_stdcxx_sync) | 1.4.2 | `BOOL` | ON\* | Enables the standard C++11 `thread` and `chrono` libraries to be used by SRT instead of the `pthreads`. | | [`ENABLE_PKTINFO`](#enable_pktinfo) | 1.5.2 | `BOOL` | OFF\* | Enables using `IP_PKTINFO` to allow the listener extracting the target IP address from incoming packets | | [`ENABLE_TESTING`](#enable_testing) | 1.3.0 | `BOOL` | OFF | Enables compiling of developer testing applications (`srt-test-live`, etc.). | | [`ENABLE_THREAD_CHECK`](#enable_thread_check) | 1.3.0 | `BOOL` | OFF | Enables `#include `, which implements `THREAD_*` macros" to support better thread debugging. | | [`ENABLE_UNITTESTS`](#enable_unittests) | 1.3.2 | `BOOL` | OFF | Enables building unit tests. | | [`OPENSSL_CRYPTO_LIBRARY`](#openssl_crypto_library) | 1.3.0 | `STRING` | OFF | Configures the path to an OpenSSL crypto library. | | [`OPENSSL_INCLUDE_DIR`](#openssl_include_dir) | 1.3.0 | `STRING` | OFF | Configures the path to include files for an OpenSSL library. | | [`OPENSSL_SSL_LIBRARY`](#openssl_ssl_library) | 1.3.0 | `STRING` | OFF | Configures the path to an OpenSSL SSL library. | | [`PKG_CONFIG_EXECUTABLE`](#pkg_config_executable) | 1.3.0 | `BOOL` | OFF | Configures the path to the `pkg-config` tool. | | [`PTHREAD_INCLUDE_DIR`](#pthread_include_dir) | 1.3.0 | `STRING` | OFF | Configures the path to include files for a `pthread` library. | | [`PTHREAD_LIBRARY`](#pthread_library) | 1.3.0 | `STRING` | OFF | Configures the path to a `pthread` library. | | [`SRT_LOG_SLOWDOWN_FREQ_MS`](#SRT_LOG_SLOWDOWN_FREQ_MS) | 1.5.2 | `INT` | 1000\* | Reduce the frequency of some frequent logs, milliseconds. | | [`USE_BUSY_WAITING`](#use_busy_waiting) | 1.3.3 | `BOOL` | OFF | Enables more accurate sending times at the cost of potentially higher CPU load. | | [`USE_CXX_STD`](#use_cxx_std) | 1.4.2 | `STRING` | OFF | Enforces using a particular C++ standard (11, 14, 17, etc.) when compiling. | | [`USE_ENCLIB`](#use_enclib) | 1.3.3 | `STRING` | openssl | Encryption library to be used (`openssl`, `openssl-evp` (since 1.5.1), `gnutls`, `mbedtls`, `botan` (since 1.6.0)). | | [`USE_GNUSTL`](#use_gnustl) | 1.3.4 | `BOOL` | OFF | Use `pkg-config` with the `gnustl` package name to extract the header and library path for the C++ standard library. | | [`USE_OPENSSL_PC`](#use_openssl_pc) | 1.3.0 | `BOOL` | ON | Use `pkg-config` to find OpenSSL libraries. | | [`OPENSSL_USE_STATIC_LIBS`](#openssl_use_static_libs) | 1.5.0 | `BOOL` | OFF | Link OpenSSL statically. | | [`USE_STATIC_LIBSTDCXX`](#use_static_libstdcxx) | 1.2.0 | `BOOL` | OFF | Enforces linking the SRT library against the static `libstdc++` library. | | [`WITH_COMPILER_PREFIX`](#with_compiler_prefix) | 1.3.0 | `STRING` | OFF | Sets C/C++ toolchains as `` and ``, overriding the default compiler. | | [`WITH_COMPILER_TYPE`](#with_compiler_type) | 1.3.0 | `STRING` | OFF | Sets the compiler type to be used (values: gcc, cc, clang, etc.). | | [`WITH_EXTRALIBS`](#with_extralibs) | 1.3.0 | `STRING` | OFF | Option required for unusual situations when a platform-specific workaround is needed and some extra libraries must be passed explicitly for linkage. | | [`WITH_SRT_NAME`](#with_srt_name) | 1.3.0 | `STRING` | OFF | Configure the SRT library name adding a custom ``. | | | | | | | \* See the option description for more details. ## Using CMake If you choose to use CMake directly for the build configuration stage, you must specify option values in the CMake format: `-D