From 9a09b5374e018468ab1673980fcfce31bcf2ebd3 Mon Sep 17 00:00:00 2001 From: Lewis Kirkaldie Date: Wed, 12 May 2021 09:27:03 +0100 Subject: [PATCH 001/124] [build] Windows Build Script improvements (#1994). Added custom build directory and VCPKG OpenSSL. --- .gitignore | 3 ++ CMakeLists.txt | 7 ++- scripts/build-windows.ps1 | 80 +++++++++++++++++++++++++++----- scripts/set-version-metadata.ps1 | 9 ++++ srtcore/version.h.in | 2 +- 5 files changed, 88 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index e179ad146..10f985468 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ _*/ # Ignode Visual Studio Code temp folder .vs/ .vscode/ + +# Ignore vcpkg submodule +vcpkg/ diff --git a/CMakeLists.txt b/CMakeLists.txt index df43a1e26..98d360671 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -790,9 +790,14 @@ MafReadDir(srtcore filelist.maf # Auto generated version file and add it to the HEADERS_srt list. if(DEFINED ENV{APPVEYOR_BUILD_NUMBER}) set(SRT_VERSION_BUILD ON) - set(APPVEYOR_BUILD_NUMBER_STRING $ENV{APPVEYOR_BUILD_NUMBER}) + 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) diff --git a/scripts/build-windows.ps1 b/scripts/build-windows.ps1 index 47ccb97f5..ab2d19d2d 100644 --- a/scripts/build-windows.ps1 +++ b/scripts/build-windows.ps1 @@ -6,7 +6,7 @@ # # By default produces a VS2019 64-bit Release binary using C++11 threads, without # encryption or unit tests enabled, but including test apps. -# Before enabling any encryption options, please install OpenSSL (or customize) +# Before enabling any encryption options, install OpenSSL or set VCKPG flag to build ################################################################################ param ( @@ -17,7 +17,9 @@ param ( [Parameter()][String]$STATIC_LINK_SSL = "OFF", [Parameter()][String]$CXX11 = "ON", [Parameter()][String]$BUILD_APPS = "ON", - [Parameter()][String]$UNIT_TESTS = "OFF" + [Parameter()][String]$UNIT_TESTS = "OFF", + [Parameter()][String]$BUILD_DIR = "_build", + [Parameter()][String]$VCPKG_OPENSSL = "OFF" ) # cmake can be optionally installed (useful when running interactively on a developer station). @@ -65,7 +67,7 @@ if ( $VS_VERSION -eq '2013' -and $DEVENV_PLATFORM -eq 'Win32' ) { $CMAKE_GENERAT if ( $VS_VERSION -eq '2013' -and $DEVENV_PLATFORM -eq 'x64' ) { $CMAKE_GENERATOR = 'Visual Studio 12 2013 Win64'; $MSBUILDVER = "12.0"; } # clear any previous build and create & enter the build directory -$buildDir = Join-Path "$projectRoot" "_build" +$buildDir = Join-Path "$projectRoot" "$BUILD_DIR" Write-Output "Creating (or cleaning if already existing) the folder $buildDir for project files and outputs" Remove-Item -Path $buildDir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null New-Item -ItemType Directory -Path $buildDir -ErrorAction SilentlyContinue | Out-Null @@ -88,19 +90,20 @@ if ( $null -eq (Get-Command "cmake.exe" -ErrorAction SilentlyContinue) ) { Start-Process $cmakeMsiFile -Wait Remove-Item $cmakeMsiFile Write-Output "Cmake should have installed, this script will now exit because of path updates - please now re-run this script" - exit + throw } else{ Write-Output "Quitting because cmake is required" - exit + throw } } +# get pthreads from nuget if CXX11 is not enabled if ( $CXX11 -eq "OFF" ) { # get pthreads (this is legacy, and is only availble in nuget for VS2015 and VS2013) if ( $VS_VERSION -gt 2015 ) { Write-Output "Pthreads is not recommended for use beyond VS2015 and is not supported by this build script - aborting build" - exit + throw } if ( $DEVENV_PLATFORM -eq 'Win32' ) { nuget install cinegy.pthreads-win32-$VS_VERSION -version 2.9.1.24 -OutputDirectory ../_packages @@ -110,6 +113,7 @@ if ( $CXX11 -eq "OFF" ) { } } +# check to see if static SSL linking was requested, and enable encryption if not already ON if ( $STATIC_LINK_SSL -eq "ON" ) { if ( $ENABLE_ENCRYPTION -eq "OFF" ) { # requesting a static link implicitly requires encryption support @@ -118,14 +122,63 @@ if ( $STATIC_LINK_SSL -eq "ON" ) { } } +# check to see if VCPKG is marked to provide OpenSSL, and enable encryption if not already ON +if ( $VCPKG_OPENSSL -eq "ON" ) { + if ( $ENABLE_ENCRYPTION -eq "OFF" ) { + # requesting VCPKG to provide OpenSSL requires encryption support + Write-Output "VCPKG compilation of OpenSSL requested, will force encryption feature ON" + $ENABLE_ENCRYPTION = "ON" + } +} + # build the cmake command flags from arguments $cmakeFlags = "-DCMAKE_BUILD_TYPE=$CONFIGURATION " + "-DENABLE_STDCXX_SYNC=$CXX11 " + "-DENABLE_APPS=$BUILD_APPS " + "-DENABLE_ENCRYPTION=$ENABLE_ENCRYPTION " + - "-DOPENSSL_USE_STATIC_LIBS=$STATIC_LINK_SSL " + "-DENABLE_UNITTESTS=$UNIT_TESTS" +# if VCPKG is flagged to provide OpenSSL, checkout VCPKG and install package +if ( $VCPKG_OPENSSL -eq 'ON' ) { + Push-Location $projectRoot + Write-Output "Cloning VCPKG into: $(Get-Location)" + if (Test-Path -Path ".\vcpkg") { + Set-Location .\vcpkg + git pull + } else { + git clone https://github.com/microsoft/vcpkg + Set-Location .\vcpkg + } + + .\bootstrap-vcpkg.bat + + if($DEVENV_PLATFORM -EQ "x64"){ + if($STATIC_LINK_SSL -EQ "ON"){ + .\vcpkg install openssl:x64-windows-static + $cmakeFlags += " -DVCPKG_TARGET_TRIPLET=x64-windows-static" + } + else{ + .\vcpkg install openssl:x64-windows + } + } + else{ + if($STATIC_LINK_SSL -EQ "ON"){ + .\vcpkg install openssl:x86-windows-static + $cmakeFlags += " -DVCPKG_TARGET_TRIPLET=x86-windows-static" + } + else{ + .\vcpkg install openssl:x86-windows + } + } + + .\vcpkg integrate install + Pop-Location + $cmakeFlags += " -DCMAKE_TOOLCHAIN_FILE=$projectRoot\vcpkg\scripts\buildsystems\vcpkg.cmake" +} +else { + $cmakeFlags += " -DOPENSSL_USE_STATIC_LIBS=$STATIC_LINK_SSL " +} + # cmake uses a flag for architecture from vs2019, so add that as a suffix if ( $VS_VERSION -eq '2019' ) { $cmakeFlags += " -A `"$DEVENV_PLATFORM`"" @@ -143,7 +196,8 @@ Invoke-Expression "& $execVar" # check build ran OK, exit if cmake failed if( $LASTEXITCODE -ne 0 ) { - return $LASTEXITCODE + Write-Output "Non-zero exit code from cmake: $LASTEXITCODE" + throw } $ErrorActionPreference = "Stop" @@ -161,13 +215,17 @@ if ( $null -eq $msBuildPath ) { $vsWherePath = Get-Command "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -ErrorAction SilentlyContinue if ( $null -eq $vsWherePath ) { Write-Output "Cannot find vswhere (used to locate msbuild). Please install VS2017 update 2 (or later) or add vswhere to your path and try again" - exit + throw } } - $msBuildPath = & $vsWherePath -version $MSBUILDVER -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1 + $msBuildPath = & $vsWherePath -products * -version $MSBUILDVER -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1 + if ( $null -eq $msBuildPath ) { + Write-Output "vswhere.exe cannot find msbuild for the specified Visual Studio version - please check the installation" + throw + } } -& $msBuildPath SRT.sln /p:Configuration=$CONFIGURATION /p:Platform=$DEVENV_PLATFORM +& $msBuildPath SRT.sln -m /p:Configuration=$CONFIGURATION /p:Platform=$DEVENV_PLATFORM # return to the directory previously occupied before running the script Pop-Location diff --git a/scripts/set-version-metadata.ps1 b/scripts/set-version-metadata.ps1 index cd36cc37d..050838e5e 100644 --- a/scripts/set-version-metadata.ps1 +++ b/scripts/set-version-metadata.ps1 @@ -27,6 +27,15 @@ if($Env:APPVEYOR){ Update-AppveyorBuild -Version "$majorVer.$minorVer.$patchVer.$buildNum" $FileDescriptionBranchCommitValue = "$Env:APPVEYOR_REPO_NAME - $($Env:APPVEYOR_REPO_BRANCH) ($($Env:APPVEYOR_REPO_COMMIT.substring(0,8)))" } +if($Env:TEAMCITY_VERSION){ + #make TeamCity update with this new version number + Write-Output "##teamcity[buildNumber '$majorVer.$minorVer.$patchVer.$buildNum']" + Write-Output "##teamcity[setParameter name='MajorVersion' value='$majorVer']" + Write-Output "##teamcity[setParameter name='MinorVersion' value='$minorVer']" + Write-Output "##teamcity[setParameter name='PatchVersion' value='$patchVer']" + Write-Output "##teamcity[setParameter name='BuildVersion' value='$buildNum']" + $FileDescriptionBranchCommitValue = "$majorVer.$minorVer.$patchVer.$buildNum - ($($Env:BUILD_VCS_NUMBER.substring(0,8)))" +} #find C++ resource files and update file description with branch / commit details $FileDescriptionStringRegex = '(\bVALUE\s+\"FileDescription\"\s*\,\s*\")([^\"]*\\\")*[^\"]*(\")' diff --git a/srtcore/version.h.in b/srtcore/version.h.in index 72ce89bcb..c32ac1226 100644 --- a/srtcore/version.h.in +++ b/srtcore/version.h.in @@ -24,7 +24,7 @@ written by #define SRT_VERSION_MAJOR @SRT_VERSION_MAJOR@ #define SRT_VERSION_MINOR @SRT_VERSION_MINOR@ #define SRT_VERSION_PATCH @SRT_VERSION_PATCH@ -#cmakedefine SRT_VERSION_BUILD @APPVEYOR_BUILD_NUMBER_STRING@ +#cmakedefine SRT_VERSION_BUILD @CI_BUILD_NUMBER_STRING@ #define SRT_VERSION_STRING "@SRT_VERSION@" #define SRT_VERSION_VALUE \ From 930d3468ae256dcb959d96d3a2a38c06c10a4645 Mon Sep 17 00:00:00 2001 From: Thierry Lelegard Date: Wed, 12 May 2021 11:50:20 +0200 Subject: [PATCH 002/124] [build] Added script to build the Windows installer for SRT libraries (#1995). See the scripts/win-installer/README.md file for details. --- scripts/win-installer/.gitignore | 10 + scripts/win-installer/README.md | 33 +++ scripts/win-installer/build-win-intaller.ps1 | 212 ++++++++++++++++++ scripts/win-installer/install-nsis.ps1 | 122 +++++++++++ scripts/win-installer/install-openssl.ps1 | 119 ++++++++++ scripts/win-installer/libsrt.nsi | 217 +++++++++++++++++++ scripts/win-installer/libsrt.props | 19 ++ 7 files changed, 732 insertions(+) create mode 100644 scripts/win-installer/.gitignore create mode 100644 scripts/win-installer/README.md create mode 100644 scripts/win-installer/build-win-intaller.ps1 create mode 100644 scripts/win-installer/install-nsis.ps1 create mode 100644 scripts/win-installer/install-openssl.ps1 create mode 100644 scripts/win-installer/libsrt.nsi create mode 100644 scripts/win-installer/libsrt.props diff --git a/scripts/win-installer/.gitignore b/scripts/win-installer/.gitignore new file mode 100644 index 000000000..ed44eef33 --- /dev/null +++ b/scripts/win-installer/.gitignore @@ -0,0 +1,10 @@ +tmp +installers +*.exe +*~ +~* +.#* +*.bak +*.autosave +.DS_Store +._* diff --git a/scripts/win-installer/README.md b/scripts/win-installer/README.md new file mode 100644 index 000000000..205e03893 --- /dev/null +++ b/scripts/win-installer/README.md @@ -0,0 +1,33 @@ +## SRT Static Libraries Installer for Windows + +This directory contains scripts to build a binary installer for +libsrt on Windows systems for Visual Studio applications using SRT. + +### Building Windows applications with libsrt + +After installing the libsrt binary, an environment variable named `LIBSRT` is +defined to the installation root (typically `C:\Program Files (x86)\libsrt`). + +In this directory, there is a Visual Studio property file named `libsrt.props`. +Simply reference this property file in your Visual Studio project to use libsrt. + +You can also do that manually by editing the application project file (the XML +file named with a `.vcxproj` extension). Add the following line just before +the end of the file: + +~~~ + +~~~ + +### Building the installer + +The first two steps need to be executed once only. Only the last step needs +to be repeated each time a new version of libsrt is available. + +- Prerequisite 1: Install OpenSSL for Windows, both 64 and 32 bits. + This can be done automatically by running the PowerShell script `install-openssl.ps1`. +- Prerequisite 2: Install NSIS, the NullSoft Installation Scripting system. + This can be done automatically by running the PowerShell script `install-nsis.ps1`. +- Build the libsrt installer by running the PowerShell script `build-win-installer.ps1`. + +The installer is then available in the directory `installers`. diff --git a/scripts/win-installer/build-win-intaller.ps1 b/scripts/win-installer/build-win-intaller.ps1 new file mode 100644 index 000000000..261c457fa --- /dev/null +++ b/scripts/win-installer/build-win-intaller.ps1 @@ -0,0 +1,212 @@ +#----------------------------------------------------------------------------- +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021, Thierry Lelegard +# +# 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/. +# +#----------------------------------------------------------------------------- + +<# + .SYNOPSIS + + Build the SRT static libraries installer for Windows. + + .PARAMETER Version + + Use the specified string as version number from libsrt. By default, if + the current commit has a tag, use that tag (initial 'v' removed). Otherwise, + the defaut version is a detailed version number (most recent version, number + of commits since then, short commit SHA). + + .PARAMETER NoPause + + Do not wait for the user to press at end of execution. By default, + execute a "pause" instruction at the end of execution, which is useful + when the script was run from Windows Explorer. + +#> +[CmdletBinding()] +param( + [string]$Version = "", + [switch]$NoPause = $false +) +Write-Output "Building the SRT static libraries installer for Windows" + +# Directory containing this script: +$ScriptDir = $PSScriptRoot + +# The root of the srt repository is two levels up. +$RepoDir = (Split-Path -Parent (Split-Path -Parent $ScriptDir)) + +# Output directory for final installers: +$OutDir = "$ScriptDir\installers" + +# Temporary directory for build operations: +$TmpDir = "$ScriptDir\tmp" + + +#----------------------------------------------------------------------------- +# A function to exit this script with optional error message, using -NoPause +#----------------------------------------------------------------------------- + +function Exit-Script([string]$Message = "") +{ + $Code = 0 + if ($Message -ne "") { + Write-Output "ERROR: $Message" + $Code = 1 + } + if (-not $NoPause) { + pause + } + exit $Code +} + + +#----------------------------------------------------------------------------- +# Build SRT version strings +#----------------------------------------------------------------------------- + +# By default, let git format a decent version number. +if (-not $Version) { + $Version = (git describe --tags ) -replace '-g','-' +} +$Version = $Version -replace '^v','' + +# Split version string in pieces and make sure to get at least four elements. +$VField = ($Version -split "[-\. ]") + @("0", "0", "0", "0") | Select-String -Pattern '^\d*$' +$VersionInfo = "$($VField[0]).$($VField[1]).$($VField[2]).$($VField[3])" + +Write-Output "SRT version: $Version" +Write-Output "Windows version info: $VersionInfo" + + +#----------------------------------------------------------------------------- +# Initialization phase, verify prerequisites +#----------------------------------------------------------------------------- + +# Locate OpenSSL root from local installation. +$SslRoot = @{ + "x64" = "C:\Program Files\OpenSSL-Win64"; + "Win32" = "C:\Program Files (x86)\OpenSSL-Win32" +} + +# Verify OpenSSL directories. +$Missing = 0 +foreach ($file in @($SslRoot["x64"], $SslRoot["Win32"])) { + if (-not (Test-Path $file)) { + Write-Output "**** Missing $file" + $Missing = $Missing + 1 + } +} +if ($Missing -gt 0) { + Exit-Script "Missing $Missing OpenSSL files, use install-openssl.ps1 to install OpenSSL" +} + +# Locate MSBuild and CMake, regardless of Visual Studio version. +Write-Output "Searching MSBuild ..." +$MSRoots = @("C:\Program Files*\MSBuild", "C:\Program Files*\Microsoft Visual Studio", "C:\Program Files*\CMake*") +$MSBuild = Get-ChildItem -Recurse -Path $MSRoots -Include MSBuild.exe -ErrorAction Ignore | + ForEach-Object { (Get-Command $_).FileVersionInfo } | + Sort-Object -Unique -Property FileVersion | + ForEach-Object { $_.FileName} | + Select-Object -Last 1 +if (-not $MSBuild) { + Exit-Script "MSBuild not found" +} + +Write-Output "Searching CMake ..." +$CMake = Get-ChildItem -Recurse -Path $MSRoots -Include cmake.exe -ErrorAction Ignore | + ForEach-Object { (Get-Command $_).FileVersionInfo } | + Sort-Object -Unique -Property FileVersion | + ForEach-Object { $_.FileName} | + Select-Object -Last 1 +if (-not $CMake) { + Exit-Script "CMake not found, check option 'C++ CMake tools for Windows' in Visual Studio installer" +} + +# Locate NSIS, the Nullsoft Scriptable Installation System. +Write-Output "Searching NSIS ..." +$NSIS = Get-Item "C:\Program Files*\NSIS\makensis.exe" | ForEach-Object { $_.FullName} | Select-Object -Last 1 +if (-not $NSIS) { + Exit-Script "NSIS not found, use install-nsis.ps1 to install NSIS" +} + +Write-Output "MSBuild: $MSBuild" +Write-Output "CMake: $CMake" +Write-Output "NSIS: $NSIS" + +# Create the directories for builds when necessary. +[void](New-Item -Path $TmpDir -ItemType Directory -Force) +[void](New-Item -Path $OutDir -ItemType Directory -Force) + + +#----------------------------------------------------------------------------- +# Configure and build SRT library using CMake on two architectures. +#----------------------------------------------------------------------------- + +foreach ($Platform in @("x64", "Win32")) { + + # Build directory. Cleanup to force a fresh cmake config. + $BuildDir = "$TmpDir\build.$Platform" + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $BuildDir + [void](New-Item -Path $BuildDir -ItemType Directory -Force) + + # Run CMake. + Write-Output "Configuring build for platform $Platform ..." + $SRoot = $SslRoot[$Platform] + & $CMake -S $RepoDir -B $BuildDir -A $Platform ` + -DENABLE_STDCXX_SYNC=ON ` + -DOPENSSL_ROOT_DIR="$SRoot" ` + -DOPENSSL_LIBRARIES="$SRoot\lib\libssl_static.lib;$SRoot\lib\libcrypto_static.lib" ` + -DOPENSSL_INCLUDE_DIR="$SRoot\include" + + # Patch version string in version.h + Get-Content "$BuildDir\version.h" | + ForEach-Object { + $_ -replace "#define *SRT_VERSION_STRING .*","#define SRT_VERSION_STRING `"$Version`"" + } | + Out-File "$BuildDir\version.new" -Encoding ascii + Move-Item "$BuildDir\version.new" "$BuildDir\version.h" -Force + + # Compile SRT. + Write-Output "Building for platform $Platform ..." + foreach ($Conf in @("Release", "Debug")) { + & $MSBuild "$BuildDir\SRT.sln" /nologo /maxcpucount /property:Configuration=$Conf /property:Platform=$Platform /target:srt_static + } +} + +# Verify the presence of compiled libraries. +Write-Output "Checking compiled libraries ..." +$Missing = 0 +foreach ($Conf in @("Release", "Debug")) { + foreach ($Platform in @("x64", "Win32")) { + $Path = "$TmpDir\build.$Platform\$Conf\srt_static.lib" + if (-not (Test-Path $Path)) { + Write-Output "**** Missing $Path" + $Missing = $Missing + 1 + } + } +} +if ($Missing -gt 0) { + Exit-Script "Missing $Missing files" +} + + +#----------------------------------------------------------------------------- +# Build the binary installer. +#----------------------------------------------------------------------------- + +Write-Output "Building installer ..." +& $NSIS /V2 ` + /DVersion="$Version" ` + /DVersionInfo="$VersionInfo" ` + /DOutDir="$OutDir" ` + /DBuildRoot="$TmpDir" ` + /DRepoDir="$RepoDir" ` + "$ScriptDir\libsrt.nsi" + +Exit-Script diff --git a/scripts/win-installer/install-nsis.ps1 b/scripts/win-installer/install-nsis.ps1 new file mode 100644 index 000000000..14879b521 --- /dev/null +++ b/scripts/win-installer/install-nsis.ps1 @@ -0,0 +1,122 @@ +#----------------------------------------------------------------------------- +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021, Thierry Lelegard +# +# 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/. +# +#----------------------------------------------------------------------------- + +<# + .SYNOPSIS + + Download, expand and install NSIS, the NullSoft Installer Scripting. + + .PARAMETER ForceDownload + + Force a download even if NSIS is already downloaded. + + .PARAMETER NoInstall + + Do not install the NSIS package. By default, NSIS is installed. + + .PARAMETER NoPause + + Do not wait for the user to press at end of execution. By default, + execute a "pause" instruction at the end of execution, which is useful + when the script was run from Windows Explorer. +#> +[CmdletBinding(SupportsShouldProcess=$true)] +param( + [switch]$ForceDownload = $false, + [switch]$NoInstall = $false, + [switch]$NoPause = $false +) + +Write-Output "NSIS download and installation procedure" +$NSISPage = "https://nsis.sourceforge.io/Download" +$FallbackURL = "http://prdownloads.sourceforge.net/nsis/nsis-3.05-setup.exe?download" + +# A function to exit this script. +function Exit-Script([string]$Message = "") +{ + $Code = 0 + if ($Message -ne "") { + Write-Output "ERROR: $Message" + $Code = 1 + } + if (-not $NoPause) { + pause + } + exit $Code +} + +# Local file names. +$RootDir = $PSScriptRoot +$TmpDir = "$RootDir\tmp" + +# Create the directory for external products when necessary. +[void] (New-Item -Path $TmpDir -ItemType Directory -Force) + +# Without this, Invoke-WebRequest is awfully slow. +$ProgressPreference = 'SilentlyContinue' + +# Get the HTML page for NSIS downloads. +$status = 0 +$message = "" +$Ref = $null +try { + $response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $NSISPage + $status = [int] [Math]::Floor($response.StatusCode / 100) +} +catch { + $message = $_.Exception.Message +} + +if ($status -ne 1 -and $status -ne 2) { + # Error fetch NSIS download page. + if ($message -eq "" -and (Test-Path variable:response)) { + Write-Output "Status code $($response.StatusCode), $($response.StatusDescription)" + } + else { + Write-Output "#### Error accessing ${NSISPage}: $message" + } +} +else { + # Parse HTML page to locate the latest installer. + $Ref = $response.Links.href | Where-Object { $_ -like "*/nsis-*-setup.exe?download" } | Select-Object -First 1 +} + +if (-not $Ref) { + # Could not find a reference to NSIS installer. + $Url = [System.Uri]$FallbackURL +} +else { + # Build the absolute URL's from base URL (the download page) and href links. + $Url = New-Object -TypeName 'System.Uri' -ArgumentList ([System.Uri]$NSISPage, $Ref) +} + +$InstallerName = (Split-Path -Leaf $Url.LocalPath) +$InstallerPath = "$TmpDir\$InstallerName" + +# Download installer +if (-not $ForceDownload -and (Test-Path $InstallerPath)) { + Write-Output "$InstallerName already downloaded, use -ForceDownload to download again" +} +else { + Write-Output "Downloading $Url ..." + Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $InstallerPath + if (-not (Test-Path $InstallerPath)) { + Exit-Script "$Url download failed" + } +} + +# Install NSIS +if (-not $NoInstall) { + Write-Output "Installing $InstallerName" + Start-Process -FilePath $InstallerPath -ArgumentList @("/S") -Wait +} + +Exit-Script diff --git a/scripts/win-installer/install-openssl.ps1 b/scripts/win-installer/install-openssl.ps1 new file mode 100644 index 000000000..83b59954f --- /dev/null +++ b/scripts/win-installer/install-openssl.ps1 @@ -0,0 +1,119 @@ +#----------------------------------------------------------------------------- +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021, Thierry Lelegard +# +# 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/. +# +#----------------------------------------------------------------------------- + +<# + .SYNOPSIS + + Download, expand and install OpenSSL for Windows. + + .PARAMETER ForceDownload + + Force a download even if the OpenSSL installers are already downloaded. + + .PARAMETER NoInstall + + Do not install the OpenSSL packages. By default, OpenSSL is installed. + + .PARAMETER NoPause + + Do not wait for the user to press at end of execution. By default, + execute a "pause" instruction at the end of execution, which is useful + when the script was run from Windows Explorer. +#> +[CmdletBinding(SupportsShouldProcess=$true)] +param( + [switch]$ForceDownload = $false, + [switch]$NoInstall = $false, + [switch]$NoPause = $false +) + +Write-Output "OpenSSL download and installation procedure" +$OpenSSLHomePage = "http://slproweb.com/products/Win32OpenSSL.html" + +# A function to exit this script. +function Exit-Script([string]$Message = "") +{ + $Code = 0 + if ($Message -ne "") { + Write-Output "ERROR: $Message" + $Code = 1 + } + if (-not $NoPause) { + pause + } + exit $Code +} + +# Local file names. +$RootDir = $PSScriptRoot +$TmpDir = "$RootDir\tmp" + +# Create the directory for external products when necessary. +[void] (New-Item -Path $TmpDir -ItemType Directory -Force) + +# Without this, Invoke-WebRequest is awfully slow. +$ProgressPreference = 'SilentlyContinue' + +# Get the HTML page for OpenSSL downloads. +$status = 0 +$message = "" +try { + $response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $OpenSSLHomePage + $status = [int] [Math]::Floor($response.StatusCode / 100) +} +catch { + $message = $_.Exception.Message +} +if ($status -ne 1 -and $status -ne 2) { + if ($message -eq "" -and (Test-Path variable:response)) { + Exit-Script "Status code $($response.StatusCode), $($response.StatusDescription)" + } + else { + Exit-Script "#### Error accessing ${OpenSSLHomePage}: $message" + } +} + +# Parse HTML page to locate the latest MSI files. +$Ref32 = $response.Links.href | Where-Object { $_ -like "*/Win32OpenSSL-*.msi" } | Select-Object -First 1 +$Ref64 = $response.Links.href | Where-Object { $_ -like "*/Win64OpenSSL-*.msi" } | Select-Object -First 1 + +# Build the absolute URL's from base URL (the download page) and href links. +$Url32 = New-Object -TypeName 'System.Uri' -ArgumentList ([System.Uri]$OpenSSLHomePage, $Ref32) +$Url64 = New-Object -TypeName 'System.Uri' -ArgumentList ([System.Uri]$OpenSSLHomePage, $Ref64) + +# Download and install one MSI package. +function Download-Install([string]$Url) +{ + $MsiName = (Split-Path -Leaf $Url.toString()) + $MsiPath = "$TmpDir\$MsiName" + + if (-not $ForceDownload -and (Test-Path $MsiPath)) { + Write-Output "$MsiName already downloaded, use -ForceDownload to download again" + } + else { + Write-Output "Downloading $Url ..." + Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $MsiPath + } + + if (-not (Test-Path $MsiPath)) { + Exit-Script "$Url download failed" + } + + if (-not $NoInstall) { + Write-Output "Installing $MsiName" + Start-Process msiexec.exe -ArgumentList @("/i", $MsiPath, "/qn", "/norestart") -Wait + } +} + +# Download and install the two MSI packages. +Download-Install $Url32 +Download-Install $Url64 +Exit-Script diff --git a/scripts/win-installer/libsrt.nsi b/scripts/win-installer/libsrt.nsi new file mode 100644 index 000000000..4628642cc --- /dev/null +++ b/scripts/win-installer/libsrt.nsi @@ -0,0 +1,217 @@ +;----------------------------------------------------------------------------- +; +; SRT - Secure, Reliable, Transport +; Copyright (c) 2021, Thierry Lelegard +; +; 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/. +; +;----------------------------------------------------------------------------- +; +; NSIS script to build the SRT binary installer for Windows. +; Do not invoke NSIS directly, use PowerShell script build-win-installer.ps1 +; to ensure that all parameters are properly passed. +; +;----------------------------------------------------------------------------- + +Name "SRT" +Caption "SRT Libraries Installer" + +!verbose push +!verbose 0 +!include "MUI2.nsh" +!include "Sections.nsh" +!include "TextFunc.nsh" +!include "FileFunc.nsh" +!include "WinMessages.nsh" +!include "x64.nsh" +!verbose pop + +!define ProductName "libsrt" +!define Build32Dir "${BuildRoot}\build.Win32" +!define Build64Dir "${BuildRoot}\build.x64" +!define SSL32Dir "C:\Program Files (x86)\OpenSSL-Win32" +!define SSL64Dir "C:\Program Files\OpenSSL-Win64" + +; Installer file information. +VIProductVersion ${VersionInfo} +VIAddVersionKey ProductName "${ProductName}" +VIAddVersionKey ProductVersion "${Version}" +VIAddVersionKey Comments "The SRT static libraries for Visual C++ on Windows" +VIAddVersionKey CompanyName "Haivision" +VIAddVersionKey LegalCopyright "Copyright (c) 2021 Haivision Systems Inc." +VIAddVersionKey FileVersion "${VersionInfo}" +VIAddVersionKey FileDescription "SRT Installer" + +; Name of binary installer file. +OutFile "${OutDir}\${ProductName}-${Version}.exe" + +; Generate a Unicode installer (default is ANSI). +Unicode true + +; Registry key for environment variables +!define EnvironmentKey '"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' + +; Registry entry for product info and uninstallation info. +!define ProductKey "Software\${ProductName}" +!define UninstallKey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${ProductName}" + +; Use XP manifest. +XPStyle on + +; Request administrator privileges for Windows Vista and higher. +RequestExecutionLevel admin + +; "Modern User Interface" (MUI) settings. +!define MUI_ABORTWARNING + +; Default installation folder. +InstallDir "$PROGRAMFILES\${ProductName}" + +; Get installation folder from registry if available from a previous installation. +InstallDirRegKey HKLM "${ProductKey}" "InstallDir" + +; Installer pages. +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES + +; Uninstaller pages. +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +; Languages. +!insertmacro MUI_LANGUAGE "English" + +; Installation initialization. +function .onInit + ; In 64-bit installers, don't use registry redirection. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} +functionEnd + +; Uninstallation initialization. +function un.onInit + ; In 64-bit installers, don't use registry redirection. + ${If} ${RunningX64} + SetRegView 64 + ${EndIf} +functionEnd + +; Installation section +Section "Install" + + ; Work on "all users" context, not current user. + SetShellVarContext all + + ; Delete obsolete files from previous versions. + Delete "$INSTDIR\LICENSE.pthread.txt" + Delete "$INSTDIR\include\srt\srt4udt.h" + Delete "$INSTDIR\include\srt\udt.h" + Delete "$INSTDIR\lib\Release-x64\pthread.lib" + Delete "$INSTDIR\lib\Release-Win32\pthread.lib" + Delete "$INSTDIR\lib\Debug-x64\srt.pdb" + Delete "$INSTDIR\lib\Debug-x64\pthread.pdb" + Delete "$INSTDIR\lib\Debug-x64\pthread.lib" + Delete "$INSTDIR\lib\Debug-Win32\srt.pdb" + Delete "$INSTDIR\lib\Debug-Win32\pthread.pdb" + Delete "$INSTDIR\lib\Debug-Win32\pthread.lib" + + SetOutPath "$INSTDIR" + File /oname=LICENSE.txt "${RepoDir}\LICENSE" + File "libsrt.props" + + ; Header files. + CreateDirectory "$INSTDIR\include\srt" + SetOutPath "$INSTDIR\include\srt" + File "${RepoDir}\srtcore\logging_api.h" + File "${RepoDir}\srtcore\platform_sys.h" + File "${RepoDir}\srtcore\srt.h" + File "${Build64Dir}\version.h" + + CreateDirectory "$INSTDIR\include\win" + SetOutPath "$INSTDIR\include\win" + File "${RepoDir}\common\win\syslog_defs.h" + + ; Libraries. + CreateDirectory "$INSTDIR\lib" + + CreateDirectory "$INSTDIR\lib\Release-x64" + SetOutPath "$INSTDIR\lib\Release-x64" + File /oname=srt.lib "${Build64Dir}\Release\srt_static.lib" + File /oname=libcrypto.lib "${SSL64Dir}\lib\VC\static\libcrypto64MD.lib" + File /oname=libssl.lib "${SSL64Dir}\lib\VC\static\libssl64MD.lib" + + CreateDirectory "$INSTDIR\lib\Debug-x64" + SetOutPath "$INSTDIR\lib\Debug-x64" + File /oname=srt.lib "${Build64Dir}\Debug\srt_static.lib" + File /oname=libcrypto.lib "${SSL64Dir}\lib\VC\static\libcrypto64MDd.lib" + File /oname=libssl.lib "${SSL64Dir}\lib\VC\static\libssl64MDd.lib" + + CreateDirectory "$INSTDIR\lib\Release-Win32" + SetOutPath "$INSTDIR\lib\Release-Win32" + File /oname=srt.lib "${Build32Dir}\Release\srt_static.lib" + File /oname=libcrypto.lib "${SSL32Dir}\lib\VC\static\libcrypto32MD.lib" + File /oname=libssl.lib "${SSL32Dir}\lib\VC\static\libssl32MD.lib" + + CreateDirectory "$INSTDIR\lib\Debug-Win32" + SetOutPath "$INSTDIR\lib\Debug-Win32" + File /oname=srt.lib "${Build32Dir}\Debug\srt_static.lib" + File /oname=libcrypto.lib "${SSL32Dir}\lib\VC\static\libcrypto32MDd.lib" + File /oname=libssl.lib "${SSL32Dir}\lib\VC\static\libssl32MDd.lib" + + ; Add an environment variable to installation root. + WriteRegStr HKLM ${EnvironmentKey} "LIBSRT" "$INSTDIR" + + ; Store installation folder in registry. + WriteRegStr HKLM "${ProductKey}" "InstallDir" $INSTDIR + + ; Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + + ; Declare uninstaller in "Add/Remove Software" control panel + WriteRegStr HKLM "${UninstallKey}" "DisplayName" "${ProductName}" + WriteRegStr HKLM "${UninstallKey}" "Publisher" "Haivision" + WriteRegStr HKLM "${UninstallKey}" "URLInfoAbout" "https://github.com/Haivision/srt" + WriteRegStr HKLM "${UninstallKey}" "DisplayVersion" "${Version}" + WriteRegStr HKLM "${UninstallKey}" "DisplayIcon" "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "${UninstallKey}" "UninstallString" "$INSTDIR\Uninstall.exe" + + ; Get estimated size of installed files + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UninstallKey}" "EstimatedSize" "$0" + + ; Notify applications of environment modifications + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + +SectionEnd + +; Uninstallation section +Section "Uninstall" + + ; Work on "all users" context, not current user. + SetShellVarContext all + + ; Get installation folder from registry + ReadRegStr $0 HKLM "${ProductKey}" "InstallDir" + + ; Delete product registry entries + DeleteRegKey HKCU "${ProductKey}" + DeleteRegKey HKLM "${ProductKey}" + DeleteRegKey HKLM "${UninstallKey}" + DeleteRegValue HKLM ${EnvironmentKey} "LIBSRT" + + ; Delete product files. + RMDir /r "$0\include" + RMDir /r "$0\lib" + Delete "$0\libsrt.props" + Delete "$0\LICENSE*" + Delete "$0\Uninstall.exe" + RMDir "$0" + + ; Notify applications of environment modifications + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + +SectionEnd diff --git a/scripts/win-installer/libsrt.props b/scripts/win-installer/libsrt.props new file mode 100644 index 000000000..d8de447c1 --- /dev/null +++ b/scripts/win-installer/libsrt.props @@ -0,0 +1,19 @@ + + + + + + + + + + $(LIBSRT)\include;%(AdditionalIncludeDirectories) + + + srt.lib;libssl.lib;libcrypto.lib;crypt32.lib;%(AdditionalDependencies) + $(LIBSRT)\lib\$(Configuration)-$(Platform);%(AdditionalLibraryDirectories) + /ignore:4099 %(AdditionalOptions) + + + + From 36f89952037c3715ed7cbfe7d98d89995ed591cf Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 11 May 2021 13:46:00 +0200 Subject: [PATCH 003/124] [core] CRendezvousQueue: added doxygen comments. Renamed m_RIDVectorLock to m_RIDListLock. --- srtcore/queue.cpp | 20 ++++++++++---------- srtcore/queue.h | 47 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 8fe5809bc..2de1515dd 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -815,7 +815,7 @@ void CHash::remove(int32_t id) // CRendezvousQueue::CRendezvousQueue() : m_lRendezvousID() - , m_RIDVectorLock() + , m_RIDListLock() { } @@ -827,7 +827,7 @@ CRendezvousQueue::~CRendezvousQueue() void CRendezvousQueue::insert( const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const steady_clock::time_point& ttl) { - ScopedLock vg(m_RIDVectorLock); + ScopedLock vg(m_RIDListLock); CRL r; r.m_iID = id; @@ -843,7 +843,7 @@ void CRendezvousQueue::insert( void CRendezvousQueue::remove(const SRTSOCKET &id) { - ScopedLock lkv (m_RIDVectorLock); + ScopedLock lkv (m_RIDListLock); for (list::iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { @@ -855,12 +855,12 @@ void CRendezvousQueue::remove(const SRTSOCKET &id) } } -CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) +CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) const { - ScopedLock vg(m_RIDVectorLock); + ScopedLock vg(m_RIDListLock); // TODO: optimize search - for (list::iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) + for (list::const_iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { if (i->m_PeerAddr == addr && ((w_id == 0) || (w_id == i->m_iID))) { @@ -915,7 +915,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con #endif { - ScopedLock vg(m_RIDVectorLock); + ScopedLock vg(m_RIDListLock); if (m_lRendezvousID.empty()) return; @@ -1004,7 +1004,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con } // The call to completeBrokenConnectionDependencies() cannot happen here - // under the lock of m_RIDVectorLock as it risks a deadlock. Collect it + // under the lock of m_RIDListLock as it risks a deadlock. Collect it // to update later. LinkStatusInfo fi = {i->m_pUDT, i->m_iID, ccerror, i->m_PeerAddr, -1}; ufailed.push_back(fi); @@ -1026,7 +1026,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con { IF_HEAVY_LOGGING(++debug_nupd); - // Collect them so that they can be updated out of m_RIDVectorLock. + // Collect them so that they can be updated out of m_RIDListLock. LinkStatusInfo fi = { i->m_pUDT, i->m_iID, SRT_SUCCESS, i->m_PeerAddr, -1}; uprocess.push_back(fi); // NOTE: safe loop, the incrementation was done before the loop body, @@ -1117,7 +1117,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con { // Now, additionally for every failed link reset the TTL so that // they are set expired right now. - ScopedLock vg(m_RIDVectorLock); + ScopedLock vg(m_RIDListLock); for (list::iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { if (find_if(ufailed.begin(), ufailed.end(), LinkStatusInfo::HasID(i->m_iID)) != ufailed.end()) diff --git a/srtcore/queue.h b/srtcore/queue.h index 2d27c67b9..d59877983 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -320,32 +320,53 @@ class CHash CHash& operator=(const CHash&); }; +/// @brief A queue of sockets pending for connection. +/// It can be either a caller socket in a non-blocking mode +/// (the connection has to be handled in background), +/// or a socket in rendezvous connection mode. class CRendezvousQueue { public: - CRendezvousQueue(); - ~CRendezvousQueue(); + CRendezvousQueue(); + ~CRendezvousQueue(); public: - void insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, - const srt::sync::steady_clock::time_point &ttl); - - void remove(const SRTSOCKET& id); - CUDT* retrieve(const sockaddr_any& addr, SRTSOCKET& id); - - void updateConnStatus(EReadStatus rst, EConnectStatus, const CPacket& response); + /// @brief Insert a new socket pending for connection (non-blocking caller or rendezvous). + /// @param id socket ID. + /// @param u pointer to a corresponding CUDT instance. + /// @param addr remote address to connect to. + /// @param ttl timepoint for connection attempt to expire. + void insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, + const srt::sync::steady_clock::time_point &ttl); + + /// @brief Remove a socket from the connection pending list. + /// @param id socket ID. + void remove(const SRTSOCKET& id); + + /// @brief Locate a socket in the connection pending queue. + /// @param addr source address of the packet received over UDP (peer address). + /// @param id socket ID. + /// @return a pointer to CUDT instance retrieved, or NULL if nothing was found. + CUDT* retrieve(const sockaddr_any& addr, SRTSOCKET& id) const; + + /// @brief Update status of connections in the pending queue. + /// Stop connecting if TTL expires. Resend handshake request every 250 ms if no response from the peer. + /// @param rst result of reading from a UDP socket: received packet / nothin read / read error. + /// @param cst target status for pending connection: reject or proceed. + /// @param response packet received from the UDP socket. + void updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& response); private: struct CRL { - SRTSOCKET m_iID; // UDT socket ID (self) - CUDT* m_pUDT; // UDT instance - sockaddr_any m_PeerAddr;// UDT sonnection peer address + SRTSOCKET m_iID; // SRT socket ID (self) + CUDT* m_pUDT; // CUDT instance + sockaddr_any m_PeerAddr;// SRT sonnection peer address srt::sync::steady_clock::time_point m_tsTTL; // the time that this request expires }; std::list m_lRendezvousID; // The sockets currently in rendezvous mode - srt::sync::Mutex m_RIDVectorLock; + mutable srt::sync::Mutex m_RIDListLock; }; class CSndQueue From 917a71513e3d90e7c2c339c7a63f8f38b7af6e16 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 11 May 2021 15:23:52 +0200 Subject: [PATCH 004/124] [core] Added CRendezvousQueue::qualifyToHandle. Now TTL of a socket pending for connection is checked on every update iteration -> more precise connection timeout. --- srtcore/queue.cpp | 276 +++++++++++++++++++--------------------------- srtcore/queue.h | 36 +++++- 2 files changed, 145 insertions(+), 167 deletions(-) diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 2de1515dd..c2aa8d40d 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -885,168 +885,22 @@ CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) cons return NULL; } -struct LinkStatusInfo +void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket &pktIn) { - CUDT* u; - SRTSOCKET id; - int errorcode; - sockaddr_any peeraddr; - int token; + vector toRemove, toProcess; - struct HasID - { - SRTSOCKET id; - HasID(SRTSOCKET p): id(p) {} - bool operator()(const LinkStatusInfo& i) - { - return i.id == id; - } - }; -}; - -void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket &response) -{ - vector ufailed, uprocess; - -#if ENABLE_HEAVY_LOGGING - int debug_nupd = 0; - int debug_nrun = 0; - int debug_nfail = 0; -#endif - - { - ScopedLock vg(m_RIDListLock); - - if (m_lRendezvousID.empty()) - return; - - HLOGC(cnlog.Debug, - log << "updateConnStatus: updating after getting pkt id=" << response.m_iID - << " status: " << ConnectStatusStr(cst)); - - for (list::iterator i = m_lRendezvousID.begin(), i_next = i; i != m_lRendezvousID.end(); i = i_next) - { - ++i_next; - // NOTE: This is a SAFE LOOP. - // Incrementation will be done at the end, after the processing did not - // REMOVE the currently processed element. When the element was removed, - // the iterator value for the next iteration will be taken from erase()'s result. - - // RST_AGAIN happens in case when the last attempt to read a packet from the UDP - // socket has read nothing. In this case it would be a repeated update, while - // still waiting for a response from the peer. When we have any other state here - // (most expectably CONN_CONTINUE or CONN_RENDEZVOUS, which means that a packet has - // just arrived in this iteration), do the update immetiately (in SRT this also - // involves additional incoming data interpretation, which wasn't the case in UDT). - - // Use "slow" cyclic responding in case when - // - RST_AGAIN (no packet was received for whichever socket) - // - a packet was received, but not for THIS socket - if (rst == RST_AGAIN || i->m_iID != response.m_iID) - { - // If no packet has been received from the peer, - // avoid sending too many requests, at most 1 request per 250ms - const steady_clock::time_point then = i->m_pUDT->m_tsLastReqTime; - const steady_clock::time_point now = steady_clock::now(); - const steady_clock::duration timeout_250ms = milliseconds_from(250); - const bool now_is_time = (now - then) > timeout_250ms; - HLOGC(cnlog.Debug, - log << "RID:@" << i->m_iID << " then=" << FormatTime(then) - << " now=" << FormatTime(now) << " passed=" << count_microseconds(now - then) - << "<=> 250000 -- now's " << (now_is_time ? "" : "NOT ") << "the time"); - - if (!now_is_time) - continue; - } - - HLOGC(cnlog.Debug, log << "RID:@" << i->m_iID << " cst=" << ConnectStatusStr(cst) << " -- sending update NOW."); - -#if ENABLE_HEAVY_LOGGING - ++debug_nrun; -#endif - - // XXX This looks like a loop that rolls in infinity without any sleeps - // inside and makes it once per about 50 calls send a hs conclusion - // for a randomly sampled rendezvous ID of a socket out of the list. - // Ok, probably the rendezvous ID should be just one so not much to - // sample from, but if so, why the container? - // - // This must be somehow fixed! - // - // Maybe the time should be simply checked once and the whole loop not - // done when "it's not the time"? - const steady_clock::time_point now = steady_clock::now(); - if (now >= i->m_tsTTL) - { - HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID - << " removed - EXPIRED (" - // The "enforced on FAILURE" is below when processAsyncConnectRequest failed. - << (is_zero(i->m_tsTTL) ? "enforced on FAILURE" : "passed TTL") - << "). WILL REMOVE from queue"); - - // Set appropriate error information, but do not update yet. - // Exit the lock first. Collect objects to update them later. - int ccerror = SRT_ECONNREJ; - if (i->m_pUDT->m_RejectReason == SRT_REJ_UNKNOWN) - { - if (!is_zero(i->m_tsTTL)) - { - // Timer expired, set TIMEOUT forcefully - i->m_pUDT->m_RejectReason = SRT_REJ_TIMEOUT; - ccerror = SRT_ENOSERVER; - } - else - { - // In case of unknown reason, rejection should at least - // suggest error on the peer - i->m_pUDT->m_RejectReason = SRT_REJ_PEER; - } - } - - // The call to completeBrokenConnectionDependencies() cannot happen here - // under the lock of m_RIDListLock as it risks a deadlock. Collect it - // to update later. - LinkStatusInfo fi = {i->m_pUDT, i->m_iID, ccerror, i->m_PeerAddr, -1}; - ufailed.push_back(fi); - - // i_next was preincremented, but this is guaranteed to point to - // the element next to erased one. - i_next = m_lRendezvousID.erase(i); - continue; - } - else - { - HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID << " still active (remaining " - << std::fixed << (count_microseconds(i->m_tsTTL - now)/1000000.0) << "s of TTL)..."); - } - - // This queue is used only in case of Async mode (rendezvous or caller-listener). - // Synchronous connection requests are handled in startConnect() completely. - if (!i->m_pUDT->m_config.bSynRecving) - { - IF_HEAVY_LOGGING(++debug_nupd); - - // Collect them so that they can be updated out of m_RIDListLock. - LinkStatusInfo fi = { i->m_pUDT, i->m_iID, SRT_SUCCESS, i->m_PeerAddr, -1}; - uprocess.push_back(fi); - // NOTE: safe loop, the incrementation was done before the loop body, - // so the `i' node can be safely deleted. Just the body must end here. - continue; - } - else - { - HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID << " deemed SYNCHRONOUS, NOT UPDATING"); - } - } - - } + // If no socket were qualified for further handling, finish here. + // Otherwise toRemove and toProcess contain items to handle. + if (!qualifyToHandle(rst, cst, pktIn.m_iID, toRemove, toProcess)) + return; // [[using locked()]]; - HLOGC(cnlog.Debug, log << "updateConnStatus: collected " << uprocess.size() << " for processing, " - << ufailed.size() << " to close"); + HLOGC(cnlog.Debug, log << "updateConnStatus: collected " << toProcess.size() << " for processing, " + << toRemove.size() << " to close"); - for (vector::iterator i = uprocess.begin(); i != uprocess.end(); ++i) + // Repeat (resend) connection request. + for (vector::iterator i = toProcess.begin(); i != toProcess.end(); ++i) { // IMPORTANT INFORMATION concerning changes towards UDT legacy. // In the UDT code there was no attempt to interpret any incoming data. @@ -1054,7 +908,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con // m_ConnRes field, and m_ConnReq field was considered at this time accordingly updated. // Therefore this procedure did only one thing: craft a new handshake packet and send it. // In SRT this may also interpret extra data (extensions in case when Agent is Responder) - // and the `response` packet may sometimes contain no data. Therefore the passed `rst` + // and the `pktIn` packet may sometimes contain no data. Therefore the passed `rst` // must be checked to distinguish the call by periodic update (RST_AGAIN) from a call // due to have received the packet (RST_OK). // @@ -1065,7 +919,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con EReadStatus read_st = rst; EConnectStatus conn_st = cst; - if (i->id != response.m_iID) + if (i->id != pktIn.m_iID) { read_st = RST_AGAIN; conn_st = CONN_AGAIN; @@ -1073,15 +927,14 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con HLOGC(cnlog.Debug, log << "updateConnStatus: processing async conn for @" << i->id << " FROM " << i->peeraddr.str()); - if (!i->u->processAsyncConnectRequest(read_st, conn_st, response, i->peeraddr)) + if (!i->u->processAsyncConnectRequest(read_st, conn_st, pktIn, i->peeraddr)) { // cst == CONN_REJECT can only be result of worker_ProcessAddressedPacket and // its already set in this case. LinkStatusInfo fi = *i; fi.errorcode = SRT_ECONNREJ; - ufailed.push_back(fi); + toRemove.push_back(fi); i->u->sendCtrl(UMSG_SHUTDOWN); - IF_HEAVY_LOGGING(++debug_nfail); } } @@ -1092,7 +945,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con // they are moved to ClosedSockets and it is believed that this function will // not be held on mutexes that long. - for (vector::iterator i = ufailed.begin(); i != ufailed.end(); ++i) + for (vector::iterator i = toRemove.begin(); i != toRemove.end(); ++i) { HLOGC(cnlog.Debug, log << "updateConnStatus: COMPLETING dep objects update on failed @" << i->id); /* @@ -1120,17 +973,110 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con ScopedLock vg(m_RIDListLock); for (list::iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { - if (find_if(ufailed.begin(), ufailed.end(), LinkStatusInfo::HasID(i->m_iID)) != ufailed.end()) + if (find_if(toRemove.begin(), toRemove.end(), LinkStatusInfo::HasID(i->m_iID)) != toRemove.end()) { LOGC(cnlog.Error, log << "updateConnStatus: processAsyncConnectRequest FAILED on @" << i->m_iID << ". Setting TTL as EXPIRED."); i->m_tsTTL = steady_clock::time_point(); // Make it expire right now, will be picked up at the next iteration } } } +} + +bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_ATR_UNUSED, + int iDstSockID, vector& toRemove, vector& toProcess) +{ + ScopedLock vg(m_RIDListLock); + + if (m_lRendezvousID.empty()) + return false; // nothing to process. HLOGC(cnlog.Debug, - log << "updateConnStatus: " << debug_nupd << "/" << debug_nrun << " sockets updated (" - << (debug_nrun - debug_nupd) << " useless). REMOVED " << debug_nfail << " sockets."); + log << "updateConnStatus: updating after getting pkt with DST socket ID @" << iDstSockID + << " status: " << ConnectStatusStr(cst)); + + for (list::iterator i = m_lRendezvousID.begin(), i_next = i; i != m_lRendezvousID.end(); i = i_next) + { + // Safe iterator to the next element. If the current element is erased, the iterator is updated again. + ++i_next; + + const steady_clock::time_point tsNow = steady_clock::now(); + + if (tsNow >= i->m_tsTTL) + { + HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID + << " removed - EXPIRED (" + // The "enforced on FAILURE" is below when processAsyncConnectRequest failed. + << (is_zero(i->m_tsTTL) ? "enforced on FAILURE" : "passed TTL") + << "). WILL REMOVE from queue."); + + // Set appropriate error information, but do not update yet. + // Exit the lock first. Collect objects to update them later. + int ccerror = SRT_ECONNREJ; + if (i->m_pUDT->m_RejectReason == SRT_REJ_UNKNOWN) + { + if (!is_zero(i->m_tsTTL)) + { + // Timer expired, set TIMEOUT forcefully + i->m_pUDT->m_RejectReason = SRT_REJ_TIMEOUT; + ccerror = SRT_ENOSERVER; + } + else + { + // In case of unknown reason, rejection should at least + // suggest error on the peer + i->m_pUDT->m_RejectReason = SRT_REJ_PEER; + } + } + + // The call to completeBrokenConnectionDependencies() cannot happen here + // under the lock of m_RIDListLock as it risks a deadlock. + // Collect in 'toRemove' to update later. + LinkStatusInfo fi = { i->m_pUDT, i->m_iID, ccerror, i->m_PeerAddr, -1 }; + toRemove.push_back(fi); + + // i_next was preincremented, but this is guaranteed to point to + // the element next to erased one. + i_next = m_lRendezvousID.erase(i); + continue; + } + else + { + HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID << " still active (remaining " + << std::fixed << (count_microseconds(i->m_tsTTL - tsNow) / 1000000.0) << "s of TTL)..."); + } + + const steady_clock::time_point tsLastReq = i->m_pUDT->m_tsLastReqTime; + const steady_clock::time_point tsRepeat = tsLastReq + milliseconds_from(250); // Repeat connection request (send HS). + + // A connection request is repeated every 250 ms if there was no response from the peer: + // - RST_AGAIN means no packet was received over UDP. + // - a packet was received, but not for THIS socket. + if ((rst == RST_AGAIN || i->m_iID != iDstSockID) && tsNow <= tsRepeat) + { + HLOGC(cnlog.Debug, + log << "RID:@" << i->m_iID << std::fixed << count_microseconds(tsNow - tsLastReq) / 1000.0 + << " ms passed since last connection request."); + + continue; + } + + HLOGC(cnlog.Debug, log << "RID:@" << i->m_iID << " cst=" << ConnectStatusStr(cst) << " -- repeating connection request."); + + // This queue is used only in case of Async mode (rendezvous or caller-listener). + // Synchronous connection requests are handled in startConnect() completely. + if (!i->m_pUDT->m_config.bSynRecving) + { + // Collect them so that they can be updated out of m_RIDListLock. + LinkStatusInfo fi = { i->m_pUDT, i->m_iID, SRT_SUCCESS, i->m_PeerAddr, -1 }; + toProcess.push_back(fi); + } + else + { + HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID << " is SYNCHRONOUS, NOT UPDATING"); + } + } + + return !toRemove.empty() || !toProcess.empty(); } // diff --git a/srtcore/queue.h b/srtcore/queue.h index d59877983..9c0affd5e 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -353,8 +353,40 @@ class CRendezvousQueue /// Stop connecting if TTL expires. Resend handshake request every 250 ms if no response from the peer. /// @param rst result of reading from a UDP socket: received packet / nothin read / read error. /// @param cst target status for pending connection: reject or proceed. - /// @param response packet received from the UDP socket. - void updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& response); + /// @param pktIn packet received from the UDP socket. + void updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn); + +private: + struct LinkStatusInfo + { + CUDT* u; + SRTSOCKET id; + int errorcode; + sockaddr_any peeraddr; + int token; + + struct HasID + { + SRTSOCKET id; + HasID(SRTSOCKET p) : id(p) {} + bool operator()(const LinkStatusInfo& i) + { + return i.id == id; + } + }; + }; + + /// @brief Qualify pending connections: + /// - Sockets with expired TTL go to the 'to_remove' list and removed from the queue straight away. + /// - If HS request is to be resent (resend 250 ms if no response from the peer) go to the 'to_process' list. + /// + /// @param rst result of reading from a UDP socket: received packet / nothin read / read error. + /// @param cst target status for pending connection: reject or proceed. + /// @param iDstSockID destination socket ID of the received packet. + /// @param[in,out] toRemove stores sockets with expired TTL. + /// @param[in,out] toProcess stores sockets which should repeat (resend) HS connection request. + bool qualifyToHandle(EReadStatus rst, EConnectStatus cst, int iDstSockID, + std::vector& toRemove, std::vector& toProcess); private: struct CRL From 87746453edcd37f2ae1987cfd052ca8f447c8738 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 11 May 2021 15:25:16 +0200 Subject: [PATCH 005/124] [tests] ConnectionTimeout.Nonblocking 500ms -> 300ms. Previously TTL was checked only every 250 ms, which resulted in a poor timeout precision. --- test/test_connection_timeout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_connection_timeout.cpp b/test/test_connection_timeout.cpp index 8b9bd31f8..241c5f1a8 100644 --- a/test/test_connection_timeout.cpp +++ b/test/test_connection_timeout.cpp @@ -100,7 +100,7 @@ TEST_F(TestConnectionTimeout, Nonblocking) { EXPECT_EQ(conn_timeout, 3000); // Set connection timeout to 500 ms to reduce the test execution time - const int connection_timeout_ms = 500; + const int connection_timeout_ms = 300; EXPECT_EQ(srt_setsockopt(client_sock, 0, SRTO_CONNTIMEO, &connection_timeout_ms, sizeof connection_timeout_ms), SRT_SUCCESS); const int yes = 1; From 0921da6cfd6e7c0f88e0a0400f05ded660af1e07 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 21 Apr 2021 16:24:13 +0200 Subject: [PATCH 006/124] [core] Fix DriftTracer: take RTT into account --- srtcore/buffer.cpp | 3 +- srtcore/buffer.h | 1 + srtcore/core.cpp | 2 +- srtcore/tsbpd_time.cpp | 107 +++++++++++++++++++++++++++++++++++++++-- srtcore/tsbpd_time.h | 12 +++-- srtcore/utilities.h | 6 ++- 6 files changed, 121 insertions(+), 10 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index e2efcefff..b29aa9322 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -1833,10 +1833,11 @@ void CRcvBuffer::setRcvTsbPdMode(const steady_clock::time_point& timebase, const } bool CRcvBuffer::addRcvTsbPdDriftSample(uint32_t timestamp_us, + int rtt, steady_clock::duration& w_udrift, steady_clock::time_point& w_newtimebase) { - return m_tsbpd.addDriftSample(timestamp_us, w_udrift, w_newtimebase); + return m_tsbpd.addDriftSample(timestamp_us, rtt, w_udrift, w_newtimebase); } int CRcvBuffer::readMsg(char* data, int len) diff --git a/srtcore/buffer.h b/srtcore/buffer.h index d32e1d29e..7f7680b8d 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -414,6 +414,7 @@ class CRcvBuffer /// @param [out] w_udrift current drift value /// @param [out] w_newtimebase current TSBPD base time bool addRcvTsbPdDriftSample(uint32_t timestamp, + int rtt, duration& w_udrift, time_point& w_newtimebase); diff --git a/srtcore/core.cpp b/srtcore/core.cpp index efc866164..a1985379d 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8279,7 +8279,7 @@ void CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival steady_clock::duration udrift(0); steady_clock::time_point newtimebase; const bool drift_updated ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), - (udrift), (newtimebase)); + rtt, (udrift), (newtimebase)); #if ENABLE_EXPERIMENTAL_BONDING if (drift_updated && m_parent->m_GroupOf) { diff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp index 0fe07fb7c..8fedf82ea 100644 --- a/srtcore/tsbpd_time.cpp +++ b/srtcore/tsbpd_time.cpp @@ -19,17 +19,110 @@ using namespace srt::sync; namespace srt { +#if SRT_DEBUG_TRACE_DRIFT +class drift_logger +{ + using steady_clock = srt::sync::steady_clock; + +public: + drift_logger() {} + + ~drift_logger() + { + ScopedLock lck(m_mtx); + m_fout.close(); + } + + void trace(unsigned ackack_timestamp, + int rtt_us, + int64_t drift_sample, + int64_t drift, + int64_t overdrift, + const std::chrono::steady_clock::time_point& tsbpd_base) + { + using namespace srt::sync; + ScopedLock lck(m_mtx); + create_file(); + + // std::string str_tnow = srt::sync::FormatTime(steady_clock::now()); + // str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [STDY]' part + + std::string str_tbase = srt::sync::FormatTime(tsbpd_base); + str_tbase.resize(str_tbase.size() - 7); // remove trailing ' [STDY]' part + + // m_fout << str_tnow << ","; + m_fout << count_microseconds(steady_clock::now() - m_start_time) << ","; + m_fout << ackack_timestamp << ","; + m_fout << rtt_us << ","; + m_fout << drift_sample << ","; + m_fout << drift << ","; + m_fout << overdrift << ","; + m_fout << str_tbase << "\n"; + m_fout.flush(); + } + +private: + void print_header() + { + m_fout << "usElapsedStd,usAckAckTimestampStd,"; + m_fout << "usRTTStd,usDriftSampleStd,usDriftStd,usOverdriftStd,TSBPDBase\n"; + } + + void create_file() + { + if (m_fout.is_open()) + return; + + m_start_time = srt::sync::steady_clock::now(); + std::string str_tnow = srt::sync::FormatTimeSys(m_start_time); + str_tnow.resize(str_tnow.size() - 7); // remove trailing ' [SYST]' part + while (str_tnow.find(':') != std::string::npos) + { + str_tnow.replace(str_tnow.find(':'), 1, 1, '_'); + } + const std::string fname = "drift_trace_" + str_tnow + ".csv"; + m_fout.open(fname, std::ofstream::out); + if (!m_fout) + std::cerr << "IPE: Failed to open " << fname << "!!!\n"; + + print_header(); + } + +private: + srt::sync::Mutex m_mtx; + std::ofstream m_fout; + srt::sync::steady_clock::time_point m_start_time; +}; + +drift_logger g_drift_logger; + +#endif // SRT_DEBUG_TRACE_DRIFT + bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, + int usRTTSample, steady_clock::duration& w_udrift, steady_clock::time_point& w_newtimebase) { if (!m_bTsbPdMode) return false; - + const time_point tsNow = steady_clock::now(); ScopedLock lck(m_mtxRW); - const steady_clock::duration tdDrift = tsNow - getPktTsbPdBaseTime(usPktTimestamp); + + // Remember the first RTT sample measured. Ideally we need RTT0 - the one from the handshaking phase, + // because TSBPD base is initialized there. But HS-based RTT is not yet implemented. + // Take the first one assuming it is close to RTT0. + if (m_iFirstRTT == -1) + { + m_iFirstRTT = usRTTSample; + } + + // A change in network delay has to be taken into account. The only way to get some estimation of it + // is to estimate RTT change and assume that the change of the one way network delay is + // approximated by the half of the RTT change. + const duration tdRTTDelta = microseconds_from((usRTTSample - m_iFirstRTT) / 2); + const steady_clock::duration tdDrift = tsNow - getPktTsbPdBaseTime(usPktTimestamp) - tdRTTDelta; const bool updated = m_DriftTracer.update(count_microseconds(tdDrift)); @@ -53,6 +146,14 @@ bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, w_udrift = tdDrift; w_newtimebase = m_tsTsbPdTimeBase; +#if SRT_DEBUG_TRACE_DRIFT + g_drift_logger.trace(usPktTimestamp, + usRTTSample, + count_microseconds(tdDrift), + m_DriftTracer.drift(), + m_DriftTracer.overdrift(), + m_tsTsbPdTimeBase); +#endif return updated; } @@ -67,7 +168,7 @@ void CTsbpdTime::setTsbPdMode(const steady_clock::time_point& timebase, bool wra // // This function is called in the HSREQ reception handler only. m_tsTsbPdTimeBase = timebase; - m_tdTsbPdDelay = delay; + m_tdTsbPdDelay = delay; } void CTsbpdTime::applyGroupTime(const steady_clock::time_point& timebase, diff --git a/srtcore/tsbpd_time.h b/srtcore/tsbpd_time.h index 5dcc7ff3a..b6cb770f5 100644 --- a/srtcore/tsbpd_time.h +++ b/srtcore/tsbpd_time.h @@ -30,7 +30,8 @@ class CTsbpdTime public: CTsbpdTime() - : m_bTsbPdMode(false) + : m_iFirstRTT(-1) + , m_bTsbPdMode(false) , m_tdTsbPdDelay(0) , m_bTsbPdWrapCheck(false) { @@ -61,13 +62,17 @@ class CTsbpdTime /// @brief Add new drift sample from an ACK-ACKACK pair. /// ACKACK packets are sent immediately (except for UDP buffering). + /// Therefore their timestamp roughly corresponds to the time of sending + /// and can be used to estimate clock drift. /// /// @param [in] pktTimestamp Timestamp of the arrived ACKACK packet. + /// @param [in] usRTTSample RTT sample from an ACK-ACKACK pair. /// @param [out] w_udrift Current clock drift value. /// @param [out] w_newtimebase Current TSBPD base time. /// /// @return true if TSBPD base time has changed, false otherwise. bool addDriftSample(uint32_t pktTimestamp, + int usRTTSample, steady_clock::duration& w_udrift, steady_clock::time_point& w_newtimebase); @@ -116,8 +121,9 @@ class CTsbpdTime void getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift) const; private: - bool m_bTsbPdMode; //< Rreceiver buffering and TSBPD is active when true. - duration m_tdTsbPdDelay; //< Negotiated buffering delay. + int m_iFirstRTT; // First measured RTT sample. + bool m_bTsbPdMode; // Receiver buffering and TSBPD is active when true. + duration m_tdTsbPdDelay; // Negotiated buffering delay. /// @brief Local time base for TsbPd. /// @note m_tsTsbPdTimeBase is changed in the following cases: diff --git a/srtcore/utilities.h b/srtcore/utilities.h index f0ad80271..7d73c8567 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -791,11 +791,13 @@ class DriftTracer m_qDriftSum += driftval; ++m_uDriftSpan; + // I moved it here to calculate accumulated overdrift. + if (CLEAR_ON_UPDATE) + m_qOverdrift = 0; + if (m_uDriftSpan < MAX_SPAN) return false; - if (CLEAR_ON_UPDATE) - m_qOverdrift = 0; // Calculate the median of all drift values. // In most cases, the divisor should be == MAX_SPAN. From a32e975f2403c8b2335e7ab9e77f21291a7e2b3c Mon Sep 17 00:00:00 2001 From: Sergei Ignatov Date: Tue, 18 May 2021 18:57:51 +1000 Subject: [PATCH 007/124] [build] Update for Android build scripts (#2009) - Remove obsolete declares and scripts; - Allow to set build parameters (ndk root, api level, archs set, versions) from the command line; - Use C++11 version of sync module by default. --- docs/build/build-android.md | 24 ++-------- scripts/build-android/README.md | 2 - scripts/build-android/build-android | 69 ++++++++++++++++++++++++++++ scripts/build-android/mkall | 71 ----------------------------- scripts/build-android/mksrt | 24 ++++++++-- scripts/build-android/mkssl | 16 ++----- scripts/build-android/packjni | 38 --------------- scripts/build-android/prepare_build | 36 --------------- 8 files changed, 100 insertions(+), 180 deletions(-) create mode 100755 scripts/build-android/build-android delete mode 100755 scripts/build-android/mkall delete mode 100755 scripts/build-android/packjni delete mode 100644 scripts/build-android/prepare_build diff --git a/docs/build/build-android.md b/docs/build/build-android.md index f2dec839e..af1685a61 100644 --- a/docs/build/build-android.md +++ b/docs/build/build-android.md @@ -2,31 +2,17 @@ **NOTE:** The scripts have been moved to [scripts/build-android](../../scripts/build-android/) folder. -## Establishing a Build Environment - -### Installing the Android NDK +## 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/) -Download the NDK r19 or newer archive from the following site: -[Download the Android NDK on developer.android.com](https://developer.android.com/ndk/downloads/index.html) -To install the Android NDK, simply expand the archive in the folder where you want to install it. - -### OpenSSL - -Google removed openssl from Android 7+. You must build openssl libs by yourself. - -## Configure the NDK Path - -Edit the ```mkall``` script to configure NDK path. Set the ```NDK``` to the directory where the NDK is installed. - ## Build SRT for Android -Run ```/bin/bash mkall > build.log``` script. Libraries will be installed to ```./target-architecture/lib```. - -## Export SRT Libraries +Run ```./build-android -n /path/to/ndk```. E.g. ```./build-android -n /home/username/Android/Sdk/ndk/21.4.7075529``` -Run ```/bin/bash packjni``` to generate ```jniLibs``` archive for Android Studio. +[Include prebuilt native libraries](https://developer.android.com/studio/projects/gradle-external-native-builds#jniLibs) from ```prebuilt``` folder into Android Studio project. diff --git a/scripts/build-android/README.md b/scripts/build-android/README.md index d225ed022..85277f2a6 100644 --- a/scripts/build-android/README.md +++ b/scripts/build-android/README.md @@ -1,5 +1,3 @@ ## Scripts for building SRT for Android -**NOTE:** The scripts have been moved from `docs/Android/` folder. Updating the paths might be required. - See [Building SRT for Android](../../docs/build/build-android.md) for the instructions. diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android new file mode 100755 index 000000000..622f525d2 --- /dev/null +++ b/scripts/build-android/build-android @@ -0,0 +1,69 @@ +#!/bin/sh + +echo_help() +{ + echo "Usage: $0 [options...]" + echo " -n Specify NDK root path for the build." + echo " -a Select target API level." + echo " -t Select target architectures." + echo " Android supports the following architectures: armeabi armeabi-v7a arm64-v8a x86 x86_64." + echo " -o Select OpenSSL (1.1.1 series) version. E.g. 1.1.1h" + echo " -s Select a specific SRT tag. E.g. v1.4.3" + echo + echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/21.4.7075529 -a 28 -t \"armeabi-v7a arm64-v8a x86 x86_64\" -o 1.1.1h -s v1.4.3" + echo +} + +# Init optional command line vars +NDK_ROOT="" +API_LEVEL=28 +BUILD_TARGETS="armeabi armeabi-v7a arm64-v8a x86 x86_64" +OPENSSL_VERSION=1.1.1h +SRT_VERSION="" + +while getopts n:a:t:o:s: option +do + case "${option}" + in + n) NDK_ROOT=${OPTARG};; + a) API_LEVEL=${OPTARG};; + t) BUILD_TARGETS=${OPTARG};; + o) OPENSSL_VERSION=${OPTARG};; + s) SRT_VERSION=${OPTARG};; + *) twentytwo=${OPTARG};; + esac +done + +echo_help + +if [ -z "$NDK_ROOT" ] ; then + echo "NDK directory not set." + exit 128 +else + if [ ! -d "$NDK_ROOT" ]; then + echo "NDK directory does not exist: $NDK_ROOT" + exit 128 + fi +fi + +# Determine the path of the executing script +BASE_DIR=$(readlink -f $0 | xargs dirname) + +$BASE_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION + +if [ ! -d $BASE_DIR/srt ]; then + git clone https://github.com/Haivision/srt srt + if [ ! -z "$SRT_VERSION" ]; then + git -C $BASE_DIR/srt checkout $SRT_VERSION + fi +fi + +JNI_DIR=$BASE_DIR/prebuilt + +for build_target in $BUILD_TARGETS; do + git -C $BASE_DIR/srt clean -fd + $BASE_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/srt -i $BASE_DIR/$build_target + + mkdir -p $JNI_DIR/$build_target + cp $BASE_DIR/$build_target/lib/libsrt.so $JNI_DIR/$build_target/libsrt.so +done diff --git a/scripts/build-android/mkall b/scripts/build-android/mkall deleted file mode 100755 index dbfe386a3..000000000 --- a/scripts/build-android/mkall +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -NDK=/opt/android-ndk-r19c - -openssl_ver=1.1.1h -#srt_version=1.4.2 -#srt_branch=dev - -API_LEVEL=28 -# Determine the path of the executing script -BASE_DIR=$(readlink -f $0 | xargs dirname) - -#wget -N https://www.openssl.org/source/openssl-$openssl_ver.tar.gz - -if [ ! -d $BASE_DIR/srt ]; then - git clone https://github.com/Haivision/srt srt -# git -C $BASE_DIR/srt checkout v${srt_version} -# git -C $BASE_DIR/srt checkout -b $srt_branch origin/$srt_branch -fi - -# Clang, binutils, the sysroot, and other toolchain pieces are all installed to $NDK/toolchains/llvm/prebuilt/ -toolchain=$NDK/toolchains/llvm/prebuilt/linux-x86_64 - -# Cross-compiler tool prefix -declare -A target_hosts -target_hosts=( - [armeabi]=arm-linux-androideabi - [arm]=arm-linux-androideabi - [arm64]=aarch64-linux-android - [x86]=i686-linux-android - [x86_64]=x86_64-linux-android -) - -# Cross-compiler prefix for -clang and -clang++ has api version -declare -A target_api -target_api=( - [armeabi]=armv5te-linux-androideabi16 - [arm]=armv7a-linux-androideabi16 - [arm64]=aarch64-linux-android21 - [x86]=i686-linux-android16 - [x86_64]=x86_64-linux-android21 -) - -declare -A sysroots -sysroots=( - [armeabi]=$BASE_DIR/armeabi - [arm]=$BASE_DIR/armeabi-v7a - [arm64]=$BASE_DIR/arm64-v8a - [x86]=$BASE_DIR/x86 - [x86_64]=$BASE_DIR/x86_64 -) - -declare -A archabi -archabi=( - [armeabi]=armeabi - [arm]=armeabi-v7a - [arm64]=arm64-v8a - [x86]=x86 - [x86_64]=x86_64 -) - -$BASE_DIR/mkssl -n $NDK -o $openssl_ver -a $API_LEVEL - -for arch in armeabi arm arm64 x86 x86_64; do - #rm -rf $BASE_DIR/openssl-$openssl_ver - #tar xf $BASE_DIR/openssl-$openssl_ver.tar.gz - #$BASE_DIR/mkssl -t $toolchain -h ${target_hosts[$arch]} -a ${target_api[$arch]} -s $BASE_DIR/openssl-$openssl_ver -i ${sysroots[$arch]} - - git -C $BASE_DIR/srt clean -fd - $BASE_DIR/mksrt -t $toolchain -h ${target_hosts[$arch]} -a ${target_api[$arch]} -s $BASE_DIR/srt -i ${sysroots[$arch]} -b ${archabi[$arch]} -n $NDK -l $API_LEVEL -done diff --git a/scripts/build-android/mksrt b/scripts/build-android/mksrt index 4d45755a4..2af96a7aa 100755 --- a/scripts/build-android/mksrt +++ b/scripts/build-android/mksrt @@ -1,7 +1,25 @@ -#!/bin/bash +#!/bin/sh -source prepare_build +while getopts s:i:t:n:a: option +do + case "${option}" + in + s) SRC_DIR=${OPTARG};; + i) INSTALL_DIR=${OPTARG};; + t) ARCH_ABI=${OPTARG};; + n) NDK_ROOT=${OPTARG};; + a) API_LEVEL=${OPTARG};; + *) twentytwo=${OPTARG};; + esac +done -./configure --use-openssl-pc=OFF --CMAKE_PREFIX_PATH=$install_dir --CMAKE_INSTALL_PREFIX=$install_dir --CMAKE_SYSTEM_NAME=Android --CMAKE_SYSTEM_VERSION=$api_lev --CMAKE_ANDROID_NDK=$NDK_HOME --CMAKE_ANDROID_ARCH_ABI=$arch_abi + +cd $SRC_DIR +./configure --use-openssl-pc=OFF --OPENSSL_USE_STATIC_LIBS=true \ +--CMAKE_PREFIX_PATH=$INSTALL_DIR --CMAKE_INSTALL_PREFIX=$INSTALL_DIR --CMAKE_ANDROID_NDK=$NDK_ROOT \ +--CMAKE_SYSTEM_NAME=Android --CMAKE_SYSTEM_VERSION=$API_LEVEL --CMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \ +--CMAKE_C_FLAGS="-fPIC" --CMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \ +--enable-c++11 --enable-stdcxx-sync \ +--enable-debug=2 --enable-logging=0 --enable-heavy-logging=0 --enable-apps=0 make make install diff --git a/scripts/build-android/mkssl b/scripts/build-android/mkssl index 726e4bb05..d0305fab7 100755 --- a/scripts/build-android/mkssl +++ b/scripts/build-android/mkssl @@ -1,27 +1,21 @@ #!/bin/sh -while getopts n:o:a: option +while getopts n:o:a:t: option do case "${option}" in - n) ndk_home=${OPTARG};; - o) ssl_ver=${OPTARG};; - a) api_lev=${OPTARG};; + n) ANDROID_NDK=${OPTARG};; + o) OPENSSL_VERSION=${OPTARG};; + a) API_LEVEL=${OPTARG};; + t) BUILD_TARGETS=${OPTARG};; *) twentytwo=${OPTARG};; esac done -ANDROID_NDK=$ndk_home -OPENSSL_VERSION=$ssl_ver - -API_LEVEL=$api_lev - BUILD_DIR=/tmp/openssl_android_build OUT_DIR=$(pwd) -BUILD_TARGETS="armeabi armeabi-v7a arm64-v8a x86 x86_64" - if [ ! -d openssl-${OPENSSL_VERSION} ] then if [ ! -f openssl-${OPENSSL_VERSION}.tar.gz ] diff --git a/scripts/build-android/packjni b/scripts/build-android/packjni deleted file mode 100755 index 80e19ac80..000000000 --- a/scripts/build-android/packjni +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -BASE_DIR=$(readlink -f $0 | xargs dirname) - -declare -A sysroots -sysroots=( - [armeabi]=$BASE_DIR/armeabi - [arm]=$BASE_DIR/armeabi-v7a - [arm64]=$BASE_DIR/arm64-v8a - [x86]=$BASE_DIR/x86 - [x86_64]=$BASE_DIR/x86_64 -) - -srt_version=1.4.2 -jni_dir=$BASE_DIR/jniLibs - -declare -A jnilibs -jnilibs=( - [armeabi=$jni_dir/armeabi - [arm]=$jni_dir/armeabi-v7a - [arm64]=$jni_dir/arm64-v8a - [x86]=$jni_dir/x86 - [x86_64]=$jni_dir/x86_64 -) - -jni_dir=$BASE_DIR/jniLibs - -# Android < 6.0 has an issue with loading versioned libraries -# The issue is because of library so-name libsrt.so.1 - -for arch in armeabi arm arm64 x86 x86_64; do - mkdir -p ${jnilibs[$arch]} - cp ${sysroots[$arch]}/lib/libsrt.so ${jnilibs[$arch]}/libsrt.so - /usr/local/bin/patchelf --set-soname libsrt.so ${jnilibs[$arch]}/libsrt.so - objdump -p ${jnilibs[$arch]}/libsrt.so | grep libsrt.so -done - -zip -r libsrt_$(date +%Y-%m-%d).zip jniLibs diff --git a/scripts/build-android/prepare_build b/scripts/build-android/prepare_build deleted file mode 100644 index c0b2cd987..000000000 --- a/scripts/build-android/prepare_build +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -while getopts t:h:a:s:i:b:n:l: option -do - case "${option}" - in - t) toolchain_dir=${OPTARG};; - h) target_host=${OPTARG};; - a) target_host_api=${OPTARG};; - s) src_dir=${OPTARG};; - i) install_dir=$OPTARG;; - b) arch_abi=${OPTARG};; - n) NDK_HOME=${OPTARG};; - l) api_lev=${OPTARG};; - *) twentytwo=${OPTARG};; - esac -done - -# Add toolchain to the search path. -export PATH=$PATH:$toolchain_dir/bin - -# Tell configure what tools to use. -export AR=$target_host-ar -export AS=$target_host-as -export LD=$target_host-ld -export STRIP=$target_host-strip - -# Tell configure which android api to use. -export CC=$target_host_api-clang -export CXX=$target_host_api-clang++ - -# Tell configure what flags Android requires. -export CFLAGS="-fPIE -fPIC" -export LDFLAGS="-pie" - -cd $src_dir From 345bab754c0a7580bde4a975a2455e36c958628d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Ma=C5=82ecki?= Date: Tue, 18 May 2021 10:21:35 +0200 Subject: [PATCH 008/124] [core] Fixed version rejection for HSv4 caller --- srtcore/core.cpp | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index a1985379d..f82f7875a 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -2400,7 +2400,17 @@ bool CUDT::interpretSrtHandshake(const CHandShake& hs, } if (hs.m_iVersion < HS_VERSION_SRT1) + { + if (m_config.uMinimumPeerSrtVersion && m_config.uMinimumPeerSrtVersion >= SRT_VERSION_FEAT_HSv5) + { + m_RejectReason = SRT_REJ_VERSION; + // This means that a version with minimum 1.3.0 that features HSv5 is required, + // hence all HSv4 clients should be rejected. + LOGP(cnlog.Error, "interpretSrtHandshake: minimum peer version 1.3.0 (HSv5 only), rejecting HSv4 client"); + return false; + } return true; // do nothing + } // Anyway, check if the handshake contains any extra data. if (hspkt.getLength() <= CHandShake::m_iContentSize) @@ -10618,16 +10628,31 @@ int CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) // (or the above procedure failed) if (result == -1) { - HLOGC(cnlog.Debug, - log << CONID() << "processConnectRequest: sending ABNORMAL handshake info req=" - << RequestTypeStr(hs.m_iReqType)); - size_t size = CHandShake::m_iContentSize; - hs.store_to((packet.m_pcData), (size)); - packet.setLength(size); - packet.m_iID = id; - setPacketTS(packet, steady_clock::now()); - HLOGC(cnlog.Debug, log << "processConnectRequest: SENDING HS (a): " << hs.show()); - m_pSndQueue->sendto(addr, packet); + if (hs.m_iVersion < HS_VERSION_SRT1) + { + HLOGC(cnlog.Debug, log << CONID() << "processConnectRequest: HSv4 caller, sending SHUTDOWN after rejection with " + << RequestTypeStr(hs.m_iReqType)); + // The HSv4 clients do not interpret the error handshake response correctly. + // In order to really disallow them to connect there's needed the shutdown response. + CPacket rsp; + setPacketTS((rsp), steady_clock::now()); + rsp.pack(UMSG_SHUTDOWN); + rsp.m_iID = m_PeerID; + m_pSndQueue->sendto(addr, rsp); + } + else + { + HLOGC(cnlog.Debug, + log << CONID() << "processConnectRequest: sending ABNORMAL handshake info req=" + << RequestTypeStr(hs.m_iReqType)); + size_t size = CHandShake::m_iContentSize; + hs.store_to((packet.m_pcData), (size)); + packet.setLength(size); + packet.m_iID = id; + setPacketTS(packet, steady_clock::now()); + HLOGC(cnlog.Debug, log << "processConnectRequest: SENDING HS (a): " << hs.show()); + m_pSndQueue->sendto(addr, packet); + } } // new connection response should be sent in acceptAndRespond() // turn the socket writable if this is the first time when this was found out. From 7e5b3ee4d834522e1b65e0e0c475c89fda58a097 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 18 May 2021 11:49:33 +0200 Subject: [PATCH 009/124] [docs] Added buffer configuration guide (#1951) --- docs/API/configuration-guidelines.md | 110 +++++++++++++++++++++++++++ docs/README.md | 15 ++-- 2 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 docs/API/configuration-guidelines.md diff --git a/docs/API/configuration-guidelines.md b/docs/API/configuration-guidelines.md new file mode 100644 index 000000000..f0566d7d0 --- /dev/null +++ b/docs/API/configuration-guidelines.md @@ -0,0 +1,110 @@ +# 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 + +As already mentioned, the maximum allowed size of the receiver buffer is limited by the value of `SRTO_FC`. +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 +using the configured value of the `SRTO_MSS` option to estimate the maximum possible payload of a packet. + +The following function returns the buffer size in packets: + +```c++ +int getRbufSizePkts(int SRTO_RCVBUF, int SRTO_MSS, int SRTO_FC) +{ + // UDP header size is assumed to be 28 bytes + // 20 bytes IPv4 + 8 bytes of UDP + const int UDPHDR_SIZE = 28; + const in pkts = (rbuf_size / (SRTO_MSS - UDPHDR_SIZE)); + + 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 - 44` + +where + +- 44 is the size in bytes of an **IPv4** header: + - 20 bytes **IPv4** + - 8 bytes of UDP + - 16 bytes of SRT packet header. + +- `MSS` is the Maximum Segment Size (aka MTU); see `SRTO_MSS`. + +### 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, int SRTO_FC) +{ + const int UDPHDR_SIZE = 28; + const int targetPayloadBytes = (msLatency + msRTT / 2) * bpsRate / 1000 / 8; + const int targetNumPackets = targetPayloadBytes / bytesPayloadSize; + const int targetSizeValue = targetNumPackets * (SRTO_MSS - UDPHDR_SIZE); + return {targetNumPackets, targetSizeValue}; +} + +// Configuring + +const auto [fc, rcvbuf] = CalculateTargetRBufSize(msRTT, bpsRate, bytesPayloadSize, SRTO_RCVLATENCY, SRTO_MSS, SRTO_FC); + +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); +``` diff --git a/docs/README.md b/docs/README.md index 3e5ce72c1..55a632bcc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,13 +2,14 @@ ## 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 Statistics](API/statistics.md) | [API](API/) | [statistics.md](API/statistics.md) | How to use SRT socket and socket group statistics. | -| | | | | +| 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 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 From d9150eaa8a791b6cba712ea68290e0beabed489d Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Tue, 18 May 2021 23:05:50 +0800 Subject: [PATCH 010/124] [core] Fixed DROPREQ by TTL packet drop (#2003) The sequence range to drop in the sender's drop request was 1 packet wider than needed. --- srtcore/buffer.cpp | 10 +++++++++- srtcore/core.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index b29aa9322..d42a57577 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -523,6 +523,10 @@ int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time // by sequence number. Consider using some circular buffer. for (int i = 0; i < offset; ++i) p = p->m_pNext; +#if ENABLE_HEAVY_LOGGING + const int32_t first_seq = p->m_iSeqNo; + int32_t last_seq = p->m_iSeqNo; +#endif // Check if the block that is the next candidate to send (m_pCurrBlock pointing) is stale. @@ -546,6 +550,9 @@ int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time bool move = false; while (msgno == p->getMsgSeq()) { +#if ENABLE_HEAVY_LOGGING + last_seq = p->m_iSeqNo; +#endif if (p == m_pCurrBlock) move = true; p = p->m_pNext; @@ -555,7 +562,8 @@ int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time } HLOGC(qslog.Debug, - log << "CSndBuffer::readData: due to TTL exceeded, " << w_msglen << " messages to drop, up to " << msgno); + log << "CSndBuffer::readData: due to TTL exceeded, SEQ " << first_seq << " - " << last_seq << ", " + << w_msglen << " packets to drop, msgno=" << msgno); // If readData returns -1, then msgno_bitset is understood as a Message ID to drop. // This means that in this case it should be written by the message sequence value only diff --git a/srtcore/core.cpp b/srtcore/core.cpp index f82f7875a..a6dfb04cd 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8881,10 +8881,11 @@ int CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime { int32_t seqpair[2]; seqpair[0] = w_packet.m_iSeqNo; - seqpair[1] = CSeqNo::incseq(seqpair[0], msglen); + SRT_ASSERT(msglen >= 1); + seqpair[1] = CSeqNo::incseq(seqpair[0], msglen - 1); HLOGC(qrlog.Debug, log << "IPE: loss-reported packets not found in SndBuf - requesting DROP: " - << "msg=" << MSGNO_SEQ::unwrap(w_packet.m_iMsgNo) << " SEQ:" + << "msg=" << MSGNO_SEQ::unwrap(w_packet.m_iMsgNo) << " msglen=" << msglen << " SEQ:" << seqpair[0] << " - " << seqpair[1] << "(" << (-offset) << " packets)"); sendCtrl(UMSG_DROPREQ, &w_packet.m_iMsgNo, seqpair, sizeof(seqpair)); @@ -8892,7 +8893,7 @@ int CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime m_pSndLossList->removeUpTo(seqpair[1]); // skip all dropped packets - m_iSndCurrSeqNo = CSeqNo::maxseq(m_iSndCurrSeqNo, CSeqNo::incseq(seqpair[1])); + m_iSndCurrSeqNo = CSeqNo::maxseq(m_iSndCurrSeqNo, seqpair[1]); continue; } @@ -11288,4 +11289,3 @@ void CUDT::handleKeepalive(const char* /*data*/, size_t /*size*/) } #endif } - From 189b1710a08c543aaae20b6d88c76e60afbffc05 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 18 May 2021 14:26:00 +0200 Subject: [PATCH 011/124] [build] Fixed __MINGW32__ macro usage. Previously a custom __MINGW__ preprocessor definition was used. It was defined in udt.h, and not included everywhere. --- srtcore/platform_sys.h | 2 +- srtcore/srt.h | 6 +++--- srtcore/srt_compat.h | 2 +- srtcore/sync.cpp | 2 +- srtcore/udt.h | 8 -------- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/srtcore/platform_sys.h b/srtcore/platform_sys.h index ed66e02bf..9fa2c7d32 100644 --- a/srtcore/platform_sys.h +++ b/srtcore/platform_sys.h @@ -30,7 +30,7 @@ #include #include -#ifndef __MINGW__ +#ifndef __MINGW32__ #include #endif diff --git a/srtcore/srt.h b/srtcore/srt.h index 92be107d2..60f3fc1e8 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -35,7 +35,7 @@ written by #ifdef _WIN32 - #ifndef __MINGW__ + #ifndef __MINGW32__ // Explicitly define 32-bit and 64-bit numbers typedef __int32 int32_t; typedef __int64 int64_t; @@ -56,7 +56,7 @@ written by #else #define SRT_API #endif - #else // __MINGW__ + #else // __MINGW32__ #define SRT_API #endif #else @@ -152,7 +152,7 @@ typedef int32_t SRTSOCKET; static const int32_t SRTGROUP_MASK = (1 << 30); #ifdef _WIN32 - #ifndef __MINGW__ + #ifndef __MINGW32__ typedef SOCKET SYSSOCKET; #else typedef int SYSSOCKET; diff --git a/srtcore/srt_compat.h b/srtcore/srt_compat.h index f7d072393..960c1b85a 100644 --- a/srtcore/srt_compat.h +++ b/srtcore/srt_compat.h @@ -22,7 +22,7 @@ written by #ifndef SRT_API #ifdef _WIN32 - #ifndef __MINGW__ + #ifndef __MINGW32__ #ifdef SRT_DYNAMIC #ifdef SRT_EXPORTS #define SRT_API __declspec(dllexport) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 7fb494256..c630f897d 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -227,7 +227,7 @@ bool srt::sync::CTimer::sleep_until(TimePoint tp) __asm__ volatile ("nop 0; nop 0; nop 0; nop 0; nop 0;"); #elif AMD64 __asm__ volatile ("nop; nop; nop; nop; nop;"); -#elif defined(_WIN32) && !defined(__MINGW__) +#elif defined(_WIN32) && !defined(__MINGW32__) __nop(); __nop(); __nop(); diff --git a/srtcore/udt.h b/srtcore/udt.h index 1bcc889ca..8d7d5eb87 100644 --- a/srtcore/udt.h +++ b/srtcore/udt.h @@ -82,13 +82,6 @@ modified by #define INCREMENT_THREAD_ITERATIONS() #endif -/* Obsolete way to define MINGW */ -#ifndef __MINGW__ -#if defined(__MINGW32__) || defined(__MINGW64__) -#define __MINGW__ 1 -#endif -#endif - #ifdef __cplusplus #include #include @@ -96,7 +89,6 @@ modified by #include #endif - //////////////////////////////////////////////////////////////////////////////// //if compiling on VC6.0 or pre-WindowsXP systems From 393a6c7041f6d883342a0bb6ca7c6d840f471229 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 12 May 2021 13:37:11 +0200 Subject: [PATCH 012/124] [core] Added srt::sync::genRandomInt(..) for a uniform way to get a random integer from the range. If C++11 is enabled, uniform_int_distribution and random_device are used. --- srtcore/api.cpp | 17 +--------- srtcore/channel.cpp | 8 +---- srtcore/congctl.cpp | 8 ++--- srtcore/core.h | 4 +-- srtcore/sync.cpp | 81 +++++++++++++++++++++++++++++++++++++++++++++ srtcore/sync.h | 12 +++++++ srtcore/utilities.h | 1 - test/test_sync.cpp | 21 ++++++++++++ 8 files changed, 120 insertions(+), 32 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 5bd307125..542832f77 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -194,22 +194,7 @@ m_bGCStatus(false), m_ClosedSockets() { // Socket ID MUST start from a random value - // Note. Don't use CTimer here, because s_UDTUnited is a static instance of CUDTUnited - // with dynamic initialization (calling this constructor), while CTimer has - // a static member s_ullCPUFrequency with dynamic initialization. - // The order of initialization is not guaranteed. - timeval t; - - gettimeofday(&t, 0); - srand((unsigned int)t.tv_usec); - - const double rand1_0 = double(rand())/RAND_MAX; - - // Motivation: in case when rand() returns the value equal to RAND_MAX, - // rand1_0 == 1, so the below formula will be - // 1 + (MAX_SOCKET_VAL-1) * 1 = 1 + MAX_SOCKET_VAL - 1 = MAX_SOCKET_VAL - // which is the highest allowed value for the socket. - m_SocketIDGenerator = 1 + int((MAX_SOCKET_VAL-1) * rand1_0); + m_SocketIDGenerator = genRandomInt(1, MAX_SOCKET_VAL); m_SocketIDGenerator_init = m_SocketIDGenerator; // XXX An unlikely exception thrown from the below calls diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 865eaaabc..f78689a3a 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -562,12 +562,6 @@ int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const if (!packet.isControl()) { - if (dcounter == 0) - { - timeval tv; - gettimeofday(&tv, 0); - srand(tv.tv_usec & 0xFFFF); - } ++dcounter; if (flwcounter) @@ -581,7 +575,7 @@ int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const if (dcounter > 8) { // Make a random number in the range between 8 and 24 - int rnd = rand() % 16 + SRT_TEST_FAKE_LOSS; + const int rnd = srt::sync::getRandomInt(8, 24); if (dcounter > rnd) { diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 0b00929b7..fdf9ddb0b 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -525,11 +525,9 @@ class FileCC : public SrtCongestionControlBase m_iLastDecSeq = m_parent->sndSeqNo(); - // remove global synchronization using randomization - srand(m_iLastDecSeq); - m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX)); - if (m_iDecRandom < 1) - m_iDecRandom = 1; + // remove global synchronization using randomization. + m_iDecRandom = genRandomInt(1, m_iAvgNAKNum); + SRT_ASSERT(m_iDecRandom >= 1); HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin << ", lastsentseqno=" << m_iLastDecSeq << ", seqdiff=" << CSeqNo::seqoff(m_iLastDecSeq, lossbegin) diff --git a/srtcore/core.h b/srtcore/core.h index 97eda7436..1d75bbaea 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -401,9 +401,7 @@ class CUDT static int32_t generateISN() { using namespace srt::sync; - // Random Initial Sequence Number (normal mode) - srand((unsigned) count_microseconds(steady_clock::now().time_since_epoch())); - return (int32_t)(CSeqNo::m_iMaxSeqNo * (double(rand()) / RAND_MAX)); + return genRandomInt(0, CSeqNo::m_iMaxSeqNo); } // For SRT_tsbpdLoop diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index c630f897d..820e0a7f9 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -18,11 +18,18 @@ #include "logging.h" #include "common.h" +// HAVE_CXX11 is defined in utilities.h, included with common.h. +// The following conditional inclusion must go after common.h. +#if HAVE_CXX11 +#include +#endif + namespace srt_logging { extern Logger inlog; } using namespace srt_logging; +using namespace std; namespace srt { @@ -267,3 +274,77 @@ bool srt::sync::CGlobEvent::waitForEvent() return g_Sync.lock_wait_for(milliseconds_from(10)); } +//////////////////////////////////////////////////////////////////////////////// +// +// Random +// +//////////////////////////////////////////////////////////////////////////////// + +namespace srt +{ +#if HAVE_CXX11 +static std::random_device& randomDevice() +{ + static std::random_device s_RandomDevice; + return s_RandomDevice; +} +#elif defined(_WIN32) && defined(__MINGW32__) +static void initRandSeed() +{ + const int64_t seed = sync::steady_clock::now().time_since_epoch().count(); + srand((unsigned int) seed); +} +static pthread_once_t s_InitRandSeedOnce = PTHREAD_ONCE_INIT; +#else + +static unsigned int genRandSeed() +{ + // Duration::count() does not depend on any global objects, + // therefore it is preferred over count)microseconds(..). + const int64_t seed = sync::steady_clock::now().time_since_epoch().count(); + return (unsigned int) seed; +} + +static unsigned int* getRandSeed() +{ + static unsigned int s_uRandSeed = genRandSeed(); + return &s_uRandSeed; +} + +#endif +} + +int srt::sync::genRandomInt(int minVal, int maxVal) +{ + // This Meyers singleton initialization is thread-safe since C++11, but is not thread-safe in C++03. + // A mutex to protect simulteneout access to the random device. + // Thread-local storage could be used here instead to store the seed / random device. + // However the generator is not used often (Initial Socket ID, Initial sequence number, FileCC), + // so sharing a single seed among threads should not impact the performance. + static sync::Mutex s_mtxRandomDevice; + sync::ScopedLock lck(s_mtxRandomDevice); +#if HAVE_CXX11 + uniform_int_distribution<> dis(minVal, maxVal); + return dis(randomDevice()); +#else +#if defined(__MINGW32__) + // No rand_r(..) for MinGW. + pthread_once(&s_InitRandSeedOnce, initRandSeed); + // rand() returns a pseudo-random integer in the range 0 to RAND_MAX inclusive + // (i.e., the mathematical range [0, RAND_MAX]). + // Therefore, rand_0_1 belongs to [0.0, 1.0]. + const double rand_0_1 = double(rand()) / RAND_MAX; +#else // not __MINGW32__ + // rand_r(..) returns a pseudo-random integer in the range 0 to RAND_MAX inclusive + // (i.e., the mathematical range [0, RAND_MAX]). + // Therefore, rand_0_1 belongs to [0.0, 1.0]. + const double rand_0_1 = double(rand_r(getRandSeed())) / RAND_MAX; +#endif + + // Map onto [minVal, maxVal]. + // Note. The probablity to get maxVal as the result is minuscule. + const int res = minVal + static_cast((maxVal - minVal) * rand_0_1); + return res; +#endif // HAVE_CXX11 +} + diff --git a/srtcore/sync.h b/srtcore/sync.h index 7457c3df9..f25c5ca8d 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -835,6 +835,18 @@ void SetThreadLocalError(const CUDTException& e); /// @returns CUDTException pointer CUDTException& GetThreadLocalError(); +//////////////////////////////////////////////////////////////////////////////// +// +// Random distribution functions. +// +//////////////////////////////////////////////////////////////////////////////// + +/// Generate a uniform-distributed random integer from [minVal; maxVal]. +/// If HAVE_CXX11, uses std::uniform_distribution(std::random_device). +/// @param[in] minVal minimum allowed value of the resulting random number. +/// @param[in] maxVal maximum allowed value of the resulting random number. +int genRandomInt(int minVal, int maxVal); + } // namespace sync } // namespace srt diff --git a/srtcore/utilities.h b/srtcore/utilities.h index 7d73c8567..caf882cd9 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -34,7 +34,6 @@ written by #define ATR_UNUSED #define ATR_DEPRECATED #endif - #if defined(__cplusplus) && __cplusplus > 199711L #define HAVE_CXX11 1 diff --git a/test/test_sync.cpp b/test/test_sync.cpp index 47d23f7bc..950af154a 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -157,6 +157,27 @@ TEST(SyncDuration, OperatorMultIntEq) EXPECT_EQ(count_milliseconds(a), 7000); } +TEST(SyncRandom, GenRandomInt) +{ + vector mn(64); + + for (int i = 0; i < 2048; ++i) + { + const int rand_val = genRandomInt(0, 63); + ASSERT_GE(rand_val, 0); + ASSERT_LE(rand_val, 63); + ++mn[rand_val]; + } + + // Uncomment to see the distribution. + // for (size_t i = 0; i < mn.size(); ++i) + // { + // cout << i << '\t'; + // for (int j=0; j Date: Wed, 19 May 2021 12:23:31 +0200 Subject: [PATCH 013/124] [core] Fixed DROPREQ on NAK behind SndLastDataAck (#2011) --- srtcore/buffer.cpp | 5 +++-- srtcore/core.cpp | 8 +++++--- srtcore/srt.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index d42a57577..bce9922b6 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -183,7 +183,7 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl) int32_t& w_msgno = w_mctrl.msgno; int32_t& w_seqno = w_mctrl.pktseq; int64_t& w_srctime = w_mctrl.srctime; - int& w_ttl = w_mctrl.msgttl; + const int& ttl = w_mctrl.msgttl; int size = len / m_iMSS; if ((len % m_iMSS) != 0) size++; @@ -254,7 +254,7 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl) s->m_llSourceTime_us = w_srctime; s->m_tsOriginTime = time; s->m_tsRexmitTime = time_point(); - s->m_iTTL = w_ttl; + s->m_iTTL = ttl; // Rewrite the actual sending time back into w_srctime // so that the calling facilities can reuse it if (!w_srctime) @@ -542,6 +542,7 @@ int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time // if found block is stale // (This is for messages that have declared TTL - messages that fail to be sent // before the TTL defined time comes, will be dropped). + if ((p->m_iTTL >= 0) && (count_milliseconds(steady_clock::now() - p->m_tsOriginTime) > p->m_iTTL)) { int32_t msgno = p->getMsgSeq(); diff --git a/srtcore/core.cpp b/srtcore/core.cpp index a6dfb04cd..f6c6cac0a 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8848,9 +8848,11 @@ int CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime // No matter whether this is right or not (maybe the attack case should be // considered, and some LOSSREPORT flood prevention), send the drop request // to the peer. - int32_t seqpair[2]; - seqpair[0] = w_packet.m_iSeqNo; - seqpair[1] = m_iSndLastDataAck; + int32_t seqpair[2] = { + w_packet.m_iSeqNo, + CSeqNo::decseq(m_iSndLastDataAck) + }; + w_packet.m_iMsgNo = 0; // Message number is not known, setting all 32 bits to 0. HLOGC(qrlog.Debug, log << "PEER reported LOSS not from the sending buffer - requesting DROP: " << "msg=" << MSGNO_SEQ::unwrap(w_packet.m_iMsgNo) << " SEQ:" diff --git a/srtcore/srt.h b/srtcore/srt.h index 60f3fc1e8..21e94879e 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -863,7 +863,7 @@ SRT_API int srt_setsockflag (SRTSOCKET u, SRT_SOCKOPT opt, const void* op typedef struct SRT_MsgCtrl_ { int flags; // Left for future - int msgttl; // TTL for a message, default -1 (no TTL limitation) + int msgttl; // TTL for a message (millisec), default -1 (no TTL limitation) int inorder; // Whether a message is allowed to supersede 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 since epoch (usec), 0: use internal time (sender) From 4ddb68efaed2fa847ed02eac61a81e68bff7b94d Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 19 May 2021 10:45:24 +0200 Subject: [PATCH 014/124] [core] Applied clang-format on queue.h and cpp --- srtcore/queue.cpp | 328 +++++++++++++------------ srtcore/queue.h | 605 +++++++++++++++++++++++----------------------- 2 files changed, 482 insertions(+), 451 deletions(-) diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index c2aa8d40d..ccc14b9b8 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -78,14 +78,14 @@ CUnitQueue::CUnitQueue() CUnitQueue::~CUnitQueue() { - CQEntry *p = m_pQEntry; + CQEntry* p = m_pQEntry; while (p != NULL) { delete[] p->m_pUnit; delete[] p->m_pBuffer; - CQEntry *q = p; + CQEntry* q = p; if (p == m_pLastQueue) p = NULL; else @@ -96,9 +96,9 @@ CUnitQueue::~CUnitQueue() int CUnitQueue::init(int size, int mss, int version) { - CQEntry *tempq = NULL; - CUnit * tempu = NULL; - char * tempb = NULL; + CQEntry* tempq = NULL; + CUnit* tempu = NULL; + char* tempb = NULL; try { @@ -142,11 +142,11 @@ int CUnitQueue::increase() { // adjust/correct m_iCount int real_count = 0; - CQEntry *p = m_pQEntry; + CQEntry* p = m_pQEntry; while (p != NULL) { - CUnit *u = p->m_pUnit; - for (CUnit *end = u + p->m_iSize; u != end; ++u) + CUnit* u = p->m_pUnit; + for (CUnit* end = u + p->m_iSize; u != end; ++u) if (u->m_iFlag != CUnit::FREE) ++real_count; @@ -159,9 +159,9 @@ int CUnitQueue::increase() if (double(m_iCount) / m_iSize < 0.9) return -1; - CQEntry *tempq = NULL; - CUnit * tempu = NULL; - char * tempb = NULL; + CQEntry* tempq = NULL; + CUnit* tempu = NULL; + char* tempb = NULL; // all queues have the same size const int size = m_pQEntry->m_iSize; @@ -179,8 +179,8 @@ int CUnitQueue::increase() delete[] tempb; LOGC(rslog.Error, - log << "CUnitQueue:increase: failed to allocate " << size << " new units." - << " Current size=" << m_iSize); + log << "CUnitQueue:increase: failed to allocate " << size << " new units." + << " Current size=" << m_iSize); return -1; } @@ -208,7 +208,7 @@ int CUnitQueue::shrink() return -1; } -CUnit *CUnitQueue::getNextAvailUnit() +CUnit* CUnitQueue::getNextAvailUnit() { if (m_iCount * 10 > m_iSize * 9) increase(); @@ -219,7 +219,7 @@ CUnit *CUnitQueue::getNextAvailUnit() int units_checked = 0; do { - const CUnit *end = m_pCurrQueue->m_pUnit + m_pCurrQueue->m_iSize; + const CUnit* end = m_pCurrQueue->m_pUnit + m_pCurrQueue->m_iSize; for (; m_pAvailUnit != end; ++m_pAvailUnit, ++units_checked) { if (m_pAvailUnit->m_iFlag == CUnit::FREE) @@ -237,7 +237,7 @@ CUnit *CUnitQueue::getNextAvailUnit() return NULL; } -void CUnitQueue::makeUnitFree(CUnit *unit) +void CUnitQueue::makeUnitFree(CUnit* unit) { SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag != CUnit::FREE); @@ -245,7 +245,7 @@ void CUnitQueue::makeUnitFree(CUnit *unit) --m_iCount; } -void CUnitQueue::makeUnitGood(CUnit *unit) +void CUnitQueue::makeUnitGood(CUnit* unit) { SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag == CUnit::FREE); @@ -262,7 +262,7 @@ CSndUList::CSndUList() , m_pWindowCond(NULL) , m_pTimer(NULL) { - m_pHeap = new CSNode *[m_iArrayLength]; + m_pHeap = new CSNode*[m_iArrayLength]; } CSndUList::~CSndUList() @@ -307,7 +307,7 @@ int CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) if (m_pHeap[0]->m_tsTimeStamp > steady_clock::now()) return -1; - CUDT *u = m_pHeap[0]->m_pUDT; + CUDT* u = m_pHeap[0]->m_pUDT; remove_(u); #define UST(field) ((u->m_b##field) ? "+" : "-") << #field << " " @@ -337,7 +337,7 @@ int CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) return 1; } -void CSndUList::remove(const CUDT *u) +void CSndUList::remove(const CUDT* u) { ScopedLock listguard(m_ListLock); @@ -356,18 +356,18 @@ steady_clock::time_point CSndUList::getNextProcTime() void CSndUList::realloc_() { - CSNode **temp = NULL; + CSNode** temp = NULL; try { - temp = new CSNode *[2 * m_iArrayLength]; + temp = new CSNode*[2 * m_iArrayLength]; } catch (...) { throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0); } - memcpy((temp), m_pHeap, sizeof(CSNode *) * m_iArrayLength); + memcpy((temp), m_pHeap, sizeof(CSNode*) * m_iArrayLength); m_iArrayLength *= 2; delete[] m_pHeap; m_pHeap = temp; @@ -384,7 +384,7 @@ void CSndUList::insert_(const steady_clock::time_point& ts, const CUDT* u) void CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT* u) { - CSNode *n = u->m_pSNode; + CSNode* n = u->m_pSNode; // do not insert repeated node if (n->m_iHeapLoc >= 0) @@ -394,7 +394,7 @@ void CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT m_iLastEntry++; m_pHeap[m_iLastEntry] = n; - n->m_tsTimeStamp = ts; + n->m_tsTimeStamp = ts; int q = m_iLastEntry; int p = q; @@ -424,7 +424,7 @@ void CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT void CSndUList::remove_(const CUDT* u) { - CSNode *n = u->m_pSNode; + CSNode* n = u->m_pSNode; if (n->m_iHeapLoc >= 0) { @@ -493,14 +493,20 @@ CSndQueue::~CSndQueue() delete m_pSndUList; } -int CSndQueue::ioctlQuery(int type) const { return m_pChannel->ioctlQuery(type); } -int CSndQueue::sockoptQuery(int level, int type) const { return m_pChannel->sockoptQuery(level, type); } +int CSndQueue::ioctlQuery(int type) const +{ + return m_pChannel->ioctlQuery(type); +} +int CSndQueue::sockoptQuery(int level, int type) const +{ + return m_pChannel->sockoptQuery(level, type); +} #if ENABLE_LOGGING - int CSndQueue::m_counter = 0; +int CSndQueue::m_counter = 0; #endif -void CSndQueue::init(CChannel *c, CTimer *t) +void CSndQueue::init(CChannel* c, CTimer* t) { m_pChannel = c; m_pTimer = t; @@ -512,7 +518,7 @@ void CSndQueue::init(CChannel *c, CTimer *t) #if ENABLE_LOGGING ++m_counter; const std::string thrname = "SRT:SndQ:w" + Sprint(m_counter); - const char* thname = thrname.c_str(); + const char* thname = thrname.c_str(); #else const char* thname = "SRT:SndQ"; #endif @@ -520,17 +526,26 @@ void CSndQueue::init(CChannel *c, CTimer *t) throw CUDTException(MJ_SYSTEMRES, MN_THREAD); } -int CSndQueue::getIpTTL() const { return m_pChannel ? m_pChannel->getIpTTL() : -1; } +int CSndQueue::getIpTTL() const +{ + return m_pChannel ? m_pChannel->getIpTTL() : -1; +} -int CSndQueue::getIpToS() const { return m_pChannel ? m_pChannel->getIpToS() : -1; } +int CSndQueue::getIpToS() const +{ + return m_pChannel ? m_pChannel->getIpToS() : -1; +} #ifdef SRT_ENABLE_BINDTODEVICE -bool CSndQueue::getBind(char* dst, size_t len) const { return m_pChannel ? m_pChannel->getBind(dst, len) : false; } +bool CSndQueue::getBind(char* dst, size_t len) const +{ + return m_pChannel ? m_pChannel->getBind(dst, len) : false; +} #endif -void *CSndQueue::worker(void *param) +void* CSndQueue::worker(void* param) { - CSndQueue *self = (CSndQueue *)param; + CSndQueue* self = (CSndQueue*)param; #if ENABLE_LOGGING THREAD_STATE_INIT(("SRT:SndQ:w" + Sprint(m_counter)).c_str()); @@ -558,8 +573,8 @@ void *CSndQueue::worker(void *param) self->m_WorkerStats.lNotReadyTs++; #endif /* SRT_DEBUG_SNDQ_HIGHRATE */ - UniqueLock windlock (self->m_WindowLock); - CSync windsync (self->m_WindowCond, windlock); + UniqueLock windlock(self->m_WindowLock); + CSync windsync(self->m_WindowCond, windlock); // wait here if there is no sockets with data to be sent THREAD_PAUSED(); @@ -646,9 +661,9 @@ CRcvUList::CRcvUList() CRcvUList::~CRcvUList() {} -void CRcvUList::insert(const CUDT *u) +void CRcvUList::insert(const CUDT* u) { - CRNode *n = u->m_pRNode; + CRNode* n = u->m_pRNode; n->m_tsTimeStamp = steady_clock::now(); if (NULL == m_pUList) @@ -667,9 +682,9 @@ void CRcvUList::insert(const CUDT *u) m_pLast = n; } -void CRcvUList::remove(const CUDT *u) +void CRcvUList::remove(const CUDT* u) { - CRNode *n = u->m_pRNode; + CRNode* n = u->m_pRNode; if (!n->m_bOnList) return; @@ -698,9 +713,9 @@ void CRcvUList::remove(const CUDT *u) n->m_pNext = n->m_pPrev = NULL; } -void CRcvUList::update(const CUDT *u) +void CRcvUList::update(const CUDT* u) { - CRNode *n = u->m_pRNode; + CRNode* n = u->m_pRNode; if (!n->m_bOnList) return; @@ -739,10 +754,10 @@ CHash::~CHash() { for (int i = 0; i < m_iHashSize; ++i) { - CBucket *b = m_pBucket[i]; + CBucket* b = m_pBucket[i]; while (NULL != b) { - CBucket *n = b->m_pNext; + CBucket* n = b->m_pNext; delete b; b = n; } @@ -753,7 +768,7 @@ CHash::~CHash() void CHash::init(int size) { - m_pBucket = new CBucket *[size]; + m_pBucket = new CBucket*[size]; for (int i = 0; i < size; ++i) m_pBucket[i] = NULL; @@ -761,10 +776,10 @@ void CHash::init(int size) m_iHashSize = size; } -CUDT *CHash::lookup(int32_t id) +CUDT* CHash::lookup(int32_t id) { // simple hash function (% hash table size); suitable for socket descriptors - CBucket *b = m_pBucket[id % m_iHashSize]; + CBucket* b = m_pBucket[id % m_iHashSize]; while (NULL != b) { @@ -776,11 +791,11 @@ CUDT *CHash::lookup(int32_t id) return NULL; } -void CHash::insert(int32_t id, CUDT *u) +void CHash::insert(int32_t id, CUDT* u) { - CBucket *b = m_pBucket[id % m_iHashSize]; + CBucket* b = m_pBucket[id % m_iHashSize]; - CBucket *n = new CBucket; + CBucket* n = new CBucket; n->m_iID = id; n->m_pUDT = u; n->m_pNext = b; @@ -790,8 +805,8 @@ void CHash::insert(int32_t id, CUDT *u) void CHash::remove(int32_t id) { - CBucket *b = m_pBucket[id % m_iHashSize]; - CBucket *p = NULL; + CBucket* b = m_pBucket[id % m_iHashSize]; + CBucket* p = NULL; while (NULL != b) { @@ -824,26 +839,28 @@ CRendezvousQueue::~CRendezvousQueue() m_lRendezvousID.clear(); } -void CRendezvousQueue::insert( - const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const steady_clock::time_point& ttl) +void CRendezvousQueue::insert(const SRTSOCKET& id, + CUDT* u, + const sockaddr_any& addr, + const steady_clock::time_point& ttl) { ScopedLock vg(m_RIDListLock); CRL r; - r.m_iID = id; - r.m_pUDT = u; + r.m_iID = id; + r.m_pUDT = u; r.m_PeerAddr = addr; - r.m_tsTTL = ttl; + r.m_tsTTL = ttl; m_lRendezvousID.push_back(r); - HLOGC(cnlog.Debug, log << "RID: adding socket @" << id << " for address: " << addr.str() - << " expires: " << FormatTime(ttl) - << " (total connectors: " << m_lRendezvousID.size() << ")"); + HLOGC(cnlog.Debug, + log << "RID: adding socket @" << id << " for address: " << addr.str() << " expires: " << FormatTime(ttl) + << " (total connectors: " << m_lRendezvousID.size() << ")"); } -void CRendezvousQueue::remove(const SRTSOCKET &id) +void CRendezvousQueue::remove(const SRTSOCKET& id) { - ScopedLock lkv (m_RIDListLock); + ScopedLock lkv(m_RIDListLock); for (list::iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { @@ -857,35 +874,36 @@ void CRendezvousQueue::remove(const SRTSOCKET &id) CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) const { - ScopedLock vg(m_RIDListLock); + ScopedLock vg(m_RIDListLock); // TODO: optimize search for (list::const_iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i) { if (i->m_PeerAddr == addr && ((w_id == 0) || (w_id == i->m_iID))) { - HLOGC(cnlog.Debug, log << "RID: found id @" << i->m_iID << " while looking for " - << (w_id ? "THIS ID FROM " : "A NEW CONNECTION FROM ") - << i->m_PeerAddr.str()); + HLOGC(cnlog.Debug, + log << "RID: found id @" << i->m_iID << " while looking for " + << (w_id ? "THIS ID FROM " : "A NEW CONNECTION FROM ") << i->m_PeerAddr.str()); w_id = i->m_iID; return i->m_pUDT; } } #if ENABLE_HEAVY_LOGGING - std::ostringstream spec; - if (w_id == 0) - spec << "A NEW CONNECTION REQUEST"; - else - spec << " AGENT @" << w_id; - HLOGC(cnlog.Debug, log << "RID: NO CONNECTOR FOR ADR:" << addr.str() - << " while looking for " << spec.str() << " (" << m_lRendezvousID.size() << " connectors total)"); + std::ostringstream spec; + if (w_id == 0) + spec << "A NEW CONNECTION REQUEST"; + else + spec << " AGENT @" << w_id; + HLOGC(cnlog.Debug, + log << "RID: NO CONNECTOR FOR ADR:" << addr.str() << " while looking for " << spec.str() << " (" + << m_lRendezvousID.size() << " connectors total)"); #endif return NULL; } -void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket &pktIn) +void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn) { vector toRemove, toProcess; @@ -896,8 +914,9 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con // [[using locked()]]; - HLOGC(cnlog.Debug, log << "updateConnStatus: collected " << toProcess.size() << " for processing, " - << toRemove.size() << " to close"); + HLOGC(cnlog.Debug, + log << "updateConnStatus: collected " << toProcess.size() << " for processing, " << toRemove.size() + << " to close"); // Repeat (resend) connection request. for (vector::iterator i = toProcess.begin(); i != toProcess.end(); ++i) @@ -925,18 +944,18 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con conn_st = CONN_AGAIN; } - HLOGC(cnlog.Debug, log << "updateConnStatus: processing async conn for @" << i->id << " FROM " << i->peeraddr.str()); + HLOGC(cnlog.Debug, + log << "updateConnStatus: processing async conn for @" << i->id << " FROM " << i->peeraddr.str()); if (!i->u->processAsyncConnectRequest(read_st, conn_st, pktIn, i->peeraddr)) { // cst == CONN_REJECT can only be result of worker_ProcessAddressedPacket and // its already set in this case. LinkStatusInfo fi = *i; - fi.errorcode = SRT_ECONNREJ; + fi.errorcode = SRT_ECONNREJ; toRemove.push_back(fi); i->u->sendCtrl(UMSG_SHUTDOWN); } - } // NOTE: it is "believed" here that all CUDT objects will not be @@ -962,7 +981,8 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con // be normally closed by the application, after it is done with them. // app can call any UDT API to learn the connection_broken error - CUDT::s_UDTUnited.m_EPoll.update_events(i->u->m_SocketID, i->u->m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); + CUDT::s_UDTUnited.m_EPoll.update_events( + i->u->m_SocketID, i->u->m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); i->u->completeBrokenConnectionDependencies(i->errorcode); } @@ -975,15 +995,21 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con { if (find_if(toRemove.begin(), toRemove.end(), LinkStatusInfo::HasID(i->m_iID)) != toRemove.end()) { - LOGC(cnlog.Error, log << "updateConnStatus: processAsyncConnectRequest FAILED on @" << i->m_iID << ". Setting TTL as EXPIRED."); - i->m_tsTTL = steady_clock::time_point(); // Make it expire right now, will be picked up at the next iteration + LOGC(cnlog.Error, + log << "updateConnStatus: processAsyncConnectRequest FAILED on @" << i->m_iID + << ". Setting TTL as EXPIRED."); + i->m_tsTTL = + steady_clock::time_point(); // Make it expire right now, will be picked up at the next iteration } } } } -bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_ATR_UNUSED, - int iDstSockID, vector& toRemove, vector& toProcess) +bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, + EConnectStatus cst SRT_ATR_UNUSED, + int iDstSockID, + vector& toRemove, + vector& toProcess) { ScopedLock vg(m_RIDListLock); @@ -991,8 +1017,8 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A return false; // nothing to process. HLOGC(cnlog.Debug, - log << "updateConnStatus: updating after getting pkt with DST socket ID @" << iDstSockID - << " status: " << ConnectStatusStr(cst)); + log << "updateConnStatus: updating after getting pkt with DST socket ID @" << iDstSockID + << " status: " << ConnectStatusStr(cst)); for (list::iterator i = m_lRendezvousID.begin(), i_next = i; i != m_lRendezvousID.end(); i = i_next) { @@ -1003,11 +1029,11 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A if (tsNow >= i->m_tsTTL) { - HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID - << " removed - EXPIRED (" - // The "enforced on FAILURE" is below when processAsyncConnectRequest failed. - << (is_zero(i->m_tsTTL) ? "enforced on FAILURE" : "passed TTL") - << "). WILL REMOVE from queue."); + HLOGC(cnlog.Debug, + log << "RID: socket @" << i->m_iID + << " removed - EXPIRED (" + // The "enforced on FAILURE" is below when processAsyncConnectRequest failed. + << (is_zero(i->m_tsTTL) ? "enforced on FAILURE" : "passed TTL") << "). WILL REMOVE from queue."); // Set appropriate error information, but do not update yet. // Exit the lock first. Collect objects to update them later. @@ -1018,7 +1044,7 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A { // Timer expired, set TIMEOUT forcefully i->m_pUDT->m_RejectReason = SRT_REJ_TIMEOUT; - ccerror = SRT_ENOSERVER; + ccerror = SRT_ENOSERVER; } else { @@ -1031,7 +1057,7 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A // The call to completeBrokenConnectionDependencies() cannot happen here // under the lock of m_RIDListLock as it risks a deadlock. // Collect in 'toRemove' to update later. - LinkStatusInfo fi = { i->m_pUDT, i->m_iID, ccerror, i->m_PeerAddr, -1 }; + LinkStatusInfo fi = {i->m_pUDT, i->m_iID, ccerror, i->m_PeerAddr, -1}; toRemove.push_back(fi); // i_next was preincremented, but this is guaranteed to point to @@ -1041,12 +1067,14 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A } else { - HLOGC(cnlog.Debug, log << "RID: socket @" << i->m_iID << " still active (remaining " - << std::fixed << (count_microseconds(i->m_tsTTL - tsNow) / 1000000.0) << "s of TTL)..."); + HLOGC(cnlog.Debug, + log << "RID: socket @" << i->m_iID << " still active (remaining " << std::fixed + << (count_microseconds(i->m_tsTTL - tsNow) / 1000000.0) << "s of TTL)..."); } const steady_clock::time_point tsLastReq = i->m_pUDT->m_tsLastReqTime; - const steady_clock::time_point tsRepeat = tsLastReq + milliseconds_from(250); // Repeat connection request (send HS). + const steady_clock::time_point tsRepeat = + tsLastReq + milliseconds_from(250); // Repeat connection request (send HS). // A connection request is repeated every 250 ms if there was no response from the peer: // - RST_AGAIN means no packet was received over UDP. @@ -1054,20 +1082,21 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_A if ((rst == RST_AGAIN || i->m_iID != iDstSockID) && tsNow <= tsRepeat) { HLOGC(cnlog.Debug, - log << "RID:@" << i->m_iID << std::fixed << count_microseconds(tsNow - tsLastReq) / 1000.0 - << " ms passed since last connection request."); + log << "RID:@" << i->m_iID << std::fixed << count_microseconds(tsNow - tsLastReq) / 1000.0 + << " ms passed since last connection request."); continue; } - HLOGC(cnlog.Debug, log << "RID:@" << i->m_iID << " cst=" << ConnectStatusStr(cst) << " -- repeating connection request."); + HLOGC(cnlog.Debug, + log << "RID:@" << i->m_iID << " cst=" << ConnectStatusStr(cst) << " -- repeating connection request."); // This queue is used only in case of Async mode (rendezvous or caller-listener). // Synchronous connection requests are handled in startConnect() completely. if (!i->m_pUDT->m_config.bSynRecving) { // Collect them so that they can be updated out of m_RIDListLock. - LinkStatusInfo fi = { i->m_pUDT, i->m_iID, SRT_SUCCESS, i->m_PeerAddr, -1 }; + LinkStatusInfo fi = {i->m_pUDT, i->m_iID, SRT_SUCCESS, i->m_PeerAddr, -1}; toProcess.push_back(fi); } else @@ -1116,11 +1145,11 @@ CRcvQueue::~CRcvQueue() delete m_pRendezvousQueue; // remove all queued messages - for (map >::iterator i = m_mBuffer.begin(); i != m_mBuffer.end(); ++i) + for (map >::iterator i = m_mBuffer.begin(); i != m_mBuffer.end(); ++i) { while (!i->second.empty()) { - CPacket *pkt = i->second.front(); + CPacket* pkt = i->second.front(); delete[] pkt->m_pcData; delete pkt; i->second.pop(); @@ -1129,15 +1158,14 @@ CRcvQueue::~CRcvQueue() } #if ENABLE_LOGGING - int CRcvQueue::m_counter = 0; +int CRcvQueue::m_counter = 0; #endif - -void CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel *cc, CTimer *t) +void CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel* cc, CTimer* t) { m_szPayloadSize = payload; - m_UnitQueue.init(qsize, (int) payload, version); + m_UnitQueue.init(qsize, (int)payload, version); m_pHash = new CHash; m_pHash->init(hsize); @@ -1161,9 +1189,9 @@ void CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel } } -void *CRcvQueue::worker(void *param) +void* CRcvQueue::worker(void* param) { - CRcvQueue * self = (CRcvQueue *)param; + CRcvQueue* self = (CRcvQueue*)param; sockaddr_any sa(self->m_UnitQueue.getIPversion()); int32_t id = 0; @@ -1173,7 +1201,7 @@ void *CRcvQueue::worker(void *param) THREAD_STATE_INIT("SRT:RcvQ:worker"); #endif - CUnit * unit = 0; + CUnit* unit = 0; EConnectStatus cst = CONN_AGAIN; while (!self->m_bClosing) { @@ -1243,12 +1271,13 @@ void *CRcvQueue::worker(void *param) // OTHERWISE: this is an "AGAIN" situation. No data was read, but the process should continue. // take care of the timing event for all UDT sockets - const steady_clock::time_point curtime_minus_syn = steady_clock::now() - microseconds_from(CUDT::COMM_SYN_INTERVAL_US); + const steady_clock::time_point curtime_minus_syn = + steady_clock::now() - microseconds_from(CUDT::COMM_SYN_INTERVAL_US); - CRNode *ul = self->m_pRcvUList->m_pUList; + CRNode* ul = self->m_pRcvUList->m_pUList; while ((NULL != ul) && (ul->m_tsTimeStamp < curtime_minus_syn)) { - CUDT *u = ul->m_pUDT; + CUDT* u = ul->m_pUDT; if (u->m_bConnected && !u->m_bBroken && !u->m_bClosing) { @@ -1304,7 +1333,7 @@ EReadStatus CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockad // check waiting list, if new socket, insert it to the list while (ifNewEntry()) { - CUDT *ne = getNewEntry(); + CUDT* ne = getNewEntry(); if (ne) { HLOGC(qrlog.Debug, @@ -1344,9 +1373,9 @@ EReadStatus CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockad if (rst == RST_OK) { w_id = w_unit->m_Packet.m_iID; - HLOGC(qrlog.Debug, log << "INCOMING PACKET: FROM=" << w_addr.str() - << " BOUND=" << m_pChannel->bindAddressAny().str() - << " " << w_unit->m_Packet.Info()); + HLOGC(qrlog.Debug, + log << "INCOMING PACKET: FROM=" << w_addr.str() << " BOUND=" << m_pChannel->bindAddressAny().str() << " " + << w_unit->m_Packet.Info()); } return rst; } @@ -1354,20 +1383,18 @@ EReadStatus CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockad EConnectStatus CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& addr) { HLOGC(cnlog.Debug, - log << "Got sockID=0 from " << addr.str() - << " - trying to resolve it as a connection request..."); + log << "Got sockID=0 from " << addr.str() << " - trying to resolve it as a connection request..."); // Introduced protection because it may potentially happen // that another thread could have closed the socket at // the same time and inject a bug between checking the // pointer for NULL and using it. - int listener_ret = SRT_REJ_UNKNOWN; - bool have_listener = false; + int listener_ret = SRT_REJ_UNKNOWN; + bool have_listener = false; { ScopedLock cg(m_LSLock); if (m_pListener) { - LOGC(cnlog.Note, - log << "PASSING request from: " << addr.str() << " to agent:" << m_pListener->socketID()); + LOGC(cnlog.Note, log << "PASSING request from: " << addr.str() << " to agent:" << m_pListener->socketID()); listener_ret = m_pListener->processConnectRequest(addr, unit->m_Packet); // This function does return a code, but it's hard to say as to whether @@ -1398,7 +1425,7 @@ EConnectStatus CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit, const soc EConnectStatus CRcvQueue::worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& addr) { - CUDT *u = m_pHash->lookup(id); + CUDT* u = m_pHash->lookup(id); if (!u) { // Pass this to either async rendezvous connection, @@ -1412,8 +1439,8 @@ EConnectStatus CRcvQueue::worker_ProcessAddressedPacket(int32_t id, CUnit* unit, if (addr != u->m_PeerAddr) { HLOGC(cnlog.Debug, - log << CONID() << "Packet for SID=" << id << " asoc with " << u->m_PeerAddr.str() - << " received from " << addr.str() << " (CONSIDERED ATTACK ATTEMPT)"); + log << CONID() << "Packet for SID=" << id << " asoc with " << u->m_PeerAddr.str() << " received from " + << addr.str() << " (CONSIDERED ATTACK ATTEMPT)"); // This came not from the address that is the peer associated // with the socket. Ignore it. return CONN_AGAIN; @@ -1454,7 +1481,7 @@ EConnectStatus CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, c // stored in the rendezvous queue (see CRcvQueue::registerConnector) // or simply 0, but then at least the address must match one of these. // If the id was 0, it will be set to the actual socket ID of the returned CUDT. - CUDT *u = m_pRendezvousQueue->retrieve(addr, (id)); + CUDT* u = m_pRendezvousQueue->retrieve(addr, (id)); if (!u) { // this socket is then completely unknown to the system. @@ -1525,7 +1552,7 @@ EConnectStatus CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, c // that we KNOW (by the cst == CONN_ACCEPT result) that the socket should be inserted // into the pending anteroom. - CUDT *ne = getNewEntry(); // This function actuall removes the entry and returns it. + CUDT* ne = getNewEntry(); // This function actuall removes the entry and returns it. // This **should** now always return a non-null value, but check it first // because if this accidentally isn't true, the call to worker_ProcessAddressedPacket will // result in redirecting it to here and so on until the call stack overflow. In case of @@ -1597,10 +1624,10 @@ void CRcvQueue::stopWorker() int CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) { - UniqueLock bufferlock (m_BufferLock); - CSync buffercond (m_BufferCond, bufferlock); + UniqueLock bufferlock(m_BufferLock); + CSync buffercond(m_BufferCond, bufferlock); - map >::iterator i = m_mBuffer.find(id); + map >::iterator i = m_mBuffer.find(id); if (i == m_mBuffer.end()) { @@ -1617,7 +1644,7 @@ int CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) } // retrieve the earliest packet - CPacket *newpkt = i->second.front(); + CPacket* newpkt = i->second.front(); if (w_packet.getLength() < newpkt->getLength()) { @@ -1649,7 +1676,7 @@ int CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) return (int)w_packet.getLength(); } -int CRcvQueue::setListener(CUDT *u) +int CRcvQueue::setListener(CUDT* u) { ScopedLock lslock(m_LSLock); @@ -1660,7 +1687,7 @@ int CRcvQueue::setListener(CUDT *u) return 0; } -void CRcvQueue::removeListener(const CUDT *u) +void CRcvQueue::removeListener(const CUDT* u) { ScopedLock lslock(m_LSLock); @@ -1668,21 +1695,24 @@ void CRcvQueue::removeListener(const CUDT *u) m_pListener = NULL; } -void CRcvQueue::registerConnector(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const steady_clock::time_point& ttl) +void CRcvQueue::registerConnector(const SRTSOCKET& id, + CUDT* u, + const sockaddr_any& addr, + const steady_clock::time_point& ttl) { HLOGC(cnlog.Debug, log << "registerConnector: adding @" << id << " addr=" << addr.str() << " TTL=" << FormatTime(ttl)); m_pRendezvousQueue->insert(id, u, addr, ttl); } -void CRcvQueue::removeConnector(const SRTSOCKET &id) +void CRcvQueue::removeConnector(const SRTSOCKET& id) { HLOGC(cnlog.Debug, log << "removeConnector: removing @" << id); m_pRendezvousQueue->remove(id); ScopedLock bufferlock(m_BufferLock); - map >::iterator i = m_mBuffer.find(id); + map >::iterator i = m_mBuffer.find(id); if (i != m_mBuffer.end()) { HLOGC(cnlog.Debug, @@ -1697,34 +1727,37 @@ void CRcvQueue::removeConnector(const SRTSOCKET &id) } } -void CRcvQueue::setNewEntry(CUDT *u) +void CRcvQueue::setNewEntry(CUDT* u) { HLOGC(cnlog.Debug, log << CUDTUnited::CONID(u->m_SocketID) << "setting socket PENDING FOR CONNECTION"); ScopedLock listguard(m_IDLock); m_vNewEntry.push_back(u); } -bool CRcvQueue::ifNewEntry() { return !(m_vNewEntry.empty()); } +bool CRcvQueue::ifNewEntry() +{ + return !(m_vNewEntry.empty()); +} -CUDT *CRcvQueue::getNewEntry() +CUDT* CRcvQueue::getNewEntry() { ScopedLock listguard(m_IDLock); if (m_vNewEntry.empty()) return NULL; - CUDT *u = (CUDT *)*(m_vNewEntry.begin()); + CUDT* u = (CUDT*)*(m_vNewEntry.begin()); m_vNewEntry.erase(m_vNewEntry.begin()); return u; } -void CRcvQueue::storePkt(int32_t id, CPacket *pkt) +void CRcvQueue::storePkt(int32_t id, CPacket* pkt) { - UniqueLock bufferlock (m_BufferLock); - CSync passcond (m_BufferCond, bufferlock); + UniqueLock bufferlock(m_BufferLock); + CSync passcond(m_BufferCond, bufferlock); - map >::iterator i = m_mBuffer.find(id); + map >::iterator i = m_mBuffer.find(id); if (i == m_mBuffer.end()) { @@ -1741,10 +1774,9 @@ void CRcvQueue::storePkt(int32_t id, CPacket *pkt) } } - void CMultiplexer::destroy() { - // Reverse order of the assigned + // Reverse order of the assigned delete m_pRcvQueue; delete m_pSndQueue; delete m_pTimer; diff --git a/srtcore/queue.h b/srtcore/queue.h index 9c0affd5e..a412fd516 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -1,11 +1,11 @@ /* * 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/. - * + * */ /***************************************************************************** @@ -50,7 +50,6 @@ modified by Haivision Systems Inc. *****************************************************************************/ - #ifndef INC_SRT_QUEUE_H #define INC_SRT_QUEUE_H @@ -69,255 +68,257 @@ class CChannel; struct CUnit { - CPacket m_Packet; // packet - enum Flag { FREE = 0, GOOD = 1, PASSACK = 2, DROPPED = 3 }; - Flag m_iFlag; // 0: free, 1: occupied, 2: msg read but not freed (out-of-order), 3: msg dropped + CPacket m_Packet; // packet + enum Flag + { + FREE = 0, + GOOD = 1, + PASSACK = 2, + DROPPED = 3 + }; + Flag m_iFlag; // 0: free, 1: occupied, 2: msg read but not freed (out-of-order), 3: msg dropped }; class CUnitQueue { public: + CUnitQueue(); + ~CUnitQueue(); - CUnitQueue(); - ~CUnitQueue(); - -public: // Storage size operations - - /// Initialize the unit queue. - /// @param [in] size queue size - /// @param [in] mss maximum segment size - /// @param [in] version IP version - /// @return 0: success, -1: failure. +public: // Storage size operations + /// Initialize the unit queue. + /// @param [in] size queue size + /// @param [in] mss maximum segment size + /// @param [in] version IP version + /// @return 0: success, -1: failure. - int init(int size, int mss, int version); + int init(int size, int mss, int version); - /// Increase (double) the unit queue size. - /// @return 0: success, -1: failure. + /// Increase (double) the unit queue size. + /// @return 0: success, -1: failure. - int increase(); + int increase(); - /// Decrease (halve) the unit queue size. - /// @return 0: success, -1: failure. + /// Decrease (halve) the unit queue size. + /// @return 0: success, -1: failure. - int shrink(); + int shrink(); public: - int size() const { return m_iSize - m_iCount; } - int capacity() const { return m_iSize; } + int size() const { return m_iSize - m_iCount; } + int capacity() const { return m_iSize; } -public: // Operations on units +public: // Operations on units + /// find an available unit for incoming packet. + /// @return Pointer to the available unit, NULL if not found. - /// find an available unit for incoming packet. - /// @return Pointer to the available unit, NULL if not found. + CUnit* getNextAvailUnit(); - CUnit* getNextAvailUnit(); + void makeUnitFree(CUnit* unit); - void makeUnitFree(CUnit * unit); - - void makeUnitGood(CUnit * unit); + void makeUnitGood(CUnit* unit); public: - inline int getIPversion() const { return m_iIPversion; } + inline int getIPversion() const { return m_iIPversion; } private: - struct CQEntry - { - CUnit* m_pUnit; // unit queue - char* m_pBuffer; // data buffer - int m_iSize; // size of each queue + struct CQEntry + { + CUnit* m_pUnit; // unit queue + char* m_pBuffer; // data buffer + int m_iSize; // size of each queue - CQEntry* m_pNext; - } - *m_pQEntry, // pointer to the first unit queue - *m_pCurrQueue, // pointer to the current available queue - *m_pLastQueue; // pointer to the last unit queue + CQEntry* m_pNext; + } * m_pQEntry, // pointer to the first unit queue + *m_pCurrQueue, // pointer to the current available queue + *m_pLastQueue; // pointer to the last unit queue - CUnit* m_pAvailUnit; // recent available unit + CUnit* m_pAvailUnit; // recent available unit - int m_iSize; // total size of the unit queue, in number of packets - int m_iCount; // total number of valid (occupied) packets in the queue + int m_iSize; // total size of the unit queue, in number of packets + int m_iCount; // total number of valid (occupied) packets in the queue - int m_iMSS; // unit buffer size - int m_iIPversion; // IP version + int m_iMSS; // unit buffer size + int m_iIPversion; // IP version private: - CUnitQueue(const CUnitQueue&); - CUnitQueue& operator=(const CUnitQueue&); + CUnitQueue(const CUnitQueue&); + CUnitQueue& operator=(const CUnitQueue&); }; struct CSNode { - CUDT* m_pUDT; // Pointer to the instance of CUDT socket - srt::sync::steady_clock::time_point m_tsTimeStamp; + CUDT* m_pUDT; // Pointer to the instance of CUDT socket + srt::sync::steady_clock::time_point m_tsTimeStamp; - int m_iHeapLoc; // location on the heap, -1 means not on the heap + int m_iHeapLoc; // location on the heap, -1 means not on the heap }; class CSndUList { -friend class CSndQueue; + friend class CSndQueue; public: - CSndUList(); - ~CSndUList(); + CSndUList(); + ~CSndUList(); public: + enum EReschedule + { + DONT_RESCHEDULE = 0, + DO_RESCHEDULE = 1 + }; - enum EReschedule { DONT_RESCHEDULE = 0, DO_RESCHEDULE = 1 }; - - static EReschedule rescheduleIf(bool cond) { return cond ? DO_RESCHEDULE : DONT_RESCHEDULE; } + static EReschedule rescheduleIf(bool cond) { return cond ? DO_RESCHEDULE : DONT_RESCHEDULE; } - /// Update the timestamp of the UDT instance on the list. - /// @param [in] u pointer to the UDT instance - /// @param [in] reschedule if the timestamp should be rescheduled + /// Update the timestamp of the UDT instance on the list. + /// @param [in] u pointer to the UDT instance + /// @param [in] reschedule if the timestamp should be rescheduled - void update(const CUDT* u, EReschedule reschedule); + void update(const CUDT* u, EReschedule reschedule); - /// Retrieve the next packet and peer address from the first entry, and reschedule it in the queue. - /// @param [out] addr destination address of the next packet - /// @param [out] pkt the next packet to be sent - /// @return 1 if successfully retrieved, -1 if no packet found. + /// Retrieve the next packet and peer address from the first entry, and reschedule it in the queue. + /// @param [out] addr destination address of the next packet + /// @param [out] pkt the next packet to be sent + /// @return 1 if successfully retrieved, -1 if no packet found. - int pop(sockaddr_any& addr, CPacket& pkt); + int pop(sockaddr_any& addr, CPacket& pkt); - /// Remove UDT instance from the list. - /// @param [in] u pointer to the UDT instance + /// Remove UDT instance from the list. + /// @param [in] u pointer to the UDT instance - void remove(const CUDT* u); + void remove(const CUDT* u); - /// Retrieve the next scheduled processing time. - /// @return Scheduled processing time of the first UDT socket in the list. + /// Retrieve the next scheduled processing time. + /// @return Scheduled processing time of the first UDT socket in the list. - srt::sync::steady_clock::time_point getNextProcTime(); + srt::sync::steady_clock::time_point getNextProcTime(); private: + /// Doubles the size of the list. + /// + void realloc_(); - /// Doubles the size of the list. - /// - void realloc_(); + /// Insert a new UDT instance into the list with realloc if required. + /// + /// @param [in] ts time stamp: next processing time + /// @param [in] u pointer to the UDT instance + void insert_(const srt::sync::steady_clock::time_point& ts, const CUDT* u); - /// Insert a new UDT instance into the list with realloc if required. - /// - /// @param [in] ts time stamp: next processing time - /// @param [in] u pointer to the UDT instance - void insert_(const srt::sync::steady_clock::time_point &ts, const CUDT* u); + /// Insert a new UDT instance into the list without realloc. + /// Should be called if there is a gauranteed space for the element. + /// + /// @param [in] ts time stamp: next processing time + /// @param [in] u pointer to the UDT instance + void insert_norealloc_(const srt::sync::steady_clock::time_point& ts, const CUDT* u); - /// Insert a new UDT instance into the list without realloc. - /// Should be called if there is a gauranteed space for the element. - /// - /// @param [in] ts time stamp: next processing time - /// @param [in] u pointer to the UDT instance - void insert_norealloc_(const srt::sync::steady_clock::time_point &ts, const CUDT* u); - - void remove_(const CUDT* u); + void remove_(const CUDT* u); private: - CSNode** m_pHeap; // The heap array - int m_iArrayLength; // physical length of the array - int m_iLastEntry; // position of last entry on the heap array + CSNode** m_pHeap; // The heap array + int m_iArrayLength; // physical length of the array + int m_iLastEntry; // position of last entry on the heap array - srt::sync::Mutex m_ListLock; + srt::sync::Mutex m_ListLock; - srt::sync::Mutex* m_pWindowLock; - srt::sync::Condition* m_pWindowCond; + srt::sync::Mutex* m_pWindowLock; + srt::sync::Condition* m_pWindowCond; - srt::sync::CTimer* m_pTimer; + srt::sync::CTimer* m_pTimer; private: - CSndUList(const CSndUList&); - CSndUList& operator=(const CSndUList&); + CSndUList(const CSndUList&); + CSndUList& operator=(const CSndUList&); }; struct CRNode { - CUDT* m_pUDT; // Pointer to the instance of CUDT socket - srt::sync::steady_clock::time_point m_tsTimeStamp; // Time Stamp + CUDT* m_pUDT; // Pointer to the instance of CUDT socket + srt::sync::steady_clock::time_point m_tsTimeStamp; // Time Stamp - CRNode* m_pPrev; // previous link - CRNode* m_pNext; // next link + CRNode* m_pPrev; // previous link + CRNode* m_pNext; // next link - bool m_bOnList; // if the node is already on the list + bool m_bOnList; // if the node is already on the list }; class CRcvUList { public: - CRcvUList(); - ~CRcvUList(); + CRcvUList(); + ~CRcvUList(); public: + /// Insert a new UDT instance to the list. + /// @param [in] u pointer to the UDT instance - /// Insert a new UDT instance to the list. - /// @param [in] u pointer to the UDT instance - - void insert(const CUDT* u); + void insert(const CUDT* u); - /// Remove the UDT instance from the list. - /// @param [in] u pointer to the UDT instance + /// Remove the UDT instance from the list. + /// @param [in] u pointer to the UDT instance - void remove(const CUDT* u); + void remove(const CUDT* u); - /// Move the UDT instance to the end of the list, if it already exists; otherwise, do nothing. - /// @param [in] u pointer to the UDT instance + /// Move the UDT instance to the end of the list, if it already exists; otherwise, do nothing. + /// @param [in] u pointer to the UDT instance - void update(const CUDT* u); + void update(const CUDT* u); public: - CRNode* m_pUList; // the head node + CRNode* m_pUList; // the head node private: - CRNode* m_pLast; // the last node + CRNode* m_pLast; // the last node private: - CRcvUList(const CRcvUList&); - CRcvUList& operator=(const CRcvUList&); + CRcvUList(const CRcvUList&); + CRcvUList& operator=(const CRcvUList&); }; class CHash { public: - CHash(); - ~CHash(); + CHash(); + ~CHash(); public: + /// Initialize the hash table. + /// @param [in] size hash table size - /// Initialize the hash table. - /// @param [in] size hash table size - - void init(int size); + void init(int size); - /// Look for a UDT instance from the hash table. - /// @param [in] id socket ID - /// @return Pointer to a UDT instance, or NULL if not found. + /// Look for a UDT instance from the hash table. + /// @param [in] id socket ID + /// @return Pointer to a UDT instance, or NULL if not found. - CUDT* lookup(int32_t id); + CUDT* lookup(int32_t id); - /// Insert an entry to the hash table. - /// @param [in] id socket ID - /// @param [in] u pointer to the UDT instance + /// Insert an entry to the hash table. + /// @param [in] id socket ID + /// @param [in] u pointer to the UDT instance - void insert(int32_t id, CUDT* u); + void insert(int32_t id, CUDT* u); - /// Remove an entry from the hash table. - /// @param [in] id socket ID + /// Remove an entry from the hash table. + /// @param [in] id socket ID - void remove(int32_t id); + void remove(int32_t id); private: - struct CBucket - { - int32_t m_iID; // Socket ID - CUDT* m_pUDT; // Socket instance + struct CBucket + { + int32_t m_iID; // Socket ID + CUDT* m_pUDT; // Socket instance - CBucket* m_pNext; // next bucket - } **m_pBucket; // list of buckets (the hash table) + CBucket* m_pNext; // next bucket + } * *m_pBucket; // list of buckets (the hash table) - int m_iHashSize; // size of hash table + int m_iHashSize; // size of hash table private: - CHash(const CHash&); - CHash& operator=(const CHash&); + CHash(const CHash&); + CHash& operator=(const CHash&); }; /// @brief A queue of sockets pending for connection. @@ -336,8 +337,7 @@ class CRendezvousQueue /// @param u pointer to a corresponding CUDT instance. /// @param addr remote address to connect to. /// @param ttl timepoint for connection attempt to expire. - void insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, - const srt::sync::steady_clock::time_point &ttl); + void insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const srt::sync::steady_clock::time_point& ttl); /// @brief Remove a socket from the connection pending list. /// @param id socket ID. @@ -359,257 +359,256 @@ class CRendezvousQueue private: struct LinkStatusInfo { - CUDT* u; - SRTSOCKET id; - int errorcode; + CUDT* u; + SRTSOCKET id; + int errorcode; sockaddr_any peeraddr; - int token; + int token; struct HasID { SRTSOCKET id; - HasID(SRTSOCKET p) : id(p) {} - bool operator()(const LinkStatusInfo& i) + HasID(SRTSOCKET p) + : id(p) { - return i.id == id; } + bool operator()(const LinkStatusInfo& i) { return i.id == id; } }; }; /// @brief Qualify pending connections: /// - Sockets with expired TTL go to the 'to_remove' list and removed from the queue straight away. /// - If HS request is to be resent (resend 250 ms if no response from the peer) go to the 'to_process' list. - /// + /// /// @param rst result of reading from a UDP socket: received packet / nothin read / read error. /// @param cst target status for pending connection: reject or proceed. /// @param iDstSockID destination socket ID of the received packet. /// @param[in,out] toRemove stores sockets with expired TTL. /// @param[in,out] toProcess stores sockets which should repeat (resend) HS connection request. - bool qualifyToHandle(EReadStatus rst, EConnectStatus cst, int iDstSockID, - std::vector& toRemove, std::vector& toProcess); + bool qualifyToHandle(EReadStatus rst, + EConnectStatus cst, + int iDstSockID, + std::vector& toRemove, + std::vector& toProcess); private: - struct CRL - { - SRTSOCKET m_iID; // SRT socket ID (self) - CUDT* m_pUDT; // CUDT instance - sockaddr_any m_PeerAddr;// SRT sonnection peer address - srt::sync::steady_clock::time_point m_tsTTL; // the time that this request expires - }; - std::list m_lRendezvousID; // The sockets currently in rendezvous mode - - mutable srt::sync::Mutex m_RIDListLock; + struct CRL + { + SRTSOCKET m_iID; // SRT socket ID (self) + CUDT* m_pUDT; // CUDT instance + sockaddr_any m_PeerAddr; // SRT sonnection peer address + srt::sync::steady_clock::time_point m_tsTTL; // the time that this request expires + }; + std::list m_lRendezvousID; // The sockets currently in rendezvous mode + + mutable srt::sync::Mutex m_RIDListLock; }; class CSndQueue { -friend class CUDT; -friend class CUDTUnited; + friend class CUDT; + friend class CUDTUnited; public: - CSndQueue(); - ~CSndQueue(); + CSndQueue(); + ~CSndQueue(); public: + // XXX There's currently no way to access the socket ID set for + // whatever the queue is currently working for. Required to find + // some way to do this, possibly by having a "reverse pointer". + // Currently just "unimplemented". + std::string CONID() const { return ""; } - // XXX There's currently no way to access the socket ID set for - // whatever the queue is currently working for. Required to find - // some way to do this, possibly by having a "reverse pointer". - // Currently just "unimplemented". - std::string CONID() const { return ""; } - - /// Initialize the sending queue. - /// @param [in] c UDP channel to be associated to the queue - /// @param [in] t Timer + /// Initialize the sending queue. + /// @param [in] c UDP channel to be associated to the queue + /// @param [in] t Timer - void init(CChannel* c, srt::sync::CTimer* t); + void init(CChannel* c, srt::sync::CTimer* t); - /// Send out a packet to a given address. - /// @param [in] addr destination address - /// @param [in] packet packet to be sent out - /// @return Size of data sent out. + /// Send out a packet to a given address. + /// @param [in] addr destination address + /// @param [in] packet packet to be sent out + /// @return Size of data sent out. - int sendto(const sockaddr_any& addr, CPacket& packet); + int sendto(const sockaddr_any& addr, CPacket& packet); - /// Get the IP TTL. - /// @param [in] ttl IP Time To Live. - /// @return TTL. + /// Get the IP TTL. + /// @param [in] ttl IP Time To Live. + /// @return TTL. - int getIpTTL() const; + int getIpTTL() const; - /// Get the IP Type of Service. - /// @return ToS. + /// Get the IP Type of Service. + /// @return ToS. - int getIpToS() const; + int getIpToS() const; #ifdef SRT_ENABLE_BINDTODEVICE - bool getBind(char* dst, size_t len) const; + bool getBind(char* dst, size_t len) const; #endif - int ioctlQuery(int type) const; - int sockoptQuery(int level, int type) const; + int ioctlQuery(int type) const; + int sockoptQuery(int level, int type) const; - void setClosing() - { - m_bClosing = true; - } + void setClosing() { m_bClosing = true; } private: - static void* worker(void* param); - srt::sync::CThread m_WorkerThread; + static void* worker(void* param); + srt::sync::CThread m_WorkerThread; private: - CSndUList* m_pSndUList; // List of UDT instances for data sending - CChannel* m_pChannel; // The UDP channel for data sending - srt::sync::CTimer* m_pTimer; // Timing facility + CSndUList* m_pSndUList; // List of UDT instances for data sending + CChannel* m_pChannel; // The UDP channel for data sending + srt::sync::CTimer* m_pTimer; // Timing facility - srt::sync::Mutex m_WindowLock; - srt::sync::Condition m_WindowCond; + srt::sync::Mutex m_WindowLock; + srt::sync::Condition m_WindowCond; - volatile bool m_bClosing; // closing the worker + volatile bool m_bClosing; // closing the worker -#if defined(SRT_DEBUG_SNDQ_HIGHRATE)//>>debug high freq worker - uint64_t m_ullDbgPeriod; - uint64_t m_ullDbgTime; - struct { +#if defined(SRT_DEBUG_SNDQ_HIGHRATE) //>>debug high freq worker + uint64_t m_ullDbgPeriod; + uint64_t m_ullDbgTime; + struct + { unsigned long lIteration; // - unsigned long lSleepTo; //SleepTo - unsigned long lNotReadyPop; //Continue + unsigned long lSleepTo; // SleepTo + unsigned long lNotReadyPop; // Continue unsigned long lSendTo; - unsigned long lNotReadyTs; - unsigned long lCondWait; //block on m_WindowCond - } m_WorkerStats; + unsigned long lNotReadyTs; + unsigned long lCondWait; // block on m_WindowCond + } m_WorkerStats; #endif /* SRT_DEBUG_SNDQ_HIGHRATE */ #if ENABLE_LOGGING - static int m_counter; + static int m_counter; #endif private: - CSndQueue(const CSndQueue&); - CSndQueue& operator=(const CSndQueue&); + CSndQueue(const CSndQueue&); + CSndQueue& operator=(const CSndQueue&); }; class CRcvQueue { -friend class CUDT; -friend class CUDTUnited; + friend class CUDT; + friend class CUDTUnited; public: - CRcvQueue(); - ~CRcvQueue(); + CRcvQueue(); + ~CRcvQueue(); public: + // XXX There's currently no way to access the socket ID set for + // whatever the queue is currently working. Required to find + // some way to do this, possibly by having a "reverse pointer". + // Currently just "unimplemented". + std::string CONID() const { return ""; } - // XXX There's currently no way to access the socket ID set for - // whatever the queue is currently working. Required to find - // some way to do this, possibly by having a "reverse pointer". - // Currently just "unimplemented". - std::string CONID() const { return ""; } - - /// Initialize the receiving queue. - /// @param [in] size queue size - /// @param [in] mss maximum packet size - /// @param [in] version IP version - /// @param [in] hsize hash table size - /// @param [in] c UDP channel to be associated to the queue - /// @param [in] t timer + /// Initialize the receiving queue. + /// @param [in] size queue size + /// @param [in] mss maximum packet size + /// @param [in] version IP version + /// @param [in] hsize hash table size + /// @param [in] c UDP channel to be associated to the queue + /// @param [in] t timer - void init(int size, size_t payload, int version, int hsize, CChannel* c, srt::sync::CTimer* t); + void init(int size, size_t payload, int version, int hsize, CChannel* c, srt::sync::CTimer* t); - /// Read a packet for a specific UDT socket id. - /// @param [in] id Socket ID - /// @param [out] packet received packet - /// @return Data size of the packet + /// Read a packet for a specific UDT socket id. + /// @param [in] id Socket ID + /// @param [out] packet received packet + /// @return Data size of the packet - int recvfrom(int32_t id, CPacket& to_packet); + int recvfrom(int32_t id, CPacket& to_packet); - void stopWorker(); + void stopWorker(); - void setClosing() - { - m_bClosing = true; - } + void setClosing() { m_bClosing = true; } private: - static void* worker(void* param); - srt::sync::CThread m_WorkerThread; - // Subroutines of worker - EReadStatus worker_RetrieveUnit(int32_t& id, CUnit*& unit, sockaddr_any& sa); - EConnectStatus worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& sa); - EConnectStatus worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr_any& sa); - EConnectStatus worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& sa); + static void* worker(void* param); + srt::sync::CThread m_WorkerThread; + // Subroutines of worker + EReadStatus worker_RetrieveUnit(int32_t& id, CUnit*& unit, sockaddr_any& sa); + EConnectStatus worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& sa); + EConnectStatus worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr_any& sa); + EConnectStatus worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& sa); private: - CUnitQueue m_UnitQueue; // The received packet queue - CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue - CHash* m_pHash; // Hash table for UDT socket looking up - CChannel* m_pChannel; // UDP channel for receving packets - srt::sync::CTimer* m_pTimer; // shared timer with the snd queue + CUnitQueue m_UnitQueue; // The received packet queue + CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue + CHash* m_pHash; // Hash table for UDT socket looking up + CChannel* m_pChannel; // UDP channel for receving packets + srt::sync::CTimer* m_pTimer; // shared timer with the snd queue - size_t m_szPayloadSize; // packet payload size + size_t m_szPayloadSize; // packet payload size - volatile bool m_bClosing; // closing the worker + volatile bool m_bClosing; // closing the worker #if ENABLE_LOGGING - static int m_counter; + static int m_counter; #endif private: - int setListener(CUDT* u); - void removeListener(const CUDT* u); + int setListener(CUDT* u); + void removeListener(const CUDT* u); - void registerConnector(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const srt::sync::steady_clock::time_point& ttl); - void removeConnector(const SRTSOCKET& id); + void registerConnector(const SRTSOCKET& id, + CUDT* u, + const sockaddr_any& addr, + const srt::sync::steady_clock::time_point& ttl); + void removeConnector(const SRTSOCKET& id); - void setNewEntry(CUDT* u); - bool ifNewEntry(); - CUDT* getNewEntry(); + void setNewEntry(CUDT* u); + bool ifNewEntry(); + CUDT* getNewEntry(); - void storePkt(int32_t id, CPacket* pkt); + void storePkt(int32_t id, CPacket* pkt); private: - srt::sync::Mutex m_LSLock; - CUDT* m_pListener; // pointer to the (unique, if any) listening UDT entity - CRendezvousQueue* m_pRendezvousQueue; // The list of sockets in rendezvous mode + srt::sync::Mutex m_LSLock; + CUDT* m_pListener; // pointer to the (unique, if any) listening UDT entity + CRendezvousQueue* m_pRendezvousQueue; // The list of sockets in rendezvous mode - std::vector m_vNewEntry; // newly added entries, to be inserted - srt::sync::Mutex m_IDLock; + std::vector m_vNewEntry; // newly added entries, to be inserted + srt::sync::Mutex m_IDLock; - std::map > m_mBuffer; // temporary buffer for rendezvous connection request - srt::sync::Mutex m_BufferLock; - srt::sync::Condition m_BufferCond; + std::map > m_mBuffer; // temporary buffer for rendezvous connection request + srt::sync::Mutex m_BufferLock; + srt::sync::Condition m_BufferCond; private: - CRcvQueue(const CRcvQueue&); - CRcvQueue& operator=(const CRcvQueue&); + CRcvQueue(const CRcvQueue&); + CRcvQueue& operator=(const CRcvQueue&); }; struct CMultiplexer { - CSndQueue* m_pSndQueue; // The sending queue - CRcvQueue* m_pRcvQueue; // The receiving queue - CChannel* m_pChannel; // The UDP channel for sending and receiving - srt::sync::CTimer* m_pTimer; // The timer - - int m_iPort; // The UDP port number of this multiplexer - int m_iIPversion; // Address family (AF_INET or AF_INET6) - int m_iRefCount; // number of UDT instances that are associated with this multiplexer - - CSrtMuxerConfig m_mcfg; - - int m_iID; // multiplexer ID - - // Constructor should reset all pointers to NULL - // to prevent dangling pointer when checking for memory alloc fails - CMultiplexer() - : m_pSndQueue(NULL) - , m_pRcvQueue(NULL) - , m_pChannel(NULL) - , m_pTimer(NULL) + CSndQueue* m_pSndQueue; // The sending queue + CRcvQueue* m_pRcvQueue; // The receiving queue + CChannel* m_pChannel; // The UDP channel for sending and receiving + srt::sync::CTimer* m_pTimer; // The timer + + int m_iPort; // The UDP port number of this multiplexer + int m_iIPversion; // Address family (AF_INET or AF_INET6) + int m_iRefCount; // number of UDT instances that are associated with this multiplexer + + CSrtMuxerConfig m_mcfg; + + int m_iID; // multiplexer ID + + // Constructor should reset all pointers to NULL + // to prevent dangling pointer when checking for memory alloc fails + CMultiplexer() + : m_pSndQueue(NULL) + , m_pRcvQueue(NULL) + , m_pChannel(NULL) + , m_pTimer(NULL) { } - void destroy(); + void destroy(); }; #endif From 445a60c19cbda6dbf24087910f5b868d90a6bddc Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 19 May 2021 12:14:03 +0200 Subject: [PATCH 015/124] [core] Refax: placing SRT classes inside 'srt' namespace. CUDT, CUDTUnited, CUDTSocket, CUDTGroup, etc. --- srtcore/api.cpp | 370 ++++++++++++++++------------------- srtcore/api.h | 38 ++-- srtcore/buffer.cpp | 15 +- srtcore/buffer.h | 16 +- srtcore/channel.cpp | 43 ++-- srtcore/channel.h | 7 +- srtcore/common.cpp | 1 + srtcore/common.h | 12 +- srtcore/congctl.cpp | 1 + srtcore/congctl.h | 18 +- srtcore/core.cpp | 238 +++++++++++----------- srtcore/core.h | 27 +-- srtcore/crypto.cpp | 1 + srtcore/crypto.h | 14 +- srtcore/epoll.h | 13 +- srtcore/fec.cpp | 13 +- srtcore/fec.h | 4 + srtcore/group.cpp | 4 + srtcore/group.h | 62 +++--- srtcore/handshake.cpp | 25 +-- srtcore/packet.cpp | 68 ++++--- srtcore/packet.h | 8 +- srtcore/packetfilter.cpp | 44 +++-- srtcore/packetfilter.h | 4 + srtcore/packetfilter_api.h | 4 +- srtcore/queue.cpp | 134 ++++++------- srtcore/queue.h | 72 +++---- srtcore/socketconfig.h | 16 +- srtcore/srt_c_api.cpp | 1 + srtcore/udt.h | 2 +- srtcore/window.cpp | 4 +- srtcore/window.h | 8 +- test/test_buffer.cpp | 2 + test/test_fec_rebuilding.cpp | 21 +- test/test_seqno.cpp | 2 + test/test_unitqueue.cpp | 3 +- testing/testmedia.cpp | 2 +- 37 files changed, 686 insertions(+), 631 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 542832f77..44a068764 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -83,7 +83,7 @@ using namespace srt::sync; extern LogConfig srt_logger_config; -void CUDTSocket::construct() +void srt::CUDTSocket::construct() { #if ENABLE_EXPERIMENTAL_BONDING m_GroupOf = NULL; @@ -94,7 +94,7 @@ void CUDTSocket::construct() setupMutex(m_ControlLock, "Control"); } -CUDTSocket::~CUDTSocket() +srt::CUDTSocket::~CUDTSocket() { delete m_pUDT; @@ -106,7 +106,7 @@ CUDTSocket::~CUDTSocket() } -SRT_SOCKSTATUS CUDTSocket::getStatus() +SRT_SOCKSTATUS srt::CUDTSocket::getStatus() { // TTL in CRendezvousQueue::updateConnStatus() will set m_bConnecting to false. // Although m_Status is still SRTS_CONNECTING, the connection is in fact to be closed due to TTL expiry. @@ -124,7 +124,7 @@ SRT_SOCKSTATUS CUDTSocket::getStatus() } // [[using locked(m_GlobControlLock)]] -void CUDTSocket::breakSocket_LOCKED() +void srt::CUDTSocket::breakSocket_LOCKED() { // This function is intended to be called from GC, // under a lock of m_GlobControlLock. @@ -135,7 +135,7 @@ void CUDTSocket::breakSocket_LOCKED() setClosed(); } -void CUDTSocket::setClosed() +void srt::CUDTSocket::setClosed() { m_Status = SRTS_CLOSED; @@ -146,14 +146,14 @@ void CUDTSocket::setClosed() m_tsClosureTimeStamp = steady_clock::now(); } -void CUDTSocket::setBrokenClosed() +void srt::CUDTSocket::setBrokenClosed() { m_pUDT->m_iBrokenCounter = 60; m_pUDT->m_bBroken = true; setClosed(); } -bool CUDTSocket::readReady() +bool srt::CUDTSocket::readReady() { if (m_pUDT->m_bConnected && m_pUDT->m_pRcvBuffer->isRcvDataReady()) return true; @@ -165,33 +165,33 @@ bool CUDTSocket::readReady() return broken(); } -bool CUDTSocket::writeReady() const +bool srt::CUDTSocket::writeReady() const { return (m_pUDT->m_bConnected && (m_pUDT->m_pSndBuffer->getCurrBufSize() < m_pUDT->m_config.iSndBufSize)) || broken(); } -bool CUDTSocket::broken() const +bool srt::CUDTSocket::broken() const { return m_pUDT->m_bBroken || !m_pUDT->m_bConnected; } //////////////////////////////////////////////////////////////////////////////// -CUDTUnited::CUDTUnited(): -m_Sockets(), -m_GlobControlLock(), -m_IDLock(), -m_mMultiplexer(), -m_MultiplexerLock(), -m_pCache(NULL), -m_bClosing(false), -m_GCStopCond(), -m_InitLock(), -m_iInstanceCount(0), -m_bGCStatus(false), -m_ClosedSockets() +srt::CUDTUnited::CUDTUnited(): + m_Sockets(), + m_GlobControlLock(), + m_IDLock(), + m_mMultiplexer(), + m_MultiplexerLock(), + m_pCache(NULL), + m_bClosing(false), + m_GCStopCond(), + m_InitLock(), + m_iInstanceCount(0), + m_bGCStatus(false), + m_ClosedSockets() { // Socket ID MUST start from a random value m_SocketIDGenerator = genRandomInt(1, MAX_SOCKET_VAL); @@ -207,7 +207,7 @@ m_ClosedSockets() m_pCache = new CCache; } -CUDTUnited::~CUDTUnited() +srt::CUDTUnited::~CUDTUnited() { // Call it if it wasn't called already. // This will happen at the end of main() of the application, @@ -224,7 +224,7 @@ CUDTUnited::~CUDTUnited() delete m_pCache; } -std::string CUDTUnited::CONID(SRTSOCKET sock) +string srt::CUDTUnited::CONID(SRTSOCKET sock) { if ( sock == 0 ) return ""; @@ -234,7 +234,7 @@ std::string CUDTUnited::CONID(SRTSOCKET sock) return os.str(); } -int CUDTUnited::startup() +int srt::CUDTUnited::startup() { ScopedLock gcinit(m_InitLock); @@ -277,7 +277,7 @@ int CUDTUnited::startup() return 0; } -int CUDTUnited::cleanup() +int srt::CUDTUnited::cleanup() { // IMPORTANT!!! // In this function there must be NO LOGGING AT ALL. This function may @@ -324,7 +324,7 @@ int CUDTUnited::cleanup() return 0; } -SRTSOCKET CUDTUnited::generateSocketID(bool for_group) +SRTSOCKET srt::CUDTUnited::generateSocketID(bool for_group) { ScopedLock guard(m_IDLock); @@ -426,7 +426,7 @@ SRTSOCKET CUDTUnited::generateSocketID(bool for_group) return sockval; } -SRTSOCKET CUDTUnited::newSocket(CUDTSocket** pps) +SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps) { // XXX consider using some replacement of std::unique_ptr // so that exceptions will clean up the object without the @@ -484,7 +484,7 @@ SRTSOCKET CUDTUnited::newSocket(CUDTSocket** pps) return ns->m_SocketID; } -int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& peer, const CPacket& hspkt, +int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& peer, const CPacket& hspkt, CHandShake& w_hs, int& w_error, CUDT*& w_acpu) { CUDTSocket* ns = NULL; @@ -852,12 +852,12 @@ int CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& peer, } // static forwarder -int CUDT::installAcceptHook(SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) +int srt::CUDT::installAcceptHook(SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) { return s_UDTUnited.installAcceptHook(lsn, hook, opaq); } -int CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) +int srt::CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) { try { @@ -873,12 +873,12 @@ int CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* h return 0; } -int CUDT::installConnectHook(SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq) +int srt::CUDT::installConnectHook(SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq) { return s_UDTUnited.installConnectHook(lsn, hook, opaq); } -int CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_fn* hook, void* opaq) +int srt::CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_fn* hook, void* opaq) { try { @@ -902,7 +902,7 @@ int CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_fn* h return 0; } -SRT_SOCKSTATUS CUDTUnited::getStatus(const SRTSOCKET u) +SRT_SOCKSTATUS srt::CUDTUnited::getStatus(const SRTSOCKET u) { // protects the m_Sockets structure ScopedLock cg(m_GlobControlLock); @@ -919,7 +919,7 @@ SRT_SOCKSTATUS CUDTUnited::getStatus(const SRTSOCKET u) return i->second->getStatus(); } -int CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) +int srt::CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) { ScopedLock cg(s->m_ControlLock); @@ -937,7 +937,7 @@ int CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) return 0; } -int CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) +int srt::CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) { ScopedLock cg(s->m_ControlLock); @@ -966,7 +966,7 @@ int CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) return 0; } -int CUDTUnited::listen(const SRTSOCKET u, int backlog) +int srt::CUDTUnited::listen(const SRTSOCKET u, int backlog) { if (backlog <= 0) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -1012,7 +1012,7 @@ int CUDTUnited::listen(const SRTSOCKET u, int backlog) return 0; } -SRTSOCKET CUDTUnited::accept_bond(const SRTSOCKET listeners [], int lsize, int64_t msTimeOut) +SRTSOCKET srt::CUDTUnited::accept_bond(const SRTSOCKET listeners [], int lsize, int64_t msTimeOut) { CEPollDesc* ed = 0; int eid = m_EPoll.create(&ed); @@ -1056,7 +1056,7 @@ SRTSOCKET CUDTUnited::accept_bond(const SRTSOCKET listeners [], int lsize, int64 return accept(lsn, ((sockaddr*)&dummy), (&outlen)); } -SRTSOCKET CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int* pw_addrlen) +SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int* pw_addrlen) { if (pw_addr && !pw_addrlen) { @@ -1190,7 +1190,7 @@ SRTSOCKET CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int* pw_ return u; } -int CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockaddr* tarname, int namelen) +int srt::CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockaddr* tarname, int namelen) { // Here both srcname and tarname must be specified if (!srcname || !tarname || size_t(namelen) < sizeof (sockaddr_in)) @@ -1235,7 +1235,7 @@ int CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockaddr* ta return connectIn(s, target_addr, SRT_SEQNO_NONE); } -int CUDTUnited::connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn) +int srt::CUDTUnited::connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn) { sockaddr_any target_addr(name, namelen); if (target_addr.len == 0) @@ -1266,7 +1266,7 @@ int CUDTUnited::connect(const SRTSOCKET u, const sockaddr* name, int namelen, in } #if ENABLE_EXPERIMENTAL_BONDING -int CUDTUnited::singleMemberConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* gd) +int srt::CUDTUnited::singleMemberConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* gd) { int gstat = groupConnect(pg, gd, 1); if (gstat == -1) @@ -1286,7 +1286,7 @@ int CUDTUnited::singleMemberConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* gd) } // [[using assert(pg->m_iBusy > 0)]] -int CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, int arraysize) +int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, int arraysize) { CUDTGroup& g = *pg; SRT_ASSERT(g.m_iBusy > 0); @@ -1822,7 +1822,7 @@ int CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, int ar #endif -int CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, int32_t forced_isn) +int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, int32_t forced_isn) { ScopedLock cg(s->m_ControlLock); // a socket can "connect" only if it is in the following states: @@ -1892,7 +1892,7 @@ int CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, int32_ } -int CUDTUnited::close(const SRTSOCKET u) +int srt::CUDTUnited::close(const SRTSOCKET u) { #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) @@ -1911,7 +1911,7 @@ int CUDTUnited::close(const SRTSOCKET u) } #if ENABLE_EXPERIMENTAL_BONDING -void CUDTUnited::deleteGroup(CUDTGroup* g) +void srt::CUDTUnited::deleteGroup(CUDTGroup* g) { using srt_logging::gmlog; @@ -1920,7 +1920,7 @@ void CUDTUnited::deleteGroup(CUDTGroup* g) } // [[using locked(m_GlobControlLock)]] -void CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g) +void srt::CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g) { SRT_ASSERT(g->groupEmpty()); @@ -1960,7 +1960,7 @@ void CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g) } #endif -int CUDTUnited::close(CUDTSocket* s) +int srt::CUDTUnited::close(CUDTSocket* s) { HLOGC(smlog.Debug, log << s->m_pUDT->CONID() << " CLOSE. Acquiring control lock"); @@ -2118,7 +2118,7 @@ int CUDTUnited::close(CUDTSocket* s) return 0; } -void CUDTUnited::getpeername(const SRTSOCKET u, sockaddr* pw_name, int* pw_namelen) +void srt::CUDTUnited::getpeername(const SRTSOCKET u, sockaddr* pw_name, int* pw_namelen) { if (!pw_name || !pw_namelen) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -2142,7 +2142,7 @@ void CUDTUnited::getpeername(const SRTSOCKET u, sockaddr* pw_name, int* pw_namel *pw_namelen = len; } -void CUDTUnited::getsockname(const SRTSOCKET u, sockaddr* pw_name, int* pw_namelen) +void srt::CUDTUnited::getsockname(const SRTSOCKET u, sockaddr* pw_name, int* pw_namelen) { if (!pw_name || !pw_namelen) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -2166,7 +2166,7 @@ void CUDTUnited::getsockname(const SRTSOCKET u, sockaddr* pw_name, int* pw_namel *pw_namelen = len; } -int CUDTUnited::select( +int srt::CUDTUnited::select( UDT::UDSET* readfds, UDT::UDSET* writefds, UDT::UDSET* exceptfds, const timeval* timeout) { const steady_clock::time_point entertime = steady_clock::now(); @@ -2276,7 +2276,7 @@ int CUDTUnited::select( return count; } -int CUDTUnited::selectEx( +int srt::CUDTUnited::selectEx( const vector& fds, vector* readfds, vector* writefds, @@ -2350,17 +2350,17 @@ int CUDTUnited::selectEx( return count; } -int CUDTUnited::epoll_create() +int srt::CUDTUnited::epoll_create() { return m_EPoll.create(); } -int CUDTUnited::epoll_clear_usocks(int eid) +int srt::CUDTUnited::epoll_clear_usocks(int eid) { return m_EPoll.clear_usocks(eid); } -int CUDTUnited::epoll_add_usock( +int srt::CUDTUnited::epoll_add_usock( const int eid, const SRTSOCKET u, const int* events) { int ret = -1; @@ -2390,27 +2390,27 @@ int CUDTUnited::epoll_add_usock( // NOTE: WILL LOCK (serially): // - CEPoll::m_EPollLock // - CUDT::m_RecvLock -int CUDTUnited::epoll_add_usock_INTERNAL(const int eid, CUDTSocket* s, const int* events) +int srt::CUDTUnited::epoll_add_usock_INTERNAL(const int eid, CUDTSocket* s, const int* events) { int ret = m_EPoll.update_usock(eid, s->m_SocketID, events); s->m_pUDT->addEPoll(eid); return ret; } -int CUDTUnited::epoll_add_ssock( +int srt::CUDTUnited::epoll_add_ssock( const int eid, const SYSSOCKET s, const int* events) { return m_EPoll.add_ssock(eid, s, events); } -int CUDTUnited::epoll_update_ssock( +int srt::CUDTUnited::epoll_update_ssock( const int eid, const SYSSOCKET s, const int* events) { return m_EPoll.update_ssock(eid, s, events); } template -int CUDTUnited::epoll_remove_entity(const int eid, EntityType* ent) +int srt::CUDTUnited::epoll_remove_entity(const int eid, EntityType* ent) { // XXX Not sure if this is anyhow necessary because setting readiness // to false doesn't actually trigger any action. Further research needed. @@ -2432,19 +2432,19 @@ int CUDTUnited::epoll_remove_entity(const int eid, EntityType* ent) } // Needed internal access! -int CUDTUnited::epoll_remove_socket_INTERNAL(const int eid, CUDTSocket* s) +int srt::CUDTUnited::epoll_remove_socket_INTERNAL(const int eid, CUDTSocket* s) { return epoll_remove_entity(eid, s->m_pUDT); } #if ENABLE_EXPERIMENTAL_BONDING -int CUDTUnited::epoll_remove_group_INTERNAL(const int eid, CUDTGroup* g) +int srt::CUDTUnited::epoll_remove_group_INTERNAL(const int eid, CUDTGroup* g) { return epoll_remove_entity(eid, g); } #endif -int CUDTUnited::epoll_remove_usock(const int eid, const SRTSOCKET u) +int srt::CUDTUnited::epoll_remove_usock(const int eid, const SRTSOCKET u) { CUDTSocket* s = 0; @@ -2470,12 +2470,12 @@ int CUDTUnited::epoll_remove_usock(const int eid, const SRTSOCKET u) return m_EPoll.update_usock(eid, u, &no_events); } -int CUDTUnited::epoll_remove_ssock(const int eid, const SYSSOCKET s) +int srt::CUDTUnited::epoll_remove_ssock(const int eid, const SYSSOCKET s) { return m_EPoll.remove_ssock(eid, s); } -int CUDTUnited::epoll_uwait( +int srt::CUDTUnited::epoll_uwait( const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, @@ -2484,17 +2484,17 @@ int CUDTUnited::epoll_uwait( return m_EPoll.uwait(eid, fdsSet, fdsSize, msTimeOut); } -int32_t CUDTUnited::epoll_set(int eid, int32_t flags) +int32_t srt::CUDTUnited::epoll_set(int eid, int32_t flags) { return m_EPoll.setflags(eid, flags); } -int CUDTUnited::epoll_release(const int eid) +int srt::CUDTUnited::epoll_release(const int eid) { return m_EPoll.release(eid); } -CUDTSocket* CUDTUnited::locateSocket(const SRTSOCKET u, ErrorHandling erh) +srt::CUDTSocket* srt::CUDTUnited::locateSocket(const SRTSOCKET u, ErrorHandling erh) { ScopedLock cg (m_GlobControlLock); CUDTSocket* s = locateSocket_LOCKED(u); @@ -2509,7 +2509,7 @@ CUDTSocket* CUDTUnited::locateSocket(const SRTSOCKET u, ErrorHandling erh) } // [[using locked(m_GlobControlLock)]]; -CUDTSocket* CUDTUnited::locateSocket_LOCKED(SRTSOCKET u) +srt::CUDTSocket* srt::CUDTUnited::locateSocket_LOCKED(SRTSOCKET u) { sockets_t::iterator i = m_Sockets.find(u); @@ -2522,7 +2522,7 @@ CUDTSocket* CUDTUnited::locateSocket_LOCKED(SRTSOCKET u) } #if ENABLE_EXPERIMENTAL_BONDING -CUDTGroup* CUDTUnited::locateAcquireGroup(SRTSOCKET u, ErrorHandling erh) +srt::CUDTGroup* srt::CUDTUnited::locateAcquireGroup(SRTSOCKET u, ErrorHandling erh) { ScopedLock cg (m_GlobControlLock); @@ -2539,7 +2539,7 @@ CUDTGroup* CUDTUnited::locateAcquireGroup(SRTSOCKET u, ErrorHandling erh) return i->second; } -CUDTGroup* CUDTUnited::acquireSocketsGroup(CUDTSocket* s) +srt::CUDTGroup* srt::CUDTUnited::acquireSocketsGroup(CUDTSocket* s) { ScopedLock cg (m_GlobControlLock); CUDTGroup* g = s->m_GroupOf; @@ -2553,7 +2553,7 @@ CUDTGroup* CUDTUnited::acquireSocketsGroup(CUDTSocket* s) } #endif -CUDTSocket* CUDTUnited::locatePeer( +srt::CUDTSocket* srt::CUDTUnited::locatePeer( const sockaddr_any& peer, const SRTSOCKET id, int32_t isn) @@ -2582,7 +2582,7 @@ CUDTSocket* CUDTUnited::locatePeer( return NULL; } -void CUDTUnited::checkBrokenSockets() +void srt::CUDTUnited::checkBrokenSockets() { ScopedLock cg(m_GlobControlLock); @@ -2724,7 +2724,7 @@ void CUDTUnited::checkBrokenSockets() } // [[using locked(m_GlobControlLock)]] -void CUDTUnited::removeSocket(const SRTSOCKET u) +void srt::CUDTUnited::removeSocket(const SRTSOCKET u) { sockets_t::iterator i = m_ClosedSockets.find(u); @@ -2829,7 +2829,7 @@ void CUDTUnited::removeSocket(const SRTSOCKET u) } } -void CUDTUnited::updateMux( +void srt::CUDTUnited::updateMux( CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/) { ScopedLock cg(m_GlobControlLock); @@ -2943,7 +2943,7 @@ void CUDTUnited::updateMux( // exists, otherwise the dispatching procedure wouldn't even call this // function. By historical reasons there's also a fallback for a case when the // multiplexer wasn't found by id, the search by port number continues. -bool CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) +bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) { ScopedLock cg(m_GlobControlLock); const int port = ls->m_SelfAddr.hport(); @@ -3026,7 +3026,7 @@ bool CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) return false; } -void* CUDTUnited::garbageCollect(void* p) +void* srt::CUDTUnited::garbageCollect(void* p) { CUDTUnited* self = (CUDTUnited*)p; @@ -3108,17 +3108,17 @@ void* CUDTUnited::garbageCollect(void* p) //////////////////////////////////////////////////////////////////////////////// -int CUDT::startup() +int srt::CUDT::startup() { return s_UDTUnited.startup(); } -int CUDT::cleanup() +int srt::CUDT::cleanup() { return s_UDTUnited.cleanup(); } -SRTSOCKET CUDT::socket() +SRTSOCKET srt::CUDT::socket() { if (!s_UDTUnited.m_bGCStatus) s_UDTUnited.startup(); @@ -3147,12 +3147,12 @@ SRTSOCKET CUDT::socket() } } -CUDT::APIError::APIError(const CUDTException& e) +srt::CUDT::APIError::APIError(const CUDTException& e) { SetThreadLocalError(e); } -CUDT::APIError::APIError(CodeMajor mj, CodeMinor mn, int syserr) +srt::CUDT::APIError::APIError(CodeMajor mj, CodeMinor mn, int syserr) { SetThreadLocalError(CUDTException(mj, mn, syserr)); } @@ -3162,7 +3162,7 @@ CUDT::APIError::APIError(CodeMajor mj, CodeMinor mn, int syserr) // This doesn't have argument of GroupType due to header file conflicts. // [[using locked(s_UDTUnited.m_GlobControlLock)]] -CUDTGroup& CUDT::newGroup(const int type) +srt::CUDTGroup& srt::CUDT::newGroup(const int type) { const SRTSOCKET id = s_UDTUnited.generateSocketID(true); @@ -3170,7 +3170,7 @@ CUDTGroup& CUDT::newGroup(const int type) return s_UDTUnited.addGroup(id, SRT_GROUP_TYPE(type)).set_id(id); } -SRTSOCKET CUDT::createGroup(SRT_GROUP_TYPE gt) +SRTSOCKET srt::CUDT::createGroup(SRT_GROUP_TYPE gt) { // Doing the same lazy-startup as with srt_create_socket() if (!s_UDTUnited.m_bGCStatus) @@ -3199,7 +3199,7 @@ SRTSOCKET CUDT::createGroup(SRT_GROUP_TYPE gt) } -int CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) +int srt::CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) { // Check if socket and group have been set correctly. int32_t sid = socket & ~SRTGROUP_MASK; @@ -3253,7 +3253,7 @@ int CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) // dead function as for now. This is only for non-managed // groups. -int CUDT::removeSocketFromGroup(SRTSOCKET socket) +int srt::CUDT::removeSocketFromGroup(SRTSOCKET socket) { CUDTSocket* s = s_UDTUnited.locateSocket(socket); if (!s) @@ -3270,7 +3270,7 @@ int CUDT::removeSocketFromGroup(SRTSOCKET socket) // [[using locked(m_ControlLock)]] // [[using locked(CUDT::s_UDTUnited.m_GlobControlLock)]] -void CUDTSocket::removeFromGroup(bool broken) +void srt::CUDTSocket::removeFromGroup(bool broken) { CUDTGroup* g = m_GroupOf; if (g) @@ -3299,7 +3299,7 @@ void CUDTSocket::removeFromGroup(bool broken) } } -SRTSOCKET CUDT::getGroupOfSocket(SRTSOCKET socket) +SRTSOCKET srt::CUDT::getGroupOfSocket(SRTSOCKET socket) { // Lock this for the whole function as we need the group // to persist the call. @@ -3311,7 +3311,7 @@ SRTSOCKET CUDT::getGroupOfSocket(SRTSOCKET socket) return s->m_GroupOf->id(); } -int CUDT::configureGroup(SRTSOCKET groupid, const char* str) +int srt::CUDT::configureGroup(SRTSOCKET groupid, const char* str) { if ( (groupid & SRTGROUP_MASK) == 0) { @@ -3327,7 +3327,7 @@ int CUDT::configureGroup(SRTSOCKET groupid, const char* str) return k.group->configure(str); } -int CUDT::getGroupData(SRTSOCKET groupid, SRT_SOCKGROUPDATA* pdata, size_t* psize) +int srt::CUDT::getGroupData(SRTSOCKET groupid, SRT_SOCKGROUPDATA* pdata, size_t* psize) { if ((groupid & SRTGROUP_MASK) == 0 || !psize) { @@ -3345,7 +3345,7 @@ int CUDT::getGroupData(SRTSOCKET groupid, SRT_SOCKGROUPDATA* pdata, size_t* psiz } #endif -int CUDT::bind(SRTSOCKET u, const sockaddr* name, int namelen) +int srt::CUDT::bind(SRTSOCKET u, const sockaddr* name, int namelen) { try { @@ -3381,7 +3381,7 @@ int CUDT::bind(SRTSOCKET u, const sockaddr* name, int namelen) } } -int CUDT::bind(SRTSOCKET u, UDPSOCKET udpsock) +int srt::CUDT::bind(SRTSOCKET u, UDPSOCKET udpsock) { try { @@ -3407,7 +3407,7 @@ int CUDT::bind(SRTSOCKET u, UDPSOCKET udpsock) } } -int CUDT::listen(SRTSOCKET u, int backlog) +int srt::CUDT::listen(SRTSOCKET u, int backlog) { try { @@ -3429,7 +3429,7 @@ int CUDT::listen(SRTSOCKET u, int backlog) } } -SRTSOCKET CUDT::accept_bond(const SRTSOCKET listeners [], int lsize, int64_t msTimeOut) +SRTSOCKET srt::CUDT::accept_bond(const SRTSOCKET listeners [], int lsize, int64_t msTimeOut) { try { @@ -3454,7 +3454,7 @@ SRTSOCKET CUDT::accept_bond(const SRTSOCKET listeners [], int lsize, int64_t msT } } -SRTSOCKET CUDT::accept(SRTSOCKET u, sockaddr* addr, int* addrlen) +SRTSOCKET srt::CUDT::accept(SRTSOCKET u, sockaddr* addr, int* addrlen) { try { @@ -3479,7 +3479,7 @@ SRTSOCKET CUDT::accept(SRTSOCKET u, sockaddr* addr, int* addrlen) } } -int CUDT::connect( +int srt::CUDT::connect( SRTSOCKET u, const sockaddr* name, const sockaddr* tname, int namelen) { try @@ -3503,7 +3503,7 @@ int CUDT::connect( } #if ENABLE_EXPERIMENTAL_BONDING -int CUDT::connectLinks(SRTSOCKET grp, +int srt::CUDT::connectLinks(SRTSOCKET grp, SRT_SOCKGROUPCONFIG targets [], int arraysize) { if (arraysize <= 0) @@ -3537,7 +3537,7 @@ int CUDT::connectLinks(SRTSOCKET grp, } #endif -int CUDT::connect( +int srt::CUDT::connect( SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn) { try @@ -3560,7 +3560,7 @@ int CUDT::connect( } } -int CUDT::close(SRTSOCKET u) +int srt::CUDT::close(SRTSOCKET u) { try { @@ -3578,7 +3578,7 @@ int CUDT::close(SRTSOCKET u) } } -int CUDT::getpeername(SRTSOCKET u, sockaddr* name, int* namelen) +int srt::CUDT::getpeername(SRTSOCKET u, sockaddr* name, int* namelen) { try { @@ -3597,7 +3597,7 @@ int CUDT::getpeername(SRTSOCKET u, sockaddr* name, int* namelen) } } -int CUDT::getsockname(SRTSOCKET u, sockaddr* name, int* namelen) +int srt::CUDT::getsockname(SRTSOCKET u, sockaddr* name, int* namelen) { try { @@ -3616,7 +3616,7 @@ int CUDT::getsockname(SRTSOCKET u, sockaddr* name, int* namelen) } } -int CUDT::getsockopt( +int srt::CUDT::getsockopt( SRTSOCKET u, int, SRT_SOCKOPT optname, void* pw_optval, int* pw_optlen) { if (!pw_optval || !pw_optlen) @@ -3651,7 +3651,7 @@ int CUDT::getsockopt( } } -int CUDT::setsockopt(SRTSOCKET u, int, SRT_SOCKOPT optname, const void* optval, int optlen) +int srt::CUDT::setsockopt(SRTSOCKET u, int, SRT_SOCKOPT optname, const void* optval, int optlen) { if (!optval) return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3683,7 +3683,7 @@ int CUDT::setsockopt(SRTSOCKET u, int, SRT_SOCKOPT optname, const void* optval, } } -int CUDT::send(SRTSOCKET u, const char* buf, int len, int) +int srt::CUDT::send(SRTSOCKET u, const char* buf, int len, int) { SRT_MSGCTRL mctrl = srt_msgctrl_default; return sendmsg2(u, buf, len, (mctrl)); @@ -3691,7 +3691,7 @@ int CUDT::send(SRTSOCKET u, const char* buf, int len, int) // --> CUDT::recv moved down -int CUDT::sendmsg( +int srt::CUDT::sendmsg( SRTSOCKET u, const char* buf, int len, int ttl, bool inorder, int64_t srctime) { @@ -3702,7 +3702,7 @@ int CUDT::sendmsg( return sendmsg2(u, buf, len, (mctrl)); } -int CUDT::sendmsg2( +int srt::CUDT::sendmsg2( SRTSOCKET u, const char* buf, int len, SRT_MSGCTRL& w_m) { try @@ -3733,14 +3733,14 @@ int CUDT::sendmsg2( } } -int CUDT::recv(SRTSOCKET u, char* buf, int len, int) +int srt::CUDT::recv(SRTSOCKET u, char* buf, int len, int) { SRT_MSGCTRL mctrl = srt_msgctrl_default; int ret = recvmsg2(u, buf, len, (mctrl)); return ret; } -int CUDT::recvmsg(SRTSOCKET u, char* buf, int len, int64_t& srctime) +int srt::CUDT::recvmsg(SRTSOCKET u, char* buf, int len, int64_t& srctime) { SRT_MSGCTRL mctrl = srt_msgctrl_default; int ret = recvmsg2(u, buf, len, (mctrl)); @@ -3748,7 +3748,7 @@ int CUDT::recvmsg(SRTSOCKET u, char* buf, int len, int64_t& srctime) return ret; } -int CUDT::recvmsg2(SRTSOCKET u, char* buf, int len, SRT_MSGCTRL& w_m) +int srt::CUDT::recvmsg2(SRTSOCKET u, char* buf, int len, SRT_MSGCTRL& w_m) { try { @@ -3774,7 +3774,7 @@ int CUDT::recvmsg2(SRTSOCKET u, char* buf, int len, SRT_MSGCTRL& w_m) } } -int64_t CUDT::sendfile( +int64_t srt::CUDT::sendfile( SRTSOCKET u, fstream& ifs, int64_t& offset, int64_t size, int block) { try @@ -3798,7 +3798,7 @@ int64_t CUDT::sendfile( } } -int64_t CUDT::recvfile( +int64_t srt::CUDT::recvfile( SRTSOCKET u, fstream& ofs, int64_t& offset, int64_t size, int block) { try @@ -3817,7 +3817,7 @@ int64_t CUDT::recvfile( } } -int CUDT::select( +int srt::CUDT::select( int, UDT::UDSET* readfds, UDT::UDSET* writefds, @@ -3849,7 +3849,7 @@ int CUDT::select( } } -int CUDT::selectEx( +int srt::CUDT::selectEx( const vector& fds, vector* readfds, vector* writefds, @@ -3881,7 +3881,7 @@ int CUDT::selectEx( } } -int CUDT::epoll_create() +int srt::CUDT::epoll_create() { try { @@ -3899,7 +3899,7 @@ int CUDT::epoll_create() } } -int CUDT::epoll_clear_usocks(int eid) +int srt::CUDT::epoll_clear_usocks(int eid) { try { @@ -3917,7 +3917,7 @@ int CUDT::epoll_clear_usocks(int eid) } } -int CUDT::epoll_add_usock(const int eid, const SRTSOCKET u, const int* events) +int srt::CUDT::epoll_add_usock(const int eid, const SRTSOCKET u, const int* events) { try { @@ -3935,7 +3935,7 @@ int CUDT::epoll_add_usock(const int eid, const SRTSOCKET u, const int* events) } } -int CUDT::epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events) +int srt::CUDT::epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events) { try { @@ -3953,7 +3953,7 @@ int CUDT::epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events) } } -int CUDT::epoll_update_usock( +int srt::CUDT::epoll_update_usock( const int eid, const SRTSOCKET u, const int* events) { try @@ -3972,7 +3972,7 @@ int CUDT::epoll_update_usock( } } -int CUDT::epoll_update_ssock( +int srt::CUDT::epoll_update_ssock( const int eid, const SYSSOCKET s, const int* events) { try @@ -3992,7 +3992,7 @@ int CUDT::epoll_update_ssock( } -int CUDT::epoll_remove_usock(const int eid, const SRTSOCKET u) +int srt::CUDT::epoll_remove_usock(const int eid, const SRTSOCKET u) { try { @@ -4010,7 +4010,7 @@ int CUDT::epoll_remove_usock(const int eid, const SRTSOCKET u) } } -int CUDT::epoll_remove_ssock(const int eid, const SYSSOCKET s) +int srt::CUDT::epoll_remove_ssock(const int eid, const SYSSOCKET s) { try { @@ -4028,7 +4028,7 @@ int CUDT::epoll_remove_ssock(const int eid, const SYSSOCKET s) } } -int CUDT::epoll_wait( +int srt::CUDT::epoll_wait( const int eid, set* readfds, set* writefds, @@ -4053,7 +4053,7 @@ int CUDT::epoll_wait( } } -int CUDT::epoll_uwait( +int srt::CUDT::epoll_uwait( const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, @@ -4075,7 +4075,7 @@ int CUDT::epoll_uwait( } } -int32_t CUDT::epoll_set( +int32_t srt::CUDT::epoll_set( const int eid, int32_t flags) { @@ -4095,7 +4095,7 @@ int32_t CUDT::epoll_set( } } -int CUDT::epoll_release(const int eid) +int srt::CUDT::epoll_release(const int eid) { try { @@ -4113,12 +4113,12 @@ int CUDT::epoll_release(const int eid) } } -CUDTException& CUDT::getlasterror() +CUDTException& srt::CUDT::getlasterror() { return GetThreadLocalError(); } -int CUDT::bstats(SRTSOCKET u, CBytePerfMon* perf, bool clear, bool instantaneous) +int srt::CUDT::bstats(SRTSOCKET u, CBytePerfMon* perf, bool clear, bool instantaneous) { #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) @@ -4144,7 +4144,7 @@ int CUDT::bstats(SRTSOCKET u, CBytePerfMon* perf, bool clear, bool instantaneous } #if ENABLE_EXPERIMENTAL_BONDING -int CUDT::groupsockbstats(SRTSOCKET u, CBytePerfMon* perf, bool clear) +int srt::CUDT::groupsockbstats(SRTSOCKET u, CBytePerfMon* perf, bool clear) { try { @@ -4167,7 +4167,7 @@ int CUDT::groupsockbstats(SRTSOCKET u, CBytePerfMon* perf, bool clear) } #endif -CUDT* CUDT::getUDTHandle(SRTSOCKET u) +srt::CUDT* srt::CUDT::getUDTHandle(SRTSOCKET u) { try { @@ -4187,7 +4187,7 @@ CUDT* CUDT::getUDTHandle(SRTSOCKET u) } } -vector CUDT::existingSockets() +vector srt::CUDT::existingSockets() { vector out; for (CUDTUnited::sockets_t::iterator i = s_UDTUnited.m_Sockets.begin(); @@ -4198,7 +4198,7 @@ vector CUDT::existingSockets() return out; } -SRT_SOCKSTATUS CUDT::getsockstate(SRTSOCKET u) +SRT_SOCKSTATUS srt::CUDT::getsockstate(SRTSOCKET u) { try { @@ -4225,7 +4225,6 @@ SRT_SOCKSTATUS CUDT::getsockstate(SRTSOCKET u) } } - //////////////////////////////////////////////////////////////////////////////// namespace UDT @@ -4233,64 +4232,64 @@ namespace UDT int startup() { - return CUDT::startup(); + return srt::CUDT::startup(); } int cleanup() { - return CUDT::cleanup(); + return srt::CUDT::cleanup(); } int bind(SRTSOCKET u, const struct sockaddr* name, int namelen) { - return CUDT::bind(u, name, namelen); + return srt::CUDT::bind(u, name, namelen); } int bind2(SRTSOCKET u, UDPSOCKET udpsock) { - return CUDT::bind(u, udpsock); + return srt::CUDT::bind(u, udpsock); } int listen(SRTSOCKET u, int backlog) { - return CUDT::listen(u, backlog); + return srt::CUDT::listen(u, backlog); } SRTSOCKET accept(SRTSOCKET u, struct sockaddr* addr, int* addrlen) { - return CUDT::accept(u, addr, addrlen); + return srt::CUDT::accept(u, addr, addrlen); } int connect(SRTSOCKET u, const struct sockaddr* name, int namelen) { - return CUDT::connect(u, name, namelen, SRT_SEQNO_NONE); + return srt::CUDT::connect(u, name, namelen, SRT_SEQNO_NONE); } int close(SRTSOCKET u) { - return CUDT::close(u); + return srt::CUDT::close(u); } int getpeername(SRTSOCKET u, struct sockaddr* name, int* namelen) { - return CUDT::getpeername(u, name, namelen); + return srt::CUDT::getpeername(u, name, namelen); } int getsockname(SRTSOCKET u, struct sockaddr* name, int* namelen) { - return CUDT::getsockname(u, name, namelen); + return srt::CUDT::getsockname(u, name, namelen); } int getsockopt( SRTSOCKET u, int level, SRT_SOCKOPT optname, void* optval, int* optlen) { - return CUDT::getsockopt(u, level, optname, optval, optlen); + return srt::CUDT::getsockopt(u, level, optname, optval, optlen); } int setsockopt( SRTSOCKET u, int level, SRT_SOCKOPT optname, const void* optval, int optlen) { - return CUDT::setsockopt(u, level, optname, optval, optlen); + return srt::CUDT::setsockopt(u, level, optname, optval, optlen); } // DEVELOPER API @@ -4298,17 +4297,17 @@ int setsockopt( int connect_debug( SRTSOCKET u, const struct sockaddr* name, int namelen, int32_t forced_isn) { - return CUDT::connect(u, name, namelen, forced_isn); + return srt::CUDT::connect(u, name, namelen, forced_isn); } int send(SRTSOCKET u, const char* buf, int len, int flags) { - return CUDT::send(u, buf, len, flags); + return srt::CUDT::send(u, buf, len, flags); } int recv(SRTSOCKET u, char* buf, int len, int flags) { - return CUDT::recv(u, buf, len, flags); + return srt::CUDT::recv(u, buf, len, flags); } @@ -4316,18 +4315,18 @@ int sendmsg( SRTSOCKET u, const char* buf, int len, int ttl, bool inorder, int64_t srctime) { - return CUDT::sendmsg(u, buf, len, ttl, inorder, srctime); + return srt::CUDT::sendmsg(u, buf, len, ttl, inorder, srctime); } int recvmsg(SRTSOCKET u, char* buf, int len, int64_t& srctime) { - return CUDT::recvmsg(u, buf, len, srctime); + return srt::CUDT::recvmsg(u, buf, len, srctime); } int recvmsg(SRTSOCKET u, char* buf, int len) { int64_t srctime; - return CUDT::recvmsg(u, buf, len, srctime); + return srt::CUDT::recvmsg(u, buf, len, srctime); } int64_t sendfile( @@ -4337,7 +4336,7 @@ int64_t sendfile( int64_t size, int block) { - return CUDT::sendfile(u, ifs, offset, size, block); + return srt::CUDT::sendfile(u, ifs, offset, size, block); } int64_t recvfile( @@ -4347,7 +4346,7 @@ int64_t recvfile( int64_t size, int block) { - return CUDT::recvfile(u, ofs, offset, size, block); + return srt::CUDT::recvfile(u, ofs, offset, size, block); } int64_t sendfile2( @@ -4358,7 +4357,7 @@ int64_t sendfile2( int block) { fstream ifs(path, ios::binary | ios::in); - int64_t ret = CUDT::sendfile(u, ifs, *offset, size, block); + int64_t ret = srt::CUDT::sendfile(u, ifs, *offset, size, block); ifs.close(); return ret; } @@ -4371,7 +4370,7 @@ int64_t recvfile2( int block) { fstream ofs(path, ios::binary | ios::out); - int64_t ret = CUDT::recvfile(u, ofs, *offset, size, block); + int64_t ret = srt::CUDT::recvfile(u, ofs, *offset, size, block); ofs.close(); return ret; } @@ -4383,7 +4382,7 @@ int select( UDSET* exceptfds, const struct timeval* timeout) { - return CUDT::select(nfds, readfds, writefds, exceptfds, timeout); + return srt::CUDT::select(nfds, readfds, writefds, exceptfds, timeout); } int selectEx( @@ -4393,47 +4392,47 @@ int selectEx( vector* exceptfds, int64_t msTimeOut) { - return CUDT::selectEx(fds, readfds, writefds, exceptfds, msTimeOut); + return srt::CUDT::selectEx(fds, readfds, writefds, exceptfds, msTimeOut); } int epoll_create() { - return CUDT::epoll_create(); + return srt::CUDT::epoll_create(); } int epoll_clear_usocks(int eid) { - return CUDT::epoll_clear_usocks(eid); + return srt::CUDT::epoll_clear_usocks(eid); } int epoll_add_usock(int eid, SRTSOCKET u, const int* events) { - return CUDT::epoll_add_usock(eid, u, events); + return srt::CUDT::epoll_add_usock(eid, u, events); } int epoll_add_ssock(int eid, SYSSOCKET s, const int* events) { - return CUDT::epoll_add_ssock(eid, s, events); + return srt::CUDT::epoll_add_ssock(eid, s, events); } int epoll_update_usock(int eid, SRTSOCKET u, const int* events) { - return CUDT::epoll_update_usock(eid, u, events); + return srt::CUDT::epoll_update_usock(eid, u, events); } int epoll_update_ssock(int eid, SYSSOCKET s, const int* events) { - return CUDT::epoll_update_ssock(eid, s, events); + return srt::CUDT::epoll_update_ssock(eid, s, events); } int epoll_remove_usock(int eid, SRTSOCKET u) { - return CUDT::epoll_remove_usock(eid, u); + return srt::CUDT::epoll_remove_usock(eid, u); } int epoll_remove_ssock(int eid, SYSSOCKET s) { - return CUDT::epoll_remove_ssock(eid, s); + return srt::CUDT::epoll_remove_ssock(eid, s); } int epoll_wait( @@ -4444,34 +4443,9 @@ int epoll_wait( set* lrfds, set* lwfds) { - return CUDT::epoll_wait(eid, readfds, writefds, msTimeOut, lrfds, lwfds); + return srt::CUDT::epoll_wait(eid, readfds, writefds, msTimeOut, lrfds, lwfds); } -/* - -#define SET_RESULT(val, num, fds, it) \ - if (val != NULL) \ - { \ - if (val->empty()) \ - { \ - if (num) *num = 0; \ - } \ - else \ - { \ - if (*num > static_cast(val->size())) \ - *num = val->size(); \ - int count = 0; \ - for (it = val->begin(); it != val->end(); ++ it) \ - { \ - if (count >= *num) \ - break; \ - fds[count ++] = *it; \ - } \ - } \ - } - -*/ - template inline void set_result(set* val, int* num, SOCKTYPE* fds) { @@ -4524,7 +4498,7 @@ int epoll_wait2( if ((lwfds != NULL) && (lwnum != NULL)) lwval = &lwset; - int ret = CUDT::epoll_wait(eid, rval, wval, msTimeOut, lrval, lwval); + int ret = srt::CUDT::epoll_wait(eid, rval, wval, msTimeOut, lrval, lwval); if (ret > 0) { //set::const_iterator i; @@ -4544,32 +4518,32 @@ int epoll_wait2( int epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut) { - return CUDT::epoll_uwait(eid, fdsSet, fdsSize, msTimeOut); + return srt::CUDT::epoll_uwait(eid, fdsSet, fdsSize, msTimeOut); } int epoll_release(int eid) { - return CUDT::epoll_release(eid); + return srt::CUDT::epoll_release(eid); } ERRORINFO& getlasterror() { - return CUDT::getlasterror(); + return srt::CUDT::getlasterror(); } int getlasterror_code() { - return CUDT::getlasterror().getErrorCode(); + return srt::CUDT::getlasterror().getErrorCode(); } const char* getlasterror_desc() { - return CUDT::getlasterror().getErrorMessage(); + return srt::CUDT::getlasterror().getErrorMessage(); } int getlasterror_errno() { - return CUDT::getlasterror().getErrno(); + return srt::CUDT::getlasterror().getErrno(); } // Get error string of a given error code @@ -4581,12 +4555,12 @@ const char* geterror_desc(int code, int err) int bstats(SRTSOCKET u, SRT_TRACEBSTATS* perf, bool clear) { - return CUDT::bstats(u, perf, clear); + return srt::CUDT::bstats(u, perf, clear); } SRT_SOCKSTATUS getsockstate(SRTSOCKET u) { - return CUDT::getsockstate(u); + return srt::CUDT::getsockstate(u); } } // namespace UDT diff --git a/srtcore/api.h b/srtcore/api.h index 4ca299b24..3ef75c6e7 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -72,6 +72,8 @@ modified by // Please refer to structure and locking information provided in the // docs/dev/low-level-info.md document. +namespace srt { + class CUDT; class CUDTSocket @@ -107,7 +109,7 @@ class CUDTSocket /// of sockets in order to prevent other methods from accessing invalid address. /// A timer is started and the socket will be removed after approximately /// 1 second (see CUDTUnited::checkBrokenSockets()). - srt::sync::steady_clock::time_point m_tsClosureTimeStamp; + sync::steady_clock::time_point m_tsClosureTimeStamp; sockaddr_any m_SelfAddr; //< local address of the socket sockaddr_any m_PeerAddr; //< peer address of the socket @@ -117,7 +119,7 @@ class CUDTSocket SRTSOCKET m_PeerID; //< peer socket ID #if ENABLE_EXPERIMENTAL_BONDING - srt::groups::SocketData* m_GroupMemberData; //< Pointer to group member data, or NULL if not a group member + groups::SocketData* m_GroupMemberData; //< Pointer to group member data, or NULL if not a group member CUDTGroup* m_GroupOf; //< Group this socket is a member of, or NULL if it isn't #endif @@ -125,10 +127,10 @@ class CUDTSocket CUDT* m_pUDT; //< pointer to the UDT entity - std::set m_QueuedSockets; //< set of connections waiting for accept() + std::set m_QueuedSockets; //< set of connections waiting for accept() - srt::sync::Condition m_AcceptCond; //< used to block "accept" call - srt::sync::Mutex m_AcceptLock; //< mutex associated to m_AcceptCond + sync::Condition m_AcceptCond; //< used to block "accept" call + sync::Mutex m_AcceptLock; //< mutex associated to m_AcceptCond unsigned int m_uiBackLog; //< maximum number of connections in queue @@ -143,9 +145,9 @@ class CUDTSocket // When deleting, you simply "unsubscribe" yourself from the multiplexer, which // will unref it and remove the list element by the iterator kept by the // socket. - int m_iMuxID; //< multiplexer ID + int m_iMuxID; //< multiplexer ID - srt::sync::Mutex m_ControlLock; //< lock this socket exclusively for control APIs: bind/listen/connect + sync::Mutex m_ControlLock; //< lock this socket exclusively for control APIs: bind/listen/connect CUDT& core() { return *m_pUDT; } @@ -346,12 +348,12 @@ friend class CRendezvousQueue; groups_t m_Groups; #endif - srt::sync::Mutex m_GlobControlLock; // used to synchronize UDT API + sync::Mutex m_GlobControlLock; // used to synchronize UDT API - srt::sync::Mutex m_IDLock; // used to synchronize ID generation + sync::Mutex m_IDLock; // used to synchronize ID generation - SRTSOCKET m_SocketIDGenerator; // seed to generate a new unique socket ID - SRTSOCKET m_SocketIDGenerator_init; // Keeps track of the very first one + SRTSOCKET m_SocketIDGenerator; // seed to generate a new unique socket ID + SRTSOCKET m_SocketIDGenerator_init; // Keeps track of the very first one std::map > m_PeerRec;// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn @@ -394,7 +396,7 @@ friend class CRendezvousQueue; // We have a guarantee that if `group` was set // as non-NULL here, it is also acquired and will not // be deleted until this busy flag is set back to false. - srt::sync::ScopedLock cgroup (*group->exp_groupLock()); + sync::ScopedLock cgroup (*group->exp_groupLock()); group->apiRelease(); // Only now that the group lock is lifted, can the // group be now deleted and this pointer potentially dangling @@ -408,21 +410,21 @@ friend class CRendezvousQueue; private: std::map m_mMultiplexer; // UDP multiplexer - srt::sync::Mutex m_MultiplexerLock; + sync::Mutex m_MultiplexerLock; private: CCache* m_pCache; // UDT network information cache private: volatile bool m_bClosing; - srt::sync::Mutex m_GCStopLock; - srt::sync::Condition m_GCStopCond; + sync::Mutex m_GCStopLock; + sync::Condition m_GCStopCond; - srt::sync::Mutex m_InitLock; + sync::Mutex m_InitLock; int m_iInstanceCount; // number of startup() called by application bool m_bGCStatus; // if the GC thread is working (true) - srt::sync::CThread m_GCThread; + sync::CThread m_GCThread; static void* garbageCollect(void*); sockets_t m_ClosedSockets; // temporarily store closed sockets @@ -440,4 +442,6 @@ friend class CRendezvousQueue; CUDTUnited& operator=(const CUDTUnited&); }; +} // namespace srt + #endif diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index bce9922b6..5a756792e 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -61,6 +61,7 @@ modified by using namespace std; using namespace srt_logging; +using namespace srt; using namespace srt::sync; // You can change this value at build config by using "ENFORCE" options. @@ -317,7 +318,7 @@ void CSndBuffer::updateInputRate(const steady_clock::time_point& time, int pkts, if (early_update || period_us > m_InRatePeriod) { // Required Byte/sec rate (payload + headers) - m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE); + m_iInRateBytesCount += (m_iInRatePktsCount * srt::CPacket::SRT_DATA_HDR_SIZE); m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us); HLOGC(bslog.Debug, log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount @@ -410,7 +411,7 @@ steady_clock::time_point CSndBuffer::getSourceTime(const CSndBuffer::Block& bloc return block.m_tsOriginTime; } -int CSndBuffer::readData(CPacket& w_packet, steady_clock::time_point& w_srctime, int kflgs) +int CSndBuffer::readData(srt::CPacket& w_packet, steady_clock::time_point& w_srctime, int kflgs) { // No data to read if (m_pCurrBlock == m_pLastBlock) @@ -511,7 +512,7 @@ int32_t CSndBuffer::getMsgNoAt(const int offset) return p->getMsgSeq(); } -int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time_point& w_srctime, int& w_msglen) +int CSndBuffer::readData(const int offset, srt::CPacket& w_packet, steady_clock::time_point& w_srctime, int& w_msglen) { int32_t& msgno_bitset = w_packet.m_iMsgNo; @@ -927,7 +928,7 @@ int CRcvBuffer::readBuffer(char* data, int len) return -1; } - const CPacket& pkt = m_pUnit[p]->m_Packet; + const srt::CPacket& pkt = m_pUnit[p]->m_Packet; if (bTsbPdEnabled) { @@ -996,7 +997,7 @@ int CRcvBuffer::readBufferToFile(fstream& ofs, int len) continue; } - const CPacket& pkt = m_pUnit[p]->m_Packet; + const srt::CPacket& pkt = m_pUnit[p]->m_Packet; #if ENABLE_LOGGING trace_seq = pkt.getSeqNo(); @@ -1436,7 +1437,7 @@ bool CRcvBuffer::isRcvDataReady(steady_clock::time_point& w_tsbpdtime, int32_t& if (m_tsbpd.isEnabled()) { - const CPacket* pkt = getRcvReadyPacket(seqdistance); + const srt::CPacket* pkt = getRcvReadyPacket(seqdistance); if (!pkt) { HLOGC(brlog.Debug, log << "isRcvDataReady: packet NOT extracted."); @@ -1573,7 +1574,7 @@ void CRcvBuffer::reportBufferStats() const uint64_t lower_time = low_ts; if (lower_time > upper_time) - upper_time += uint64_t(CPacket::MAX_TIMESTAMP) + 1; + upper_time += uint64_t(srt::CPacket::MAX_TIMESTAMP) + 1; int32_t timespan = upper_time - lower_time; int seqspan = 0; diff --git a/srtcore/buffer.h b/srtcore/buffer.h index 7f7680b8d..9a92e25b0 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -145,7 +145,7 @@ class CSndBuffer /// @param [out] origintime origin time stamp of the message /// @param [in] kflags Odd|Even crypto key flag /// @return Actual length of data read. - int readData(CPacket& w_packet, time_point& w_origintime, int kflgs); + int readData(srt::CPacket& w_packet, time_point& w_origintime, int kflgs); /// Find data position to pack a DATA packet for a retransmission. /// @param [out] data the pointer to the data position. @@ -154,7 +154,7 @@ class CSndBuffer /// @param [out] origintime origin time stamp of the message /// @param [out] msglen length of the message /// @return Actual length of data read. - int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen); + int readData(const int offset, srt::CPacket& w_packet, time_point& w_origintime, int& w_msglen); /// Get the time of the last retransmission (if any) of the DATA packet. /// @param [in] offset offset from the last ACK point (backward sequence number difference) @@ -288,7 +288,7 @@ class CRcvBuffer /// Construct the buffer. /// @param [in] queue CUnitQueue that actually holds the units (packets) /// @param [in] bufsize_pkts in units (packets) - CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE); + CRcvBuffer(srt::CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE); ~CRcvBuffer(); public: @@ -296,7 +296,7 @@ class CRcvBuffer /// @param [in] unit pointer to a data unit containing new packet /// @param [in] offset offset from last ACK point. /// @return 0 is success, -1 if data is repeated. - int addData(CUnit* unit, int offset); + int addData(srt::CUnit* unit, int offset); /// Read data into a user buffer. /// @param [in] data pointer to user buffer. @@ -402,7 +402,7 @@ class CRcvBuffer bool isRcvDataReady(); bool isRcvDataAvailable() { return m_iLastAckPos != m_iStartPos; } - CPacket* getRcvReadyPacket(int32_t seqdistance); + srt::CPacket* getRcvReadyPacket(int32_t seqdistance); /// Set TimeStamp-Based Packet Delivery Rx Mode /// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay @@ -462,7 +462,7 @@ class CRcvBuffer /// data. size_t freeUnitAt(size_t p) { - CUnit* u = m_pUnit[p]; + srt::CUnit* u = m_pUnit[p]; m_pUnit[p] = NULL; size_t rmbytes = u->m_Packet.getLength(); m_pUnitQueue->makeUnitFree(u); @@ -528,9 +528,9 @@ class CRcvBuffer } private: - CUnit** m_pUnit; // Array of pointed units collected in the buffer + srt::CUnit** m_pUnit; // Array of pointed units collected in the buffer const int m_iSize; // Size of the internal array of CUnit* items - CUnitQueue* m_pUnitQueue; // the shared unit queue + srt::CUnitQueue* m_pUnitQueue; // the shared unit queue int m_iStartPos; // HEAD: first packet available for reading int m_iLastAckPos; // the last ACKed position (exclusive), follows the last readable diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index f78689a3a..c7b6e93f3 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -71,6 +71,8 @@ modified by using namespace std; using namespace srt_logging; +namespace srt { + #ifdef _WIN32 // use INVALID_SOCKET, as provided #else @@ -136,17 +138,18 @@ static int set_cloexec(int fd, int set) { #endif // if defined(_AIX) ... #endif // ifndef _WIN32 #endif // if ENABLE_CLOEXEC +} // namespace srt -CChannel::CChannel() +srt::CChannel::CChannel() :m_iSocket(INVALID_SOCKET) { } -CChannel::~CChannel() +srt::CChannel::~CChannel() { } -void CChannel::createSocket(int family) +void srt::CChannel::createSocket(int family) { #if ENABLE_SOCK_CLOEXEC bool cloexec_flag = false; @@ -198,7 +201,7 @@ void CChannel::createSocket(int family) } -void CChannel::open(const sockaddr_any& addr) +void srt::CChannel::open(const sockaddr_any& addr) { createSocket(addr.family()); socklen_t namelen = addr.size(); @@ -212,7 +215,7 @@ void CChannel::open(const sockaddr_any& addr) setUDPSockOpt(); } -void CChannel::open(int family) +void srt::CChannel::open(int family) { createSocket(family); @@ -254,7 +257,7 @@ void CChannel::open(int family) setUDPSockOpt(); } -void CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr) +void srt::CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr) { // The getsockname() call is done before calling it and the // result is placed into udpsocks_addr. @@ -263,7 +266,7 @@ void CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr) setUDPSockOpt(); } -void CChannel::setUDPSockOpt() +void srt::CChannel::setUDPSockOpt() { #if defined(BSD) || TARGET_OS_MAC // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value @@ -390,7 +393,7 @@ void CChannel::setUDPSockOpt() #endif } -void CChannel::close() const +void srt::CChannel::close() const { #ifndef _WIN32 ::close(m_iSocket); @@ -399,26 +402,26 @@ void CChannel::close() const #endif } -int CChannel::getSndBufSize() +int srt::CChannel::getSndBufSize() { socklen_t size = (socklen_t) sizeof m_mcfg.iUDPSndBufSize; ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*) &m_mcfg.iUDPSndBufSize, &size); return m_mcfg.iUDPSndBufSize; } -int CChannel::getRcvBufSize() +int srt::CChannel::getRcvBufSize() { socklen_t size = (socklen_t) sizeof m_mcfg.iUDPRcvBufSize; ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*) &m_mcfg.iUDPRcvBufSize, &size); return m_mcfg.iUDPRcvBufSize; } -void CChannel::setConfig(const CSrtMuxerConfig& config) +void srt::CChannel::setConfig(const CSrtMuxerConfig& config) { m_mcfg = config; } -int CChannel::getIpTTL() const +int srt::CChannel::getIpTTL() const { if (m_iSocket == INVALID_SOCKET) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -441,7 +444,7 @@ int CChannel::getIpTTL() const return m_mcfg.iIpTTL; } -int CChannel::getIpToS() const +int srt::CChannel::getIpToS() const { if (m_iSocket == INVALID_SOCKET) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); @@ -467,7 +470,7 @@ int CChannel::getIpToS() const } #ifdef SRT_ENABLE_BINDTODEVICE -bool CChannel::getBind(char* dst, size_t len) +bool srt::CChannel::getBind(char* dst, size_t len) { if (m_iSocket == INVALID_SOCKET) return false; // No socket to get data from @@ -485,7 +488,7 @@ bool CChannel::getBind(char* dst, size_t len) } #endif -int CChannel::ioctlQuery(int type SRT_ATR_UNUSED) const +int srt::CChannel::ioctlQuery(int type SRT_ATR_UNUSED) const { #if defined(unix) || defined(__APPLE__) int value = 0; @@ -496,7 +499,7 @@ int CChannel::ioctlQuery(int type SRT_ATR_UNUSED) const return -1; } -int CChannel::sockoptQuery(int level SRT_ATR_UNUSED, int option SRT_ATR_UNUSED) const +int srt::CChannel::sockoptQuery(int level SRT_ATR_UNUSED, int option SRT_ATR_UNUSED) const { #if defined(unix) || defined(__APPLE__) int value = 0; @@ -508,7 +511,7 @@ int CChannel::sockoptQuery(int level SRT_ATR_UNUSED, int option SRT_ATR_UNUSED) return -1; } -void CChannel::getSockAddr(sockaddr_any& w_addr) const +void srt::CChannel::getSockAddr(sockaddr_any& w_addr) const { // The getsockname function requires only to have enough target // space to copy the socket name, it doesn't have to be correlated @@ -519,7 +522,7 @@ void CChannel::getSockAddr(sockaddr_any& w_addr) const w_addr.len = namelen; } -void CChannel::getPeerAddr(sockaddr_any& w_addr) const +void srt::CChannel::getPeerAddr(sockaddr_any& w_addr) const { socklen_t namelen = (socklen_t) w_addr.storage_size(); ::getpeername(m_iSocket, (w_addr.get()), (&namelen)); @@ -527,7 +530,7 @@ void CChannel::getPeerAddr(sockaddr_any& w_addr) const } -int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const +int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const { HLOGC(kslog.Debug, log << "CChannel::sendto: SENDING NOW DST=" << addr.str() << " target=@" << packet.m_iID @@ -615,7 +618,7 @@ int CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const return res; } -EReadStatus CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) const +EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) const { EReadStatus status = RST_OK; int msg_flags = 0; diff --git a/srtcore/channel.h b/srtcore/channel.h index 6ec51c875..ad6b3f785 100644 --- a/srtcore/channel.h +++ b/srtcore/channel.h @@ -59,6 +59,8 @@ modified by #include "socketconfig.h" #include "netinet_any.h" +namespace srt { + class CChannel { void createSocket(int family); @@ -114,14 +116,14 @@ class CChannel /// @param [in] packet reference to a CPacket entity. /// @return Actual size of data sent. - int sendto(const sockaddr_any& addr, CPacket& packet) const; + int sendto(const sockaddr_any& addr, srt::CPacket& packet) const; /// Receive a packet from the channel and record the source address. /// @param [in] addr pointer to the source address. /// @param [in] packet reference to a CPacket entity. /// @return Actual size of data received. - EReadStatus recvfrom(sockaddr_any& addr, CPacket& packet) const; + EReadStatus recvfrom(sockaddr_any& addr, srt::CPacket& packet) const; void setConfig(const CSrtMuxerConfig& config); @@ -160,5 +162,6 @@ class CChannel sockaddr_any m_BindAddr; }; +} // namespace srt #endif diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 31b1bebe0..389933b26 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -70,6 +70,7 @@ modified by #include // SysStrError +using namespace srt; using namespace srt::sync; namespace srt_logging { diff --git a/srtcore/common.h b/srtcore/common.h index 8a47a0c6c..f6fdba44a 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -311,7 +311,9 @@ enum EInitEvent TEV_INIT_OHEADBW }; -class CPacket; +namespace srt { + class CPacket; +} // XXX Use some more standard less hand-crafted solution, if possible // XXX Consider creating a mapping between TEV_* values and associated types, @@ -322,7 +324,7 @@ struct EventVariant enum Type {UNDEFINED, PACKET, ARRAY, ACK, STAGE, INIT} type; union U { - const CPacket* packet; + const srt::CPacket* packet; int32_t ack; struct { @@ -341,7 +343,7 @@ struct EventVariant // Note: UNDEFINED and ARRAY don't have assignment operator. // For ARRAY you'll use 'set' function. For UNDEFINED there's nothing. - explicit EventVariant(const CPacket* arg) + explicit EventVariant(const srt::CPacket* arg) { type = PACKET; u.packet = arg; @@ -430,7 +432,7 @@ class EventArgType; // use a full-templated version. TBD. template<> struct EventVariant::VariantFor { - typedef const CPacket* type; + typedef const srt::CPacket* type; static type U::*field() {return &U::packet;} }; @@ -1406,7 +1408,7 @@ inline std::string SrtVersionString(int version) return buf; } -bool SrtParseConfig(std::string s, SrtConfig& w_config); +bool SrtParseConfig(std::string s, srt::SrtConfig& w_config); struct PacketMetric { diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index fdf9ddb0b..998256216 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -34,6 +34,7 @@ #include "logging.h" using namespace std; +using namespace srt; using namespace srt::sync; using namespace srt_logging; diff --git a/srtcore/congctl.h b/srtcore/congctl.h index 6419605c0..0ad835783 100644 --- a/srtcore/congctl.h +++ b/srtcore/congctl.h @@ -16,10 +16,12 @@ #include #include -class CUDT; +namespace srt { + class CUDT; +} class SrtCongestionControlBase; -typedef SrtCongestionControlBase* srtcc_create_t(CUDT* parent); +typedef SrtCongestionControlBase* srtcc_create_t(srt::CUDT* parent); class SrtCongestion { @@ -97,7 +99,7 @@ class SrtCongestion // in appropriate time. It should select appropriate // congctl basing on the value in selector, then // pin oneself in into CUDT for receiving event signals. - bool configure(CUDT* parent); + bool configure(srt::CUDT* parent); // This function will intentionally delete the contained object. // This makes future calls to ready() return false. Calling @@ -129,13 +131,15 @@ class SrtCongestion }; }; -class CPacket; +namespace srt { + class CPacket; +} class SrtCongestionControlBase { protected: // Here can be some common fields - CUDT* m_parent; + srt::CUDT* m_parent; double m_dPktSndPeriod; double m_dCWndSize; @@ -150,7 +154,7 @@ class SrtCongestionControlBase //char* m_pcParam; // Used to access m_llMaxBw. Use m_parent->maxBandwidth() instead. // Constructor in protected section so that this class is semi-abstract. - SrtCongestionControlBase(CUDT* parent); + SrtCongestionControlBase(srt::CUDT* parent); public: // This could be also made abstract, but this causes a linkage @@ -192,7 +196,7 @@ class SrtCongestionControlBase // Arg 2: value calculated out of CUDT's m_config.llInputBW and m_config.iOverheadBW. virtual void updateBandwidth(int64_t, int64_t) {} - virtual bool needsQuickACK(const CPacket&) + virtual bool needsQuickACK(const srt::CPacket&) { return false; } diff --git a/srtcore/core.cpp b/srtcore/core.cpp index f6c6cac0a..1e9d2f052 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -83,10 +83,12 @@ using namespace srt; using namespace srt::sync; using namespace srt_logging; -CUDTUnited CUDT::s_UDTUnited; +namespace srt { + CUDTUnited CUDT::s_UDTUnited; +} -const SRTSOCKET UDT::INVALID_SOCK = CUDT::INVALID_SOCK; -const int UDT::ERROR = CUDT::ERROR; +const SRTSOCKET UDT::INVALID_SOCK = srt::CUDT::INVALID_SOCK; +const int UDT::ERROR = srt::CUDT::ERROR; //#define SRT_CMD_HSREQ 1 /* SRT Handshake Request (sender) */ #define SRT_CMD_HSREQ_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */ @@ -221,7 +223,7 @@ const SrtOptionAction s_sockopt_action; } // namespace srt -void CUDT::construct() +void srt::CUDT::construct() { m_pSndBuffer = NULL; m_pRcvBuffer = NULL; @@ -271,7 +273,7 @@ void CUDT::construct() // m_cbPacketArrival.set(this, &CUDT::defaultPacketArrival); } -CUDT::CUDT(CUDTSocket* parent): m_parent(parent) +srt::CUDT::CUDT(CUDTSocket* parent): m_parent(parent) { construct(); @@ -294,7 +296,7 @@ CUDT::CUDT(CUDTSocket* parent): m_parent(parent) } -CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor): m_parent(parent) +srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor): m_parent(parent) { construct(); @@ -330,7 +332,7 @@ CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor): m_parent(parent) m_pCache = ancestor.m_pCache; } -CUDT::~CUDT() +srt::CUDT::~CUDT() { // release mutex/condtion variables destroySynch(); @@ -344,7 +346,7 @@ CUDT::~CUDT() delete m_pRNode; } -void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) +void srt::CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) { if (m_bBroken || m_bClosing) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); @@ -403,7 +405,7 @@ void CUDT::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen) } } -void CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) +void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) { ScopedLock cg(m_ConnectionLock); @@ -782,7 +784,7 @@ void CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) #if ENABLE_EXPERIMENTAL_BONDING -SRT_ERRNO CUDT::applyMemberConfigObject(const SRT_SocketOptionObject& opt) +SRT_ERRNO srt::CUDT::applyMemberConfigObject(const SRT_SocketOptionObject& opt) { SRT_SOCKOPT this_opt = SRTO_VERSION; for (size_t i = 0; i < opt.options.size(); ++i) @@ -796,7 +798,7 @@ SRT_ERRNO CUDT::applyMemberConfigObject(const SRT_SocketOptionObject& opt) } #endif -bool CUDT::setstreamid(SRTSOCKET u, const std::string &sid) +bool srt::CUDT::setstreamid(SRTSOCKET u, const std::string &sid) { CUDT *that = getUDTHandle(u); if (!that) @@ -812,7 +814,7 @@ bool CUDT::setstreamid(SRTSOCKET u, const std::string &sid) return true; } -std::string CUDT::getstreamid(SRTSOCKET u) +string srt::CUDT::getstreamid(SRTSOCKET u) { CUDT *that = getUDTHandle(u); if (!that) @@ -823,7 +825,7 @@ std::string CUDT::getstreamid(SRTSOCKET u) // XXX REFACTOR: Make common code for CUDT constructor and clearData, // possibly using CUDT::construct. -void CUDT::clearData() +void srt::CUDT::clearData() { // Initial sequence number, loss, acknowledgement, etc. int udpsize = m_config.iMSS - CPacket::UDP_HDR_SIZE; @@ -912,7 +914,7 @@ void CUDT::clearData() m_tsRcvPeerStartTime = steady_clock::time_point(); } -void CUDT::open() +void srt::CUDT::open() { ScopedLock cg(m_ConnectionLock); @@ -965,7 +967,7 @@ void CUDT::open() m_bOpened = true; } -void CUDT::setListenState() +void srt::CUDT::setListenState() { ScopedLock cg(m_ConnectionLock); @@ -986,7 +988,7 @@ void CUDT::setListenState() m_bListening = true; } -size_t CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgtype, int hs_version) +size_t srt::CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgtype, int hs_version) { if (srtlen < SRT_HS_E_SIZE) { @@ -1014,7 +1016,7 @@ size_t CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgtype, } } -size_t CUDT::fillSrtHandshake_HSREQ(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version) +size_t srt::CUDT::fillSrtHandshake_HSREQ(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version) { // INITIATOR sends HSREQ. @@ -1077,7 +1079,7 @@ size_t CUDT::fillSrtHandshake_HSREQ(uint32_t *aw_srtdata, size_t /* srtlen - unu return 3; } -size_t CUDT::fillSrtHandshake_HSRSP(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version) +size_t srt::CUDT::fillSrtHandshake_HSRSP(uint32_t *aw_srtdata, size_t /* srtlen - unused */, int hs_version) { // Setting m_tsRcvPeerStartTime is done in processSrtMsg_HSREQ(), so // this condition will be skipped only if this function is called without @@ -1185,7 +1187,7 @@ size_t CUDT::fillSrtHandshake_HSRSP(uint32_t *aw_srtdata, size_t /* srtlen - unu return 3; } -size_t CUDT::prepareSrtHsMsg(int cmd, uint32_t *srtdata, size_t size) +size_t srt::CUDT::prepareSrtHsMsg(int cmd, uint32_t *srtdata, size_t size) { size_t srtlen = fillSrtHandshake(srtdata, size, cmd, handshakeVersion()); HLOGF(cnlog.Debug, @@ -1201,7 +1203,7 @@ size_t CUDT::prepareSrtHsMsg(int cmd, uint32_t *srtdata, size_t size) return srtlen; } -void CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in) +void srt::CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in) { CPacket srtpkt; int32_t srtcmd = (int32_t)cmd; @@ -1259,7 +1261,7 @@ void CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in) } } -size_t CUDT::fillHsExtConfigString(uint32_t* pcmdspec, int cmd, const string& str) +size_t srt::CUDT::fillHsExtConfigString(uint32_t* pcmdspec, int cmd, const string& str) { uint32_t* space = pcmdspec + 1; size_t wordsize = (str.size() + 3) / 4; @@ -1278,7 +1280,7 @@ size_t CUDT::fillHsExtConfigString(uint32_t* pcmdspec, int cmd, const string& st #if ENABLE_EXPERIMENTAL_BONDING // [[using locked(m_parent->m_ControlLock)]] // [[using locked(s_UDTUnited.m_GlobControlLock)]] -size_t CUDT::fillHsExtGroup(uint32_t* pcmdspec) +size_t srt::CUDT::fillHsExtGroup(uint32_t* pcmdspec) { SRT_ASSERT(m_parent->m_GroupOf != NULL); uint32_t* space = pcmdspec + 1; @@ -1320,7 +1322,7 @@ size_t CUDT::fillHsExtGroup(uint32_t* pcmdspec) } #endif -size_t CUDT::fillHsExtKMREQ(uint32_t* pcmdspec, size_t ki) +size_t srt::CUDT::fillHsExtKMREQ(uint32_t* pcmdspec, size_t ki) { uint32_t* space = pcmdspec + 1; @@ -1349,7 +1351,7 @@ size_t CUDT::fillHsExtKMREQ(uint32_t* pcmdspec, size_t ki) return ra_size; } -size_t CUDT::fillHsExtKMRSP(uint32_t* pcmdspec, const uint32_t* kmdata, size_t kmdata_wordsize) +size_t srt::CUDT::fillHsExtKMRSP(uint32_t* pcmdspec, const uint32_t* kmdata, size_t kmdata_wordsize) { uint32_t* space = pcmdspec + 1; const uint32_t failure_kmrsp[] = {SRT_KM_S_UNSECURED}; @@ -1396,7 +1398,7 @@ size_t CUDT::fillHsExtKMRSP(uint32_t* pcmdspec, const uint32_t* kmdata, size_t k // PREREQUISITE: // pkt must be set the buffer and configured for UMSG_HANDSHAKE. // Note that this function replaces also serialization for the HSv4. -bool CUDT::createSrtHandshake( +bool srt::CUDT::createSrtHandshake( int srths_cmd, int srtkm_cmd, const uint32_t* kmdata, @@ -1939,7 +1941,7 @@ RttTracer s_rtt_trace; #endif -bool CUDT::processSrtMsg(const CPacket *ctrlpkt) +bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt) { uint32_t *srtdata = (uint32_t *)ctrlpkt->m_pcData; size_t len = ctrlpkt->getLength(); @@ -2021,7 +2023,7 @@ bool CUDT::processSrtMsg(const CPacket *ctrlpkt) return true; } -int CUDT::processSrtMsg_HSREQ(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv) +int srt::CUDT::processSrtMsg_HSREQ(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv) { // Set this start time in the beginning, regardless as to whether TSBPD is being // used or not. This must be done in the Initiator as well as Responder. @@ -2235,7 +2237,7 @@ int CUDT::processSrtMsg_HSREQ(const uint32_t *srtdata, size_t bytelen, uint32_t return SRT_CMD_HSRSP; } -int CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv) +int srt::CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint32_t ts, int hsv) { // XXX Check for mis-version // With HSv4 we accept only version less than 1.3.0 @@ -2381,7 +2383,7 @@ int CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint32_t } // This function is called only when the URQ_CONCLUSION handshake has been received from the peer. -bool CUDT::interpretSrtHandshake(const CHandShake& hs, +bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, const CPacket& hspkt, uint32_t* out_data, size_t* pw_len) @@ -2894,7 +2896,7 @@ bool CUDT::interpretSrtHandshake(const CHandShake& hs, return true; } -bool CUDT::checkApplyFilterConfig(const std::string &confstr) +bool srt::CUDT::checkApplyFilterConfig(const std::string &confstr) { SrtFilterConfig cfg; if (!ParseFilterConfig(confstr, (cfg))) @@ -2976,7 +2978,7 @@ bool CUDT::checkApplyFilterConfig(const std::string &confstr) } #if ENABLE_EXPERIMENTAL_BONDING -bool CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_ATR_UNUSED, int hsreq_type_cmd SRT_ATR_UNUSED) +bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_ATR_UNUSED, int hsreq_type_cmd SRT_ATR_UNUSED) { // `data_size` isn't checked because we believe it's checked earlier. // Also this code doesn't predict to get any other format than the official one, @@ -3147,7 +3149,7 @@ bool CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_ATR_UN // exclusively on the listener side (HSD_RESPONDER, HSv5+). // [[using locked(s_UDTUnited.m_GlobControlLock)]] -SRTSOCKET CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint32_t link_flags) +SRTSOCKET srt::CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint32_t link_flags) { // Note: This function will lock pg->m_GroupLock! @@ -3245,7 +3247,7 @@ SRTSOCKET CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint32_t l return gp->id(); } -void CUDT::synchronizeWithGroup(CUDTGroup* gp) +void srt::CUDT::synchronizeWithGroup(CUDTGroup* gp) { ScopedLock gl (*gp->exp_groupLock()); @@ -3344,7 +3346,7 @@ void CUDT::synchronizeWithGroup(CUDTGroup* gp) } #endif -void CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) +void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) { ScopedLock cg (m_ConnectionLock); @@ -3723,7 +3725,7 @@ void CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) } // Asynchronous connection -EConnectStatus CUDT::processAsyncConnectResponse(const CPacket &pkt) ATR_NOEXCEPT +EConnectStatus srt::CUDT::processAsyncConnectResponse(const CPacket &pkt) ATR_NOEXCEPT { EConnectStatus cst = CONN_CONTINUE; CUDTException e; @@ -3740,7 +3742,7 @@ EConnectStatus CUDT::processAsyncConnectResponse(const CPacket &pkt) ATR_NOEXCEP return cst; } -bool CUDT::processAsyncConnectRequest(EReadStatus rst, +bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, const CPacket& response, const sockaddr_any& serv_addr) @@ -3834,7 +3836,7 @@ bool CUDT::processAsyncConnectRequest(EReadStatus rst, return status; } -void CUDT::cookieContest() +void srt::CUDT::cookieContest() { if (m_SrtHsSide != HSD_DRAW) return; @@ -3899,7 +3901,7 @@ void CUDT::cookieContest() // - There's no KMX (including first responder's handshake in rendezvous). This writes 0 to w_kmdatasize. // - The encryption status is failure. Respond with fail code and w_kmdatasize = 1. // - The last KMX was successful. Respond with the original kmdata and their size in w_kmdatasize. -EConnectStatus CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize) +EConnectStatus srt::CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize) { // If the last CONCLUSION message didn't contain the KMX extension, there's // no key recorded yet, so it can't be extracted. Mark this w_kmdatasize empty though. @@ -3973,7 +3975,7 @@ EConnectStatus CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize) return CONN_ACCEPT; } -EConnectStatus CUDT::processRendezvous( +EConnectStatus srt::CUDT::processRendezvous( const CPacket& response, const sockaddr_any& serv_addr, EReadStatus rst, CPacket& w_reqpkt) { @@ -4243,7 +4245,7 @@ EConnectStatus CUDT::processRendezvous( } // [[using locked(m_ConnectionLock)]]; -EConnectStatus CUDT::processConnectResponse(const CPacket& response, CUDTException* eout) ATR_NOEXCEPT +EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTException* eout) ATR_NOEXCEPT { // NOTE: ASSUMED LOCK ON: m_ConnectionLock. @@ -4475,7 +4477,7 @@ EConnectStatus CUDT::processConnectResponse(const CPacket& response, CUDTExcepti return postConnect(response, false, eout); } -bool CUDT::applyResponseSettings() ATR_NOEXCEPT +bool srt::CUDT::applyResponseSettings() ATR_NOEXCEPT { if (!m_ConnRes.valid()) { @@ -4505,7 +4507,7 @@ bool CUDT::applyResponseSettings() ATR_NOEXCEPT return true; } -EConnectStatus CUDT::postConnect(const CPacket &response, bool rendezvous, CUDTException *eout) ATR_NOEXCEPT +EConnectStatus srt::CUDT::postConnect(const CPacket &response, bool rendezvous, CUDTException *eout) ATR_NOEXCEPT { if (m_ConnRes.m_iVersion < HS_VERSION_SRT1) m_tsRcvPeerStartTime = steady_clock::time_point(); // will be set correctly in SRT HS. @@ -4713,7 +4715,7 @@ EConnectStatus CUDT::postConnect(const CPacket &response, bool rendezvous, CUDTE return CONN_ACCEPT; } -void CUDT::checkUpdateCryptoKeyLen(const char *loghdr SRT_ATR_UNUSED, int32_t typefield) +void srt::CUDT::checkUpdateCryptoKeyLen(const char *loghdr SRT_ATR_UNUSED, int32_t typefield) { int enc_flags = SrtHSRequest::SRT_HSTYPE_ENCFLAGS::unwrap(typefield); @@ -4759,7 +4761,7 @@ void CUDT::checkUpdateCryptoKeyLen(const char *loghdr SRT_ATR_UNUSED, int32_t ty } // Rendezvous -void CUDT::rendezvousSwitchState(UDTRequestType& w_rsptype, bool& w_needs_extension, bool& w_needs_hsrsp) +void srt::CUDT::rendezvousSwitchState(UDTRequestType& w_rsptype, bool& w_needs_extension, bool& w_needs_hsrsp) { UDTRequestType req = m_ConnRes.m_iReqType; int hs_flags = SrtHSRequest::SRT_HSTYPE_HSFLAGS::unwrap(m_ConnRes.m_iType); @@ -5123,7 +5125,7 @@ void CUDT::rendezvousSwitchState(UDTRequestType& w_rsptype, bool& w_needs_extens * This thread runs only if TsbPd mode is enabled * Hold received packets until its time to 'play' them, at PktTimeStamp + TsbPdDelay. */ -void *CUDT::tsbpd(void *param) +void * srt::CUDT::tsbpd(void *param) { CUDT *self = (CUDT *)param; @@ -5332,7 +5334,7 @@ void *CUDT::tsbpd(void *param) return NULL; } -void CUDT::updateForgotten(int seqlen, int32_t lastack, int32_t skiptoseqno) +void srt::CUDT::updateForgotten(int seqlen, int32_t lastack, int32_t skiptoseqno) { /* Update drop/skip stats */ enterCS(m_StatsLock); @@ -5347,7 +5349,7 @@ void CUDT::updateForgotten(int seqlen, int32_t lastack, int32_t skiptoseqno) dropFromLossLists(lastack, CSeqNo::decseq(skiptoseqno)); //remove(from,to-inclusive) } -bool CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout) +bool srt::CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout) { // This will be lazily created due to being the common // code with HSv5 rendezvous, in which this will be run @@ -5409,7 +5411,7 @@ bool CUDT::prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUD return true; } -void CUDT::rewriteHandshakeData(const sockaddr_any& peer, CHandShake& w_hs) +void srt::CUDT::rewriteHandshakeData(const sockaddr_any& peer, CHandShake& w_hs) { // this is a reponse handshake w_hs.m_iReqType = URQ_CONCLUSION; @@ -5428,7 +5430,7 @@ void CUDT::rewriteHandshakeData(const sockaddr_any& peer, CHandShake& w_hs) CIPAddress::ntop(peer, (w_hs.m_piPeerIP)); } -void CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& peer, const CPacket& hspkt, CHandShake& w_hs) +void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& peer, const CPacket& hspkt, CHandShake& w_hs) { HLOGC(cnlog.Debug, log << "acceptAndRespond: setting up data according to handshake"); @@ -5610,7 +5612,7 @@ void CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& peer, // be created, as this happens before the completion of the connection (and // therefore configuration of the crypter object), which can only take place upon // reception of CONCLUSION response from the listener. -bool CUDT::createCrypter(HandshakeSide side, bool bidirectional) +bool srt::CUDT::createCrypter(HandshakeSide side, bool bidirectional) { // Lazy initialization if (m_pCryptoControl) @@ -5636,7 +5638,7 @@ bool CUDT::createCrypter(HandshakeSide side, bool bidirectional) return m_pCryptoControl->init(side, bidirectional); } -SRT_REJECT_REASON CUDT::setupCC() +SRT_REJECT_REASON srt::CUDT::setupCC() { // Prepare configuration object, // Create the CCC object and configure it. @@ -5719,7 +5721,7 @@ SRT_REJECT_REASON CUDT::setupCC() return SRT_REJ_UNKNOWN; } -void CUDT::considerLegacySrtHandshake(const steady_clock::time_point &timebase) +void srt::CUDT::considerLegacySrtHandshake(const steady_clock::time_point &timebase) { // Do a fast pre-check first - this simply declares that agent uses HSv5 // and the legacy SRT Handshake is not to be done. Second check is whether @@ -5769,7 +5771,7 @@ void CUDT::considerLegacySrtHandshake(const steady_clock::time_point &timebase) sendSrtMsg(SRT_CMD_HSREQ); } -void CUDT::checkSndTimers(Whether2RegenKm regen) +void srt::CUDT::checkSndTimers(Whether2RegenKm regen) { if (m_SrtHsSide == HSD_INITIATOR) { @@ -5797,7 +5799,7 @@ void CUDT::checkSndTimers(Whether2RegenKm regen) } } -void CUDT::addressAndSend(CPacket& w_pkt) +void srt::CUDT::addressAndSend(CPacket& w_pkt) { w_pkt.m_iID = m_PeerID; setPacketTS(w_pkt, steady_clock::now()); @@ -5811,7 +5813,7 @@ void CUDT::addressAndSend(CPacket& w_pkt) } // [[using maybe_locked(m_GlobControlLock, if called from GC)]] -bool CUDT::closeInternal() +bool srt::CUDT::closeInternal() { // NOTE: this function is called from within the garbage collector thread. @@ -5987,7 +5989,7 @@ bool CUDT::closeInternal() return true; } -int CUDT::receiveBuffer(char *data, int len) +int srt::CUDT::receiveBuffer(char *data, int len) { if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_BUFFER, SrtCongestion::STAD_RECV, data, len, SRT_MSGTTL_INF, false)) throw CUDTException(MJ_NOTSUP, MN_INVALBUFFERAPI, 0); @@ -6112,7 +6114,7 @@ int CUDT::receiveBuffer(char *data, int len) // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]]; // [[using locked(m_SendLock)]]; -void CUDT::checkNeedDrop(bool& w_bCongestion) +void srt::CUDT::checkNeedDrop(bool& w_bCongestion) { if (!m_bPeerTLPktDrop) return; @@ -6209,7 +6211,7 @@ void CUDT::checkNeedDrop(bool& w_bCongestion) } } -int CUDT::sendmsg(const char *data, int len, int msttl, bool inorder, int64_t srctime) +int srt::CUDT::sendmsg(const char *data, int len, int msttl, bool inorder, int64_t srctime) { SRT_MSGCTRL mctrl = srt_msgctrl_default; mctrl.msgttl = msttl; @@ -6221,7 +6223,7 @@ int CUDT::sendmsg(const char *data, int len, int msttl, bool inorder, int64_t sr // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]] // GroupLock is applied when this function is called from inside CUDTGroup::send, // which is the only case when the m_parent->m_GroupOf is not NULL. -int CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl) +int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl) { bool bCongestion = false; @@ -6508,13 +6510,13 @@ int CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl) return size; } -int CUDT::recv(char* data, int len) +int srt::CUDT::recv(char* data, int len) { SRT_MSGCTRL mctrl = srt_msgctrl_default; return recvmsg2(data, len, (mctrl)); } -int CUDT::recvmsg(char* data, int len, int64_t& srctime) +int srt::CUDT::recvmsg(char* data, int len, int64_t& srctime) { SRT_MSGCTRL mctrl = srt_msgctrl_default; int res = recvmsg2(data, len, (mctrl)); @@ -6525,7 +6527,7 @@ int CUDT::recvmsg(char* data, int len, int64_t& srctime) // [[using maybe_locked(CUDTGroup::m_GroupLock, m_parent->m_GroupOf != NULL)]] // GroupLock is applied when this function is called from inside CUDTGroup::recv, // which is the only case when the m_parent->m_GroupOf is not NULL. -int CUDT::recvmsg2(char* data, int len, SRT_MSGCTRL& w_mctrl) +int srt::CUDT::recvmsg2(char* data, int len, SRT_MSGCTRL& w_mctrl) { // Check if the socket is a member of a receiver group. // If so, then reading by receiveMessage is disallowed. @@ -6557,7 +6559,7 @@ int CUDT::recvmsg2(char* data, int len, SRT_MSGCTRL& w_mctrl) // - 0 - by return value // - 1 - by exception // - 2 - by abort (unused) -int CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_exception) +int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_exception) { // Recvmsg isn't restricted to the congctl type, it's the most // basic method of passing the data. You can retrieve data as @@ -6809,7 +6811,7 @@ int CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_excep return res; } -int64_t CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int block) +int64_t srt::CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int block) { if (m_bBroken || m_bClosing) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); @@ -6931,7 +6933,7 @@ int64_t CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int block) return size - tosend; } -int64_t CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int block) +int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int block) { if (!m_bConnected || !m_CongCtl.ready()) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); @@ -7050,7 +7052,7 @@ int64_t CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int block) return size - torecv; } -void CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) +void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) { if (!m_bConnected) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); @@ -7242,7 +7244,7 @@ void CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) } } -bool CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) +bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) { // Special things that must be done HERE, not in SrtCongestion, // because it involves the input buffer in CUDT. It would be @@ -7360,7 +7362,7 @@ bool CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) return true; } -void CUDT::initSynch() +void srt::CUDT::initSynch() { setupMutex(m_SendBlockLock, "SendBlock"); setupCond(m_SendBlockCond, "SendBlock"); @@ -7375,7 +7377,7 @@ void CUDT::initSynch() setupCond(m_RcvTsbPdCond, "RcvTsbPd"); } -void CUDT::destroySynch() +void srt::CUDT::destroySynch() { releaseMutex(m_SendBlockLock); @@ -7400,7 +7402,7 @@ void CUDT::destroySynch() releaseCond(m_RcvTsbPdCond); } -void CUDT::releaseSynch() +void srt::CUDT::releaseSynch() { SRT_ASSERT(m_bClosing); // wake up user calls @@ -7430,7 +7432,7 @@ void CUDT::releaseSynch() } // [[using locked(m_RcvBufferLock)]]; -int32_t CUDT::ackDataUpTo(int32_t ack) +int32_t srt::CUDT::ackDataUpTo(int32_t ack) { int acksize = CSeqNo::seqoff(m_iRcvLastSkipAck, ack); @@ -7456,6 +7458,7 @@ int32_t CUDT::ackDataUpTo(int32_t ack) return ack; } +namespace srt { #if ENABLE_HEAVY_LOGGING static void DebugAck(string hdr, int prev, int ack) { @@ -7487,8 +7490,9 @@ static void DebugAck(string hdr, int prev, int ack) #else static inline void DebugAck(string, int, int) {} #endif +} -void CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rparam, int size) +void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rparam, int size) { CPacket ctrlpkt; setPacketTS(ctrlpkt, steady_clock::now()); @@ -7627,7 +7631,7 @@ void CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rparam, m_tsLastSndTime = steady_clock::now(); } -int CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) +int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) { SRT_ASSERT(ctrlpkt.getMsgTimeStamp() != 0); int32_t ack; @@ -7877,7 +7881,7 @@ int CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) return nbsent; } -void CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) +void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) { #if ENABLE_EXPERIMENTAL_BONDING // This is for the call of CSndBuffer::getMsgNoAt that returns @@ -7964,7 +7968,7 @@ void CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) leaveCS(m_StatsLock); } -void CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point& currtime) +void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point& currtime) { const int32_t* ackdata = (const int32_t*)ctrlpkt.m_pcData; const int32_t ackdata_seqno = ackdata[ACKD_RCVLASTACK]; @@ -8216,7 +8220,7 @@ void CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point leaveCS(m_StatsLock); } -void CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival) +void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival) { int32_t ack = 0; @@ -8307,7 +8311,7 @@ void CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival m_iRcvLastAckAck = ack; } -void CUDT::processCtrlLossReport(const CPacket& ctrlpkt) +void srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt) { const int32_t* losslist = (int32_t*)(ctrlpkt.m_pcData); const size_t losslist_len = ctrlpkt.getLength() / 4; @@ -8451,7 +8455,7 @@ void CUDT::processCtrlLossReport(const CPacket& ctrlpkt) leaveCS(m_StatsLock); } -void CUDT::processCtrlHS(const CPacket& ctrlpkt) +void srt::CUDT::processCtrlHS(const CPacket& ctrlpkt) { CHandShake req; req.load_from(ctrlpkt.m_pcData, ctrlpkt.getLength()); @@ -8562,7 +8566,7 @@ void CUDT::processCtrlHS(const CPacket& ctrlpkt) } } -void CUDT::processCtrlDropReq(const CPacket& ctrlpkt) +void srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt) { { const bool using_rexmit_flag = m_bPeerRexmitFlag; @@ -8601,7 +8605,7 @@ void CUDT::processCtrlDropReq(const CPacket& ctrlpkt) } } -void CUDT::processCtrlShutdown() +void srt::CUDT::processCtrlShutdown() { m_bShutdown = true; m_bClosing = true; @@ -8614,7 +8618,7 @@ void CUDT::processCtrlShutdown() completeBrokenConnectionDependencies(SRT_ECONNLOST); // LOCKS! } -void CUDT::processCtrlUserDefined(const CPacket& ctrlpkt) +void srt::CUDT::processCtrlUserDefined(const CPacket& ctrlpkt) { HLOGC(inlog.Debug, log << CONID() << "CONTROL EXT MSG RECEIVED:" << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType()) @@ -8644,7 +8648,7 @@ void CUDT::processCtrlUserDefined(const CPacket& ctrlpkt) } } -void CUDT::processCtrl(const CPacket &ctrlpkt) +void srt::CUDT::processCtrl(const CPacket &ctrlpkt) { // Just heard from the peer, reset the expiration count. m_iEXPCount = 1; @@ -8714,7 +8718,7 @@ void CUDT::processCtrl(const CPacket &ctrlpkt) } } -void CUDT::updateSrtRcvSettings() +void srt::CUDT::updateSrtRcvSettings() { // CHANGED: we need to apply the tsbpd delay only for socket TSBPD. // For Group TSBPD the buffer will have to deliver packets always on request @@ -8745,7 +8749,7 @@ void CUDT::updateSrtRcvSettings() } } -void CUDT::updateSrtSndSettings() +void srt::CUDT::updateSrtSndSettings() { if (m_bPeerTsbPd) { @@ -8768,7 +8772,7 @@ void CUDT::updateSrtSndSettings() } } -void CUDT::updateAfterSrtHandshake(int hsv) +void srt::CUDT::updateAfterSrtHandshake(int hsv) { HLOGC(cnlog.Debug, log << "updateAfterSrtHandshake: HS version " << hsv); // This is blocked from being run in the "app reader" version because here @@ -8823,7 +8827,7 @@ void CUDT::updateAfterSrtHandshake(int hsv) } } -int CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime) +int srt::CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime) { // protect m_iSndLastDataAck from updating by ACK processing UniqueLock ackguard(m_RecvAckLock); @@ -8935,7 +8939,7 @@ int CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origintime return 0; } -std::pair CUDT::packData(CPacket& w_packet) +std::pair srt::CUDT::packData(CPacket& w_packet) { int payload = 0; bool probe = false; @@ -9216,7 +9220,7 @@ std::pair CUDT::packData(CPacket& w_packet) } // This is a close request, but called from the -void CUDT::processClose() +void srt::CUDT::processClose() { sendCtrl(UMSG_SHUTDOWN); @@ -9242,7 +9246,7 @@ void CUDT::processClose() CGlobEvent::triggerEvent(); } -void CUDT::sendLossReport(const std::vector > &loss_seqs) +void srt::CUDT::sendLossReport(const std::vector > &loss_seqs) { typedef vector > loss_seqs_t; @@ -9274,7 +9278,7 @@ void CUDT::sendLossReport(const std::vector > &loss_ } -bool CUDT::overrideSndSeqNo(int32_t seq) +bool srt::CUDT::overrideSndSeqNo(int32_t seq) { // This function is intended to be called from the socket // group managmenet functions to synchronize the sequnece in @@ -9325,7 +9329,7 @@ bool CUDT::overrideSndSeqNo(int32_t seq) return true; } -int CUDT::processData(CUnit* in_unit) +int srt::CUDT::processData(CUnit* in_unit) { if (m_bClosing) return -1; @@ -9965,7 +9969,7 @@ int CUDT::processData(CUnit* in_unit) } #if ENABLE_EXPERIMENTAL_BONDING -void CUDT::updateIdleLinkFrom(CUDT* source) +void srt::CUDT::updateIdleLinkFrom(CUDT* source) { ScopedLock lg (m_RecvLock); @@ -9999,7 +10003,7 @@ void CUDT::updateIdleLinkFrom(CUDT* source) // XXX This function is currently unused. It should be fixed and put into use. // See the blocked call in CUDT::processData(). // XXX REVIEW LOCKS WHEN REACTIVATING! -CUDT::loss_seqs_t CUDT::defaultPacketArrival(void* vself, CPacket& pkt) +srt::CUDT::loss_seqs_t srt::CUDT::defaultPacketArrival(void* vself, CPacket& pkt) { // [[using affinity(m_pRcvBuffer->workerThread())]]; CUDT* self = (CUDT*)vself; @@ -10074,7 +10078,7 @@ CUDT::loss_seqs_t CUDT::defaultPacketArrival(void* vself, CPacket& pkt) /// do not include the lacking packet. /// The tolerance is not increased infinitely - it's bordered by iMaxReorderTolerance. /// This value can be set in options - SRT_LOSSMAXTTL. -void CUDT::unlose(const CPacket &packet) +void srt::CUDT::unlose(const CPacket &packet) { ScopedLock lg(m_RcvLossLock); int32_t sequence = packet.m_iSeqNo; @@ -10219,7 +10223,7 @@ breakbreak:; } } -void CUDT::dropFromLossLists(int32_t from, int32_t to) +void srt::CUDT::dropFromLossLists(int32_t from, int32_t to) { ScopedLock lg(m_RcvLossLock); m_pRcvLossList->remove(from, to); @@ -10262,7 +10266,7 @@ void CUDT::dropFromLossLists(int32_t from, int32_t to) } // This function, as the name states, should bake a new cookie. -int32_t CUDT::bake(const sockaddr_any& addr, int32_t current_cookie, int correction) +int32_t srt::CUDT::bake(const sockaddr_any& addr, int32_t current_cookie, int correction) { static unsigned int distractor = 0; unsigned int rollover = distractor + 10; @@ -10321,7 +10325,7 @@ int32_t CUDT::bake(const sockaddr_any& addr, int32_t current_cookie, int correct // and this will be directly passed to the caller. // [[using locked(m_pRcvQueue->m_LSLock)]]; -int CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) +int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) { // XXX ASSUMPTIONS: // [[using assert(packet.m_iID == 0)]] @@ -10675,7 +10679,7 @@ int CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) return RejectReasonForURQ(hs.m_iReqType); } -void CUDT::addLossRecord(std::vector &lr, int32_t lo, int32_t hi) +void srt::CUDT::addLossRecord(std::vector &lr, int32_t lo, int32_t hi) { if (lo == hi) lr.push_back(lo); @@ -10686,7 +10690,7 @@ void CUDT::addLossRecord(std::vector &lr, int32_t lo, int32_t hi) } } -int CUDT::checkACKTimer(const steady_clock::time_point &currtime) +int srt::CUDT::checkACKTimer(const steady_clock::time_point &currtime) { int because_decision = BECAUSE_NO_REASON; if (currtime > m_tsNextACKTime // ACK time has come @@ -10725,7 +10729,7 @@ int CUDT::checkACKTimer(const steady_clock::time_point &currtime) return because_decision; } -int CUDT::checkNAKTimer(const steady_clock::time_point& currtime) +int srt::CUDT::checkNAKTimer(const steady_clock::time_point& currtime) { // XXX The problem with working NAKREPORT with SRT_ARQ_ONREQ // is not that it would be inappropriate, but because it's not @@ -10764,7 +10768,7 @@ int CUDT::checkNAKTimer(const steady_clock::time_point& currtime) return debug_decision; } -bool CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_reason ATR_UNUSED) +bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_reason ATR_UNUSED) { // VERY HEAVY LOGGING #if ENABLE_HEAVY_LOGGING & 1 @@ -10859,7 +10863,7 @@ bool CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_rea return false; } -void CUDT::checkRexmitTimer(const steady_clock::time_point& currtime) +void srt::CUDT::checkRexmitTimer(const steady_clock::time_point& currtime) { /* There are two algorithms of blind packet retransmission: LATEREXMIT and FASTREXMIT. * @@ -10933,7 +10937,7 @@ void CUDT::checkRexmitTimer(const steady_clock::time_point& currtime) m_pSndQueue->m_pSndUList->update(this, CSndUList::DO_RESCHEDULE); } -void CUDT::checkTimers() +void srt::CUDT::checkTimers() { // update CC parameters updateCC(TEV_CHECKTIMER, EventVariant(TEV_CHT_INIT)); @@ -10981,7 +10985,7 @@ void CUDT::checkTimers() } } -void CUDT::updateBrokenConnection() +void srt::CUDT::updateBrokenConnection() { m_bClosing = true; releaseSynch(); @@ -10990,7 +10994,7 @@ void CUDT::updateBrokenConnection() CGlobEvent::triggerEvent(); } -void CUDT::completeBrokenConnectionDependencies(int errorcode) +void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) { int token = -1; @@ -11049,7 +11053,7 @@ void CUDT::completeBrokenConnectionDependencies(int errorcode) #endif } -void CUDT::addEPoll(const int eid) +void srt::CUDT::addEPoll(const int eid) { enterCS(s_UDTUnited.m_EPoll.m_EPollLock); m_sPollID.insert(eid); @@ -11071,7 +11075,7 @@ void CUDT::addEPoll(const int eid) } } -void CUDT::removeEPollEvents(const int eid) +void srt::CUDT::removeEPollEvents(const int eid) { // clear IO events notifications; // since this happens after the epoll ID has been removed, they cannot be set again @@ -11080,14 +11084,14 @@ void CUDT::removeEPollEvents(const int eid) s_UDTUnited.m_EPoll.update_events(m_SocketID, remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false); } -void CUDT::removeEPollID(const int eid) +void srt::CUDT::removeEPollID(const int eid) { enterCS(s_UDTUnited.m_EPoll.m_EPollLock); m_sPollID.erase(eid); leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); } -void CUDT::ConnectSignal(ETransmissionEvent evt, EventSlot sl) +void srt::CUDT::ConnectSignal(ETransmissionEvent evt, EventSlot sl) { if (evt >= TEV_E_SIZE) return; // sanity check @@ -11095,7 +11099,7 @@ void CUDT::ConnectSignal(ETransmissionEvent evt, EventSlot sl) m_Slots[evt].push_back(sl); } -void CUDT::DisconnectSignal(ETransmissionEvent evt) +void srt::CUDT::DisconnectSignal(ETransmissionEvent evt) { if (evt >= TEV_E_SIZE) return; // sanity check @@ -11103,7 +11107,7 @@ void CUDT::DisconnectSignal(ETransmissionEvent evt) m_Slots[evt].clear(); } -void CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var) +void srt::CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var) { for (std::vector::iterator i = m_Slots[tev].begin(); i != m_Slots[tev].end(); ++i) { @@ -11111,7 +11115,7 @@ void CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var) } } -int CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) +int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) { CUDTSocket *s = s_UDTUnited.locateSocket(u); if (!s || !s->m_pUDT) @@ -11134,7 +11138,7 @@ int CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) return std::abs(timespan); } -int CUDT::rejectReason(SRTSOCKET u) +int srt::CUDT::rejectReason(SRTSOCKET u) { CUDTSocket* s = s_UDTUnited.locateSocket(u); if (!s || !s->m_pUDT) @@ -11143,7 +11147,7 @@ int CUDT::rejectReason(SRTSOCKET u) return s->m_pUDT->m_RejectReason; } -int CUDT::rejectReason(SRTSOCKET u, int value) +int srt::CUDT::rejectReason(SRTSOCKET u, int value) { CUDTSocket* s = s_UDTUnited.locateSocket(u); if (!s || !s->m_pUDT) @@ -11156,7 +11160,7 @@ int CUDT::rejectReason(SRTSOCKET u, int value) return 0; } -int64_t CUDT::socketStartTime(SRTSOCKET u) +int64_t srt::CUDT::socketStartTime(SRTSOCKET u) { CUDTSocket* s = s_UDTUnited.locateSocket(u); if (!s || !s->m_pUDT) @@ -11165,7 +11169,7 @@ int64_t CUDT::socketStartTime(SRTSOCKET u) return count_microseconds(s->m_pUDT->m_stats.tsStartTime.time_since_epoch()); } -bool CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs, const CPacket& hspkt) +bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs, const CPacket& hspkt) { // Prepare the information for the hook. @@ -11266,7 +11270,7 @@ bool CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs return true; } -void CUDT::handleKeepalive(const char* /*data*/, size_t /*size*/) +void srt::CUDT::handleKeepalive(const char* /*data*/, size_t /*size*/) { // Here can be handled some protocol definition // for extra data sent through keepalive. diff --git a/srtcore/core.h b/srtcore/core.h index 1d75bbaea..2e463423c 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -137,14 +137,16 @@ enum SeqPairItems SEQ_BEGIN = 0, SEQ_END = 1, SEQ_SIZE = 2 }; -#if ENABLE_EXPERIMENTAL_BONDING -class CUDTGroup; -#endif // Extended SRT Congestion control class - only an incomplete definition required class CCryptoControl; + +namespace srt { class CUDTUnited; class CUDTSocket; +#if ENABLE_EXPERIMENTAL_BONDING +class CUDTGroup; +#endif // XXX REFACTOR: The 'CUDT' class is to be merged with 'CUDTSocket'. // There's no reason for separating them, there's no case of having them @@ -167,10 +169,10 @@ class CUDT friend class PacketFilter; friend class CUDTGroup; friend struct FByOldestActive; // this functional will use private fields - friend class TestMockCUDT; + friend class TestMockCUDT; // unit tests - typedef srt::sync::steady_clock::time_point time_point; - typedef srt::sync::steady_clock::duration duration; + typedef sync::steady_clock::time_point time_point; + typedef sync::steady_clock::duration duration; private: // constructor and desctructor void construct(); @@ -1111,12 +1113,12 @@ class CUDT private: // for UDP multiplexer - CSndQueue* m_pSndQueue; // packet sending queue - CRcvQueue* m_pRcvQueue; // packet receiving queue - sockaddr_any m_PeerAddr; // peer address - uint32_t m_piSelfIP[4]; // local UDP IP address - CSNode* m_pSNode; // node information for UDT list used in snd queue - CRNode* m_pRNode; // node information for UDT list used in rcv queue + CSndQueue* m_pSndQueue; // packet sending queue + CRcvQueue* m_pRcvQueue; // packet receiving queue + sockaddr_any m_PeerAddr; // peer address + uint32_t m_piSelfIP[4]; // local UDP IP address + CSNode* m_pSNode; // node information for UDT list used in snd queue + CRNode* m_pRNode; // node information for UDT list used in rcv queue public: // For SrtCongestion const CSndQueue* sndQueue() { return m_pSndQueue; } @@ -1129,5 +1131,6 @@ class CUDT void removeEPollID(const int eid); }; +} // namespace srt #endif diff --git a/srtcore/crypto.cpp b/srtcore/crypto.cpp index 5351e1afe..c7c27abab 100644 --- a/srtcore/crypto.cpp +++ b/srtcore/crypto.cpp @@ -27,6 +27,7 @@ written by #include "logging.h" #include "core.h" +using namespace srt; using namespace srt_logging; #define SRT_MAX_KMRETRY 10 diff --git a/srtcore/crypto.h b/srtcore/crypto.h index 9d1dafc3d..4e067678b 100644 --- a/srtcore/crypto.h +++ b/srtcore/crypto.h @@ -38,6 +38,11 @@ extern Logger cnlog; #endif } +namespace srt +{ + class CUDT; +} + // For KMREQ/KMRSP. Only one field is used. const size_t SRT_KMR_KMSTATE = 0; @@ -49,8 +54,7 @@ enum Whether2RegenKm {DONT_REGEN_KM = 0, REGEN_KM = 1}; class CCryptoControl { -//public: - class CUDT* m_parent; + srt::CUDT* m_parent; SRTSOCKET m_SocketID; size_t m_iSndKmKeyLen; //Key length @@ -192,7 +196,7 @@ class CCryptoControl return false; } - CCryptoControl(CUDT* parent, SRTSOCKET id); + CCryptoControl(srt::CUDT* parent, SRTSOCKET id); // DEBUG PURPOSES: std::string CONID() const; @@ -254,14 +258,14 @@ class CCryptoControl /// the encryption will fail. /// XXX Encryption flags in the PH_MSGNO /// field in the header must be correctly set before calling. - EncryptionStatus encrypt(CPacket& w_packet); + EncryptionStatus encrypt(srt::CPacket& w_packet); /// Decrypts the packet. If the packet has ENCKEYSPEC part /// in PH_MSGNO set to EK_NOENC, it does nothing. It decrypts /// only if the encryption correctly configured, otherwise it /// fails. After successful decryption, the ENCKEYSPEC part // in PH_MSGNO is set to EK_NOENC. - EncryptionStatus decrypt(CPacket& w_packet); + EncryptionStatus decrypt(srt::CPacket& w_packet); ~CCryptoControl(); }; diff --git a/srtcore/epoll.h b/srtcore/epoll.h index 3786137d5..63533855c 100644 --- a/srtcore/epoll.h +++ b/srtcore/epoll.h @@ -348,11 +348,18 @@ std::string DisplayEpollWatch(); } }; +namespace srt +{ + class CUDT; + class CRendezvousQueue; + class CUDTGroup; +} + class CEPoll { -friend class CUDT; -friend class CUDTGroup; -friend class CRendezvousQueue; +friend class srt::CUDT; +friend class srt::CUDTGroup; +friend class srt::CRendezvousQueue; public: CEPoll(); diff --git a/srtcore/fec.cpp b/srtcore/fec.cpp index c02af2821..31239eed8 100644 --- a/srtcore/fec.cpp +++ b/srtcore/fec.cpp @@ -35,6 +35,7 @@ using namespace std; using namespace srt_logging; +namespace srt { const char FECFilterBuiltin::defaultConfig [] = "fec,rows:1,layout:staircase,arq:onreq"; @@ -1118,11 +1119,11 @@ static void DebugPrintCells(int32_t base, const std::deque& cells, size_t } // Ok, we have some empty cells, so just adjust to the start of a row. - size_t bstep = i % row_size; - if (i < bstep) // you never know... - i = 0; - else - i -= bstep; + size_t bstep = i % row_size; + if (i < bstep) // you never know... + i = 0; + else + i -= bstep; for ( ; i < cells.size(); i += row_size ) { @@ -2557,3 +2558,5 @@ size_t FECFilterBuiltin::ExtendColumns(size_t colgx) return colgx; } + +} // namespace srt diff --git a/srtcore/fec.h b/srtcore/fec.h index 9423f0d35..57305bfac 100644 --- a/srtcore/fec.h +++ b/srtcore/fec.h @@ -19,6 +19,8 @@ #include "packetfilter_api.h" +namespace srt { + class FECFilterBuiltin: public SrtPacketFilterBase { SrtFilterConfig cfg; @@ -270,4 +272,6 @@ class FECFilterBuiltin: public SrtPacketFilterBase static bool verifyConfig(const SrtFilterConfig& config, std::string& w_errormsg); }; +} // namespace srt + #endif diff --git a/srtcore/group.cpp b/srtcore/group.cpp index b16bfc349..854508ef4 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -13,6 +13,8 @@ using namespace srt_logging; // The SRT_DEF_VERSION is defined in core.cpp. extern const int32_t SRT_DEF_VERSION; +namespace srt { + int32_t CUDTGroup::s_tokenGen = 0; // [[using locked(this->m_GroupLock)]]; @@ -4587,3 +4589,5 @@ void CUDTGroup::debugGroup() } } #endif + +} // namespace srt diff --git a/srtcore/group.h b/srtcore/group.h index ad779e39f..ec5d124d3 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -22,20 +22,24 @@ Written by #include "group_common.h" #include "group_backup.h" +namespace srt +{ + #if ENABLE_HEAVY_LOGGING const char* const srt_log_grp_state[] = {"PENDING", "IDLE", "RUNNING", "BROKEN"}; #endif + class CUDTGroup { friend class CUDTUnited; - typedef srt::sync::steady_clock::time_point time_point; - typedef srt::sync::steady_clock::duration duration; - typedef srt::sync::steady_clock steady_clock; - typedef srt::groups::SocketData SocketData; - typedef srt::groups::SendBackupCtx SendBackupCtx; - typedef srt::groups::BackupMemberState BackupMemberState; + typedef sync::steady_clock::time_point time_point; + typedef sync::steady_clock::duration duration; + typedef sync::steady_clock steady_clock; + typedef groups::SocketData SocketData; + typedef groups::SendBackupCtx SendBackupCtx; + typedef groups::BackupMemberState BackupMemberState; public: typedef SRT_MEMBERSTATUS GroupState; @@ -97,7 +101,7 @@ class CUDTGroup typedef std::list group_t; typedef group_t::iterator gli_t; - typedef std::vector< std::pair > sendable_t; + typedef std::vector< std::pair > sendable_t; struct Sendstate { @@ -211,7 +215,7 @@ class CUDTGroup private: // For Backup, sending all previous packet - int sendBackupRexmit(CUDT& core, SRT_MSGCTRL& w_mc); + int sendBackupRexmit(srt::CUDT& core, SRT_MSGCTRL& w_mc); // Support functions for sendBackup and sendBroadcast /// Check if group member is idle. @@ -232,7 +236,7 @@ class CUDTGroup /// @param[in] currtime current timestamp void sendBackup_QualifyMemberStates(SendBackupCtx& w_sendBackupCtx, const steady_clock::time_point& currtime); - void sendBackup_AssignBackupState(CUDT& socket, BackupMemberState state, const steady_clock::time_point& currtime); + void sendBackup_AssignBackupState(srt::CUDT& socket, BackupMemberState state, const steady_clock::time_point& currtime); /// Qualify the state of the active link: fresh, stable, unstable, wary. /// @retval active backup member state: fresh, stable, unstable, wary. @@ -319,7 +323,7 @@ class CUDTGroup void setOpt(SRT_SOCKOPT optname, const void* optval, int optlen); void getOpt(SRT_SOCKOPT optName, void* optval, int& w_optlen); - void deriveSettings(CUDT* source); + void deriveSettings(srt::CUDT* source); bool applyFlags(uint32_t flags, HandshakeSide); SRT_SOCKSTATUS getStatus(); @@ -333,14 +337,14 @@ class CUDTGroup return m_type == SRT_GTYPE_BROADCAST; } - srt::sync::Mutex* exp_groupLock() { return &m_GroupLock; } - void addEPoll(int eid); - void removeEPollEvents(const int eid); - void removeEPollID(const int eid); - void updateReadState(SRTSOCKET sock, int32_t sequence); - void updateWriteState(); - void updateFailedLink(); - void activateUpdateEvent(bool still_have_items); + sync::Mutex* exp_groupLock() { return &m_GroupLock; } + void addEPoll(int eid); + void removeEPollEvents(const int eid); + void removeEPollID(const int eid); + void updateReadState(SRTSOCKET sock, int32_t sequence); + void updateWriteState(); + void updateFailedLink(); + void activateUpdateEvent(bool still_have_items); /// Update the in-group array of packet providers per sequence number. /// Also basing on the information already provided by possibly other sockets, @@ -353,16 +357,16 @@ class CUDTGroup /// @param provider The core of the socket for which the packet was dispatched /// @param time TSBPD time of this packet /// @return The bitmap that marks by 'false' packets lost since next to exp_sequence - std::vector providePacket(int32_t exp_sequence, int32_t sequence, CUDT* provider, uint64_t time); + std::vector providePacket(int32_t exp_sequence, int32_t sequence, srt::CUDT* provider, uint64_t time); /// This is called from the ACK action by particular socket, which /// actually signs off the packet for extraction. /// /// @param core The socket core for which the ACK was sent /// @param ack The past-the-last-received ACK sequence number - void readyPackets(CUDT* core, int32_t ack); + void readyPackets(srt::CUDT* core, int32_t ack); - void syncWithSocket(const CUDT& core, const HandshakeSide side); + void syncWithSocket(const srt::CUDT& core, const HandshakeSide side); int getGroupData(SRT_SOCKGROUPDATA* pdata, size_t* psize); int getGroupData_LOCKED(SRT_SOCKGROUPDATA* pdata, size_t* psize); int configure(const char* str); @@ -390,7 +394,7 @@ class CUDTGroup // If so, grab the status of all member sockets. void getGroupCount(size_t& w_size, bool& w_still_alive); - class CUDTUnited* m_pGlobal; + class srt::CUDTUnited* m_pGlobal; srt::sync::Mutex m_GroupLock; SRTSOCKET m_GroupID; @@ -493,7 +497,7 @@ class CUDTGroup bool isStillBusy() { - srt::sync::ScopedLock glk(m_GroupLock); + sync::ScopedLock glk(m_GroupLock); return m_iBusy || !m_Group.empty(); } @@ -647,7 +651,7 @@ class CUDTGroup ReadPos* checkPacketAhead(); - void recv_CollectAliveAndBroken(std::vector& w_alive, std::set& w_broken); + void recv_CollectAliveAndBroken(std::vector& w_alive, std::set& w_broken); /// The function polls alive member sockets and retrieves a list of read-ready. /// [acquires lock for CUDT::s_UDTUnited.m_GlobControlLock] @@ -656,7 +660,7 @@ class CUDTGroup /// @returns list of read-ready sockets /// @throws CUDTException(MJ_CONNECTION, MN_NOCONN, 0) /// @throws CUDTException(MJ_AGAIN, MN_RDAVAIL, 0) - std::vector recv_WaitForReadReady(const std::vector& aliveMembers, std::set& w_broken); + std::vector recv_WaitForReadReady(const std::vector& aliveMembers, std::set& w_broken); // This is the sequence number of a packet that has been previously // delivered. Initially it should be set to SRT_SEQNO_NONE so that the sequence read @@ -791,11 +795,11 @@ class CUDTGroup } // Live state synchronization - bool getBufferTimeBase(CUDT* forthesakeof, time_point& w_tb, bool& w_wp, duration& w_dr); + bool getBufferTimeBase(srt::CUDT* forthesakeof, time_point& w_tb, bool& w_wp, duration& w_dr); bool applyGroupSequences(SRTSOCKET, int32_t& w_snd_isn, int32_t& w_rcv_isn); - void synchronizeDrift(CUDT* cu, duration udrift, time_point newtimebase); + void synchronizeDrift(srt::CUDT* cu, duration udrift, time_point newtimebase); - void updateLatestRcv(CUDTSocket*); + void updateLatestRcv(srt::CUDTSocket*); // Property accessors SRTU_PROPERTY_RW_CHAIN(CUDTGroup, SRTSOCKET, id, m_GroupID); @@ -809,4 +813,6 @@ class CUDTGroup SRTU_PROPERTY_RO(bool, closing, m_bClosing); }; +} // namespace srt + #endif // INC_SRT_GROUP_H diff --git a/srtcore/handshake.cpp b/srtcore/handshake.cpp index 95f9cb899..755fb9dbf 100644 --- a/srtcore/handshake.cpp +++ b/srtcore/handshake.cpp @@ -58,18 +58,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "utilities.h" using namespace std; - - -CHandShake::CHandShake(): -m_iVersion(0), -m_iType(0), // Universal: UDT_UNDEFINED or no flags -m_iISN(0), -m_iMSS(0), -m_iFlightFlagSize(0), -m_iReqType(URQ_WAVEAHAND), -m_iID(0), -m_iCookie(0), -m_extension(false) +using namespace srt; + + +CHandShake::CHandShake() + : m_iVersion(0) + , m_iType(0) // Universal: UDT_UNDEFINED or no flags + , m_iISN(0) + , m_iMSS(0) + , m_iFlightFlagSize(0) + , m_iReqType(URQ_WAVEAHAND) + , m_iID(0) + , m_iCookie(0) + , m_extension(false) { for (int i = 0; i < 4; ++ i) m_piPeerIP[i] = 0; diff --git a/srtcore/packet.cpp b/srtcore/packet.cpp index 4524d2232..26a4b2080 100644 --- a/srtcore/packet.cpp +++ b/srtcore/packet.cpp @@ -174,14 +174,14 @@ namespace srt_logging using namespace srt_logging; // Set up the aliases in the constructure -CPacket::CPacket(): -m_extra_pad(), -m_data_owned(false), -m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO])), -m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO])), -m_iTimeStamp((int32_t&)(m_nHeader[SRT_PH_TIMESTAMP])), -m_iID((int32_t&)(m_nHeader[SRT_PH_ID])), -m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef())) +srt::CPacket::CPacket(): + m_extra_pad(), + m_data_owned(false), + m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO])), + m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO])), + m_iTimeStamp((int32_t&)(m_nHeader[SRT_PH_TIMESTAMP])), + m_iID((int32_t&)(m_nHeader[SRT_PH_ID])), + m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef())) { m_nHeader.clear(); @@ -195,12 +195,12 @@ m_pcData((char*&)(m_PacketVector[PV_DATA].dataRef())) m_PacketVector[PV_DATA].set(NULL, 0); } -char* CPacket::getData() +char* srt::CPacket::getData() { return (char*)m_PacketVector[PV_DATA].dataRef(); } -void CPacket::allocate(size_t alloc_buffer_size) +void srt::CPacket::allocate(size_t alloc_buffer_size) { if (m_data_owned) { @@ -214,14 +214,14 @@ void CPacket::allocate(size_t alloc_buffer_size) m_data_owned = true; } -void CPacket::deallocate() +void srt::CPacket::deallocate() { if (m_data_owned) delete [] (char*)m_PacketVector[PV_DATA].data(); m_PacketVector[PV_DATA].set(NULL, 0); } -char* CPacket::release() +char* srt::CPacket::release() { // When not owned, release returns NULL. char* buffer = NULL; @@ -235,7 +235,7 @@ char* CPacket::release() return buffer; } -CPacket::~CPacket() +srt::CPacket::~CPacket() { // PV_HEADER is always owned, PV_DATA may use a "borrowed" buffer. // Delete the internal buffer only if it was declared as owned. @@ -244,17 +244,17 @@ CPacket::~CPacket() } -size_t CPacket::getLength() const +size_t srt::CPacket::getLength() const { return m_PacketVector[PV_DATA].size(); } -void CPacket::setLength(size_t len) +void srt::CPacket::setLength(size_t len) { m_PacketVector[PV_DATA].setLength(len); } -void CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size) +void srt::CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size) { // Set (bit-0 = 1) and (bit-1~15 = type) setControl(pkttype); @@ -365,7 +365,7 @@ void CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, } } -void CPacket::toNL() +void srt::CPacket::toNL() { // XXX USE HtoNLA! if (isControl()) @@ -383,7 +383,7 @@ void CPacket::toNL() } } -void CPacket::toHL() +void srt::CPacket::toHL() { // convert back into local host order uint32_t* p = m_nHeader; @@ -401,22 +401,22 @@ void CPacket::toHL() } -IOVector* CPacket::getPacketVector() +IOVector* srt::CPacket::getPacketVector() { return m_PacketVector; } -UDTMessageType CPacket::getType() const +UDTMessageType srt::CPacket::getType() const { return UDTMessageType(SEQNO_MSGTYPE::unwrap(m_nHeader[SRT_PH_SEQNO])); } -int CPacket::getExtendedType() const +int srt::CPacket::getExtendedType() const { return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]); } -int32_t CPacket::getAckSeqNo() const +int32_t srt::CPacket::getAckSeqNo() const { // read additional information field // This field is used only in UMSG_ACK and UMSG_ACKACK, @@ -425,7 +425,7 @@ int32_t CPacket::getAckSeqNo() const return m_nHeader[SRT_PH_MSGNO]; } -uint16_t CPacket::getControlFlags() const +uint16_t srt::CPacket::getControlFlags() const { // This returns exactly the "extended type" value, // which is not used at all in case when the standard @@ -434,17 +434,17 @@ uint16_t CPacket::getControlFlags() const return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]); } -PacketBoundary CPacket::getMsgBoundary() const +PacketBoundary srt::CPacket::getMsgBoundary() const { return PacketBoundary(MSGNO_PACKET_BOUNDARY::unwrap(m_nHeader[SRT_PH_MSGNO])); } -bool CPacket::getMsgOrderFlag() const +bool srt::CPacket::getMsgOrderFlag() const { return 0!= MSGNO_PACKET_INORDER::unwrap(m_nHeader[SRT_PH_MSGNO]); } -int32_t CPacket::getMsgSeq(bool has_rexmit) const +int32_t srt::CPacket::getMsgSeq(bool has_rexmit) const { if ( has_rexmit ) { @@ -456,13 +456,13 @@ int32_t CPacket::getMsgSeq(bool has_rexmit) const } } -bool CPacket::getRexmitFlag() const +bool srt::CPacket::getRexmitFlag() const { // return false; // return 0 != MSGNO_REXMIT::unwrap(m_nHeader[SRT_PH_MSGNO]); } -EncryptionKeySpec CPacket::getMsgCryptoFlags() const +EncryptionKeySpec srt::CPacket::getMsgCryptoFlags() const { return EncryptionKeySpec(MSGNO_ENCKEYSPEC::unwrap(m_nHeader[SRT_PH_MSGNO])); } @@ -470,19 +470,19 @@ EncryptionKeySpec CPacket::getMsgCryptoFlags() const // This is required as the encryption/decryption happens in place. // This is required to clear off the flags after decryption or set // crypto flags after encrypting a packet. -void CPacket::setMsgCryptoFlags(EncryptionKeySpec spec) +void srt::CPacket::setMsgCryptoFlags(EncryptionKeySpec spec) { int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_ENCKEYSPEC::mask; m_nHeader[SRT_PH_MSGNO] = clr_msgno | EncryptionKeyBits(spec); } -uint32_t CPacket::getMsgTimeStamp() const +uint32_t srt::CPacket::getMsgTimeStamp() const { // SRT_DEBUG_TSBPD_WRAP may enable smaller timestamp for faster wraparoud handling tests return (uint32_t)m_nHeader[SRT_PH_TIMESTAMP] & TIMESTAMP_MASK; } -CPacket* CPacket::clone() const +srt::CPacket* srt::CPacket::clone() const { CPacket* pkt = new CPacket; memcpy((pkt->m_nHeader), m_nHeader, HDR_SIZE); @@ -493,6 +493,8 @@ CPacket* CPacket::clone() const return pkt; } +namespace srt { + // Useful for debugging std::string PacketMessageFlagStr(uint32_t msgno_field) { @@ -521,8 +523,10 @@ inline void SprintSpecialWord(std::ostream& os, int32_t val) os << val; } +} // namespace srt + #if ENABLE_LOGGING -std::string CPacket::Info() +std::string srt::CPacket::Info() { std::ostringstream os; os << "TARGET=@" << m_iID << " "; diff --git a/srtcore/packet.h b/srtcore/packet.h index 8724e9d07..c968b08c0 100644 --- a/srtcore/packet.h +++ b/srtcore/packet.h @@ -214,9 +214,9 @@ inline EncryptionKeySpec GetEncryptionKeySpec(int32_t msgno) const int32_t PUMASK_SEQNO_PROBE = 0xF; -std::string PacketMessageFlagStr(uint32_t msgno_field); -class CChannel; +namespace srt { +std::string PacketMessageFlagStr(uint32_t msgno_field); class CPacket { @@ -284,7 +284,7 @@ friend class CRcvQueue; void setControl(UDTMessageType type) { - m_nHeader[SRT_PH_SEQNO] = SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(type); + m_nHeader[srt::SRT_PH_SEQNO] = SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(type); } /// Read the extended packet type. @@ -430,4 +430,6 @@ friend class CRcvQueue; #endif }; +} // namespace srt + #endif diff --git a/srtcore/packetfilter.cpp b/srtcore/packetfilter.cpp index 1122c06a2..dffb2a8ba 100644 --- a/srtcore/packetfilter.cpp +++ b/srtcore/packetfilter.cpp @@ -26,7 +26,7 @@ using namespace std; using namespace srt_logging; using namespace srt::sync; -bool ParseFilterConfig(std::string s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf) +bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf) { if (!SrtParseConfig(s, (w_config))) return false; @@ -43,13 +43,13 @@ bool ParseFilterConfig(std::string s, SrtFilterConfig& w_config, PacketFilter::F return true; } -bool ParseFilterConfig(std::string s, SrtFilterConfig& w_config) +bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config) { return ParseFilterConfig(s, (w_config), NULL); } // Parameters are passed by value because they need to be potentially modicied inside. -bool CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer) +bool srt::CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer) { PacketFilter::Factory* fac = PacketFilter::find(w_agent.type); if (!fac) @@ -109,18 +109,20 @@ bool CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer) return true; } -struct SortBySequence -{ - bool operator()(const CUnit* u1, const CUnit* u2) +namespace srt { + struct SortBySequence { - int32_t s1 = u1->m_Packet.getSeqNo(); - int32_t s2 = u2->m_Packet.getSeqNo(); + bool operator()(const CUnit* u1, const CUnit* u2) + { + int32_t s1 = u1->m_Packet.getSeqNo(); + int32_t s2 = u2->m_Packet.getSeqNo(); - return CSeqNo::seqcmp(s1, s2) < 0; - } -}; + return CSeqNo::seqcmp(s1, s2) < 0; + } + }; +} // namespace srt -void PacketFilter::receive(CUnit* unit, std::vector& w_incoming, loss_seqs_t& w_loss_seqs) +void srt::PacketFilter::receive(CUnit* unit, std::vector& w_incoming, loss_seqs_t& w_loss_seqs) { const CPacket& rpkt = unit->m_Packet; @@ -206,7 +208,7 @@ void PacketFilter::receive(CUnit* unit, std::vector& w_incoming, loss_se } -bool PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet) +bool srt::PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet) { bool have = m_filter->packControlPacket(m_sndctlpkt, seq); if (!have) @@ -238,7 +240,7 @@ bool PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet) } -void PacketFilter::InsertRebuilt(vector& incoming, CUnitQueue* uq) +void srt::PacketFilter::InsertRebuilt(vector& incoming, CUnitQueue* uq) { if (m_provided.empty()) return; @@ -273,19 +275,21 @@ void PacketFilter::InsertRebuilt(vector& incoming, CUnitQueue* uq) m_provided.clear(); } -bool PacketFilter::IsBuiltin(const string& s) +bool srt::PacketFilter::IsBuiltin(const string& s) { return builtin_filters.count(s); } +namespace srt { std::set PacketFilter::builtin_filters; PacketFilter::filters_map_t PacketFilter::filters; +} -PacketFilter::Factory::~Factory() +srt::PacketFilter::Factory::~Factory() { } -void PacketFilter::globalInit() +void srt::PacketFilter::globalInit() { // Add here builtin packet filters and mark them // as builtin. This will disallow users to register @@ -295,7 +299,7 @@ void PacketFilter::globalInit() builtin_filters.insert("fec"); } -bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr) +bool srt::PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr) { m_parent = parent; @@ -329,7 +333,7 @@ bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& co return true; } -bool PacketFilter::correctConfig(const SrtFilterConfig& conf) +bool srt::PacketFilter::correctConfig(const SrtFilterConfig& conf) { const string* pname = map_getp(conf.parameters, "type"); @@ -346,7 +350,7 @@ bool PacketFilter::correctConfig(const SrtFilterConfig& conf) return true; } -PacketFilter::~PacketFilter() +srt::PacketFilter::~PacketFilter() { delete m_filter; } diff --git a/srtcore/packetfilter.h b/srtcore/packetfilter.h index 545e38e02..a26b07fa5 100644 --- a/srtcore/packetfilter.h +++ b/srtcore/packetfilter.h @@ -19,6 +19,8 @@ #include "utilities.h" #include "packetfilter_api.h" +namespace srt { + class CUnitQueue; struct CUnit; class CUDT; @@ -212,4 +214,6 @@ inline SRT_ARQLevel PacketFilter::arqLevel() { SRT_ASSERT(m_filter); return m_fi bool ParseFilterConfig(std::string s, SrtFilterConfig& out, PacketFilter::Factory** ppf); +} // namespace srt + #endif diff --git a/srtcore/packetfilter_api.h b/srtcore/packetfilter_api.h index 74279f9e3..d714b865b 100644 --- a/srtcore/packetfilter_api.h +++ b/srtcore/packetfilter_api.h @@ -19,6 +19,8 @@ #include #include +namespace srt { + class CPacket; enum SrtPktHeaderFields @@ -151,6 +153,6 @@ class SrtPacketFilterBase } }; - +} // namespace srt #endif diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index ccc14b9b8..fe323ab4c 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -65,7 +65,7 @@ using namespace std; using namespace srt::sync; using namespace srt_logging; -CUnitQueue::CUnitQueue() +srt::CUnitQueue::CUnitQueue() : m_pQEntry(NULL) , m_pCurrQueue(NULL) , m_pLastQueue(NULL) @@ -76,7 +76,7 @@ CUnitQueue::CUnitQueue() { } -CUnitQueue::~CUnitQueue() +srt::CUnitQueue::~CUnitQueue() { CQEntry* p = m_pQEntry; @@ -94,7 +94,7 @@ CUnitQueue::~CUnitQueue() } } -int CUnitQueue::init(int size, int mss, int version) +int srt::CUnitQueue::init(int size, int mss, int version) { CQEntry* tempq = NULL; CUnit* tempu = NULL; @@ -138,7 +138,7 @@ int CUnitQueue::init(int size, int mss, int version) // XXX Lots of common code with CUnitQueue:init. // Consider merging. -int CUnitQueue::increase() +int srt::CUnitQueue::increase() { // adjust/correct m_iCount int real_count = 0; @@ -202,13 +202,13 @@ int CUnitQueue::increase() return 0; } -int CUnitQueue::shrink() +int srt::CUnitQueue::shrink() { // currently queue cannot be shrunk. return -1; } -CUnit* CUnitQueue::getNextAvailUnit() +srt::CUnit* srt::CUnitQueue::getNextAvailUnit() { if (m_iCount * 10 > m_iSize * 9) increase(); @@ -237,7 +237,7 @@ CUnit* CUnitQueue::getNextAvailUnit() return NULL; } -void CUnitQueue::makeUnitFree(CUnit* unit) +void srt::CUnitQueue::makeUnitFree(CUnit* unit) { SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag != CUnit::FREE); @@ -245,7 +245,7 @@ void CUnitQueue::makeUnitFree(CUnit* unit) --m_iCount; } -void CUnitQueue::makeUnitGood(CUnit* unit) +void srt::CUnitQueue::makeUnitGood(CUnit* unit) { SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag == CUnit::FREE); @@ -253,7 +253,7 @@ void CUnitQueue::makeUnitGood(CUnit* unit) ++m_iCount; } -CSndUList::CSndUList() +srt::CSndUList::CSndUList() : m_pHeap(NULL) , m_iArrayLength(512) , m_iLastEntry(-1) @@ -265,12 +265,12 @@ CSndUList::CSndUList() m_pHeap = new CSNode*[m_iArrayLength]; } -CSndUList::~CSndUList() +srt::CSndUList::~CSndUList() { delete[] m_pHeap; } -void CSndUList::update(const CUDT* u, EReschedule reschedule) +void srt::CSndUList::update(const CUDT* u, EReschedule reschedule) { ScopedLock listguard(m_ListLock); @@ -296,7 +296,7 @@ void CSndUList::update(const CUDT* u, EReschedule reschedule) insert_(steady_clock::now(), u); } -int CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) +int srt::CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) { ScopedLock listguard(m_ListLock); @@ -337,14 +337,14 @@ int CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) return 1; } -void CSndUList::remove(const CUDT* u) +void srt::CSndUList::remove(const CUDT* u) { ScopedLock listguard(m_ListLock); remove_(u); } -steady_clock::time_point CSndUList::getNextProcTime() +steady_clock::time_point srt::CSndUList::getNextProcTime() { ScopedLock listguard(m_ListLock); @@ -354,7 +354,7 @@ steady_clock::time_point CSndUList::getNextProcTime() return m_pHeap[0]->m_tsTimeStamp; } -void CSndUList::realloc_() +void srt::CSndUList::realloc_() { CSNode** temp = NULL; @@ -373,7 +373,7 @@ void CSndUList::realloc_() m_pHeap = temp; } -void CSndUList::insert_(const steady_clock::time_point& ts, const CUDT* u) +void srt::CSndUList::insert_(const steady_clock::time_point& ts, const CUDT* u) { // increase the heap array size if necessary if (m_iLastEntry == m_iArrayLength - 1) @@ -382,7 +382,7 @@ void CSndUList::insert_(const steady_clock::time_point& ts, const CUDT* u) insert_norealloc_(ts, u); } -void CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT* u) +void srt::CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT* u) { CSNode* n = u->m_pSNode; @@ -422,7 +422,7 @@ void CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const CUDT } } -void CSndUList::remove_(const CUDT* u) +void srt::CSndUList::remove_(const CUDT* u) { CSNode* n = u->m_pSNode; @@ -462,7 +462,7 @@ void CSndUList::remove_(const CUDT* u) } // -CSndQueue::CSndQueue() +srt::CSndQueue::CSndQueue() : m_pSndUList(NULL) , m_pChannel(NULL) , m_pTimer(NULL) @@ -472,7 +472,7 @@ CSndQueue::CSndQueue() setupCond(m_WindowCond, "Window"); } -CSndQueue::~CSndQueue() +srt::CSndQueue::~CSndQueue() { m_bClosing = true; @@ -493,20 +493,20 @@ CSndQueue::~CSndQueue() delete m_pSndUList; } -int CSndQueue::ioctlQuery(int type) const +int srt::CSndQueue::ioctlQuery(int type) const { return m_pChannel->ioctlQuery(type); } -int CSndQueue::sockoptQuery(int level, int type) const +int srt::CSndQueue::sockoptQuery(int level, int type) const { return m_pChannel->sockoptQuery(level, type); } #if ENABLE_LOGGING -int CSndQueue::m_counter = 0; +int srt::CSndQueue::m_counter = 0; #endif -void CSndQueue::init(CChannel* c, CTimer* t) +void srt::CSndQueue::init(CChannel* c, CTimer* t) { m_pChannel = c; m_pTimer = t; @@ -526,24 +526,24 @@ void CSndQueue::init(CChannel* c, CTimer* t) throw CUDTException(MJ_SYSTEMRES, MN_THREAD); } -int CSndQueue::getIpTTL() const +int srt::CSndQueue::getIpTTL() const { return m_pChannel ? m_pChannel->getIpTTL() : -1; } -int CSndQueue::getIpToS() const +int srt::CSndQueue::getIpToS() const { return m_pChannel ? m_pChannel->getIpToS() : -1; } #ifdef SRT_ENABLE_BINDTODEVICE -bool CSndQueue::getBind(char* dst, size_t len) const +bool srt::CSndQueue::getBind(char* dst, size_t len) const { return m_pChannel ? m_pChannel->getBind(dst, len) : false; } #endif -void* CSndQueue::worker(void* param) +void* srt::CSndQueue::worker(void* param) { CSndQueue* self = (CSndQueue*)param; @@ -645,7 +645,7 @@ void* CSndQueue::worker(void* param) return NULL; } -int CSndQueue::sendto(const sockaddr_any& w_addr, CPacket& w_packet) +int srt::CSndQueue::sendto(const sockaddr_any& w_addr, CPacket& w_packet) { // send out the packet immediately (high priority), this is a control packet m_pChannel->sendto(w_addr, w_packet); @@ -653,15 +653,15 @@ int CSndQueue::sendto(const sockaddr_any& w_addr, CPacket& w_packet) } // -CRcvUList::CRcvUList() +srt::CRcvUList::CRcvUList() : m_pUList(NULL) , m_pLast(NULL) { } -CRcvUList::~CRcvUList() {} +srt::CRcvUList::~CRcvUList() {} -void CRcvUList::insert(const CUDT* u) +void srt::CRcvUList::insert(const CUDT* u) { CRNode* n = u->m_pRNode; n->m_tsTimeStamp = steady_clock::now(); @@ -682,7 +682,7 @@ void CRcvUList::insert(const CUDT* u) m_pLast = n; } -void CRcvUList::remove(const CUDT* u) +void srt::CRcvUList::remove(const CUDT* u) { CRNode* n = u->m_pRNode; @@ -713,7 +713,7 @@ void CRcvUList::remove(const CUDT* u) n->m_pNext = n->m_pPrev = NULL; } -void CRcvUList::update(const CUDT* u) +void srt::CRcvUList::update(const CUDT* u) { CRNode* n = u->m_pRNode; @@ -744,13 +744,13 @@ void CRcvUList::update(const CUDT* u) } // -CHash::CHash() +srt::CHash::CHash() : m_pBucket(NULL) , m_iHashSize(0) { } -CHash::~CHash() +srt::CHash::~CHash() { for (int i = 0; i < m_iHashSize; ++i) { @@ -766,7 +766,7 @@ CHash::~CHash() delete[] m_pBucket; } -void CHash::init(int size) +void srt::CHash::init(int size) { m_pBucket = new CBucket*[size]; @@ -776,7 +776,7 @@ void CHash::init(int size) m_iHashSize = size; } -CUDT* CHash::lookup(int32_t id) +srt::CUDT* srt::CHash::lookup(int32_t id) { // simple hash function (% hash table size); suitable for socket descriptors CBucket* b = m_pBucket[id % m_iHashSize]; @@ -791,7 +791,7 @@ CUDT* CHash::lookup(int32_t id) return NULL; } -void CHash::insert(int32_t id, CUDT* u) +void srt::CHash::insert(int32_t id, CUDT* u) { CBucket* b = m_pBucket[id % m_iHashSize]; @@ -803,7 +803,7 @@ void CHash::insert(int32_t id, CUDT* u) m_pBucket[id % m_iHashSize] = n; } -void CHash::remove(int32_t id) +void srt::CHash::remove(int32_t id) { CBucket* b = m_pBucket[id % m_iHashSize]; CBucket* p = NULL; @@ -828,18 +828,18 @@ void CHash::remove(int32_t id) } // -CRendezvousQueue::CRendezvousQueue() +srt::CRendezvousQueue::CRendezvousQueue() : m_lRendezvousID() , m_RIDListLock() { } -CRendezvousQueue::~CRendezvousQueue() +srt::CRendezvousQueue::~CRendezvousQueue() { m_lRendezvousID.clear(); } -void CRendezvousQueue::insert(const SRTSOCKET& id, +void srt::CRendezvousQueue::insert(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const steady_clock::time_point& ttl) @@ -858,7 +858,7 @@ void CRendezvousQueue::insert(const SRTSOCKET& id, << " (total connectors: " << m_lRendezvousID.size() << ")"); } -void CRendezvousQueue::remove(const SRTSOCKET& id) +void srt::CRendezvousQueue::remove(const SRTSOCKET& id) { ScopedLock lkv(m_RIDListLock); @@ -872,7 +872,7 @@ void CRendezvousQueue::remove(const SRTSOCKET& id) } } -CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) const +srt::CUDT* srt::CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) const { ScopedLock vg(m_RIDListLock); @@ -903,7 +903,7 @@ CUDT* CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& w_id) cons return NULL; } -void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn) +void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn) { vector toRemove, toProcess; @@ -1005,7 +1005,7 @@ void CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, con } } -bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, +bool srt::CRendezvousQueue::qualifyToHandle(EReadStatus rst, EConnectStatus cst SRT_ATR_UNUSED, int iDstSockID, vector& toRemove, @@ -1109,7 +1109,7 @@ bool CRendezvousQueue::qualifyToHandle(EReadStatus rst, } // -CRcvQueue::CRcvQueue() +srt::CRcvQueue::CRcvQueue() : m_WorkerThread() , m_UnitQueue() , m_pRcvUList(NULL) @@ -1129,7 +1129,7 @@ CRcvQueue::CRcvQueue() setupCond(m_BufferCond, "QueueBuffer"); } -CRcvQueue::~CRcvQueue() +srt::CRcvQueue::~CRcvQueue() { m_bClosing = true; @@ -1158,10 +1158,10 @@ CRcvQueue::~CRcvQueue() } #if ENABLE_LOGGING -int CRcvQueue::m_counter = 0; +int srt::CRcvQueue::m_counter = 0; #endif -void CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel* cc, CTimer* t) +void srt::CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel* cc, CTimer* t) { m_szPayloadSize = payload; @@ -1189,7 +1189,7 @@ void CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CChannel } } -void* CRcvQueue::worker(void* param) +void* srt::CRcvQueue::worker(void* param) { CRcvQueue* self = (CRcvQueue*)param; sockaddr_any sa(self->m_UnitQueue.getIPversion()); @@ -1322,7 +1322,7 @@ void* CRcvQueue::worker(void* param) return NULL; } -EReadStatus CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockaddr_any& w_addr) +EReadStatus srt::CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockaddr_any& w_addr) { #if !USE_BUSY_WAITING // This might be not really necessary, and probably @@ -1380,7 +1380,7 @@ EReadStatus CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_unit, sockad return rst; } -EConnectStatus CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& addr) +EConnectStatus srt::CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& addr) { HLOGC(cnlog.Debug, log << "Got sockID=0 from " << addr.str() << " - trying to resolve it as a connection request..."); @@ -1423,7 +1423,7 @@ EConnectStatus CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit, const soc return worker_TryAsyncRend_OrStore(0, unit, addr); // 0 id because the packet came in with that very ID. } -EConnectStatus CRcvQueue::worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& addr) +EConnectStatus srt::CRcvQueue::worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& addr) { CUDT* u = m_pHash->lookup(id); if (!u) @@ -1475,7 +1475,7 @@ EConnectStatus CRcvQueue::worker_ProcessAddressedPacket(int32_t id, CUnit* unit, // This function then tries to manage the packet as a rendezvous connection // request in ASYNC mode; when this is not applicable, it stores the packet // in the "receiving queue" so that it will be picked up in the "main" thread. -EConnectStatus CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr_any& addr) +EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, const sockaddr_any& addr) { // This 'retrieve' requires that 'id' be either one of those // stored in the rendezvous queue (see CRcvQueue::registerConnector) @@ -1605,7 +1605,7 @@ EConnectStatus CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* unit, c return CONN_CONTINUE; } -void CRcvQueue::stopWorker() +void srt::CRcvQueue::stopWorker() { // We use the decent way, so we say to the thread "please exit". m_bClosing = true; @@ -1622,7 +1622,7 @@ void CRcvQueue::stopWorker() m_WorkerThread.join(); } -int CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) +int srt::CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) { UniqueLock bufferlock(m_BufferLock); CSync buffercond(m_BufferCond, bufferlock); @@ -1676,7 +1676,7 @@ int CRcvQueue::recvfrom(int32_t id, CPacket& w_packet) return (int)w_packet.getLength(); } -int CRcvQueue::setListener(CUDT* u) +int srt::CRcvQueue::setListener(CUDT* u) { ScopedLock lslock(m_LSLock); @@ -1687,7 +1687,7 @@ int CRcvQueue::setListener(CUDT* u) return 0; } -void CRcvQueue::removeListener(const CUDT* u) +void srt::CRcvQueue::removeListener(const CUDT* u) { ScopedLock lslock(m_LSLock); @@ -1695,7 +1695,7 @@ void CRcvQueue::removeListener(const CUDT* u) m_pListener = NULL; } -void CRcvQueue::registerConnector(const SRTSOCKET& id, +void srt::CRcvQueue::registerConnector(const SRTSOCKET& id, CUDT* u, const sockaddr_any& addr, const steady_clock::time_point& ttl) @@ -1705,7 +1705,7 @@ void CRcvQueue::registerConnector(const SRTSOCKET& id, m_pRendezvousQueue->insert(id, u, addr, ttl); } -void CRcvQueue::removeConnector(const SRTSOCKET& id) +void srt::CRcvQueue::removeConnector(const SRTSOCKET& id) { HLOGC(cnlog.Debug, log << "removeConnector: removing @" << id); m_pRendezvousQueue->remove(id); @@ -1727,19 +1727,19 @@ void CRcvQueue::removeConnector(const SRTSOCKET& id) } } -void CRcvQueue::setNewEntry(CUDT* u) +void srt::CRcvQueue::setNewEntry(CUDT* u) { HLOGC(cnlog.Debug, log << CUDTUnited::CONID(u->m_SocketID) << "setting socket PENDING FOR CONNECTION"); ScopedLock listguard(m_IDLock); m_vNewEntry.push_back(u); } -bool CRcvQueue::ifNewEntry() +bool srt::CRcvQueue::ifNewEntry() { return !(m_vNewEntry.empty()); } -CUDT* CRcvQueue::getNewEntry() +srt::CUDT* srt::CRcvQueue::getNewEntry() { ScopedLock listguard(m_IDLock); @@ -1752,7 +1752,7 @@ CUDT* CRcvQueue::getNewEntry() return u; } -void CRcvQueue::storePkt(int32_t id, CPacket* pkt) +void srt::CRcvQueue::storePkt(int32_t id, CPacket* pkt) { UniqueLock bufferlock(m_BufferLock); CSync passcond(m_BufferCond, bufferlock); @@ -1774,7 +1774,7 @@ void CRcvQueue::storePkt(int32_t id, CPacket* pkt) } } -void CMultiplexer::destroy() +void srt::CMultiplexer::destroy() { // Reverse order of the assigned delete m_pRcvQueue; diff --git a/srtcore/queue.h b/srtcore/queue.h index a412fd516..b2ccb36d8 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -63,8 +63,10 @@ modified by #include #include -class CUDT; +namespace srt +{ class CChannel; +class CUDT; struct CUnit { @@ -92,7 +94,6 @@ class CUnitQueue /// @param [in] mss maximum segment size /// @param [in] version IP version /// @return 0: success, -1: failure. - int init(int size, int mss, int version); /// Increase (double) the unit queue size. @@ -112,7 +113,6 @@ class CUnitQueue public: // Operations on units /// find an available unit for incoming packet. /// @return Pointer to the available unit, NULL if not found. - CUnit* getNextAvailUnit(); void makeUnitFree(CUnit* unit); @@ -149,8 +149,8 @@ class CUnitQueue struct CSNode { - CUDT* m_pUDT; // Pointer to the instance of CUDT socket - srt::sync::steady_clock::time_point m_tsTimeStamp; + CUDT* m_pUDT; // Pointer to the instance of CUDT socket + sync::steady_clock::time_point m_tsTimeStamp; int m_iHeapLoc; // location on the heap, -1 means not on the heap }; @@ -193,7 +193,7 @@ class CSndUList /// Retrieve the next scheduled processing time. /// @return Scheduled processing time of the first UDT socket in the list. - srt::sync::steady_clock::time_point getNextProcTime(); + sync::steady_clock::time_point getNextProcTime(); private: /// Doubles the size of the list. @@ -204,14 +204,14 @@ class CSndUList /// /// @param [in] ts time stamp: next processing time /// @param [in] u pointer to the UDT instance - void insert_(const srt::sync::steady_clock::time_point& ts, const CUDT* u); + void insert_(const sync::steady_clock::time_point& ts, const CUDT* u); /// Insert a new UDT instance into the list without realloc. /// Should be called if there is a gauranteed space for the element. /// /// @param [in] ts time stamp: next processing time /// @param [in] u pointer to the UDT instance - void insert_norealloc_(const srt::sync::steady_clock::time_point& ts, const CUDT* u); + void insert_norealloc_(const sync::steady_clock::time_point& ts, const CUDT* u); void remove_(const CUDT* u); @@ -220,12 +220,12 @@ class CSndUList int m_iArrayLength; // physical length of the array int m_iLastEntry; // position of last entry on the heap array - srt::sync::Mutex m_ListLock; + sync::Mutex m_ListLock; - srt::sync::Mutex* m_pWindowLock; - srt::sync::Condition* m_pWindowCond; + sync::Mutex* m_pWindowLock; + sync::Condition* m_pWindowCond; - srt::sync::CTimer* m_pTimer; + sync::CTimer* m_pTimer; private: CSndUList(const CSndUList&); @@ -234,8 +234,8 @@ class CSndUList struct CRNode { - CUDT* m_pUDT; // Pointer to the instance of CUDT socket - srt::sync::steady_clock::time_point m_tsTimeStamp; // Time Stamp + CUDT* m_pUDT; // Pointer to the instance of CUDT socket + sync::steady_clock::time_point m_tsTimeStamp; // Time Stamp CRNode* m_pPrev; // previous link CRNode* m_pNext; // next link @@ -401,7 +401,7 @@ class CRendezvousQueue }; std::list m_lRendezvousID; // The sockets currently in rendezvous mode - mutable srt::sync::Mutex m_RIDListLock; + mutable sync::Mutex m_RIDListLock; }; class CSndQueue @@ -514,7 +514,7 @@ class CRcvQueue /// @param [in] c UDP channel to be associated to the queue /// @param [in] t timer - void init(int size, size_t payload, int version, int hsize, CChannel* c, srt::sync::CTimer* t); + void init(int size, size_t payload, int version, int hsize, CChannel* c, sync::CTimer* t); /// Read a packet for a specific UDT socket id. /// @param [in] id Socket ID @@ -528,8 +528,8 @@ class CRcvQueue void setClosing() { m_bClosing = true; } private: - static void* worker(void* param); - srt::sync::CThread m_WorkerThread; + static void* worker(void* param); + sync::CThread m_WorkerThread; // Subroutines of worker EReadStatus worker_RetrieveUnit(int32_t& id, CUnit*& unit, sockaddr_any& sa); EConnectStatus worker_ProcessConnectionRequest(CUnit* unit, const sockaddr_any& sa); @@ -537,11 +537,11 @@ class CRcvQueue EConnectStatus worker_ProcessAddressedPacket(int32_t id, CUnit* unit, const sockaddr_any& sa); private: - CUnitQueue m_UnitQueue; // The received packet queue - CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue - CHash* m_pHash; // Hash table for UDT socket looking up - CChannel* m_pChannel; // UDP channel for receving packets - srt::sync::CTimer* m_pTimer; // shared timer with the snd queue + CUnitQueue m_UnitQueue; // The received packet queue + CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue + CHash* m_pHash; // Hash table for UDT socket looking up + CChannel* m_pChannel; // UDP channel for receving packets + sync::CTimer* m_pTimer; // shared timer with the snd queue size_t m_szPayloadSize; // packet payload size @@ -554,10 +554,10 @@ class CRcvQueue int setListener(CUDT* u); void removeListener(const CUDT* u); - void registerConnector(const SRTSOCKET& id, - CUDT* u, - const sockaddr_any& addr, - const srt::sync::steady_clock::time_point& ttl); + void registerConnector(const SRTSOCKET& id, + CUDT* u, + const sockaddr_any& addr, + const sync::steady_clock::time_point& ttl); void removeConnector(const SRTSOCKET& id); void setNewEntry(CUDT* u); @@ -567,16 +567,16 @@ class CRcvQueue void storePkt(int32_t id, CPacket* pkt); private: - srt::sync::Mutex m_LSLock; + sync::Mutex m_LSLock; CUDT* m_pListener; // pointer to the (unique, if any) listening UDT entity CRendezvousQueue* m_pRendezvousQueue; // The list of sockets in rendezvous mode std::vector m_vNewEntry; // newly added entries, to be inserted - srt::sync::Mutex m_IDLock; + sync::Mutex m_IDLock; std::map > m_mBuffer; // temporary buffer for rendezvous connection request - srt::sync::Mutex m_BufferLock; - srt::sync::Condition m_BufferCond; + sync::Mutex m_BufferLock; + sync::Condition m_BufferCond; private: CRcvQueue(const CRcvQueue&); @@ -585,10 +585,10 @@ class CRcvQueue struct CMultiplexer { - CSndQueue* m_pSndQueue; // The sending queue - CRcvQueue* m_pRcvQueue; // The receiving queue - CChannel* m_pChannel; // The UDP channel for sending and receiving - srt::sync::CTimer* m_pTimer; // The timer + CSndQueue* m_pSndQueue; // The sending queue + CRcvQueue* m_pRcvQueue; // The receiving queue + CChannel* m_pChannel; // The UDP channel for sending and receiving + sync::CTimer* m_pTimer; // The timer int m_iPort; // The UDP port number of this multiplexer int m_iIPversion; // Address family (AF_INET or AF_INET6) @@ -611,4 +611,6 @@ struct CMultiplexer void destroy(); }; +} // namespace srt + #endif diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 1db4bb63a..72b90195e 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -396,7 +396,7 @@ struct CSrtConfigSetter static void set(CSrtConfig& co, const void* optval, int optlen) { int ival = cast_optval(optval, optlen); - if (ival < int(CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize)) + if (ival < int(srt::CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize)) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); co.iMSS = ival; @@ -435,7 +435,7 @@ struct CSrtConfigSetter if (bs <= 0) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.iSndBufSize = bs / (co.iMSS - CPacket::UDP_HDR_SIZE); + co.iSndBufSize = bs / (co.iMSS - srt::CPacket::UDP_HDR_SIZE); } }; @@ -449,7 +449,7 @@ struct CSrtConfigSetter throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); // Mimimum recv buffer size is 32 packets - const int mssin_size = co.iMSS - CPacket::UDP_HDR_SIZE; + const int mssin_size = co.iMSS - srt::CPacket::UDP_HDR_SIZE; if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT) co.iRcvBufSize = val / mssin_size; @@ -937,8 +937,8 @@ struct CSrtConfigSetter // This means that the filter might have been installed before, // and the fix to the maximum payload size was already applied. // This needs to be checked now. - SrtFilterConfig fc; - if (!ParseFilterConfig(co.sPacketFilterConfig.str(), fc)) + srt::SrtFilterConfig fc; + if (!srt::ParseFilterConfig(co.sPacketFilterConfig.str(), fc)) { // Break silently. This should not happen LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: IPE: failing filter configuration installed"); @@ -1128,9 +1128,9 @@ struct CSrtConfigSetter using namespace srt_logging; std::string arg((const char*)optval, optlen); // Parse the configuration string prematurely - SrtFilterConfig fc; - PacketFilter::Factory* fax = 0; - if (!ParseFilterConfig(arg, (fc), (&fax))) + srt::SrtFilterConfig fc; + srt::PacketFilter::Factory* fax = 0; + if (!srt::ParseFilterConfig(arg, (fc), (&fax))) { LOGC(aclog.Error, log << "SRTO_PACKETFILTER: Incorrect syntax. Use: FILTERTYPE[,KEY:VALUE...]. " diff --git a/srtcore/srt_c_api.cpp b/srtcore/srt_c_api.cpp index bfd130148..dbe668743 100644 --- a/srtcore/srt_c_api.cpp +++ b/srtcore/srt_c_api.cpp @@ -24,6 +24,7 @@ written by #include "utilities.h" using namespace std; +using namespace srt; extern "C" { diff --git a/srtcore/udt.h b/srtcore/udt.h index 8d7d5eb87..b1af441b2 100644 --- a/srtcore/udt.h +++ b/srtcore/udt.h @@ -249,7 +249,7 @@ namespace logging { using namespace srt_logging; } -} +} // namespace srt // Planned deprecated removal: rel1.6.0 // There's also no portable way possible to enforce a deprecation diff --git a/srtcore/window.cpp b/srtcore/window.cpp index ea8386fe1..96562d7a4 100644 --- a/srtcore/window.cpp +++ b/srtcore/window.cpp @@ -151,7 +151,7 @@ void CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_probeW r_probeWindow[k] = 1000; //1 msec -> 1000 pkts/sec for (size_t i = 0; i < asize; ++ i) - r_bytesWindow[i] = CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i] + r_bytesWindow[i] = srt::CPacket::SRT_MAX_PAYLOAD_SIZE; //based on 1 pkt/sec set in r_pktWindow[i] } @@ -188,7 +188,7 @@ int CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, cons // claculate speed, or return 0 if not enough valid value if (count > (asize >> 1)) { - bytes += (CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received + bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received bytesps = (unsigned long)ceil(1000000.0 / (double(sum) / double(bytes))); return (int)ceil(1000000.0 / (sum / count)); } diff --git a/srtcore/window.h b/srtcore/window.h index 7dbfb73bf..d1065b3da 100644 --- a/srtcore/window.h +++ b/srtcore/window.h @@ -231,7 +231,7 @@ class CPktTimeWindow: CPktTimeWindowTools } /// Shortcut to test a packet for possible probe 1 or 2 - void probeArrival(const CPacket& pkt, bool unordered) + void probeArrival(const srt::CPacket& pkt, bool unordered) { const int inorder16 = pkt.m_iSeqNo & PUMASK_SEQNO_PROBE; @@ -252,7 +252,7 @@ class CPktTimeWindow: CPktTimeWindowTools } /// Record the arrival time of the first probing packet. - void probe1Arrival(const CPacket& pkt, bool unordered) + void probe1Arrival(const srt::CPacket& pkt, bool unordered) { if (unordered && pkt.m_iSeqNo == m_Probe1Sequence) { @@ -269,7 +269,7 @@ class CPktTimeWindow: CPktTimeWindowTools /// Record the arrival time of the second probing packet and the interval between packet pairs. - void probe2Arrival(const CPacket& pkt) + void probe2Arrival(const srt::CPacket& pkt) { // Reject probes that don't refer to the very next packet // towards the one that was lately notified by probe1Arrival. @@ -299,7 +299,7 @@ class CPktTimeWindow: CPktTimeWindowTools // record the probing packets interval // Adjust the time for what a complete packet would have take const int64_t timediff = srt::sync::count_microseconds(m_tsCurrArrTime - m_tsProbeTime); - const int64_t timediff_times_pl_size = timediff * CPacket::SRT_MAX_PAYLOAD_SIZE; + const int64_t timediff_times_pl_size = timediff * srt::CPacket::SRT_MAX_PAYLOAD_SIZE; // Let's take it simpler than it is coded here: // (stating that a packet has never zero size) diff --git a/test/test_buffer.cpp b/test/test_buffer.cpp index 795a6d52f..047ced7e2 100644 --- a/test/test_buffer.cpp +++ b/test/test_buffer.cpp @@ -2,6 +2,8 @@ #include "gtest/gtest.h" #include "buffer.h" +using namespace srt; + TEST(CRcvBuffer, Create) { diff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp index 913473af7..8ea7ea26b 100644 --- a/test/test_fec_rebuilding.cpp +++ b/test/test_fec_rebuilding.cpp @@ -13,6 +13,7 @@ #include "api.h" using namespace std; +using namespace srt; class TestFECRebuilding: public testing::Test { @@ -91,16 +92,18 @@ class TestFECRebuilding: public testing::Test } }; -class TestMockCUDT -{ -public: - CUDT* core; - - bool checkApplyFilterConfig(const string& s) +namespace srt { + class TestMockCUDT { - return core->checkApplyFilterConfig(s); - } -}; + public: + CUDT* core; + + bool checkApplyFilterConfig(const string& s) + { + return core->checkApplyFilterConfig(s); + } + }; +} // The expected whole procedure of connection using FEC is // expected to: diff --git a/test/test_seqno.cpp b/test/test_seqno.cpp index df2ecca53..4a1cb0ec8 100644 --- a/test/test_seqno.cpp +++ b/test/test_seqno.cpp @@ -2,6 +2,8 @@ #include "common.h" #include "core.h" +using namespace srt; + const int32_t CSeqNo::m_iSeqNoTH; const int32_t CSeqNo::m_iMaxSeqNo; diff --git a/test/test_unitqueue.cpp b/test/test_unitqueue.cpp index f9010b9e7..324766f39 100644 --- a/test/test_unitqueue.cpp +++ b/test/test_unitqueue.cpp @@ -3,9 +3,8 @@ #include "gtest/gtest.h" #include "queue.h" - using namespace std; - +using namespace srt; /// Create CUnitQueue with queue size of 4 units. /// The size of 4 is chosen on purpose, because diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index 1cb49cb64..501e5f8d7 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -2903,7 +2903,7 @@ class UdpSource: public virtual Source, public virtual UdpCommon struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; - if (::setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) + if (::setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv)) < 0) Error(SysError(), "Setting timeout for UDP"); } From 22cc92424acd650ee0238eb092df521e19434068 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 19 May 2021 12:15:08 +0200 Subject: [PATCH 016/124] [core] Applied clang-format on channel.h and cpp --- srtcore/channel.cpp | 574 ++++++++++++++++++++++---------------------- srtcore/channel.h | 128 +++++----- 2 files changed, 356 insertions(+), 346 deletions(-) diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index c7b6e93f3..6e56e97f7 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -1,11 +1,11 @@ /* * 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/. - * + * */ /***************************************************************************** @@ -53,7 +53,7 @@ modified by #include "platform_sys.h" #include -#include // Logging +#include // Logging #include #include @@ -65,34 +65,30 @@ modified by #include "utilities.h" #ifdef _WIN32 - typedef int socklen_t; +typedef int socklen_t; #endif using namespace std; using namespace srt_logging; -namespace srt { +namespace srt +{ #ifdef _WIN32 - // use INVALID_SOCKET, as provided +// use INVALID_SOCKET, as provided #else - static const int INVALID_SOCKET = -1; +static const int INVALID_SOCKET = -1; #endif #if ENABLE_SOCK_CLOEXEC #ifndef _WIN32 -#if defined(_AIX) || \ - defined(__APPLE__) || \ - defined(__DragonFly__) || \ - defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__linux__) || \ - defined(__OpenBSD__) || \ - defined(__NetBSD__) +#if defined(_AIX) || defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ + defined(__FreeBSD_kernel__) || defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) // Set the CLOEXEC flag using ioctl() function -static int set_cloexec(int fd, int set) { +static int set_cloexec(int fd, int set) +{ int r; do @@ -106,7 +102,8 @@ static int set_cloexec(int fd, int set) { } #else // Set the CLOEXEC flag using fcntl() function -static int set_cloexec(int fd, int set) { +static int set_cloexec(int fd, int set) +{ int flags; int r; @@ -141,13 +138,11 @@ static int set_cloexec(int fd, int set) { } // namespace srt srt::CChannel::CChannel() - :m_iSocket(INVALID_SOCKET) + : m_iSocket(INVALID_SOCKET) { } -srt::CChannel::~CChannel() -{ -} +srt::CChannel::~CChannel() {} void srt::CChannel::createSocket(int family) { @@ -158,14 +153,14 @@ void srt::CChannel::createSocket(int family) m_iSocket = ::socket(family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); if (m_iSocket == INVALID_SOCKET) { - m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); + m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); cloexec_flag = true; } #else - m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); + m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); cloexec_flag = true; #endif -#else // ENABLE_SOCK_CLOEXEC +#else // ENABLE_SOCK_CLOEXEC m_iSocket = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); #endif // ENABLE_SOCK_CLOEXEC @@ -174,10 +169,12 @@ void srt::CChannel::createSocket(int family) #if ENABLE_SOCK_CLOEXEC #ifdef _WIN32 - // XXX ::SetHandleInformation(hInputWrite, HANDLE_FLAG_INHERIT, 0) + // XXX ::SetHandleInformation(hInputWrite, HANDLE_FLAG_INHERIT, 0) #else - if (cloexec_flag) { - if (0 != set_cloexec(m_iSocket, 1)) { + if (cloexec_flag) + { + if (0 != set_cloexec(m_iSocket, 1)) + { throw CUDTException(MJ_SETUP, MN_NONE, NET_ERROR); } } @@ -186,19 +183,19 @@ void srt::CChannel::createSocket(int family) if ((m_mcfg.iIpV6Only != -1) && (family == AF_INET6)) // (not an error if it fails) { - const int res ATR_UNUSED = ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_V6ONLY, - (const char*) &m_mcfg.iIpV6Only, sizeof m_mcfg.iIpV6Only); + const int res ATR_UNUSED = + ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&m_mcfg.iIpV6Only, sizeof m_mcfg.iIpV6Only); #if ENABLE_LOGGING if (res == -1) { - int err = errno; + int err = errno; char msg[160]; - LOGC(kmlog.Error, log << "::setsockopt: failed to set IPPROTO_IPV6/IPV6_V6ONLY = " - << m_mcfg.iIpV6Only << ": " << SysStrError(err, msg, 159)); + LOGC(kmlog.Error, + log << "::setsockopt: failed to set IPPROTO_IPV6/IPV6_V6ONLY = " << m_mcfg.iIpV6Only << ": " + << SysStrError(err, msg, 159)); } #endif // ENABLE_LOGGING } - } void srt::CChannel::open(const sockaddr_any& addr) @@ -219,14 +216,14 @@ void srt::CChannel::open(int family) { createSocket(family); - //sendto or WSASendTo will also automatically bind the socket - addrinfo hints; + // sendto or WSASendTo will also automatically bind the socket + addrinfo hints; addrinfo* res; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_PASSIVE; - hints.ai_family = family; + hints.ai_flags = AI_PASSIVE; + hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; const int eai = ::getaddrinfo(NULL, "0", &hints, &res); @@ -248,7 +245,7 @@ void srt::CChannel::open(int family) ::freeaddrinfo(res); throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); } - m_BindAddr = sockaddr_any(res->ai_addr, (sockaddr_any::len_t) res->ai_addrlen); + m_BindAddr = sockaddr_any(res->ai_addr, (sockaddr_any::len_t)res->ai_addrlen); ::freeaddrinfo(res); @@ -261,159 +258,169 @@ void srt::CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr) { // The getsockname() call is done before calling it and the // result is placed into udpsocks_addr. - m_iSocket = udpsock; + m_iSocket = udpsock; m_BindAddr = udpsocks_addr; setUDPSockOpt(); } void srt::CChannel::setUDPSockOpt() { - #if defined(BSD) || TARGET_OS_MAC - // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value - int maxsize = 64000; - if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*) &m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize)) - ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*) &maxsize, sizeof maxsize); - if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize)) - ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*) &maxsize, sizeof maxsize); - #else - // for other systems, if requested is greated than maximum, the maximum value will be automactally used - if ((0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*) &m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize)) || - (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*) &m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))) - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - #endif - - if (m_mcfg.iIpTTL != -1) - { - if (m_BindAddr.family() == AF_INET) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*) &m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - else - { - // If IPv6 address is unspecified, set BOTH IP_TTL and IPV6_UNICAST_HOPS. - - // For specified IPv6 address, set IPV6_UNICAST_HOPS ONLY UNLESS it's an IPv4-mapped-IPv6 - if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char*) &m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) - { - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - } - // For specified IPv6 address, set IP_TTL ONLY WHEN it's an IPv4-mapped-IPv6 - if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*) &m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) - { - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - } - } - } - - if (m_mcfg.iIpToS != -1) - { - if (m_BindAddr.family() == AF_INET) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*) &m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - else - { - // If IPv6 address is unspecified, set BOTH IP_TOS and IPV6_TCLASS. +#if defined(BSD) || TARGET_OS_MAC + // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value + int maxsize = 64000; + if (0 != ::setsockopt( + m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize)) + ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&maxsize, sizeof maxsize); + if (0 != ::setsockopt( + m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize)) + ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&maxsize, sizeof maxsize); +#else + // for other systems, if requested is greated than maximum, the maximum value will be automactally used + if ((0 != + ::setsockopt( + m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize)) || + (0 != ::setsockopt( + m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); +#endif + + if (m_mcfg.iIpTTL != -1) + { + if (m_BindAddr.family() == AF_INET) + { + if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + else + { + // If IPv6 address is unspecified, set BOTH IP_TTL and IPV6_UNICAST_HOPS. + + // For specified IPv6 address, set IPV6_UNICAST_HOPS ONLY UNLESS it's an IPv4-mapped-IPv6 + if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || + !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) + { + if (0 != + ::setsockopt( + m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) + { + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + } + // For specified IPv6 address, set IP_TTL ONLY WHEN it's an IPv4-mapped-IPv6 + if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) + { + if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL)) + { + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + } + } + } + + if (m_mcfg.iIpToS != -1) + { + if (m_BindAddr.family() == AF_INET) + { + if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + else + { + // If IPv6 address is unspecified, set BOTH IP_TOS and IPV6_TCLASS. #ifdef IPV6_TCLASS - // For specified IPv6 address, set IPV6_TCLASS ONLY UNLESS it's an IPv4-mapped-IPv6 - if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_TCLASS, (const char*) &m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) - { - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - } + // For specified IPv6 address, set IPV6_TCLASS ONLY UNLESS it's an IPv4-mapped-IPv6 + if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || + !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) + { + if (0 != ::setsockopt( + m_iSocket, IPPROTO_IPV6, IPV6_TCLASS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) + { + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + } #endif - // For specified IPv6 address, set IP_TOS ONLY WHEN it's an IPv4-mapped-IPv6 - if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) - { - if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*) &m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) - { - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - } - } - } + // For specified IPv6 address, set IP_TOS ONLY WHEN it's an IPv4-mapped-IPv6 + if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr)) + { + if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS)) + { + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + } + } + } #ifdef SRT_ENABLE_BINDTODEVICE - if (!m_mcfg.sBindToDevice.empty()) - { - if (m_BindAddr.family() != AF_INET) - { - LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE can only be set with AF_INET connections"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_BINDTODEVICE, - m_mcfg.sBindToDevice.c_str(), m_mcfg.sBindToDevice.size())) - { + if (!m_mcfg.sBindToDevice.empty()) + { + if (m_BindAddr.family() != AF_INET) + { + LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE can only be set with AF_INET connections"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + if (0 != ::setsockopt( + m_iSocket, SOL_SOCKET, SO_BINDTODEVICE, m_mcfg.sBindToDevice.c_str(), m_mcfg.sBindToDevice.size())) + { #if ENABLE_LOGGING - char buf[255]; - const char* err = SysStrError(NET_ERROR, buf, 255); - LOGC(kmlog.Error, log << "setsockopt(SRTO_BINDTODEVICE): " << err); + char buf[255]; + const char* err = SysStrError(NET_ERROR, buf, 255); + LOGC(kmlog.Error, log << "setsockopt(SRTO_BINDTODEVICE): " << err); #endif // ENABLE_LOGGING - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); - } - } + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + } + } #endif #ifdef UNIX - // Set non-blocking I/O - // UNIX does not support SO_RCVTIMEO - int opts = ::fcntl(m_iSocket, F_GETFL); - if (-1 == ::fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + // Set non-blocking I/O + // UNIX does not support SO_RCVTIMEO + int opts = ::fcntl(m_iSocket, F_GETFL); + if (-1 == ::fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); #elif defined(_WIN32) - u_long nonBlocking = 1; - if (0 != ioctlsocket (m_iSocket, FIONBIO, &nonBlocking)) - throw CUDTException (MJ_SETUP, MN_NORES, NET_ERROR); + u_long nonBlocking = 1; + if (0 != ioctlsocket(m_iSocket, FIONBIO, &nonBlocking)) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); #else - timeval tv; - tv.tv_sec = 0; -#if defined (BSD) || TARGET_OS_MAC - // Known BSD bug as the day I wrote this code. - // A small time out value will cause the socket to block forever. - tv.tv_usec = 10000; + timeval tv; + tv.tv_sec = 0; +#if defined(BSD) || TARGET_OS_MAC + // Known BSD bug as the day I wrote this code. + // A small time out value will cause the socket to block forever. + tv.tv_usec = 10000; #else - tv.tv_usec = 100; + tv.tv_usec = 100; #endif - // Set receiving time-out value - if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval))) - throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); + // Set receiving time-out value + if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval))) + throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR); #endif } void srt::CChannel::close() const { - #ifndef _WIN32 - ::close(m_iSocket); - #else - ::closesocket(m_iSocket); - #endif +#ifndef _WIN32 + ::close(m_iSocket); +#else + ::closesocket(m_iSocket); +#endif } int srt::CChannel::getSndBufSize() { - socklen_t size = (socklen_t) sizeof m_mcfg.iUDPSndBufSize; - ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*) &m_mcfg.iUDPSndBufSize, &size); - return m_mcfg.iUDPSndBufSize; + socklen_t size = (socklen_t)sizeof m_mcfg.iUDPSndBufSize; + ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_mcfg.iUDPSndBufSize, &size); + return m_mcfg.iUDPSndBufSize; } int srt::CChannel::getRcvBufSize() { - socklen_t size = (socklen_t) sizeof m_mcfg.iUDPRcvBufSize; - ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*) &m_mcfg.iUDPRcvBufSize, &size); - return m_mcfg.iUDPRcvBufSize; + socklen_t size = (socklen_t)sizeof m_mcfg.iUDPRcvBufSize; + ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_mcfg.iUDPRcvBufSize, &size); + return m_mcfg.iUDPRcvBufSize; } void srt::CChannel::setConfig(const CSrtMuxerConfig& config) @@ -423,50 +430,50 @@ void srt::CChannel::setConfig(const CSrtMuxerConfig& config) int srt::CChannel::getIpTTL() const { - if (m_iSocket == INVALID_SOCKET) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - socklen_t size = (socklen_t) sizeof m_mcfg.iIpTTL; - if (m_BindAddr.family() == AF_INET) - { - ::getsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (char*) &m_mcfg.iIpTTL, &size); - } - else if (m_BindAddr.family() == AF_INET6) - { - ::getsockopt(m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char*) &m_mcfg.iIpTTL, &size); - } - else - { - // If family is unspecified, the socket probably doesn't exist. - LOGC(kmlog.Error, log << "IPE: CChannel::getIpTTL called with unset family"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - return m_mcfg.iIpTTL; + if (m_iSocket == INVALID_SOCKET) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + socklen_t size = (socklen_t)sizeof m_mcfg.iIpTTL; + if (m_BindAddr.family() == AF_INET) + { + ::getsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (char*)&m_mcfg.iIpTTL, &size); + } + else if (m_BindAddr.family() == AF_INET6) + { + ::getsockopt(m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char*)&m_mcfg.iIpTTL, &size); + } + else + { + // If family is unspecified, the socket probably doesn't exist. + LOGC(kmlog.Error, log << "IPE: CChannel::getIpTTL called with unset family"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + return m_mcfg.iIpTTL; } int srt::CChannel::getIpToS() const { - if (m_iSocket == INVALID_SOCKET) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - socklen_t size = (socklen_t) sizeof m_mcfg.iIpToS; - if (m_BindAddr.family() == AF_INET) - { - ::getsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (char*) &m_mcfg.iIpToS, &size); - } - else if (m_BindAddr.family() == AF_INET6) - { + if (m_iSocket == INVALID_SOCKET) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + socklen_t size = (socklen_t)sizeof m_mcfg.iIpToS; + if (m_BindAddr.family() == AF_INET) + { + ::getsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (char*)&m_mcfg.iIpToS, &size); + } + else if (m_BindAddr.family() == AF_INET6) + { #ifdef IPV6_TCLASS - ::getsockopt(m_iSocket, IPPROTO_IPV6, IPV6_TCLASS, (char*) &m_mcfg.iIpToS, &size); + ::getsockopt(m_iSocket, IPPROTO_IPV6, IPV6_TCLASS, (char*)&m_mcfg.iIpToS, &size); #endif - } - else - { - // If family is unspecified, the socket probably doesn't exist. - LOGC(kmlog.Error, log << "IPE: CChannel::getIpToS called with unset family"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - return m_mcfg.iIpToS; + } + else + { + // If family is unspecified, the socket probably doesn't exist. + LOGC(kmlog.Error, log << "IPE: CChannel::getIpToS called with unset family"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + return m_mcfg.iIpToS; } #ifdef SRT_ENABLE_BINDTODEVICE @@ -478,7 +485,7 @@ bool srt::CChannel::getBind(char* dst, size_t len) // Try to obtain it directly from the function. If not possible, // then return from internal data. socklen_t length = len; - int res = ::getsockopt(m_iSocket, SOL_SOCKET, SO_BINDTODEVICE, dst, &length); + int res = ::getsockopt(m_iSocket, SOL_SOCKET, SO_BINDTODEVICE, dst, &length); if (res == -1) return false; // Happens on Linux v < 3.8 @@ -492,8 +499,8 @@ int srt::CChannel::ioctlQuery(int type SRT_ATR_UNUSED) const { #if defined(unix) || defined(__APPLE__) int value = 0; - int res = ::ioctl(m_iSocket, type, &value); - if ( res != -1 ) + int res = ::ioctl(m_iSocket, type, &value); + if (res != -1) return value; #endif return -1; @@ -502,10 +509,10 @@ int srt::CChannel::ioctlQuery(int type SRT_ATR_UNUSED) const int srt::CChannel::sockoptQuery(int level SRT_ATR_UNUSED, int option SRT_ATR_UNUSED) const { #if defined(unix) || defined(__APPLE__) - int value = 0; - socklen_t len = sizeof (int); - int res = ::getsockopt(m_iSocket, level, option, &value, &len); - if ( res != -1 ) + int value = 0; + socklen_t len = sizeof(int); + int res = ::getsockopt(m_iSocket, level, option, &value, &len); + if (res != -1) return value; #endif return -1; @@ -517,26 +524,23 @@ void srt::CChannel::getSockAddr(sockaddr_any& w_addr) const // space to copy the socket name, it doesn't have to be correlated // with the address family. So the maximum space for any name, // regardless of the family, does the job. - socklen_t namelen = (socklen_t) w_addr.storage_size(); + socklen_t namelen = (socklen_t)w_addr.storage_size(); ::getsockname(m_iSocket, (w_addr.get()), (&namelen)); w_addr.len = namelen; } void srt::CChannel::getPeerAddr(sockaddr_any& w_addr) const { - socklen_t namelen = (socklen_t) w_addr.storage_size(); + socklen_t namelen = (socklen_t)w_addr.storage_size(); ::getpeername(m_iSocket, (w_addr.get()), (&namelen)); w_addr.len = namelen; } - int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const { - HLOGC(kslog.Debug, log << "CChannel::sendto: SENDING NOW DST=" << addr.str() - << " target=@" << packet.m_iID - << " size=" << packet.getLength() - << " pkt.ts=" << packet.m_iTimeStamp - << " " << packet.Info()); + HLOGC(kslog.Debug, + log << "CChannel::sendto: SENDING NOW DST=" << addr.str() << " target=@" << packet.m_iID + << " size=" << packet.getLength() << " pkt.ts=" << packet.m_iTimeStamp << " " << packet.Info()); #ifdef SRT_TEST_FAKE_LOSS @@ -546,18 +550,18 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const #undef FAKELOSS_STRING #undef FAKELOSS_WRAP - static int dcounter = 0; + static int dcounter = 0; static int flwcounter = 0; struct FakelossConfig { - pair config; + pair config; FakelossConfig(const char* f) { vector out; Split(f, '+', back_inserter(out)); - config.first = atoi(out[0].c_str()); + config.first = atoi(out[0].c_str()); config.second = out.size() > 1 ? atoi(out[1].c_str()) : 8; } }; @@ -571,7 +575,9 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const { // This is a counter of how many packets in a row shall be lost --flwcounter; - HLOGC(kslog.Debug, log << "CChannel: TEST: FAKE LOSS OF %" << packet.getSeqNo() << " (" << flwcounter << " more to drop)"); + HLOGC(kslog.Debug, + log << "CChannel: TEST: FAKE LOSS OF %" << packet.getSeqNo() << " (" << flwcounter + << " more to drop)"); return packet.getLength(); // fake successful sendinf } @@ -583,7 +589,9 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const if (dcounter > rnd) { dcounter = 1; - HLOGC(kslog.Debug, log << "CChannel: TEST: FAKE LOSS OF %" << packet.getSeqNo() << " (will drop " << fakeloss.config.first << " more)"); + HLOGC(kslog.Debug, + log << "CChannel: TEST: FAKE LOSS OF %" << packet.getSeqNo() << " (will drop " + << fakeloss.config.first << " more)"); flwcounter = fakeloss.config.first; return packet.getLength(); // fake successful sendinf } @@ -592,51 +600,51 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const #endif - // convert control information into network order - packet.toNL(); - - #ifndef _WIN32 - msghdr mh; - mh.msg_name = (sockaddr*)&addr; - mh.msg_namelen = addr.size(); - mh.msg_iov = (iovec*)packet.m_PacketVector; - mh.msg_iovlen = 2; - mh.msg_control = NULL; - mh.msg_controllen = 0; - mh.msg_flags = 0; - - const int res = ::sendmsg(m_iSocket, &mh, 0); - #else - DWORD size = (DWORD) (CPacket::HDR_SIZE + packet.getLength()); - int addrsize = addr.size(); - int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, NULL, NULL); - res = (0 == res) ? size : -1; - #endif - - packet.toHL(); - - return res; + // convert control information into network order + packet.toNL(); + +#ifndef _WIN32 + msghdr mh; + mh.msg_name = (sockaddr*)&addr; + mh.msg_namelen = addr.size(); + mh.msg_iov = (iovec*)packet.m_PacketVector; + mh.msg_iovlen = 2; + mh.msg_control = NULL; + mh.msg_controllen = 0; + mh.msg_flags = 0; + + const int res = ::sendmsg(m_iSocket, &mh, 0); +#else + DWORD size = (DWORD)(CPacket::HDR_SIZE + packet.getLength()); + int addrsize = addr.size(); + int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, NULL, NULL); + res = (0 == res) ? size : -1; +#endif + + packet.toHL(); + + return res; } EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) const { - EReadStatus status = RST_OK; - int msg_flags = 0; - int recv_size = -1; + EReadStatus status = RST_OK; + int msg_flags = 0; + int recv_size = -1; #if defined(UNIX) || defined(_WIN32) - fd_set set; + fd_set set; timeval tv; FD_ZERO(&set); FD_SET(m_iSocket, &set); - tv.tv_sec = 0; - tv.tv_usec = 10000; - const int select_ret = ::select((int) m_iSocket + 1, &set, NULL, &set, &tv); + tv.tv_sec = 0; + tv.tv_usec = 10000; + const int select_ret = ::select((int)m_iSocket + 1, &set, NULL, &set, &tv); #else - const int select_ret = 1; // the socket is expected to be in the blocking mode itself + const int select_ret = 1; // the socket is expected to be in the blocking mode itself #endif - if (select_ret == 0) // timeout + if (select_ret == 0) // timeout { w_packet.setLength(-1); return RST_AGAIN; @@ -646,13 +654,13 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con if (select_ret > 0) { msghdr mh; - mh.msg_name = (w_addr.get()); - mh.msg_namelen = w_addr.size(); - mh.msg_iov = (w_packet.m_PacketVector); - mh.msg_iovlen = 2; - mh.msg_control = NULL; + mh.msg_name = (w_addr.get()); + mh.msg_namelen = w_addr.size(); + mh.msg_iov = (w_packet.m_PacketVector); + mh.msg_iovlen = 2; + mh.msg_control = NULL; mh.msg_controllen = 0; - mh.msg_flags = 0; + mh.msg_flags = 0; recv_size = ::recvmsg(m_iSocket, (&mh), 0); msg_flags = mh.msg_flags; @@ -683,7 +691,8 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con if (select_ret == -1 || recv_size == -1) { const int err = NET_ERROR; - if (err == EAGAIN || err == EINTR || err == ECONNREFUSED) // For EAGAIN, this isn't an error, just a useless call. + if (err == EAGAIN || err == EINTR || + err == ECONNREFUSED) // For EAGAIN, this isn't an error, just a useless call. { status = RST_AGAIN; } @@ -713,16 +722,23 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con // value one Windows than 0, unless this procedure below is rewritten // to use WSARecvMsg(). - int recv_ret = SOCKET_ERROR; - DWORD flag = 0; + int recv_ret = SOCKET_ERROR; + DWORD flag = 0; - if (select_ret > 0) // the total number of socket handles that are ready + if (select_ret > 0) // the total number of socket handles that are ready { - DWORD size = (DWORD) (CPacket::HDR_SIZE + w_packet.getLength()); - int addrsize = w_addr.size(); - - recv_ret = ::WSARecvFrom(m_iSocket, ((LPWSABUF)w_packet.m_PacketVector), 2, - (&size), (&flag), (w_addr.get()), (&addrsize), NULL, NULL); + DWORD size = (DWORD)(CPacket::HDR_SIZE + w_packet.getLength()); + int addrsize = w_addr.size(); + + recv_ret = ::WSARecvFrom(m_iSocket, + ((LPWSABUF)w_packet.m_PacketVector), + 2, + (&size), + (&flag), + (w_addr.get()), + (&addrsize), + NULL, + NULL); if (recv_ret == 0) recv_size = size; } @@ -737,16 +753,9 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con // WSAETIMEDOUT, which isn't mentioned in the documentation of WSARecvFrom at all. // // These below errors are treated as "fatal", all others are treated as "again". - static const int fatals [] = - { - WSAEFAULT, - WSAEINVAL, - WSAENETDOWN, - WSANOTINITIALISED, - WSA_OPERATION_ABORTED - }; + static const int fatals[] = {WSAEFAULT, WSAEINVAL, WSAENETDOWN, WSANOTINITIALISED, WSA_OPERATION_ABORTED}; static const int* fatals_end = fatals + Size(fatals); - const int err = NET_ERROR; + const int err = NET_ERROR; if (std::find(fatals, fatals_end, err) != fatals_end) { HLOGC(krlog.Debug, log << CONID() << "(sys)WSARecvFrom: " << SysStrError(err) << " [" << err << "]"); @@ -765,12 +774,12 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con msg_flags = 1; #endif - // Sanity check for a case when it didn't fill in even the header if (size_t(recv_size) < CPacket::HDR_SIZE) { status = RST_AGAIN; - HLOGC(krlog.Debug, log << CONID() << "POSSIBLE ATTACK: received too short packet with " << recv_size << " bytes"); + HLOGC(krlog.Debug, + log << CONID() << "POSSIBLE ATTACK: received too short packet with " << recv_size << " bytes"); goto Return_error; } @@ -791,10 +800,11 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con // When this happens, then you have at best a fragment of the buffer and it's // useless anyway. This is solved by dropping the packet and fake that no // packet was received, so the packet will be then retransmitted. - if ( msg_flags != 0 ) + if (msg_flags != 0) { - HLOGC(krlog.Debug, log << CONID() << "NET ERROR: packet size=" << recv_size - << " msg_flags=0x" << hex << msg_flags << ", possibly MSG_TRUNC (0x" << hex << int(MSG_TRUNC) << ")"); + HLOGC(krlog.Debug, + log << CONID() << "NET ERROR: packet size=" << recv_size << " msg_flags=0x" << hex << msg_flags + << ", possibly MSG_TRUNC (0x" << hex << int(MSG_TRUNC) << ")"); status = RST_AGAIN; goto Return_error; } @@ -803,21 +813,21 @@ EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet) con // convert back into local host order // XXX use NtoHLA(). - //for (int i = 0; i < 4; ++ i) + // for (int i = 0; i < 4; ++ i) // w_packet.m_nHeader[i] = ntohl(w_packet.m_nHeader[i]); { uint32_t* p = w_packet.m_nHeader; - for (size_t i = 0; i < SRT_PH_E_SIZE; ++ i) + for (size_t i = 0; i < SRT_PH_E_SIZE; ++i) { *p = ntohl(*p); - ++ p; + ++p; } } if (w_packet.isControl()) { - for (size_t j = 0, n = w_packet.getLength() / sizeof (uint32_t); j < n; ++ j) - *((uint32_t *)w_packet.m_pcData + j) = ntohl(*((uint32_t *)w_packet.m_pcData + j)); + for (size_t j = 0, n = w_packet.getLength() / sizeof(uint32_t); j < n; ++j) + *((uint32_t*)w_packet.m_pcData + j) = ntohl(*((uint32_t*)w_packet.m_pcData + j)); } return RST_OK; diff --git a/srtcore/channel.h b/srtcore/channel.h index ad6b3f785..0255102fe 100644 --- a/srtcore/channel.h +++ b/srtcore/channel.h @@ -1,11 +1,11 @@ /* * 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/. - * + * */ /***************************************************************************** @@ -59,107 +59,107 @@ modified by #include "socketconfig.h" #include "netinet_any.h" -namespace srt { +namespace srt +{ class CChannel { - void createSocket(int family); -public: + void createSocket(int family); - // XXX There's currently no way to access the socket ID set for - // whatever the channel is currently working for. Required to find - // some way to do this, possibly by having a "reverse pointer". - // Currently just "unimplemented". - std::string CONID() const { return ""; } +public: + // XXX There's currently no way to access the socket ID set for + // whatever the channel is currently working for. Required to find + // some way to do this, possibly by having a "reverse pointer". + // Currently just "unimplemented". + std::string CONID() const { return ""; } - CChannel(); - ~CChannel(); + CChannel(); + ~CChannel(); - /// Open a UDP channel. - /// @param [in] addr The local address that UDP will use. + /// Open a UDP channel. + /// @param [in] addr The local address that UDP will use. - void open(const sockaddr_any& addr); + void open(const sockaddr_any& addr); - void open(int family); + void open(int family); - /// Open a UDP channel based on an existing UDP socket. - /// @param [in] udpsock UDP socket descriptor. + /// Open a UDP channel based on an existing UDP socket. + /// @param [in] udpsock UDP socket descriptor. - void attach(UDPSOCKET udpsock, const sockaddr_any& adr); + void attach(UDPSOCKET udpsock, const sockaddr_any& adr); - /// Disconnect and close the UDP entity. + /// Disconnect and close the UDP entity. - void close() const; + void close() const; - /// Get the UDP sending buffer size. - /// @return Current UDP sending buffer size. + /// Get the UDP sending buffer size. + /// @return Current UDP sending buffer size. - int getSndBufSize(); + int getSndBufSize(); - /// Get the UDP receiving buffer size. - /// @return Current UDP receiving buffer size. + /// Get the UDP receiving buffer size. + /// @return Current UDP receiving buffer size. - int getRcvBufSize(); + int getRcvBufSize(); - /// Query the socket address that the channel is using. - /// @param [out] addr pointer to store the returned socket address. + /// Query the socket address that the channel is using. + /// @param [out] addr pointer to store the returned socket address. - void getSockAddr(sockaddr_any& addr) const; + void getSockAddr(sockaddr_any& addr) const; - /// Query the peer side socket address that the channel is connect to. - /// @param [out] addr pointer to store the returned socket address. + /// Query the peer side socket address that the channel is connect to. + /// @param [out] addr pointer to store the returned socket address. - void getPeerAddr(sockaddr_any& addr) const; + void getPeerAddr(sockaddr_any& addr) const; - /// Send a packet to the given address. - /// @param [in] addr pointer to the destination address. - /// @param [in] packet reference to a CPacket entity. - /// @return Actual size of data sent. + /// Send a packet to the given address. + /// @param [in] addr pointer to the destination address. + /// @param [in] packet reference to a CPacket entity. + /// @return Actual size of data sent. - int sendto(const sockaddr_any& addr, srt::CPacket& packet) const; + int sendto(const sockaddr_any& addr, srt::CPacket& packet) const; - /// Receive a packet from the channel and record the source address. - /// @param [in] addr pointer to the source address. - /// @param [in] packet reference to a CPacket entity. - /// @return Actual size of data received. + /// Receive a packet from the channel and record the source address. + /// @param [in] addr pointer to the source address. + /// @param [in] packet reference to a CPacket entity. + /// @return Actual size of data received. - EReadStatus recvfrom(sockaddr_any& addr, srt::CPacket& packet) const; + EReadStatus recvfrom(sockaddr_any& addr, srt::CPacket& packet) const; - void setConfig(const CSrtMuxerConfig& config); + void setConfig(const CSrtMuxerConfig& config); - /// Get the IP TTL. - /// @param [in] ttl IP Time To Live. - /// @return TTL. + /// Get the IP TTL. + /// @param [in] ttl IP Time To Live. + /// @return TTL. - int getIpTTL() const; + int getIpTTL() const; - /// Get the IP Type of Service. - /// @return ToS. + /// Get the IP Type of Service. + /// @return ToS. - int getIpToS() const; + int getIpToS() const; #ifdef SRT_ENABLE_BINDTODEVICE - bool getBind(char* dst, size_t len); + bool getBind(char* dst, size_t len); #endif - int ioctlQuery(int type) const; - int sockoptQuery(int level, int option) const; + int ioctlQuery(int type) const; + int sockoptQuery(int level, int option) const; - const sockaddr* bindAddress() { return m_BindAddr.get(); } - const sockaddr_any& bindAddressAny() { return m_BindAddr; } + const sockaddr* bindAddress() { return m_BindAddr.get(); } + const sockaddr_any& bindAddressAny() { return m_BindAddr; } private: - void setUDPSockOpt(); + void setUDPSockOpt(); private: + UDPSOCKET m_iSocket; // socket descriptor - UDPSOCKET m_iSocket; // socket descriptor - - // Mutable because when querying original settings - // this comprises the cache for extracted values, - // although the object itself isn't considered modified. - mutable CSrtMuxerConfig m_mcfg; // Note: ReuseAddr is unused and ineffective. - sockaddr_any m_BindAddr; + // Mutable because when querying original settings + // this comprises the cache for extracted values, + // although the object itself isn't considered modified. + mutable CSrtMuxerConfig m_mcfg; // Note: ReuseAddr is unused and ineffective. + sockaddr_any m_BindAddr; }; } // namespace srt From 44eb6cedebb14aeecb66066d3d590aeb127b2e6e Mon Sep 17 00:00:00 2001 From: LELEGARD Thierry Date: Thu, 27 May 2021 11:35:01 +0200 Subject: [PATCH 017/124] [build] Improved Windows installer - More comprehensive README. - Added a sample installation script for users to automate the download and installation of libsrt. Useful to automate user's CI/CD pipeline. - Renamed typo in script name ("intaller"). - Updated build script to also produce the .zip archive as published with version 1.4.3. But note that binaries don't compress well (only 2% space) and publishing a .zip instead of the .exe does not provide much improvement anyway. --- scripts/win-installer/README.md | 122 +++++++++++++--- ...n-intaller.ps1 => build-win-installer.ps1} | 15 ++ scripts/win-installer/install-libsrt.ps1 | 131 ++++++++++++++++++ 3 files changed, 252 insertions(+), 16 deletions(-) rename scripts/win-installer/{build-win-intaller.ps1 => build-win-installer.ps1} (93%) create mode 100644 scripts/win-installer/install-libsrt.ps1 diff --git a/scripts/win-installer/README.md b/scripts/win-installer/README.md index 205e03893..ff54df258 100644 --- a/scripts/win-installer/README.md +++ b/scripts/win-installer/README.md @@ -1,33 +1,123 @@ -## SRT Static Libraries Installer for Windows +# SRT Static Libraries Installer for Windows This directory contains scripts to build a binary installer for libsrt on Windows systems for Visual Studio applications using SRT. -### Building Windows applications with libsrt +## SRT developer: Building the libsrt installer + +### Prerequisites + +These first two steps need to be executed once only. + +- Prerequisite 1: Install OpenSSL for Windows, both 64 and 32 bits. + This can be done automatically by running the PowerShell script `install-openssl.ps1`. + +- Prerequisite 2: Install NSIS, the NullSoft Installation Scripting system. + This can be done automatically by running the PowerShell script `install-nsis.ps1`. + +### Building the libsrt installer + +To build the libsrt installer, simply run the PowerShell script `build-win-installer.ps1`. +Running it without parameters, for instance launching it from the Windows Explorer, is +sufficient to build the installer. + +Optional parameters: + +- `-Version name` : + Use the specified string as version number for libsrt. By default, if the + current commit has a tag, use that tag (initial "v" removed, for instance + `1.4.3`). Otherwise, the defaut version is a detailed version number (most + recent version, number of commits since then, short commit SHA, for instance + `1.4.3-32-g22cc924`). Use that option if necessary to specify some other + non-standard form of version string. + +- `-NoPause` : + Do not wait for the user to press `` at end of execution. By default, + execute a `pause` instruction at the end of execution, which is useful + when the script was launched from Windows Explorer. Use that option when the + script is invoked from another PowerShell script. + +The installer is then available in the directory `installers`. + +The name of the installer is `libsrt-VERS.exe` where `VERS` is the SRT version number +(see the `-Version` option). + +The installer shall then be published as a release asset in the `srt` repository +on GitHub, either as `libsrt-VERS.exe` or `libsrt-VERS-win-installer.zip`. +In the latter case, the archive shall contain `libsrt-VERS.exe`. + +## SRT user: Using the libsrt installer -After installing the libsrt binary, an environment variable named `LIBSRT` is -defined to the installation root (typically `C:\Program Files (x86)\libsrt`). +### Installing the SRT libraries -In this directory, there is a Visual Studio property file named `libsrt.props`. -Simply reference this property file in your Visual Studio project to use libsrt. +To install the SRT libraries, simply run the `libsrt-VERS.exe` installer which is +available in the [SRT release area](https://github.com/Haivision/srt/releases). + +After installing the libsrt binaries, an environment variable named `LIBSRT` is +defined with the installation root (typically `C:\Program Files (x86)\libsrt`). + +If there is a need for automation, in a CI/CD pipeline for instance, the download +of the latest `libsrt-VERS.exe` and its installation can be automated using the +sample PowerShell script `install-libsrt.ps1` which is available in this directory. +This script may be freely copied in the user's build environment. + +When run without parameters (for instance from the Windows explorer), this +script downloads and installs the latest version of libsrt. + +Optional parameters: + +- `-Destination path` : + Specify a local directory where the libsrt package will be downloaded. + By default, use the `tmp` subdirectory from this script's directory. + +- `-ForceDownload` : + Force a download even if the package is already downloaded in the + destination path. Note that the latest version is always checked. + If a older package is already present but a newer one is available + online, the newer one is always downloaded, even without this option. + +- `-GitHubActions` : + When used in a GitHub Actions workflow, make sure that the `LIBSRT` + environment variable is propagated to subsequent jobs. In your GitHub + workflow, in the initial setup phase, use + `script-dir\install-libsrt.ps1 -GitHubActions -NoPause`. + +- `-NoInstall` : + Do not install the package, only download it. By default, libsrt is installed. + +- `-NoPause` : + Do not wait for the user to press `` at end of execution. By default, + execute a `pause` instruction at the end of execution, which is useful + when the script was launched from Windows Explorer. Use that option when the + script is invoked from another PowerShell script. + +### Building Windows applications with libsrt + +In the SRT installation root directory (specified in environment variable `LIBSRT`), +there is a Visual Studio property file named `libsrt.props`. Simply reference this +property file in your Visual Studio project to use libsrt. You can also do that manually by editing the application project file (the XML file named with a `.vcxproj` extension). Add the following line just before the end of the file: ~~~ - + ~~~ -### Building the installer +With this setup, just compile your application normally, either using the +Visual Studio IDE or the MSBuild command line tool. -The first two steps need to be executed once only. Only the last step needs -to be repeated each time a new version of libsrt is available. +## Files reference -- Prerequisite 1: Install OpenSSL for Windows, both 64 and 32 bits. - This can be done automatically by running the PowerShell script `install-openssl.ps1`. -- Prerequisite 2: Install NSIS, the NullSoft Installation Scripting system. - This can be done automatically by running the PowerShell script `install-nsis.ps1`. -- Build the libsrt installer by running the PowerShell script `build-win-installer.ps1`. +This directory contains the following files: -The installer is then available in the directory `installers`. +| File name | Usage +| ----------------------- | ----- +| build-win-installer.ps1 | PowerShell script to build the libsrt installer. +| install-libsrt.ps1 | Sample PowerShell script to automatically install libsrt (for user's projects). +| install-openssl.ps1 | PowerShell script to install OpenSSL (prerequisite to build the installer). +| install-nsis.ps1 | PowerShell script to install NSIS (prerequisite to build the installer). +| libsrt.nsi | NSIS installation script (used to build the installer). +| libsrt.props | Visual Studio property files to use libsrt (embedded in the installer). +| README.md | This text file. diff --git a/scripts/win-installer/build-win-intaller.ps1 b/scripts/win-installer/build-win-installer.ps1 similarity index 93% rename from scripts/win-installer/build-win-intaller.ps1 rename to scripts/win-installer/build-win-installer.ps1 index 261c457fa..4265edf8e 100644 --- a/scripts/win-installer/build-win-intaller.ps1 +++ b/scripts/win-installer/build-win-installer.ps1 @@ -200,6 +200,9 @@ if ($Missing -gt 0) { # Build the binary installer. #----------------------------------------------------------------------------- +$InstallExe = "$OutDir\libsrt-$Version.exe" +$InstallZip = "$OutDir\libsrt-$Version-win-installer.zip" + Write-Output "Building installer ..." & $NSIS /V2 ` /DVersion="$Version" ` @@ -209,4 +212,16 @@ Write-Output "Building installer ..." /DRepoDir="$RepoDir" ` "$ScriptDir\libsrt.nsi" +if (-not (Test-Path $InstallExe)) { + Exit-Script "**** Missing $InstallExe" +} + +Write-Output "Building installer archive ..." +Remove-Item -Force -ErrorAction SilentlyContinue $InstallZip +Compress-Archive -Path $InstallExe -DestinationPath $InstallZip -CompressionLevel Optimal + +if (-not (Test-Path $InstallZip)) { + Exit-Script "**** Missing $InstallZip" +} + Exit-Script diff --git a/scripts/win-installer/install-libsrt.ps1 b/scripts/win-installer/install-libsrt.ps1 new file mode 100644 index 000000000..ae1b8133e --- /dev/null +++ b/scripts/win-installer/install-libsrt.ps1 @@ -0,0 +1,131 @@ +# SRT library download and install for Windows. +# Copyright (c) 2021, Thierry Lelegard +# All rights reserved. + +<# + .SYNOPSIS + + Download and install the libsrt library for Windows. This script is + provided to automate the build of Windows applications using libsrt. + + .PARAMETER Destination + + Specify a local directory where the libsrt package will be downloaded. + By default, use "tmp" subdirectory from this script. + + .PARAMETER ForceDownload + + Force a download even if the package is already downloaded. + + .PARAMETER GitHubActions + + When used in a GitHub Actions workflow, make sure that the LIBSRT + environment variable is propagated to subsequent jobs. + + .PARAMETER NoInstall + + Do not install the package. By default, libsrt is installed. + + .PARAMETER NoPause + + Do not wait for the user to press at end of execution. By default, + execute a "pause" instruction at the end of execution, which is useful + when the script was run from Windows Explorer. +#> +[CmdletBinding(SupportsShouldProcess=$true)] +param( + [string]$Destination = "", + [switch]$ForceDownload = $false, + [switch]$GitHubActions = $false, + [switch]$NoInstall = $false, + [switch]$NoPause = $false +) + +Write-Output "libsrt download and installation procedure" + +# Default directory for downloaded products. +if (-not $Destination) { + $Destination = "$PSScriptRoot\tmp" +} + +# A function to exit this script. +function Exit-Script([string]$Message = "") +{ + $Code = 0 + if ($Message -ne "") { + Write-Output "ERROR: $Message" + $Code = 1 + } + if (-not $NoPause) { + pause + } + exit $Code +} + +# Without this, Invoke-WebRequest is awfully slow. +$ProgressPreference = 'SilentlyContinue' + +# Get the URL of the latest libsrt installer. +$URL = (Invoke-RestMethod "https://api.github.com/repos/Haivision/srt/releases?per_page=20" | + ForEach-Object { $_.assets } | + ForEach-Object { $_.browser_download_url } | + Select-String @("/libsrt-.*\.exe$", "/libsrt-.*-win-installer\.zip$") | + Select-Object -First 1) + +if (-not $URL) { + Exit-Script "Could not find a libsrt installer on GitHub" +} +if (-not ($URL -match "\.zip$") -and -not ($URL -match "\.exe$")) { + Exit-Script "Unexpected URL, not .exe, not .zip: $URL" +} + +# Installer name and path. +$InstName = (Split-Path -Leaf $URL) +$InstPath = "$Destination\$InstName" + +# Create the directory for downloaded products when necessary. +[void](New-Item -Path $Destination -ItemType Directory -Force) + +# Download installer +if (-not $ForceDownload -and (Test-Path $InstPath)) { + Write-Output "$InstName already downloaded, use -ForceDownload to download again" +} +else { + Write-Output "Downloading $URL ..." + Invoke-WebRequest $URL.ToString() -UseBasicParsing -UserAgent Download -OutFile $InstPath + if (-not (Test-Path $InstPath)) { + Exit-Script "$URL download failed" + } +} + +# If installer is an archive, expect an exe with same name inside. +if ($InstName -match "\.zip$") { + + # Expected installer name in archive. + $ZipName = $InstName + $ZipPath = $InstPath + $InstName = $ZipName -replace '-win-installer.zip','.exe' + $InstPath = "$Destination\$InstName" + + # Extract the installer. + Remove-Item -Force $InstPath -ErrorAction SilentlyContinue + Write-Output "Expanding $ZipName ..." + Expand-Archive $ZipPath -DestinationPath $Destination + if (-not (Test-Path $InstPath)) { + Exit-Script "$InstName not found in $ZipName" + } +} + +# Install libsrt +if (-not $NoInstall) { + Write-Output "Installing $InstName" + Start-Process -FilePath $InstPath -ArgumentList @("/S") -Wait +} + +# Propagate LIBSRT in next jobs for GitHub Actions. +if ($GitHubActions -and (-not -not $env:GITHUB_ENV) -and (Test-Path $env:GITHUB_ENV)) { + $libsrt = [System.Environment]::GetEnvironmentVariable("LIBSRT","Machine") + Write-Output "LIBSRT=$libsrt" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append +} + +Exit-Script From e2a00aa03a36e153ab8cfe2c0790f7bf43747d8d Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Fri, 28 May 2021 11:04:53 +0200 Subject: [PATCH 018/124] [core] Detect reusable bindings and binding conflicts correctly (#1588). Introduced new SRT socket error SRT_EBINDCONFLICT. --- .travis.yml | 5 +- docs/API/API-functions.md | 86 ++++-- scripts/generate-error-types.tcl | 18 +- srtcore/api.cpp | 189 +++++++++---- srtcore/api.h | 5 + srtcore/srt.h | 2 + srtcore/strerror_defs.cpp | 12 +- test/filelist.maf | 1 + test/test_reuseaddr.cpp | 440 +++++++++++++++++++++++++++++++ test/test_sync.cpp | 4 +- 10 files changed, 672 insertions(+), 90 deletions(-) create mode 100644 test/test_reuseaddr.cpp diff --git a/.travis.yml b/.travis.yml index 4ffe49add..51631c086 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ matrix: - make - cd .. env: BUILD_TYPE=Release - + # Power jobs - os: linux arch: ppc64le @@ -69,6 +69,7 @@ matrix: - BUILD_TYPE=Release - BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON' script: + - TESTS_IPv6="TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*:ReuseAddr.ProtocolVersion" ; # Tests to skip due to lack of IPv6 support - if [ "$TRAVIS_COMPILER" == "x86_64-w64-mingw32-g++" ]; then export CC="x86_64-w64-mingw32-gcc"; export CXX="x86_64-w64-mingw32-g++"; @@ -91,7 +92,7 @@ script: make -j$(nproc); fi - if [ "$TRAVIS_COMPILER" != "x86_64-w64-mingw32-g++" ]; then - ./test-srt --gtest_filter="-TestMuxer.IPv4_and_IPv6:TestIPv6.v6_calls_v6*"; + ./test-srt --gtest_filter="-$TESTS_IPv6"; fi - if (( "$RUN_CODECOV" )); then source ./scripts/collect-gcov.sh; diff --git a/docs/API/API-functions.md b/docs/API/API-functions.md index 44f8ac19a..5a1fffd70 100644 --- a/docs/API/API-functions.md +++ b/docs/API/API-functions.md @@ -384,13 +384,14 @@ connecting, use [`srt_connect_bind`](#srt_connect_bind) for that purpose. | `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_ECONNSETUP`](#srt_econnsetup) | Internal creation of a UDP socket failed | -| [`SRT_ESOCKFAIL`](#srt_esockfail) | Internal configuration of a UDP socket (`bind`, `setsockopt`) failed | -| | | +| 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_EBINDCONFLICT`](#srt_ebindconflict)| Binding specification conflicts with existing one | +| | | [:arrow_up:   Back to List of Functions & Structures](#srt-api-functions) @@ -841,18 +842,19 @@ first on the automatically created socket for the connection. | `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 | -| | | +| 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 @@ -3225,6 +3227,54 @@ 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 diff --git a/scripts/generate-error-types.tcl b/scripts/generate-error-types.tcl index 15c8c0fa2..b51d60eb1 100755 --- a/scripts/generate-error-types.tcl +++ b/scripts/generate-error-types.tcl @@ -61,6 +61,7 @@ set code_minor { XSIZE 12 EIDINVAL 13 EEMPTY 14 + BUSYPORT 15 WRAVAIL 1 RDAVAIL 2 @@ -121,7 +122,7 @@ set errortypes { XSIZE "Message is too large to send (it must be less than the SRT send buffer size)" EIDINVAL "Invalid epoll ID" EEMPTY "All sockets removed from epoll, waiting would deadlock" - + BUSYPORT "Another socket is bound to that port and is not reusable for requested settings" } AGAIN "Non-blocking call failure" { @@ -142,11 +143,10 @@ set main_array_item { const char** strerror_array_major [] = { $minor_array_list }; - } set major_size_item { -size_t strerror_array_sizes [] = { +const size_t strerror_array_sizes [] = { $minor_array_sizes }; } @@ -155,11 +155,9 @@ set minor_array_item { const char* strerror_msgs_$majorlc [] = { $minor_message_items }; - } set strerror_function { - const char* strerror_get_message(size_t major, size_t minor) { static const char* const undefined = "UNDEFINED ERROR"; @@ -228,16 +226,17 @@ proc Generate:imp {} { puts [subst -nobackslashes -nocommands $::minor_array_item] append minor_array_list " strerror_msgs_$majorlc, // MJ_$mt = $majitem\n" - append minor_array_sizes " [expr {$minitem}],\n" + #append minor_array_sizes " [expr {$minitem}],\n" + append minor_array_sizes " SRT_ARRAY_SIZE(strerror_msgs_$majorlc) - 1,\n" incr majitem } - append minor_array_list " NULL\n" - append minor_array_sizes " 0\n" + append minor_array_list " NULL" + append minor_array_sizes " 0" puts [subst -nobackslashes -nocommands $::main_array_item] + puts {#define SRT_ARRAY_SIZE(ARR) sizeof(ARR) / sizeof(ARR[0])} puts [subst -nobackslashes -nocommands $::major_size_item] - puts "" puts $::strerror_function puts "\} // namespace srt" @@ -250,4 +249,3 @@ if {[lindex $argv 0] != ""} { } Generate:$defmode - diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 44a068764..ad243d50e 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -2829,51 +2829,150 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u) } } -void srt::CUDTUnited::updateMux( - CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/) +void srt::CUDTUnited::configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int af) { - ScopedLock cg(m_GlobControlLock); + w_m.m_mcfg = s->m_pUDT->m_config; + w_m.m_iIPversion = af; + w_m.m_iRefCount = 1; + w_m.m_iID = s->m_SocketID; +} - // Don't try to reuse given address, if udpsock was given. - // In such a case rely exclusively on that very socket and - // use it the way as it is configured, of course, create also - // always a new multiplexer for that very socket. - if (!udpsock && s->m_pUDT->m_config.bReuseAddr) - { - const int port = addr.hport(); +uint16_t srt::CUDTUnited::installMuxer(CUDTSocket* w_s, CMultiplexer& fw_sm) +{ + w_s->m_pUDT->m_pSndQueue = fw_sm.m_pSndQueue; + w_s->m_pUDT->m_pRcvQueue = fw_sm.m_pRcvQueue; + w_s->m_iMuxID = fw_sm.m_iID; + sockaddr_any sa; + fw_sm.m_pChannel->getSockAddr((sa)); + w_s->m_SelfAddr = sa; // Will be also completed later, but here it's needed for later checks + return sa.hport(); +} - // find a reusable address - for (map::iterator i = m_mMultiplexer.begin(); - i != m_mMultiplexer.end(); ++ i) - { - // Use the "family" value blindly from the address; we - // need to find an existing multiplexer that binds to the - // given port in the same family as requested address. - if ((i->second.m_iIPversion == addr.family()) - && i->second.m_mcfg == s->m_pUDT->m_config) - { - if (i->second.m_iPort == port) +bool srt::CUDTUnited::channelSettingsMatch(const CMultiplexer& m, const CUDTSocket* s) +{ + return m.m_mcfg.bReuseAddr && m.m_mcfg == s->m_pUDT->m_config; +} + +void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/) +{ + ScopedLock cg(m_GlobControlLock); + + // If udpsock is provided, then this socket will be simply + // taken for binding as a good deal. It would be nice to make + // a sanity check to see if this UDP socket isn't already installed + // in some multiplexer, but we state this UDP socket isn't accessible + // anyway so this wouldn't be possible. + if (!udpsock) + { + // If not, we need to see if there exist already a multiplexer bound + // to the same endpoint. + const int port = addr.hport(); + + bool reuse_attempt = false; + for (map::iterator i = m_mMultiplexer.begin(); + i != m_mMultiplexer.end(); ++ i) + { + CMultiplexer& m = i->second; + + // First, we need to find a multiplexer with the same port. + if (m.m_iPort != port) { - // HLOGF(smlog.Debug, "reusing multiplexer for port - // %hd\n", port); - // reuse the existing multiplexer - ++ i->second.m_iRefCount; - s->m_pUDT->m_pSndQueue = i->second.m_pSndQueue; - s->m_pUDT->m_pRcvQueue = i->second.m_pRcvQueue; - s->m_iMuxID = i->second.m_iID; - s->m_SelfAddr.family(addr.family()); - return; + HLOGC(smlog.Debug, log << "bind: muxer @" << m.m_iID << " found, but for port " + << m.m_iPort << " (requested port: " << port << ")"); + continue; } - } - } - } + + // If this is bound to the wildcard address, it can be reused if: + // - addr is also a wildcard + // - channel settings match + // Otherwise it's a conflict. + sockaddr_any sa; + m.m_pChannel->getSockAddr((sa)); + + HLOGC(smlog.Debug, log << "bind: Found existing muxer @" << m.m_iID << " : " << sa.str() + << " - check against " << addr.str()); + + if (sa.isany()) + { + if (!addr.isany()) + { + LOGC(smlog.Error, log << "bind: Address: " << addr.str() + << " conflicts with existing wildcard binding: " << sa.str()); + throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); + } + + // Still, for ANY you need either the same family, or open + // for families. + if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != s->m_pUDT->m_config.iIpV6Only) + { + LOGC(smlog.Error, log << "bind: Address: " << addr.str() + << " conflicts with existing IPv6 wildcard binding: " << sa.str()); + throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); + } + + if ((m.m_mcfg.iIpV6Only == 0 || s->m_pUDT->m_config.iIpV6Only == 0) && m.m_iIPversion != addr.family()) + { + LOGC(smlog.Error, log << "bind: Address: " << addr.str() + << " conflicts with IPv6 wildcard binding: " << sa.str() + << " : family " << (m.m_iIPversion == AF_INET ? "IPv4" : "IPv6") + << " vs. " << (addr.family() == AF_INET ? "IPv4" : "IPv6")); + throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); + } + reuse_attempt = true; + HLOGC(smlog.Debug, log << "bind: wildcard address - multiplexer reusable"); + } + else if (addr.isany() && addr.family() == sa.family()) + { + LOGC(smlog.Error, log << "bind: Wildcard address: " << addr.str() + << " conflicts with existting IP binding: " << sa.str()); + throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); + } + // If this is bound to a certain address, AND: + else if (sa.equal_address(addr)) + { + // - the address is the same as addr + reuse_attempt = true; + HLOGC(smlog.Debug, log << "bind: same IP address - multiplexer reusable"); + } + else + { + HLOGC(smlog.Debug, log << "bind: IP addresses differ - ALLOWED to create a new multiplexer"); + } + // Otherwise: + // - the address is different than addr + // - the address can't be reused, but this can go on with new one. + + // If this is a reusage attempt: + if (reuse_attempt) + { + // - if the channel settings match, it can be reused + if (channelSettingsMatch(m, s)) + { + HLOGC(smlog.Debug, log << "bind: reusing multiplexer for port " << port); + // reuse the existing multiplexer + ++ i->second.m_iRefCount; + installMuxer((s), (i->second)); + return; + } + else + { + // - if not, it's a conflict + LOGC(smlog.Error, log << "bind: Address: " << addr.str() + << " conflicts with binding: " << sa.str() << " due to channel settings"); + throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); + } + } + // If not, proceed to the next one, and when there are no reusage + // candidates, proceed with creating a new multiplexer. + + // Note that a binding to a different IP address is not treated + // as a candidate for either reuseage or conflict. + } + } // a new multiplexer is needed CMultiplexer m; - m.m_mcfg = s->m_pUDT->m_config; - m.m_iIPversion = addr.family(); - m.m_iRefCount = 1; - m.m_iID = s->m_SocketID; + configureMuxer((m), s, addr.family()); try { @@ -2903,13 +3002,7 @@ void srt::CUDTUnited::updateMux( m.m_pChannel->open(addr); } - sockaddr_any sa; - m.m_pChannel->getSockAddr((sa)); - m.m_iPort = sa.hport(); - s->m_SelfAddr = sa; // Will be also completed later, but here it's needed for later checks - m.m_pTimer = new CTimer; - m.m_pSndQueue = new CSndQueue; m.m_pSndQueue->init(m.m_pChannel, m.m_pTimer); m.m_pRcvQueue = new CRcvQueue; @@ -2917,11 +3010,10 @@ void srt::CUDTUnited::updateMux( 32, s->m_pUDT->maxPayloadSize(), m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer); + // Rewrite the port here, as it might be only known upon return + // from CChannel::open. + m.m_iPort = installMuxer((s), m); m_mMultiplexer[m.m_iID] = m; - - s->m_pUDT->m_pSndQueue = m.m_pSndQueue; - s->m_pUDT->m_pRcvQueue = m.m_pRcvQueue; - s->m_iMuxID = m.m_iID; } catch (const CUDTException&) { @@ -2934,8 +3026,7 @@ void srt::CUDTUnited::updateMux( throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0); } - HLOGF(smlog.Debug, - "creating new multiplexer for port %i\n", m.m_iPort); + HLOGC(smlog.Debug, log << "bind: creating new multiplexer for port " << m.m_iPort); } // This function is going to find a multiplexer for the port contained diff --git a/srtcore/api.h b/srtcore/api.h index 3ef75c6e7..4228d8b46 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -408,6 +408,11 @@ friend class CRendezvousQueue; void updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* = NULL); bool updateListenerMux(CUDTSocket* s, const CUDTSocket* ls); + // Utility functions for updateMux + void configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int af); + uint16_t installMuxer(CUDTSocket* w_s, CMultiplexer& sm); + bool channelSettingsMatch(const CMultiplexer& m, const CUDTSocket* s); + private: std::map m_mMultiplexer; // UDP multiplexer sync::Mutex m_MultiplexerLock; diff --git a/srtcore/srt.h b/srtcore/srt.h index 21e94879e..5d3349a48 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -473,6 +473,7 @@ enum CodeMinor MN_XSIZE = 12, MN_EIDINVAL = 13, MN_EEMPTY = 14, + MN_BUSYPORT = 15, // MJ_AGAIN MN_WRAVAIL = 1, MN_RDAVAIL = 2, @@ -528,6 +529,7 @@ typedef enum SRT_ERRNO SRT_ELARGEMSG = MN(NOTSUP, XSIZE), SRT_EINVPOLLID = MN(NOTSUP, EIDINVAL), SRT_EPOLLEMPTY = MN(NOTSUP, EEMPTY), + SRT_EBINDCONFLICT = MN(NOTSUP, BUSYPORT), SRT_EASYNCFAIL = MJ(AGAIN), SRT_EASYNCSND = MN(AGAIN, WRAVAIL), diff --git a/srtcore/strerror_defs.cpp b/srtcore/strerror_defs.cpp index c37ee276d..7393c1279 100644 --- a/srtcore/strerror_defs.cpp +++ b/srtcore/strerror_defs.cpp @@ -19,7 +19,6 @@ const char* strerror_msgs_success [] = { "" }; - // MJ_SETUP 'Connection setup failure' const char* strerror_msgs_setup [] = { @@ -32,7 +31,6 @@ const char* strerror_msgs_setup [] = { "" }; - // MJ_CONNECTION '' const char* strerror_msgs_connection [] = { @@ -42,7 +40,6 @@ const char* strerror_msgs_connection [] = { "" }; - // MJ_SYSTEMRES 'System resource failure' const char* strerror_msgs_systemres [] = { @@ -53,7 +50,6 @@ const char* strerror_msgs_systemres [] = { "" }; - // MJ_FILESYSTEM 'File system failure' const char* strerror_msgs_filesystem [] = { @@ -65,7 +61,6 @@ const char* strerror_msgs_filesystem [] = { "" }; - // MJ_NOTSUP 'Operation not supported' const char* strerror_msgs_notsup [] = { @@ -84,10 +79,10 @@ const char* strerror_msgs_notsup [] = { "Operation not supported: Message is too large to send (it must be less than the SRT send buffer size)", // MN_XSIZE = 12 "Operation not supported: Invalid epoll ID", // MN_EIDINVAL = 13 "Operation not supported: All sockets removed from epoll, waiting would deadlock", // MN_EEMPTY = 14 + "Operation not supported: Another socket is bound to that port and is not reusable for requested settings", // MN_BUSYPORT = 15 "" }; - // MJ_AGAIN 'Non-blocking call failure' const char* strerror_msgs_again [] = { @@ -99,7 +94,6 @@ const char* strerror_msgs_again [] = { "" }; - // MJ_PEERERROR 'The peer side has signaled an error' const char* strerror_msgs_peererror [] = { @@ -108,7 +102,6 @@ const char* strerror_msgs_peererror [] = { }; - const char** strerror_array_major [] = { strerror_msgs_success, // MJ_SUCCESS = 0 strerror_msgs_setup, // MJ_SETUP = 1 @@ -123,7 +116,7 @@ const char** strerror_array_major [] = { #define SRT_ARRAY_SIZE(ARR) sizeof(ARR) / sizeof(ARR[0]) -const size_t strerror_array_sizes[] = { +const size_t strerror_array_sizes [] = { SRT_ARRAY_SIZE(strerror_msgs_success) - 1, SRT_ARRAY_SIZE(strerror_msgs_setup) - 1, SRT_ARRAY_SIZE(strerror_msgs_connection) - 1, @@ -135,6 +128,7 @@ const size_t strerror_array_sizes[] = { 0 }; + const char* strerror_get_message(size_t major, size_t minor) { static const char* const undefined = "UNDEFINED ERROR"; diff --git a/test/filelist.maf b/test/filelist.maf index 77f0d4b1f..d92cabd9d 100644 --- a/test/filelist.maf +++ b/test/filelist.maf @@ -20,6 +20,7 @@ test_sync.cpp test_timer.cpp test_unitqueue.cpp test_utilities.cpp +test_reuseaddr.cpp # Tests for bonding only - put here! diff --git a/test/test_reuseaddr.cpp b/test/test_reuseaddr.cpp new file mode 100644 index 000000000..18ab5fdfa --- /dev/null +++ b/test/test_reuseaddr.cpp @@ -0,0 +1,440 @@ +#include "gtest/gtest.h" +#include +#ifndef _WIN32 +#include +#endif + +#include "common.h" +#include "srt.h" +#include "udt.h" + +// Copied from ../apps/apputil.cpp, can't really link this file here. +sockaddr_any CreateAddr(const std::string& name, unsigned short port, int pref_family = AF_INET) +{ + using namespace std; + + // 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; +} + +#ifdef _WIN32 + +// On Windows there's a function for it, but it requires an extra +// iphlp library to be attached to the executable, which is kinda +// problematic. Temporarily block tests using this function on Windows. + +std::string GetLocalIP() +{ + std::cout << "!!!WARNING!!!: GetLocalIP not supported, test FORCEFULLY passed\n"; + return ""; +} +#else +struct IfAddr +{ + ifaddrs* handle; + IfAddr() + { + getifaddrs(&handle); + } + + ~IfAddr() + { + freeifaddrs(handle); + } +}; + +std::string GetLocalIP() +{ + struct ifaddrs * ifa=NULL; + void * tmpAddrPtr=NULL; + + IfAddr ifAddr; + + for (ifa = ifAddr.handle; ifa != NULL; ifa = ifa->ifa_next) + { + if (!ifa->ifa_addr) + { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) + { + // is a valid IP4 Address + sockaddr_in* psin = (struct sockaddr_in *)ifa->ifa_addr; + tmpAddrPtr=&psin->sin_addr; + + if (ntohl(psin->sin_addr.s_addr) == 0x7f000001) // Skip 127.0.0.1 + continue; + + char addressBuffer[INET_ADDRSTRLEN] = ""; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + return addressBuffer; + printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer); + } else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6 + // is a valid IP6 Address + tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + char addressBuffer[INET6_ADDRSTRLEN] = ""; + inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN); + return addressBuffer; + } + } + + return ""; +} +#endif + +int client_pollid = SRT_ERROR; +SRTSOCKET m_client_sock = SRT_ERROR; + +void clientSocket(std::string ip, int port, bool expect_success) +{ + int yes = 1; + int no = 0; + + int family = AF_INET; + if (ip.substr(0, 2) == "6.") + { + family = AF_INET6; + ip = ip.substr(2); + } + + m_client_sock = srt_create_socket(); + ASSERT_NE(m_client_sock, SRT_ERROR); + + ASSERT_NE(srt_setsockopt(m_client_sock, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // for async connect + ASSERT_NE(srt_setsockflag(m_client_sock, SRTO_SENDER, &yes, sizeof yes), SRT_ERROR); + + ASSERT_NE(srt_setsockopt(m_client_sock, 0, SRTO_TSBPDMODE, &yes, sizeof yes), SRT_ERROR); + + int epoll_out = SRT_EPOLL_OUT; + srt_epoll_add_usock(client_pollid, m_client_sock, &epoll_out); + + sockaddr_any sa = CreateAddr(ip, port, family); + + std::cout << "Connecting to: " << sa.str() << std::endl; + + int connect_res = srt_connect(m_client_sock, sa.get(), sa.size()); + + if (connect_res == -1) + { + std::cout << "srt_connect: " << srt_getlasterror_str() << std::endl; + } + + if (expect_success) + { + EXPECT_NE(connect_res, -1); + // Socket readiness for connection is checked by polling on WRITE allowed sockets. + + { + int rlen = 2; + SRTSOCKET read[2]; + + int wlen = 2; + SRTSOCKET write[2]; + + EXPECT_NE(srt_epoll_wait(client_pollid, read, &rlen, + write, &wlen, + -1, // -1 is set for debuging purpose. + // in case of production we need to set appropriate value + 0, 0, 0, 0), SRT_ERROR); + + + EXPECT_EQ(rlen, 0); // get exactly one write event without reads + EXPECT_EQ(wlen, 1); // get exactly one write event without reads + EXPECT_EQ(write[0], m_client_sock); // for our client socket + } + + char buffer[1316] = {1, 2, 3, 4}; + EXPECT_NE(srt_sendmsg(m_client_sock, buffer, sizeof buffer, + -1, // infinit ttl + true // in order must be set to true + ), + SRT_ERROR); + } + else + { + EXPECT_EQ(connect_res, -1); + } + + std::cout << "Client exit\n"; +} + +int server_pollid = SRT_ERROR; + +void serverSocket(std::string ip, int port, bool expect_success) +{ + int yes = 1; + int no = 0; + + SRTSOCKET m_bindsock = srt_create_socket(); + ASSERT_NE(m_bindsock, SRT_ERROR); + + ASSERT_NE(srt_setsockopt(m_bindsock, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // for async connect + ASSERT_NE(srt_setsockopt(m_bindsock, 0, SRTO_TSBPDMODE, &yes, sizeof yes), SRT_ERROR); + + int epoll_in = SRT_EPOLL_IN; + srt_epoll_add_usock(server_pollid, m_bindsock, &epoll_in); + + sockaddr_any sa = CreateAddr(ip, port); + + std::cout << "Bind to: " << sa.str() << std::endl; + + int bind_res = srt_bind(m_bindsock, sa.get(), sa.size()); + if (!expect_success) + { + std::cout << "Binding should fail: " << srt_getlasterror_str() << std::endl; + ASSERT_EQ(bind_res, SRT_ERROR); + return; + } + + ASSERT_NE(bind_res, SRT_ERROR); + + ASSERT_NE(srt_listen(m_bindsock, SOMAXCONN), SRT_ERROR); + + if (ip == "0.0.0.0") + ip = "127.0.0.1"; // override wildcard + else if ( ip == "::") + ip = "::1"; + + std::thread client(clientSocket, ip, port, expect_success); + + { // wait for connection from client + int rlen = 2; + SRTSOCKET read[2]; + + int wlen = 2; + SRTSOCKET write[2]; + + ASSERT_NE(srt_epoll_wait(server_pollid, + read, &rlen, + write, &wlen, + 3000, // -1 is set for debuging purpose. + // in case of production we need to set appropriate value + 0, 0, 0, 0), SRT_ERROR ); + + + ASSERT_EQ(rlen, 1); // get exactly one read event without writes + ASSERT_EQ(wlen, 0); // get exactly one read event without writes + ASSERT_EQ(read[0], m_bindsock); // read event is for bind socket + } + + sockaddr_any scl; + + SRTSOCKET m_sock = srt_accept(m_bindsock, scl.get(), &scl.len); + if (m_sock == -1) + { + std::cout << "srt_accept: " << srt_getlasterror_str() << std::endl; + } + ASSERT_NE(m_sock, SRT_INVALID_SOCK); + + sockaddr_any showacp = (sockaddr*)&scl; + std::cout << "Accepted from: " << showacp.str() << std::endl; + + srt_epoll_add_usock(server_pollid, m_sock, &epoll_in); // wait for input + + char buffer[1316]; + { // wait for 1316 packet from client + int rlen = 2; + SRTSOCKET read[2]; + + int wlen = 2; + SRTSOCKET write[2]; + + ASSERT_NE(srt_epoll_wait(server_pollid, + read, &rlen, + write, &wlen, + -1, // -1 is set for debuging purpose. + // in case of production we need to set appropriate value + 0, 0, 0, 0), SRT_ERROR ); + + + ASSERT_EQ(rlen, 1); // get exactly one read event without writes + ASSERT_EQ(wlen, 0); // get exactly one read event without writes + ASSERT_EQ(read[0], m_sock); // read event is for bind socket + } + + char pattern[4] = {1, 2, 3, 4}; + + ASSERT_EQ(srt_recvmsg(m_sock, buffer, sizeof buffer), + 1316); + + EXPECT_EQ(memcmp(pattern, buffer, sizeof pattern), 0); + + client.join(); + srt_close(m_sock); + srt_close(m_bindsock); + srt_close(m_client_sock); // cannot close m_client_sock after srt_sendmsg because of issue in api.c:2346 + + std::cout << "Server exit\n"; +} + +TEST(ReuseAddr, SameAddr1) +{ + ASSERT_EQ(srt_startup(), 0); + + client_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, client_pollid); + + server_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, server_pollid); + + std::thread server_1(serverSocket, "127.0.0.1", 5000, true); + server_1.join(); + + std::thread server_2(serverSocket, "127.0.0.1", 5000, true); + server_2.join(); + + (void)srt_epoll_release(client_pollid); + (void)srt_epoll_release(server_pollid); + srt_cleanup(); +} + +TEST(ReuseAddr, SameAddr2) +{ + std::string localip = GetLocalIP(); + if (localip == "") + return; // DISABLE TEST if this doesn't work. + + ASSERT_EQ(srt_startup(), 0); + + client_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, client_pollid); + + server_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, server_pollid); + + std::thread server_1(serverSocket, localip, 5000, true); + server_1.join(); + + std::thread server_2(serverSocket, localip, 5000, true); + server_2.join(); + + (void)srt_epoll_release(client_pollid); + (void)srt_epoll_release(server_pollid); + srt_cleanup(); +} + +TEST(ReuseAddr, DiffAddr) +{ + std::string localip = GetLocalIP(); + if (localip == "") + return; // DISABLE TEST if this doesn't work. + + ASSERT_EQ(srt_startup(), 0); + + client_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, client_pollid); + + server_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, server_pollid); + + serverSocket("127.0.0.1", 5000, true); + serverSocket(localip, 5000, true); + + (void)srt_epoll_release(client_pollid); + (void)srt_epoll_release(server_pollid); + srt_cleanup(); +} + +TEST(ReuseAddr, Wildcard) +{ +#if defined(_WIN32) || defined(CYGWIN) + std::cout << "!!!WARNING!!!: On Windows connection to localhost this way isn't possible.\n" + "Forcing test to pass, PLEASE FIX.\n"; + return; +#endif + std::string localip = GetLocalIP(); + if (localip == "") + return; // DISABLE TEST if this doesn't work. + + ASSERT_EQ(srt_startup(), 0); + + client_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, client_pollid); + + server_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, server_pollid); + + serverSocket("0.0.0.0", 5000, true); + serverSocket(localip, 5000, false); + + (void)srt_epoll_release(client_pollid); + (void)srt_epoll_release(server_pollid); + srt_cleanup(); +} + + +TEST(ReuseAddr, ProtocolVersion) +{ +#if defined(_WIN32) || defined(CYGWIN) + std::cout << "!!!WARNING!!!: On Windows connection to localhost this way isn't possible.\n" + "Forcing test to pass, PLEASE FIX.\n"; + return; +#endif + ASSERT_EQ(srt_startup(), 0); + + client_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, client_pollid); + + server_pollid = srt_epoll_create(); + ASSERT_NE(SRT_ERROR, server_pollid); + + serverSocket("::", 5000, true); + serverSocket("0.0.0.0", 5000, true); + + (void)srt_epoll_release(client_pollid); + (void)srt_epoll_release(server_pollid); + srt_cleanup(); +} diff --git a/test/test_sync.cpp b/test/test_sync.cpp index 950af154a..4967fbf86 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -449,8 +449,8 @@ TEST(SyncEvent, WaitForTwoNotifyOne) using wait_t = decltype(future_t().wait_for(chrono::microseconds(0))); wait_t wait_state[2] = { - move(future_result[0].wait_for(chrono::microseconds(100))), - move(future_result[1].wait_for(chrono::microseconds(100))) + move(future_result[0].wait_for(chrono::microseconds(500))), + move(future_result[1].wait_for(chrono::microseconds(500))) }; cerr << "SyncEvent::WaitForTwoNotifyOne: NOTIFICATION came from " << notified_clients.size() From 17fee159f9089e84cb2115747ba89c8d9ea7386a Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Mon, 31 May 2021 19:45:33 +0800 Subject: [PATCH 019/124] [core] make sure TTL will not drop packets over last block (#2005) --- srtcore/buffer.cpp | 11 +++++++++-- srtcore/buffer.h | 2 +- srtcore/core.cpp | 7 ------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index 5a756792e..db3102e7a 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -522,8 +522,15 @@ int CSndBuffer::readData(const int offset, srt::CPacket& w_packet, steady_clock: // XXX Suboptimal procedure to keep the blocks identifiable // by sequence number. Consider using some circular buffer. - for (int i = 0; i < offset; ++i) + for (int i = 0; i < offset && p != m_pLastBlock; ++i) + { p = p->m_pNext; + } + if (p == m_pLastBlock) + { + LOGC(qslog.Error, log << "CSndBuffer::readData: offset " << offset << " too large!"); + return 0; + } #if ENABLE_HEAVY_LOGGING const int32_t first_seq = p->m_iSeqNo; int32_t last_seq = p->m_iSeqNo; @@ -550,7 +557,7 @@ int CSndBuffer::readData(const int offset, srt::CPacket& w_packet, steady_clock: w_msglen = 1; p = p->m_pNext; bool move = false; - while (msgno == p->getMsgSeq()) + while (p != m_pLastBlock && msgno == p->getMsgSeq()) { #if ENABLE_HEAVY_LOGGING last_seq = p->m_iSeqNo; diff --git a/srtcore/buffer.h b/srtcore/buffer.h index 9a92e25b0..f69bef1d9 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -153,7 +153,7 @@ class CSndBuffer /// @param [out] msgno message number of the packet. /// @param [out] origintime origin time stamp of the message /// @param [out] msglen length of the message - /// @return Actual length of data read. + /// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded). int readData(const int offset, srt::CPacket& w_packet, time_point& w_origintime, int& w_msglen); /// Get the time of the last retransmission (if any) of the DATA packet. diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 1e9d2f052..826e9c18d 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8882,7 +8882,6 @@ int srt::CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origi int msglen; const int payload = m_pSndBuffer->readData(offset, (w_packet), (w_origintime), (msglen)); - SRT_ASSERT(payload != 0); if (payload == -1) { int32_t seqpair[2]; @@ -8903,12 +8902,6 @@ int srt::CUDT::packLostData(CPacket& w_packet, steady_clock::time_point& w_origi continue; } - // NOTE: This is just a sanity check. Returning 0 is impossible to happen - // in case of retransmission. If the offset was a positive value, then the - // block must exist in the old blocks because it wasn't yet cut off by ACK - // and has been already recorded as sent (otherwise the peer wouldn't send - // back the loss report). May something happen here in case when the send - // loss record has been updated by the FASTREXMIT. else if (payload == 0) continue; From 1751babcbe7758ec515d2ec6f2d1bac0f5e94991 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Mon, 31 May 2021 16:04:02 +0200 Subject: [PATCH 020/124] [core] FIX: Added check for NULL unit when passing to updateConnStatus (#2028) --- srtcore/core.cpp | 48 +++++++++++++++++++++++++++++------------------ srtcore/core.h | 6 +++--- srtcore/queue.cpp | 20 ++++++++++++-------- srtcore/queue.h | 2 +- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 826e9c18d..90162fa89 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -3600,7 +3600,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) // it means that it has done all that was required, however none of the below // things has to be done (this function will do it by itself if needed). // Otherwise the handshake rolling can be interrupted and considered complete. - cst = processRendezvous(response, serv_addr, RST_OK, (reqpkt)); + cst = processRendezvous(&response, serv_addr, RST_OK, (reqpkt)); if (cst == CONN_CONTINUE) continue; break; @@ -3744,7 +3744,7 @@ EConnectStatus srt::CUDT::processAsyncConnectResponse(const CPacket &pkt) ATR_NO bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, - const CPacket& response, + const CPacket* pResponse /*[[nullable]]*/, const sockaddr_any& serv_addr) { // IMPORTANT! @@ -3773,7 +3773,7 @@ bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst, if (cst == CONN_RENDEZVOUS) { HLOGC(cnlog.Debug, log << "processAsyncConnectRequest: passing to processRendezvous"); - cst = processRendezvous(response, serv_addr, rst, (request)); + cst = processRendezvous(pResponse, serv_addr, rst, (request)); if (cst == CONN_ACCEPT) { HLOGC(cnlog.Debug, @@ -3976,7 +3976,7 @@ EConnectStatus srt::CUDT::craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatas } EConnectStatus srt::CUDT::processRendezvous( - const CPacket& response, const sockaddr_any& serv_addr, + const CPacket* pResponse /*[[nullable]]*/, const sockaddr_any& serv_addr, EReadStatus rst, CPacket& w_reqpkt) { if (m_RdvState == CHandShake::RDV_CONNECTED) @@ -4053,7 +4053,7 @@ EConnectStatus srt::CUDT::processRendezvous( // We have JUST RECEIVED packet in this session (not that this is called as periodic update). // Sanity check m_tsLastReqTime = steady_clock::time_point(); - if (response.getLength() == size_t(-1)) + if (!pResponse || pResponse->getLength() == size_t(-1)) { m_RejectReason = SRT_REJ_IPE; LOGC(cnlog.Fatal, @@ -4061,7 +4061,7 @@ EConnectStatus srt::CUDT::processRendezvous( return CONN_REJECT; } - if (!interpretSrtHandshake(m_ConnRes, response, kmdata, &kmdatasize)) + if (!interpretSrtHandshake(m_ConnRes, *pResponse, kmdata, &kmdatasize)) { HLOGC(cnlog.Debug, log << "processRendezvous: rejecting due to problems in interpretSrtHandshake REQ-TIME: LOW."); @@ -4114,7 +4114,7 @@ EConnectStatus srt::CUDT::processRendezvous( // not be done in case of rendezvous. The section in postConnect() is // predicted to run only in regular CALLER handling. - if (rst != RST_OK || response.getLength() == size_t(-1)) + if (rst != RST_OK || !pResponse || pResponse->getLength() == size_t(-1)) { // Actually the -1 length would be an IPE, but it's likely that this was reported already. HLOGC( @@ -4125,7 +4125,7 @@ EConnectStatus srt::CUDT::processRendezvous( { HLOGC(cnlog.Debug, log << "processRendezvous: INITIATOR, will send AGREEMENT - interpreting HSRSP extension"); - if (!interpretSrtHandshake(m_ConnRes, response, 0, 0)) + if (!interpretSrtHandshake(m_ConnRes, *pResponse, 0, 0)) { // m_RejectReason is already set, so set the reqtype accordingly m_ConnReq.m_iReqType = URQFailure(m_RejectReason); @@ -4165,10 +4165,7 @@ EConnectStatus srt::CUDT::processRendezvous( w_reqpkt.setLength(m_iMaxSRTPayloadSize); if (m_RdvState == CHandShake::RDV_CONNECTED) { - // When synchro=false, don't lock a mutex for rendezvous queue. - // This is required when this function is called in the - // receive queue worker thread - it would lock itself. - int cst = postConnect(response, true, 0); + int cst = postConnect(pResponse, true, 0); if (cst == CONN_REJECT) { // m_RejectReason already set @@ -4304,7 +4301,7 @@ EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTEx m_RdvState = CHandShake::RDV_CONNECTED; } - return postConnect(response, hsv5, eout); + return postConnect(&response, hsv5, eout); } if (!response.isControl(UMSG_HANDSHAKE)) @@ -4474,7 +4471,7 @@ EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTEx } } - return postConnect(response, false, eout); + return postConnect(&response, false, eout); } bool srt::CUDT::applyResponseSettings() ATR_NOEXCEPT @@ -4507,7 +4504,7 @@ bool srt::CUDT::applyResponseSettings() ATR_NOEXCEPT return true; } -EConnectStatus srt::CUDT::postConnect(const CPacket &response, bool rendezvous, CUDTException *eout) ATR_NOEXCEPT +EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, CUDTException *eout) ATR_NOEXCEPT { if (m_ConnRes.m_iVersion < HS_VERSION_SRT1) m_tsRcvPeerStartTime = steady_clock::time_point(); // will be set correctly in SRT HS. @@ -4516,6 +4513,21 @@ EConnectStatus srt::CUDT::postConnect(const CPacket &response, bool rendezvous, // in rendezvous it's completed before calling this function. if (!rendezvous) { + // The "local storage depleted" case shouldn't happen here, but + // this is a theoretical path that needs prevention. + bool ok = pResponse; + if (!ok) + { + m_RejectReason = SRT_REJ_IPE; + if (eout) + { + *eout = CUDTException(MJ_SETUP, MN_REJECTED, 0); + } + return CONN_REJECT; + } + + // [[assert (pResponse != NULL)]]; + // NOTE: THIS function must be called before calling prepareConnectionObjects. // The reason why it's not part of prepareConnectionObjects is that the activities // done there are done SIMILAR way in acceptAndRespond, which also calls this @@ -4527,7 +4539,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket &response, bool rendezvous, // // Currently just this function must be called always BEFORE prepareConnectionObjects // everywhere except acceptAndRespond(). - bool ok = applyResponseSettings(); + ok = applyResponseSettings(); // This will actually be done also in rendezvous HSv4, // however in this case the HSREQ extension will not be attached, @@ -4537,8 +4549,8 @@ EConnectStatus srt::CUDT::postConnect(const CPacket &response, bool rendezvous, // May happen that 'response' contains a data packet that was sent in rendezvous mode. // In this situation the interpretation of handshake was already done earlier. - ok = ok && response.isControl(); - ok = ok && interpretSrtHandshake(m_ConnRes, response, 0, 0); + ok = ok && pResponse->isControl(); + ok = ok && interpretSrtHandshake(m_ConnRes, *pResponse, 0, 0); if (!ok) { diff --git a/srtcore/core.h b/srtcore/core.h index 2e463423c..eed601ea0 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -475,12 +475,12 @@ class CUDT /// @param response incoming handshake response packet to be interpreted /// @param serv_addr incoming packet's address /// @param rst Current read status to know if the HS packet was freshly received from the peer, or this is only a periodic update (RST_AGAIN) - SRT_ATR_NODISCARD EConnectStatus processRendezvous(const CPacket &response, const sockaddr_any& serv_addr, EReadStatus, CPacket& reqpkt); + SRT_ATR_NODISCARD EConnectStatus processRendezvous(const CPacket* response, const sockaddr_any& serv_addr, EReadStatus, CPacket& reqpkt); SRT_ATR_NODISCARD bool prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout); - SRT_ATR_NODISCARD EConnectStatus postConnect(const CPacket& response, bool rendezvous, CUDTException* eout) ATR_NOEXCEPT; + SRT_ATR_NODISCARD EConnectStatus postConnect(const CPacket* response, bool rendezvous, CUDTException* eout) ATR_NOEXCEPT; SRT_ATR_NODISCARD bool applyResponseSettings() ATR_NOEXCEPT; SRT_ATR_NODISCARD EConnectStatus processAsyncConnectResponse(const CPacket& pkt) ATR_NOEXCEPT; - SRT_ATR_NODISCARD bool processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, const CPacket& response, const sockaddr_any& serv_addr); + SRT_ATR_NODISCARD bool processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, const CPacket* response, const sockaddr_any& serv_addr); SRT_ATR_NODISCARD EConnectStatus craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize); void checkUpdateCryptoKeyLen(const char* loghdr, int32_t typefield); diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index fe323ab4c..9be4af013 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -903,17 +903,21 @@ srt::CUDT* srt::CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET& return NULL; } -void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn) +void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst, CUnit* unit) { vector toRemove, toProcess; + const CPacket* pkt = unit ? &unit->m_Packet : NULL; + + // Need a stub value for a case when there's no unit provided ("storage depleted" case). + // It should be normally NOT IN USE because in case of "storage depleted", rst != RST_OK. + const SRTSOCKET dest_id = pkt ? pkt->m_iID : 0; + // If no socket were qualified for further handling, finish here. // Otherwise toRemove and toProcess contain items to handle. - if (!qualifyToHandle(rst, cst, pktIn.m_iID, toRemove, toProcess)) + if (!qualifyToHandle(rst, cst, dest_id, (toRemove), (toProcess))) return; - // [[using locked()]]; - HLOGC(cnlog.Debug, log << "updateConnStatus: collected " << toProcess.size() << " for processing, " << toRemove.size() << " to close"); @@ -938,7 +942,7 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst EReadStatus read_st = rst; EConnectStatus conn_st = cst; - if (i->id != pktIn.m_iID) + if (i->id != dest_id) { read_st = RST_AGAIN; conn_st = CONN_AGAIN; @@ -947,7 +951,7 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst HLOGC(cnlog.Debug, log << "updateConnStatus: processing async conn for @" << i->id << " FROM " << i->peeraddr.str()); - if (!i->u->processAsyncConnectRequest(read_st, conn_st, pktIn, i->peeraddr)) + if (!i->u->processAsyncConnectRequest(read_st, conn_st, pkt, i->peeraddr)) { // cst == CONN_REJECT can only be result of worker_ProcessAddressedPacket and // its already set in this case. @@ -1310,7 +1314,7 @@ void* srt::CRcvQueue::worker(void* param) // worker_TryAsyncRend_OrStore ---> // CUDT::processAsyncConnectResponse ---> // CUDT::processConnectResponse - self->m_pRendezvousQueue->updateConnStatus(rst, cst, unit->m_Packet); + self->m_pRendezvousQueue->updateConnStatus(rst, cst, unit); // XXX updateConnStatus may have removed the connector from the list, // however there's still m_mBuffer in CRcvQueue for that socket to care about. @@ -1526,7 +1530,7 @@ EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUnit* un { LOGC(cnlog.Warn, log << "AsyncOrRND: PACKET NOT HANDSHAKE - re-requesting handshake from peer"); storePkt(id, unit->m_Packet.clone()); - if (!u->processAsyncConnectRequest(RST_AGAIN, CONN_CONTINUE, unit->m_Packet, u->m_PeerAddr)) + if (!u->processAsyncConnectRequest(RST_AGAIN, CONN_CONTINUE, &unit->m_Packet, u->m_PeerAddr)) { // Reuse previous behavior to reject a packet cst = CONN_REJECT; diff --git a/srtcore/queue.h b/srtcore/queue.h index b2ccb36d8..56afff9b6 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -354,7 +354,7 @@ class CRendezvousQueue /// @param rst result of reading from a UDP socket: received packet / nothin read / read error. /// @param cst target status for pending connection: reject or proceed. /// @param pktIn packet received from the UDP socket. - void updateConnStatus(EReadStatus rst, EConnectStatus cst, const CPacket& pktIn); + void updateConnStatus(EReadStatus rst, EConnectStatus cst, CUnit* unit); private: struct LinkStatusInfo From e37f4abc017f717220ccb624db41aa0fa03e2349 Mon Sep 17 00:00:00 2001 From: Sergei Ignatov Date: Tue, 1 Jun 2021 18:43:22 +1000 Subject: [PATCH 021/124] [build] Set openssl vars explicitly; Support mbedtls Android build (#2030) --- scripts/build-android/build-android | 48 ++++++++++++++++++++++------- scripts/build-android/mkmbedtls | 27 ++++++++++++++++ scripts/build-android/mksrt | 11 +++++-- 3 files changed, 73 insertions(+), 13 deletions(-) create mode 100755 scripts/build-android/mkmbedtls diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android index 622f525d2..3d69dac0c 100755 --- a/scripts/build-android/build-android +++ b/scripts/build-android/build-android @@ -6,9 +6,11 @@ echo_help() echo " -n Specify NDK root path for the build." echo " -a Select target API level." echo " -t Select target architectures." - echo " Android supports the following architectures: armeabi armeabi-v7a arm64-v8a x86 x86_64." + echo " Android supports the following architectures: armeabi-v7a arm64-v8a x86 x86_64." + echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls" echo " -o Select OpenSSL (1.1.1 series) version. E.g. 1.1.1h" - echo " -s Select a specific SRT tag. E.g. v1.4.3" + echo " -m Select Mbed TLS version. E.g. v2.26.0" + echo " -s Select SRT version. E.g. v1.4.3" echo echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/21.4.7075529 -a 28 -t \"armeabi-v7a arm64-v8a x86 x86_64\" -o 1.1.1h -s v1.4.3" echo @@ -17,11 +19,13 @@ echo_help() # Init optional command line vars NDK_ROOT="" API_LEVEL=28 -BUILD_TARGETS="armeabi armeabi-v7a arm64-v8a x86 x86_64" +BUILD_TARGETS="armeabi-v7a arm64-v8a x86 x86_64" OPENSSL_VERSION=1.1.1h SRT_VERSION="" +ENC_LIB=openssl +MBEDTLS_VERSION=v2.26.0 -while getopts n:a:t:o:s: option +while getopts n:a:t:o:s:e:m: option do case "${option}" in @@ -30,6 +34,8 @@ do t) BUILD_TARGETS=${OPTARG};; o) OPENSSL_VERSION=${OPTARG};; s) SRT_VERSION=${OPTARG};; + e) ENC_LIB=${OPTARG};; + m) MBEDTLS_VERSION=${OPTARG};; *) twentytwo=${OPTARG};; esac done @@ -49,7 +55,19 @@ fi # Determine the path of the executing script BASE_DIR=$(readlink -f $0 | xargs dirname) -$BASE_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION +if [ $ENC_LIB = 'openssl' ]; then + $BASE_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION +elif [ $ENC_LIB = 'mbedtls' ]; then + if [ ! -d $BASE_DIR/mbedtls ]; then + git clone https://github.com/ARMmbed/mbedtls mbedtls + if [ ! -z "$MBEDTLS_VERSION" ]; then + git -C $BASE_DIR/mbedtls checkout $MBEDTLS_VERSION + fi + fi +else + echo "Unknown encryption library. Possible options: openssl mbedtls" + exit 128 +fi if [ ! -d $BASE_DIR/srt ]; then git clone https://github.com/Haivision/srt srt @@ -58,12 +76,20 @@ if [ ! -d $BASE_DIR/srt ]; then fi fi -JNI_DIR=$BASE_DIR/prebuilt - for build_target in $BUILD_TARGETS; do - git -C $BASE_DIR/srt clean -fd - $BASE_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/srt -i $BASE_DIR/$build_target + LIB_DIR=$BASE_DIR/$build_target/lib + JNI_DIR=$BASE_DIR/prebuilt/$build_target + + mkdir -p $JNI_DIR - mkdir -p $JNI_DIR/$build_target - cp $BASE_DIR/$build_target/lib/libsrt.so $JNI_DIR/$build_target/libsrt.so + if [ $ENC_LIB = 'mbedtls' ]; then + $BASE_DIR/mkmbedtls -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/mbedtls -i $BASE_DIR/$build_target + cp $LIB_DIR/libmbedcrypto.so $JNI_DIR/libmbedcrypto.so + cp $LIB_DIR/libmbedtls.so $JNI_DIR/libmbedtls.so + cp $LIB_DIR/libmbedx509.so $JNI_DIR/libmbedx509.so + fi + + git -C $BASE_DIR/srt clean -fd + $BASE_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $BASE_DIR/srt -i $BASE_DIR/$build_target + cp $LIB_DIR/libsrt.so $JNI_DIR/libsrt.so done diff --git a/scripts/build-android/mkmbedtls b/scripts/build-android/mkmbedtls new file mode 100755 index 000000000..176154184 --- /dev/null +++ b/scripts/build-android/mkmbedtls @@ -0,0 +1,27 @@ +#!/bin/sh + +while getopts s:i:t:n:a: option +do + case "${option}" + in + s) SRC_DIR=${OPTARG};; + i) INSTALL_DIR=${OPTARG};; + t) ARCH_ABI=${OPTARG};; + n) NDK_ROOT=${OPTARG};; + a) API_LEVEL=${OPTARG};; + *) twentytwo=${OPTARG};; + esac +done + + +BUILD_DIR=/tmp/mbedtls_android_build +rm -rf $BUILD_DIR +mkdir $BUILD_DIR +cd $BUILD_DIR +cmake -DENABLE_TESTING=Off -DUSE_SHARED_MBEDTLS_LIBRARY=On \ +-DCMAKE_PREFIX_PATH=$INSTALL_DIR -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DCMAKE_ANDROID_NDK=$NDK_ROOT \ +-DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=$API_LEVEL -DCMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \ +-DCMAKE_C_FLAGS="-fPIC" -DCMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \ +-DCMAKE_BUILD_TYPE=RelWithDebInfo $SRC_DIR +cmake --build . +cmake --install . diff --git a/scripts/build-android/mksrt b/scripts/build-android/mksrt index 2af96a7aa..b2e176046 100755 --- a/scripts/build-android/mksrt +++ b/scripts/build-android/mksrt @@ -1,6 +1,6 @@ #!/bin/sh -while getopts s:i:t:n:a: option +while getopts s:i:t:n:a:e: option do case "${option}" in @@ -9,13 +9,20 @@ do t) ARCH_ABI=${OPTARG};; n) NDK_ROOT=${OPTARG};; a) API_LEVEL=${OPTARG};; + e) ENC_LIB=${OPTARG};; *) twentytwo=${OPTARG};; esac done cd $SRC_DIR -./configure --use-openssl-pc=OFF --OPENSSL_USE_STATIC_LIBS=true \ +./configure --use-enclib=$ENC_LIB \ +--use-openssl-pc=OFF --OPENSSL_USE_STATIC_LIBS=TRUE \ +--OPENSSL_INCLUDE_DIR=$INSTALL_DIR/include \ +--OPENSSL_CRYPTO_LIBRARY=$INSTALL_DIR/lib/libcrypto.a --OPENSSL_SSL_LIBRARY=$INSTALL_DIR/lib/libssl.a \ +--STATIC_MBEDTLS=FALSE \ +--MBEDTLS_INCLUDE_DIR=$INSTALL_DIR/include --MBEDTLS_INCLUDE_DIRS=$INSTALL_DIR/include \ +--MBEDTLS_LIBRARIES=$INSTALL_DIR/lib/libmbedtls.so \ --CMAKE_PREFIX_PATH=$INSTALL_DIR --CMAKE_INSTALL_PREFIX=$INSTALL_DIR --CMAKE_ANDROID_NDK=$NDK_ROOT \ --CMAKE_SYSTEM_NAME=Android --CMAKE_SYSTEM_VERSION=$API_LEVEL --CMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \ --CMAKE_C_FLAGS="-fPIC" --CMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \ From 0f0caf948733033915f09914c907fe5e1ecc375b Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 1 Jun 2021 15:08:17 +0200 Subject: [PATCH 022/124] [core] Added atomic support and marked atomic key fields detected by thread sanitizer (#1863) --- srtcore/api.cpp | 45 +++++--- srtcore/api.h | 4 +- srtcore/atomic.h | 210 ++++++++++++++++++++++++++++++++++++ srtcore/atomic_msvc.h | 245 ++++++++++++++++++++++++++++++++++++++++++ srtcore/congctl.cpp | 4 +- srtcore/core.cpp | 114 +++++++++++--------- srtcore/core.h | 75 ++++++------- srtcore/group.h | 2 +- srtcore/queue.cpp | 6 +- srtcore/queue.h | 10 +- srtcore/sync.h | 74 +++++++++++++ 11 files changed, 677 insertions(+), 112 deletions(-) create mode 100644 srtcore/atomic.h create mode 100644 srtcore/atomic_msvc.h diff --git a/srtcore/api.cpp b/srtcore/api.cpp index ad243d50e..aee13f389 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -2641,13 +2641,17 @@ void srt::CUDTUnited::checkBrokenSockets() // NOT WHETHER THEY ARE ALSO READY TO PLAY at the time when // this function is called (isRcvDataReady also checks if the // available data is "ready to play"). - && s->m_pUDT->m_pRcvBuffer->isRcvDataAvailable() - && (s->m_pUDT->m_iBrokenCounter -- > 0)) + && s->m_pUDT->m_pRcvBuffer->isRcvDataAvailable()) { - // HLOGF(smlog.Debug, "STILL KEEPING socket (still have data): - // %d\n", i->first); - // if there is still data in the receiver buffer, wait longer - continue; + const int bc = s->m_pUDT->m_iBrokenCounter.load(); + if (bc > 0) + { + // HLOGF(smlog.Debug, "STILL KEEPING socket (still have data): + // %d\n", i->first); + // if there is still data in the receiver buffer, wait longer + s->m_pUDT->m_iBrokenCounter.store(bc - 1); + continue; + } } #if ENABLE_EXPERIMENTAL_BONDING @@ -2702,15 +2706,17 @@ void srt::CUDTUnited::checkBrokenSockets() // RcvUList const steady_clock::time_point now = steady_clock::now(); const steady_clock::duration closed_ago = now - j->second->m_tsClosureTimeStamp; - if ((closed_ago > seconds_from(1)) - && ((!j->second->m_pUDT->m_pRNode) - || !j->second->m_pUDT->m_pRNode->m_bOnList)) + if (closed_ago > seconds_from(1)) { - HLOGC(smlog.Debug, log << "checkBrokenSockets: @" << j->second->m_SocketID << " closed " - << FormatDuration(closed_ago) << " ago and removed from RcvQ - will remove"); + CRNode* rnode = j->second->m_pUDT->m_pRNode; + if (!rnode || !rnode->m_bOnList) + { + HLOGC(smlog.Debug, log << "checkBrokenSockets: @" << j->second->m_SocketID << " closed " + << FormatDuration(closed_ago) << " ago and removed from RcvQ - will remove"); - // HLOGF(smlog.Debug, "will unref socket: %d\n", j->first); - tbr.push_back(j->first); + // HLOGF(smlog.Debug, "will unref socket: %d\n", j->first); + tbr.push_back(j->first); + } } } @@ -2734,6 +2740,19 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u) CUDTSocket* const s = i->second; + // The socket may be in the trashcan now, but could + // still be under processing in the sender/receiver worker + // threads. If that's the case, SKIP IT THIS TIME. The + // socket will be checked next time the GC rollover starts. + CSNode* sn = s->m_pUDT->m_pSNode; + if (sn && sn->m_iHeapLoc != -1) + return; + + CRNode* rn = s->m_pUDT->m_pRNode; + if (rn && rn->m_bOnList) + return; + + #if ENABLE_EXPERIMENTAL_BONDING if (s->m_GroupOf) { diff --git a/srtcore/api.h b/srtcore/api.h index 4228d8b46..5750c9db1 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -102,7 +102,7 @@ class CUDTSocket void construct(); - SRT_SOCKSTATUS m_Status; //< current socket state + srt::sync::atomic m_Status; //< current socket state /// Time when the socket is closed. /// When the socket is closed, it is not removed immediately from the list @@ -421,7 +421,7 @@ friend class CRendezvousQueue; CCache* m_pCache; // UDT network information cache private: - volatile bool m_bClosing; + srt::sync::atomic m_bClosing; sync::Mutex m_GCStopLock; sync::Condition m_GCStopCond; diff --git a/srtcore/atomic.h b/srtcore/atomic.h new file mode 100644 index 000000000..5cedd396d --- /dev/null +++ b/srtcore/atomic.h @@ -0,0 +1,210 @@ +//---------------------------------------------------------------------------- +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or distribute +// this software, either in source code form or as a compiled binary, for any +// purpose, commercial or non-commercial, and by any means. +// +// In jurisdictions that recognize copyright laws, the author or authors of +// this software dedicate any and all copyright interest in the software to the +// public domain. We make this dedication for the benefit of the public at +// large and to the detriment of our heirs and successors. We intend this +// dedication to be an overt act of relinquishment in perpetuity of all present +// and future rights to this software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to +//----------------------------------------------------------------------------- + +// SRT Project information: +// This file was adopted from a Public Domain project from +// https://github.com/mbitsnbites/atomic +// Only namespaces were changed to adopt it for SRT project. + +#ifndef SRT_SYNC_ATOMIC_H_ +#define SRT_SYNC_ATOMIC_H_ + +// Macro for disallowing copying of an object. +#if __cplusplus >= 201103L +#define ATOMIC_DISALLOW_COPY(T) \ + T(const T&) = delete; \ + T& operator=(const T&) = delete; +#else +#define ATOMIC_DISALLOW_COPY(T) \ + T(const T&); \ + T& operator=(const T&); +#endif + +// A portable static assert. +#if __cplusplus >= 201103L +#define ATOMIC_STATIC_ASSERT(condition, message) \ + static_assert((condition), message) +#else +// Based on: http://stackoverflow.com/a/809465/5778708 +#define ATOMIC_STATIC_ASSERT(condition, message) \ + _impl_STATIC_ASSERT_LINE(condition, __LINE__) +#define _impl_PASTE(a, b) a##b +#ifdef __GNUC__ +#define _impl_UNUSED __attribute__((__unused__)) +#else +#define _impl_UNUSED +#endif +#define _impl_STATIC_ASSERT_LINE(condition, line) \ + typedef char _impl_PASTE( \ + STATIC_ASSERT_failed_, \ + line)[(2 * static_cast(!!(condition))) - 1] _impl_UNUSED +#endif + +#if defined(__GNUC__) || defined(__clang__) || defined(__xlc__) +#define ATOMIC_USE_GCC_INTRINSICS +#elif defined(_MSC_VER) +#define ATOMIC_USE_MSVC_INTRINSICS +#include "atomic_msvc.h" +#elif __cplusplus >= 201103L +#define ATOMIC_USE_CPP11_ATOMIC +#include +#else +#error Unsupported compiler / system. +#endif + +namespace srt { +namespace sync { +template +class atomic { +public: + ATOMIC_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || + sizeof(T) == 8, + "Only types of size 1, 2, 4 or 8 are supported"); + + atomic() : value_(static_cast(0)) {} + + explicit atomic(const T value) : value_(value) {} + + /// @brief Performs an atomic increment operation (value + 1). + /// @returns The new value of the atomic object. + T operator++() { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + return msvc::interlocked::increment(&value_); +#else + return ++value_; +#endif + } + + /// @brief Performs an atomic decrement operation (value - 1). + /// @returns The new value of the atomic object. + T operator--() { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + return msvc::interlocked::decrement(&value_); +#else + return --value_; +#endif + } + + /// @brief Performs an atomic compare-and-swap (CAS) operation. + /// + /// The value of the atomic object is only updated to the new value if the + /// old value of the atomic object matches @c expected_val. + /// + /// @param expected_val The expected value of the atomic object. + /// @param new_val The new value to write to the atomic object. + /// @returns True if new_value was written to the atomic object. + bool compare_exchange(const T expected_val, const T new_val) { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + T e = expected_val; + return __atomic_compare_exchange_n( + &value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + const T old_val = + msvc::interlocked::compare_exchange(&value_, new_val, expected_val); + return (old_val == expected_val); +#else + T e = expected_val; + return value_.compare_exchange_weak(e, new_val); +#endif + } + + /// @brief Performs an atomic set operation. + /// + /// The value of the atomic object is unconditionally updated to the new + /// value. + /// + /// @param new_val The new value to write to the atomic object. + void store(const T new_val) { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + __atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + (void)msvc::interlocked::exchange(&value_, new_val); +#else + value_.store(new_val); +#endif + } + + /// @returns the current value of the atomic object. + /// @note Be careful about how this is used, since any operations on the + /// returned value are inherently non-atomic. + T load() const { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + return __atomic_load_n(&value_, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + // TODO(m): Is there a better solution for MSVC? + return value_; +#else + return value_; +#endif + } + + /// @brief Performs an atomic exchange operation. + /// + /// The value of the atomic object is unconditionally updated to the new + /// value, and the old value is returned. + /// + /// @param new_val The new value to write to the atomic object. + /// @returns the old value. + T exchange(const T new_val) { +#if defined(ATOMIC_USE_GCC_INTRINSICS) + return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST); +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + return msvc::interlocked::exchange(&value_, new_val); +#else + return value_.exchange(new_val); +#endif + } + + T operator=(const T new_value) { + store(new_value); + return new_value; + } + + operator T() const { + return load(); + } + +private: +#if defined(ATOMIC_USE_GCC_INTRINSICS) || defined(ATOMIC_USE_MSVC_INTRINSICS) + volatile T value_; +#else + std::atomic value_; +#endif + + ATOMIC_DISALLOW_COPY(atomic) +}; + +} // namespace sync +} // namespace srt + +// Undef temporary defines. +#undef ATOMIC_USE_GCC_INTRINSICS +#undef ATOMIC_USE_MSVC_INTRINSICS +#undef ATOMIC_USE_CPP11_ATOMIC + +#endif // ATOMIC_ATOMIC_H_ diff --git a/srtcore/atomic_msvc.h b/srtcore/atomic_msvc.h new file mode 100644 index 000000000..9e4df2dbd --- /dev/null +++ b/srtcore/atomic_msvc.h @@ -0,0 +1,245 @@ +//----------------------------------------------------------------------------- +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or distribute +// this software, either in source code form or as a compiled binary, for any +// purpose, commercial or non-commercial, and by any means. +// +// In jurisdictions that recognize copyright laws, the author or authors of +// this software dedicate any and all copyright interest in the software to the +// public domain. We make this dedication for the benefit of the public at +// large and to the detriment of our heirs and successors. We intend this +// dedication to be an overt act of relinquishment in perpetuity of all present +// and future rights to this software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to +//----------------------------------------------------------------------------- + +// SRT Project information: +// This file was adopted from a Public Domain project from +// https://github.com/mbitsnbites/atomic +// Only namespaces were changed to adopt it for SRT project. + +#ifndef SRT_SYNC_ATOMIC_MSVC_H_ +#define SRT_SYNC_ATOMIC_MSVC_H_ + +// Define which functions we need (don't include ). +extern "C" { +short _InterlockedIncrement16(short volatile*); +long _InterlockedIncrement(long volatile*); +__int64 _InterlockedIncrement64(__int64 volatile*); + +short _InterlockedDecrement16(short volatile*); +long _InterlockedDecrement(long volatile*); +__int64 _InterlockedDecrement64(__int64 volatile*); + +char _InterlockedExchange8(char volatile*, char); +short _InterlockedExchange16(short volatile*, short); +long __cdecl _InterlockedExchange(long volatile*, long); +__int64 _InterlockedExchange64(__int64 volatile*, __int64); + +char _InterlockedCompareExchange8(char volatile*, char, char); +short _InterlockedCompareExchange16(short volatile*, short, short); +long __cdecl _InterlockedCompareExchange(long volatile*, long, long); +__int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); +}; + +// Define which functions we want to use as inline intriniscs. +#pragma intrinsic(_InterlockedIncrement) +#pragma intrinsic(_InterlockedIncrement16) + +#pragma intrinsic(_InterlockedDecrement) +#pragma intrinsic(_InterlockedDecrement16) + +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedCompareExchange8) +#pragma intrinsic(_InterlockedCompareExchange16) + +#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedExchange8) +#pragma intrinsic(_InterlockedExchange16) + +#if defined(_M_X64) +#pragma intrinsic(_InterlockedIncrement64) +#pragma intrinsic(_InterlockedDecrement64) +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedExchange64) +#endif // _M_X64 + +namespace srt { +namespace sync { +namespace msvc { +template +struct interlocked { +}; + +template +struct interlocked { + static inline T increment(T volatile* x) { + // There's no _InterlockedIncrement8(). + char old_val, new_val; + do { + old_val = static_cast(*x); + new_val = old_val + static_cast(1); + } while (_InterlockedCompareExchange8(reinterpret_cast(x), + new_val, + old_val) != old_val); + return static_cast(new_val); + } + + static inline T decrement(T volatile* x) { + // There's no _InterlockedDecrement8(). + char old_val, new_val; + do { + old_val = static_cast(*x); + new_val = old_val - static_cast(1); + } while (_InterlockedCompareExchange8(reinterpret_cast(x), + new_val, + old_val) != old_val); + return static_cast(new_val); + } + + static inline T compare_exchange(T volatile* x, + const T new_val, + const T expected_val) { + return static_cast( + _InterlockedCompareExchange8(reinterpret_cast(x), + static_cast(new_val), + static_cast(expected_val))); + } + + static inline T exchange(T volatile* x, const T new_val) { + return static_cast(_InterlockedExchange8( + reinterpret_cast(x), static_cast(new_val))); + } +}; + +template +struct interlocked { + static inline T increment(T volatile* x) { + return static_cast( + _InterlockedIncrement16(reinterpret_cast(x))); + } + + static inline T decrement(T volatile* x) { + return static_cast( + _InterlockedDecrement16(reinterpret_cast(x))); + } + + static inline T compare_exchange(T volatile* x, + const T new_val, + const T expected_val) { + return static_cast( + _InterlockedCompareExchange16(reinterpret_cast(x), + static_cast(new_val), + static_cast(expected_val))); + } + + static inline T exchange(T volatile* x, const T new_val) { + return static_cast( + _InterlockedExchange16(reinterpret_cast(x), + static_cast(new_val))); + } +}; + +template +struct interlocked { + static inline T increment(T volatile* x) { + return static_cast( + _InterlockedIncrement(reinterpret_cast(x))); + } + + static inline T decrement(T volatile* x) { + return static_cast( + _InterlockedDecrement(reinterpret_cast(x))); + } + + static inline T compare_exchange(T volatile* x, + const T new_val, + const T expected_val) { + return static_cast( + _InterlockedCompareExchange(reinterpret_cast(x), + static_cast(new_val), + static_cast(expected_val))); + } + + static inline T exchange(T volatile* x, const T new_val) { + return static_cast(_InterlockedExchange( + reinterpret_cast(x), static_cast(new_val))); + } +}; + +template +struct interlocked { + static inline T increment(T volatile* x) { +#if defined(_M_X64) + return static_cast( + _InterlockedIncrement64(reinterpret_cast(x))); +#else + // There's no _InterlockedIncrement64() for 32-bit x86. + __int64 old_val, new_val; + do { + old_val = static_cast<__int64>(*x); + new_val = old_val + static_cast<__int64>(1); + } while (_InterlockedCompareExchange64( + reinterpret_cast(x), new_val, old_val) != + old_val); + return static_cast(new_val); +#endif // _M_X64 + } + + static inline T decrement(T volatile* x) { +#if defined(_M_X64) + return static_cast( + _InterlockedDecrement64(reinterpret_cast(x))); +#else + // There's no _InterlockedDecrement64() for 32-bit x86. + __int64 old_val, new_val; + do { + old_val = static_cast<__int64>(*x); + new_val = old_val - static_cast<__int64>(1); + } while (_InterlockedCompareExchange64( + reinterpret_cast(x), new_val, old_val) != + old_val); + return static_cast(new_val); +#endif // _M_X64 + } + + static inline T compare_exchange(T volatile* x, + const T new_val, + const T expected_val) { + return static_cast(_InterlockedCompareExchange64( + reinterpret_cast(x), + static_cast(new_val), + static_cast(expected_val))); + } + + static inline T exchange(T volatile* x, const T new_val) { +#if defined(_M_X64) + return static_cast( + _InterlockedExchange64(reinterpret_cast(x), + static_cast(new_val))); +#else + // There's no _InterlockedExchange64 for 32-bit x86. + __int64 old_val; + do { + old_val = static_cast<__int64>(*x); + } while (_InterlockedCompareExchange64( + reinterpret_cast(x), new_val, old_val) != + old_val); + return static_cast(old_val); +#endif // _M_X64 + } +}; +} // namespace msvc +} // namespace sync +} // namespace srt + +#endif // ATOMIC_ATOMIC_MSVC_H_ diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 998256216..4612e6852 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -60,7 +60,7 @@ void SrtCongestion::Check() class LiveCC: public SrtCongestionControlBase { int64_t m_llSndMaxBW; //Max bandwidth (bytes/sec) - size_t m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit + srt::sync::atomic m_zSndAvgPayloadSize; //Average Payload Size of packets to xmit size_t m_zMaxPayloadSize; // NAKREPORT stuff. @@ -167,7 +167,7 @@ class LiveCC: public SrtCongestionControlBase void updatePktSndPeriod() { // packet = payload + header - const double pktsize = (double) m_zSndAvgPayloadSize + CPacket::SRT_DATA_HDR_SIZE; + const double pktsize = (double) m_zSndAvgPayloadSize.load() + CPacket::SRT_DATA_HDR_SIZE; m_dPktSndPeriod = 1000 * 1000.0 * (pktsize / m_llSndMaxBW); HLOGC(cclog.Debug, log << "LiveCC: sending period updated: " << m_dPktSndPeriod << " by avg pktsize=" << m_zSndAvgPayloadSize diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 90162fa89..17611191e 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -254,7 +254,7 @@ void srt::CUDT::construct() // TODO: m_iBrokenCounter should be still set to some default. m_bPeerHealth = true; m_RejectReason = SRT_REJ_UNKNOWN; - m_tsLastReqTime = steady_clock::time_point(); + m_tsLastReqTime.store(steady_clock::time_point()); m_SrtHsSide = HSD_DRAW; m_uPeerSrtVersion = 0; // Not defined until connected. m_iTsbPdDelay_ms = 0; @@ -947,11 +947,11 @@ void srt::CUDT::open() m_tdNAKInterval = m_tdMinNakInterval; const steady_clock::time_point currtime = steady_clock::now(); - m_tsLastRspTime = currtime; - m_tsNextACKTime = currtime + m_tdACKInterval; - m_tsNextNAKTime = currtime + m_tdNAKInterval; - m_tsLastRspAckTime = currtime; - m_tsLastSndTime = currtime; + m_tsLastRspTime.store(currtime); + m_tsNextACKTime.store(currtime + m_tdACKInterval); + m_tsNextNAKTime.store(currtime + m_tdNAKInterval); + m_tsLastRspAckTime = currtime; + m_tsLastSndTime.store(currtime); m_tsUnstableSince = steady_clock::time_point(); m_tsFreshActivation = steady_clock::time_point(); @@ -3524,7 +3524,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn) while (!m_bClosing) { - const steady_clock::duration tdiff = steady_clock::now() - m_tsLastReqTime; + const steady_clock::duration tdiff = steady_clock::now() - m_tsLastReqTime.load(); // avoid sending too many requests, at most 1 request per 250ms // SHORT VERSION: @@ -5714,11 +5714,11 @@ SRT_REJECT_REASON srt::CUDT::setupCC() // Update timers const steady_clock::time_point currtime = steady_clock::now(); - m_tsLastRspTime = currtime; - m_tsNextACKTime = currtime + m_tdACKInterval; - m_tsNextNAKTime = currtime + m_tdNAKInterval; - m_tsLastRspAckTime = currtime; - m_tsLastSndTime = currtime; + m_tsLastRspTime.store(currtime); + m_tsNextACKTime.store(currtime + m_tdACKInterval); + m_tsNextNAKTime.store(currtime + m_tdNAKInterval); + m_tsLastRspAckTime = currtime; + m_tsLastSndTime.store(currtime); HLOGC(rslog.Debug, log << "setupCC: setting parameters: mss=" << m_config.iMSS << " maxCWNDSize/FlowWindowSize=" << m_iFlowWindowSize @@ -6848,6 +6848,7 @@ int64_t srt::CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int blo if (m_pSndBuffer->getCurrBufSize() == 0) { // delay the EXP timer to avoid mis-fired timeout + // XXX Lock ??? ScopedLock ack_lock(m_RecvAckLock); m_tsLastRspAckTime = steady_clock::now(); m_iReXmitCount = 1; } @@ -7151,8 +7152,8 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) const double interval = (double) count_microseconds(currtime - m_stats.tsLastSampleTime); perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval; perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval; - perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval); - perf->pktFlowWindow = m_iFlowWindowSize; + perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval.load()); + perf->pktFlowWindow = m_iFlowWindowSize.load(); perf->pktCongestionWindow = (int)m_dCongestionWindow; perf->pktFlightSize = getFlightSpan(); perf->msRTT = (double)m_iSRTT / 1000.0; @@ -7164,7 +7165,7 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) : m_CongCtl.ready() ? Bps2Mbps(m_CongCtl->sndBandwidth()) : 0; - const int64_t availbw = m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth; + const int64_t availbw = m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth.load(); perf->mbpsBandwidth = Bps2Mbps(availbw * (m_iMaxSRTPayloadSize + pktHdrSize)); @@ -7640,7 +7641,7 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp // Fix keepalive if (nbsent) - m_tsLastSndTime = steady_clock::now(); + m_tsLastSndTime.store(steady_clock::now()); } int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) @@ -8010,7 +8011,7 @@ void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_ if (CSeqNo::seqcmp(ackdata_seqno, m_iSndLastAck) >= 0) { ScopedLock ack_lock(m_RecvAckLock); - m_iFlowWindowSize -= CSeqNo::seqoff(m_iSndLastAck, ackdata_seqno); + m_iFlowWindowSize = m_iFlowWindowSize - CSeqNo::seqoff(m_iSndLastAck, ackdata_seqno); m_iSndLastAck = ackdata_seqno; // TODO: m_tsLastRspAckTime should be protected with m_RecvAckLock @@ -8150,11 +8151,15 @@ void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_ // improvements and testing. Double smoothing is applied here to be // consistent with the previous behavior. - if (rtt != INITIAL_RTT && rttvar != INITIAL_RTTVAR) + int crtt = m_iSRTT.load(), crttvar = m_iRTTVar.load(); + + if (crtt != INITIAL_RTT && rttvar != INITIAL_RTTVAR) { - m_iRTTVar = avg_iir<4>(m_iRTTVar, abs(rtt - m_iSRTT)); - m_iSRTT = avg_iir<8>(m_iSRTT, rtt); + crttvar = avg_iir<4>(crttvar, abs(crtt - crtt)); + crtt = avg_iir<8>(crtt, crtt); } + m_iSRTT = crtt; + m_iRTTVar = crttvar; } else // Transmission is unidirectional. { @@ -8212,9 +8217,9 @@ void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_ else bytesps = pktps * m_iMaxSRTPayloadSize; - m_iBandwidth = avg_iir<8>(m_iBandwidth, bandwidth); - m_iDeliveryRate = avg_iir<8>(m_iDeliveryRate, pktps); - m_iByteDeliveryRate = avg_iir<8>(m_iByteDeliveryRate, bytesps); + m_iBandwidth = avg_iir<8>(m_iBandwidth.load(), bandwidth); + m_iDeliveryRate = avg_iir<8>(m_iDeliveryRate.load(), pktps); + m_iByteDeliveryRate = avg_iir<8>(m_iByteDeliveryRate.load(), bytesps); // Update Estimated Bandwidth and packet delivery rate // m_iRcvRate = m_iDeliveryRate; @@ -8272,8 +8277,8 @@ void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr // on subsequent RTT samples (during transmission). if (m_bIsFirstRTTReceived) { - m_iRTTVar = avg_iir<4>(m_iRTTVar, abs(rtt - m_iSRTT)); - m_iSRTT = avg_iir<8>(m_iSRTT, rtt); + m_iRTTVar = avg_iir<4>(m_iRTTVar.load(), abs(rtt - m_iSRTT.load())); + m_iSRTT = avg_iir<8>(m_iSRTT.load(), rtt); } // Reset the value of smoothed RTT on the first RTT sample after initialization // (at the beginning of transmission). @@ -8568,7 +8573,7 @@ void srt::CUDT::processCtrlHS(const CPacket& ctrlpkt) const int nbsent = m_pSndQueue->sendto(m_PeerAddr, response); if (nbsent) { - m_tsLastSndTime = steady_clock::now(); + m_tsLastSndTime.store(steady_clock::now()); } } } @@ -8687,7 +8692,7 @@ void srt::CUDT::processCtrl(const CPacket &ctrlpkt) case UMSG_CGWARNING: // 100 - Delay Warning // One way packet delay is increasing, so decrease the sending rate - m_tdSendInterval = (m_tdSendInterval * 1125) / 1000; + m_tdSendInterval = (m_tdSendInterval.load() * 1125) / 1000; // XXX Note as interesting fact: this is only prepared for handling, // but nothing in the code is sending this message. Probably predicted // for a custom congctl. There's a predicted place to call it under @@ -8957,7 +8962,9 @@ std::pair srt::CUDT::packData(CPacket& w_packet) const steady_clock::time_point enter_time = steady_clock::now(); if (!is_zero(m_tsNextSendTime) && enter_time > m_tsNextSendTime) - m_tdSendTimeDiff += enter_time - m_tsNextSendTime; + { + m_tdSendTimeDiff = m_tdSendTimeDiff.load() + (enter_time - m_tsNextSendTime); + } string reason = "reXmit"; @@ -9083,7 +9090,7 @@ std::pair srt::CUDT::packData(CPacket& w_packet) else { m_tsNextSendTime = steady_clock::time_point(); - m_tdSendTimeDiff = m_tdSendTimeDiff.zero(); + m_tdSendTimeDiff = steady_clock::duration(); return std::make_pair(0, enter_time); } } @@ -9092,7 +9099,7 @@ std::pair srt::CUDT::packData(CPacket& w_packet) HLOGC(qslog.Debug, log << "packData: CONGESTED: cwnd=min(" << m_iFlowWindowSize << "," << m_dCongestionWindow << ")=" << cwnd << " seqlen=(" << m_iSndLastAck << "-" << m_iSndCurrSeqNo << ")=" << flightspan); m_tsNextSendTime = steady_clock::time_point(); - m_tdSendTimeDiff = m_tdSendTimeDiff.zero(); + m_tdSendTimeDiff = steady_clock::duration(); return std::make_pair(0, enter_time); } @@ -9166,7 +9173,7 @@ std::pair srt::CUDT::packData(CPacket& w_packet) #endif // Fix keepalive - m_tsLastSndTime = enter_time; + m_tsLastSndTime.store(enter_time); considerLegacySrtHandshake(steady_clock::time_point()); @@ -9205,18 +9212,24 @@ std::pair srt::CUDT::packData(CPacket& w_packet) else { #if USE_BUSY_WAITING - m_tsNextSendTime = enter_time + m_tdSendInterval; + m_tsNextSendTime = enter_time + m_tdSendInterval.load(); #else - if (m_tdSendTimeDiff >= m_tdSendInterval) + const duration sendint = m_tdSendInterval; + const duration sendbrw = m_tdSendTimeDiff; + + if (sendbrw >= sendint) { // Send immidiately m_tsNextSendTime = enter_time; - m_tdSendTimeDiff -= m_tdSendInterval; + + // ATOMIC NOTE: this is the only thread that + // modifies this field + m_tdSendTimeDiff = sendbrw - sendint; } else { - m_tsNextSendTime = enter_time + (m_tdSendInterval - m_tdSendTimeDiff); - m_tdSendTimeDiff = m_tdSendTimeDiff.zero(); + m_tsNextSendTime = enter_time + (sendint - sendbrw); + m_tdSendTimeDiff = duration(); } #endif } @@ -9343,7 +9356,7 @@ int srt::CUDT::processData(CUnit* in_unit) // Just heard from the peer, reset the expiration count. m_iEXPCount = 1; - m_tsLastRspTime = steady_clock::now(); + m_tsLastRspTime.store(steady_clock::now()); const bool need_tsbpd = m_bTsbPd || m_bGroupTsbPd; @@ -9792,7 +9805,7 @@ int srt::CUDT::processData(CUnit* in_unit) // a given period). if (m_CongCtl->needsQuickACK(packet)) { - m_tsNextACKTime = steady_clock::now(); + m_tsNextACKTime.store(steady_clock::now()); } } @@ -10626,7 +10639,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) HLOGC(cnlog.Debug, log << "processConnectRequest: rejecting due to problems in createSrtHandshake."); result = -1; // enforce fallthrough for the below condition! - hs.m_iReqType = URQFailure(m_RejectReason == SRT_REJ_UNKNOWN ? SRT_REJ_IPE : m_RejectReason); + hs.m_iReqType = URQFailure(m_RejectReason == SRT_REJ_UNKNOWN ? int(SRT_REJ_IPE) : m_RejectReason.load()); } else { @@ -10698,7 +10711,7 @@ void srt::CUDT::addLossRecord(std::vector &lr, int32_t lo, int32_t hi) int srt::CUDT::checkACKTimer(const steady_clock::time_point &currtime) { int because_decision = BECAUSE_NO_REASON; - if (currtime > m_tsNextACKTime // ACK time has come + if (currtime > m_tsNextACKTime.load() // ACK time has come // OR the number of sent packets since last ACK has reached // the congctl-defined value of ACK Interval // (note that none of the builtin congctls defines ACK Interval) @@ -10710,7 +10723,7 @@ int srt::CUDT::checkACKTimer(const steady_clock::time_point &currtime) const steady_clock::duration ack_interval = m_CongCtl->ACKTimeout_us() > 0 ? microseconds_from(m_CongCtl->ACKTimeout_us()) : m_tdACKInterval; - m_tsNextACKTime = currtime + ack_interval; + m_tsNextACKTime.store(currtime + ack_interval); m_iPktCount = 0; m_iLightACKCount = 1; @@ -10762,14 +10775,14 @@ int srt::CUDT::checkNAKTimer(const steady_clock::time_point& currtime) if (loss_len > 0) { - if (currtime <= m_tsNextNAKTime) + if (currtime <= m_tsNextNAKTime.load()) return BECAUSE_NO_REASON; // wait for next NAK time sendCtrl(UMSG_LOSSREPORT); debug_decision = BECAUSE_NAKREPORT; } - m_tsNextNAKTime = currtime + m_tdNAKInterval; + m_tsNextNAKTime.store(currtime + m_tdNAKInterval); return debug_decision; } @@ -10805,7 +10818,7 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec steady_clock::time_point next_exp_time; if (m_CongCtl->RTO()) { - next_exp_time = m_tsLastRspTime + microseconds_from(m_CongCtl->RTO()); + next_exp_time = m_tsLastRspTime.load() + microseconds_from(m_CongCtl->RTO()); } else { @@ -10813,7 +10826,7 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec microseconds_from(m_iEXPCount * (m_iSRTT + 4 * m_iRTTVar) + COMM_SYN_INTERVAL_US); if (exp_timeout < (m_iEXPCount * m_tdMinExpInterval)) exp_timeout = m_iEXPCount * m_tdMinExpInterval; - next_exp_time = m_tsLastRspTime + exp_timeout; + next_exp_time = m_tsLastRspTime.load() + exp_timeout; } if (currtime <= next_exp_time && !m_bBreakAsUnstable) @@ -10823,8 +10836,9 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec const int PEER_IDLE_TMO_US = m_config.iPeerIdleTimeout * 1000; // Haven't received any information from the peer, is it dead?! // timeout: at least 16 expirations and must be greater than 5 seconds + time_point last_rsp_time = m_tsLastRspTime.load(); if (m_bBreakAsUnstable || ((m_iEXPCount > COMM_RESPONSE_MAX_EXP) && - (currtime - m_tsLastRspTime > microseconds_from(PEER_IDLE_TMO_US)))) + (currtime - last_rsp_time > microseconds_from(PEER_IDLE_TMO_US)))) { // // Connection is broken. @@ -10832,7 +10846,7 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec // Application will detect this when it calls any UDT methods next time. // HLOGC(xtlog.Debug, - log << "CONNECTION EXPIRED after " << count_milliseconds(currtime - m_tsLastRspTime) << "ms"); + log << "CONNECTION EXPIRED after " << count_milliseconds(currtime - last_rsp_time) << "ms"); m_bClosing = true; m_bBroken = true; m_iBrokenCounter = 30; @@ -10848,7 +10862,7 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec HLOGC(xtlog.Debug, log << "EXP TIMER: count=" << m_iEXPCount << "/" << (+COMM_RESPONSE_MAX_EXP) << " elapsed=" - << (count_microseconds(currtime - m_tsLastRspTime)) << "/" << (+PEER_IDLE_TMO_US) << "us"); + << (count_microseconds(currtime - last_rsp_time)) << "/" << (+PEER_IDLE_TMO_US) << "us"); ++m_iEXPCount; @@ -10969,7 +10983,7 @@ void srt::CUDT::checkTimers() // Check if FAST or LATE packet retransmission is required checkRexmitTimer(currtime); - if (currtime > m_tsLastSndTime + microseconds_from(COMM_KEEPALIVE_PERIOD_US)) + if (currtime > m_tsLastSndTime.load() + microseconds_from(COMM_KEEPALIVE_PERIOD_US)) { sendCtrl(UMSG_KEEPALIVE); #if ENABLE_EXPERIMENTAL_BONDING @@ -11051,7 +11065,7 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) // explicitly, otherwise they will never be deleted. if (pending_broken) { - // XXX This somehow can cause a deadlock + // XXX This somehow can cause a deadlock, even without GlobControlLock // s_UDTUnited.close(m_parent); m_parent->setBrokenClosed(); } diff --git a/srtcore/core.h b/srtcore/core.h index eed601ea0..d190780a0 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -56,7 +56,6 @@ modified by #include #include - #include "srt.h" #include "common.h" #include "list.h" @@ -173,6 +172,8 @@ class CUDT typedef sync::steady_clock::time_point time_point; typedef sync::steady_clock::duration duration; + typedef srt::sync::AtomicClock atomic_time_point; + typedef srt::sync::AtomicDuration atomic_duration; private: // constructor and desctructor void construct(); @@ -310,7 +311,7 @@ class CUDT int32_t schedSeqNo() const { return m_iSndNextSeqNo; } bool overrideSndSeqNo(int32_t seq); - srt::sync::steady_clock::time_point lastRspTime() const { return m_tsLastRspTime; } + srt::sync::steady_clock::time_point lastRspTime() const { return m_tsLastRspTime.load(); } srt::sync::steady_clock::time_point freshActivationStart() const { return m_tsFreshActivation; } int32_t rcvSeqNo() const { return m_iRcvCurrSeqNo; } @@ -723,30 +724,30 @@ class CUDT void EmitSignal(ETransmissionEvent tev, EventVariant var); // Internal state - volatile bool m_bListening; // If the UDT entity is listening to connection - volatile bool m_bConnecting; // The short phase when connect() is called but not yet completed - volatile bool m_bConnected; // Whether the connection is on or off - volatile bool m_bClosing; // If the UDT entity is closing - volatile bool m_bShutdown; // If the peer side has shutdown the connection - volatile bool m_bBroken; // If the connection has been broken - volatile bool m_bBreakAsUnstable; // A flag indicating that the socket should become broken because it has been unstable for too long. - volatile bool m_bPeerHealth; // If the peer status is normal - volatile int m_RejectReason; + srt::sync::atomic m_bListening; // If the UDT entity is listening to connection + srt::sync::atomic m_bConnecting; // The short phase when connect() is called but not yet completed + srt::sync::atomic m_bConnected; // Whether the connection is on or off + srt::sync::atomic m_bClosing; // If the UDT entity is closing + srt::sync::atomic m_bShutdown; // If the peer side has shutdown the connection + srt::sync::atomic m_bBroken; // If the connection has been broken + srt::sync::atomic m_bBreakAsUnstable; // A flag indicating that the socket should become broken because it has been unstable for too long. + srt::sync::atomic m_bPeerHealth; // If the peer status is normal + srt::sync::atomic m_RejectReason; bool m_bOpened; // If the UDT entity has been opened - int m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected + srt::sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected int m_iEXPCount; // Expiration counter - int m_iBandwidth; // Estimated bandwidth, number of packets per second - int m_iSRTT; // Smoothed RTT (an exponentially-weighted moving average (EWMA) + srt::sync::atomic m_iBandwidth; // Estimated bandwidth, number of packets per second + srt::sync::atomic m_iSRTT; // Smoothed RTT (an exponentially-weighted moving average (EWMA) // of an endpoint's RTT samples), in microseconds - int m_iRTTVar; // The variation in the RTT samples (RTT variance), in microseconds - bool m_bIsFirstRTTReceived; // True if the first RTT sample was obtained from the ACK/ACKACK pair + srt::sync::atomic m_iRTTVar; // The variation in the RTT samples (RTT variance), in microseconds + srt::sync::atomic m_bIsFirstRTTReceived;// True if the first RTT sample was obtained from the ACK/ACKACK pair // at the receiver side or received by the sender from an ACK packet. // It's used to reset the initial value of smoothed RTT (m_iSRTT) // at the beginning of transmission (including the one taken from // cache). False by default. - int m_iDeliveryRate; // Packet arrival rate at the receiver side - int m_iByteDeliveryRate; // Byte arrival rate at the receiver side + srt::sync::atomic m_iDeliveryRate; // Packet arrival rate at the receiver side + srt::sync::atomic m_iByteDeliveryRate; // Byte arrival rate at the receiver side CHandShake m_ConnReq; // Connection request CHandShake m_ConnRes; // Connection response @@ -758,24 +759,24 @@ class CUDT CSndLossList* m_pSndLossList; // Sender loss list CPktTimeWindow<16, 16> m_SndTimeWindow; // Packet sending time window - /*volatile*/ duration m_tdSendInterval; // Inter-packet time, in CPU clock cycles + atomic_duration m_tdSendInterval; // Inter-packet time, in CPU clock cycles - /*volatile*/ duration m_tdSendTimeDiff; // Aggregate difference in inter-packet sending time + atomic_duration m_tdSendTimeDiff; // Aggregate difference in inter-packet sending time - volatile int m_iFlowWindowSize; // Flow control window size - volatile double m_dCongestionWindow; // Congestion window size + srt::sync::atomic m_iFlowWindowSize; // Flow control window size + double m_dCongestionWindow; // Congestion window size private: // Timers - /*volatile*/ time_point m_tsNextACKTime; // Next ACK time, in CPU clock cycles, same below - /*volatile*/ time_point m_tsNextNAKTime; // Next NAK time - - /*volatile*/ duration m_tdACKInterval; // ACK interval - /*volatile*/ duration m_tdNAKInterval; // NAK interval - /*volatile*/ time_point m_tsLastRspTime; // Timestamp of last response from the peer - /*volatile*/ time_point m_tsLastRspAckTime; // Timestamp of last ACK from the peer - /*volatile*/ time_point m_tsLastSndTime; // Timestamp of last data/ctrl sent (in system ticks) + atomic_time_point m_tsNextACKTime; // Next ACK time, in CPU clock cycles, same below + atomic_time_point m_tsNextNAKTime; // Next NAK time + + duration m_tdACKInterval; // ACK interval + duration m_tdNAKInterval; // NAK interval + atomic_time_point m_tsLastRspTime; // Timestamp of last response from the peer + time_point m_tsLastRspAckTime; // Timestamp of last ACK from the peer + atomic_time_point m_tsLastSndTime; // Timestamp of last data/ctrl sent (in system ticks) time_point m_tsLastWarningTime; // Last time that a warning message is sent - time_point m_tsLastReqTime; // last time when a connection request is sent + atomic_time_point m_tsLastReqTime; // last time when a connection request is sent time_point m_tsRcvPeerStartTime; time_point m_tsLingerExpiration; // Linger expiration time (for GC to close a socket with data in sending buffer) time_point m_tsLastAckTime; // Timestamp of last ACK @@ -787,8 +788,8 @@ class CUDT time_point m_tsNextSendTime; // Scheduled time of next packet sending - volatile int32_t m_iSndLastFullAck; // Last full ACK received - volatile int32_t m_iSndLastAck; // Last ACK received + srt::sync::atomic m_iSndLastFullAck;// Last full ACK received + srt::sync::atomic m_iSndLastAck; // Last ACK received // NOTE: m_iSndLastDataAck is the value strictly bound to the CSndBufer object (m_pSndBuffer) // and this is the sequence number that refers to the block at position [0]. Upon acknowledgement, @@ -798,9 +799,9 @@ class CUDT // to the sending buffer. This way, extraction of an old packet for retransmission should // require only the lost sequence number, and how to find the packet with this sequence // will be up to the sending buffer. - volatile int32_t m_iSndLastDataAck; // The real last ACK that updates the sender buffer and loss list - volatile int32_t m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT - volatile int32_t m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet + srt::sync::atomic m_iSndLastDataAck;// The real last ACK that updates the sender buffer and loss list + srt::sync::atomic m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT + srt::sync::atomic m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet // Note important differences between Curr and Next fields: // - m_iSndCurrSeqNo: this is used by SRT:SndQ:worker thread and it's operated from CUDT::packData @@ -862,7 +863,7 @@ class CUDT int32_t m_iRcvLastSkipAck; // Last dropped sequence ACK int32_t m_iRcvLastAckAck; // Last sent ACK that has been acknowledged int32_t m_iAckSeqNo; // Last ACK sequence number - int32_t m_iRcvCurrSeqNo; // Largest received sequence number + srt::sync::atomic m_iRcvCurrSeqNo; // Largest received sequence number int32_t m_iRcvCurrPhySeqNo; // Same as m_iRcvCurrSeqNo, but physical only (disregarding a filter) int32_t m_iPeerISN; // Initial Sequence Number of the peer side diff --git a/srtcore/group.h b/srtcore/group.h index ec5d124d3..549900370 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -435,7 +435,7 @@ class CUDTGroup bool m_bSyncOnMsgNo; SRT_GROUP_TYPE m_type; CUDTSocket* m_listener; // A "group" can only have one listener. - int m_iBusy; + srt::sync::atomic m_iBusy; CallbackHolder m_cbConnectHook; void installConnectHook(srt_connect_callback_fn* hook, void* opaq) { diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 9be4af013..b9d7ed02e 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -242,15 +242,17 @@ void srt::CUnitQueue::makeUnitFree(CUnit* unit) SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag != CUnit::FREE); unit->m_iFlag = CUnit::FREE; + --m_iCount; } void srt::CUnitQueue::makeUnitGood(CUnit* unit) { + ++m_iCount; + SRT_ASSERT(unit != NULL); SRT_ASSERT(unit->m_iFlag == CUnit::FREE); unit->m_iFlag = CUnit::GOOD; - ++m_iCount; } srt::CSndUList::CSndUList() @@ -431,7 +433,7 @@ void srt::CSndUList::remove_(const CUDT* u) // remove the node from heap m_pHeap[n->m_iHeapLoc] = m_pHeap[m_iLastEntry]; m_iLastEntry--; - m_pHeap[n->m_iHeapLoc]->m_iHeapLoc = n->m_iHeapLoc; + m_pHeap[n->m_iHeapLoc]->m_iHeapLoc = n->m_iHeapLoc.load(); int q = n->m_iHeapLoc; int p = q * 2 + 1; diff --git a/srtcore/queue.h b/srtcore/queue.h index 56afff9b6..ee05440c8 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -137,7 +137,7 @@ class CUnitQueue CUnit* m_pAvailUnit; // recent available unit int m_iSize; // total size of the unit queue, in number of packets - int m_iCount; // total number of valid (occupied) packets in the queue + srt::sync::atomic m_iCount; // total number of valid (occupied) packets in the queue int m_iMSS; // unit buffer size int m_iIPversion; // IP version @@ -152,7 +152,7 @@ struct CSNode CUDT* m_pUDT; // Pointer to the instance of CUDT socket sync::steady_clock::time_point m_tsTimeStamp; - int m_iHeapLoc; // location on the heap, -1 means not on the heap + srt::sync::atomic m_iHeapLoc; // location on the heap, -1 means not on the heap }; class CSndUList @@ -240,7 +240,7 @@ struct CRNode CRNode* m_pPrev; // previous link CRNode* m_pNext; // next link - bool m_bOnList; // if the node is already on the list + srt::sync::atomic m_bOnList; // if the node is already on the list }; class CRcvUList @@ -465,7 +465,7 @@ class CSndQueue srt::sync::Mutex m_WindowLock; srt::sync::Condition m_WindowCond; - volatile bool m_bClosing; // closing the worker + srt::sync::atomic m_bClosing; // closing the worker #if defined(SRT_DEBUG_SNDQ_HIGHRATE) //>>debug high freq worker uint64_t m_ullDbgPeriod; @@ -545,7 +545,7 @@ class CRcvQueue size_t m_szPayloadSize; // packet payload size - volatile bool m_bClosing; // closing the worker + srt::sync::atomic m_bClosing; // closing the worker #if ENABLE_LOGGING static int m_counter; #endif diff --git a/srtcore/sync.h b/srtcore/sync.h index f25c5ca8d..53123c682 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -18,10 +18,12 @@ #include #include #include +#include #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_STDCXX_STEADY #define SRT_SYNC_CLOCK_STR "STDCXX_STEADY" #else #include +#include "atomic.h" // Defile clock type to use #ifdef IA32 @@ -180,6 +182,11 @@ class TimePoint { } + TimePoint(const Duration& duration_since_epoch) + : m_timestamp(duration_since_epoch.count()) + { + } + ~TimePoint() {} public: // Relational operators @@ -224,6 +231,73 @@ inline Duration operator*(const int& lhs, const Duration +class AtomicDuration +{ + atomic dur; + typedef typename Clock::duration duration_type; + typedef typename Clock::time_point time_point_type; +public: + + AtomicDuration() ATR_NOEXCEPT : dur(0) {} + + duration_type load() + { + int64_t val = dur.load(); + return duration_type(val); + } + + void store(const duration_type& d) + { + dur.store(d.count()); + } + + AtomicDuration& operator=(const duration_type& s) + { + dur = s.count(); + return *this; + } + + operator duration_type() const + { + return duration_type(dur); + } +}; + +template +class AtomicClock +{ + atomic dur; + typedef typename Clock::duration duration_type; + typedef typename Clock::time_point time_point_type; +public: + + AtomicClock() ATR_NOEXCEPT : dur(0) {} + + time_point_type load() const + { + int64_t val = dur.load(); + return time_point_type(duration_type(val)); + } + + void store(const time_point_type& d) + { + dur.store(uint64_t(d.time_since_epoch().count())); + } + + AtomicClock& operator=(const time_point_type& s) + { + dur = s.time_since_epoch().count(); + return *this; + } + + operator time_point_type() const + { + return time_point_type(duration_type(dur.load())); + } +}; + + /////////////////////////////////////////////////////////////////////////////// // // Duration and timepoint conversions From 28a7006a3a35ec9331f6c2c310e353e9ba2a6368 Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Tue, 1 Jun 2021 21:31:09 +0800 Subject: [PATCH 023/124] [core] use seq larger than m_RcvBaseSeqNo to update group readablity (#2026) --- srtcore/buffer.cpp | 62 +++++++++++++++++++++++++++++++--------------- srtcore/buffer.h | 11 ++++++-- srtcore/core.cpp | 11 +++++++- srtcore/group.cpp | 6 +++++ srtcore/group.h | 1 + 5 files changed, 68 insertions(+), 23 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index db3102e7a..b63439580 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -1123,8 +1123,10 @@ size_t CRcvBuffer::dropData(int len) bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, bool& w_passack, int32_t& w_skipseqno, - int32_t& w_curpktseq) + int32_t& w_curpktseq, + int32_t base_seq) { + HLOGC(brlog.Debug, log << "getRcvFirstMsg: base_seq=" << base_seq); w_skipseqno = SRT_SEQNO_NONE; w_passack = false; // tsbpdtime will be retrieved by the below call @@ -1137,8 +1139,8 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, /* Check the acknowledged packets */ // getRcvReadyMsg returns true if the time to play for the first message - // (returned in w_tsbpdtime) is in the past. - if (getRcvReadyMsg((w_tsbpdtime), (w_curpktseq), -1)) + // that larger than base_seq is in the past. + if (getRcvReadyMsg((w_tsbpdtime), (w_curpktseq), -1, base_seq)) { HLOGC(brlog.Debug, log << "getRcvFirstMsg: ready CONTIG packet: %" << w_curpktseq); return true; @@ -1167,9 +1169,10 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, * No acked packets ready but caller want to know next packet to wait for * Check the not yet acked packets that may be stuck by missing packet(s). */ - bool haslost = false; - w_tsbpdtime = steady_clock::time_point(); // redundant, for clarity - w_passack = true; + bool haslost = false; + steady_clock::time_point tsbpdtime = steady_clock::time_point(); + w_tsbpdtime = steady_clock::time_point(); + w_passack = true; // XXX SUSPECTED ISSUE with this algorithm: // The above call to getRcvReadyMsg() should report as to whether: @@ -1195,8 +1198,11 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, // When done so, the below loop would be completely unnecessary. // Logical description of the below algorithm: - // 1. Check if the VERY FIRST PACKET is valid; if so then: - // - check if it's ready to play, return boolean value that marks it. + // 1. update w_tsbpdtime and w_curpktseq if found one packet ready to play + // - keep check the next packet if still smaller than base_seq + // 2. set w_skipseqno if found packets before w_curpktseq lost + // if no packets larger than base_seq ready to play, return the largest RTP + // else return the first one that larger than base_seq and rady to play for (int i = m_iLastAckPos, n = shift(m_iLastAckPos, m_iMaxPos); i != n; i = shiftFwd(i)) { @@ -1208,19 +1214,21 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, } else { - /* We got the 1st valid packet */ - w_tsbpdtime = getPktTsbPdTime(m_pUnit[i]->m_Packet.getMsgTimeStamp()); - if (w_tsbpdtime <= steady_clock::now()) + tsbpdtime = getPktTsbPdTime(m_pUnit[i]->m_Packet.getMsgTimeStamp()); + if (tsbpdtime <= steady_clock::now()) { /* Packet ready to play */ + w_tsbpdtime = tsbpdtime; + w_curpktseq = m_pUnit[i]->m_Packet.m_iSeqNo; if (haslost) + w_skipseqno = w_curpktseq; + + if (base_seq != SRT_SEQNO_NONE && CSeqNo::seqcmp(w_curpktseq, base_seq) <= 0) { - /* - * Packet stuck on non-acked side because of missing packets. - * Tell 1st valid packet seqno so caller can skip (drop) the missing packets. - */ - w_skipseqno = m_pUnit[i]->m_Packet.m_iSeqNo; - w_curpktseq = w_skipseqno; + HLOGC(brlog.Debug, + log << "getRcvFirstMsg: found ready packet %" << w_curpktseq + << " but not larger than base_seq, try next"); + continue; } HLOGC(brlog.Debug, @@ -1234,6 +1242,10 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, // ... return true; } + + if (!is_zero(w_tsbpdtime)) { + return true; + } HLOGC(brlog.Debug, log << "getRcvFirstMsg: found NOT READY packet, nSKIPPED: " << ((i - m_iLastAckPos + m_iSize) % m_iSize)); @@ -1246,6 +1258,9 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, // the 'haslost' is set, which means that it continues only to find the first valid // packet after stating that the very first packet isn't valid. } + if (!is_zero(w_tsbpdtime)) { + return true; + } HLOGC(brlog.Debug, log << "getRcvFirstMsg: found NO PACKETS"); return false; } @@ -1276,7 +1291,7 @@ int32_t CRcvBuffer::getTopMsgno() const return m_pUnit[m_iStartPos]->m_Packet.getMsgSeq(); } -bool CRcvBuffer::getRcvReadyMsg(steady_clock::time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto) +bool CRcvBuffer::getRcvReadyMsg(steady_clock::time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto, int base_seq) { const bool havelimit = upto != -1; int end = -1, past_end = -1; @@ -1342,7 +1357,8 @@ bool CRcvBuffer::getRcvReadyMsg(steady_clock::time_point& w_tsbpdtime, int32_t& // 1. Get the TSBPD time of the unit. Stop and return false if this unit // is not yet ready to play. // 2. If it's ready to play, check also if it's decrypted. If not, skip it. - // 3. If it's ready to play and decrypted, stop and return it. + // 3. Check also if it's larger than base_seq, if not, skip it. + // 4. If it's ready to play, decrypted and larger than base, stop and return it. if (!havelimit) { w_tsbpdtime = getPktTsbPdTime(m_pUnit[i]->m_Packet.getMsgTimeStamp()); @@ -1361,6 +1377,12 @@ bool CRcvBuffer::getRcvReadyMsg(steady_clock::time_point& w_tsbpdtime, int32_t& IF_HEAVY_LOGGING(reason = "DECRYPTION FAILED"); freeunit = true; /* packet not decrypted */ } + else if (base_seq != SRT_SEQNO_NONE && CSeqNo::seqcmp(w_curpktseq, base_seq) <= 0) + { + IF_HEAVY_LOGGING(reason = "smaller than base_seq"); + w_tsbpdtime = steady_clock::time_point(); + freeunit = true; + } else { HLOGC(brlog.Debug, @@ -1415,7 +1437,7 @@ bool CRcvBuffer::getRcvReadyMsg(steady_clock::time_point& w_tsbpdtime, int32_t& if (freeunit) { - HLOGC(brlog.Debug, log << "getRcvReadyMsg: POS=" << i << " FREED"); + HLOGC(brlog.Debug, log << "getRcvReadyMsg: POS=" << i << " FREED: " << reason); /* removed skipped, dropped, undecryptable bytes from rcv buffer */ const int rmbytes = (int)m_pUnit[i]->m_Packet.getLength(); countBytes(-1, -rmbytes, true); diff --git a/srtcore/buffer.h b/srtcore/buffer.h index f69bef1d9..9bf02f216 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -430,11 +430,17 @@ class CRcvBuffer /// @param [out] w_passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app) /// @param [out] w_skipseqno SRT_SEQNO_NONE or seq number of 1st unacknowledged pkt ready to play preceeded by /// missing packets. + /// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base if exist packet ready-to-play + /// and larger than base /// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true /// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE: /// IF skipseqno != SRT_SEQNO_NONE, packet ready to play preceeded by missing packets.; /// IF skipseqno == SRT_SEQNO_NONE, no missing packet but 1st not ready to play. - bool getRcvFirstMsg(time_point& w_tsbpdtime, bool& w_passack, int32_t& w_skipseqno, int32_t& w_curpktseq); + bool getRcvFirstMsg(time_point& w_tsbpdtime, + bool& w_passack, + int32_t& w_skipseqno, + int32_t& w_curpktseq, + int32_t base_seq = SRT_SEQNO_NONE); /// Update the ACK point of the buffer. /// @param [in] len size of data to be skip & acknowledged. @@ -473,9 +479,10 @@ class CRcvBuffer /// Parameters (of the 1st packet queue, ready to play or not): /// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if /// none + /// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base /// @retval true 1st packet ready to play without discontinuity (no hole) /// @retval false tsbpdtime = 0: no packet ready to play - bool getRcvReadyMsg(time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto); + bool getRcvReadyMsg(time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto, int base_seq = SRT_SEQNO_NONE); public: /// @brief Get clock drift in microseconds. diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 17611191e..7a337cf41 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -5161,8 +5161,17 @@ void * srt::CUDT::tsbpd(void *param) int32_t current_pkt_seq = 0; steady_clock::time_point tsbpdtime; bool rxready = false; + int32_t rcv_base_seq = SRT_SEQNO_NONE; #if ENABLE_EXPERIMENTAL_BONDING bool shall_update_group = false; + if (gkeeper.group) + { + // Functions called below will lock m_GroupLock, which in hierarchy + // lies after m_RecvLock. Must unlock m_RecvLock to be able to lock + // m_GroupLock inside the calls. + InvertedLock unrecv(self->m_RecvLock); + rcv_base_seq = gkeeper.group->getRcvBaseSeqNo(); + } #endif enterCS(self->m_RcvBufferLock); @@ -5174,7 +5183,7 @@ void * srt::CUDT::tsbpd(void *param) int32_t skiptoseqno = SRT_SEQNO_NONE; bool passack = true; // Get next packet to wait for even if not acked - rxready = self->m_pRcvBuffer->getRcvFirstMsg((tsbpdtime), (passack), (skiptoseqno), (current_pkt_seq)); + rxready = self->m_pRcvBuffer->getRcvFirstMsg((tsbpdtime), (passack), (skiptoseqno), (current_pkt_seq), rcv_base_seq); HLOGC(tslog.Debug, log << boolalpha << "NEXT PKT CHECK: rdy=" << rxready << " passack=" << passack << " skipto=%" diff --git a/srtcore/group.cpp b/srtcore/group.cpp index 854508ef4..a0be7dd72 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -2134,6 +2134,12 @@ void CUDTGroup::updateReadState(SRTSOCKET /* not sure if needed */, int32_t sequ } } +int32_t CUDTGroup::getRcvBaseSeqNo() +{ + ScopedLock lg(m_GroupLock); + return m_RcvBaseSeqNo; +} + void CUDTGroup::updateWriteState() { ScopedLock lg(m_GroupLock); diff --git a/srtcore/group.h b/srtcore/group.h index 549900370..e4b2fb6ed 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -345,6 +345,7 @@ class CUDTGroup void updateWriteState(); void updateFailedLink(); void activateUpdateEvent(bool still_have_items); + int32_t getRcvBaseSeqNo(); /// Update the in-group array of packet providers per sequence number. /// Also basing on the information already provided by possibly other sockets, From b4a5887964d1a56df57b7f45beb77c7e1fea51bd Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Wed, 2 Jun 2021 16:19:16 +0800 Subject: [PATCH 024/124] [build] Added compile_commands.json to .gitignore (#2031) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 10f985468..699d0e1b4 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ _*/ # Ignore vcpkg submodule vcpkg/ + +# LSP +compile_commands.json From d6e8e213c0b374444bb5f0c04fda54197869b655 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Thu, 3 Jun 2021 11:15:12 +0800 Subject: [PATCH 025/124] [core] Fix build error when -DSRT_DEBUG_TRACE_DRIFT=1 --- srtcore/tsbpd_time.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp index 8fedf82ea..ff01f8a30 100644 --- a/srtcore/tsbpd_time.cpp +++ b/srtcore/tsbpd_time.cpp @@ -22,7 +22,7 @@ namespace srt #if SRT_DEBUG_TRACE_DRIFT class drift_logger { - using steady_clock = srt::sync::steady_clock; + typedef srt::sync::steady_clock steady_clock; public: drift_logger() {} @@ -33,12 +33,12 @@ class drift_logger m_fout.close(); } - void trace(unsigned ackack_timestamp, - int rtt_us, - int64_t drift_sample, - int64_t drift, - int64_t overdrift, - const std::chrono::steady_clock::time_point& tsbpd_base) + void trace(unsigned ackack_timestamp, + int rtt_us, + int64_t drift_sample, + int64_t drift, + int64_t overdrift, + const srt::sync::steady_clock::time_point& tsbpd_base) { using namespace srt::sync; ScopedLock lck(m_mtx); From acf38a72586cf50e94e6ff8c20344eb14067caa3 Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Thu, 3 Jun 2021 16:04:06 +0800 Subject: [PATCH 026/124] [core] Fixed skip non-empty data (#2033) --- srtcore/buffer.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index b63439580..e2eb4f406 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -1169,10 +1169,11 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, * No acked packets ready but caller want to know next packet to wait for * Check the not yet acked packets that may be stuck by missing packet(s). */ - bool haslost = false; - steady_clock::time_point tsbpdtime = steady_clock::time_point(); - w_tsbpdtime = steady_clock::time_point(); - w_passack = true; + bool haslost = false; + int last_ready_pos = -1; + steady_clock::time_point tsbpdtime = steady_clock::time_point(); + w_tsbpdtime = steady_clock::time_point(); + w_passack = true; // XXX SUSPECTED ISSUE with this algorithm: // The above call to getRcvReadyMsg() should report as to whether: @@ -1215,11 +1216,20 @@ bool CRcvBuffer::getRcvFirstMsg(steady_clock::time_point& w_tsbpdtime, else { tsbpdtime = getPktTsbPdTime(m_pUnit[i]->m_Packet.getMsgTimeStamp()); + /* Packet ready to play */ if (tsbpdtime <= steady_clock::now()) { - /* Packet ready to play */ - w_tsbpdtime = tsbpdtime; - w_curpktseq = m_pUnit[i]->m_Packet.m_iSeqNo; + // If the last ready-to-play packet exists, free it. + if (!is_zero(w_tsbpdtime)) { + HLOGC(brlog.Debug, + log << "getRcvFirstMsg: found next ready packet, free last %" + << w_curpktseq << " POS=" << last_ready_pos); + SRT_ASSERT(w_curpktseq != SRT_SEQNO_NONE); + freeUnitAt(last_ready_pos); + } + w_tsbpdtime = tsbpdtime; + w_curpktseq = m_pUnit[i]->m_Packet.m_iSeqNo; + last_ready_pos = i; if (haslost) w_skipseqno = w_curpktseq; From 5205c3cc0edeef78c3737f3c02eafad14fe1f122 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 4 Jun 2021 09:45:23 +0200 Subject: [PATCH 027/124] [docs] Edits of the requirements in ReadMe.md (#2035) --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1c9aff2d8..e0403c4df 100644 --- a/README.md +++ b/README.md @@ -45,12 +45,15 @@ As audio/video packets are streamed from a source to a destination device, SRT d ## Requirements -* cmake (as build system) -* Tcl 8.5 (optional for user-friendly build system) -* OpenSSL -* Pthreads (for POSIX systems it's builtin, for Windows there's a library) - -For detailed description of the build system and options, please read [SRT Build Options](docs/build/build-options.md). +* C++03 (or above) compliant compiler. +* CMake 2.8.12 or above (as build system). +* OpenSSL 1.1 (to enable encryption, or build with `-DENABLE_ENCRYPTION=OFF`). +* Multithreading is provided by either of the following: + * C++11: standard library (`std` by `-DENABLE_STDCXX_SYNC=ON` CMake option); + * C++03: Pthreads (for POSIX systems it's built in, for Windows there is a ported library). +* Tcl 8.5 (optional, used by `./configure` script or use CMake directly). + +For a detailed description of the build system and options, please refer to [SRT Build Options](docs/build/build-options.md). ### Build on Linux From e761745eaf8c2d1a371d1a3043f0de8c449e4f95 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Mon, 7 Jun 2021 15:39:34 +0200 Subject: [PATCH 028/124] [tests] Added fixes for FEC test occasional failure (#2037) --- test/test_fec_rebuilding.cpp | 56 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp index 8ea7ea26b..17f7cfbc9 100644 --- a/test/test_fec_rebuilding.cpp +++ b/test/test_fec_rebuilding.cpp @@ -297,7 +297,7 @@ TEST(TestFEC, Connection) ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1); ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1); - + srt_listen(l, 1); auto connect_res = std::async(std::launch::async, [&s, &sa]() { @@ -305,19 +305,21 @@ TEST(TestFEC, Connection) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + // Given 2s timeout for accepting as it has occasionally happened with Travis + // that 1s might not be enough. + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; - srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); - srt_getsockflag(a, SRTO_PACKETFILTER, result_config2, &result_config2_size); + EXPECT_NE(srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size), -1); + EXPECT_NE(srt_getsockflag(a, SRTO_PACKETFILTER, result_config2, &result_config2_size), -1); string caller_config = result_config1; string accept_config = result_config2; @@ -358,15 +360,15 @@ TEST(TestFEC, ConnectionReorder) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); @@ -411,15 +413,15 @@ TEST(TestFEC, ConnectionFull1) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); @@ -463,15 +465,15 @@ TEST(TestFEC, ConnectionFull2) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); @@ -516,15 +518,15 @@ TEST(TestFEC, ConnectionMess) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); @@ -567,15 +569,15 @@ TEST(TestFEC, ConnectionForced) }); SRTSOCKET la[] = { l }; - SRTSOCKET a = srt_accept_bond(la, 1, 1000); - EXPECT_NE(a, SRT_ERROR); + SRTSOCKET a = srt_accept_bond(la, 1, 2000); + ASSERT_NE(a, SRT_ERROR); EXPECT_EQ(connect_res.get(), SRT_SUCCESS); // Now that the connection is established, check negotiated config - char result_config1[200]; + char result_config1[200] = ""; int result_config1_size = 200; - char result_config2[200]; + char result_config2[200] = ""; int result_config2_size = 200; srt_getsockflag(s, SRTO_PACKETFILTER, result_config1, &result_config1_size); From e63b3580cbca5e7b73e172b371cb822477b84d09 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 11 Jun 2021 19:30:43 +0200 Subject: [PATCH 029/124] [apps] Output json stats values as numbers --- apps/apputil.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/apputil.cpp b/apps/apputil.cpp index 0333c768f..bf808a95d 100644 --- a/apps/apputil.cpp +++ b/apps/apputil.cpp @@ -484,7 +484,6 @@ class SrtStatsJson : public SrtStatsWriter string WriteStats(int sid, const CBytePerfMon& mon) override { std::ostringstream output; - static const string qt = R"(")"; string pretty_cr, pretty_tab; if (Option("pretty")) @@ -540,9 +539,7 @@ class SrtStatsJson : public SrtStatsWriter // Print the current field output << quotekey(i->name); - output << qt; i->PrintValue(output, mon); - output << qt; } // Close the previous subcategory From 16eca6b404a697c705ab7d37af9ea852cd77936e Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Wed, 16 Jun 2021 18:59:13 +0200 Subject: [PATCH 030/124] [docs] Wrong error code for srt_accept_bond when timed out (#2040) --- docs/API/API-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API/API-functions.md b/docs/API/API-functions.md index 5a1fffd70..d59ce481e 100644 --- a/docs/API/API-functions.md +++ b/docs/API/API-functions.md @@ -646,7 +646,7 @@ calling this function. | [`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_EASYNCRCV`](#srt_easyncrcv) | No connection reported on any listener socket as the timeout has been reached. This error is only
reported when `msTimeOut` is not -1 | +| [`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 | | | | From 8c4f288a5ef2b737e83bd77940dc9794c0e82a53 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Thu, 17 Jun 2021 15:56:30 +0200 Subject: [PATCH 031/124] [apps] Refactored app support components to make them more reusable (#2042) * Extracted componentable parts from srt-test-relay * Fixed: VerbLock is in use by testactivemedia --- apps/apputil.hpp | 15 ++ apps/logsupport.cpp | 31 +++ apps/logsupport.hpp | 2 + apps/verbose.hpp | 18 ++ testing/srt-test-live.cpp | 31 --- testing/srt-test-relay.cpp | 326 ++--------------------------- testing/srt-test-relay.maf | 1 + testing/testactivemedia.cpp | 120 +++++++++++ testing/testactivemedia.hpp | 188 +++++++++++++++++ testing/testmedia.cpp | 395 ++++++++++++++++-------------------- testing/testmedia.hpp | 53 ++++- testing/testmediabase.hpp | 4 +- 12 files changed, 630 insertions(+), 554 deletions(-) create mode 100644 testing/testactivemedia.cpp create mode 100644 testing/testactivemedia.hpp diff --git a/apps/apputil.hpp b/apps/apputil.hpp index f7bf83df3..4f2b84bf7 100644 --- a/apps/apputil.hpp +++ b/apps/apputil.hpp @@ -90,6 +90,21 @@ const int SysAGAIN = EAGAIN; 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) { diff --git a/apps/logsupport.cpp b/apps/logsupport.cpp index 2acbf64cc..fbd70c47e 100644 --- a/apps/logsupport.cpp +++ b/apps/logsupport.cpp @@ -171,4 +171,35 @@ set SrtParseLogFA(string fa, set* punknown) 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); +} + diff --git a/apps/logsupport.hpp b/apps/logsupport.hpp index 63e732560..79115d726 100644 --- a/apps/logsupport.hpp +++ b/apps/logsupport.hpp @@ -13,11 +13,13 @@ #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; diff --git a/apps/verbose.hpp b/apps/verbose.hpp index ec0276c12..10591888b 100644 --- a/apps/verbose.hpp +++ b/apps/verbose.hpp @@ -74,11 +74,29 @@ class ErrLog: public Log } }; +// 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...); +} + + // Manipulator tags static const Verbose::LogNoEol VerbNoEOL; #if SRT_ENABLE_VERBOSE_LOCK diff --git a/testing/srt-test-live.cpp b/testing/srt-test-live.cpp index 5977b52b7..5bac09d78 100644 --- a/testing/srt-test-live.cpp +++ b/testing/srt-test-live.cpp @@ -378,37 +378,6 @@ extern "C" int SrtRejectByCodeHook(void* op, SRTSOCKET acpsock, int , const sock return -1; } -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); -} - int main( int argc, char** argv ) { // This is mainly required on Windows to initialize the network system, diff --git a/testing/srt-test-relay.cpp b/testing/srt-test-relay.cpp index 141bb8e83..1214125b7 100755 --- a/testing/srt-test-relay.cpp +++ b/testing/srt-test-relay.cpp @@ -15,6 +15,7 @@ written by #include "platform_sys.h" +#include #include #include #include @@ -32,6 +33,8 @@ written by #include #include +#include "testactivemedia.hpp" + #include "apputil.hpp" #include "uriparser.hpp" #include "logsupport.hpp" @@ -41,13 +44,15 @@ written by #include "testmedia.hpp" #include "threadname.h" + + + bool Upload(UriParser& srt, UriParser& file); bool Download(UriParser& srt, UriParser& file); srt_logging::Logger applog(SRT_LOGFA_APP, srt_logger_config, "srt-relay"); -volatile bool g_program_interrupted = false; -volatile bool g_program_established = false; +std::atomic g_program_established {false}; SrtModel* g_pending_model = nullptr; @@ -56,7 +61,7 @@ thread::id g_root_thread = std::this_thread::get_id(); static void OnINT_SetInterrupted(int) { Verb() << VerbLock << "SIGINT: Setting interrupt state."; - ::g_program_interrupted = true; + ::transmit_int_state = true; // Just for a case, forcefully close all active SRT sockets. SrtModel* pm = ::g_pending_model; @@ -83,168 +88,10 @@ static void OnINT_SetInterrupted(int) using namespace std; -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); } - -template -struct Medium -{ - class SrtMainLoop* master = nullptr; - MediumDir* med = nullptr; - unique_ptr pinned_med; - list buffer; - mutex buffer_lock; - thread thr; - condition_variable ready; - volatile bool running = false; - std::exception_ptr xp; // To catch exception thrown by a thread - - virtual void Runner() = 0; - - void RunnerBase() - { - try - { - Runner(); - } - catch (...) - { - xp = std::current_exception(); - } - - //Verb() << "Medium: " << this << ": thread exit"; - unique_lock g(buffer_lock); - running = false; - ready.notify_all(); - //Verb() << VerbLock << "Medium: EXIT NOTIFIED"; - } - - void run() - { - running = true; - std::ostringstream tns; - tns << typeid(*this).name() << ":" << this; - ThreadName tn(tns.str().c_str()); - thr = thread( [this] { RunnerBase(); } ); - } - - void quit() - { - if (!med) - return; - - applog.Debug() << "Medium(" << typeid(*med).name() << ") quit. Buffer contains " << buffer.size() << " blocks"; - - string name; - if (Verbose::on) - name = typeid(*med).name(); - - med->Close(); - if (thr.joinable()) - { - applog.Debug() << "Medium::quit: Joining medium thread (" << name << ") ..."; - thr.join(); - applog.Debug() << "... done"; - } - - if (xp) - { - try { - std::rethrow_exception(xp); - } catch (TransmissionError& e) { - if (Verbose::on) - Verb() << VerbLock << "Medium " << this << " exited with Transmission Error:\n\t" << e.what(); - else - cerr << "Transmission Error: " << e.what() << endl; - } catch (...) { - if (Verbose::on) - Verb() << VerbLock << "Medium " << this << " exited with UNKNOWN EXCEPTION:"; - else - cerr << "UNKNOWN EXCEPTION on medium\n"; - } - } - - // Prevent further quits from running - med = nullptr; - } - - void Setup(SrtMainLoop* mst, MediumDir* t) - { - med = t; - master = mst; - // Leave pinned_med as 0 - } - - void Setup(SrtMainLoop* mst, unique_ptr&& medbase) - { - pinned_med = move(medbase); - med = pinned_med.get(); - master = mst; - } - - virtual ~Medium() - { - //Verb() << "Medium: " << this << " DESTROYED. Threads quit."; - quit(); - } -}; - size_t g_chunksize = 0; size_t g_default_live_chunksize = 1316; size_t g_default_file_chunksize = 1456; -struct SourceMedium: Medium -{ - // Source Runner: read payloads and put on the buffer - void Runner() override; - - // External user: call this to get the buffer. - MediaPacket Extract(); -}; - -struct TargetMedium: Medium -{ - void Runner() override; - - bool Schedule(const MediaPacket& data) - { - lock_guard lg(buffer_lock); - if (!running || ::g_program_interrupted) - return false; - - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): [" << data.payload.size() << "] CLIENT -> BUFFER"; - buffer.push_back(data); - ready.notify_one(); - return true; - } - - void Interrupt() - { - lock_guard lg(buffer_lock); - running = false; - ready.notify_one(); - } - - ~TargetMedium() - { - //Verb() << "TargetMedium: DESTROYING"; - Interrupt(); - // ~Medium will do quit() additionally, which joins the thread - } - -}; - class SrtMainLoop { UriParser m_srtspec; @@ -275,140 +122,6 @@ class SrtMainLoop } }; - -void SourceMedium::Runner() -{ - ThreadName::set("SourceRN"); - if (!master) - { - cerr << "IPE: incorrect setup, master empty\n"; - return; - } - - /* Don't stop me now... - struct OnReturn - { - SrtMainLoop* m; - OnReturn(SrtMainLoop* mst): m(mst) {} - ~OnReturn() - { - m->MakeStop(); - } - } on_return(master); - */ - - Verb() << VerbLock << "Starting SourceMedium: " << this; - for (;;) - { - auto input = med->Read(g_chunksize); - if (input.payload.empty() && med->End()) - { - Verb() << VerbLock << "Exiting SourceMedium: " << this; - return; - } - applog.Debug() << "SourceMedium(" << typeid(*med).name() << "): [" << input.payload.size() << "] MEDIUM -> BUFFER. signal(" << &ready << ")"; - - lock_guard g(buffer_lock); - buffer.push_back(input); - ready.notify_one(); - } -} - -MediaPacket SourceMedium::Extract() -{ - if (!master) - return {}; - - unique_lock g(buffer_lock); - for (;;) - { - if (!buffer.empty()) - { - MediaPacket top; - swap(top, *buffer.begin()); - buffer.pop_front(); - applog.Debug() << "SourceMedium(" << typeid(*med).name() << "): [" << top.payload.size() << "] BUFFER -> CLIENT"; - return top; - } - else - { - // Don't worry about the media status as long as you have somthing in the buffer. - // Purge the buffer first, then worry about the other things. - if (!running || ::g_program_interrupted) - { - applog.Debug() << "Extract(" << typeid(*med).name() << "): INTERRUPTED READING (" - << (!running ? "local" : (!master->IsRunning() ? "master" : "unknown")) << ")"; - //Verb() << "SourceMedium " << this << " not running"; - return {}; - } - - } - - // Block until ready - applog.Debug() << "Extract(" << typeid(*med).name() << "): " << this << " wait(" << &ready << ") -->"; - ready.wait_for(g, chrono::seconds(1), [this] { return running && master->IsRunning() && !buffer.empty(); }); - applog.Debug() << "Extract(" << typeid(*med).name() << "): " << this << " <-- notified (running:" - << boolalpha << running << " master:" << master->IsRunning() << " buffer:" << buffer.size() << ")"; - } -} - -void TargetMedium::Runner() -{ - ThreadName::set("TargetRN"); - auto on_return_set = OnReturnSet(running, false); - Verb() << VerbLock << "Starting TargetMedium: " << this; - for (;;) - { - MediaPacket val; - { - unique_lock lg(buffer_lock); - if (buffer.empty()) - { - if (!running) - { - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): buffer empty, medium stopped, exiting."; - return; - } - - bool gotsomething = ready.wait_for(lg, chrono::seconds(1), [this] { return !running || !buffer.empty(); } ); - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): [" << val.payload.size() << "] BUFFER update (timeout:" - << boolalpha << gotsomething << " running: " << running << ")"; - if (::g_program_interrupted || !running || !med || med->Broken()) - { - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): buffer empty, medium " - << (!::g_program_interrupted ? - (running ? - (med ? - (med->Broken() ? "broken" : "UNKNOWN") - : "deleted") - : "stopped") - : "killed"); - return; - } - if (!gotsomething) // exit on timeout - continue; - } - swap(val, *buffer.begin()); - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): [" << val.payload.size() << "] BUFFER extraction"; - - buffer.pop_front(); - } - - // Check before writing - if (med->Broken()) - { - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): [" << val.payload.size() << "] BUFFER -> DISCARDED (medium broken)"; - running = false; - return; - } - - applog.Debug() << "TargetMedium(" << typeid(*med).name() << "): [" << val.payload.size() << "] BUFFER -> MEDIUM"; - // You get the data to send, send them. - med->Write(val); - } -} - - int main( int argc, char** argv ) { OptionName @@ -605,7 +318,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin { Verb() << "Setting up output: " << spec; unique_ptr m { new TargetMedium }; - m->Setup(this, Target::Create(spec)); + m->Setup(Target::Create(spec)); m_output_media.push_back(move(m)); } @@ -631,14 +344,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin Verb() << "... Established. configuring other pipes:"; // Once it's ready, use it to initialize the medium. - - m_srt_relay.reset(new SrtRelay); - m_srt_relay->StealFrom(m); - - m_srt_source.Setup(this, m_srt_relay.get()); - bool file_mode = (transtype == "file"); - if (g_chunksize == 0) { if (file_mode) @@ -649,6 +355,11 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin Verb() << "DEFAULT CHUNKSIZE used: " << g_chunksize; } + m_srt_relay.reset(new SrtRelay); + m_srt_relay->StealFrom(m); + + m_srt_source.Setup(m_srt_relay.get(), g_chunksize); + // Now check the input medium if (input_echoback) { @@ -656,7 +367,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin // Add SRT medium to output targets, and keep input medium empty. unique_ptr m { new TargetMedium }; - m->Setup(this, m_srt_relay.get()); + m->Setup(m_srt_relay.get()); m_output_media.push_back(move(m)); } else @@ -665,7 +376,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin // to the output list, as this will be fed directly // by the data from this input medium in a spearate engine. Verb() << "Setting up input: " << input_spec; - m_input_medium.Setup(this, Source::Create(input_spec)); + m_input_medium.Setup(Source::Create(input_spec), g_chunksize); if (!file_mode) { @@ -796,6 +507,11 @@ void SrtMainLoop::run() } Verb() << "MEDIA LOOP EXIT"; + for (auto& m : m_output_media) + { + m->quit(); + } + m_input_medium.quit(); m_srt_source.quit(); if (m_input_xp) diff --git a/testing/srt-test-relay.maf b/testing/srt-test-relay.maf index b1b22afb2..33cba8173 100644 --- a/testing/srt-test-relay.maf +++ b/testing/srt-test-relay.maf @@ -3,6 +3,7 @@ SOURCES srt-test-relay.cpp testmedia.cpp +testactivemedia.cpp ../apps/apputil.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp diff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp new file mode 100644 index 000000000..765d22ef6 --- /dev/null +++ b/testing/testactivemedia.cpp @@ -0,0 +1,120 @@ + +#include "testactivemedia.hpp" + +void SourceMedium::Runner() +{ + ThreadName::set("SourceRN"); + + Verb() << VerbLock << "Starting SourceMedium: " << this; + for (;;) + { + auto input = med->Read(chunksize_); + if (input.payload.empty() && med->End()) + { + Verb() << VerbLock << "Exiting SourceMedium: " << this; + return; + } + LOGP(applog.Debug, "SourceMedium(", typeid(*med).name(), "): [", input.payload.size(), "] MEDIUM -> BUFFER. signal(", &ready, ")"); + + lock_guard g(buffer_lock); + buffer.push_back(input); + ready.notify_one(); + } +} + +MediaPacket SourceMedium::Extract() +{ + unique_lock g(buffer_lock); + for (;;) + { + if (::transmit_int_state) + running = false; + + if (!buffer.empty()) + { + MediaPacket top; + swap(top, *buffer.begin()); + buffer.pop_front(); + LOGP(applog.Debug, "SourceMedium(", typeid(*med).name(), "): [", top.payload.size(), "] BUFFER -> CLIENT"); + return top; + } + else + { + // Don't worry about the media status as long as you have somthing in the buffer. + // Purge the buffer first, then worry about the other things. + if (!running) + { + //LOGP(applog.Debug, "Extract(", typeid(*med).name(), "): INTERRUPTED READING"); + //Verb() << "SourceMedium " << this << " not running"; + return {}; + } + + } + + // Block until ready + //LOGP(applog.Debug, "Extract(", typeid(*med).name(), "): ", this, " wait(", &ready, ") -->"); + + ready.wait_for(g, chrono::seconds(1), [this] { return running && !buffer.empty(); }); + + // LOGP(applog.Debug, "Extract(", typeid(*med).name(), "): ", this, " <-- notified (running:" + // << boolalpha << running << " buffer:" << buffer.size() << ")"); + } +} + +void TargetMedium::Runner() +{ + ThreadName::set("TargetRN"); + auto on_return_set = OnReturnSet(running, false); + Verb() << VerbLock << "Starting TargetMedium: " << this; + for (;;) + { + MediaPacket val; + { + unique_lock lg(buffer_lock); + if (buffer.empty()) + { + if (!running) + { + //LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): buffer empty, medium stopped, exiting."); + return; + } + + bool gotsomething = ready.wait_for(lg, chrono::seconds(1), [this] { return !running || !buffer.empty(); } ); + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): [", val.payload.size(), "] BUFFER update (timeout:", + boolalpha, gotsomething, " running: ", running, ")"); + if (::transmit_int_state || !running || !med || med->Broken()) + { + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): buffer empty, medium ", + (!::transmit_int_state ? + (running ? + (med ? + (med->Broken() ? "broken" : "UNKNOWN") + : "deleted") + : "stopped") + : "killed")); + return; + } + if (!gotsomething) // exit on timeout + continue; + } + swap(val, *buffer.begin()); + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): [", val.payload.size(), "] BUFFER extraction"); + + buffer.pop_front(); + } + + // Check before writing + if (med->Broken()) + { + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): [", val.payload.size(), "] BUFFER -> DISCARDED (medium broken)"); + running = false; + return; + } + + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): [", val.payload.size(), "] BUFFER -> MEDIUM"); + // You get the data to send, send them. + med->Write(val); + } +} + + diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp new file mode 100644 index 000000000..b94ff9aa3 --- /dev/null +++ b/testing/testactivemedia.hpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "testmedia.hpp" +#include "logsupport.hpp" + +#define SRT_ENABLE_VERBOSE_LOCK 1 +#include "verbose.hpp" + +#include "logging.h" +#include "threadname.h" + +extern srt_logging::Logger applog; + +template +struct Medium +{ + MediumDir* med = nullptr; + std::unique_ptr pinned_med; + std::list buffer; + std::mutex buffer_lock; + std::thread thr; + std::condition_variable ready; + std::atomic running {false}; + std::exception_ptr xp; // To catch exception thrown by a thread + + virtual void Runner() = 0; + + void RunnerBase() + { + try + { + running = true; + Runner(); + } + catch (...) + { + xp = std::current_exception(); + } + + //Verb() << "Medium: " << this << ": thread exit"; + std::unique_lock g(buffer_lock); + running = false; + ready.notify_all(); + //Verb() << VerbLock << "Medium: EXIT NOTIFIED"; + } + + void run() + { + running = true; + std::ostringstream tns; + tns << typeid(*this).name() << ":" << this; + ThreadName tn(tns.str().c_str()); + thr = thread( [this] { RunnerBase(); } ); + } + + void quit() + { + if (!med) + return; + + LOGP(applog.Debug, "Medium(", typeid(*med).name(), ") quit. Buffer contains ", buffer.size(), " blocks"); + + std::string name; + if (Verbose::on) + name = typeid(*med).name(); + + med->Close(); + if (thr.joinable()) + { + LOGP(applog.Debug, "Medium::quit: Joining medium thread (", name, ") ..."); + thr.join(); + LOGP(applog.Debug, "... done"); + } + + if (xp) + { + try { + std::rethrow_exception(xp); + } catch (TransmissionError& e) { + if (Verbose::on) + Verb() << VerbLock << "Medium " << this << " exited with Transmission Error:\n\t" << e.what(); + else + cerr << "Transmission Error: " << e.what() << endl; + } catch (...) { + if (Verbose::on) + Verb() << VerbLock << "Medium " << this << " exited with UNKNOWN EXCEPTION:"; + else + cerr << "UNKNOWN EXCEPTION on medium\n"; + } + } + + // Prevent further quits from running + med = nullptr; + } + + void Setup(MediumDir* t) + { + med = t; + // Leave pinned_med as 0 + } + + void Setup(std::unique_ptr&& medbase) + { + pinned_med = std::move(medbase); + med = pinned_med.get(); + } + + virtual ~Medium() + { + //Verb() << "Medium: " << this << " DESTROYED. Threads quit."; + quit(); + } + + virtual void Start() { run(); } + virtual void Stop() { quit(); } +}; + +struct SourceMedium: Medium +{ + size_t chunksize_ = 0; + typedef Medium Base; + + // Source Runner: read payloads and put on the buffer + void Runner() override; + + // External user: call this to get the buffer. + MediaPacket Extract(); + + template + void Setup(Arg&& medium, size_t chunksize) + { + chunksize_ = chunksize; + return Base::Setup(std::move(medium)); + } +}; + +struct TargetMedium: Medium +{ + void Runner() override; + + bool Schedule(const MediaPacket& data) + { + LOGP(applog.Debug, "TargetMedium::Schedule LOCK ... "); + lock_guard lg(buffer_lock); + LOGP(applog.Debug, "TargetMedium::Schedule LOCKED - checking: running=", running, " interrupt=", ::transmit_int_state); + if (!running || ::transmit_int_state) + { + LOGP(applog.Debug, "TargetMedium::Schedule: not running, discarding packet"); + return false; + } + + LOGP(applog.Debug, "TargetMedium(", typeid(*med).name(), "): Schedule: [", data.payload.size(), "] CLIENT -> BUFFER"); + buffer.push_back(data); + ready.notify_one(); + return true; + } + + void Clear() + { + lock_guard lg(buffer_lock); + buffer.clear(); + } + + void Interrupt() + { + lock_guard lg(buffer_lock); + running = false; + ready.notify_one(); + } + + ~TargetMedium() + { + //Verb() << "TargetMedium: DESTROYING"; + Interrupt(); + // ~Medium will do quit() additionally, which joins the thread + } +}; + + diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index 501e5f8d7..f986aa5dc 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #if !defined(_WIN32) #include @@ -48,8 +49,8 @@ using srt_logging::SockStatusStr; using srt_logging::MemberStatusStr; #endif -volatile bool transmit_throw_on_interrupt = false; -volatile bool transmit_int_state = false; +std::atomic transmit_throw_on_interrupt {false}; +std::atomic transmit_int_state {false}; int transmit_bw_report = 0; unsigned transmit_stats_report = 0; size_t transmit_chunk_size = SRT_LIVE_DEF_PLSIZE; @@ -2715,276 +2716,238 @@ static inline bool IsMulticast(in_addr adr) return c >= 224 && c <= 239; } - -class UdpCommon +void UdpCommon::Setup(string host, int port, map attr) { -protected: - int m_sock = -1; - sockaddr_any sadr; - string adapter; - map m_options; + m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (m_sock == -1) + Error(SysError(), "UdpCommon::Setup: socket"); - void Setup(string host, int port, map attr) - { - m_sock = 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); - int yes = 1; - ::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof yes); + sadr = CreateAddr(host, port); - sadr = CreateAddr(host, port); + bool is_multicast = false; + if (sadr.family() == AF_INET) + { + if (attr.count("multicast")) + { + 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 (IsMulticast(sadr.sin.sin_addr)) + { + is_multicast = true; + } - bool is_multicast = false; - if (sadr.family() == AF_INET) + if (is_multicast) { - if (attr.count("multicast")) + ip_mreq_source mreq_ssm; + ip_mreq mreq; + sockaddr_any maddr; + int opt_name; + void* mreq_arg_ptr; + socklen_t mreq_arg_size; + + adapter = attr.count("adapter") ? attr.at("adapter") : string(); + if (adapter == "") { - if (!IsMulticast(sadr.sin.sin_addr)) - { - throw std::runtime_error("UdpCommon: requested multicast for a non-multicast-type IP address"); - } - is_multicast = true; + 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 if (IsMulticast(sadr.sin.sin_addr)) + else { - is_multicast = true; + Verb() << "Multicast: home address: " << adapter << ":" << port; + maddr = CreateAddr(adapter, port); } - if (is_multicast) + if (attr.count("source")) { - ip_mreq_source mreq_ssm; - ip_mreq mreq; - sockaddr_any maddr; - 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")) - { - /* 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 - { - 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; - } + /* 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 + { + 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; + 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; + 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"; + // 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; + 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"); - } + int res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg, mreq_arg_size); - attr.erase("multicast"); - attr.erase("adapter"); + 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; + // 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"); - } + attr.erase("ttl"); + } - m_options = attr; + m_options = attr; - for (auto o: udp_options) + for (auto o: udp_options) + { + // Ignore "binding" - for UDP there are no post options. + if (m_options.count(o.name)) { - // 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; - } + 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); +void UdpCommon::Error(int err, string src) +{ + char buf[512]; + string message = SysStrError(err, buf, 512u); - if (Verbose::on) - Verb() << "FAILURE\n" << src << ": [" << err << "] " << message; - else - cerr << "\nERROR #" << err << ": " << message << endl; + if (Verbose::on) + Verb() << "FAILURE\n" << src << ": [" << err << "] " << message; + else + cerr << "\nERROR #" << err << ": " << message << endl; - throw TransmissionError("error: " + src + ": " + message); - } + throw TransmissionError("error: " + src + ": " + message); +} - ~UdpCommon() - { +UdpCommon::~UdpCommon() +{ #ifdef _WIN32 - if (m_sock != -1) - { - shutdown(m_sock, SD_BOTH); - closesocket(m_sock); - m_sock = -1; - } + if (m_sock != -1) + { + shutdown(m_sock, SD_BOTH); + closesocket(m_sock); + m_sock = -1; + } #else - close(m_sock); + close(m_sock); #endif - } -}; - +} -class UdpSource: public virtual Source, public virtual UdpCommon +UdpSource::UdpSource(string host, int port, const map& attr) { - bool eof = true; -public: + Setup(host, port, attr); + int stat = ::bind(m_sock, sadr.get(), sadr.size()); + if (stat == -1) + Error(SysError(), "Binding address for UDP"); + eof = false; + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (::setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv)) < 0) + Error(SysError(), "Setting timeout for UDP"); +} - UdpSource(string host, int port, const map& attr) +MediaPacket UdpSource::Read(size_t chunk) +{ + bytevector data(chunk); + sockaddr_any sa(sadr.family()); + int64_t srctime = 0; +AGAIN: + int stat = recvfrom(m_sock, data.data(), (int) chunk, 0, sa.get(), &sa.syslen()); + int err = SysError(); + if (transmit_use_sourcetime) { - Setup(host, port, attr); - int stat = ::bind(m_sock, sadr.get(), sadr.size()); - if (stat == -1) - Error(SysError(), "Binding address for UDP"); - eof = false; - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; - if (::setsockopt(m_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv, sizeof(tv)) < 0) - Error(SysError(), "Setting timeout for UDP"); + srctime = srt_time_now(); } - - MediaPacket Read(size_t chunk) override + if (stat == -1) { - bytevector data(chunk); - sockaddr_any sa(sadr.family()); - int64_t srctime = 0; -AGAIN: - int stat = recvfrom(m_sock, data.data(), (int) chunk, 0, sa.get(), &sa.syslen()); - int err = SysError(); - if (transmit_use_sourcetime) - { - srctime = srt_time_now(); - } - if (stat == -1) - { - if (!::transmit_int_state && err == SysAGAIN) - goto AGAIN; + if (!::transmit_int_state && err == SysAGAIN) + goto AGAIN; - Error(SysError(), "UDP Read/recvfrom"); - } - - if (stat < 1) - { - eof = true; - return bytevector(); - } - - chunk = size_t(stat); - if (chunk < data.size()) - data.resize(chunk); + Error(SysError(), "UDP Read/recvfrom"); + } - return MediaPacket(data, srctime); + if (stat < 1) + { + eof = true; + return bytevector(); } - bool IsOpen() override { return m_sock != -1; } - bool End() override { return eof; } -}; + chunk = size_t(stat); + if (chunk < data.size()) + data.resize(chunk); + + return MediaPacket(data, srctime); +} -class UdpTarget: public virtual Target, public virtual UdpCommon +UdpTarget::UdpTarget(string host, int port, const map& attr) { -public: - UdpTarget(string host, int port, const map& attr ) + Setup(host, port, attr); + if (adapter != "") { - Setup(host, port, attr); - if (adapter != "") - { - auto maddr = CreateAddr(adapter, 0); - in_addr addr = maddr.sin.sin_addr; + auto maddr = CreateAddr(adapter, 0); + 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 res = setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_IF, reinterpret_cast(&addr), sizeof(addr)); + if (res == -1) + { + Error(SysError(), "setsockopt/IP_MULTICAST_IF: " + adapter); } } +} - void Write(const MediaPacket& data) override - { - int stat = sendto(m_sock, data.payload.data(), data.payload.size(), 0, (sockaddr*)&sadr, sizeof sadr); - if (stat == -1) - Error(SysError(), "UDP Write/sendto"); - } - - bool IsOpen() override { return m_sock != -1; } - bool Broken() override { return false; } -}; - -class UdpRelay: public Relay, public UdpSource, public UdpTarget +void UdpTarget::Write(const MediaPacket& data) { -public: - UdpRelay(string host, int port, const map& attr): - UdpSource(host, port, attr), - UdpTarget(host, port, attr) - { - } + int stat = sendto(m_sock, data.payload.data(), data.payload.size(), 0, (sockaddr*)&sadr, sizeof sadr); + if (stat == -1) + Error(SysError(), "UDP Write/sendto"); +} - bool IsOpen() override { return m_sock != -1; } -}; template struct Udp; template <> struct Udp { typedef UdpSource type; }; diff --git a/testing/testmedia.hpp b/testing/testmedia.hpp index b251f140b..d3447a0d0 100644 --- a/testing/testmedia.hpp +++ b/testing/testmedia.hpp @@ -15,14 +15,16 @@ #include #include #include +#include +#include "apputil.hpp" #include "testmediabase.hpp" #include // Needs access to CUDTException #include extern srt_listen_callback_fn* transmit_accept_hook_fn; extern void* transmit_accept_hook_op; -extern volatile bool transmit_int_state; +extern std::atomic transmit_int_state; extern std::shared_ptr transmit_stats_writer; @@ -298,6 +300,55 @@ class SrtModel: public SrtCommon } }; +class UdpCommon +{ +protected: + int m_sock = -1; + sockaddr_any sadr; + std::string adapter; + std::map m_options; + void Setup(std::string host, int port, std::map attr); + void Error(int err, std::string src); + + ~UdpCommon(); +}; + + +class UdpSource: public virtual Source, public virtual UdpCommon +{ + bool eof = true; +public: + + UdpSource(string host, int port, const map& attr); + + MediaPacket Read(size_t chunk) override; + + bool IsOpen() override { return m_sock != -1; } + bool End() override { return eof; } +}; + +class UdpTarget: public virtual Target, public virtual UdpCommon +{ +public: + UdpTarget(string host, int port, const map& attr); + + void Write(const MediaPacket& data) override; + bool IsOpen() override { return m_sock != -1; } + bool Broken() override { return false; } +}; + +class UdpRelay: public Relay, public UdpSource, public UdpTarget +{ +public: + UdpRelay(string host, int port, const map& attr): + UdpSource(host, port, attr), + UdpTarget(host, port, attr) + { + } + + bool IsOpen() override { return m_sock != -1; } +}; + #endif diff --git a/testing/testmediabase.hpp b/testing/testmediabase.hpp index a04803e04..3eb16a4bb 100644 --- a/testing/testmediabase.hpp +++ b/testing/testmediabase.hpp @@ -17,8 +17,10 @@ #include #include +#include "uriparser.hpp" + typedef std::vector bytevector; -extern volatile bool transmit_throw_on_interrupt; +extern std::atomic transmit_throw_on_interrupt; extern int transmit_bw_report; extern unsigned transmit_stats_report; extern size_t transmit_chunk_size; From e932e8fbdda4a053023985a6f9c076cf09810e98 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 21 Jun 2021 17:48:48 +0200 Subject: [PATCH 032/124] [core] Fixed getTsbPdTimeBase: carryover within 2 wrapping periods (#2043) --- srtcore/tsbpd_time.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp index ff01f8a30..54a8c5df5 100644 --- a/srtcore/tsbpd_time.cpp +++ b/srtcore/tsbpd_time.cpp @@ -38,6 +38,7 @@ class drift_logger int64_t drift_sample, int64_t drift, int64_t overdrift, + const srt::sync::steady_clock::time_point& pkt_base, const srt::sync::steady_clock::time_point& tsbpd_base) { using namespace srt::sync; @@ -50,6 +51,9 @@ class drift_logger std::string str_tbase = srt::sync::FormatTime(tsbpd_base); str_tbase.resize(str_tbase.size() - 7); // remove trailing ' [STDY]' part + std::string str_pkt_base = srt::sync::FormatTime(pkt_base); + str_pkt_base.resize(str_pkt_base.size() - 7); // remove trailing ' [STDY]' part + // m_fout << str_tnow << ","; m_fout << count_microseconds(steady_clock::now() - m_start_time) << ","; m_fout << ackack_timestamp << ","; @@ -57,6 +61,7 @@ class drift_logger m_fout << drift_sample << ","; m_fout << drift << ","; m_fout << overdrift << ","; + m_fout << str_pkt_base << ","; m_fout << str_tbase << "\n"; m_fout.flush(); } @@ -65,7 +70,7 @@ class drift_logger void print_header() { m_fout << "usElapsedStd,usAckAckTimestampStd,"; - m_fout << "usRTTStd,usDriftSampleStd,usDriftStd,usOverdriftStd,TSBPDBase\n"; + m_fout << "usRTTStd,usDriftSampleStd,usDriftStd,usOverdriftStd,tsPktBase,TSBPDBase\n"; } void create_file() @@ -121,8 +126,9 @@ bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, // A change in network delay has to be taken into account. The only way to get some estimation of it // is to estimate RTT change and assume that the change of the one way network delay is // approximated by the half of the RTT change. - const duration tdRTTDelta = microseconds_from((usRTTSample - m_iFirstRTT) / 2); - const steady_clock::duration tdDrift = tsNow - getPktTsbPdBaseTime(usPktTimestamp) - tdRTTDelta; + const duration tdRTTDelta = microseconds_from((usRTTSample - m_iFirstRTT) / 2); + const time_point tsPktBaseTime = getPktTsbPdBaseTime(usPktTimestamp); + const steady_clock::duration tdDrift = tsNow - tsPktBaseTime - tdRTTDelta; const bool updated = m_DriftTracer.update(count_microseconds(tdDrift)); @@ -152,6 +158,7 @@ bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, count_microseconds(tdDrift), m_DriftTracer.drift(), m_DriftTracer.overdrift(), + tsPktBaseTime, m_tsTsbPdTimeBase); #endif return updated; @@ -168,7 +175,7 @@ void CTsbpdTime::setTsbPdMode(const steady_clock::time_point& timebase, bool wra // // This function is called in the HSREQ reception handler only. m_tsTsbPdTimeBase = timebase; - m_tdTsbPdDelay = delay; + m_tdTsbPdDelay = delay; } void CTsbpdTime::applyGroupTime(const steady_clock::time_point& timebase, @@ -210,8 +217,11 @@ void CTsbpdTime::applyGroupDrift(const steady_clock::time_point& timebase, CTsbpdTime::time_point CTsbpdTime::getTsbPdTimeBase(uint32_t timestamp_us) const { - const uint64_t carryover_us = - (m_bTsbPdWrapCheck && timestamp_us < TSBPD_WRAP_PERIOD) ? uint64_t(CPacket::MAX_TIMESTAMP) + 1 : 0; + // A data packet within [TSBPD_WRAP_PERIOD; 2 * TSBPD_WRAP_PERIOD] would end TSBPD wrap-aware state. + // Some incoming control packets may not update the TSBPD base (calling updateTsbPdTimeBase(..)), + // but may come before a data packet with a timestamp in this range. Therefore the whole range should be tracked. + const int64_t carryover_us = + (m_bTsbPdWrapCheck && timestamp_us <= 2 * TSBPD_WRAP_PERIOD) ? int64_t(CPacket::MAX_TIMESTAMP) + 1 : 0; return (m_tsTsbPdTimeBase + microseconds_from(carryover_us)); } @@ -243,14 +253,14 @@ void CTsbpdTime::updateTsbPdTimeBase(uint32_t usPktTimestamp) return; } - // Check if timestamp is in the last 30 seconds before reaching the MAX_TIMESTAMP. + // Check if timestamp is within the TSBPD_WRAP_PERIOD before reaching the MAX_TIMESTAMP. if (usPktTimestamp > (CPacket::MAX_TIMESTAMP - TSBPD_WRAP_PERIOD)) { // Approching wrap around point, start wrap check period (if for packet delivery head) m_bTsbPdWrapCheck = true; LOGC(tslog.Debug, - log << "tsbpd wrap period begins with ts=" << usPktTimestamp << " drift: " << m_DriftTracer.drift() - << "us."); + log << "tsbpd wrap period begins with ts=" << usPktTimestamp + << " TIME BASE: " << FormatTime(m_tsTsbPdTimeBase) << " drift: " << m_DriftTracer.drift() << "us."); } } From 94322d4081b45153b6c1fe7785d6973b472de497 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Fri, 2 Jul 2021 21:06:28 +0800 Subject: [PATCH 033/124] [core] Fix unused-variable warning --- srtcore/api.cpp | 2 +- srtcore/buffer.cpp | 4 ++-- srtcore/channel.cpp | 2 +- srtcore/core.cpp | 12 ++++++------ srtcore/crypto.cpp | 7 ++++--- srtcore/epoll.cpp | 4 ++-- srtcore/fec.cpp | 2 +- srtcore/group.cpp | 6 +++--- srtcore/logging.h | 4 ++-- srtcore/sync.h | 3 ++- srtcore/utilities.h | 7 +++---- test/test_listen_callback.cpp | 2 +- testing/testmedia.cpp | 2 +- 13 files changed, 29 insertions(+), 28 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index aee13f389..d38442590 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -1384,7 +1384,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i // Set all options that were requested by the options set on a group // prior to connecting. - string error_reason ATR_UNUSED; + string error_reason SRT_ATR_UNUSED; try { for (size_t i = 0; i < g.m_config.size(); ++i) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index e2eb4f406..bbe41b7f6 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -986,8 +986,8 @@ int CRcvBuffer::readBufferToFile(fstream& ofs, int len) int lastack = m_iLastAckPos; int rs = len; - int32_t trace_seq ATR_UNUSED = SRT_SEQNO_NONE; - int trace_shift ATR_UNUSED = -1; + int32_t trace_seq SRT_ATR_UNUSED = SRT_SEQNO_NONE; + int trace_shift SRT_ATR_UNUSED = -1; while ((p != lastack) && (rs > 0)) { diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 6e56e97f7..92fd6b991 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -183,7 +183,7 @@ void srt::CChannel::createSocket(int family) if ((m_mcfg.iIpV6Only != -1) && (family == AF_INET6)) // (not an error if it fails) { - const int res ATR_UNUSED = + const int res SRT_ATR_UNUSED = ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&m_mcfg.iIpV6Only, sizeof m_mcfg.iIpV6Only); #if ENABLE_LOGGING if (res == -1) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 7a337cf41..15a138a3a 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -2385,7 +2385,7 @@ int srt::CUDT::processSrtMsg_HSRSP(const uint32_t *srtdata, size_t bytelen, uint // This function is called only when the URQ_CONCLUSION handshake has been received from the peer. bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, const CPacket& hspkt, - uint32_t* out_data, + uint32_t* out_data SRT_ATR_UNUSED, size_t* pw_len) { // Initialize pw_len to 0 to handle the unencrypted case @@ -2440,7 +2440,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, uint32_t* p = reinterpret_cast(hspkt.m_pcData + CHandShake::m_iContentSize); size_t size = hspkt.getLength() - CHandShake::m_iContentSize; // Due to previous cond check we grant it's >0 - int hsreq_type_cmd ATR_UNUSED = SRT_CMD_NONE; + int hsreq_type_cmd SRT_ATR_UNUSED = SRT_CMD_NONE; if (IsSet(ext_flags, CHandShake::HS_EXT_HSREQ)) { @@ -2671,7 +2671,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs, m_config.sCongestion.set("live", 4); } - bool have_group ATR_UNUSED = false; + bool have_group SRT_ATR_UNUSED = false; if (IsSet(ext_flags, CHandShake::HS_EXT_CONFIG)) { @@ -7715,7 +7715,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) // IF ack %> m_iRcvLastAck if (CSeqNo::seqcmp(ack, m_iRcvLastAck) > 0) { - const int32_t first_seq ATR_UNUSED = ackDataUpTo(ack); + const int32_t first_seq SRT_ATR_UNUSED = ackDataUpTo(ack); InvertedLock un_bufflock (m_RcvBufferLock); #if ENABLE_EXPERIMENTAL_BONDING @@ -8318,7 +8318,7 @@ void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr { steady_clock::duration udrift(0); steady_clock::time_point newtimebase; - const bool drift_updated ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), + const bool drift_updated SRT_ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), rtt, (udrift), (newtimebase)); #if ENABLE_EXPERIMENTAL_BONDING if (drift_updated && m_parent->m_GroupOf) @@ -10795,7 +10795,7 @@ int srt::CUDT::checkNAKTimer(const steady_clock::time_point& currtime) return debug_decision; } -bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_reason ATR_UNUSED) +bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int check_reason SRT_ATR_UNUSED) { // VERY HEAVY LOGGING #if ENABLE_HEAVY_LOGGING & 1 diff --git a/srtcore/crypto.cpp b/srtcore/crypto.cpp index c7c27abab..6c482a586 100644 --- a/srtcore/crypto.cpp +++ b/srtcore/crypto.cpp @@ -43,7 +43,7 @@ using namespace srt_logging; */ // 10* HAICRYPT_DEF_KM_PRE_ANNOUNCE -const int SRT_CRYPT_KM_PRE_ANNOUNCE = 0x10000; +const int SRT_CRYPT_KM_PRE_ANNOUNCE SRT_ATR_UNUSED = 0x10000; namespace srt_logging { @@ -662,6 +662,8 @@ std::string CCryptoControl::CONID() const return os.str(); } +#ifdef SRT_ENABLE_ENCRYPTION + #if ENABLE_HEAVY_LOGGING static std::string CryptoFlags(int flg) { @@ -679,9 +681,8 @@ static std::string CryptoFlags(int flg) copy(f.begin(), f.end(), ostream_iterator(os, "|")); return os.str(); } -#endif +#endif // ENABLE_HEAVY_LOGGING -#ifdef SRT_ENABLE_ENCRYPTION bool CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir, HaiCrypt_Handle& w_hCrypto) { diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index 71945bdbd..548418f88 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -713,7 +713,7 @@ int CEPoll::wait(const int eid, set* readfds, set* writefd throw CUDTException(MJ_AGAIN, MN_XMTIMEOUT, 0); } - const bool wait_signaled ATR_UNUSED = CGlobEvent::waitForEvent(); + const bool wait_signaled SRT_ATR_UNUSED = CGlobEvent::waitForEvent(); HLOGC(ealog.Debug, log << "CEPoll::wait: EVENT WAITING: " << (wait_signaled ? "TRIGGERED" : "CHECKPOINT")); } @@ -779,7 +779,7 @@ int CEPoll::swait(CEPollDesc& d, map& st, int64_t msTimeOut, boo st[i->fd] = i->events; IF_HEAVY_LOGGING(singles << "@" << i->fd << ":"); IF_HEAVY_LOGGING(PrintEpollEvent(singles, i->events, i->parent->edgeOnly())); - const bool edged ATR_UNUSED = d.checkEdge(i++); // NOTE: potentially deletes `i` + const bool edged SRT_ATR_UNUSED = d.checkEdge(i++); // NOTE: potentially deletes `i` IF_HEAVY_LOGGING(singles << (edged ? "<^> " : " ")); } diff --git a/srtcore/fec.cpp b/srtcore/fec.cpp index 31239eed8..61adc0957 100644 --- a/srtcore/fec.cpp +++ b/srtcore/fec.cpp @@ -2029,7 +2029,7 @@ void FECFilterBuiltin::RcvCheckDismissColumn(int32_t seq, int colgx, loss_seqs_t any_dismiss = true; const int32_t newbase = rcv.colq[numberCols()].base; - int32_t newbase_row ATR_UNUSED; // For logging only, but including FATAL. + int32_t newbase_row SRT_ATR_UNUSED; // For logging only, but including FATAL. // Sanity check // If sanity check failed OR if the number of existing row // groups doesn't enclose those that need to be dismissed, diff --git a/srtcore/group.cpp b/srtcore/group.cpp index a0be7dd72..f2f99201b 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -3168,7 +3168,7 @@ CUDTGroup::BackupMemberState CUDTGroup::sendBackup_QualifyActiveState(const gli_ } // [[using locked(this->m_GroupLock)]] -bool CUDTGroup::sendBackup_CheckSendStatus(const steady_clock::time_point& currtime ATR_UNUSED, +bool CUDTGroup::sendBackup_CheckSendStatus(const steady_clock::time_point& currtime SRT_ATR_UNUSED, const int send_status, const int32_t lastseq, const int32_t pktseq, @@ -3769,7 +3769,7 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx // suffer linear search. int nwaiting = 0; - int nactivated ATR_UNUSED = 0; + int nactivated SRT_ATR_UNUSED = 0; int stat = -1; for (gli_t d = m_Group.begin(); d != m_Group.end(); ++d) { @@ -4217,7 +4217,7 @@ int CUDTGroup::sendBackupRexmit(CUDT& core, SRT_MSGCTRL& w_mc) // sequences already used by the link from which packets were // copied to the backup buffer. IF_HEAVY_LOGGING(int32_t old = core.schedSeqNo()); - const bool su ATR_UNUSED = core.overrideSndSeqNo(curseq); + const bool su SRT_ATR_UNUSED = core.overrideSndSeqNo(curseq); HLOGC(gslog.Debug, log << "sendBackupRexmit: OVERRIDING seq %" << old << " with %" << curseq << (su ? " - succeeded" : " - FAILED!")); diff --git a/srtcore/logging.h b/srtcore/logging.h index cfb239f1e..8767f2aa7 100644 --- a/srtcore/logging.h +++ b/srtcore/logging.h @@ -422,7 +422,7 @@ inline void PrintArgs(std::ostream& serr, Arg1&& arg1, Args&&... args) } template -inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line ATR_UNUSED, const std::string& area ATR_UNUSED, Args&&... args ATR_UNUSED) +inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, Args&&... args SRT_ATR_UNUSED) { #ifdef ENABLE_LOGGING std::ostringstream serr; @@ -440,7 +440,7 @@ inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line AT #else template -inline void LogDispatcher::PrintLogLine(const char* file ATR_UNUSED, int line ATR_UNUSED, const std::string& area ATR_UNUSED, const Arg& arg ATR_UNUSED) +inline void LogDispatcher::PrintLogLine(const char* file SRT_ATR_UNUSED, int line SRT_ATR_UNUSED, const std::string& area SRT_ATR_UNUSED, const Arg& arg SRT_ATR_UNUSED) { #ifdef ENABLE_LOGGING std::ostringstream serr; diff --git a/srtcore/sync.h b/srtcore/sync.h index 53123c682..7da6952f7 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -51,6 +51,7 @@ #endif // ENABLE_STDCXX_SYNC +#include "srt.h" #include "utilities.h" class CUDTException; // defined in common.h @@ -596,7 +597,7 @@ class CSync cond.notify_all(); } - void signal_locked(UniqueLock& lk ATR_UNUSED) + void signal_locked(UniqueLock& lk SRT_ATR_UNUSED) { // EXPECTED: lk.mutex() is LOCKED. m_cond->notify_one(); diff --git a/srtcore/utilities.h b/srtcore/utilities.h index caf882cd9..ed96306f5 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -18,7 +18,7 @@ written by // ATTRIBUTES: // -// ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings) +// SRT_ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings) // ATR_DEPRECATED: declare an entity deprecated (compiler should warn when used) // ATR_NOEXCEPT: The true `noexcept` from C++11, or nothing if compiling in pre-C++11 mode // ATR_NOTHROW: In C++11: `noexcept`. In pre-C++11: `throw()`. Required for GNU libstdc++. @@ -28,10 +28,8 @@ written by #ifdef __GNUG__ -#define ATR_UNUSED __attribute__((unused)) #define ATR_DEPRECATED __attribute__((deprecated)) #else -#define ATR_UNUSED #define ATR_DEPRECATED #endif #if defined(__cplusplus) && __cplusplus > 199711L @@ -719,7 +717,8 @@ struct CallbackHolder // Casting function-to-function, however, should not. Unfortunately // newer compilers disallow that, too (when a signature differs), but // then they should better use the C++11 way, much more reliable and safer. - void* (*testfn)(void*) ATR_UNUSED = (void*(*)(void*))f; + void* (*testfn)(void*) = (void*(*)(void*))f; + (void)(testfn); #endif opaque = o; fn = f; diff --git a/test/test_listen_callback.cpp b/test/test_listen_callback.cpp index 680ac6911..c8a441273 100644 --- a/test/test_listen_callback.cpp +++ b/test/test_listen_callback.cpp @@ -112,7 +112,7 @@ TEST(Core, ListenCallback) { (void)srt_cleanup(); } -int SrtTestListenCallback(void* opaq, SRTSOCKET ns, int hsversion, const struct sockaddr* peeraddr, const char* streamid) +int SrtTestListenCallback(void* opaq, SRTSOCKET ns SRT_ATR_UNUSED, int hsversion, const struct sockaddr* peeraddr, const char* streamid) { using namespace std; diff --git a/testing/testmedia.cpp b/testing/testmedia.cpp index f986aa5dc..932406888 100755 --- a/testing/testmedia.cpp +++ b/testing/testmedia.cpp @@ -2260,7 +2260,7 @@ MediaPacket SrtSource::Read(size_t chunk) { static size_t counter = 1; - bool have_group ATR_UNUSED = !m_group_nodes.empty(); + bool have_group SRT_ATR_UNUSED = !m_group_nodes.empty(); bytevector data(chunk); // EXPERIMENTAL From 3c1c490715a6a6025bdda85a8ef1acf64616d8e8 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Fri, 2 Jul 2021 21:29:40 +0800 Subject: [PATCH 034/124] [tests] Fix -Wsign-compare --- test/test_buffer.cpp | 6 +++--- test/test_epoll.cpp | 4 ++-- test/test_fec_rebuilding.cpp | 6 +++--- test/test_ipv6.cpp | 2 +- test/test_seqno.cpp | 2 +- test/test_socket_options.cpp | 20 ++++++++++---------- test/test_sync.cpp | 6 +++--- test/test_utilities.cpp | 6 +++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/test/test_buffer.cpp b/test/test_buffer.cpp index 047ced7e2..d2e7b39f6 100644 --- a/test/test_buffer.cpp +++ b/test/test_buffer.cpp @@ -47,7 +47,7 @@ TEST(CRcvBuffer, FullBuffer) for (int i = 0; i < buffer_size_pkts - 1; ++i) { const int res = rcv_buffer.readBuffer(buff.data(), buff.size()); - EXPECT_EQ(res, payload_size); + EXPECT_EQ(size_t(res), payload_size); } } @@ -109,7 +109,7 @@ TEST(CRcvBuffer, ReadData) std::array buff; const int res = rcv_buffer.readBuffer(buff.data(), buff.size()); - EXPECT_EQ(res, payload_size); + EXPECT_EQ(size_t(res), payload_size); } @@ -148,7 +148,7 @@ TEST(CRcvBuffer, AddData) for (int i = 0; i < ack_pkts; ++i) { const int res = rcv_buffer.readBuffer(buff.data(), buff.size()); - EXPECT_EQ(res, payload_size); + EXPECT_EQ(size_t(res), payload_size); EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size_pkts - ack_pkts + i); } diff --git a/test/test_epoll.cpp b/test/test_epoll.cpp index 8445450d3..8fb36be53 100644 --- a/test/test_epoll.cpp +++ b/test/test_epoll.cpp @@ -408,7 +408,7 @@ TEST(CEPoll, HandleEpollEvent2) int result = epoll.uwait(epoll_id, fds, 1024, -1); ASSERT_EQ(result, 1); - ASSERT_EQ(fds[0].events, SRT_EPOLL_ERR); + ASSERT_EQ(fds[0].events, int(SRT_EPOLL_ERR)); // Edge-triggered means that after one wait call was done, the next // call to this event should no longer report it. Now use timeout 0 @@ -529,7 +529,7 @@ TEST(CEPoll, ThreadedUpdate) int result = epoll.uwait(epoll_id, fds, 1024, -1); cerr << "Exit no longer infinite-wait by uwait, result=" << result << "\n"; ASSERT_EQ(result, 1); - ASSERT_EQ(fds[0].events, SRT_EPOLL_ERR); + ASSERT_EQ(fds[0].events, int(SRT_EPOLL_ERR)); cerr << "THREAD JOIN...\n"; td.join(); diff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp index 17f7cfbc9..1cfdf8ff9 100644 --- a/test/test_fec_rebuilding.cpp +++ b/test/test_fec_rebuilding.cpp @@ -801,7 +801,7 @@ TEST_F(TestFECRebuilding, NoRebuild) bool want_passthru_fec = fec->receive(*fecpkt, loss); EXPECT_EQ(want_passthru_fec, false); // Confirm that it's been eaten up - EXPECT_EQ(provided.size(), 0); // Confirm that nothing was rebuilt + EXPECT_EQ(provided.size(), 0U); // Confirm that nothing was rebuilt /* // XXX With such a short sequence, losses will not be reported. @@ -879,8 +879,8 @@ TEST_F(TestFECRebuilding, Rebuild) const bool want_passthru_fec = fec->receive(*fecpkt, loss); EXPECT_EQ(want_passthru_fec, false); // Confirm that it's been eaten up - EXPECT_EQ(loss.size(), 0); - ASSERT_EQ(provided.size(), 1); + EXPECT_EQ(loss.size(), 0U); + ASSERT_EQ(provided.size(), 1U); SrtPacket& rebuilt = provided[0]; CPacket& skipped = *source[4]; diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 677cae180..820288fa8 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -61,7 +61,7 @@ class TestIPv6 void ShowAddress(std::string src, const sockaddr_any& w) { - ASSERT_NE(fam.count(w.family()), 0) << "INVALID FAMILY"; + ASSERT_NE(fam.count(w.family()), 0U) << "INVALID FAMILY"; std::cout << src << ": " << w.str() << " (" << fam[w.family()] << ")" << std::endl; } diff --git a/test/test_seqno.cpp b/test/test_seqno.cpp index 4a1cb0ec8..f3f50de62 100644 --- a/test/test_seqno.cpp +++ b/test/test_seqno.cpp @@ -27,7 +27,7 @@ TEST(CSeqNo, seqcmp) EXPECT_EQ(CSeqNo::seqcmp(1, 128), -127); // abs(seq1 - seq2) >= 0x3FFFFFFF : seq2 - seq1 - EXPECT_EQ(CSeqNo::seqcmp(0x7FFFFFFF, 1), 0x80000002); // -2147483646 + EXPECT_EQ(CSeqNo::seqcmp(0x7FFFFFFF, 1), int(0x80000002)); // -2147483646 EXPECT_EQ(CSeqNo::seqcmp(1, 0x7FFFFFFF), 0x7FFFFFFE); // 2147483646 } diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 74a607838..d2e1da704 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -123,7 +123,7 @@ TEST_F(TestSocketOptions, LossMaxTTL) int opt_len = 0; ASSERT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS); EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the accepted socket"; - EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the accepted socket"; + EXPECT_EQ(size_t(opt_len), sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the accepted socket"; SRT_TRACEBSTATS stats; EXPECT_EQ(srt_bstats(accepted_sock, &stats, 0), SRT_SUCCESS); @@ -131,7 +131,7 @@ TEST_F(TestSocketOptions, LossMaxTTL) ASSERT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_LOSSMAXTTL, &opt_val, &opt_len), SRT_SUCCESS); EXPECT_EQ(opt_val, loss_max_ttl) << "Wrong SRTO_LOSSMAXTTL value on the listener socket"; - EXPECT_EQ(opt_len, sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the listener socket"; + EXPECT_EQ(size_t(opt_len), sizeof opt_len) << "Wrong SRTO_LOSSMAXTTL value length on the listener socket"; ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); } @@ -272,7 +272,7 @@ TEST_F(TestSocketOptions, StreamIDOdd) int buffer_len = sizeof buffer; EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); EXPECT_EQ(std::string(buffer), sid_odd); - EXPECT_EQ(buffer_len, sid_odd.size()); + EXPECT_EQ(size_t(buffer_len), sid_odd.size()); EXPECT_EQ(strlen(buffer), sid_odd.size()); StartListener(); @@ -283,7 +283,7 @@ TEST_F(TestSocketOptions, StreamIDOdd) buffer[i] = 'a'; buffer_len = (int)(sizeof buffer); EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); - EXPECT_EQ(buffer_len, sid_odd.size()); + EXPECT_EQ(size_t(buffer_len), sid_odd.size()); EXPECT_EQ(strlen(buffer), sid_odd.size()); ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); @@ -301,7 +301,7 @@ TEST_F(TestSocketOptions, StreamIDEven) int buffer_len = sizeof buffer; EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); EXPECT_EQ(std::string(buffer), sid_even); - EXPECT_EQ(buffer_len, sid_even.size()); + EXPECT_EQ(size_t(buffer_len), sid_even.size()); EXPECT_EQ(strlen(buffer), sid_even.size()); StartListener(); @@ -312,7 +312,7 @@ TEST_F(TestSocketOptions, StreamIDEven) buffer[i] = 'a'; buffer_len = (int)(sizeof buffer); EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); - EXPECT_EQ(buffer_len, sid_even.size()); + EXPECT_EQ(size_t(buffer_len), sid_even.size()); EXPECT_EQ(strlen(buffer), sid_even.size()); ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); @@ -337,7 +337,7 @@ TEST_F(TestSocketOptions, StreamIDAlmostFull) int buffer_len = sizeof buffer; EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); EXPECT_EQ(std::string(buffer), sid_amost_full); - EXPECT_EQ(buffer_len, sid_amost_full.size()); + EXPECT_EQ(size_t(buffer_len), sid_amost_full.size()); EXPECT_EQ(strlen(buffer), sid_amost_full.size()); StartListener(); @@ -348,7 +348,7 @@ TEST_F(TestSocketOptions, StreamIDAlmostFull) buffer[i] = 'a'; buffer_len = (int)(sizeof buffer); EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); - EXPECT_EQ(buffer_len, sid_amost_full.size()); + EXPECT_EQ(size_t(buffer_len), sid_amost_full.size()); EXPECT_EQ(strlen(buffer), sid_amost_full.size()); EXPECT_EQ(buffer[sid_amost_full.size()-1], 'z'); @@ -373,7 +373,7 @@ TEST_F(TestSocketOptions, StreamIDFull) int buffer_len = sizeof buffer; EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); EXPECT_EQ(std::string(buffer), sid_full); - EXPECT_EQ(buffer_len, sid_full.size()); + EXPECT_EQ(size_t(buffer_len), sid_full.size()); EXPECT_EQ(strlen(buffer), sid_full.size()); StartListener(); @@ -384,7 +384,7 @@ TEST_F(TestSocketOptions, StreamIDFull) buffer[i] = 'a'; buffer_len = (int)(sizeof buffer); EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS); - EXPECT_EQ(buffer_len, sid_full.size()); + EXPECT_EQ(size_t(buffer_len), sid_full.size()); EXPECT_EQ(strlen(buffer), sid_full.size()); EXPECT_EQ(buffer[sid_full.size()-1], 'z'); diff --git a/test/test_sync.cpp b/test/test_sync.cpp index 4967fbf86..6fa59c137 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -461,7 +461,7 @@ TEST(SyncEvent, WaitForTwoNotifyOne) // Now exactly one waiting thread should become ready // Error if: 0 (none ready) or 2 (both ready, while notify_one was used) - ASSERT_EQ(notified_clients.size(), 1); + ASSERT_EQ(notified_clients.size(), 1U); const int ready = notified_clients[0]; const int not_ready = (ready + 1) % 2; @@ -611,7 +611,7 @@ TEST(Sync, FormatTime) const regex rex("([[:digit:]]+D )?([[:digit:]]{2}):([[:digit:]]{2}):([[:digit:]]{2}).([[:digit:]]{6,}) \\[STDY\\]"); std::smatch sm; EXPECT_TRUE(regex_match(timestr, sm, rex)); - EXPECT_LE(sm.size(), 6); + EXPECT_LE(sm.size(), 6U); if (sm.size() != 6 && sm.size() != 5) return 0; @@ -655,7 +655,7 @@ TEST(Sync, FormatTimeSys) const regex rex("([[:digit:]]{2}):([[:digit:]]{2}):([[:digit:]]{2}).([[:digit:]]{6}) \\[SYST\\]"); std::smatch sm; EXPECT_TRUE(regex_match(timestr, sm, rex)); - EXPECT_EQ(sm.size(), 5); + EXPECT_EQ(sm.size(), 5U); if (sm.size() != 5) return 0; diff --git a/test/test_utilities.cpp b/test/test_utilities.cpp index 7deabe736..0ee56771c 100644 --- a/test/test_utilities.cpp +++ b/test/test_utilities.cpp @@ -219,7 +219,7 @@ TEST(ConfigString, Setting) StringStorage s; EXPECT_TRUE(s.empty()); - EXPECT_EQ(s.size(), 0); + EXPECT_EQ(s.size(), 0U); EXPECT_EQ(s.str(), std::string()); char example_ac1[] = "example_long"; @@ -246,7 +246,7 @@ TEST(ConfigString, Setting) EXPECT_EQ(s.size(), sizeof (example_ac3)-1); EXPECT_TRUE(s.set(example_ace, sizeof (example_ace)-1)); - EXPECT_EQ(s.size(), 0); + EXPECT_EQ(s.size(), 0U); string example_s1 = "example_long"; string example_s2 = "short"; @@ -268,6 +268,6 @@ TEST(ConfigString, Setting) EXPECT_EQ(s.size(), example_s3.size()); EXPECT_TRUE(s.set(example_se)); - EXPECT_EQ(s.size(), 0); + EXPECT_EQ(s.size(), 0U); EXPECT_TRUE(s.empty()); } From e8d890caf38c0ee851bf6c5a76da1bca407bd5db Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 21 Jun 2021 16:18:53 +0200 Subject: [PATCH 035/124] [core] Moved mutex from CSndQueue to CSndUList Co-authored-by: Sektor van Skijlen --- CMakeLists.txt | 2 +- srtcore/queue.cpp | 51 +++++++++++++++++++++++++++-------------------- srtcore/queue.h | 35 +++++++++++++++----------------- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98d360671..c14c81c55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ option(ENABLE_CXX_DEPS "Extra library dependencies in srt.pc for the CXX librari 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 /temporary fix for #729/" OFF) +option(ENABLE_MONOTONIC_CLOCK "Enforced clock_gettime with monotonic clock on GC CV" OFF) option(ENABLE_STDCXX_SYNC "Use C++11 chrono and threads for timing instead of pthreads" OFF) option(USE_OPENSSL_PC "Use pkg-config to find OpenSSL libraries" ON) option(USE_BUSY_WAITING "Enable more accurate sending times at a cost of potentially higher CPU load" OFF) diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index b9d7ed02e..f17ad5745 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -255,20 +255,20 @@ void srt::CUnitQueue::makeUnitGood(CUnit* unit) unit->m_iFlag = CUnit::GOOD; } -srt::CSndUList::CSndUList() +srt::CSndUList::CSndUList(sync::CTimer* pTimer) : m_pHeap(NULL) , m_iArrayLength(512) , m_iLastEntry(-1) , m_ListLock() - , m_pWindowLock(NULL) - , m_pWindowCond(NULL) - , m_pTimer(NULL) + , m_pTimer(pTimer) { + setupCond(m_ListCond, "CSndUListCond"); m_pHeap = new CSNode*[m_iArrayLength]; } srt::CSndUList::~CSndUList() { + releaseCond(m_ListCond); delete[] m_pHeap; } @@ -305,7 +305,7 @@ int srt::CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) if (-1 == m_iLastEntry) return -1; - // no pop until the next schedulled time + // no pop until the next scheduled time if (m_pHeap[0]->m_tsTimeStamp > steady_clock::now()) return -1; @@ -342,7 +342,6 @@ int srt::CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) void srt::CSndUList::remove(const CUDT* u) { ScopedLock listguard(m_ListLock); - remove_(u); } @@ -356,6 +355,21 @@ steady_clock::time_point srt::CSndUList::getNextProcTime() return m_pHeap[0]->m_tsTimeStamp; } +void srt::CSndUList::waitNonEmpty() const +{ + UniqueLock listguard(m_ListLock); + if (m_iLastEntry >= 0) + return; + + m_ListCond.wait(listguard); +} + +void srt::CSndUList::signalInterrupt() const +{ + ScopedLock listguard(m_ListLock); + m_ListCond.notify_all(); +} + void srt::CSndUList::realloc_() { CSNode** temp = NULL; @@ -420,7 +434,8 @@ void srt::CSndUList::insert_norealloc_(const steady_clock::time_point& ts, const // first entry, activate the sending queue if (0 == m_iLastEntry) { - CSync::lock_signal(*m_pWindowCond, *m_pWindowLock); + // m_ListLock is assumed to be locked. + m_ListCond.notify_all(); } } @@ -468,10 +483,8 @@ srt::CSndQueue::CSndQueue() : m_pSndUList(NULL) , m_pChannel(NULL) , m_pTimer(NULL) - , m_WindowCond() , m_bClosing(false) { - setupCond(m_WindowCond, "Window"); } srt::CSndQueue::~CSndQueue() @@ -483,14 +496,14 @@ srt::CSndQueue::~CSndQueue() m_pTimer->interrupt(); } - CSync::lock_signal(m_WindowCond, m_WindowLock); + // Unblock CSndQueue worker thread if it is waiting. + m_pSndUList->signalInterrupt(); if (m_WorkerThread.joinable()) { HLOGC(rslog.Debug, log << "SndQueue: EXIT"); m_WorkerThread.join(); } - releaseCond(m_WindowCond); delete m_pSndUList; } @@ -510,12 +523,9 @@ int srt::CSndQueue::m_counter = 0; void srt::CSndQueue::init(CChannel* c, CTimer* t) { - m_pChannel = c; - m_pTimer = t; - m_pSndUList = new CSndUList; - m_pSndUList->m_pWindowLock = &m_WindowLock; - m_pSndUList->m_pWindowCond = &m_WindowCond; - m_pSndUList->m_pTimer = m_pTimer; + m_pChannel = c; + m_pTimer = t; + m_pSndUList = new CSndUList(t); #if ENABLE_LOGGING ++m_counter; @@ -575,14 +585,11 @@ void* srt::CSndQueue::worker(void* param) self->m_WorkerStats.lNotReadyTs++; #endif /* SRT_DEBUG_SNDQ_HIGHRATE */ - UniqueLock windlock(self->m_WindowLock); - CSync windsync(self->m_WindowCond, windlock); - // wait here if there is no sockets with data to be sent THREAD_PAUSED(); - if (!self->m_bClosing && (self->m_pSndUList->m_iLastEntry < 0)) + if (!self->m_bClosing) { - windsync.wait(); + self->m_pSndUList->waitNonEmpty(); #if defined(SRT_DEBUG_SNDQ_HIGHRATE) self->m_WorkerStats.lCondWait++; diff --git a/srtcore/queue.h b/srtcore/queue.h index ee05440c8..77256c3fc 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -157,10 +157,8 @@ struct CSNode class CSndUList { - friend class CSndQueue; - public: - CSndUList(); + CSndUList(sync::CTimer* pTimer); ~CSndUList(); public: @@ -175,30 +173,32 @@ class CSndUList /// Update the timestamp of the UDT instance on the list. /// @param [in] u pointer to the UDT instance /// @param [in] reschedule if the timestamp should be rescheduled - void update(const CUDT* u, EReschedule reschedule); /// Retrieve the next packet and peer address from the first entry, and reschedule it in the queue. /// @param [out] addr destination address of the next packet /// @param [out] pkt the next packet to be sent /// @return 1 if successfully retrieved, -1 if no packet found. - int pop(sockaddr_any& addr, CPacket& pkt); /// Remove UDT instance from the list. /// @param [in] u pointer to the UDT instance - - void remove(const CUDT* u); + void remove(const CUDT* u);// EXCLUDES(m_ListLock); /// Retrieve the next scheduled processing time. /// @return Scheduled processing time of the first UDT socket in the list. - sync::steady_clock::time_point getNextProcTime(); + /// Wait for the list to become non empty. + void waitNonEmpty() const; + + /// Signal to stop waiting in waitNonEmpty(). + void signalInterrupt() const; + private: /// Doubles the size of the list. /// - void realloc_(); + void realloc_();// REQUIRES(m_ListLock); /// Insert a new UDT instance into the list with realloc if required. /// @@ -211,21 +211,21 @@ class CSndUList /// /// @param [in] ts time stamp: next processing time /// @param [in] u pointer to the UDT instance - void insert_norealloc_(const sync::steady_clock::time_point& ts, const CUDT* u); + void insert_norealloc_(const sync::steady_clock::time_point& ts, const CUDT* u);// REQUIRES(m_ListLock); + /// Removes CUDT entry from the list. + /// If the last entry is removed, calls sync::CTimer::interrupt(). void remove_(const CUDT* u); private: CSNode** m_pHeap; // The heap array int m_iArrayLength; // physical length of the array - int m_iLastEntry; // position of last entry on the heap array + int m_iLastEntry; // position of last entry on the heap array or -1 if empty. - sync::Mutex m_ListLock; + mutable sync::Mutex m_ListLock; // Protects the list (m_pHeap, m_iArrayLength, m_iLastEntry). + mutable sync::Condition m_ListCond; - sync::Mutex* m_pWindowLock; - sync::Condition* m_pWindowCond; - - sync::CTimer* m_pTimer; + sync::CTimer* const m_pTimer; private: CSndUList(const CSndUList&); @@ -462,9 +462,6 @@ class CSndQueue CChannel* m_pChannel; // The UDP channel for data sending srt::sync::CTimer* m_pTimer; // Timing facility - srt::sync::Mutex m_WindowLock; - srt::sync::Condition m_WindowCond; - srt::sync::atomic m_bClosing; // closing the worker #if defined(SRT_DEBUG_SNDQ_HIGHRATE) //>>debug high freq worker From e9c550b0e7c26ff80d7ad80d2ad2ab916d249c08 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 21 Jun 2021 17:09:27 +0200 Subject: [PATCH 036/124] [core] Refactor CSndUList: pop CUDT, not a packet --- srtcore/core.cpp | 4 +-- srtcore/queue.cpp | 82 ++++++++++++++++++++++++++--------------------- srtcore/queue.h | 11 +++---- 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 15a138a3a..14dd2c888 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -7974,14 +7974,14 @@ void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) #endif // insert this socket to snd list if it is not on the list yet - m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE); + const steady_clock::time_point currtime = steady_clock::now(); + m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE, currtime); if (m_config.bSynSending) { CSync::lock_signal(m_SendBlockCond, m_SendBlockLock); } - const steady_clock::time_point currtime = steady_clock::now(); // record total time used for sending enterCS(m_StatsLock); m_stats.sndDuration += count_microseconds(currtime - m_stats.sndDurationCounter); diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index f17ad5745..8cefd276d 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -272,7 +272,7 @@ srt::CSndUList::~CSndUList() delete[] m_pHeap; } -void srt::CSndUList::update(const CUDT* u, EReschedule reschedule) +void srt::CSndUList::update(const CUDT* u, EReschedule reschedule, sync::steady_clock::time_point ts) { ScopedLock listguard(m_ListLock); @@ -285,58 +285,33 @@ void srt::CSndUList::update(const CUDT* u, EReschedule reschedule) if (n->m_iHeapLoc == 0) { - n->m_tsTimeStamp = steady_clock::now(); + n->m_tsTimeStamp = ts; m_pTimer->interrupt(); return; } remove_(u); - insert_norealloc_(steady_clock::now(), u); + insert_norealloc_(ts, u); return; } - insert_(steady_clock::now(), u); + insert_(ts, u); } -int srt::CSndUList::pop(sockaddr_any& w_addr, CPacket& w_pkt) +srt::CUDT* srt::CSndUList::pop() { ScopedLock listguard(m_ListLock); if (-1 == m_iLastEntry) - return -1; + return NULL; // no pop until the next scheduled time if (m_pHeap[0]->m_tsTimeStamp > steady_clock::now()) - return -1; + return NULL; CUDT* u = m_pHeap[0]->m_pUDT; remove_(u); - -#define UST(field) ((u->m_b##field) ? "+" : "-") << #field << " " - - HLOGC(qslog.Debug, - log << "SND:pop: requesting packet from @" << u->socketID() << " STATUS: " << UST(Listening) - << UST(Connecting) << UST(Connected) << UST(Closing) << UST(Shutdown) << UST(Broken) << UST(PeerHealth) - << UST(Opened)); -#undef UST - - if (!u->m_bConnected || u->m_bBroken) - return -1; - - // pack a packet from the socket - const std::pair res_time = u->packData((w_pkt)); - - if (res_time.first <= 0) - return -1; - - w_addr = u->m_PeerAddr; - - // insert a new entry, ts is the next processing time - const steady_clock::time_point send_time = res_time.second; - if (!is_zero(send_time)) - insert_norealloc_(send_time, u); - - return 1; + return u; } void srt::CSndUList::remove(const CUDT* u) @@ -630,18 +605,51 @@ void* srt::CSndQueue::worker(void* param) } THREAD_RESUMED(); - // it is time to send the next pkt - sockaddr_any addr; - CPacket pkt; - if (self->m_pSndUList->pop((addr), (pkt)) < 0) + // Get a socket with a send request if any. + CUDT* u = self->m_pSndUList->pop(); + if (u == NULL) { +#if defined(SRT_DEBUG_SNDQ_HIGHRATE) + self->m_WorkerStats.lNotReadyPop++; +#endif /* SRT_DEBUG_SNDQ_HIGHRATE */ continue; + } + +#define UST(field) ((u->m_b##field) ? "+" : "-") << #field << " " + HLOGC(qslog.Debug, + log << "CSndQueue: requesting packet from @" << u->socketID() << " STATUS: " << UST(Listening) + << UST(Connecting) << UST(Connected) << UST(Closing) << UST(Shutdown) << UST(Broken) << UST(PeerHealth) + << UST(Opened)); +#undef UST + if (!u->m_bConnected || u->m_bBroken) + { #if defined(SRT_DEBUG_SNDQ_HIGHRATE) self->m_WorkerStats.lNotReadyPop++; #endif /* SRT_DEBUG_SNDQ_HIGHRATE */ + continue; } + // pack a packet from the socket + CPacket pkt; + const std::pair res_time = u->packData((pkt)); + + // Check if payload size is invalid. + if (res_time.first <= 0) + { +#if defined(SRT_DEBUG_SNDQ_HIGHRATE) + self->m_WorkerStats.lNotReadyPop++; +#endif /* SRT_DEBUG_SNDQ_HIGHRATE */ + continue; + } + + const sockaddr_any addr = u->m_PeerAddr; + // Insert a new entry, send_time is the next processing time. + // TODO: maybe reschedule by taking the smaller time? + const steady_clock::time_point send_time = res_time.second; + if (!is_zero(send_time)) + self->m_pSndUList->update(u, CSndUList::DONT_RESCHEDULE, send_time); + HLOGC(qslog.Debug, log << self->CONID() << "chn:SENDING: " << pkt.Info()); self->m_pChannel->sendto(addr, pkt); diff --git a/srtcore/queue.h b/srtcore/queue.h index 77256c3fc..2b7408747 100644 --- a/srtcore/queue.h +++ b/srtcore/queue.h @@ -173,13 +173,12 @@ class CSndUList /// Update the timestamp of the UDT instance on the list. /// @param [in] u pointer to the UDT instance /// @param [in] reschedule if the timestamp should be rescheduled - void update(const CUDT* u, EReschedule reschedule); + /// @param [in] ts the next time to trigger sending logic on the CUDT + void update(const CUDT* u, EReschedule reschedule, sync::steady_clock::time_point ts = sync::steady_clock::now()); - /// Retrieve the next packet and peer address from the first entry, and reschedule it in the queue. - /// @param [out] addr destination address of the next packet - /// @param [out] pkt the next packet to be sent - /// @return 1 if successfully retrieved, -1 if no packet found. - int pop(sockaddr_any& addr, CPacket& pkt); + /// Retrieve the next (in time) socket from the heap to process its sending request. + /// @return a pointer to CUDT instance to process next. + CUDT* pop(); /// Remove UDT instance from the list. /// @param [in] u pointer to the UDT instance From 96a41db2e0a7f53f9b16a0f823663892afadb1b3 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 12 Jul 2021 16:47:07 +0200 Subject: [PATCH 037/124] [core] CSndUList::update: reschedule if earlier time --- srtcore/queue.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 8cefd276d..2b0fd2c74 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -280,7 +280,10 @@ void srt::CSndUList::update(const CUDT* u, EReschedule reschedule, sync::steady_ if (n->m_iHeapLoc >= 0) { - if (!reschedule) // EReschedule to bool conversion, predicted. + if (reschedule == DONT_RESCHEDULE) + return; + + if (n->m_tsTimeStamp <= ts) return; if (n->m_iHeapLoc == 0) @@ -644,11 +647,9 @@ void* srt::CSndQueue::worker(void* param) } const sockaddr_any addr = u->m_PeerAddr; - // Insert a new entry, send_time is the next processing time. - // TODO: maybe reschedule by taking the smaller time? - const steady_clock::time_point send_time = res_time.second; - if (!is_zero(send_time)) - self->m_pSndUList->update(u, CSndUList::DONT_RESCHEDULE, send_time); + const steady_clock::time_point next_send_time = res_time.second; + if (!is_zero(next_send_time)) + self->m_pSndUList->update(u, CSndUList::DO_RESCHEDULE, next_send_time); HLOGC(qslog.Debug, log << self->CONID() << "chn:SENDING: " << pkt.Info()); self->m_pChannel->sendto(addr, pkt); From 65ae2575798595d209f4d57452b0b990e7295d55 Mon Sep 17 00:00:00 2001 From: Guangqing Chen Date: Tue, 20 Jul 2021 11:56:49 +0200 Subject: [PATCH 038/124] [core] Added missing RCV buffer lock in CUDT::receiveBuffer(..). Co-authored-by: Maxim Sharabayko --- srtcore/core.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 14dd2c888..65b51e850 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -6108,7 +6108,9 @@ int srt::CUDT::receiveBuffer(char *data, int len) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); } + enterCS(m_RcvBufferLock); const int res = m_pRcvBuffer->readBuffer(data, len); + leaveCS(m_RcvBufferLock); /* Kick TsbPd thread to schedule next wakeup (if running) */ if (m_bTsbPd) @@ -7056,7 +7058,9 @@ int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int blo } unitsize = int((torecv > block) ? block : torecv); + enterCS(m_RcvBufferLock); recvsize = m_pRcvBuffer->readBufferToFile(ofs, unitsize); + leaveCS(m_RcvBufferLock); if (recvsize > 0) { From ec24e15d50778844989676b4d36476d1c88f7bd5 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Wed, 21 Jul 2021 11:48:23 +0800 Subject: [PATCH 039/124] [core] Replace hacky static_assert by SRT_STATIC_ASSERT Remove local static SRTDATA_MAXSIZE since there is another one in global namespace. --- srtcore/core.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 65b51e850..75c0171ae 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -1208,16 +1208,9 @@ void srt::CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in) CPacket srtpkt; int32_t srtcmd = (int32_t)cmd; - static const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ / sizeof(int32_t); - - // This is in order to issue a compile error if the SRT_CMD_MAXSZ is - // too small to keep all the data. As this is "static const", declaring - // an array of such specified size in C++ isn't considered VLA. - static const int SRTDATA_SIZE = SRTDATA_MAXSIZE >= SRT_HS_E_SIZE ? SRTDATA_MAXSIZE : -1; - - // This will be effectively larger than SRT_HS_E_SIZE, but it will be also used - // for incoming data. We have a guarantee that it won't be larger than SRTDATA_MAXSIZE. - uint32_t srtdata[SRTDATA_SIZE]; + SRT_STATIC_ASSERT(SRTDATA_MAXSIZE >= SRT_HS_E_SIZE, "SRT_CMD_MAXSZ is too small to hold all the data"); + // This will be effectively larger than SRT_HS_E_SIZE, but it will be also used for incoming data. + uint32_t srtdata[SRTDATA_MAXSIZE]; size_t srtlen = 0; @@ -1233,7 +1226,7 @@ void srt::CUDT::sendSrtMsg(int cmd, uint32_t *srtdata_in, size_t srtlen_in) { case SRT_CMD_HSREQ: case SRT_CMD_HSRSP: - srtlen = prepareSrtHsMsg(cmd, srtdata, SRTDATA_SIZE); + srtlen = prepareSrtHsMsg(cmd, srtdata, SRTDATA_MAXSIZE); break; case SRT_CMD_KMREQ: // Sender From 1df29db15d671c91ea8e1dc30c263cd39e8138ad Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Wed, 21 Jul 2021 11:56:54 +0800 Subject: [PATCH 040/124] [core] use sizeof(uint32_t) in SRTDATA_MAXSIZE Since all usecase of SRTDATA_MAXSIZE are array of uint32_t. --- srtcore/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srtcore/crypto.h b/srtcore/crypto.h index 4e067678b..558f229f2 100644 --- a/srtcore/crypto.h +++ b/srtcore/crypto.h @@ -48,7 +48,7 @@ namespace srt const size_t SRT_KMR_KMSTATE = 0; #define SRT_CMD_MAXSZ HCRYPT_MSG_KM_MAX_SZ /* Maximum SRT custom messages payload size (bytes) */ -const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(int32_t); +const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(uint32_t); enum Whether2RegenKm {DONT_REGEN_KM = 0, REGEN_KM = 1}; From a34aa086060071e024076cec05f1b24ec7834416 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Thu, 22 Jul 2021 12:17:22 +0800 Subject: [PATCH 041/124] [core] Set CLOEXEC for epoll on Linux epoll_create1() was added to the kernel in version 2.6.27. Library support is provided in glibc starting with version 2.9 which was released at the year of 2008. --- srtcore/epoll.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index 548418f88..5755c9dff 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -108,7 +108,11 @@ int CEPoll::create(CEPollDesc** pout) int localid = 0; #ifdef LINUX - localid = epoll_create(1024); + int flags = 0; +#if ENABLE_SOCK_CLOEXEC + flags |= EPOLL_CLOEXEC; +#endif + localid = epoll_create1(flags); /* Possible reasons of -1 error: EMFILE: The per-user limit on the number of epoll instances imposed by /proc/sys/fs/epoll/max_user_instances was encountered. ENFILE: The system limit on the total number of open files has been reached. From 2ca53138a3669c192d2f9f8166c9749941f10dae Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 22 Jul 2021 15:07:01 +0200 Subject: [PATCH 042/124] [core] Added Clang TSA attributes. (#2000) - Added CMake build option ENABLE_CLANG_TSA. - srt::sync::UniqueLock now may throw an exception in unlock and lock. - MSVC SAL attributes are partially added. --- CMakeLists.txt | 7 +++ srtcore/logging.h | 3 + srtcore/platform_sys.h | 2 +- srtcore/srt.h | 2 +- srtcore/srt_attr_defs.h | 119 ++++++++++++++++++++++++++++++++++++++++ srtcore/sync.h | 46 ++++++++++------ srtcore/sync_posix.cpp | 21 ++++--- srtcore/udt.h | 4 +- 8 files changed, 176 insertions(+), 28 deletions(-) create mode 100644 srtcore/srt_attr_defs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c14c81c55..f210ff34f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,8 @@ option(USE_BUSY_WAITING "Enable more accurate sending times at a cost of potenti 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_CLANG_TSA "Enable Clang Thread Safety Analysis" OFF) + set(TARGET_srt "srt" CACHE STRING "The name for the SRT library") # Use application-defined group reader @@ -634,6 +636,11 @@ if (ENABLE_THREAD_CHECK) ) 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. diff --git a/srtcore/logging.h b/srtcore/logging.h index 8767f2aa7..5669c8f45 100644 --- a/srtcore/logging.h +++ b/srtcore/logging.h @@ -131,7 +131,10 @@ struct LogConfig { } + SRT_ATTR_ACQUIRE(mutex) void lock() { mutex.lock(); } + + SRT_ATTR_RELEASE(mutex) void unlock() { mutex.unlock(); } }; diff --git a/srtcore/platform_sys.h b/srtcore/platform_sys.h index 9fa2c7d32..79760080e 100644 --- a/srtcore/platform_sys.h +++ b/srtcore/platform_sys.h @@ -41,7 +41,7 @@ #include #include #if defined(_MSC_VER) - #pragma warning(disable:4251) + #pragma warning(disable: 4251 26812) #endif #else diff --git a/srtcore/srt.h b/srtcore/srt.h index 5d3349a48..496112249 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -963,7 +963,7 @@ typedef struct SRT_EPOLL_EVENT_STR int events; // SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR #ifdef __cplusplus SRT_EPOLL_EVENT_STR(SRTSOCKET s, int ev): fd(s), events(ev) {} - SRT_EPOLL_EVENT_STR() {} // NOTE: allows singular values, no init. + SRT_EPOLL_EVENT_STR(): fd(-1), events(0) {} // NOTE: allows singular values, no init. #endif } SRT_EPOLL_EVENT; SRT_API int srt_epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut); diff --git a/srtcore/srt_attr_defs.h b/srtcore/srt_attr_defs.h new file mode 100644 index 000000000..24bc8bc84 --- /dev/null +++ b/srtcore/srt_attr_defs.h @@ -0,0 +1,119 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2019 Haivision Systems Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ +/***************************************************************************** +The file contains various planform and compiler dependent attribute definitions +used by SRT library internally. + +1. Attributes for thread safety analysis + - Clang (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader). + - Other compilers: none. + + *****************************************************************************/ + +#ifndef INC_SRT_ATTR_DEFS_H +#define INC_SRT_ATTR_DEFS_H + +#if _MSC_VER >= 1920 +// In case of MSVC these attributes have to preceed the attributed objects (variable, function). +// E.g. SRT_ATTR_GUARDED_BY(mtx) int object; +// It is tricky to annotate e.g. the following function, as clang complaints it does not know 'm'. +// SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) +// inline void enterCS(Mutex& m) { m.lock(); } +#define SRT_ATTR_CAPABILITY(expr) +#define SRT_ATTR_SCOPED_CAPABILITY +#define SRT_ATTR_GUARDED_BY(expr) _Guarded_by_(expr) +#define SRT_ATTR_PT_GUARDED_BY(expr) +#define SRT_ATTR_ACQUIRED_BEFORE(...) +#define SRT_ATTR_ACQUIRED_AFTER(...) +#define SRT_ATTR_REQUIRES(expr) _Requires_lock_held_(expr) +#define SRT_ATTR_REQUIRES_SHARED(...) +#define SRT_ATTR_ACQUIRE(expr) _Acquires_nonreentrant_lock_(expr) +#define SRT_ATTR_ACQUIRE_SHARED(...) +#define SRT_ATTR_RELEASE(expr) _Releases_lock_(expr) +#define SRT_ATTR_RELEASE_SHARED(...) +#define SRT_ATTR_RELEASE_GENERIC(...) +#define SRT_ATTR_TRY_ACQUIRE(...) _Acquires_nonreentrant_lock_(expr) +#define SRT_ATTR_TRY_ACQUIRE_SHARED(...) +#define SRT_ATTR_EXCLUDES(...) +#define SRT_ATTR_ASSERT_CAPABILITY(expr) +#define SRT_ATTR_ASSERT_SHARED_CAPABILITY(x) +#define SRT_ATTR_RETURN_CAPABILITY(x) +#define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS +#else + +#if defined(__clang__) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define SRT_ATTR_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SRT_ATTR_SCOPED_CAPABILITY \ + THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define SRT_ATTR_GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define SRT_ATTR_PT_GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define SRT_ATTR_ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define SRT_ATTR_ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define SRT_ATTR_REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define SRT_ATTR_REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define SRT_ATTR_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define SRT_ATTR_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define SRT_ATTR_RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define SRT_ATTR_RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define SRT_ATTR_RELEASE_GENERIC(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__)) + +#define SRT_ATTR_TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define SRT_ATTR_TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define SRT_ATTR_EXCLUDES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define SRT_ATTR_ASSERT_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define SRT_ATTR_ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define SRT_ATTR_RETURN_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +#endif // not _MSC_VER + +#endif // INC_SRT_ATTR_DEFS_H diff --git a/srtcore/sync.h b/srtcore/sync.h index 7da6952f7..081cb41e4 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -53,6 +53,7 @@ #include "srt.h" #include "utilities.h" +#include "srt_attr_defs.h" class CUDTException; // defined in common.h @@ -379,7 +380,7 @@ using ScopedLock = lock_guard; /// Mutex is a class wrapper, that should mimic the std::chrono::mutex class. /// At the moment the extra function ref() is temporally added to allow calls /// to pthread_cond_timedwait(). Will be removed by introducing CEvent. -class Mutex +class SRT_ATTR_CAPABILITY("mutex") Mutex { friend class SyncEvent; @@ -388,11 +389,11 @@ class Mutex ~Mutex(); public: - int lock(); - int unlock(); + int lock() SRT_ATTR_ACQUIRE(); + int unlock() SRT_ATTR_RELEASE(); /// @return true if the lock was acquired successfully, otherwise false - bool try_lock(); + bool try_lock() SRT_ATTR_TRY_ACQUIRE(true); // TODO: To be removed with introduction of the CEvent. pthread_mutex_t& ref() { return m_mutex; } @@ -402,10 +403,13 @@ class Mutex }; /// A pthread version of std::chrono::scoped_lock (or lock_guard for C++11) -class ScopedLock +class SRT_ATTR_SCOPED_CAPABILITY ScopedLock { public: + SRT_ATTR_ACQUIRE(m) ScopedLock(Mutex& m); + + SRT_ATTR_RELEASE() ~ScopedLock(); private: @@ -413,17 +417,25 @@ class ScopedLock }; /// A pthread version of std::chrono::unique_lock -class UniqueLock +class SRT_ATTR_SCOPED_CAPABILITY UniqueLock { friend class SyncEvent; public: + SRT_ATTR_ACQUIRE(m_Mutex) UniqueLock(Mutex &m); + + SRT_ATTR_RELEASE(m_Mutex) ~UniqueLock(); public: + SRT_ATTR_ACQUIRE(m_Mutex) void lock(); + + SRT_ATTR_RELEASE(m_Mutex) void unlock(); + + SRT_ATTR_RETURN_CAPABILITY(m_Mutex) Mutex* mutex(); // reflects C++11 unique_lock::mutex() private: @@ -432,26 +444,28 @@ class UniqueLock }; #endif // ENABLE_STDCXX_SYNC -inline void enterCS(Mutex& m) { m.lock(); } -inline bool tryEnterCS(Mutex& m) { return m.try_lock(); } -inline void leaveCS(Mutex& m) { m.unlock(); } +inline void enterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) { m.lock(); } + +inline bool tryEnterCS(Mutex& m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); } + +inline void leaveCS(Mutex& m) SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) { m.unlock(); } class InvertedLock { - Mutex *m_pMutex; + Mutex& m_mtx; - public: +public: + SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) InvertedLock(Mutex& m) - : m_pMutex(&m) + : m_mtx(m) { - leaveCS(*m_pMutex); + m_mtx.unlock(); } + SRT_ATTR_ACQUIRE(m_mtx) ~InvertedLock() { - if (!m_pMutex) - return; - enterCS(*m_pMutex); + m_mtx.lock(); } }; diff --git a/srtcore/sync_posix.cpp b/srtcore/sync_posix.cpp index 0972dd731..960a1dfad 100644 --- a/srtcore/sync_posix.cpp +++ b/srtcore/sync_posix.cpp @@ -244,22 +244,27 @@ srt::sync::UniqueLock::UniqueLock(Mutex& m) srt::sync::UniqueLock::~UniqueLock() { - unlock(); + if (m_iLocked == 0) + { + unlock(); + } } void srt::sync::UniqueLock::lock() { - if (m_iLocked == -1) - m_iLocked = m_Mutex.lock(); + if (m_iLocked != -1) + throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0); + + m_iLocked = m_Mutex.lock(); } void srt::sync::UniqueLock::unlock() { - if (m_iLocked == 0) - { - m_Mutex.unlock(); - m_iLocked = -1; - } + if (m_iLocked != 0) + throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0); + + m_Mutex.unlock(); + m_iLocked = -1; } srt::sync::Mutex* srt::sync::UniqueLock::mutex() diff --git a/srtcore/udt.h b/srtcore/udt.h index b1af441b2..60bc8d07d 100644 --- a/srtcore/udt.h +++ b/srtcore/udt.h @@ -70,10 +70,10 @@ modified by #include "srt.h" /* -* SRT_ENABLE_THREADCHECK (THIS IS SET IN MAKEFILE NOT HERE) +* SRT_ENABLE_THREADCHECK IS SET IN MAKEFILE, NOT HERE */ #if defined(SRT_ENABLE_THREADCHECK) -#include +#include "threadcheck.h" #else #define THREAD_STATE_INIT(name) #define THREAD_EXIT() From d5d4b18f3efc59617b47e8dc6ca9b40b62872e93 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 26 Jul 2021 09:24:22 +0200 Subject: [PATCH 043/124] [docs] Fixed a link in Configuration Guidelines --- docs/API/configuration-guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/API/configuration-guidelines.md b/docs/API/configuration-guidelines.md index f0566d7d0..1e6d2111e 100644 --- a/docs/API/configuration-guidelines.md +++ b/docs/API/configuration-guidelines.md @@ -6,7 +6,7 @@ The receiver buffer can be configured with the [`SRTO_RCVBUF`](./API-socket-opti 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. +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: From 589f103926e9297fac4cd7f2c1e9dbdde9d8925c Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Mon, 5 Jul 2021 18:46:21 +0800 Subject: [PATCH 044/124] [core] Move CSrtConfigSetter templates to cpp file They are only used by socketconfig.cpp, socketconfig.h is included by multiple files. --- srtcore/socketconfig.cpp | 818 ++++++++++++++++++++++++++++++++++++++ srtcore/socketconfig.h | 829 --------------------------------------- 2 files changed, 818 insertions(+), 829 deletions(-) diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index e50bb08f5..8cb06a08f 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -54,6 +54,824 @@ written by extern const int32_t SRT_DEF_VERSION = SrtParseVersion(SRT_VERSION); +typedef void setter_function(CSrtConfig& co, const void* optval, int optlen); + +template +struct CSrtConfigSetter +{ + static setter_function set; +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + int ival = cast_optval(optval, optlen); + if (ival < int(srt::CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iMSS = ival; + + // Packet size cannot be greater than UDP buffer size + if (co.iMSS > co.iUDPSndBufSize) + co.iMSS = co.iUDPSndBufSize; + if (co.iMSS > co.iUDPRcvBufSize) + co.iMSS = co.iUDPRcvBufSize; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + const int fc = cast_optval(optval, optlen); + if (fc < co.DEF_MIN_FLIGHT_PKT) + { + LOGC(kmlog.Error, log << "SRTO_FC: minimum allowed value is 32 (provided: " << fc << ")"); + throw CUDTException(MJ_NOTSUP, MN_INVAL); + } + + co.iFlightFlagSize = fc; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + int bs = cast_optval(optval, optlen); + if (bs <= 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iSndBufSize = bs / (co.iMSS - srt::CPacket::UDP_HDR_SIZE); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val <= 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + // Mimimum recv buffer size is 32 packets + const int mssin_size = co.iMSS - srt::CPacket::UDP_HDR_SIZE; + + if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT) + co.iRcvBufSize = val / mssin_size; + else + co.iRcvBufSize = co.DEF_MIN_FLIGHT_PKT; + + // recv buffer MUST not be greater than FC size + if (co.iRcvBufSize > co.iFlightFlagSize) + co.iRcvBufSize = co.iFlightFlagSize; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.Linger = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iUDPSndBufSize = std::max(co.iMSS, cast_optval(optval, optlen)); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iUDPRcvBufSize = std::max(co.iMSS, cast_optval(optval, optlen)); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bRendezvous = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iSndTimeOut = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iRcvTimeOut = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bSynSending = cast_optval(optval, optlen); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bSynRecving = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bReuseAddr = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int64_t val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.llMaxBW = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + int val = cast_optval(optval, optlen); + if (!(val == -1) && !((val >= 1) && (val <= 255))) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.iIpTTL = cast_optval(optval); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iIpToS = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; +#ifdef SRT_ENABLE_BINDTODEVICE + using namespace std; + using namespace srt_logging; + + string val; + if (optlen == -1) + val = (const char *)optval; + else + val.assign((const char *)optval, optlen); + if (val.size() >= IFNAMSIZ) + { + LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE: device name too long (max: IFNAMSIZ=" << IFNAMSIZ << ")"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + co.sBindToDevice = val; +#else + (void)co; // prevent warning + (void)optval; + (void)optlen; + LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE is not supported on that platform"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); +#endif + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.llInputBW = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int64_t val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.llMinInputBW = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int32_t val = cast_optval(optval, optlen); + if (val < 5 || val > 100) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + co.iOverheadBW = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bDataSender = cast_optval(optval, optlen); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bTSBPD = cast_optval(optval, optlen); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iRcvLatency = val; + co.iPeerLatency = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iRcvLatency = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iPeerLatency = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bTLPktDrop = cast_optval(optval, optlen); + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < -1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iSndDropDelay = val; + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; +#ifdef SRT_ENABLE_ENCRYPTION + // Password must be 10-80 characters. + // Or it can be empty to clear the password. + if ((optlen != 0) && (optlen < 10 || optlen > HAICRYPT_SECRET_MAX_SZ)) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + memset(&co.CryptoSecret, 0, sizeof(co.CryptoSecret)); + co.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE; + co.CryptoSecret.len = (optlen <= (int)sizeof(co.CryptoSecret.str) ? optlen : (int)sizeof(co.CryptoSecret.str)); + memcpy((co.CryptoSecret.str), optval, co.CryptoSecret.len); +#else + (void)co; // prevent warning + (void)optval; + if (optlen == 0) + return; // Allow to set empty passphrase if no encryption supported. + + LOGC(aclog.Error, log << "SRTO_PASSPHRASE: encryption not enabled at compile time"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); +#endif + } +}; +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; +#ifdef SRT_ENABLE_ENCRYPTION + const int v = cast_optval(optval, optlen); + int const allowed[4] = { + 0, // Default value, if this results for initiator, defaults to 16. See below. + 16, // AES-128 + 24, // AES-192 + 32 // AES-256 + }; + const int *const allowed_end = allowed + 4; + if (std::find(allowed, allowed_end, v) == allowed_end) + { + LOGC(aclog.Error, + log << "Invalid value for option SRTO_PBKEYLEN: " << v << "; allowed are: 0, 16, 24, 32"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + // Note: This works a little different in HSv4 and HSv5. + + // HSv4: + // The party that is set SRTO_SENDER will send KMREQ, and it will + // use default value 16, if SRTO_PBKEYLEN is the default value 0. + // The responder that receives KMRSP has nothing to say about + // PBKEYLEN anyway and it will take the length of the key from + // the initiator (sender) as a good deal. + // + // HSv5: + // The initiator (independently on the sender) will send KMREQ, + // and as it should be the sender to decide about the PBKEYLEN. + // Your application should do the following then: + // 1. The sender should set PBKEYLEN to the required value. + // 2. If the sender is initiator, it will create the key using + // its preset PBKEYLEN (or default 16, if not set) and the + // receiver-responder will take it as a good deal. + // 3. Leave the PBKEYLEN value on the receiver as default 0. + // 4. If sender is responder, it should then advertise the PBKEYLEN + // value in the initial handshake messages (URQ_INDUCTION if + // listener, and both URQ_WAVEAHAND and URQ_CONCLUSION in case + // of rendezvous, as it is the matter of luck who of them will + // eventually become the initiator). This way the receiver + // being an initiator will set iSndCryptoKeyLen before setting + // up KMREQ for sending to the sender-responder. + // + // Note that in HSv5 if both sides set PBKEYLEN, the responder + // wins, unless the initiator is a sender (the effective PBKEYLEN + // will be the one advertised by the responder). If none sets, + // PBKEYLEN will default to 16. + + co.iSndCryptoKeyLen = v; +#else + (void)co; // prevent warning + (void)optval; + (void)optlen; + LOGC(aclog.Error, log << "SRTO_PBKEYLEN: encryption not enabled at compile time"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); +#endif + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bRcvNakReport = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + using namespace srt::sync; + co.tdConnTimeOut = milliseconds_from(val); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bDriftTracer = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iMaxReorderTolerance = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.uSrtVersion = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.uMinimumPeerSrtVersion = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + if (size_t(optlen) > CSrtConfig::MAX_SID_LENGTH) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.sStreamName.set((const char*)optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + std::string val; + if (optlen == -1) + val = (const char*)optval; + else + val.assign((const char*)optval, optlen); + + // Translate alias + if (val == "vod") + val = "file"; + + bool res = SrtCongestion::exists(val); + if (!res) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.sCongestion.set(val); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bMessageAPI = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + const int val = cast_optval(optval, optlen); + if (val < 0) + { + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + if (val > SRT_LIVE_MAX_PLSIZE) + { + LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE, maximum payload per MTU."); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + if (!co.sPacketFilterConfig.empty()) + { + // This means that the filter might have been installed before, + // and the fix to the maximum payload size was already applied. + // This needs to be checked now. + srt::SrtFilterConfig fc; + if (!srt::ParseFilterConfig(co.sPacketFilterConfig.str(), fc)) + { + // Break silently. This should not happen + LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: IPE: failing filter configuration installed"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + const size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; + if (size_t(val) > efc_max_payload_size) + { + LOGC(aclog.Error, + log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE decreased by " << fc.extra_size + << " required for packet filter header"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + } + + co.zExpPayloadSize = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + // XXX Note that here the configuration for SRTT_LIVE + // is the same as DEFAULT VALUES for these fields set + // in CUDT::CUDT. + switch (cast_optval(optval, optlen)) + { + case SRTT_LIVE: + // Default live options: + // - tsbpd: on + // - latency: 120ms + // - linger: off + // - congctl: live + // - extraction method: message (reading call extracts one message) + co.bTSBPD = true; + co.iRcvLatency = SRT_LIVE_DEF_LATENCY_MS; + co.iPeerLatency = 0; + co.bTLPktDrop = true; + co.iSndDropDelay = 0; + co.bMessageAPI = true; + co.bRcvNakReport = true; + co.zExpPayloadSize = SRT_LIVE_DEF_PLSIZE; + co.Linger.l_onoff = 0; + co.Linger.l_linger = 0; + co.sCongestion.set("live", 4); + break; + + case SRTT_FILE: + // File transfer mode: + // - tsbpd: off + // - latency: 0 + // - linger: on + // - congctl: file (original UDT congestion control) + // - extraction method: stream (reading call extracts as many bytes as available and fits in buffer) + co.bTSBPD = false; + co.iRcvLatency = 0; + co.iPeerLatency = 0; + co.bTLPktDrop = false; + co.iSndDropDelay = -1; + co.bMessageAPI = false; + co.bRcvNakReport = false; + co.zExpPayloadSize = 0; // use maximum + co.Linger.l_onoff = 1; + co.Linger.l_linger = CSrtConfig::DEF_LINGER_S; + co.sCongestion.set("file", 4); + break; + + default: + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + } +}; + +#if ENABLE_EXPERIMENTAL_BONDING +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iGroupConnect = cast_optval(optval, optlen); + } +}; +#endif + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + + const int val = cast_optval(optval, optlen); + if (val < 0) + { + LOGC(aclog.Error, + log << "SRTO_KMREFRESHRATE=" << val << " can't be negative"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + // Changing the KMREFRESHRATE sets KMPREANNOUNCE to the maximum allowed value + co.uKmRefreshRatePkt = (unsigned) val; + + if (co.uKmPreAnnouncePkt == 0 && co.uKmRefreshRatePkt == 0) + return; // Both values are default + + const unsigned km_preanno = co.uKmPreAnnouncePkt == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : co.uKmPreAnnouncePkt; + const unsigned km_refresh = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt; + + if (co.uKmPreAnnouncePkt == 0 || km_preanno > (km_refresh - 1) / 2) + { + co.uKmPreAnnouncePkt = (km_refresh - 1) / 2; + LOGC(aclog.Warn, + log << "SRTO_KMREFRESHRATE=0x" << std::hex << km_refresh << ": setting SRTO_KMPREANNOUNCE=0x" + << std::hex << co.uKmPreAnnouncePkt); + } + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + + const int val = cast_optval(optval, optlen); + if (val < 0) + { + LOGC(aclog.Error, + log << "SRTO_KMPREANNOUNCE=" << val << " can't be negative"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + const unsigned km_preanno = val == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : val; + const unsigned kmref = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt; + if (km_preanno > (kmref - 1) / 2) + { + LOGC(aclog.Error, + log << "SRTO_KMPREANNOUNCE=0x" << std::hex << km_preanno << " exceeds KmRefresh/2, 0x" << ((kmref - 1) / 2) + << " - OPTION REJECTED."); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + co.uKmPreAnnouncePkt = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.bEnforcedEnc = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + const int val = cast_optval(optval, optlen); + if (val < 0) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iPeerIdleTimeout = val; + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iIpV6Only = cast_optval(optval, optlen); + } +}; + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + std::string arg((const char*)optval, optlen); + // Parse the configuration string prematurely + srt::SrtFilterConfig fc; + srt::PacketFilter::Factory* fax = 0; + if (!srt::ParseFilterConfig(arg, (fc), (&fax))) + { + LOGC(aclog.Error, + log << "SRTO_PACKETFILTER: Incorrect syntax. Use: FILTERTYPE[,KEY:VALUE...]. " + "FILTERTYPE (" + << fc.type << ") must be installed (or builtin)"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + std::string error; + if (!fax->verifyConfig(fc, (error))) + { + LOGC(aclog.Error, log << "SRTO_PACKETFILTER: Incorrect config: " << error); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; + if (co.zExpPayloadSize > efc_max_payload_size) + { + LOGC(aclog.Warn, + log << "Due to filter-required extra " << fc.extra_size << " bytes, SRTO_PAYLOADSIZE fixed to " + << efc_max_payload_size << " bytes"); + co.zExpPayloadSize = efc_max_payload_size; + } + + co.sPacketFilterConfig.set(arg); + } +}; + +#if ENABLE_EXPERIMENTAL_BONDING +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + using namespace srt_logging; + // This option is meaningless for the socket itself. + // It's set here just for the sake of setting it on a listener + // socket so that it is then applied on the group when a + // group connection is configuired. + const int val = cast_optval(optval, optlen); + + // Search if you already have SRTO_PEERIDLETIMEO set + + const int idletmo = co.iPeerIdleTimeout; + + // Both are in milliseconds. + // This option is RECORDED in microseconds, while + // idletmo is recorded in milliseconds, only translated to + // microseconds directly before use. + if (val >= idletmo) + { + LOGC(aclog.Error, log << "group option: SRTO_GROUPSTABTIMEO(" << val + << ") exceeds SRTO_PEERIDLETIMEO(" << idletmo << ")"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + + co.uStabilityTimeout = val * 1000; + } +}; +#endif + +template<> +struct CSrtConfigSetter +{ + static void set(CSrtConfig& co, const void* optval, int optlen) + { + co.iRetransmitAlgo = cast_optval(optval, optlen); + } +}; + static struct SrtConfigSetter { setter_function* fn[SRTO_E_SIZE]; diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index 72b90195e..a9d2a0856 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -116,14 +116,6 @@ struct CSrtMuxerConfig struct CSrtConfig; -typedef void setter_function(CSrtConfig& co, const void* optval, int optlen); - -template -struct CSrtConfigSetter -{ - static setter_function set; -}; - template class StringStorage { @@ -314,14 +306,6 @@ struct CSrtConfig: CSrtMuxerConfig } int set(SRT_SOCKOPT optName, const void* val, int size); - - // Could be later made a more robust version with - // dispatching to the right data type. - template - void set(const void* val, int size) - { - CSrtConfigSetter::set(*this, val, size); - } }; @@ -390,817 +374,4 @@ inline bool cast_optval(const void* optval, int optlen) return false; } -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - int ival = cast_optval(optval, optlen); - if (ival < int(srt::CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize)) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iMSS = ival; - - // Packet size cannot be greater than UDP buffer size - if (co.iMSS > co.iUDPSndBufSize) - co.iMSS = co.iUDPSndBufSize; - if (co.iMSS > co.iUDPRcvBufSize) - co.iMSS = co.iUDPRcvBufSize; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - const int fc = cast_optval(optval, optlen); - if (fc < co.DEF_MIN_FLIGHT_PKT) - { - LOGC(kmlog.Error, log << "SRTO_FC: minimum allowed value is 32 (provided: " << fc << ")"); - throw CUDTException(MJ_NOTSUP, MN_INVAL); - } - - co.iFlightFlagSize = fc; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - int bs = cast_optval(optval, optlen); - if (bs <= 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iSndBufSize = bs / (co.iMSS - srt::CPacket::UDP_HDR_SIZE); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val <= 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - // Mimimum recv buffer size is 32 packets - const int mssin_size = co.iMSS - srt::CPacket::UDP_HDR_SIZE; - - if (val > mssin_size * co.DEF_MIN_FLIGHT_PKT) - co.iRcvBufSize = val / mssin_size; - else - co.iRcvBufSize = co.DEF_MIN_FLIGHT_PKT; - - // recv buffer MUST not be greater than FC size - if (co.iRcvBufSize > co.iFlightFlagSize) - co.iRcvBufSize = co.iFlightFlagSize; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.Linger = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iUDPSndBufSize = std::max(co.iMSS, cast_optval(optval, optlen)); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iUDPRcvBufSize = std::max(co.iMSS, cast_optval(optval, optlen)); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bRendezvous = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < -1) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iSndTimeOut = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < -1) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iRcvTimeOut = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bSynSending = cast_optval(optval, optlen); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bSynRecving = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bReuseAddr = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int64_t val = cast_optval(optval, optlen); - if (val < -1) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.llMaxBW = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - int val = cast_optval(optval, optlen); - if (!(val == -1) && !((val >= 1) && (val <= 255))) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.iIpTTL = cast_optval(optval); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iIpToS = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; -#ifdef SRT_ENABLE_BINDTODEVICE - using namespace std; - using namespace srt_logging; - - string val; - if (optlen == -1) - val = (const char *)optval; - else - val.assign((const char *)optval, optlen); - if (val.size() >= IFNAMSIZ) - { - LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE: device name too long (max: IFNAMSIZ=" << IFNAMSIZ << ")"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - co.sBindToDevice = val; -#else - (void)co; // prevent warning - (void)optval; - (void)optlen; - LOGC(kmlog.Error, log << "SRTO_BINDTODEVICE is not supported on that platform"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); -#endif - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int64_t val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.llInputBW = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int64_t val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.llMinInputBW = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int32_t val = cast_optval(optval, optlen); - if (val < 5 || val > 100) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - co.iOverheadBW = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bDataSender = cast_optval(optval, optlen); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bTSBPD = cast_optval(optval, optlen); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iRcvLatency = val; - co.iPeerLatency = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iRcvLatency = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iPeerLatency = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bTLPktDrop = cast_optval(optval, optlen); - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < -1) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iSndDropDelay = val; - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; -#ifdef SRT_ENABLE_ENCRYPTION - // Password must be 10-80 characters. - // Or it can be empty to clear the password. - if ((optlen != 0) && (optlen < 10 || optlen > HAICRYPT_SECRET_MAX_SZ)) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - memset(&co.CryptoSecret, 0, sizeof(co.CryptoSecret)); - co.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE; - co.CryptoSecret.len = (optlen <= (int)sizeof(co.CryptoSecret.str) ? optlen : (int)sizeof(co.CryptoSecret.str)); - memcpy((co.CryptoSecret.str), optval, co.CryptoSecret.len); -#else - (void)co; // prevent warning - (void)optval; - if (optlen == 0) - return; // Allow to set empty passphrase if no encryption supported. - - LOGC(aclog.Error, log << "SRTO_PASSPHRASE: encryption not enabled at compile time"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); -#endif - } -}; -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; -#ifdef SRT_ENABLE_ENCRYPTION - const int v = cast_optval(optval, optlen); - int const allowed[4] = { - 0, // Default value, if this results for initiator, defaults to 16. See below. - 16, // AES-128 - 24, // AES-192 - 32 // AES-256 - }; - const int *const allowed_end = allowed + 4; - if (std::find(allowed, allowed_end, v) == allowed_end) - { - LOGC(aclog.Error, - log << "Invalid value for option SRTO_PBKEYLEN: " << v << "; allowed are: 0, 16, 24, 32"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - // Note: This works a little different in HSv4 and HSv5. - - // HSv4: - // The party that is set SRTO_SENDER will send KMREQ, and it will - // use default value 16, if SRTO_PBKEYLEN is the default value 0. - // The responder that receives KMRSP has nothing to say about - // PBKEYLEN anyway and it will take the length of the key from - // the initiator (sender) as a good deal. - // - // HSv5: - // The initiator (independently on the sender) will send KMREQ, - // and as it should be the sender to decide about the PBKEYLEN. - // Your application should do the following then: - // 1. The sender should set PBKEYLEN to the required value. - // 2. If the sender is initiator, it will create the key using - // its preset PBKEYLEN (or default 16, if not set) and the - // receiver-responder will take it as a good deal. - // 3. Leave the PBKEYLEN value on the receiver as default 0. - // 4. If sender is responder, it should then advertise the PBKEYLEN - // value in the initial handshake messages (URQ_INDUCTION if - // listener, and both URQ_WAVEAHAND and URQ_CONCLUSION in case - // of rendezvous, as it is the matter of luck who of them will - // eventually become the initiator). This way the receiver - // being an initiator will set iSndCryptoKeyLen before setting - // up KMREQ for sending to the sender-responder. - // - // Note that in HSv5 if both sides set PBKEYLEN, the responder - // wins, unless the initiator is a sender (the effective PBKEYLEN - // will be the one advertised by the responder). If none sets, - // PBKEYLEN will default to 16. - - co.iSndCryptoKeyLen = v; -#else - (void)co; // prevent warning - (void)optval; - (void)optlen; - LOGC(aclog.Error, log << "SRTO_PBKEYLEN: encryption not enabled at compile time"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); -#endif - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bRcvNakReport = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - using namespace srt::sync; - co.tdConnTimeOut = milliseconds_from(val); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bDriftTracer = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iMaxReorderTolerance = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.uSrtVersion = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.uMinimumPeerSrtVersion = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - if (size_t(optlen) > CSrtConfig::MAX_SID_LENGTH) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.sStreamName.set((const char*)optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - std::string val; - if (optlen == -1) - val = (const char*)optval; - else - val.assign((const char*)optval, optlen); - - // Translate alias - if (val == "vod") - val = "file"; - - bool res = SrtCongestion::exists(val); - if (!res) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.sCongestion.set(val); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bMessageAPI = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - const int val = cast_optval(optval, optlen); - if (val < 0) - { - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - if (val > SRT_LIVE_MAX_PLSIZE) - { - LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE, maximum payload per MTU."); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - if (!co.sPacketFilterConfig.empty()) - { - // This means that the filter might have been installed before, - // and the fix to the maximum payload size was already applied. - // This needs to be checked now. - srt::SrtFilterConfig fc; - if (!srt::ParseFilterConfig(co.sPacketFilterConfig.str(), fc)) - { - // Break silently. This should not happen - LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: IPE: failing filter configuration installed"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - const size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; - if (size_t(val) > efc_max_payload_size) - { - LOGC(aclog.Error, - log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE decreased by " << fc.extra_size - << " required for packet filter header"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - } - - co.zExpPayloadSize = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - // XXX Note that here the configuration for SRTT_LIVE - // is the same as DEFAULT VALUES for these fields set - // in CUDT::CUDT. - switch (cast_optval(optval, optlen)) - { - case SRTT_LIVE: - // Default live options: - // - tsbpd: on - // - latency: 120ms - // - linger: off - // - congctl: live - // - extraction method: message (reading call extracts one message) - co.bTSBPD = true; - co.iRcvLatency = SRT_LIVE_DEF_LATENCY_MS; - co.iPeerLatency = 0; - co.bTLPktDrop = true; - co.iSndDropDelay = 0; - co.bMessageAPI = true; - co.bRcvNakReport = true; - co.zExpPayloadSize = SRT_LIVE_DEF_PLSIZE; - co.Linger.l_onoff = 0; - co.Linger.l_linger = 0; - co.sCongestion.set("live", 4); - break; - - case SRTT_FILE: - // File transfer mode: - // - tsbpd: off - // - latency: 0 - // - linger: on - // - congctl: file (original UDT congestion control) - // - extraction method: stream (reading call extracts as many bytes as available and fits in buffer) - co.bTSBPD = false; - co.iRcvLatency = 0; - co.iPeerLatency = 0; - co.bTLPktDrop = false; - co.iSndDropDelay = -1; - co.bMessageAPI = false; - co.bRcvNakReport = false; - co.zExpPayloadSize = 0; // use maximum - co.Linger.l_onoff = 1; - co.Linger.l_linger = CSrtConfig::DEF_LINGER_S; - co.sCongestion.set("file", 4); - break; - - default: - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - } -}; - -#if ENABLE_EXPERIMENTAL_BONDING -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iGroupConnect = cast_optval(optval, optlen); - } -}; -#endif - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - - const int val = cast_optval(optval, optlen); - if (val < 0) - { - LOGC(aclog.Error, - log << "SRTO_KMREFRESHRATE=" << val << " can't be negative"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - // Changing the KMREFRESHRATE sets KMPREANNOUNCE to the maximum allowed value - co.uKmRefreshRatePkt = (unsigned) val; - - if (co.uKmPreAnnouncePkt == 0 && co.uKmRefreshRatePkt == 0) - return; // Both values are default - - const unsigned km_preanno = co.uKmPreAnnouncePkt == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : co.uKmPreAnnouncePkt; - const unsigned km_refresh = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt; - - if (co.uKmPreAnnouncePkt == 0 || km_preanno > (km_refresh - 1) / 2) - { - co.uKmPreAnnouncePkt = (km_refresh - 1) / 2; - LOGC(aclog.Warn, - log << "SRTO_KMREFRESHRATE=0x" << std::hex << km_refresh << ": setting SRTO_KMPREANNOUNCE=0x" - << std::hex << co.uKmPreAnnouncePkt); - } - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - - const int val = cast_optval(optval, optlen); - if (val < 0) - { - LOGC(aclog.Error, - log << "SRTO_KMPREANNOUNCE=" << val << " can't be negative"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - const unsigned km_preanno = val == 0 ? HAICRYPT_DEF_KM_PRE_ANNOUNCE : val; - const unsigned kmref = co.uKmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : co.uKmRefreshRatePkt; - if (km_preanno > (kmref - 1) / 2) - { - LOGC(aclog.Error, - log << "SRTO_KMPREANNOUNCE=0x" << std::hex << km_preanno << " exceeds KmRefresh/2, 0x" << ((kmref - 1) / 2) - << " - OPTION REJECTED."); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - co.uKmPreAnnouncePkt = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.bEnforcedEnc = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - const int val = cast_optval(optval, optlen); - if (val < 0) - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - - co.iPeerIdleTimeout = val; - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iIpV6Only = cast_optval(optval, optlen); - } -}; - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - std::string arg((const char*)optval, optlen); - // Parse the configuration string prematurely - srt::SrtFilterConfig fc; - srt::PacketFilter::Factory* fax = 0; - if (!srt::ParseFilterConfig(arg, (fc), (&fax))) - { - LOGC(aclog.Error, - log << "SRTO_PACKETFILTER: Incorrect syntax. Use: FILTERTYPE[,KEY:VALUE...]. " - "FILTERTYPE (" - << fc.type << ") must be installed (or builtin)"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - std::string error; - if (!fax->verifyConfig(fc, (error))) - { - LOGC(aclog.Error, log << "SRTO_PACKETFILTER: Incorrect config: " << error); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - size_t efc_max_payload_size = SRT_LIVE_MAX_PLSIZE - fc.extra_size; - if (co.zExpPayloadSize > efc_max_payload_size) - { - LOGC(aclog.Warn, - log << "Due to filter-required extra " << fc.extra_size << " bytes, SRTO_PAYLOADSIZE fixed to " - << efc_max_payload_size << " bytes"); - co.zExpPayloadSize = efc_max_payload_size; - } - - co.sPacketFilterConfig.set(arg); - } -}; - -#if ENABLE_EXPERIMENTAL_BONDING -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - using namespace srt_logging; - // This option is meaningless for the socket itself. - // It's set here just for the sake of setting it on a listener - // socket so that it is then applied on the group when a - // group connection is configuired. - const int val = cast_optval(optval, optlen); - - // Search if you already have SRTO_PEERIDLETIMEO set - - const int idletmo = co.iPeerIdleTimeout; - - // Both are in milliseconds. - // This option is RECORDED in microseconds, while - // idletmo is recorded in milliseconds, only translated to - // microseconds directly before use. - if (val >= idletmo) - { - LOGC(aclog.Error, log << "group option: SRTO_GROUPSTABTIMEO(" << val - << ") exceeds SRTO_PEERIDLETIMEO(" << idletmo << ")"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - - co.uStabilityTimeout = val * 1000; - } -}; -#endif - -template<> -struct CSrtConfigSetter -{ - static void set(CSrtConfig& co, const void* optval, int optlen) - { - co.iRetransmitAlgo = cast_optval(optval, optlen); - } -}; - -#if TEMPLATE -#endif - #endif From 127c85c1098a91864528235342735de54156de59 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Mon, 5 Jul 2021 19:30:54 +0800 Subject: [PATCH 045/124] [core] Put CSrtConfigSetter into anonymous namespace And use simple switch case. The library size is reduced from 1224 KB to 1216 KB on macOS build with: -DENABLE_TESTING=ON -DENABLE_UNITTESTS=ON -DENABLE_HEAVY_LOGGING=ON \ -DUSE_ENCLIB=mbedtls -DENABLE_EXPERIMENTAL_BONDING=ON -DENABLE_ENCRYPTION=OFF \ -DENABLE_STDCXX_SYNC=ON --- srtcore/socketconfig.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 8cb06a08f..2fcc475b2 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -54,6 +54,7 @@ written by extern const int32_t SRT_DEF_VERSION = SrtParseVersion(SRT_VERSION); +namespace { typedef void setter_function(CSrtConfig& co, const void* optval, int optlen); template @@ -872,15 +873,11 @@ struct CSrtConfigSetter } }; -static struct SrtConfigSetter +int dispatchSet(SRT_SOCKOPT optName, CSrtConfig& co, const void* optval, int optlen) { - setter_function* fn[SRTO_E_SIZE]; - - SrtConfigSetter() + switch (optName) { - memset(fn, 0, sizeof fn); - -#define DISPATCH(optname) fn[optname] = &CSrtConfigSetter::set; +#define DISPATCH(optname) case optname: CSrtConfigSetter::set(co, optval, optlen); return 0; DISPATCH(SRTO_MSS); DISPATCH(SRTO_FC); @@ -937,17 +934,16 @@ static struct SrtConfigSetter DISPATCH(SRTO_RETRANSMITALGO); #undef DISPATCH + default: + return -1; } -} srt_config_setter; +} + +} // anonymous namespace int CSrtConfig::set(SRT_SOCKOPT optName, const void* optval, int optlen) { - setter_function* fn = srt_config_setter.fn[optName]; - if (!fn) - return -1; // No such option - - fn(*this, optval, optlen); // MAY THROW EXCEPTION. - return 0; + return dispatchSet(optName, *this, optval, optlen); } #if ENABLE_EXPERIMENTAL_BONDING From 877adfa5fc4c98050faaa5062c0ab5097d634ca1 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 27 Jul 2021 15:21:35 +0200 Subject: [PATCH 046/124] [docs] Removed unused SRTO_FC from config function in configuration guidelines. --- docs/API/configuration-guidelines.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/API/configuration-guidelines.md b/docs/API/configuration-guidelines.md index 1e6d2111e..54d3cd15a 100644 --- a/docs/API/configuration-guidelines.md +++ b/docs/API/configuration-guidelines.md @@ -32,7 +32,7 @@ int getRbufSizePkts(int SRTO_RCVBUF, int SRTO_MSS, int SRTO_FC) // UDP header size is assumed to be 28 bytes // 20 bytes IPv4 + 8 bytes of UDP const int UDPHDR_SIZE = 28; - const in pkts = (rbuf_size / (SRTO_MSS - UDPHDR_SIZE)); + const int pkts = (rbuf_size / (SRTO_MSS - UDPHDR_SIZE)); return min(pkts, SRTO_FC); } @@ -88,7 +88,7 @@ where ```c++ -auto CalculateTargetRBufSize(int msRTT, int bpsRate, int bytesPayloadSize, int msLatency, int SRTO_MSS, int SRTO_FC) +auto CalculateTargetRBufSize(int msRTT, int bpsRate, int bytesPayloadSize, int msLatency, int SRTO_MSS) { const int UDPHDR_SIZE = 28; const int targetPayloadBytes = (msLatency + msRTT / 2) * bpsRate / 1000 / 8; @@ -99,7 +99,7 @@ auto CalculateTargetRBufSize(int msRTT, int bpsRate, int bytesPayloadSize, int m // Configuring -const auto [fc, rcvbuf] = CalculateTargetRBufSize(msRTT, bpsRate, bytesPayloadSize, SRTO_RCVLATENCY, SRTO_MSS, SRTO_FC); +const auto [fc, rcvbuf] = CalculateTargetRBufSize(msRTT, bpsRate, bytesPayloadSize, SRTO_RCVLATENCY, SRTO_MSS); int optval = fc; int optlen = sizeof optval; From ea4edffc257bb634fe8944e530ed5fc355860c92 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 27 Jul 2021 00:41:16 +0200 Subject: [PATCH 047/124] [core] Moved compiler attribute definitions --- srtcore/srt_attr_defs.h | 80 +++++++++++++++++++++++++++++++++++++---- srtcore/utilities.h | 72 +------------------------------------ 2 files changed, 75 insertions(+), 77 deletions(-) diff --git a/srtcore/srt_attr_defs.h b/srtcore/srt_attr_defs.h index 24bc8bc84..82e6e5e3a 100644 --- a/srtcore/srt_attr_defs.h +++ b/srtcore/srt_attr_defs.h @@ -3,23 +3,91 @@ * Copyright (c) 2019 Haivision Systems Inc. * * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this + * 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/. * */ /***************************************************************************** The file contains various planform and compiler dependent attribute definitions used by SRT library internally. - -1. Attributes for thread safety analysis - - Clang (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader). - - Other compilers: none. - *****************************************************************************/ #ifndef INC_SRT_ATTR_DEFS_H #define INC_SRT_ATTR_DEFS_H +// ATTRIBUTES: +// +// SRT_ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings) +// ATR_DEPRECATED: declare an entity deprecated (compiler should warn when used) +// ATR_NOEXCEPT: The true `noexcept` from C++11, or nothing if compiling in pre-C++11 mode +// ATR_NOTHROW: In C++11: `noexcept`. In pre-C++11: `throw()`. Required for GNU libstdc++. +// ATR_CONSTEXPR: In C++11: `constexpr`. Otherwise empty. +// ATR_OVERRIDE: In C++11: `override`. Otherwise empty. +// ATR_FINAL: In C++11: `final`. Otherwise empty. + +#ifdef __GNUG__ +#define ATR_DEPRECATED __attribute__((deprecated)) +#else +#define ATR_DEPRECATED +#endif + +#if defined(__cplusplus) && __cplusplus > 199711L +#define HAVE_CXX11 1 +// For gcc 4.7, claim C++11 is supported, as long as experimental C++0x is on, +// however it's only the "most required C++11 support". +#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 // 4.7 only! +#define ATR_NOEXCEPT +#define ATR_NOTHROW throw() +#define ATR_CONSTEXPR +#define ATR_OVERRIDE +#define ATR_FINAL +#else +#define HAVE_FULL_CXX11 1 +#define ATR_NOEXCEPT noexcept +#define ATR_NOTHROW noexcept +#define ATR_CONSTEXPR constexpr +#define ATR_OVERRIDE override +#define ATR_FINAL final +#endif +#elif defined(_MSC_VER) && _MSC_VER >= 1800 +// Microsoft Visual Studio supports C++11, but not fully, +// and still did not change the value of __cplusplus. Treat +// this special way. +// _MSC_VER == 1800 means Microsoft Visual Studio 2013. +#define HAVE_CXX11 1 +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 +#define HAVE_FULL_CXX11 1 +#define ATR_NOEXCEPT noexcept +#define ATR_NOTHROW noexcept +#define ATR_CONSTEXPR constexpr +#define ATR_OVERRIDE override +#define ATR_FINAL final +#else +#define ATR_NOEXCEPT +#define ATR_NOTHROW throw() +#define ATR_CONSTEXPR +#define ATR_OVERRIDE +#define ATR_FINAL +#endif +#else +#define HAVE_CXX11 0 +#define ATR_NOEXCEPT +#define ATR_NOTHROW throw() +#define ATR_CONSTEXPR +#define ATR_OVERRIDE +#define ATR_FINAL +#endif // __cplusplus + +#if !HAVE_CXX11 && defined(REQUIRE_CXX11) && REQUIRE_CXX11 == 1 +#error "The currently compiled application required C++11, but your compiler doesn't support it." +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Attributes for thread safety analysis +// - Clang TSA (https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader). +// - MSVC SAL (partially). +// - Other compilers: none. +/////////////////////////////////////////////////////////////////////////////// #if _MSC_VER >= 1920 // In case of MSVC these attributes have to preceed the attributed objects (variable, function). // E.g. SRT_ATTR_GUARDED_BY(mtx) int object; diff --git a/srtcore/utilities.h b/srtcore/utilities.h index ed96306f5..6d888b3d8 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -16,81 +16,11 @@ written by #ifndef INC_SRT_UTILITIES_H #define INC_SRT_UTILITIES_H -// ATTRIBUTES: -// -// SRT_ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings) -// ATR_DEPRECATED: declare an entity deprecated (compiler should warn when used) -// ATR_NOEXCEPT: The true `noexcept` from C++11, or nothing if compiling in pre-C++11 mode -// ATR_NOTHROW: In C++11: `noexcept`. In pre-C++11: `throw()`. Required for GNU libstdc++. -// ATR_CONSTEXPR: In C++11: `constexpr`. Otherwise empty. -// ATR_OVERRIDE: In C++11: `override`. Otherwise empty. -// ATR_FINAL: In C++11: `final`. Otherwise empty. - - -#ifdef __GNUG__ -#define ATR_DEPRECATED __attribute__((deprecated)) -#else -#define ATR_DEPRECATED -#endif -#if defined(__cplusplus) && __cplusplus > 199711L -#define HAVE_CXX11 1 - -// For gcc 4.7, claim C++11 is supported, as long as experimental C++0x is on, -// however it's only the "most required C++11 support". -#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 // 4.7 only! -#define ATR_NOEXCEPT -#define ATR_NOTHROW throw() -#define ATR_CONSTEXPR -#define ATR_OVERRIDE -#define ATR_FINAL -#else -#define HAVE_FULL_CXX11 1 -#define ATR_NOEXCEPT noexcept -#define ATR_NOTHROW noexcept -#define ATR_CONSTEXPR constexpr -#define ATR_OVERRIDE override -#define ATR_FINAL final -#endif - -// Microsoft Visual Studio supports C++11, but not fully, -// and still did not change the value of __cplusplus. Treat -// this special way. -// _MSC_VER == 1800 means Microsoft Visual Studio 2013. -#elif defined(_MSC_VER) && _MSC_VER >= 1800 -#define HAVE_CXX11 1 -#if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026 -#define HAVE_FULL_CXX11 1 -#define ATR_NOEXCEPT noexcept -#define ATR_NOTHROW noexcept -#define ATR_CONSTEXPR constexpr -#define ATR_OVERRIDE override -#define ATR_FINAL final -#else -#define ATR_NOEXCEPT -#define ATR_NOTHROW throw() -#define ATR_CONSTEXPR -#define ATR_OVERRIDE -#define ATR_FINAL -#endif -#else -#define HAVE_CXX11 0 -#define ATR_NOEXCEPT -#define ATR_NOTHROW throw() -#define ATR_CONSTEXPR -#define ATR_OVERRIDE -#define ATR_FINAL - -#endif - -#if !HAVE_CXX11 && defined(REQUIRE_CXX11) && REQUIRE_CXX11 == 1 -#error "The currently compiled application required C++11, but your compiler doesn't support it." -#endif - - // Windows warning disabler #define _CRT_SECURE_NO_WARNINGS 1 #include "platform_sys.h" +#include "srt_attr_defs.h" // defines HAVE_CXX11 // Happens that these are defined, undefine them in advance #undef min From 158f35d6ba24d92d5a217f06ef402b133bfd50ae Mon Sep 17 00:00:00 2001 From: Laurent Bigonville Date: Fri, 30 Jul 2021 00:04:24 +0200 Subject: [PATCH 048/124] [core] Fix FTBFS on Debian kfreebsd Fixes: #2066 --- srtcore/epoll.cpp | 4 ++++ srtcore/utilities.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index 5755c9dff..bfce672cc 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -58,6 +58,10 @@ modified by #include #include +#if defined(__FreeBSD_kernel__) +#include +#endif + #include "common.h" #include "epoll.h" #include "logging.h" diff --git a/srtcore/utilities.h b/srtcore/utilities.h index 6d888b3d8..b1f21fbb2 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -115,7 +115,7 @@ written by # include -#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) # include From 5ac27a3733c7938eab5fc147d10412b8304fafbd Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 2 Aug 2021 17:15:04 +0200 Subject: [PATCH 049/124] [tests] Tests for socket options API (#1929) --- docs/API/API-socket-options.md | 2 + test/any.hpp | 504 +++++++++++++++++++++++++++ test/filelist.maf | 2 + test/test_listen_callback.cpp | 6 +- test/test_socket_options.cpp | 598 ++++++++++++++++++++++++++++++++- 5 files changed, 1107 insertions(+), 5 deletions(-) create mode 100644 test/any.hpp diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 3c9f91556..b87d80ab0 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -847,6 +847,8 @@ 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) --- diff --git a/test/any.hpp b/test/any.hpp new file mode 100644 index 000000000..d47722bae --- /dev/null +++ b/test/any.hpp @@ -0,0 +1,504 @@ +// +// Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers. +// +// See also: +// + http://en.cppreference.com/w/cpp/any +// + http://en.cppreference.com/w/cpp/experimental/any +// + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any +// + https://cplusplus.github.io/LWG/lwg-active.html#2509 +// +// +// Copyright (c) 2016 Denilson das Mercês Amorim +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef LINB_ANY_HPP +#define LINB_ANY_HPP +#pragma once +#include +#include +#include + + +#if defined(PARTICLE) +#if !defined(__cpp_exceptions) && !defined(ANY_IMPL_NO_EXCEPTIONS) && !defined(ANY_IMPL_EXCEPTIONS) +# define ANY_IMPL_NO_EXCEPTIONS +# endif +#else +// you can opt-out of exceptions by definining ANY_IMPL_NO_EXCEPTIONS, +// but you must ensure not to cast badly when passing an `any' object to any_cast(any) +#endif + +#if defined(PARTICLE) +#if !defined(__cpp_rtti) && !defined(ANY_IMPL_NO_RTTI) && !defined(ANY_IMPL_RTTI) +# define ANY_IMPL_NO_RTTI +# endif +#else +// you can opt-out of RTTI by defining ANY_IMPL_NO_RTTI, +// in order to disable functions working with the typeid of a type +#endif + + +namespace linb +{ + +class bad_any_cast : public std::bad_cast +{ +public: + const char* what() const noexcept override + { + return "bad any cast"; + } +}; + +class any final +{ +public: + /// Constructs an object of type any with an empty state. + any() : + vtable(nullptr) + { + } + + /// Constructs an object of type any with an equivalent state as other. + any(const any& rhs) : + vtable(rhs.vtable) + { + if(!rhs.empty()) + { + rhs.vtable->copy(rhs.storage, this->storage); + } + } + + /// Constructs an object of type any with a state equivalent to the original state of other. + /// rhs is left in a valid but otherwise unspecified state. + any(any&& rhs) noexcept : + vtable(rhs.vtable) + { + if(!rhs.empty()) + { + rhs.vtable->move(rhs.storage, this->storage); + rhs.vtable = nullptr; + } + } + + /// Same effect as this->clear(). + ~any() + { + this->clear(); + } + + /// Constructs an object of type any that contains an object of type T direct-initialized with std::forward(value). + /// + /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. + /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. + template::type, any>::value>::type> + any(ValueType&& value) + { + static_assert(std::is_copy_constructible::type>::value, + "T shall satisfy the CopyConstructible requirements."); + this->construct(std::forward(value)); + } + + /// Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown. + any& operator=(const any& rhs) + { + any(rhs).swap(*this); + return *this; + } + + /// Has the same effect as any(std::move(rhs)).swap(*this). + /// + /// The state of *this is equivalent to the original state of rhs and rhs is left in a valid + /// but otherwise unspecified state. + any& operator=(any&& rhs) noexcept + { + any(std::move(rhs)).swap(*this); + return *this; + } + + /// Has the same effect as any(std::forward(value)).swap(*this). No effect if a exception is thrown. + /// + /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. + /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. + template::type, any>::value>::type> + any& operator=(ValueType&& value) + { + static_assert(std::is_copy_constructible::type>::value, + "T shall satisfy the CopyConstructible requirements."); + any(std::forward(value)).swap(*this); + return *this; + } + + /// If not empty, destroys the contained object. + void clear() noexcept + { + if(!empty()) + { + this->vtable->destroy(storage); + this->vtable = nullptr; + } + } + + /// Returns true if *this has no contained object, otherwise false. + bool empty() const noexcept + { + return this->vtable == nullptr; + } + +#ifndef ANY_IMPL_NO_RTTI + /// If *this has a contained object of type T, typeid(T); otherwise typeid(void). + const std::type_info& type() const noexcept + { + return empty()? typeid(void) : this->vtable->type(); + } +#endif + + /// Exchange the states of *this and rhs. + void swap(any& rhs) noexcept + { + if(this->vtable != rhs.vtable) + { + any tmp(std::move(rhs)); + + // move from *this to rhs. + rhs.vtable = this->vtable; + if(this->vtable != nullptr) + { + this->vtable->move(this->storage, rhs.storage); + //this->vtable = nullptr; -- unneeded, see below + } + + // move from tmp (previously rhs) to *this. + this->vtable = tmp.vtable; + if(tmp.vtable != nullptr) + { + tmp.vtable->move(tmp.storage, this->storage); + tmp.vtable = nullptr; + } + } + else // same types + { + if(this->vtable != nullptr) + this->vtable->swap(this->storage, rhs.storage); + } + } + +private: // Storage and Virtual Method Table + union storage_union + { + using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of::value>::type; + + void* dynamic; + stack_storage_t stack; // 2 words for e.g. shared_ptr + }; + + /// Base VTable specification. + struct vtable_type + { + // Note: The caller is responssible for doing .vtable = nullptr after destructful operations + // such as destroy() and/or move(). + +#ifndef ANY_IMPL_NO_RTTI + /// The type of the object this vtable is for. + const std::type_info& (*type)() noexcept; +#endif + + /// Destroys the object in the union. + /// The state of the union after this call is unspecified, caller must ensure not to use src anymore. + void(*destroy)(storage_union&) noexcept; + + /// Copies the **inner** content of the src union into the yet unitialized dest union. + /// As such, both inner objects will have the same state, but on separate memory locations. + void(*copy)(const storage_union& src, storage_union& dest); + + /// Moves the storage from src to the yet unitialized dest union. + /// The state of src after this call is unspecified, caller must ensure not to use src anymore. + void(*move)(storage_union& src, storage_union& dest) noexcept; + + /// Exchanges the storage between lhs and rhs. + void(*swap)(storage_union& lhs, storage_union& rhs) noexcept; + }; + + /// VTable for dynamically allocated storage. + template + struct vtable_dynamic + { +#ifndef ANY_IMPL_NO_RTTI + static const std::type_info& type() noexcept + { + return typeid(T); + } +#endif + + static void destroy(storage_union& storage) noexcept + { + //assert(reinterpret_cast(storage.dynamic)); + delete reinterpret_cast(storage.dynamic); + } + + static void copy(const storage_union& src, storage_union& dest) + { + dest.dynamic = new T(*reinterpret_cast(src.dynamic)); + } + + static void move(storage_union& src, storage_union& dest) noexcept + { + dest.dynamic = src.dynamic; + src.dynamic = nullptr; + } + + static void swap(storage_union& lhs, storage_union& rhs) noexcept + { + // just exchage the storage pointers. + std::swap(lhs.dynamic, rhs.dynamic); + } + }; + + /// VTable for stack allocated storage. + template + struct vtable_stack + { +#ifndef ANY_IMPL_NO_RTTI + static const std::type_info& type() noexcept + { + return typeid(T); + } +#endif + + static void destroy(storage_union& storage) noexcept + { + reinterpret_cast(&storage.stack)->~T(); + } + + static void copy(const storage_union& src, storage_union& dest) + { + new (&dest.stack) T(reinterpret_cast(src.stack)); + } + + static void move(storage_union& src, storage_union& dest) noexcept + { + // one of the conditions for using vtable_stack is a nothrow move constructor, + // so this move constructor will never throw a exception. + new (&dest.stack) T(std::move(reinterpret_cast(src.stack))); + destroy(src); + } + + static void swap(storage_union& lhs, storage_union& rhs) noexcept + { + storage_union tmp_storage; + move(rhs, tmp_storage); + move(lhs, rhs); + move(tmp_storage, lhs); + } + }; + + /// Whether the type T must be dynamically allocated or can be stored on the stack. + template + struct requires_allocation : + std::integral_constant::value // N4562 §6.3/3 [any.class] + && sizeof(T) <= sizeof(storage_union::stack) + && std::alignment_of::value <= std::alignment_of::value)> + {}; + + /// Returns the pointer to the vtable of the type T. + template + static vtable_type* vtable_for_type() + { + using VTableType = typename std::conditional::value, vtable_dynamic, vtable_stack>::type; + static vtable_type table = { +#ifndef ANY_IMPL_NO_RTTI + VTableType::type, +#endif + VTableType::destroy, + VTableType::copy, VTableType::move, + VTableType::swap, + }; + return &table; + } + +protected: + template + friend const T* any_cast(const any* operand) noexcept; + template + friend T* any_cast(any* operand) noexcept; + +#ifndef ANY_IMPL_NO_RTTI + /// Same effect as is_same(this->type(), t); + bool is_typed(const std::type_info& t) const + { + return is_same(this->type(), t); + } +#endif + +#ifndef ANY_IMPL_NO_RTTI + /// Checks if two type infos are the same. + /// + /// If ANY_IMPL_FAST_TYPE_INFO_COMPARE is defined, checks only the address of the + /// type infos, otherwise does an actual comparision. Checking addresses is + /// only a valid approach when there's no interaction with outside sources + /// (other shared libraries and such). + static bool is_same(const std::type_info& a, const std::type_info& b) + { +#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE + return &a == &b; +#else + return a == b; +#endif + } +#endif + + /// Casts (with no type_info checks) the storage pointer as const T*. + template + const T* cast() const noexcept + { + return requires_allocation::type>::value? + reinterpret_cast(storage.dynamic) : + reinterpret_cast(&storage.stack); + } + + /// Casts (with no type_info checks) the storage pointer as T*. + template + T* cast() noexcept + { + return requires_allocation::type>::value? + reinterpret_cast(storage.dynamic) : + reinterpret_cast(&storage.stack); + } + +private: + storage_union storage; // on offset(0) so no padding for align + vtable_type* vtable; + + template + typename std::enable_if::value>::type + do_construct(ValueType&& value) + { + storage.dynamic = new T(std::forward(value)); + } + + template + typename std::enable_if::value>::type + do_construct(ValueType&& value) + { + new (&storage.stack) T(std::forward(value)); + } + + /// Chooses between stack and dynamic allocation for the type decay_t, + /// assigns the correct vtable, and constructs the object on our storage. + template + void construct(ValueType&& value) + { + using T = typename std::decay::type; + + this->vtable = vtable_for_type(); + + do_construct(std::forward(value)); + } +}; + + + +namespace detail +{ + template + inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::true_type) + { + return std::move(*p); + } + + template + inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::false_type) + { + return *p; + } +} + +/// Performs *any_cast>>(&operand), or throws bad_any_cast on failure. +template +inline ValueType any_cast(const any& operand) +{ + auto p = any_cast::type>::type>(&operand); +#ifndef ANY_IMPL_NO_EXCEPTIONS + if(p == nullptr) throw bad_any_cast(); +#endif + return *p; +} + +/// Performs *any_cast>(&operand), or throws bad_any_cast on failure. +template +inline ValueType any_cast(any& operand) +{ + auto p = any_cast::type>(&operand); +#ifndef ANY_IMPL_NO_EXCEPTIONS + if(p == nullptr) throw bad_any_cast(); +#endif + return *p; +} + +/// +/// If ValueType is MoveConstructible and isn't a lvalue reference, performs +/// std::move(*any_cast>(&operand)), otherwise +/// *any_cast>(&operand). Throws bad_any_cast on failure. +/// +template +inline ValueType any_cast(any&& operand) +{ + using can_move = std::integral_constant::value + && !std::is_lvalue_reference::value>; + + auto p = any_cast::type>(&operand); +#ifndef ANY_IMPL_NO_EXCEPTIONS + if(p == nullptr) throw bad_any_cast(); +#endif + return detail::any_cast_move_if_true(p, can_move()); +} + +/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object +/// contained by operand, otherwise nullptr. +template +inline const ValueType* any_cast(const any* operand) noexcept +{ + using T = typename std::decay::type; + +#ifndef ANY_IMPL_NO_RTTI + if (operand && operand->is_typed(typeid(T))) +#else + if (operand && operand->vtable == any::vtable_for_type()) +#endif + return operand->cast(); + else + return nullptr; +} + +/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object +/// contained by operand, otherwise nullptr. +template +inline ValueType* any_cast(any* operand) noexcept +{ + using T = typename std::decay::type; + +#ifndef ANY_IMPL_NO_RTTI + if (operand && operand->is_typed(typeid(T))) +#else + if (operand && operand->vtable == any::vtable_for_type()) +#endif + return operand->cast(); + else + return nullptr; +} + +} + +namespace std +{ + inline void swap(linb::any& lhs, linb::any& rhs) noexcept + { + lhs.swap(rhs); + } +} + +#endif diff --git a/test/filelist.maf b/test/filelist.maf index d92cabd9d..0cb25cee8 100644 --- a/test/filelist.maf +++ b/test/filelist.maf @@ -1,3 +1,5 @@ +HEADERS +any.hpp SOURCES test_buffer.cpp diff --git a/test/test_listen_callback.cpp b/test/test_listen_callback.cpp index c8a441273..7abe6916a 100644 --- a/test/test_listen_callback.cpp +++ b/test/test_listen_callback.cpp @@ -183,8 +183,12 @@ int SrtTestListenCallback(void* opaq, SRTSOCKET ns SRT_ATR_UNUSED, int hsversion #if SRT_ENABLE_ENCRYPTION cerr << "TEST: Setting password '" << exp_pw << "' as per user '" << username << "'\n"; - srt_setsockflag(ns, SRTO_PASSPHRASE, exp_pw.c_str(), exp_pw.size()); + EXPECT_EQ(srt_setsockflag(ns, SRTO_PASSPHRASE, exp_pw.c_str(), exp_pw.size()), SRT_SUCCESS); #endif + + // Checking that SRTO_RCVLATENCY (PRE option) can be altered in the listener callback. + int optval = 200; + EXPECT_EQ(srt_setsockflag(ns, SRTO_RCVLATENCY, &optval, sizeof optval), SRT_SUCCESS); return 0; } diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index d2e1da704..47700c9a6 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -13,9 +13,11 @@ #include #include #include +#include // SRT includes -#include +#include "any.hpp" +#include "socketconfig.h" #include "srt.h" using namespace std; @@ -36,15 +38,26 @@ class TestSocketOptions } public: - void StartListener() + void BindListener() { // Specify address of the listener sockaddr* psa = (sockaddr*)&m_sa; ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR); + } + + void StartListener() + { + BindListener(); srt_listen(m_listen_sock, 1); } + int Connect() + { + sockaddr* psa = (sockaddr*)&m_sa; + return srt_connect(m_caller_sock, psa, sizeof m_sa); + } + SRTSOCKET EstablishConnection() { auto accept_async = [](SRTSOCKET listen_sock) { @@ -55,8 +68,7 @@ class TestSocketOptions }; auto accept_res = async(launch::async, accept_async, m_listen_sock); - sockaddr* psa = (sockaddr*)&m_sa; - const int connect_res = srt_connect(m_caller_sock, psa, sizeof m_sa); + const int connect_res = Connect(); EXPECT_EQ(connect_res, SRT_SUCCESS); const SRTSOCKET accepted_sock = accept_res.get(); @@ -108,6 +120,584 @@ class TestSocketOptions }; +enum class RestrictionType +{ + PREBIND = 0, + PRE = 1, + POST = 2 +}; + +const char* RestrictionTypeStr(RestrictionType val) +{ + switch (val) + { + case RestrictionType::PREBIND: + return "PREBIND"; + break; + case RestrictionType::PRE: + return "PRE"; + break; + case RestrictionType::POST: + return "POST"; + break; + default: + break; + } + return "INVALID"; +} + +struct OptionTestEntry +{ + SRT_SOCKOPT optid; + const char* optname; // TODO: move to a separate array, function or std::map. + RestrictionType restriction; // TODO: consider using SRTO_R_PREBIND, etc. from core.cpp + size_t opt_len; + linb::any min_val; + linb::any max_val; + linb::any dflt_val; + linb::any ndflt_val; + vector invalid_vals; +}; + +static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }. +static const size_t DFT_MTU_SIZE = 1500; // Default MTU size +static const size_t SRT_PKT_SIZE = DFT_MTU_SIZE - UDP_HDR_SIZE; // MTU without UDP header + +const OptionTestEntry g_test_matrix_options[] = +{ + // Option ID, Option Name | Restriction | optlen | min | max | default | nondefault | invalid vals | + //SRTO_BINDTODEVICE + //{ SRTO_CONGESTION, "SRTO_CONGESTION", RestrictionType::PRE, 4, "live", "file", "live", "file", {"liv", ""} }, + { SRTO_CONNTIMEO, "SRTO_CONNTIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 3000, 250, {-1} }, + { SRTO_DRIFTTRACER, "SRTO_DRIFTTRACER", RestrictionType::POST, sizeof(bool), false, true, true, false, {} }, + { SRTO_ENFORCEDENCRYPTION, "SRTO_ENFORCEDENCRYPTION", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, + //SRTO_EVENT + { SRTO_FC, "SRTO_FC", RestrictionType::PRE, sizeof(int), 32, INT32_MAX, 25600, 10000, {-1, 31} }, + //SRTO_GROUPCONNECT + //SRTO_GROUPSTABTIMEO + //SRTO_GROUPTYPE + //SRTO_INPUTBW + //SRTO_IPTOS + //SRTO_IPTTL + //SRTO_IPV6ONLY + //SRTO_ISN + { SRTO_KMPREANNOUNCE, "SRTO_KMPREANNOUNCE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1} }, + { SRTO_KMREFRESHRATE, "SRTO_KMREFRESHRATE", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 1024, {-1} }, + //SRTO_KMSTATE + { SRTO_LATENCY, "SRTO_LATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 200, {-1} }, + //SRTO_LINGER + { SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", RestrictionType::POST, sizeof(int), 0, INT32_MAX, 0, 10, {} }, + //SRTO_MAXBW + { SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, + //SRTO_MININPUTBW + { SRTO_MINVERSION, "SRTO_MINVERSION", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0x010000, 0x010300, {} }, + { SRTO_MSS, "SRTO_MSS", RestrictionType::PREBIND, sizeof(int), 76, 65536, 1500, 1400, {-1, 0, 75} }, + { SRTO_NAKREPORT, "SRTO_NAKREPORT", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, + { SRTO_OHEADBW, "SRTO_OHEADBW", RestrictionType::POST, sizeof(int), 5, 100, 25, 20, {-1, 0, 4, 101} }, + //SRTO_PACKETFILTER + //SRTO_PASSPHRASE + { SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", RestrictionType::PRE, sizeof(int), 0, 1456, 1316, 1400, {-1, 1500} }, + //SRTO_PBKEYLEN + //SRTO_PEERIDLETIMEO + { SRTO_PEERIDLETIMEO, "SRTO_PEERIDLETIMEO", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 5000, 4500, {-1} }, + { SRTO_PEERLATENCY, "SRTO_PEERLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 0, 180, {-1} }, + //SRTO_PEERVERSION + { SRTO_RCVBUF, "SRTO_RCVBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} }, + //SRTO_RCVDATA + //SRTO_RCVKMSTATE + { SRTO_RCVLATENCY, "SRTO_RCVLATENCY", RestrictionType::PRE, sizeof(int), 0, INT32_MAX, 120, 1100, {-1} }, + //SRTO_RCVSYN + { SRTO_RCVTIMEO, "SRTO_RCVTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 2000, {-2} }, + //SRTO_RENDEZVOUS + //SRTO_RETRANSMITALGO + //SRTO_REUSEADDR + //SRTO_SENDER + { SRTO_SNDBUF, "SRTO_SNDBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} }, + //SRTO_SNDDATA + { SRTO_SNDDROPDELAY, "SRTO_SNDDROPDELAY", RestrictionType::POST, sizeof(int), -1, INT32_MAX, 0, 1500, {-2} }, + //SRTO_SNDKMSTATE + //SRTO_SNDSYN + { SRTO_SNDTIMEO, "SRTO_SNDTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 1400, {-2} }, + //SRTO_STATE + //SRTO_STREAMID + { SRTO_TLPKTDROP, "SRTO_TLPKTDROP", RestrictionType::PRE, sizeof(bool), false, true, true, false, {} }, + //SRTO_TRANSTYPE + //SRTO_TSBPDMODE + //SRTO_UDP_RCVBUF + //SRTO_UDP_SNDBUF + //SRTO_VERSION +}; + + +template +void CheckGetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueType& value, const char* desc) +{ + ValueType opt_val; + int opt_len = 0; + EXPECT_EQ(srt_getsockopt(sock, 0, entry.optid, &opt_val, &opt_len), SRT_SUCCESS) + << "Getting " << entry.optname << " returned error: " << srt_getlasterror_str(); + + EXPECT_EQ(opt_val, value) << desc << ": Wrong " << entry.optname << " value " << opt_val; + EXPECT_EQ(opt_len, entry.opt_len) << desc << "Wrong " << entry.optname << " value length"; +} + +typedef char const* strptr; +template<> +void CheckGetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const strptr& value, const char* desc) +{ + char opt_val[16]; + int opt_len = 0; + EXPECT_EQ(srt_getsockopt(sock, 0, entry.optid, &opt_val, &opt_len), SRT_SUCCESS) + << "Getting " << entry.optname << " returned error: " << srt_getlasterror_str(); + + EXPECT_EQ(strncmp(opt_val, value, min(opt_len, entry.opt_len)), 0) << desc << ": Wrong " << entry.optname << " value " << opt_val; + EXPECT_EQ(opt_len, entry.opt_len) << desc << "Wrong " << entry.optname << " value length"; +} + +template +void CheckSetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueType& value, int expect_return, const char* desc) +{ + ValueType opt_val = value; + int opt_len = entry.opt_len; + EXPECT_EQ(srt_setsockopt(sock, 0, entry.optid, &opt_val, opt_len), expect_return) + << "Setting " << entry.optname << " to " << opt_val << " must " << (expect_return == SRT_SUCCESS ? "succeed" : "fail"); + + if (expect_return == SRT_SUCCESS) + { + CheckGetSockOpt(entry, sock, value, desc); + } + // TODO: else check the previous value is in force +} + +template +bool CheckDefaultValue(const OptionTestEntry& entry, SRTSOCKET sock, const char* desc) +{ + try { + const ValueType dflt_val = linb::any_cast(entry.dflt_val); + CheckGetSockOpt(entry, sock, dflt_val, desc); + } + catch (const linb::bad_any_cast&) + { + std::cerr << entry.optname << " default value type: " << entry.dflt_val.type().name() << "\n"; + return false; + } + + return true; +} + +template +bool CheckSetNonDefaultValue(const OptionTestEntry& entry, SRTSOCKET sock, int expected_return, const char* desc) +{ + try { + /*const ValueType dflt_val = linb::any_cast(entry.dflt_val); + const ValueType min_val = linb::any_cast(entry.min_val); + const ValueType max_val = linb::any_cast(entry.max_val);*/ + //const ValueType ndflt_val = (min_val != dflt_val) ? min_val : max_val; + + const ValueType ndflt_val = linb::any_cast(entry.ndflt_val);; + + CheckSetSockOpt(entry, sock, ndflt_val, expected_return, desc); + } + catch (const linb::bad_any_cast&) + { + std::cerr << entry.optname << " non-default value type: " << entry.ndflt_val.type().name() << "\n"; + return false; + } + + return true; +} + +template +bool CheckMinValue(const OptionTestEntry& entry, SRTSOCKET sock, const char* desc) +{ + try { + const ValueType min_val = linb::any_cast(entry.min_val); + CheckSetSockOpt(entry, sock, min_val, SRT_SUCCESS, desc); + + const ValueType dflt_val = linb::any_cast(entry.dflt_val); + CheckSetSockOpt(entry, sock, dflt_val, SRT_SUCCESS, desc); + } + catch (const linb::bad_any_cast&) + { + std::cerr << entry.optname << " min value type: " << entry.min_val.type().name() << "\n"; + return false; + } + + return true; +} + +template +bool CheckMaxValue(const OptionTestEntry& entry, SRTSOCKET sock, const char* desc) +{ + try { + const ValueType max_val = linb::any_cast(entry.max_val); + CheckSetSockOpt(entry, sock, max_val, SRT_SUCCESS, desc); + } + catch (const linb::bad_any_cast&) + { + std::cerr << entry.optname << " max value type: " << entry.max_val.type().name() << "\n"; + return false; + } + + return true; +} + +template +bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char* sock_name) +{ + for (const auto inval : entry.invalid_vals) + { + try { + const ValueType val = linb::any_cast(inval); + CheckSetSockOpt(entry, sock, val, SRT_ERROR, "[Caller, invalid val]"); + } + catch (const linb::bad_any_cast&) + { + std::cerr << entry.optname << " value type: " << inval.type().name() << "\n"; + return false; + } + } + + return true; +} + +TEST_F(TestSocketOptions, DefaultVals) +{ + for (const auto& entry : g_test_matrix_options) + { + const char* test_desc = "[Caller, default]"; + if (entry.dflt_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + } + else if (entry.dflt_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + } + else if (entry.dflt_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + } + else if (entry.dflt_val.type() == typeid(const char*)) + { + EXPECT_TRUE(CheckDefaultValue(entry, m_caller_sock, test_desc)); + } + else + { + FAIL() << entry.optname << ": Unexpected type " << entry.dflt_val.type().name(); + } + } +} + +TEST_F(TestSocketOptions, MaxVals) +{ + // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation + for (const auto& entry : g_test_matrix_options) + { + if (entry.optid == SRTO_KMPREANNOUNCE || entry.optid == SRTO_KMREFRESHRATE) + { + cerr << "Skipping " << entry.optname << "\n"; + continue; + } + + const char* test_desc = "[Caller, max value]"; + if (entry.max_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckMaxValue(entry, m_caller_sock, test_desc)); + } + else if (entry.max_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckMaxValue(entry, m_caller_sock, test_desc)); + } + else if (entry.max_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckMaxValue(entry, m_caller_sock, test_desc)); + } + else + { + FAIL() << "Unexpected type " << entry.max_val.type().name(); + } + + // TODO: back to default ? + } +} + +TEST_F(TestSocketOptions, MinVals) +{ + // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation + for (const auto& entry : g_test_matrix_options) + { + const char* test_desc = "[Caller, min val]"; + if (entry.min_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckMinValue(entry, m_caller_sock, test_desc)); + } + else if (entry.min_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckMinValue(entry, m_caller_sock, test_desc)); + } + else if (entry.min_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckMinValue(entry, m_caller_sock, test_desc)); + } + else + { + FAIL() << entry.optname << ": Unexpected type " << entry.min_val.type().name(); + } + + // TODO: back to default + } +} + +TEST_F(TestSocketOptions, InvalidVals) +{ + // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation + for (const auto& entry : g_test_matrix_options) + { + if (entry.dflt_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + } + else if (entry.dflt_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + } + else if (entry.dflt_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + } + else + { + FAIL() << "Unexpected type " << entry.dflt_val.type().name(); + } + + // TODO: expect default is still in force? + } +} + + + +// TODO: taken from test_enforced_encryption +static const char* const socket_state_array[] = { + "IGNORE_SRTS", + "SRTS_INVALID", + "SRTS_INIT", + "SRTS_OPENED", + "SRTS_LISTENING", + "SRTS_CONNECTING", + "SRTS_CONNECTED", + "SRTS_BROKEN", + "SRTS_CLOSING", + "SRTS_CLOSED", + "SRTS_NONEXIST" +}; + +// A trick that allows the array to be indexed by -1 +const char* const* g_socket_state = socket_state_array + 1; + +#if 0 +// No socket option can be set in blocking mode because m_ConnectionLock is required by both srt_setsockopt and srt_connect +// TODO: Use non-blocking mode +TEST_F(TestSocketOptions, RestrictionCallerConnecting) +{ + // The default SRTO_CONNTIMEO is 3 seconds. It is assumed all socket options could be checked. + auto connect_async = [this]() { + return Connect(); + }; + auto connect_res = async(launch::async, connect_async); + + for (int i = 0; i < 100; ++i) + { + if (srt_getsockstate(m_caller_sock) == SRTS_CONNECTING) + break; + + this_thread::sleep_for(chrono::microseconds(100)); + } + + cout << "Running test\n"; + + for (const auto& entry : g_test_matrix_options) + { + if (entry.restriction != RestrictionType::PRE) + continue; + + // Setting a valid minimum value + EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, entry.optid, &entry.min_val, entry.opt_len), SRT_ERROR) + << "Setting " << entry.optname << " (PRE) must not succeed while connecting. Sock state: " << g_socket_state[srt_getsockstate(m_caller_sock)]; + } + + connect_res.get(); +} +#endif + +TEST_F(TestSocketOptions, RestrictionBind) +{ + BindListener(); + + for (const auto& entry : g_test_matrix_options) + { + const char* test_desc = "[Caller, after bind]"; + const int expected_res = (entry.restriction == RestrictionType::PREBIND) ? SRT_ERROR : SRT_SUCCESS; + + if (entry.dflt_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << "Sock state : " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else if (entry.dflt_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << "Sock state : " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else if (entry.dflt_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << "Sock state : " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else + { + FAIL() << "Unexpected type " << entry.dflt_val.type().name(); + } + } +} + +// Check that only socket option with POST binding can be set on a listener socket in "listening" state. +TEST_F(TestSocketOptions, RestrictionListening) +{ + StartListener(); + + for (const auto& entry : g_test_matrix_options) + { + const int expected_res = (entry.restriction != RestrictionType::POST) ? SRT_ERROR : SRT_SUCCESS; + + // Setting a valid minimum value + const char* test_desc ="[Listener, listening]"; + + if (entry.dflt_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else if (entry.dflt_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else if (entry.dflt_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, m_listen_sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(m_listen_sock)]; + } + else + { + FAIL() << "Unexpected type " << entry.dflt_val.type().name(); + } + } +} + +// Check that only socket option with POST binding can be set on a connected socket (caller and accepted). +TEST_F(TestSocketOptions, RestrictionConnected) +{ + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + for (const auto& entry : g_test_matrix_options) + { + const int expected_res = (entry.restriction != RestrictionType::POST) ? SRT_ERROR : SRT_SUCCESS; + + // Setting a valid minimum value + for (SRTSOCKET sock : { m_caller_sock, accepted_sock }) + { + const char* test_desc = sock == m_caller_sock ? "[Caller, connected]" : "[Accepted, connected]"; + + if (entry.dflt_val.type() == typeid(bool)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(sock)]; + } + else if (entry.dflt_val.type() == typeid(int)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(sock)]; + } + else if (entry.dflt_val.type() == typeid(int64_t)) + { + EXPECT_TRUE(CheckSetNonDefaultValue(entry, sock, expected_res, test_desc)) + << test_desc << entry.optname << " Sock state: " << g_socket_state[srt_getsockstate(sock)]; + } + else + { + FAIL() << "Unexpected type " << entry.dflt_val.type().name(); + } + } + } +} + +// TODO: TEST_F(TestSocketOptions, CheckInheritedAfterConnection) +// Check that accepted socket has correct socket option values. +// Check setting and getting SRT_MININPUTBW +TEST_F(TestSocketOptions, TLPktDropInherits) +{ + const bool tlpktdrop_dflt = true; + const bool tlpktdrop_new = false; + + bool optval = tlpktdrop_dflt; + int optlen = (int)(sizeof optval); + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_TLPKTDROP, &tlpktdrop_new, sizeof tlpktdrop_new), SRT_SUCCESS); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_TLPKTDROP, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, tlpktdrop_new); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check accepted socket inherits values + for (SRTSOCKET sock : { m_listen_sock, accepted_sock }) + { + optval = tlpktdrop_dflt; + optlen = (int)(sizeof optval); + EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_TLPKTDROP, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optlen, (int)(sizeof optval)); + EXPECT_EQ(optval, tlpktdrop_new); + } + + this_thread::sleep_for(chrono::seconds(2)); + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + +TEST_F(TestSocketOptions, Latency) +{ + const int latency_a = 140; + const int latency_b = 100; + const int latency_dflt = 120; + + int optval; + int optlen = (int)(sizeof optval); + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVLATENCY, &latency_a, sizeof latency_a), SRT_SUCCESS); + EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_PEERLATENCY, &latency_b, sizeof latency_b), SRT_SUCCESS); + + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_RCVLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_a); + EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_PEERLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_b); + + StartListener(); + const SRTSOCKET accepted_sock = EstablishConnection(); + + // Check caller socket + EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_RCVLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_dflt); + EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_PEERLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_a); + + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_RCVLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_a); + EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_PEERLATENCY, &optval, &optlen), SRT_SUCCESS); + EXPECT_EQ(optval, latency_dflt); + + ASSERT_NE(srt_close(accepted_sock), SRT_ERROR); +} + /// A regression test for issue #735, fixed by PR #843. /// Checks propagation of listener's socket option SRTO_LOSSMAXTTL /// on SRT sockets being accepted. From 8f169a9445a52f27f074cbc7b5f2bf92dd24e8e2 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 3 Aug 2021 12:19:13 +0200 Subject: [PATCH 050/124] [core] Changed the default SRTO_RETRANSMITALGO to 1 (#2069) SRTO_TRANSTYPE defaults are updated accordingly. --- docs/API/API-socket-options.md | 8 +++---- docs/API/API.md | 38 ++++++++++++++++++++-------------- srtcore/socketconfig.cpp | 8 ++++++- srtcore/socketconfig.h | 2 +- test/test_socket_options.cpp | 2 +- 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index b87d80ab0..84606135a 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -239,7 +239,7 @@ The following table lists SRT API socket options in alphabetical order. Option d | [`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` | | 0 | [0, 1] | RW | GSD | +| [`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+ | @@ -1275,12 +1275,12 @@ procedure of `srt_bind` and then `srt_connect` (or `srt_rendezvous`) to one anot | OptName | Since | Restrict | Type | Units | Default | Range | Dir | Entity | | --------------------- | ----- | -------- | --------- | ------ | ------- | ------ | --- | ------ | -| `SRTO_RETRANSMITALGO` | 1.4.2 | pre | `int32_t` | | 0 | [0, 1] | RW | GSD | +| `SRTO_RETRANSMITALGO` | 1.4.2 | pre | `int32_t` | | 1 | [0, 1] | RW | GSD | Retransmission algorithm to use (SENDER option): -- 0 - Default (retransmit on every loss report). -- 1 - Reduced retransmissions (not more often than once per RTT); reduced +- 0 - Retransmit on every loss report (higher overhead, but slightly higher chance to recover a lost packet). +- 1 - Reduced retransmissions (retransmit not more often than once per RTT); reduced bandwidth consumption. This option is effective only on the sending side. It influences the decision diff --git a/docs/API/API.md b/docs/API/API.md index 594f9a12d..faca780c7 100644 --- a/docs/API/API.md +++ b/docs/API/API.md @@ -521,14 +521,15 @@ either `FASTREXMIT` or `LATEREXMIT`. This will be explained below. Setting `SRTO_TRANSTYPE` to `SRTT_LIVE` sets the following [socket options](API-socket-options.md): -- `SRTO_TSBPDMODE` = true -- `SRTO_RCVLATENCY` = 120 -- `SRTO_PEERLATENCY` = 0 -- `SRTO_TLPKTDROP` = true -- `SRTO_MESSAGEAPI` = true -- `SRTO_NAKREPORT` = true -- `SRTO_PAYLOADSIZE` = 1316 -- `SRTO_CONGESTION` = "live" +- [`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_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 @@ -580,6 +581,10 @@ 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 @@ -598,14 +603,15 @@ NAKREPORT method is considered so effective that FASTREXMIT isn't necessary. Setting `SRTO_TRANSTYPE` to `SRTT_FILE` sets the following [socket options](API-socket-options.md): -- `SRTO_TSBPDMODE` = false -- `SRTO_RCVLATENCY` = 0 -- `SRTO_PEERLATENCY` = 0 -- `SRTO_TLPKTDROP` = false -- `SRTO_MESSAGEAPI` = false -- `SRTO_NAKREPORT` = false -- `SRTO_PAYLOADSIZE` = 0 -- `SRTO_CONGESTION` = "file" +- [`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_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 diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index 2fcc475b2..a62881cd7 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -656,6 +656,7 @@ struct CSrtConfigSetter co.iSndDropDelay = 0; co.bMessageAPI = true; co.bRcvNakReport = true; + co.iRetransmitAlgo = 1; co.zExpPayloadSize = SRT_LIVE_DEF_PLSIZE; co.Linger.l_onoff = 0; co.Linger.l_linger = 0; @@ -676,6 +677,7 @@ struct CSrtConfigSetter co.iSndDropDelay = -1; co.bMessageAPI = false; co.bRcvNakReport = false; + co.iRetransmitAlgo = 0; co.zExpPayloadSize = 0; // use maximum co.Linger.l_onoff = 1; co.Linger.l_linger = CSrtConfig::DEF_LINGER_S; @@ -869,7 +871,11 @@ struct CSrtConfigSetter { static void set(CSrtConfig& co, const void* optval, int optlen) { - co.iRetransmitAlgo = cast_optval(optval, optlen); + const int val = cast_optval(optval, optlen); + if (val < 0 || val > 1) + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + + co.iRetransmitAlgo = val; } }; diff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h index a9d2a0856..3e41077d3 100644 --- a/srtcore/socketconfig.h +++ b/srtcore/socketconfig.h @@ -271,7 +271,7 @@ struct CSrtConfig: CSrtMuxerConfig , iGroupConnect(0) , iPeerIdleTimeout(COMM_RESPONSE_TIMEOUT_MS) , uStabilityTimeout(COMM_DEF_STABILITY_TIMEOUT_US) - , iRetransmitAlgo(0) + , iRetransmitAlgo(1) , llInputBW(0) , llMinInputBW(0) , iOverheadBW(25) diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index 47700c9a6..bf37513ce 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -209,7 +209,7 @@ const OptionTestEntry g_test_matrix_options[] = //SRTO_RCVSYN { SRTO_RCVTIMEO, "SRTO_RCVTIMEO", RestrictionType::POST, sizeof(int), -1, INT32_MAX, -1, 2000, {-2} }, //SRTO_RENDEZVOUS - //SRTO_RETRANSMITALGO + { SRTO_RETRANSMITALGO, "SRTO_RETRANSMITALGO", RestrictionType::PRE, sizeof(int), 0, 1, 1, 0, {-1, 2} }, //SRTO_REUSEADDR //SRTO_SENDER { SRTO_SNDBUF, "SRTO_SNDBUF", RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} }, From 1a85c029af0c89c7d37f9cf71731bd551db3ec5c Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 3 Aug 2021 12:39:58 +0200 Subject: [PATCH 051/124] [core] Annotating CUDT::m_pCryptoControl locking behavior (#2070) --- srtcore/core.cpp | 11 ++++------- srtcore/core.h | 22 ++++++++++++++++------ srtcore/sync.h | 2 +- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 75c0171ae..cf01d9e35 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -1497,14 +1497,11 @@ bool srt::CUDT::createSrtHandshake( w_hs.m_iType |= CHandShake::HS_EXT_HSREQ; bool have_sid = false; - if (srths_cmd == SRT_CMD_HSREQ) + if (srths_cmd == SRT_CMD_HSREQ && !m_config.sStreamName.empty()) { - if (!m_config.sStreamName.empty()) - { - have_sid = true; - w_hs.m_iType |= CHandShake::HS_EXT_CONFIG; - logext << ",SID"; - } + have_sid = true; + w_hs.m_iType |= CHandShake::HS_EXT_CONFIG; + logext << ",SID"; } // If this is a response, we have also information diff --git a/srtcore/core.h b/srtcore/core.h index d190780a0..9a1ad01f0 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -302,6 +302,8 @@ class CUDT static std::vector existingSockets(); void addressAndSend(CPacket& pkt); + + SRT_ATTR_REQUIRES(m_ConnectionLock) void sendSrtMsg(int cmd, uint32_t *srtdata_in = NULL, size_t srtlen_in = 0); bool isOPT_TsbPd() const { return m_config.bTSBPD; } @@ -457,7 +459,8 @@ class CUDT /// @retval 1 Connection in progress (m_ConnReq turned into RESPONSE) /// @retval -1 Connection failed - SRT_ATR_NODISCARD EConnectStatus processConnectResponse(const CPacket& pkt, CUDTException* eout) ATR_NOEXCEPT; + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + EConnectStatus processConnectResponse(const CPacket& pkt, CUDTException* eout) ATR_NOEXCEPT; // This function works in case of HSv5 rendezvous. It changes the state // according to the present state and received message type, as well as the @@ -476,9 +479,15 @@ class CUDT /// @param response incoming handshake response packet to be interpreted /// @param serv_addr incoming packet's address /// @param rst Current read status to know if the HS packet was freshly received from the peer, or this is only a periodic update (RST_AGAIN) - SRT_ATR_NODISCARD EConnectStatus processRendezvous(const CPacket* response, const sockaddr_any& serv_addr, EReadStatus, CPacket& reqpkt); - SRT_ATR_NODISCARD bool prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout); - SRT_ATR_NODISCARD EConnectStatus postConnect(const CPacket* response, bool rendezvous, CUDTException* eout) ATR_NOEXCEPT; + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + EConnectStatus processRendezvous(const CPacket* response, const sockaddr_any& serv_addr, EReadStatus, CPacket& reqpkt); + + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + bool prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout); + + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + EConnectStatus postConnect(const CPacket* response, bool rendezvous, CUDTException* eout) ATR_NOEXCEPT; + SRT_ATR_NODISCARD bool applyResponseSettings() ATR_NOEXCEPT; SRT_ATR_NODISCARD EConnectStatus processAsyncConnectResponse(const CPacket& pkt) ATR_NOEXCEPT; SRT_ATR_NODISCARD bool processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, const CPacket* response, const sockaddr_any& serv_addr); @@ -708,7 +717,8 @@ class CUDT int m_iTsbPdDelay_ms; // Rx delay to absorb burst, in milliseconds int m_iPeerTsbPdDelay_ms; // Tx delay that the peer uses to absorb burst, in milliseconds bool m_bTLPktDrop; // Enable Too-late Packet Drop - UniquePtr m_pCryptoControl; // Congestion control SRT class (small data extension) + SRT_ATTR_PT_GUARDED_BY(m_ConnectionLock) + UniquePtr m_pCryptoControl; // Crypto control module CCache* m_pCache; // Network information cache // Congestion control @@ -932,7 +942,7 @@ class CUDT // Failure to create the crypter means that an encrypted // connection should be rejected if ENFORCEDENCRYPTION is on. - SRT_ATR_NODISCARD + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) bool createCrypter(HandshakeSide side, bool bidi); private: // Generation and processing of packets diff --git a/srtcore/sync.h b/srtcore/sync.h index 081cb41e4..d78aed980 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -446,7 +446,7 @@ class SRT_ATTR_SCOPED_CAPABILITY UniqueLock inline void enterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) { m.lock(); } -inline bool tryEnterCS(Mutex& m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); } +inline bool tryEnterCS(Mutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); } inline void leaveCS(Mutex& m) SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) { m.unlock(); } From 73cad8dab15035d5f320a7e8869d7986649cbc8e Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Mon, 29 Mar 2021 20:07:48 +0800 Subject: [PATCH 052/124] [core] Refactor ThreadName implementation * Add support for macOS and iOS * Add test_threadname --- srtcore/threadname.h | 182 ++++++++++++++++++++++++++++----------- test/filelist.maf | 1 + test/test_threadname.cpp | 61 +++++++++++++ 3 files changed, 192 insertions(+), 52 deletions(-) create mode 100644 test/test_threadname.cpp diff --git a/srtcore/threadname.h b/srtcore/threadname.h index 38fea471b..6fd901aff 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -1,11 +1,11 @@ /* * 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/. - * + * */ /***************************************************************************** @@ -16,85 +16,163 @@ written by #ifndef INC_SRT_THREADNAME_H #define INC_SRT_THREADNAME_H -#ifdef __linux__ - +#if defined(__APPLE__) || defined(__linux__) +#if defined(__linux__) #include +#endif + +#include +#endif + #include +#include +#include + +#include "sync.h" class ThreadName { - char old_name[128]; - char new_name[128]; - bool good; -public: - static const size_t BUFSIZE = 128; +#if defined(__APPLE__) || defined(__linux__) - static bool get(char* namebuf) + class ThreadNameImpl { - return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1; - } + public: + static const size_t BUFSIZE = 64; + static const bool DUMMY_IMPL = false; - static bool set(const char* name) - { - return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1; - } + static bool get(char* namebuf) + { +#if defined(__linux__) + // since Linux 2.6.11. The buffer should allow space for up to 16 + // bytes; the returned string will be null-terminated. + return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1; +#elif defined(__APPLE__) + // since macos(10.6), ios(3.2) + return pthread_getname_np(pthread_self(), namebuf, BUFSIZE) == 0; +#else +#error "unsupported platform" +#endif + } + static bool set(const char* name) + { +#if defined(__linux__) + // The name can be up to 16 bytes long, including the terminating + // null byte. (If the length of the string, including the terminating + // null byte, exceeds 16 bytes, the string is silently truncated.) + return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1; +#elif defined(__APPLE__) + // since macos(10.6), ios(3.2) + return pthread_setname_np(name) == 0; +#else +#error "unsupported platform" +#endif + } - ThreadName(const char* name) - { - if ( (good = get(old_name)) ) + ThreadNameImpl(const char* name) { - snprintf(new_name, 127, "%s", name); - new_name[127] = 0; - prctl(PR_SET_NAME, (unsigned long)new_name, 0, 0); + reset = false; + tid = pthread_self(); + + if (!get(old_name)) + return; + + reset = set(name); + if (reset) + return; + + // Try with a shorter name. 15 is the upper limit supported by Linux, + // other platforms should support a larger value. So 15 should works + // on all platforms. + size_t max_len = 15; + if (std::strlen(name) > max_len) + reset = set(std::string(name, max_len).c_str()); } - } - ~ThreadName() - { - if ( good ) - prctl(PR_SET_NAME, (unsigned long)old_name, 0, 0); - } -}; + ~ThreadNameImpl() + { + if (!reset) + return; + + // ensure it's called on the right thread + if (tid == pthread_self()) + set(old_name); + } + + private: + bool reset; + pthread_t tid; + char old_name[BUFSIZE]; + }; #else -#include "sync.h" + class ThreadNameImpl + { + public: + static const bool DUMMY_IMPL = true; + static const size_t BUFSIZE = 64; -// Fallback version, which simply reports the thread name as -// T, and custom names used with `set` are ignored. -// If you know how to implement this for other systems than -// Linux, you can make another conditional. This one is now -// the "ultimate fallback". + static bool get(char* output) + { + // The default implementation will simply try to get the thread ID + std::ostringstream bs; + bs << "T" << srt::sync::this_thread::get_id(); + size_t s = bs.str().copy(output, BUFSIZE - 1); + output[s] = '\0'; + return true; + } + + static bool set(const char*) { return false; } + + ThreadNameImpl(const char*) {} + + ~ThreadNameImpl() // just to make it "non-trivially-destructible" for compatibility with normal version + { + } + }; + +#endif // platform dependent impl + + // Why delegate to impl: + // 1. to make sure implementation on different platforms have the same interface. + // 2. it's simple to add some wrappers like get(const std::string &). + ThreadNameImpl impl; -class ThreadName -{ public: - static const size_t BUFSIZE = 128; + static const bool DUMMY_IMPL = ThreadNameImpl::DUMMY_IMPL; + static const size_t BUFSIZE = ThreadNameImpl::BUFSIZE; - static bool get(char* output) - { - // The default implementation will simply try to get the thread ID - std::ostringstream bs; - bs << "T" << srt::sync::this_thread::get_id(); - size_t s = bs.str().copy(output, BUFSIZE-1); - output[s] = '\0'; - return true; + // len should >= BUFSIZE + static bool get(char* output) { + return ThreadNameImpl::get(output); } - static bool set(const char*) { return false; } - ThreadName(const char*) + static bool get(std::string& name) { + char buf[BUFSIZE]; + bool ret = get(buf); + if (ret) + name = buf; + return ret; } - ~ThreadName() // just to make it "non-trivially-destructible" for compatibility with normal version + // note: set can fail if name is too long. The upper limit is platform + // dependent. strlen(name) <= 15 should work on most of the platform. + static bool set(const char* name) { return ThreadNameImpl::set(name); } + + static bool set(const std::string& name) { return set(name.c_str()); } + + ThreadName(const char* name) + : impl(name) { } + ThreadName(const std::string& name) + : impl(name.c_str()) + { + } }; - - -#endif #endif diff --git a/test/filelist.maf b/test/filelist.maf index 0cb25cee8..f39dfe2e6 100644 --- a/test/filelist.maf +++ b/test/filelist.maf @@ -19,6 +19,7 @@ test_muxer.cpp test_seqno.cpp test_socket_options.cpp test_sync.cpp +test_threadname.cpp test_timer.cpp test_unitqueue.cpp test_utilities.cpp diff --git a/test/test_threadname.cpp b/test/test_threadname.cpp new file mode 100644 index 000000000..f9b1d1d8c --- /dev/null +++ b/test/test_threadname.cpp @@ -0,0 +1,61 @@ +#include +#include + +#include "gtest/gtest.h" +#include "threadname.h" + +TEST(ThreadName, GetSet) +{ + std::string name("getset"); + char buf[ThreadName::BUFSIZE * 2]; + + memset(buf, 'a', sizeof(buf)); + ASSERT_EQ(ThreadName::get(buf), true); + // ensure doesn't write out-of-range + size_t max = ThreadName::BUFSIZE - 1; + ASSERT_LE(strlen(buf), max); + + if (ThreadName::DUMMY_IMPL) + return; + + ASSERT_EQ(ThreadName::set(name), true); + memset(buf, 'a', sizeof(buf)); + ASSERT_EQ(ThreadName::get(buf), true); + ASSERT_EQ(buf, name); +} + +TEST(ThreadName, AutoReset) +{ + std::string old_name("old"); + std::string new_name("new-name"); + if (ThreadName::DUMMY_IMPL) + { + // just make sure the API is correct + ThreadName t("test"); + return; + } + + ASSERT_EQ(ThreadName::set(old_name), true); + std::string name; + ASSERT_EQ(ThreadName::get(name), true); + ASSERT_EQ(name, old_name); + + { + ThreadName threadName(new_name); + ASSERT_EQ(ThreadName::get(name), true); + ASSERT_EQ(name, new_name); + } + + ASSERT_EQ(ThreadName::get(name), true); + ASSERT_EQ(name, old_name); + + { + new_name.resize(std::max(512, ThreadName::BUFSIZE * 2), 'z'); + ThreadName threadName(new_name); + ASSERT_EQ(ThreadName::get(name), true); + ASSERT_EQ(new_name.compare(0, name.size(), name), 0); + } + + ASSERT_EQ(ThreadName::get(name), true); + ASSERT_EQ(name, old_name); +} From d6f93a16f4adbbf5b85de23e72e2d84cebef053b Mon Sep 17 00:00:00 2001 From: quink-black Date: Wed, 4 Aug 2021 22:37:02 +0800 Subject: [PATCH 053/124] [core] Update srtcore/threadname.h Co-authored-by: Maxim Sharabayko --- srtcore/threadname.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/srtcore/threadname.h b/srtcore/threadname.h index 6fd901aff..2b3964276 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -144,7 +144,10 @@ class ThreadName static const bool DUMMY_IMPL = ThreadNameImpl::DUMMY_IMPL; static const size_t BUFSIZE = ThreadNameImpl::BUFSIZE; - // len should >= BUFSIZE + /// @brief Print thread ID to the provided buffer. + /// The size of the destination buffer is assumed to be at least ThreadName::BUFSIZE. + /// @param [out] output destination buffer to get thread name + /// @return true on success, false on failure static bool get(char* output) { return ThreadNameImpl::get(output); } From adba7afcea44db5a87debeb150760021108d9db1 Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Wed, 4 Aug 2021 23:04:36 +0800 Subject: [PATCH 054/124] [core] Use ThreadName::BUFSIZE in CreateLogLinePrefix() --- srtcore/common.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 389933b26..0e19dc611 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -595,16 +595,20 @@ void LogDispatcher::CreateLogLinePrefix(std::ostringstream& serr) { using namespace std; - char tmp_buf[512]; + SRT_STATIC_ASSERT(ThreadName::BUFSIZE >= sizeof("hh:mm:ss.") * 2, // multiply 2 for some margin + "ThreadName::BUFSIZE is too small to be used for strftime"); + char tmp_buf[ThreadName::BUFSIZE]; if ( !isset(SRT_LOGF_DISABLE_TIME) ) { // Not necessary if sending through the queue. timeval tv; - gettimeofday(&tv, 0); + gettimeofday(&tv, NULL); struct tm tm = SysLocalTime((time_t) tv.tv_sec); - strftime(tmp_buf, 512, "%X.", &tm); - serr << tmp_buf << setw(6) << setfill('0') << tv.tv_usec; + if (strftime(tmp_buf, sizeof(tmp_buf), "%X.", &tm)) + { + serr << tmp_buf << setw(6) << setfill('0') << tv.tv_usec; + } } string out_prefix; From 6dcbaf0eb302f7eec51a4f2dcb93d3d5855276ab Mon Sep 17 00:00:00 2001 From: Sergei Ignatov Date: Thu, 5 Aug 2021 18:07:49 +1000 Subject: [PATCH 055/124] [build] Cross-compile android from macOS host (#2071) --- configure-data.tcl | 15 +++++++++++-- scripts/build-android/build-android | 34 ++++++++++++++++++++++++----- scripts/build-android/mkssl | 9 ++++---- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/configure-data.tcl b/configure-data.tcl index 66902324a..5c0ee2ee7 100644 --- a/configure-data.tcl +++ b/configure-data.tcl @@ -343,8 +343,19 @@ proc postprocess {} { # Otherwise don't set PKG_CONFIG_PATH and we'll see. } - if { $::HAVE_DARWIN && !$toolchain_changed} { - + set use_brew 0 + if { $::HAVE_DARWIN && !$toolchain_changed } { + set use_brew 1 + } + 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] diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android index 3d69dac0c..0d56a8f01 100755 --- a/scripts/build-android/build-android +++ b/scripts/build-android/build-android @@ -52,11 +52,35 @@ else fi fi -# Determine the path of the executing script -BASE_DIR=$(readlink -f $0 | xargs dirname) +SCRIPT_DIR=$(pwd) +HOST_TAG='unknown' +unamestr=$(uname -s) +if [ "$unamestr" = 'Linux' ]; then + SCRIPT_DIR=$(readlink -f $0 | xargs dirname) + HOST_TAG='linux-x86_64' +elif [ "$unamestr" = 'Darwin' ]; then + SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) + if [ $(uname -p) = 'arm' ]; then + echo "NDK does not currently support ARM64" + exit 128 + else + HOST_TAG='darwin-x86_64' + fi +fi + +# Write files relative to current location +BASE_DIR=$(pwd) +case "${BASE_DIR}" in + *\ * ) + echo "Your path contains whitespaces, which is not supported by 'make install'." + exit 128 + ;; +esac +cd "${BASE_DIR}" if [ $ENC_LIB = 'openssl' ]; then - $BASE_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION + echo "Building OpenSSL $OPENSSL_VERSION" + $SCRIPT_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION -d $BASE_DIR -h $HOST_TAG elif [ $ENC_LIB = 'mbedtls' ]; then if [ ! -d $BASE_DIR/mbedtls ]; then git clone https://github.com/ARMmbed/mbedtls mbedtls @@ -83,13 +107,13 @@ for build_target in $BUILD_TARGETS; do mkdir -p $JNI_DIR if [ $ENC_LIB = 'mbedtls' ]; then - $BASE_DIR/mkmbedtls -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/mbedtls -i $BASE_DIR/$build_target + $SCRIPT_DIR/mkmbedtls -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/mbedtls -i $BASE_DIR/$build_target cp $LIB_DIR/libmbedcrypto.so $JNI_DIR/libmbedcrypto.so cp $LIB_DIR/libmbedtls.so $JNI_DIR/libmbedtls.so cp $LIB_DIR/libmbedx509.so $JNI_DIR/libmbedx509.so fi git -C $BASE_DIR/srt clean -fd - $BASE_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $BASE_DIR/srt -i $BASE_DIR/$build_target + $SCRIPT_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $BASE_DIR/srt -i $BASE_DIR/$build_target cp $LIB_DIR/libsrt.so $JNI_DIR/libsrt.so done diff --git a/scripts/build-android/mkssl b/scripts/build-android/mkssl index d0305fab7..4e9d0df28 100755 --- a/scripts/build-android/mkssl +++ b/scripts/build-android/mkssl @@ -1,6 +1,6 @@ #!/bin/sh -while getopts n:o:a:t: option +while getopts n:o:a:t:d:h: option do case "${option}" in @@ -8,13 +8,14 @@ do o) OPENSSL_VERSION=${OPTARG};; a) API_LEVEL=${OPTARG};; t) BUILD_TARGETS=${OPTARG};; + d) OUT_DIR=${OPTARG};; + h) HOST_TAG=${OPTARG};; *) twentytwo=${OPTARG};; esac done BUILD_DIR=/tmp/openssl_android_build -OUT_DIR=$(pwd) if [ ! -d openssl-${OPENSSL_VERSION} ] then @@ -29,7 +30,7 @@ cd openssl-${OPENSSL_VERSION} || exit 128 ##### Prepare Files ##### -sed -i 's/.*-mandroid.*//' Configurations/15-android.conf +sed -i.bak 's/.*-mandroid.*//' Configurations/15-android.conf patch -p1 -N < Date: Thu, 5 Aug 2021 12:49:20 +0200 Subject: [PATCH 056/124] [core] Fixed uninitialized DST socket ID in SHUTDOWN ctrl message --- srtcore/api.h | 11 +++++++++-- srtcore/core.cpp | 9 ++++++--- srtcore/core.h | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/srtcore/api.h b/srtcore/api.h index 5750c9db1..e1ba244f3 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -325,14 +325,21 @@ friend class CRendezvousQueue; CEPoll& epoll_ref() { return m_EPoll; } private: -// void init(); - /// Generates a new socket ID. This function starts from a randomly /// generated value (at initialization time) and goes backward with /// with next calls. The possible values come from the range without /// the SRTGROUP_MASK bit, and the group bit is set when the ID is /// generated for groups. It is also internally checked if the /// newly generated ID isn't already used by an existing socket or group. + /// + /// Socket ID value range. + /// - [0]: reserved for handshake procedure. If the destination Socket ID is 0 + /// (destination Socket ID unknown) the packet will be sent to the listening socket + /// or to a socket that is in the rendezvous connection phase. + /// - [1; 2 ^ 30): single socket ID range. + /// - (2 ^ 30; 2 ^ 31): group socket ID range. Effectively any positive number + /// from [1; 2 ^ 30) with bit 30 set to 1. Bit 31 is zero. + /// The most significant bit 31 (sign bit) is left unused so that checking for a value <= 0 identifies an invalid socket ID. /// /// @param group The socket id should be for socket group. /// @return The new socket ID. diff --git a/srtcore/core.cpp b/srtcore/core.cpp index cf01d9e35..a96ca4c47 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -243,6 +243,7 @@ void srt::CUDT::construct() // Will be reset to 0 for HSv5, this value is important for HSv4. m_iSndHsRetryCnt = SRT_MAX_HSRETRY + 1; + m_PeerID = 0; m_bOpened = false; m_bListening = false; m_bConnecting = false; @@ -3784,9 +3785,9 @@ bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst, { // m_RejectReason already set at worker_ProcessAddressedPacket. LOGC(cnlog.Warn, - log << "processAsyncConnectRequest: REJECT reported from HS processing:" + log << "processAsyncConnectRequest: REJECT reported from HS processing: " << srt_rejectreason_str(m_RejectReason) - << "- not processing further"); //; REQ-TIME LOW"); XXX ? + << " - not processing further"); // m_tsLastReqTime = steady_clock::time_point(); XXX ? return false; } @@ -5957,7 +5958,7 @@ bool srt::CUDT::closeInternal() { if (!m_bShutdown) { - HLOGC(smlog.Debug, log << CONID() << "CLOSING - sending SHUTDOWN to the peer"); + HLOGC(smlog.Debug, log << CONID() << "CLOSING - sending SHUTDOWN to the peer @" << m_PeerID); sendCtrl(UMSG_SHUTDOWN); } @@ -7615,6 +7616,8 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp break; case UMSG_SHUTDOWN: // 101 - Shutdown + if (m_PeerID == 0) // Dont't send SHUTDOWN if we don't know peer ID. + break; ctrlpkt.pack(pkttype); ctrlpkt.m_iID = m_PeerID; nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt); diff --git a/srtcore/core.h b/srtcore/core.h index 9a1ad01f0..6b8472c64 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -1029,7 +1029,7 @@ class CUDT private: // Trace struct CoreStats { - time_point tsStartTime; // timestamp when the UDT entity is started + time_point tsStartTime; // timestamp when the UDT entity is started int64_t sentTotal; // total number of sent data packets, including retransmissions int64_t sentUniqTotal; // total number of sent data packets, excluding rexmit and filter control int64_t recvTotal; // total number of received packets From 0fca8741ce319066c1abe62757e1fa7edeeb9d58 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 5 Aug 2021 12:50:13 +0200 Subject: [PATCH 057/124] [tests] Fixed build warning: unused parameter --- test/test_socket_options.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index bf37513ce..eb0b05912 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -349,7 +349,7 @@ bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char { try { const ValueType val = linb::any_cast(inval); - CheckSetSockOpt(entry, sock, val, SRT_ERROR, "[Caller, invalid val]"); + CheckSetSockOpt(entry, sock, val, SRT_ERROR, sock_name); } catch (const linb::bad_any_cast&) { @@ -454,17 +454,18 @@ TEST_F(TestSocketOptions, InvalidVals) // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation for (const auto& entry : g_test_matrix_options) { + const char* desc = "[Caller, invalid val]"; if (entry.dflt_val.type() == typeid(bool)) { - EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, desc)); } else if (entry.dflt_val.type() == typeid(int)) { - EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, desc)); } else if (entry.dflt_val.type() == typeid(int64_t)) { - EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, "[Caller, invalid val]")); + EXPECT_TRUE(CheckInvalidValues(entry, m_caller_sock, desc)); } else { From 747f288e77e88a9e0f7db70f2fa8477868fa5928 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 6 Aug 2021 13:44:36 +0200 Subject: [PATCH 058/124] [core] Check if CryptoControl exists in createSrtHandshake(..). If it does not, it will lead to a crash, reported in #1979. --- srtcore/core.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index a96ca4c47..63e4fadd9 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -1725,6 +1725,16 @@ bool srt::CUDT::createSrtHandshake( HLOGC(cnlog.Debug, log << "createSrtHandshake: " << (m_config.CryptoSecret.len > 0 ? "Agent uses ENCRYPTION" : "Peer requires ENCRYPTION")); + + if (!m_pCryptoControl && (srtkm_cmd == SRT_CMD_KMREQ || srtkm_cmd == SRT_CMD_KMRSP)) + { + m_RejectReason = SRT_REJ_IPE; + LOGC(cnlog.Error, log << "createSrtHandshake: IPE: need to send KM, but CryptoControl does not exist." + << " Socket state: connected=" << boolalpha << m_bConnected << ", connecting=" << m_bConnecting + << ", broken=" << m_bBroken << ", closing=" << m_bClosing << "."); + return false; + } + if (srtkm_cmd == SRT_CMD_KMREQ) { bool have_any_keys = false; @@ -1753,7 +1763,6 @@ bool srt::CUDT::createSrtHandshake( { offset += ra_size + 1; ra_size = fillHsExtKMRSP(p + offset - 1, kmdata, kmdata_wordsize); - } else { From f0aa009f0d591c1f74e6d01f84055b69b56a7d04 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 9 Aug 2021 10:47:38 +0200 Subject: [PATCH 059/124] [core] Renamed congestion control event handling functions --- srtcore/congctl.cpp | 52 +++++++++++++++++++++++++++------------------ srtcore/core.cpp | 38 ++++++++++++++++----------------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 4612e6852..3b0f923a0 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -81,7 +81,7 @@ class LiveCC: public SrtCongestionControlBase m_zSndAvgPayloadSize = m_zMaxPayloadSize; m_iMinNakInterval_us = 20000; //Minimum NAK Report Period (usec) - m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator + m_iNakReportAccel = 2; //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2) HLOGC(cclog.Debug, log << "Creating LiveCC: bw=" << m_llSndMaxBW << " avgplsize=" << m_zSndAvgPayloadSize); @@ -92,11 +92,11 @@ class LiveCC: public SrtCongestionControlBase // from receiving thread. parent->ConnectSignal(TEV_SEND, SSLOT(updatePayloadSize)); - /* - * Readjust the max SndPeriod onACK (and onTimeout) - */ - parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(updatePktSndPeriod_onTimer)); - parent->ConnectSignal(TEV_ACK, SSLOT(updatePktSndPeriod_onAck)); + // + // Adjust the max SndPeriod onACK and onTimeout. + // + parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO)); + parent->ConnectSignal(TEV_ACK, SSLOT(onAck)); } bool checkTransArgs(SrtCongestion::TransAPI api, SrtCongestion::TransDir dir, const char* , size_t size, int , bool ) ATR_OVERRIDE @@ -153,17 +153,22 @@ class LiveCC: public SrtCongestionControlBase HLOGC(cclog.Debug, log << "LiveCC: avg payload size updated: " << m_zSndAvgPayloadSize); } - void updatePktSndPeriod_onTimer(ETransmissionEvent , EventVariant var) + /// @brief On RTO event update an inter-packet send interval. + /// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO. + void onRTO(ETransmissionEvent , EventVariant var) { - if ( var.get() != TEV_CHT_INIT ) + if (var.get() != TEV_CHT_INIT ) updatePktSndPeriod(); } - void updatePktSndPeriod_onAck(ETransmissionEvent , EventVariant ) + /// @brief Handle an incoming ACK event. + /// Mainly updates a send interval between packets relying on the maximum BW limit. + void onAck(ETransmissionEvent, EventVariant ) { updatePktSndPeriod(); } + /// @brief Updates a send interval between packets relying on the maximum BW limit. void updatePktSndPeriod() { // packet = payload + header @@ -289,9 +294,9 @@ class FileCC : public SrtCongestionControlBase m_dCWndSize = 16; m_dPktSndPeriod = 1; - parent->ConnectSignal(TEV_ACK, SSLOT(updateSndPeriod)); - parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(slowdownSndPeriod)); - parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(speedupToWindowSize)); + parent->ConnectSignal(TEV_ACK, SSLOT(onACK)); + parent->ConnectSignal(TEV_LOSSREPORT, SSLOT(onLossReport)); + parent->ConnectSignal(TEV_CHECKTIMER, SSLOT(onRTO)); HLOGC(cclog.Debug, log << "Creating FileCC"); } @@ -305,10 +310,11 @@ class FileCC : public SrtCongestionControlBase return true; } + /// Tells if an early ACK is needed (before the next Full ACK happening every 10ms). + /// In FileCC, treat non-full-payload as an end-of-message (stream) + /// and request ACK to be sent immediately. bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE { - // For FileCC, treat non-full-buffer situation as an end-of-message situation; - // request ACK to be sent immediately. if (pkt.getLength() < m_parent->maxPayloadSize()) { // This is not a regular fixed size packet... @@ -329,9 +335,10 @@ class FileCC : public SrtCongestionControlBase } private: - - // SLOTS - void updateSndPeriod(ETransmissionEvent, EventVariant arg) + /// Handle icoming ACK event. + /// In slow start stage increase CWND. Leave slow start once maximum CWND is reached. + /// In congestion avoidance stage adjust inter packet send interval value to achieve maximum rate. + void onACK(ETransmissionEvent, EventVariant arg) { const int ack = arg.get(); @@ -455,9 +462,10 @@ class FileCC : public SrtCongestionControlBase } - // When a lossreport has been received, it might be due to having - // reached the available bandwidth limit. Slowdown to avoid further losses. - void slowdownSndPeriod(ETransmissionEvent, EventVariant arg) + /// When a lossreport has been received, it might be due to having + /// reached the available bandwidth limit. Slowdown to avoid further losses. + /// Leave the slow start stage if it was active. + void onLossReport(ETransmissionEvent, EventVariant arg) { const int32_t* losslist = arg.get_ptr(); size_t losslist_size = arg.get_len(); @@ -559,7 +567,9 @@ class FileCC : public SrtCongestionControlBase } } - void speedupToWindowSize(ETransmissionEvent, EventVariant arg) + /// @brief On retransmission timeout leave slow start stage if it was active. + /// @param arg EventVariant::STAGE to distinguish between INIT and actual RTO. + void onRTO(ETransmissionEvent, EventVariant arg) { ECheckTimerStage stg = arg.get(); diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 63e4fadd9..c11e66064 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -10899,21 +10899,21 @@ bool srt::CUDT::checkExpTimer(const steady_clock::time_point& currtime, int chec void srt::CUDT::checkRexmitTimer(const steady_clock::time_point& currtime) { - /* There are two algorithms of blind packet retransmission: LATEREXMIT and FASTREXMIT. - * - * LATEREXMIT is only used with FileCC. - * The mode is triggered when some time has passed since the last ACK from - * the receiver, while there is still some unacknowledged data in the sender's buffer, - * and the loss list is empty. - * - * FASTREXMIT is only used with LiveCC. - * The mode is triggered if the receiver does not send periodic NAK reports, - * when some time has passed since the last ACK from the receiver, - * while there is still some unacknowledged data in the sender's buffer. - * - * In case the above conditions are met, the unacknowledged packets - * in the sender's buffer will be added to loss list and retransmitted. - */ + // There are two algorithms of blind packet retransmission: LATEREXMIT and FASTREXMIT. + // + // LATEREXMIT is only used with FileCC. + // The RTO is triggered when some time has passed since the last ACK from + // the receiver, while there is still some unacknowledged data in the sender's buffer, + // and the loss list is empty at the moment of RTO (nothing to retransmit yet). + // + // FASTREXMIT is only used with LiveCC. + // The RTO is triggered if the receiver is not configured to send periodic NAK reports, + // when some time has passed since the last ACK from the receiver, + // while there is still some unacknowledged data in the sender's buffer. + // + // In case the above conditions are met, the unacknowledged packets + // in the sender's buffer will be added to the SND loss list and retransmitted. + // const uint64_t rtt_syn = (m_iSRTT + 4 * m_iRTTVar + 2 * COMM_SYN_INTERVAL_US); const uint64_t exp_int_us = (m_iReXmitCount * rtt_syn + COMM_SYN_INTERVAL_US); @@ -10926,19 +10926,19 @@ void srt::CUDT::checkRexmitTimer(const steady_clock::time_point& currtime) if (m_pSndBuffer->getCurrBufSize() <= 0) return; - const bool is_laterexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_LATEREXMIT; - const bool is_fastrexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_FASTREXMIT; + const bool is_laterexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_LATEREXMIT; // FileCC + const bool is_fastrexmit = m_CongCtl->rexmitMethod() == SrtCongestion::SRM_FASTREXMIT; // LiveCC // If the receiver will send periodic NAK reports, then FASTREXMIT (live) is inactive. // TODO: Probably some method of "blind rexmit" MUST BE DONE, when TLPKTDROP is off. if (is_fastrexmit && m_bPeerNakReport) return; - // Schedule for retransmission IF: + // Schedule a retransmission IF: // - there are packets in flight (getFlightSpan() > 0); // - in case of LATEREXMIT (File Mode): the sender loss list is empty // (the receiver didn't send any LOSSREPORT, or LOSSREPORT was lost on track). - // - in case of FASTREXMIT (Live Mode): there is the latency constraint, therefore + // - in case of FASTREXMIT (Live Mode): the RTO (rtt_syn) was triggered, therefore // schedule unacknowledged packets for retransmission regardless of the loss list emptiness. if (getFlightSpan() > 0 && (!is_laterexmit || m_pSndLossList->getLossLength() == 0)) { From 252337c129c011cada22dcd1772beae40579989d Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 9 Aug 2021 10:54:58 +0200 Subject: [PATCH 060/124] [core] Moved congestion control into the srt namespace --- srtcore/congctl.cpp | 9 ++++++--- srtcore/congctl.h | 11 ++++------- srtcore/socketconfig.cpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 3b0f923a0..2301dfc68 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -34,10 +34,11 @@ #include "logging.h" using namespace std; -using namespace srt; using namespace srt::sync; using namespace srt_logging; +namespace srt { + SrtCongestionControlBase::SrtCongestionControlBase(CUDT* parent) { m_parent = parent; @@ -399,7 +400,7 @@ class FileCC : public SrtCongestionControlBase else { double inc = 0; - const int loss_bw = 2 * (1000000 / m_dLastDecPeriod); // 2 times last loss point + const int loss_bw = static_cast(2 * (1000000 / m_dLastDecPeriod)); // 2 times last loss point const int bw_pktps = min(loss_bw, m_parent->bandwidth()); int64_t B = (int64_t)(bw_pktps - 1000000.0 / m_dPktSndPeriod); @@ -500,7 +501,7 @@ class FileCC : public SrtCongestionControlBase m_bLoss = true; // TODO: const int pktsInFlight = CSeqNo::seqoff(m_iLastAck, m_parent->sndSeqNo()); - const int pktsInFlight = m_parent->SRTT() / m_dPktSndPeriod; + const int pktsInFlight = static_cast(m_parent->SRTT() / m_dPktSndPeriod); const int numPktsLost = m_parent->sndLossLength(); const int lost_pcent_x10 = pktsInFlight > 0 ? (numPktsLost * 1000) / pktsInFlight : 0; @@ -656,3 +657,5 @@ SrtCongestion::~SrtCongestion() { dispose(); } + +} // namespace srt diff --git a/srtcore/congctl.h b/srtcore/congctl.h index 0ad835783..b957dbdd0 100644 --- a/srtcore/congctl.h +++ b/srtcore/congctl.h @@ -17,10 +17,9 @@ #include namespace srt { - class CUDT; -} -class SrtCongestionControlBase; +class CUDT; +class SrtCongestionControlBase; typedef SrtCongestionControlBase* srtcc_create_t(srt::CUDT* parent); class SrtCongestion @@ -131,9 +130,7 @@ class SrtCongestion }; }; -namespace srt { - class CPacket; -} +class CPacket; class SrtCongestionControlBase { @@ -224,6 +221,6 @@ class SrtCongestionControlBase }; - +} // namespace srt #endif diff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp index a62881cd7..820a4334e 100644 --- a/srtcore/socketconfig.cpp +++ b/srtcore/socketconfig.cpp @@ -570,7 +570,7 @@ struct CSrtConfigSetter if (val == "vod") val = "file"; - bool res = SrtCongestion::exists(val); + bool res = srt::SrtCongestion::exists(val); if (!res) throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); From d7dcf0cab7e7a44d9c2daf387f809585fffc715f Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 11 Aug 2021 16:41:34 +0200 Subject: [PATCH 061/124] [core] Check if socket is still open before replying to HS --- srtcore/core.cpp | 2 ++ srtcore/queue.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index c11e66064..7c0f3acf5 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -3769,6 +3769,8 @@ bool srt::CUDT::processAsyncConnectRequest(EReadStatus rst, bool status = true; ScopedLock cg(m_ConnectionLock); + if (!m_bOpened) // Check the socket has not been closed before already. + return false; if (cst == CONN_RENDEZVOUS) { diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 2b0fd2c74..03ba97e47 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -989,11 +989,12 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst for (vector::iterator i = toRemove.begin(); i != toRemove.end(); ++i) { HLOGC(cnlog.Debug, log << "updateConnStatus: COMPLETING dep objects update on failed @" << i->id); - /* - * Setting m_bConnecting to false but keeping socket in rendezvous queue is not a good idea. - * Next CUDT::close will not remove it from rendezvous queue (because !m_bConnecting) - * and may crash on next pass. - */ + // + // Setting m_bConnecting to false, and need to remove the socket from the rendezvous queue + // because the next CUDT::close will not remove it from the queue when m_bConnecting = false, + // and may crash on next pass. + // + // TODO: maybe lock i->u->m_ConnectionLock? i->u->m_bConnecting = false; remove(i->u->m_SocketID); From 7728b7000fb720d1d974f1d24db07b4ce82adf95 Mon Sep 17 00:00:00 2001 From: Laurent Bigonville Date: Thu, 12 Aug 2021 15:10:13 +0200 Subject: [PATCH 062/124] [core] Prefer the endian.h header file from glibc if available On the Debian kfreebsd port, both endian.h and sys/endian.h are available. After discussing with the kfreebsd port maintainer and since this is userspace related, we should prefer the one from the glibc See: #2066 --- srtcore/utilities.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srtcore/utilities.h b/srtcore/utilities.h index b1f21fbb2..60a286ec0 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -57,7 +57,7 @@ written by #endif -#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) +#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__) || defined(__GLIBC__) # include @@ -115,7 +115,7 @@ written by # include -#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) # include From f1c96d9868c4b9daa05d07bc8dca1b681cad314b Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 12 Aug 2021 11:58:56 +0200 Subject: [PATCH 063/124] [core] Check Win QPC frequency is non-zero --- srtcore/sync_posix.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/srtcore/sync_posix.cpp b/srtcore/sync_posix.cpp index 960a1dfad..c44fe86c2 100644 --- a/srtcore/sync_posix.cpp +++ b/srtcore/sync_posix.cpp @@ -86,6 +86,12 @@ static int64_t get_cpu_frequency() if (QueryPerformanceFrequency(&ccf)) { frequency = ccf.QuadPart / 1000000; // counts per microsecond + if (frequency == 0) + { + LOGC(inlog.Warn, log << "Win QPC frequency of " << ccf.QuadPart + << " counts/s is below the required 1 us accuracy. Please consider using C++11 timing (-DENABLE_STDCXX_SYNC=ON) instead."); + frequency = 1; // set back to 1 to avoid division by zero. + } } else { From 6ca1e0daa59ec0d7983ab8da002a5f7281bd2a2b Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 13 Aug 2021 12:16:00 +0200 Subject: [PATCH 064/124] [tests] Fixed possible TestIPv6 hangups if connection fails --- test/test_ipv6.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/test/test_ipv6.cpp b/test/test_ipv6.cpp index 820288fa8..69a51bfbb 100644 --- a/test/test_ipv6.cpp +++ b/test/test_ipv6.cpp @@ -48,11 +48,14 @@ class TestIPv6 { sockaddr_any sa (family); sa.hport(m_listen_port); - ASSERT_EQ(inet_pton(family, address.c_str(), sa.get_addr()), 1); + EXPECT_EQ(inet_pton(family, address.c_str(), sa.get_addr()), 1); std::cout << "Calling: " << address << "(" << fam[family] << ")\n"; - ASSERT_NE(srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa), SRT_ERROR); + const int connect_res = srt_connect(m_caller_sock, (sockaddr*)&sa, sizeof sa); + EXPECT_NE(connect_res, SRT_ERROR) << "srt_connect() failed with: " << srt_getlasterror_str(); + if (connect_res == SRT_ERROR) + srt_close(m_listener_sock); PrintAddresses(m_caller_sock, "CALLER"); } @@ -61,7 +64,7 @@ class TestIPv6 void ShowAddress(std::string src, const sockaddr_any& w) { - ASSERT_NE(fam.count(w.family()), 0U) << "INVALID FAMILY"; + EXPECT_NE(fam.count(w.family()), 0U) << "INVALID FAMILY"; std::cout << src << ": " << w.str() << " (" << fam[w.family()] << ")" << std::endl; } @@ -70,16 +73,23 @@ class TestIPv6 sockaddr_any sc1; SRTSOCKET accepted_sock = srt_accept(m_listener_sock, sc1.get(), &sc1.len); - EXPECT_NE(accepted_sock, SRT_INVALID_SOCK); + EXPECT_NE(accepted_sock, SRT_INVALID_SOCK) << "accept() failed with: " << srt_getlasterror_str(); + if (accepted_sock == SRT_INVALID_SOCK) { + return sockaddr_any(); + } PrintAddresses(accepted_sock, "ACCEPTED"); sockaddr_any sn; EXPECT_NE(srt_getsockname(accepted_sock, sn.get(), &sn.len), SRT_ERROR); - - int32_t ipv6_zero [] = {0, 0, 0, 0}; - EXPECT_NE(memcmp(ipv6_zero, sn.get_addr(), sizeof ipv6_zero), 0) - << "EMPTY address in srt_getsockname"; + EXPECT_NE(sn.get_addr(), nullptr); + + if (sn.get_addr() != nullptr) + { + const int32_t ipv6_zero[] = { 0, 0, 0, 0 }; + EXPECT_NE(memcmp(ipv6_zero, sn.get_addr(), sizeof ipv6_zero), 0) + << "EMPTY address in srt_getsockname"; + } srt_close(accepted_sock); return sn; From b2141220f5e441a9cee99f8d80b2a32bb38f7577 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 13 Aug 2021 11:48:32 +0200 Subject: [PATCH 065/124] [core] Fixed int64_t to long type cast --- srtcore/api.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index d38442590..264192155 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -2171,8 +2171,8 @@ int srt::CUDTUnited::select( { const steady_clock::time_point entertime = steady_clock::now(); - const long timeo_us = timeout - ? timeout->tv_sec * 1000000 + timeout->tv_usec + const int64_t timeo_us = timeout + ? static_cast(timeout->tv_sec) * 1000000 + timeout->tv_usec : -1; const steady_clock::duration timeo(microseconds_from(timeo_us)); @@ -2285,7 +2285,7 @@ int srt::CUDTUnited::selectEx( { const steady_clock::time_point entertime = steady_clock::now(); - const long timeo_us = msTimeOut >= 0 + const int64_t timeo_us = msTimeOut >= 0 ? msTimeOut * 1000 : -1; const steady_clock::duration timeo(microseconds_from(timeo_us)); From bc5a6429473648a70396a9acc229e04fd5e4d0a9 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 13 Aug 2021 14:37:20 +0200 Subject: [PATCH 066/124] [tests] Fixed range loop construct warning --- test/test_socket_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp index eb0b05912..d010de510 100644 --- a/test/test_socket_options.cpp +++ b/test/test_socket_options.cpp @@ -345,7 +345,7 @@ bool CheckMaxValue(const OptionTestEntry& entry, SRTSOCKET sock, const char* des template bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char* sock_name) { - for (const auto inval : entry.invalid_vals) + for (const auto& inval : entry.invalid_vals) { try { const ValueType val = linb::any_cast(inval); From ae11c18453fd46f15606e601b7232f48e3d4a464 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 13 Aug 2021 11:45:35 +0200 Subject: [PATCH 067/124] [core] CUDTSocket now owns a member CUDT class (composition). --- srtcore/api.cpp | 244 ++++++++++++++++++++++------------------------ srtcore/api.h | 31 +++++- srtcore/core.cpp | 20 ++-- srtcore/group.cpp | 18 ++-- 4 files changed, 164 insertions(+), 149 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 264192155..7f6d7ecaa 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -96,10 +96,6 @@ void srt::CUDTSocket::construct() srt::CUDTSocket::~CUDTSocket() { - - delete m_pUDT; - m_pUDT = NULL; - releaseMutex(m_AcceptLock); releaseCond(m_AcceptCond); releaseMutex(m_ControlLock); @@ -113,11 +109,11 @@ SRT_SOCKSTATUS srt::CUDTSocket::getStatus() // In this case m_bConnected is also false. Both checks are required to avoid hitting // a regular state transition from CONNECTING to CONNECTED. - if (m_pUDT->m_bBroken) + if (m_UDT.m_bBroken) return SRTS_BROKEN; // Connecting timed out - if ((m_Status == SRTS_CONNECTING) && !m_pUDT->m_bConnecting && !m_pUDT->m_bConnected) + if ((m_Status == SRTS_CONNECTING) && !m_UDT.m_bConnecting && !m_UDT.m_bConnected) return SRTS_BROKEN; return m_Status; @@ -128,10 +124,10 @@ void srt::CUDTSocket::breakSocket_LOCKED() { // This function is intended to be called from GC, // under a lock of m_GlobControlLock. - m_pUDT->m_bBroken = true; - m_pUDT->m_iBrokenCounter = 0; + m_UDT.m_bBroken = true; + m_UDT.m_iBrokenCounter = 0; HLOGC(smlog.Debug, log << "@" << m_SocketID << " CLOSING AS SOCKET"); - m_pUDT->closeInternal(); + m_UDT.closeInternal(); setClosed(); } @@ -148,16 +144,16 @@ void srt::CUDTSocket::setClosed() void srt::CUDTSocket::setBrokenClosed() { - m_pUDT->m_iBrokenCounter = 60; - m_pUDT->m_bBroken = true; + m_UDT.m_iBrokenCounter = 60; + m_UDT.m_bBroken = true; setClosed(); } bool srt::CUDTSocket::readReady() { - if (m_pUDT->m_bConnected && m_pUDT->m_pRcvBuffer->isRcvDataReady()) + if (m_UDT.m_bConnected && m_UDT.m_pRcvBuffer->isRcvDataReady()) return true; - if (m_pUDT->m_bListening) + if (m_UDT.m_bListening) { return m_QueuedSockets.size() > 0; } @@ -167,14 +163,14 @@ bool srt::CUDTSocket::readReady() bool srt::CUDTSocket::writeReady() const { - return (m_pUDT->m_bConnected - && (m_pUDT->m_pSndBuffer->getCurrBufSize() < m_pUDT->m_config.iSndBufSize)) + return (m_UDT.m_bConnected + && (m_UDT.m_pSndBuffer->getCurrBufSize() < m_UDT.m_config.iSndBufSize)) || broken(); } bool srt::CUDTSocket::broken() const { - return m_pUDT->m_bBroken || !m_pUDT->m_bConnected; + return m_UDT.m_bBroken || !m_UDT.m_bConnected; } //////////////////////////////////////////////////////////////////////////////// @@ -239,7 +235,7 @@ int srt::CUDTUnited::startup() ScopedLock gcinit(m_InitLock); if (m_iInstanceCount++ > 0) - return 1; + return 1; // Global initialization code #ifdef _WIN32 @@ -290,10 +286,10 @@ int srt::CUDTUnited::cleanup() ScopedLock gcinit(m_InitLock); if (--m_iInstanceCount > 0) - return 0; + return 0; if (!m_bGCStatus) - return 0; + return 0; m_bClosing = true; // NOTE: we can do relaxed signaling here because @@ -436,7 +432,6 @@ SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps) try { ns = new CUDTSocket; - ns->m_pUDT = new CUDT(ns); } catch (...) { @@ -455,8 +450,8 @@ SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps) } ns->m_Status = SRTS_INIT; ns->m_ListenSocket = 0; - ns->m_pUDT->m_SocketID = ns->m_SocketID; - ns->m_pUDT->m_pCache = m_pCache; + ns->core().m_SocketID = ns->m_SocketID; + ns->core().m_pCache = m_pCache; try { @@ -507,7 +502,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p // if this connection has already been processed if ((ns = locatePeer(peer, w_hs.m_iID, w_hs.m_iISN)) != NULL) { - if (ns->m_pUDT->m_bBroken) + if (ns->core().m_bBroken) { // last connection from the "peer" address has been broken ns->setClosed(); @@ -523,15 +518,15 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p << "newConnection: located a WORKING peer @" << w_hs.m_iID << " - ADAPTING."); - w_hs.m_iISN = ns->m_pUDT->m_iISN; - w_hs.m_iMSS = ns->m_pUDT->MSS(); - w_hs.m_iFlightFlagSize = ns->m_pUDT->m_config.iFlightFlagSize; + w_hs.m_iISN = ns->core().m_iISN; + w_hs.m_iMSS = ns->core().MSS(); + w_hs.m_iFlightFlagSize = ns->core().m_config.iFlightFlagSize; w_hs.m_iReqType = URQ_CONCLUSION; w_hs.m_iID = ns->m_SocketID; // Report the original UDT because it will be // required to complete the HS data for conclusion response. - w_acpu = ns->m_pUDT; + w_acpu = &ns->core(); return 0; @@ -554,8 +549,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p try { - ns = new CUDTSocket; - ns->m_pUDT = new CUDT(ns, *(ls->m_pUDT)); + ns = new CUDTSocket(*ls); // No need to check the peer, this is the address from which the request has come. ns->m_PeerAddr = peer; } @@ -567,7 +561,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p return -1; } - ns->m_pUDT->m_RejectReason = SRT_REJ_UNKNOWN; // pre-set a universal value + ns->core().m_RejectReason = SRT_REJ_UNKNOWN; // pre-set a universal value try { @@ -585,13 +579,13 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p } ns->m_ListenSocket = listen; - ns->m_pUDT->m_SocketID = ns->m_SocketID; + ns->core().m_SocketID = ns->m_SocketID; ns->m_PeerID = w_hs.m_iID; ns->m_iISN = w_hs.m_iISN; HLOGC(cnlog.Debug, log << "newConnection: DATA: lsnid=" << listen - << " id=" << ns->m_pUDT->m_SocketID - << " peerid=" << ns->m_pUDT->m_PeerID + << " id=" << ns->core().m_SocketID + << " peerid=" << ns->core().m_PeerID << " ISN=" << ns->m_iISN); int error = 0; @@ -621,11 +615,11 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p m_Sockets[ns->m_SocketID] = ns; } - if (ls->m_pUDT->m_cbAcceptHook) + if (ls->core().m_cbAcceptHook) { - if (!ls->m_pUDT->runAcceptHook(ns->m_pUDT, peer.get(), w_hs, hspkt)) + if (!ls->core().runAcceptHook(&ns->core(), peer.get(), w_hs, hspkt)) { - w_error = ns->m_pUDT->m_RejectReason; + w_error = ns->core().m_RejectReason; error = 1; goto ERR_ROLLBACK; @@ -633,15 +627,15 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p } // bind to the same addr of listening socket - ns->m_pUDT->open(); + ns->core().open(); updateListenerMux(ns, ls); - ns->m_pUDT->acceptAndRespond(ls->m_SelfAddr, peer, hspkt, (w_hs)); + ns->core().acceptAndRespond(ls->m_SelfAddr, peer, hspkt, (w_hs)); } catch (...) { // Extract the error that was set in this new failed entity. - w_error = ns->m_pUDT->m_RejectReason; + w_error = ns->core().m_RejectReason; error = 1; goto ERR_ROLLBACK; } @@ -651,11 +645,11 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p // copy address information of local node // Precisely, what happens here is: // - Get the IP address and port from the system database - ns->m_pUDT->m_pSndQueue->m_pChannel->getSockAddr((ns->m_SelfAddr)); + ns->core().m_pSndQueue->m_pChannel->getSockAddr((ns->m_SelfAddr)); // - OVERWRITE just the IP address itself by a value taken from piSelfIP // (the family is used exactly as the one taken from what has been returned // by getsockaddr) - CIPAddress::pton((ns->m_SelfAddr), ns->m_pUDT->m_piSelfIP, peer); + CIPAddress::pton((ns->m_SelfAddr), ns->core().m_piSelfIP, peer); { // protect the m_PeerRec structure (and group existence) @@ -757,7 +751,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p /* SETUP HERE IF NEEDED - ns->m_pUDT->m_cbPacketArrival.set(ns->m_pUDT, &CUDT::groupPacketArrival); + ns->core().m_cbPacketArrival.set(ns->m_pUDT, &CUDT::groupPacketArrival); */ } else @@ -783,7 +777,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p HLOGC(cnlog.Debug, log << "ACCEPT: new socket @" << ns->m_SocketID << " submitted for acceptance"); // acknowledge users waiting for new connections on the listening socket - m_EPoll.update_events(listen, ls->m_pUDT->m_sPollID, SRT_EPOLL_ACCEPT, true); + m_EPoll.update_events(listen, ls->core().m_sPollID, SRT_EPOLL_ACCEPT, true); CGlobEvent::triggerEvent(); @@ -803,7 +797,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p // acknowledge INTERNAL users waiting for new connections on the listening socket // that are reported when a new socket is connected within an already connected group. - m_EPoll.update_events(listen, ls->m_pUDT->m_sPollID, SRT_EPOLL_UPDATE, true); + m_EPoll.update_events(listen, ls->core().m_sPollID, SRT_EPOLL_UPDATE, true); CGlobEvent::triggerEvent(); } @@ -823,7 +817,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p #endif SRTSOCKET id = ns->m_SocketID; - ns->m_pUDT->closeInternal(); + ns->core().closeInternal(); ns->setClosed(); // The mapped socket should be now unmapped to preserve the situation that @@ -862,7 +856,7 @@ int srt::CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_ try { CUDTSocket* s = locateSocket(lsn, ERH_THROW); - s->m_pUDT->installAcceptHook(hook, opaq); + s->core().installAcceptHook(hook, opaq); } catch (CUDTException& e) { @@ -891,7 +885,7 @@ int srt::CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_ } #endif CUDTSocket* s = locateSocket(u, ERH_THROW); - s->m_pUDT->installConnectHook(hook, opaq); + s->core().installConnectHook(hook, opaq); } catch (CUDTException& e) { @@ -927,12 +921,12 @@ int srt::CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name) if (s->m_Status != SRTS_INIT) throw CUDTException(MJ_NOTSUP, MN_NONE, 0); - s->m_pUDT->open(); + s->core().open(); updateMux(s, name); s->m_Status = SRTS_OPENED; // copy address information of local node - s->m_pUDT->m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); + s->core().m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); return 0; } @@ -956,12 +950,12 @@ int srt::CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) // Successfully extracted, so update the size name.len = namelen; - s->m_pUDT->open(); + s->core().open(); updateMux(s, name, &udpsock); s->m_Status = SRTS_OPENED; // copy address information of local node - s->m_pUDT->m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); + s->core().m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); return 0; } @@ -998,14 +992,14 @@ int srt::CUDTUnited::listen(const SRTSOCKET u, int backlog) // [[using assert(s->m_Status == OPENED)]]; // listen is not supported in rendezvous connection setup - if (s->m_pUDT->m_config.bRendezvous) + if (s->core().m_config.bRendezvous) throw CUDTException(MJ_NOTSUP, MN_ISRENDEZVOUS, 0); s->m_uiBackLog = backlog; // [[using assert(s->m_Status == OPENED)]]; // (still, unchanged) - s->m_pUDT->setListenState(); // propagates CUDTException, + s->core().setListenState(); // propagates CUDTException, // if thrown, remains in OPENED state if so. s->m_Status = SRTS_LISTENING; @@ -1080,7 +1074,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int } // no "accept" in rendezvous connection setup - if (ls->m_pUDT->m_config.bRendezvous) + if (ls->core().m_config.bRendezvous) { LOGC(cnlog.Fatal, log << "CUDTUnited::accept: RENDEZVOUS flag passed through check in srt_listen when it set listen state"); // This problem should never happen because `srt_listen` function should have @@ -1098,7 +1092,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int UniqueLock accept_lock(ls->m_AcceptLock); CSync accept_sync(ls->m_AcceptCond, accept_lock); - if ((ls->m_Status != SRTS_LISTENING) || ls->m_pUDT->m_bBroken) + if ((ls->m_Status != SRTS_LISTENING) || ls->core().m_bBroken) { // This socket has been closed. accepted = true; @@ -1110,7 +1104,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int ls->m_QueuedSockets.erase(b); accepted = true; } - else if (!ls->m_pUDT->m_config.bSynRecving) + else if (!ls->core().m_config.bSynRecving) { accepted = true; } @@ -1119,13 +1113,13 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int accept_sync.wait(); if (ls->m_QueuedSockets.empty()) - m_EPoll.update_events(listen, ls->m_pUDT->m_sPollID, SRT_EPOLL_ACCEPT, false); + m_EPoll.update_events(listen, ls->core().m_sPollID, SRT_EPOLL_ACCEPT, false); } if (u == CUDT::INVALID_SOCK) { // non-blocking receiving, no connection available - if (!ls->m_pUDT->m_config.bSynRecving) + if (!ls->core().m_config.bSynRecving) { LOGC(cnlog.Error, log << "srt_accept: no pending connection available at the moment"); throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0); @@ -1150,7 +1144,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int // and the already accepted socket has successfully joined // the mirror group. If so, RETURN THE GROUP ID, not the socket ID. #if ENABLE_EXPERIMENTAL_BONDING - if (ls->m_pUDT->m_config.iGroupConnect == 1 && s->m_GroupOf) + if (ls->core().m_config.iGroupConnect == 1 && s->m_GroupOf) { // Put a lock to protect the group against accidental deletion // in the meantime. @@ -1370,7 +1364,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i if (pg->m_cbConnectHook) { // Derive the connect hook by the socket, if set on the group - ns->m_pUDT->m_cbConnectHook = pg->m_cbConnectHook; + ns->core().m_cbConnectHook = pg->m_cbConnectHook; } SRT_SocketOptionObject* config = targets[tii].config; @@ -1494,7 +1488,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i // be probably still in use to exchange information about // packets assymetrically lost. But for no other purpose. /* - ns->m_pUDT->m_cbPacketArrival.set(ns->m_pUDT, &CUDT::groupPacketArrival); + ns->core().m_cbPacketArrival.set(ns->m_pUDT, &CUDT::groupPacketArrival); */ int isn = g.currentSchedSequence(); @@ -1508,14 +1502,14 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i } // Set it the groupconnect option, as all in-group sockets should have. - ns->m_pUDT->m_config.iGroupConnect = 1; + ns->core().m_config.iGroupConnect = 1; // Every group member will have always nonblocking // (this implies also non-blocking connect/accept). // The group facility functions will block when necessary // using epoll_wait. - ns->m_pUDT->m_config.bSynRecving = false; - ns->m_pUDT->m_config.bSynSending = false; + ns->core().m_config.bSynRecving = false; + ns->core().m_config.bSynSending = false; HLOGC(aclog.Debug, log << "groupConnect: NOTIFIED AS PENDING @" << sid << " both read and write"); // If this socket is not to block the current connect process, @@ -1832,7 +1826,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i if (s->m_Status == SRTS_INIT) { - if (s->m_pUDT->m_config.bRendezvous) + if (s->core().m_config.bRendezvous) throw CUDTException(MJ_NOTSUP, MN_ISRENDUNBOUND, 0); // If bind() was done first on this socket, then the @@ -1840,7 +1834,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i // same thing as bind() does, just with empty address so that // the binding parameters are autoselected. - s->m_pUDT->open(); + s->core().open(); sockaddr_any autoselect_sa (target_addr.family()); // This will create such a sockaddr_any that // will return true from empty(). @@ -1878,7 +1872,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i { // record peer address s->m_PeerAddr = target_addr; - s->m_pUDT->startConnect(target_addr, forced_isn); + s->core().startConnect(target_addr, forced_isn); } catch (CUDTException& e) // Interceptor, just to change the state. { @@ -1962,23 +1956,21 @@ void srt::CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g) int srt::CUDTUnited::close(CUDTSocket* s) { - HLOGC(smlog.Debug, log << s->m_pUDT->CONID() << " CLOSE. Acquiring control lock"); - + HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSE. Acquiring control lock"); ScopedLock socket_cg(s->m_ControlLock); + HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSING (removing from listening, closing CUDT)"); - HLOGC(smlog.Debug, log << s->m_pUDT->CONID() << " CLOSING (removing from listening, closing CUDT)"); - - const bool synch_close_snd = s->m_pUDT->m_config.bSynSending; + const bool synch_close_snd = s->core().m_config.bSynSending; SRTSOCKET u = s->m_SocketID; if (s->m_Status == SRTS_LISTENING) { - if (s->m_pUDT->m_bBroken) + if (s->core().m_bBroken) return 0; s->m_tsClosureTimeStamp = steady_clock::now(); - s->m_pUDT->m_bBroken = true; + s->core().m_bBroken = true; // Change towards original UDT: // Leave all the closing activities for garbageCollect to happen, @@ -1989,8 +1981,8 @@ int srt::CUDTUnited::close(CUDTSocket* s) // be unable to bind to this port that the about-to-delete listener // is currently occupying (due to blocked slot in the RcvQueue). - HLOGC(smlog.Debug, log << s->m_pUDT->CONID() << " CLOSING (removing listener immediately)"); - s->m_pUDT->notListening(); + HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSING (removing listener immediately)"); + s->core().notListening(); // broadcast all "accept" waiting CSync::lock_broadcast(s->m_AcceptCond, s->m_AcceptLock); @@ -2002,10 +1994,10 @@ int srt::CUDTUnited::close(CUDTSocket* s) // may block INDEFINITELY. As long as it's acceptable to block the // call to srt_close(), and all functions in all threads where this // very socket is used, this shall not block the central database. - s->m_pUDT->closeInternal(); + s->core().closeInternal(); // synchronize with garbage collection. - HLOGC(smlog.Debug, log << "@" << u << "U::close done. GLOBAL CLOSE: " << s->m_pUDT->CONID() << ". Acquiring GLOBAL control lock"); + HLOGC(smlog.Debug, log << "@" << u << "U::close done. GLOBAL CLOSE: " << s->core().CONID() << ". Acquiring GLOBAL control lock"); ScopedLock manager_cg(m_GlobControlLock); // since "s" is located before m_GlobControlLock, locate it again in case // it became invalid @@ -2052,7 +2044,7 @@ int srt::CUDTUnited::close(CUDTSocket* s) HLOGC(smlog.Debug, log << "@" << u << " GLOBAL CLOSING: sync-waiting for releasing sender resources..."); for (;;) { - CSndBuffer* sb = s->m_pUDT->m_pSndBuffer; + CSndBuffer* sb = s->core().m_pSndBuffer; // Disconnected from buffer - nothing more to check. if (!sb) @@ -2080,7 +2072,7 @@ int srt::CUDTUnited::close(CUDTSocket* s) } if (!isgone) { - isgone = !s->m_pUDT->m_bOpened; + isgone = !s->core().m_bOpened; } if (isgone) { @@ -2131,7 +2123,7 @@ void srt::CUDTUnited::getpeername(const SRTSOCKET u, sockaddr* pw_name, int* pw_ if (!s) throw CUDTException(MJ_NOTSUP, MN_SIDINVAL, 0); - if (!s->m_pUDT->m_bConnected || s->m_pUDT->m_bBroken) + if (!s->core().m_bConnected || s->core().m_bBroken) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); const int len = s->m_PeerAddr.size(); @@ -2152,7 +2144,7 @@ void srt::CUDTUnited::getsockname(const SRTSOCKET u, sockaddr* pw_name, int* pw_ if (!s) throw CUDTException(MJ_NOTSUP, MN_SIDINVAL, 0); - if (s->m_pUDT->m_bBroken) + if (s->core().m_bBroken) throw CUDTException(MJ_NOTSUP, MN_SIDINVAL, 0); if (s->m_Status == SRTS_INIT) @@ -2306,7 +2298,7 @@ int srt::CUDTUnited::selectEx( { CUDTSocket* s = locateSocket(*i); - if ((!s) || s->m_pUDT->m_bBroken || (s->m_Status == SRTS_CLOSED)) + if ((!s) || s->core().m_bBroken || (s->m_Status == SRTS_CLOSED)) { if (exceptfds) { @@ -2318,10 +2310,10 @@ int srt::CUDTUnited::selectEx( if (readfds) { - if ((s->m_pUDT->m_bConnected - && s->m_pUDT->m_pRcvBuffer->isRcvDataReady() + if ((s->core().m_bConnected + && s->core().m_pRcvBuffer->isRcvDataReady() ) - || (s->m_pUDT->m_bListening + || (s->core().m_bListening && (s->m_QueuedSockets.size() > 0))) { readfds->push_back(s->m_SocketID); @@ -2331,9 +2323,9 @@ int srt::CUDTUnited::selectEx( if (writefds) { - if (s->m_pUDT->m_bConnected - && (s->m_pUDT->m_pSndBuffer->getCurrBufSize() - < s->m_pUDT->m_config.iSndBufSize)) + if (s->core().m_bConnected + && (s->core().m_pSndBuffer->getCurrBufSize() + < s->core().m_config.iSndBufSize)) { writefds->push_back(s->m_SocketID); ++ count; @@ -2393,7 +2385,7 @@ int srt::CUDTUnited::epoll_add_usock( int srt::CUDTUnited::epoll_add_usock_INTERNAL(const int eid, CUDTSocket* s, const int* events) { int ret = m_EPoll.update_usock(eid, s->m_SocketID, events); - s->m_pUDT->addEPoll(eid); + s->core().addEPoll(eid); return ret; } @@ -2434,7 +2426,7 @@ int srt::CUDTUnited::epoll_remove_entity(const int eid, EntityType* ent) // Needed internal access! int srt::CUDTUnited::epoll_remove_socket_INTERNAL(const int eid, CUDTSocket* s) { - return epoll_remove_entity(eid, s->m_pUDT); + return epoll_remove_entity(eid, &s->core()); } #if ENABLE_EXPERIMENTAL_BONDING @@ -2461,7 +2453,7 @@ int srt::CUDTUnited::epoll_remove_usock(const int eid, const SRTSOCKET u) { s = locateSocket(u); if (s) - return epoll_remove_entity(eid, s->m_pUDT); + return epoll_remove_entity(eid, &s->core()); } LOGC(ealog.Error, log << "remove_usock: @" << u @@ -2623,7 +2615,7 @@ void srt::CUDTUnited::checkBrokenSockets() CUDTSocket* s = i->second; // check broken connection - if (s->m_pUDT->m_bBroken) + if (s->core().m_bBroken) { if (s->m_Status == SRTS_LISTENING) { @@ -2635,21 +2627,21 @@ void srt::CUDTUnited::checkBrokenSockets() continue; } } - else if ((s->m_pUDT->m_pRcvBuffer != NULL) + else if ((s->core().m_pRcvBuffer != NULL) // FIXED: calling isRcvDataAvailable() just to get the information // whether there are any data waiting in the buffer, // NOT WHETHER THEY ARE ALSO READY TO PLAY at the time when // this function is called (isRcvDataReady also checks if the // available data is "ready to play"). - && s->m_pUDT->m_pRcvBuffer->isRcvDataAvailable()) + && s->core().m_pRcvBuffer->isRcvDataAvailable()) { - const int bc = s->m_pUDT->m_iBrokenCounter.load(); + const int bc = s->core().m_iBrokenCounter.load(); if (bc > 0) { // HLOGF(smlog.Debug, "STILL KEEPING socket (still have data): // %d\n", i->first); // if there is still data in the receiver buffer, wait longer - s->m_pUDT->m_iBrokenCounter.store(bc - 1); + s->core().m_iBrokenCounter.store(bc - 1); continue; } } @@ -2688,16 +2680,16 @@ void srt::CUDTUnited::checkBrokenSockets() j != m_ClosedSockets.end(); ++ j) { // HLOGF(smlog.Debug, "checking CLOSED socket: %d\n", j->first); - if (!is_zero(j->second->m_pUDT->m_tsLingerExpiration)) + if (!is_zero(j->second->core().m_tsLingerExpiration)) { // asynchronous close: - if ((!j->second->m_pUDT->m_pSndBuffer) - || (0 == j->second->m_pUDT->m_pSndBuffer->getCurrBufSize()) - || (j->second->m_pUDT->m_tsLingerExpiration <= steady_clock::now())) + if ((!j->second->core().m_pSndBuffer) + || (0 == j->second->core().m_pSndBuffer->getCurrBufSize()) + || (j->second->core().m_tsLingerExpiration <= steady_clock::now())) { HLOGC(smlog.Debug, log << "checkBrokenSockets: marking CLOSED qualified @" << j->second->m_SocketID); - j->second->m_pUDT->m_tsLingerExpiration = steady_clock::time_point(); - j->second->m_pUDT->m_bClosing = true; + j->second->core().m_tsLingerExpiration = steady_clock::time_point(); + j->second->core().m_bClosing = true; j->second->m_tsClosureTimeStamp = steady_clock::now(); } } @@ -2708,7 +2700,7 @@ void srt::CUDTUnited::checkBrokenSockets() const steady_clock::duration closed_ago = now - j->second->m_tsClosureTimeStamp; if (closed_ago > seconds_from(1)) { - CRNode* rnode = j->second->m_pUDT->m_pRNode; + CRNode* rnode = j->second->core().m_pRNode; if (!rnode || !rnode->m_bOnList) { HLOGC(smlog.Debug, log << "checkBrokenSockets: @" << j->second->m_SocketID << " closed " @@ -2744,11 +2736,11 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u) // still be under processing in the sender/receiver worker // threads. If that's the case, SKIP IT THIS TIME. The // socket will be checked next time the GC rollover starts. - CSNode* sn = s->m_pUDT->m_pSNode; + CSNode* sn = s->core().m_pSNode; if (sn && sn->m_iHeapLoc != -1) return; - CRNode* rn = s->m_pUDT->m_pRNode; + CRNode* rn = s->core().m_pRNode; if (rn && rn->m_bOnList) return; @@ -2804,14 +2796,14 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u) * remains forever causing epoll_wait to unblock continuously for inexistent * sockets. Get rid of all events for this socket. */ - m_EPoll.update_events(u, s->m_pUDT->m_sPollID, + m_EPoll.update_events(u, s->core().m_sPollID, SRT_EPOLL_IN|SRT_EPOLL_OUT|SRT_EPOLL_ERR, false); // delete this one m_ClosedSockets.erase(i); HLOGC(smlog.Debug, log << "GC/removeSocket: closing associated UDT @" << u); - s->m_pUDT->closeInternal(); + s->core().closeInternal(); HLOGC(smlog.Debug, log << "GC/removeSocket: DELETING SOCKET @" << u); delete s; @@ -2850,7 +2842,7 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u) void srt::CUDTUnited::configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int af) { - w_m.m_mcfg = s->m_pUDT->m_config; + w_m.m_mcfg = s->core().m_config; w_m.m_iIPversion = af; w_m.m_iRefCount = 1; w_m.m_iID = s->m_SocketID; @@ -2858,8 +2850,8 @@ void srt::CUDTUnited::configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int uint16_t srt::CUDTUnited::installMuxer(CUDTSocket* w_s, CMultiplexer& fw_sm) { - w_s->m_pUDT->m_pSndQueue = fw_sm.m_pSndQueue; - w_s->m_pUDT->m_pRcvQueue = fw_sm.m_pRcvQueue; + w_s->core().m_pSndQueue = fw_sm.m_pSndQueue; + w_s->core().m_pRcvQueue = fw_sm.m_pRcvQueue; w_s->m_iMuxID = fw_sm.m_iID; sockaddr_any sa; fw_sm.m_pChannel->getSockAddr((sa)); @@ -2869,7 +2861,7 @@ uint16_t srt::CUDTUnited::installMuxer(CUDTSocket* w_s, CMultiplexer& fw_sm) bool srt::CUDTUnited::channelSettingsMatch(const CMultiplexer& m, const CUDTSocket* s) { - return m.m_mcfg.bReuseAddr && m.m_mcfg == s->m_pUDT->m_config; + return m.m_mcfg.bReuseAddr && m.m_mcfg == s->core().m_config; } void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/) @@ -2922,14 +2914,14 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U // Still, for ANY you need either the same family, or open // for families. - if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != s->m_pUDT->m_config.iIpV6Only) + if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != s->core().m_config.iIpV6Only) { LOGC(smlog.Error, log << "bind: Address: " << addr.str() << " conflicts with existing IPv6 wildcard binding: " << sa.str()); throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); } - if ((m.m_mcfg.iIpV6Only == 0 || s->m_pUDT->m_config.iIpV6Only == 0) && m.m_iIPversion != addr.family()) + if ((m.m_mcfg.iIpV6Only == 0 || s->core().m_config.iIpV6Only == 0) && m.m_iIPversion != addr.family()) { LOGC(smlog.Error, log << "bind: Address: " << addr.str() << " conflicts with IPv6 wildcard binding: " << sa.str() @@ -3026,7 +3018,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U m.m_pSndQueue->init(m.m_pChannel, m.m_pTimer); m.m_pRcvQueue = new CRcvQueue; m.m_pRcvQueue->init( - 32, s->m_pUDT->maxPayloadSize(), m.m_iIPversion, 1024, + 32, s->core().maxPayloadSize(), m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer); // Rewrite the port here, as it might be only known upon return @@ -3127,8 +3119,8 @@ bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls) { // reuse the existing multiplexer ++ mux->m_iRefCount; - s->m_pUDT->m_pSndQueue = mux->m_pSndQueue; - s->m_pUDT->m_pRcvQueue = mux->m_pRcvQueue; + s->core().m_pSndQueue = mux->m_pSndQueue; + s->core().m_pRcvQueue = mux->m_pRcvQueue; s->m_iMuxID = mux->m_iID; return true; } @@ -3745,8 +3737,8 @@ int srt::CUDT::getsockopt( } #endif - CUDT* udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->m_pUDT; - udt->getOpt(optname, (pw_optval), (*pw_optlen)); + CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + udt.getOpt(optname, (pw_optval), (*pw_optlen)); return 0; } catch (const CUDTException& e) @@ -3777,8 +3769,8 @@ int srt::CUDT::setsockopt(SRTSOCKET u, int, SRT_SOCKOPT optname, const void* opt } #endif - CUDT* udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->m_pUDT; - udt->setOpt(optname, optval, optlen); + CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + udt.setOpt(optname, optval, optlen); return 0; } catch (const CUDTException& e) @@ -3889,8 +3881,8 @@ int64_t srt::CUDT::sendfile( { try { - CUDT* udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->m_pUDT; - return udt->sendfile(ifs, offset, size, block); + CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + return udt.sendfile(ifs, offset, size, block); } catch (const CUDTException& e) { @@ -4237,8 +4229,8 @@ int srt::CUDT::bstats(SRTSOCKET u, CBytePerfMon* perf, bool clear, bool instanta try { - CUDT* udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->m_pUDT; - udt->bstats(perf, clear, instantaneous); + CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + udt.bstats(perf, clear, instantaneous); return 0; } catch (const CUDTException& e) @@ -4281,7 +4273,7 @@ srt::CUDT* srt::CUDT::getUDTHandle(SRTSOCKET u) { try { - return s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->m_pUDT; + return &s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); } catch (const CUDTException& e) { diff --git a/srtcore/api.h b/srtcore/api.h index e1ba244f3..a1bfbffd7 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -76,6 +76,8 @@ namespace srt { class CUDT; +/// @brief Class CUDTSocket is a control layer on top of the CUDT core functionality layer. +/// CUDTSocket owns CUDT. class CUDTSocket { public: @@ -89,7 +91,26 @@ class CUDTSocket , m_GroupOf() #endif , m_iISN(0) - , m_pUDT(NULL) + , m_UDT(this) + , m_AcceptCond() + , m_AcceptLock() + , m_uiBackLog(0) + , m_iMuxID(-1) + { + construct(); + } + + CUDTSocket(const CUDTSocket& ancestor) + : m_Status(SRTS_INIT) + , m_SocketID(0) + , m_ListenSocket(0) + , m_PeerID(0) +#if ENABLE_EXPERIMENTAL_BONDING + , m_GroupMemberData() + , m_GroupOf() +#endif + , m_iISN(0) + , m_UDT(this, ancestor.m_UDT) , m_AcceptCond() , m_AcceptLock() , m_uiBackLog(0) @@ -125,8 +146,10 @@ class CUDTSocket int32_t m_iISN; //< initial sequence number, used to tell different connection from same IP:port - CUDT* m_pUDT; //< pointer to the UDT entity +private: + CUDT m_UDT; //< internal SRT socket logic +public: std::set m_QueuedSockets; //< set of connections waiting for accept() sync::Condition m_AcceptCond; //< used to block "accept" call @@ -149,7 +172,8 @@ class CUDTSocket sync::Mutex m_ControlLock; //< lock this socket exclusively for control APIs: bind/listen/connect - CUDT& core() { return *m_pUDT; } + CUDT& core() { return m_UDT; } + const CUDT& core() const { return m_UDT; } static int64_t getPeerSpec(SRTSOCKET id, int32_t isn) { @@ -188,7 +212,6 @@ class CUDTSocket bool broken() const; private: - CUDTSocket(const CUDTSocket&); CUDTSocket& operator=(const CUDTSocket&); }; diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 7c0f3acf5..c887218d9 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -4670,8 +4670,8 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, // the local port must be correctly assigned BEFORE CUDT::startConnect(), // otherwise if startConnect() fails, the multiplexer cannot be located // by garbage collection and will cause leak - s->m_pUDT->m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); - CIPAddress::pton((s->m_SelfAddr), s->m_pUDT->m_piSelfIP, m_PeerAddr); + s->core().m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); + CIPAddress::pton((s->m_SelfAddr), s->core().m_piSelfIP, m_PeerAddr); //int token = -1; #if ENABLE_EXPERIMENTAL_BONDING @@ -11154,10 +11154,10 @@ void srt::CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var) int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) { CUDTSocket *s = s_UDTUnited.locateSocket(u); - if (!s || !s->m_pUDT) + if (!s) return -1; - CSndBuffer *b = s->m_pUDT->m_pSndBuffer; + CSndBuffer *b = s->core().m_pSndBuffer; if (!b) return -1; @@ -11177,32 +11177,32 @@ int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) int srt::CUDT::rejectReason(SRTSOCKET u) { CUDTSocket* s = s_UDTUnited.locateSocket(u); - if (!s || !s->m_pUDT) + if (!s) return SRT_REJ_UNKNOWN; - return s->m_pUDT->m_RejectReason; + return s->core().m_RejectReason; } int srt::CUDT::rejectReason(SRTSOCKET u, int value) { CUDTSocket* s = s_UDTUnited.locateSocket(u); - if (!s || !s->m_pUDT) + if (!s) return APIError(MJ_NOTSUP, MN_SIDINVAL); if (value < SRT_REJC_PREDEFINED) return APIError(MJ_NOTSUP, MN_INVAL); - s->m_pUDT->m_RejectReason = value; + s->core().m_RejectReason = value; return 0; } int64_t srt::CUDT::socketStartTime(SRTSOCKET u) { CUDTSocket* s = s_UDTUnited.locateSocket(u); - if (!s || !s->m_pUDT) + if (!s) return APIError(MJ_NOTSUP, MN_SIDINVAL); - return count_microseconds(s->m_pUDT->m_stats.tsStartTime.time_since_epoch()); + return count_microseconds(s->core().m_stats.tsStartTime.time_since_epoch()); } bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs, const CPacket& hspkt) diff --git a/srtcore/group.cpp b/srtcore/group.cpp index f2f99201b..2c9bf5f6d 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -231,7 +231,7 @@ CUDTGroup::SocketData* CUDTGroup::add(SocketData data) gli_t end = m_Group.end(); if (m_iMaxPayloadSize == -1) { - int plsize = data.ps->m_pUDT->OPT_PayloadSize(); + int plsize = data.ps->core().OPT_PayloadSize(); HLOGC(gmlog.Debug, log << "CUDTGroup::add: taking MAX payload size from socket @" << data.ps->m_SocketID << ": " << plsize << " " << (plsize ? "(explicit)" : "(unspecified = fallback to 1456)")); @@ -2738,13 +2738,13 @@ void CUDTGroup::synchronizeDrift(CUDT* cu, steady_clock::duration udrift, steady continue; // Skip the entity that has reported this - if (cu == gi->ps->m_pUDT) + if (cu == &gi->ps->core()) continue; steady_clock::time_point this_timebase; steady_clock::duration this_udrift(0); bool wrp = false; - gi->ps->m_pUDT->m_pRcvBuffer->getInternalTimeBase((this_timebase), (wrp), (this_udrift)); + gi->ps->core().m_pRcvBuffer->getInternalTimeBase((this_timebase), (wrp), (this_udrift)); udrift = std::min(udrift, this_udrift); steady_clock::time_point new_newtimebase = std::min(newtimebase, this_timebase); @@ -2775,7 +2775,7 @@ void CUDTGroup::synchronizeDrift(CUDT* cu, steady_clock::duration udrift, steady if (gi->laststatus != SRTS_CONNECTED) continue; - gi->ps->m_pUDT->m_pRcvBuffer->applyGroupDrift(newtimebase, wrap_period, udrift); + gi->ps->core().m_pRcvBuffer->applyGroupDrift(newtimebase, wrap_period, udrift); } } @@ -3094,7 +3094,7 @@ void CUDTGroup::sendBackup_CheckIdleTime(gli_t w_d) // probability that the link will be recognized as IDLE on the // reception side ASAP. int32_t arg = 1; - w_d->ps->m_pUDT->sendCtrl(UMSG_KEEPALIVE, &arg); + w_d->ps->core().sendCtrl(UMSG_KEEPALIVE, &arg); } } @@ -4411,9 +4411,9 @@ void CUDTGroup::updateLatestRcv(CUDTSocket* s) HLOGC(grlog.Debug, log << "updateLatestRcv: BACKUP group, updating from active link @" << s->m_SocketID << " with %" - << s->m_pUDT->m_iRcvLastSkipAck); + << s->core().m_iRcvLastSkipAck); - CUDT* source = s->m_pUDT; + CUDT* source = &s->core(); vector targets; UniqueLock lg(m_GroupLock); @@ -4448,13 +4448,13 @@ void CUDTGroup::updateLatestRcv(CUDTSocket* s) } // Sanity check - if (!gi->ps->m_pUDT->m_bConnected) + if (!gi->ps->core().m_bConnected) { HLOGC(grlog.Debug, log << "grp: IPE: NOT updating rcv-seq on @" << gi->id << " - IDLE BUT NOT CONNECTED"); continue; } - targets.push_back(gi->ps->m_pUDT); + targets.push_back(&gi->ps->core()); } lg.unlock(); From 399e8bf69fde85bb107d30babf21402cf6789a2e Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 16 Aug 2021 10:53:12 +0200 Subject: [PATCH 068/124] [tests] Test FileUpload: find unused UDP port (#2086) --- test/test_file_transmission.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 790555eb7..8150ca3f2 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -45,17 +45,35 @@ TEST(Transmission, FileUpload) sa_lsn.sin_addr.s_addr = INADDR_ANY; sa_lsn.sin_port = htons(5555); + // Find unused a port not used by any other service. + // Otherwise srt_connect may actually connect. + int bind_res = -1; + for (int port = 5000; port <= 5555; ++port) + { + sa_lsn.sin_port = htons(port); + bind_res = srt_bind(sock_lsn, (sockaddr*)&sa_lsn, sizeof sa_lsn); + if (bind_res == 0) + { + std::cout << "Running test on port " << port << "\n"; + break; + } + + ASSERT_TRUE(bind_res == SRT_EINVOP) << "Bind failed not due to an occupied port. Result " << bind_res; + } + + ASSERT_GE(bind_res, 0); + srt_bind(sock_lsn, (sockaddr*)&sa_lsn, sizeof sa_lsn); int optval = 0; int optlen = sizeof optval; ASSERT_EQ(srt_getsockflag(sock_lsn, SRTO_SNDBUF, &optval, &optlen), 0); - size_t filesize = 7 * optval; + const size_t filesize = 7 * optval; { std::cout << "WILL CREATE source file with size=" << filesize << " (= 7 * " << optval << "[sndbuf])\n"; std::ofstream outfile("file.source", std::ios::out | std::ios::binary); - ASSERT_EQ(!!outfile, true); + ASSERT_EQ(!!outfile, true) << srt_getlasterror_str(); srand(time(0)); @@ -96,6 +114,7 @@ TEST(Transmission, FileUpload) ASSERT_NE(n, SRT_ERROR); if (n == 0) { + std::cerr << "Received 0 bytes, breaking.\n"; break; } @@ -110,7 +129,7 @@ TEST(Transmission, FileUpload) sockaddr_in sa = sockaddr_in(); sa.sin_family = AF_INET; - sa.sin_port = htons(5555); + sa.sin_port = sa_lsn.sin_port; ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr), 1); srt_connect(sock_clr, (sockaddr*)&sa, sizeof(sa)); @@ -126,8 +145,8 @@ TEST(Transmission, FileUpload) size_t shift = 0; while (n > 0) { - int st = srt_send(sock_clr, buf.data()+shift, n); - ASSERT_GT(st, 0); + const int st = srt_send(sock_clr, buf.data()+shift, n); + ASSERT_GT(st, 0) << srt_getlasterror_str(); n -= st; shift += st; From 0925d6891a9f1226de547293c3dd614f4df209cb Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 16 Aug 2021 15:38:18 +0200 Subject: [PATCH 069/124] [docs] Improved a note about srt_recv(..) and payload size (#2080) --- docs/API/API-functions.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/API/API-functions.md b/docs/API/API-functions.md index d59ce481e..58b729fad 100644 --- a/docs/API/API-functions.md +++ b/docs/API/API-functions.md @@ -1885,8 +1885,13 @@ 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 size of `SRTO_PAYLOADSIZE`. In this mode, -however, with default settings of [`SRTO_TSBPDMODE`](API-socket-options.md#SRTO_TSBPDMODE) +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 From 7e2d82bab90fc1dfddd312ebeddb153cc186ace3 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 17 Aug 2021 09:59:27 +0200 Subject: [PATCH 070/124] [apps] Fixed loop over OptionScheme (#2089) --- apps/apputil.cpp | 2 +- apps/apputil.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/apputil.cpp b/apps/apputil.cpp index bf808a95d..611b99976 100644 --- a/apps/apputil.cpp +++ b/apps/apputil.cpp @@ -251,7 +251,7 @@ options_t ProcessOptions(char* const* argv, int argc, std::vector } // Find the key in the scheme. If not found, treat it as ARG_NONE. - for (auto s: scheme) + for (const auto& s: scheme) { if (s.names().count(current_key)) { diff --git a/apps/apputil.hpp b/apps/apputil.hpp index 4f2b84bf7..5bac461e0 100644 --- a/apps/apputil.hpp +++ b/apps/apputil.hpp @@ -220,7 +220,7 @@ struct OptionScheme OptionScheme(const OptionName& id, Args tp); - const std::set& names(); + const std::set& names() const; }; struct OptionName @@ -265,7 +265,7 @@ struct OptionName }; inline OptionScheme::OptionScheme(const OptionName& id, Args tp): pid(&id), type(tp) {} -inline const std::set& OptionScheme::names() { return pid->names; } +inline const std::set& OptionScheme::names() const { return pid->names; } template inline typename OutType::type Option(const options_t&, OutValue deflt=OutValue()) { return deflt; } From aed5f2086d2029b0b323687f6d6377ffa54ccd2f Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 17 Aug 2021 12:04:27 +0200 Subject: [PATCH 071/124] [build] Default STDCXX_SYNC=ON on Windows, try to use CLOCK_MONOTONIC by default on Linux. (#2088) Updated Windows build instructions (default C++11). --- CMakeLists.txt | 27 ++++++++------ docs/build/build-win.md | 16 ++++++--- scripts/haiUtil.cmake | 79 ++++++++++++++++++++++------------------- 3 files changed, 71 insertions(+), 51 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f210ff34f..c1cb13ced 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,16 @@ if (ENABLE_DEBUG) endif() +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 (LINUX) + 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) option(ENABLE_CXX11 "Should the c++11 parts (srt-live-transmit) be enabled" ON) @@ -129,8 +139,8 @@ option(ENABLE_CXX_DEPS "Extra library dependencies in srt.pc for the CXX librari 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" OFF) -option(ENABLE_STDCXX_SYNC "Use C++11 chrono and threads for timing instead of pthreads" 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(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) @@ -265,6 +275,10 @@ if (DEFINED HAVE_INET_PTON) endif() 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() @@ -435,6 +449,7 @@ elseif (ENABLE_STDCXX_SYNC) 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) @@ -526,14 +541,6 @@ if (USE_STATIC_LIBSTDCXX) endif() endif() -# We need clock_gettime, but on some systems this is only provided -# by librt. Check if librt is required. -if (ENABLE_MONOTONIC_CLOCK AND LINUX) - # "requires" - exits on FATAL_ERROR when clock_gettime not available - test_requires_clock_gettime(NEED_CLOCK_GETTIME) - set (WITH_EXTRALIBS "${WITH_EXTRALIBS} ${NEED_CLOCK_GETTIME}") -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 diff --git a/docs/build/build-win.md b/docs/build/build-win.md index 3f47b310b..e09175142 100644 --- a/docs/build/build-win.md +++ b/docs/build/build-win.md @@ -54,7 +54,7 @@ only unencrypted mode can be used. With the enabled SRT encryption, one of the following Crypto libraries is required: -- `OpenSSL` (default) +- `OpenSSL` (**default**) - `LibreSSL` - `MbedTLS` @@ -62,8 +62,8 @@ one of the following Crypto libraries is required: SRT as of v1.4.2 supports two threading libraries: -- `pthreads` (default) -- Standard C++ thread library available in C++11 (recommended for Windows) +- Standard C++ thread library available in C++11 (**default on Windows**) +- `pthreads` (not recommended on Windows) The `pthreads` library is provided out-of-the-box on all POSIX-based systems. On Windows it can be provided as a 3rd party library (see below). @@ -73,6 +73,10 @@ However the C++ standard thread library is recommended to be used on Windows. #### 1.3.1. VCpkg Packet Manager (optional) +Can be used to: +- build OpenSSL library (dependency of SRT). +- build pthreads library (dependency of SRT). + [vcpkg](https://github.com/microsoft/vcpkg) is a C++ library manager for Windows, Linux and MacOS. Consider its [prerequisites](https://github.com/microsoft/vcpkg/blob/master/README.md#quick-start) before proceeding. @@ -181,8 +185,8 @@ to specify the directory that will contain the LibreSSL headers and libraries. SRT can use one of these two threading libraries: -- C++11 threads (SRT v1.4.2 and above) - recommended for Windows -- `pthreads` (default) +- C++11 threads (SRT v1.4.2 and above) - recommended, default since SRT v1.4.4; +- `pthreads` (not recommended on Windows). #### 2.2.1. Using C++11 Threading @@ -193,6 +197,8 @@ Otherwise the external PThreads for Windows wrapper library is required. #### 2.2.2. Building PThreads +It is not recommended to use `pthreads` port on Windows. Consider using [C++11 instead](#221-using-c11-threading), + ##### 2.2.2.1. Using vcpkg **Note!** The `vcpkg` working directory is referenced as `VCPKG_ROOT`. diff --git a/scripts/haiUtil.cmake b/scripts/haiUtil.cmake index e161f1e5b..9e4fb4d56 100644 --- a/scripts/haiUtil.cmake +++ b/scripts/haiUtil.cmake @@ -12,11 +12,11 @@ include(CheckCXXSourceCompiles) # Useful for combinging paths function(adddirname prefix lst out_lst) - set(output) - foreach(item ${lst}) - list(APPEND output "${prefix}/${item}") - endforeach() - set(${out_lst} ${${out_lst}} ${output} PARENT_SCOPE) + set(output) + foreach(item ${lst}) + list(APPEND output "${prefix}/${item}") + endforeach() + set(${out_lst} ${${out_lst}} ${output} PARENT_SCOPE) endfunction() # Splits a version formed as "major.minor.patch" recorded in variable 'prefix' @@ -32,11 +32,11 @@ ENDMACRO(set_version_variables) # Sets given variable to 1, if the condition that follows it is satisfied. # Otherwise set it to 0. MACRO(set_if varname) - IF(${ARGN}) - SET(${varname} 1) - ELSE(${ARGN}) - SET(${varname} 0) - ENDIF(${ARGN}) + IF(${ARGN}) + SET(${varname} 1) + ELSE(${ARGN}) + SET(${varname} 0) + ENDIF(${ARGN}) ENDMACRO(set_if) FUNCTION(join_arguments outvar) @@ -80,11 +80,11 @@ MACRO(MafReadDir directory maffile) configure_file(${directory}/${maffile} dummy_${maffile}.cmake.out) file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/dummy_${maffile}.cmake.out) - #message("DEBUG: MAF FILE CONTENTS: ${MAFREAD_CONTENTS}") - #message("DEBUG: PASSED VARIABLES:") - #foreach(DEBUG_VAR ${MAFREAD_TAGS}) - # message("DEBUG: ${DEBUG_VAR}=${MAFREAD_VAR_${DEBUG_VAR}}") - #endforeach() + #message("DEBUG: MAF FILE CONTENTS: ${MAFREAD_CONTENTS}") + #message("DEBUG: PASSED VARIABLES:") + #foreach(DEBUG_VAR ${MAFREAD_TAGS}) + # message("DEBUG: ${DEBUG_VAR}=${MAFREAD_VAR_${DEBUG_VAR}}") + #endforeach() # The unnamed section becomes SOURCES set (MAFREAD_VARIABLE ${MAFREAD_VAR_SOURCES}) @@ -186,15 +186,15 @@ MACRO(MafReadDir directory maffile) ENDFOREACH() # Final debug report - #set (ALL_VARS "") - #message("DEBUG: extracted variables:") - #foreach(DEBUG_VAR ${MAFREAD_TAGS}) - # list(APPEND ALL_VARS ${MAFREAD_VAR_${DEBUG_VAR}}) - #endforeach() - #list(REMOVE_DUPLICATES ALL_VARS) - #foreach(DEBUG_VAR ${ALL_VARS}) - # message("DEBUG: --> ${DEBUG_VAR} = ${${DEBUG_VAR}}") - #endforeach() + #set (ALL_VARS "") + #message("DEBUG: extracted variables:") + #foreach(DEBUG_VAR ${MAFREAD_TAGS}) + # list(APPEND ALL_VARS ${MAFREAD_VAR_${DEBUG_VAR}}) + #endforeach() + #list(REMOVE_DUPLICATES ALL_VARS) + #foreach(DEBUG_VAR ${ALL_VARS}) + # message("DEBUG: --> ${DEBUG_VAR} = ${${DEBUG_VAR}}") + #endforeach() ENDMACRO(MafReadDir) # NOTE: This is historical only. Not in use. @@ -214,9 +214,9 @@ MACRO(GetMafHeaders directory outvar) ENDMACRO(GetMafHeaders) function (getVarsWith _prefix _varResult) - get_cmake_property(_vars VARIABLES) - string (REGEX MATCHALL "(^|;)${_prefix}[A-Za-z0-9_]*" _matchedVars "${_vars}") - set (${_varResult} ${_matchedVars} PARENT_SCOPE) + get_cmake_property(_vars VARIABLES) + string (REGEX MATCHALL "(^|;)${_prefix}[A-Za-z0-9_]*" _matchedVars "${_vars}") + set (${_varResult} ${_matchedVars} PARENT_SCOPE) endfunction() function (check_testcode_compiles testcode libraries _successful) @@ -228,15 +228,18 @@ function (check_testcode_compiles testcode libraries _successful) set (CMAKE_REQUIRED_LIBRARIES ${save_required_libraries}) endfunction() -function (test_requires_clock_gettime _result) +function (test_requires_clock_gettime _enable _linklib) # This function tests if clock_gettime can be used # - at all # - with or without librt # Result will be: - # rt (if librt required) - # "" (if no extra libraries required) - # -- killed by FATAL_ERROR if clock_gettime is not available + # - CLOCK_MONOTONIC is available, link with librt: + # _enable = ON; _linklib = "-lrt". + # - CLOCK_MONOTONIC is available, link without librt: + # _enable = ON; _linklib = "". + # - CLOCK_MONOTONIC is not available: + # _enable = OFF; _linklib = "-". set (code " #include @@ -249,19 +252,23 @@ function (test_requires_clock_gettime _result) check_testcode_compiles(${code} "" HAVE_CLOCK_GETTIME_IN) if (HAVE_CLOCK_GETTIME_IN) - message(STATUS "Checked clock_gettime(): no extra libs needed") - set (${_result} "" PARENT_SCOPE) + message(STATUS "CLOCK_MONOTONIC: availabe, no extra libs needed") + set (${_enable} ON PARENT_SCOPE) + set (${_linklib} "" PARENT_SCOPE) return() endif() check_testcode_compiles(${code} "rt" HAVE_CLOCK_GETTIME_LIBRT) if (HAVE_CLOCK_GETTIME_LIBRT) - message(STATUS "Checked clock_gettime(): requires -lrt") - set (${_result} "-lrt" PARENT_SCOPE) + message(STATUS "CLOCK_MONOTONIC: available, requires -lrt") + set (${_enable} ON PARENT_SCOPE) + set (${_linklib} "-lrt" PARENT_SCOPE) return() endif() - message(FATAL_ERROR "clock_gettime() is not available on this system") + set (${_enable} OFF PARENT_SCOPE) + set (${_linklib} "-" PARENT_SCOPE) + message(STATUS "CLOCK_MONOTONIC: not available on this system") endfunction() function (parse_compiler_type wct _type _suffix) From 9475ad0ec04cd67cf7b43ddd9a53230ee09df769 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 17 Aug 2021 11:08:52 +0200 Subject: [PATCH 072/124] [core] Removed redundant srt namespace scope resolution in CUDT --- srtcore/core.h | 90 +++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/srtcore/core.h b/srtcore/core.h index 6b8472c64..9c9a38f04 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -172,8 +172,8 @@ class CUDT typedef sync::steady_clock::time_point time_point; typedef sync::steady_clock::duration duration; - typedef srt::sync::AtomicClock atomic_time_point; - typedef srt::sync::AtomicDuration atomic_duration; + typedef sync::AtomicClock atomic_time_point; + typedef sync::AtomicDuration atomic_duration; private: // constructor and desctructor void construct(); @@ -313,8 +313,8 @@ class CUDT int32_t schedSeqNo() const { return m_iSndNextSeqNo; } bool overrideSndSeqNo(int32_t seq); - srt::sync::steady_clock::time_point lastRspTime() const { return m_tsLastRspTime.load(); } - srt::sync::steady_clock::time_point freshActivationStart() const { return m_tsFreshActivation; } + sync::steady_clock::time_point lastRspTime() const { return m_tsLastRspTime.load(); } + sync::steady_clock::time_point freshActivationStart() const { return m_tsFreshActivation; } int32_t rcvSeqNo() const { return m_iRcvCurrSeqNo; } int flowWindowSize() const { return m_iFlowWindowSize; } @@ -386,7 +386,7 @@ class CUDT // So, this can be simply defined as: TS = (RTS - STS) % (MAX_TIMESTAMP+1) // XXX Would be nice to check if local_time > m_tsStartTime, // otherwise it may go unnoticed with clock skew. - return (int32_t) srt::sync::count_microseconds(from_time - m_stats.tsStartTime); + return (int32_t) sync::count_microseconds(from_time - m_stats.tsStartTime); } void setPacketTS(CPacket& p, const time_point& local_time) @@ -398,14 +398,14 @@ class CUDT // immediately to free the socket void notListening() { - srt::sync::ScopedLock cg(m_ConnectionLock); + sync::ScopedLock cg(m_ConnectionLock); m_bListening = false; m_pRcvQueue->removeListener(this); } static int32_t generateISN() { - using namespace srt::sync; + using namespace sync; return genRandomInt(0, CSeqNo::m_iMaxSeqNo); } @@ -420,8 +420,8 @@ class CUDT SRTU_PROPERTY_RO(CRcvBuffer*, rcvBuffer, m_pRcvBuffer); SRTU_PROPERTY_RO(bool, isTLPktDrop, m_bTLPktDrop); SRTU_PROPERTY_RO(bool, isSynReceiving, m_config.bSynRecving); - SRTU_PROPERTY_RR(srt::sync::Condition*, recvDataCond, &m_RecvDataCond); - SRTU_PROPERTY_RR(srt::sync::Condition*, recvTsbPdCond, &m_RcvTsbPdCond); + SRTU_PROPERTY_RR(sync::Condition*, recvDataCond, &m_RecvDataCond); + SRTU_PROPERTY_RR(sync::Condition*, recvTsbPdCond, &m_RcvTsbPdCond); /// @brief Request a socket to be broken due to too long instability (normally by a group). void breakAsUnstable() { m_bBreakAsUnstable = true; } @@ -734,30 +734,30 @@ class CUDT void EmitSignal(ETransmissionEvent tev, EventVariant var); // Internal state - srt::sync::atomic m_bListening; // If the UDT entity is listening to connection - srt::sync::atomic m_bConnecting; // The short phase when connect() is called but not yet completed - srt::sync::atomic m_bConnected; // Whether the connection is on or off - srt::sync::atomic m_bClosing; // If the UDT entity is closing - srt::sync::atomic m_bShutdown; // If the peer side has shutdown the connection - srt::sync::atomic m_bBroken; // If the connection has been broken - srt::sync::atomic m_bBreakAsUnstable; // A flag indicating that the socket should become broken because it has been unstable for too long. - srt::sync::atomic m_bPeerHealth; // If the peer status is normal - srt::sync::atomic m_RejectReason; + sync::atomic m_bListening; // If the UDT entity is listening to connection + sync::atomic m_bConnecting; // The short phase when connect() is called but not yet completed + sync::atomic m_bConnected; // Whether the connection is on or off + sync::atomic m_bClosing; // If the UDT entity is closing + sync::atomic m_bShutdown; // If the peer side has shutdown the connection + sync::atomic m_bBroken; // If the connection has been broken + sync::atomic m_bBreakAsUnstable; // A flag indicating that the socket should become broken because it has been unstable for too long. + sync::atomic m_bPeerHealth; // If the peer status is normal + sync::atomic m_RejectReason; bool m_bOpened; // If the UDT entity has been opened - srt::sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected + sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected int m_iEXPCount; // Expiration counter - srt::sync::atomic m_iBandwidth; // Estimated bandwidth, number of packets per second - srt::sync::atomic m_iSRTT; // Smoothed RTT (an exponentially-weighted moving average (EWMA) + sync::atomic m_iBandwidth; // Estimated bandwidth, number of packets per second + sync::atomic m_iSRTT; // Smoothed RTT (an exponentially-weighted moving average (EWMA) // of an endpoint's RTT samples), in microseconds - srt::sync::atomic m_iRTTVar; // The variation in the RTT samples (RTT variance), in microseconds - srt::sync::atomic m_bIsFirstRTTReceived;// True if the first RTT sample was obtained from the ACK/ACKACK pair + sync::atomic m_iRTTVar; // The variation in the RTT samples (RTT variance), in microseconds + sync::atomic m_bIsFirstRTTReceived; // True if the first RTT sample was obtained from the ACK/ACKACK pair // at the receiver side or received by the sender from an ACK packet. // It's used to reset the initial value of smoothed RTT (m_iSRTT) // at the beginning of transmission (including the one taken from // cache). False by default. - srt::sync::atomic m_iDeliveryRate; // Packet arrival rate at the receiver side - srt::sync::atomic m_iByteDeliveryRate; // Byte arrival rate at the receiver side + sync::atomic m_iDeliveryRate; // Packet arrival rate at the receiver side + sync::atomic m_iByteDeliveryRate; // Byte arrival rate at the receiver side CHandShake m_ConnReq; // Connection request CHandShake m_ConnRes; // Connection response @@ -773,7 +773,7 @@ class CUDT atomic_duration m_tdSendTimeDiff; // Aggregate difference in inter-packet sending time - srt::sync::atomic m_iFlowWindowSize; // Flow control window size + sync::atomic m_iFlowWindowSize; // Flow control window size double m_dCongestionWindow; // Congestion window size private: // Timers @@ -798,8 +798,8 @@ class CUDT time_point m_tsNextSendTime; // Scheduled time of next packet sending - srt::sync::atomic m_iSndLastFullAck;// Last full ACK received - srt::sync::atomic m_iSndLastAck; // Last ACK received + sync::atomic m_iSndLastFullAck; // Last full ACK received + sync::atomic m_iSndLastAck; // Last ACK received // NOTE: m_iSndLastDataAck is the value strictly bound to the CSndBufer object (m_pSndBuffer) // and this is the sequence number that refers to the block at position [0]. Upon acknowledgement, @@ -809,9 +809,9 @@ class CUDT // to the sending buffer. This way, extraction of an old packet for retransmission should // require only the lost sequence number, and how to find the packet with this sequence // will be up to the sending buffer. - srt::sync::atomic m_iSndLastDataAck;// The real last ACK that updates the sender buffer and loss list - srt::sync::atomic m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT - srt::sync::atomic m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet + sync::atomic m_iSndLastDataAck;// The real last ACK that updates the sender buffer and loss list + sync::atomic m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT + sync::atomic m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet // Note important differences between Curr and Next fields: // - m_iSndCurrSeqNo: this is used by SRT:SndQ:worker thread and it's operated from CUDT::packData @@ -873,7 +873,7 @@ class CUDT int32_t m_iRcvLastSkipAck; // Last dropped sequence ACK int32_t m_iRcvLastAckAck; // Last sent ACK that has been acknowledged int32_t m_iAckSeqNo; // Last ACK sequence number - srt::sync::atomic m_iRcvCurrSeqNo; // Largest received sequence number + sync::atomic m_iRcvCurrSeqNo; // Largest received sequence number int32_t m_iRcvCurrPhySeqNo; // Same as m_iRcvCurrSeqNo, but physical only (disregarding a filter) int32_t m_iPeerISN; // Initial Sequence Number of the peer side @@ -884,10 +884,10 @@ class CUDT bool m_bTsbPd; // Peer sends TimeStamp-Based Packet Delivery Packets bool m_bGroupTsbPd; // TSBPD should be used for GROUP RECEIVER instead - srt::sync::CThread m_RcvTsbPdThread; // Rcv TsbPD Thread handle - srt::sync::Condition m_RcvTsbPdCond; // TSBPD signals if reading is ready. Use together with m_RecvLock + sync::CThread m_RcvTsbPdThread; // Rcv TsbPD Thread handle + sync::Condition m_RcvTsbPdCond; // TSBPD signals if reading is ready. Use together with m_RecvLock bool m_bTsbPdAckWakeup; // Signal TsbPd thread on Ack sent - srt::sync::Mutex m_RcvTsbPdStartupLock; // Protects TSBPD thread creating and joining + sync::Mutex m_RcvTsbPdStartupLock; // Protects TSBPD thread creating and joining CallbackHolder m_cbAcceptHook; CallbackHolder m_cbConnectHook; @@ -909,21 +909,21 @@ class CUDT private: // synchronization: mutexes and conditions - srt::sync::Mutex m_ConnectionLock; // used to synchronize connection operation + sync::Mutex m_ConnectionLock; // used to synchronize connection operation - srt::sync::Condition m_SendBlockCond; // used to block "send" call - srt::sync::Mutex m_SendBlockLock; // lock associated to m_SendBlockCond + sync::Condition m_SendBlockCond; // used to block "send" call + sync::Mutex m_SendBlockLock; // lock associated to m_SendBlockCond - srt::sync::Mutex m_RcvBufferLock; // Protects the state of the m_pRcvBuffer + sync::Mutex m_RcvBufferLock; // Protects the state of the m_pRcvBuffer // Protects access to m_iSndCurrSeqNo, m_iSndLastAck - srt::sync::Mutex m_RecvAckLock; // Protects the state changes while processing incomming ACK (SRT_EPOLL_OUT) + sync::Mutex m_RecvAckLock; // Protects the state changes while processing incomming ACK (SRT_EPOLL_OUT) - srt::sync::Condition m_RecvDataCond; // used to block "srt_recv*" when there is no data. Use together with m_RecvLock - srt::sync::Mutex m_RecvLock; // used to synchronize "srt_recv*" call, protects TSBPD drift updates (CRcvBuffer::isRcvDataReady()) + sync::Condition m_RecvDataCond; // used to block "srt_recv*" when there is no data. Use together with m_RecvLock + sync::Mutex m_RecvLock; // used to synchronize "srt_recv*" call, protects TSBPD drift updates (CRcvBuffer::isRcvDataReady()) - srt::sync::Mutex m_SendLock; // used to synchronize "send" call - srt::sync::Mutex m_RcvLossLock; // Protects the receiver loss list (access: CRcvQueue::worker, CUDT::tsbpd) - mutable srt::sync::Mutex m_StatsLock; // used to synchronize access to trace statistics + sync::Mutex m_SendLock; // used to synchronize "send" call + sync::Mutex m_RcvLossLock; // Protects the receiver loss list (access: CRcvQueue::worker, CUDT::tsbpd) + mutable sync::Mutex m_StatsLock; // used to synchronize access to trace statistics void initSynch(); void destroySynch(); From 675e75de015f61c156a1c9fa50a3e8607d721e5a Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 17 Aug 2021 11:12:21 +0200 Subject: [PATCH 073/124] [core] Added SRT_ATTR_GUARDED_BY to some members of CUDT. Imported from #1859. Co-authored-by: Mikolaj Malecki --- srtcore/core.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/srtcore/core.h b/srtcore/core.h index 9c9a38f04..a9d2f9dc3 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -744,7 +744,7 @@ class CUDT sync::atomic m_bPeerHealth; // If the peer status is normal sync::atomic m_RejectReason; bool m_bOpened; // If the UDT entity has been opened - sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected + sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected int m_iEXPCount; // Expiration counter sync::atomic m_iBandwidth; // Estimated bandwidth, number of packets per second @@ -773,6 +773,7 @@ class CUDT atomic_duration m_tdSendTimeDiff; // Aggregate difference in inter-packet sending time + SRT_ATTR_GUARDED_BY(m_RecvAckLock) sync::atomic m_iFlowWindowSize; // Flow control window size double m_dCongestionWindow; // Congestion window size @@ -782,6 +783,7 @@ class CUDT duration m_tdACKInterval; // ACK interval duration m_tdNAKInterval; // NAK interval + SRT_ATTR_GUARDED_BY(m_RecvAckLock) atomic_time_point m_tsLastRspTime; // Timestamp of last response from the peer time_point m_tsLastRspAckTime; // Timestamp of last ACK from the peer atomic_time_point m_tsLastSndTime; // Timestamp of last data/ctrl sent (in system ticks) @@ -799,6 +801,7 @@ class CUDT time_point m_tsNextSendTime; // Scheduled time of next packet sending sync::atomic m_iSndLastFullAck; // Last full ACK received + SRT_ATTR_GUARDED_BY(m_RecvAckLock) sync::atomic m_iSndLastAck; // Last ACK received // NOTE: m_iSndLastDataAck is the value strictly bound to the CSndBufer object (m_pSndBuffer) @@ -809,9 +812,9 @@ class CUDT // to the sending buffer. This way, extraction of an old packet for retransmission should // require only the lost sequence number, and how to find the packet with this sequence // will be up to the sending buffer. - sync::atomic m_iSndLastDataAck;// The real last ACK that updates the sender buffer and loss list - sync::atomic m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT - sync::atomic m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet + sync::atomic m_iSndLastDataAck; // The real last ACK that updates the sender buffer and loss list + sync::atomic m_iSndCurrSeqNo; // The largest sequence number that HAS BEEN SENT + sync::atomic m_iSndNextSeqNo; // The sequence number predicted to be placed at the currently scheduled packet // Note important differences between Curr and Next fields: // - m_iSndCurrSeqNo: this is used by SRT:SndQ:worker thread and it's operated from CUDT::packData @@ -853,6 +856,8 @@ class CUDT bool m_bPeerTLPktDrop; // Enable sender late packet dropping bool m_bPeerNakReport; // Sender's peer (receiver) issues Periodic NAK Reports bool m_bPeerRexmitFlag; // Receiver supports rexmit flag in payload packets + + SRT_ATTR_GUARDED_BY(m_RecvAckLock) int32_t m_iReXmitCount; // Re-Transmit Count since last ACK private: // Receiving related data From 4fe19fcd2718602bab508a7cc5ccd57e4dd3ccd0 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 18 Aug 2021 11:18:38 +0200 Subject: [PATCH 074/124] [docs] Updated RCV buffer size calculation guide. Using long long for high bitrates. --- docs/API/configuration-guidelines.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/API/configuration-guidelines.md b/docs/API/configuration-guidelines.md index 54d3cd15a..83693d1f1 100644 --- a/docs/API/configuration-guidelines.md +++ b/docs/API/configuration-guidelines.md @@ -87,13 +87,12 @@ where ```c++ - auto CalculateTargetRBufSize(int msRTT, int bpsRate, int bytesPayloadSize, int msLatency, int SRTO_MSS) { const int UDPHDR_SIZE = 28; - const int targetPayloadBytes = (msLatency + msRTT / 2) * bpsRate / 1000 / 8; - const int targetNumPackets = targetPayloadBytes / bytesPayloadSize; - const int targetSizeValue = targetNumPackets * (SRTO_MSS - UDPHDR_SIZE); + 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}; } From 67f70d0e6039ef0cf795e7b9f61b523dab6f17ce Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 17 Aug 2021 15:46:31 +0200 Subject: [PATCH 075/124] [apps] Fixed testing apps building with GCC 4.8 --- testing/testactivemedia.hpp | 2 +- testing/testmediabase.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index b94ff9aa3..06a1cd922 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -29,7 +29,7 @@ struct Medium std::mutex buffer_lock; std::thread thr; std::condition_variable ready; - std::atomic running {false}; + std::atomic running = {false}; std::exception_ptr xp; // To catch exception thrown by a thread virtual void Runner() = 0; diff --git a/testing/testmediabase.hpp b/testing/testmediabase.hpp index 3eb16a4bb..04a85d435 100644 --- a/testing/testmediabase.hpp +++ b/testing/testmediabase.hpp @@ -11,6 +11,7 @@ #ifndef INC_SRT_COMMON_TRANMITBASE_HPP #define INC_SRT_COMMON_TRANMITBASE_HPP +#include #include #include #include From 5f37067ce077b417bafb4f4e7a0766a3f794efe8 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 18 Aug 2021 11:38:23 +0200 Subject: [PATCH 076/124] [apps] Workaround bad move semantics of OptionScheme. OptionScheme::pid does not own an object. --- testing/srt-test-multiplex.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/testing/srt-test-multiplex.cpp b/testing/srt-test-multiplex.cpp index 2b6b2b2af..859547069 100644 --- a/testing/srt-test-multiplex.cpp +++ b/testing/srt-test-multiplex.cpp @@ -464,11 +464,15 @@ int main( int argc, char** argv ) } } cleanupobj; - // Check options + const OptionName + o_loglevel = { "ll", "loglevel" }, + o_input = { "i" }, + o_output = { "o" }; + vector optargs = { - { {"ll", "loglevel"}, OptionScheme::ARG_ONE }, - { {"i"}, OptionScheme::ARG_VAR }, - { {"o"}, OptionScheme::ARG_VAR } + { o_loglevel, OptionScheme::ARG_ONE }, + { o_input, OptionScheme::ARG_VAR }, + { o_output, OptionScheme::ARG_VAR } }; map> params = ProcessOptions(argv, argc, optargs); From 74aff8287caf404cdcb7b33172412709a1a20821 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 18 Aug 2021 12:44:40 +0200 Subject: [PATCH 077/124] [build] Bump version to 1.4.4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1cb13ced..a52dbad49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ # cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR) -set (SRT_VERSION 1.4.3) +set (SRT_VERSION 1.4.4) set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts") include(haiUtil) # needed for set_version_variables From 8b1be6196f109f2fb8a1a791bfb092e9ca41af36 Mon Sep 17 00:00:00 2001 From: ThibaultBee <37510686+ThibaultBee@users.noreply.github.com> Date: Mon, 23 Aug 2021 12:15:40 +0200 Subject: [PATCH 078/124] [build] Fixed ENABLE_MONOTONIC_CLOCK=ON when target is Android --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a52dbad49..242bf7e70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,8 @@ 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(POSIX LINUX OR DARWIN OR BSD OR (CYGWIN AND CYGWIN_USE_POSIX)) +set_if(ANDROID ${CMAKE_SYSTEM_NAME} MATCHES "ANDROID") +set_if(POSIX LINUX OR DARWIN OR BSD OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX)) set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR CYGWIN OR GNU) # Not sure what to do in case of compiling by MSVC. @@ -114,7 +115,7 @@ set(ENABLE_MONOTONIC_CLOCK_DEFAULT OFF) set(MONOTONIC_CLOCK_LINKLIB "") if (MICROSOFT) set(ENABLE_STDCXX_SYNC_DEFAULT ON) -elseif (LINUX) +elseif (POSIX) test_requires_clock_gettime(ENABLE_MONOTONIC_CLOCK_DEFAULT MONOTONIC_CLOCK_LINKLIB) endif() From cbdd676aa50d4517eb634f54ece27f93894f4f0d Mon Sep 17 00:00:00 2001 From: "guangqing.chen" Date: Sat, 21 Aug 2021 15:50:53 +0800 Subject: [PATCH 079/124] [core] Added missing lock for isRcvDataReady() --- srtcore/group.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/srtcore/group.cpp b/srtcore/group.cpp index 2c9bf5f6d..e835453ea 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -2071,11 +2071,13 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& readReady.push_back(*sockiter); } - else if (sock->core().m_pRcvBuffer->isRcvDataReady()) + else { // No read-readiness reported by epoll, but probably missed or not yet handled // as the receiver buffer is read-ready. - readReady.push_back(sock); + ScopedLock lg(sock->core().m_RcvBufferLock); + if (sock->core().m_pRcvBuffer && sock->core().m_pRcvBuffer->isRcvDataReady()) + readReady.push_back(sock); } } From ab9e69b28d2193e4f407537e2c144fdae09628a0 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 25 Aug 2021 10:45:22 +0200 Subject: [PATCH 080/124] [docs] Removed a reference to YAML syntax as it is not used actually. See #2047. --- docs/features/access-control.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/access-control.md b/docs/features/access-control.md index 101502566..d583f795b 100644 --- a/docs/features/access-control.md +++ b/docs/features/access-control.md @@ -46,7 +46,7 @@ specification in POSIX: `#!`. The next two characters are: -- `:` - this marks the YAML format, the only one currently used +- `:` - marks the format of the following key-value pair syntax (the only one defined currently). - The content format, which is either: - `:` - the comma-separated keys with no nesting - `{` - like above, but nesting is allowed and must end with `}` From da706240d10332ae9bb804558823996963f7160d Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Wed, 25 Aug 2021 03:46:55 -0500 Subject: [PATCH 081/124] [build] Fix Build for Android. (#2100) Some versions of CMake set CMAKE_SYSTEM_NAME to "Android". Link the atomic library for Android targets. --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 242bf7e70..4d817261a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ 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 ${CMAKE_SYSTEM_NAME} MATCHES "ANDROID") +set_if(ANDROID "${CMAKE_SYSTEM_NAME}" MATCHES "^[Aa][Nn][Dd][Rr][Oo][Ii][Dd]") set_if(POSIX LINUX OR DARWIN OR BSD OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX)) set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR CYGWIN OR GNU) @@ -867,6 +867,8 @@ if (srt_libspec_shared) target_link_libraries(${TARGET_srt}_shared PRIVATE wsock32.lib ws2_32.lib) elseif (APPLE) set_property(TARGET ${TARGET_srt}_shared PROPERTY MACOSX_RPATH ON) + elseif (ANDROID) + target_link_libraries(${TARGET_srt}_shared PRIVATE atomic) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_shared PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) @@ -901,6 +903,8 @@ if (srt_libspec_static) endif() elseif (MINGW) target_link_libraries(${TARGET_srt}_static PRIVATE wsock32 ws2_32) + elseif (ANDROID) + target_link_libraries(${TARGET_srt}_static PUBLIC atomic) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_static PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) From fb0987500f1fbc33ef156c13768646adcd7af7be Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Fri, 27 Aug 2021 04:51:42 -0500 Subject: [PATCH 082/124] [build] Fix build for Linux GLIBC-2.8 and earlier. (#2103) --- srtcore/epoll.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index bfce672cc..d4919ff39 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -112,11 +112,31 @@ int CEPoll::create(CEPollDesc** pout) int localid = 0; #ifdef LINUX - int flags = 0; -#if ENABLE_SOCK_CLOEXEC - flags |= EPOLL_CLOEXEC; -#endif - localid = epoll_create1(flags); + + // NOTE: epoll_create1() and EPOLL_CLOEXEC were introduced in GLIBC-2.9. + // So earlier versions of GLIBC, must use epoll_create() and set + // FD_CLOEXEC on the file descriptor returned by it after the fact. + #if defined(EPOLL_CLOEXEC) + int flags = 0; + #if ENABLE_SOCK_CLOEXEC + flags |= EPOLL_CLOEXEC; + #endif + localid = epoll_create1(flags); + #else + localid = epoll_create(1); + #if ENABLE_SOCK_CLOEXEC + if (localid != -1) + { + int fdFlags = fcntl(localid, F_GETFD); + if (fdFlags != -1) + { + fdFlags |= FD_CLOEXEC; + fcntl(localid, F_SETFD, fdFlags); + } + } + #endif + #endif + /* Possible reasons of -1 error: EMFILE: The per-user limit on the number of epoll instances imposed by /proc/sys/fs/epoll/max_user_instances was encountered. ENFILE: The system limit on the total number of open files has been reached. From 4fc0f317b04196b9f36c5ac46ba4f357295baa50 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 30 Aug 2021 16:18:02 +0200 Subject: [PATCH 083/124] [build] Use lowercase CMAKE_SYSTEM_NAME on Android --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d817261a..ed2253b05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ 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 "${CMAKE_SYSTEM_NAME}" MATCHES "^[Aa][Nn][Dd][Rr][Oo][Ii][Dd]") +set_if(ANDROID ${SYSNAME_LC} MATCHES "android") set_if(POSIX LINUX OR DARWIN OR BSD OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX)) set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR CYGWIN OR GNU) From 409a40d408090c56026413e5706414f1363aa430 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Tue, 31 Aug 2021 12:02:28 +0200 Subject: [PATCH 084/124] [core] Detect pthread_getname* availability --- CMakeLists.txt | 3 ++ scripts/FindPThreadGetSetName.cmake | 82 +++++++++++++++++++++++++++++ srtcore/srt_attr_defs.h | 2 +- srtcore/threadname.h | 57 ++++++++++++++++---- 4 files changed, 134 insertions(+), 10 deletions(-) create mode 100644 scripts/FindPThreadGetSetName.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ed2253b05..3693b5b37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,9 @@ if (DEFINED HAVE_INET_PTON) add_definitions(-DHAVE_INET_PTON=1) endif() +include(FindPThreadGetSetName) +FindPThreadGetSetName() # Defines HAVE_PTHREAD_GETNAME_* and HAVE_PTHREAD_SETNAME_* + 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.") diff --git a/scripts/FindPThreadGetSetName.cmake b/scripts/FindPThreadGetSetName.cmake new file mode 100644 index 000000000..fa818fd73 --- /dev/null +++ b/scripts/FindPThreadGetSetName.cmake @@ -0,0 +1,82 @@ +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021 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/. +# + +# Check for pthread_getname_np(3) and pthread_setname_np(3) +# used in srtcore/threadname.h. +# +# Some BSD distros need to include for pthread_getname_np(). +# +# TODO: Some BSD distros have pthread_get_name_np() and pthread_set_name_np() +# instead of pthread_getname_np() and pthread_setname_np(). +# +# Sets: +# HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H +# HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H +# HAVE_PTHREAD_GETNAME_NP +# HAVE_PTHREAD_SETNAME_NP +# Sets as appropriate: +# add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1) +# add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1) +# add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1) +# add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) + +include(CheckSymbolExists) + +function(FindPThreadGetSetName) + + unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE) + unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H CACHE) + unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE) + unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H CACHE) + + unset(HAVE_PTHREAD_GETNAME_NP) + unset(HAVE_PTHREAD_GETNAME_NP PARENT_SCOPE) + unset(HAVE_PTHREAD_GETNAME_NP CACHE) + unset(HAVE_PTHREAD_SETNAME_NP) + unset(HAVE_PTHREAD_SETNAME_NP PARENT_SCOPE) + unset(HAVE_PTHREAD_SETNAME_NP CACHE) + + set(CMAKE_REQUIRED_DEFINITIONS + -D_GNU_SOURCE -D_DARWIN_C_SOURCE -D_POSIX_SOURCE=1) + set(CMAKE_REQUIRED_FLAGS "-pthread") + + message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread_np.h':") + check_symbol_exists( + pthread_getname_np "pthread_np.h" HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1) + endif() + check_symbol_exists( + pthread_setname_np "pthread_np.h" HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1) + endif() + + message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread.h':") + check_symbol_exists(pthread_getname_np "pthread.h" HAVE_PTHREAD_GETNAME_NP) + if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + set(HAVE_PTHREAD_GETNAME_NP TRUE PARENT_SCOPE) + endif() + check_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) + if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + set(HAVE_PTHREAD_SETNAME_NP TRUE PARENT_SCOPE) + endif() + if (HAVE_PTHREAD_GETNAME_NP) + add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1) + endif() + if (HAVE_PTHREAD_SETNAME_NP) + add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) + endif() + + unset(CMAKE_REQUIRED_DEFINITIONS) + unset(CMAKE_REQUIRED_FLAGS) + +endfunction(FindPThreadGetSetName) diff --git a/srtcore/srt_attr_defs.h b/srtcore/srt_attr_defs.h index 82e6e5e3a..00d35e069 100644 --- a/srtcore/srt_attr_defs.h +++ b/srtcore/srt_attr_defs.h @@ -116,7 +116,7 @@ used by SRT library internally. #define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS #else -#if defined(__clang__) +#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5) #define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) #else #define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op diff --git a/srtcore/threadname.h b/srtcore/threadname.h index 2b3964276..e392f6d8e 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -16,24 +16,60 @@ written by #ifndef INC_SRT_THREADNAME_H #define INC_SRT_THREADNAME_H -#if defined(__APPLE__) || defined(__linux__) -#if defined(__linux__) -#include +// NOTE: +// HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H +// HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H +// HAVE_PTHREAD_GETNAME_NP +// HAVE_PTHREAD_GETNAME_NP +// Are detected and set in ../CMakeLists.txt. +// OS Availability of pthread_getname_np(..) and pthread_setname_np(..):: +// MacOS(10.6) +// iOS(3.2) +// AIX(7.1) +// FreeBSD(version?), OpenBSD(Version?) +// Linux-GLIBC(GLIBC-2.12). +// Linux-MUSL(MUSL-1.1.20 Partial Implementation. See below). +// MINGW-W64(4.0.6) + +#if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \ + || defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + #include + #if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \ + && !defined(HAVE_PTHREAD_GETNAME_NP) + #define HAVE_PTHREAD_GETNAME_NP 1 + #endif + #if defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) \ + && !defined(HAVE_PTHREAD_SETNAME_NP) + #define HAVE_PTHREAD_SETNAME_NP 1 + #endif #endif -#include +#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \ + || defined(__linux__) + // NOTE: + // Linux pthread_getname_np() and pthread_setname_np() became available + // in GLIBC-2.12 and later. + // Some Linux runtimes do not have pthread_getname_np(), but have + // pthread_setname_np(), for instance MUSL at least as of v1.1.20. + // So using the prctl() for Linux is more portable. + #if defined(__linux__) + #include + #endif + #include #endif #include #include #include +#include "common.h" #include "sync.h" class ThreadName { -#if defined(__APPLE__) || defined(__linux__) +#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \ + || defined(__linux__) class ThreadNameImpl { @@ -47,8 +83,7 @@ class ThreadName // since Linux 2.6.11. The buffer should allow space for up to 16 // bytes; the returned string will be null-terminated. return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1; -#elif defined(__APPLE__) - // since macos(10.6), ios(3.2) +#elif defined(HAVE_PTHREAD_GETNAME_NP) return pthread_getname_np(pthread_self(), namebuf, BUFSIZE) == 0; #else #error "unsupported platform" @@ -57,14 +92,18 @@ class ThreadName static bool set(const char* name) { + SRT_ASSERT(name != NULL); #if defined(__linux__) // The name can be up to 16 bytes long, including the terminating // null byte. (If the length of the string, including the terminating // null byte, exceeds 16 bytes, the string is silently truncated.) return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1; -#elif defined(__APPLE__) - // since macos(10.6), ios(3.2) +#elif defined(HAVE_PTHREAD_SETNAME_NP) + #if defined(__APPLE__) return pthread_setname_np(name) == 0; + #else + return pthread_setname_np(pthread_self(), name) == 0; + #endif #else #error "unsupported platform" #endif From 5e75c3221f227e86bbd4400fdc91d98f55cd0455 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 31 Aug 2021 16:27:03 +0200 Subject: [PATCH 085/124] [core] Placed ThreadName class inside srt namespace --- apps/srt-tunnel.cpp | 18 +++++++++--------- srtcore/threadname.h | 4 ++++ test/test_threadname.cpp | 2 ++ testing/srt-test-multiplex.cpp | 10 +++++----- testing/srt-test-relay.cpp | 4 ++-- testing/testactivemedia.cpp | 4 ++-- testing/testactivemedia.hpp | 2 +- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/srt-tunnel.cpp b/apps/srt-tunnel.cpp index 2c4aacfb3..fd25fb998 100644 --- a/apps/srt-tunnel.cpp +++ b/apps/srt-tunnel.cpp @@ -223,17 +223,17 @@ class Engine Engine(Tunnel* p, Medium* m1, Medium* m2, const std::string& nid) : #ifdef HAVE_FULL_CXX11 - media {m1, m2}, + media {m1, m2}, #endif - parent_tunnel(p), nameid(nid) + 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; + // 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 } @@ -241,7 +241,7 @@ class Engine { Verb() << "START: " << media[DIR_IN]->uri() << " --> " << media[DIR_OUT]->uri(); std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id(); - ThreadName tn(thrn.c_str()); + srt::ThreadName tn(thrn.c_str()); thr = thread([this]() { Worker(); }); } diff --git a/srtcore/threadname.h b/srtcore/threadname.h index e392f6d8e..a3dbb475e 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -65,6 +65,8 @@ written by #include "common.h" #include "sync.h" +namespace srt { + class ThreadName { @@ -217,4 +219,6 @@ class ThreadName } }; +} // namespace srt + #endif diff --git a/test/test_threadname.cpp b/test/test_threadname.cpp index f9b1d1d8c..67301f97b 100644 --- a/test/test_threadname.cpp +++ b/test/test_threadname.cpp @@ -4,6 +4,8 @@ #include "gtest/gtest.h" #include "threadname.h" +using namespace srt; + TEST(ThreadName, GetSet) { std::string name("getset"); diff --git a/testing/srt-test-multiplex.cpp b/testing/srt-test-multiplex.cpp index 859547069..e2d5c8b89 100644 --- a/testing/srt-test-multiplex.cpp +++ b/testing/srt-test-multiplex.cpp @@ -154,14 +154,14 @@ struct MediumPair applog.Note() << sout.str(); } } - catch (Source::ReadEOF& x) + catch (const Source::ReadEOF&) { applog.Note() << "EOS - closing media for loop: " << name; src->Close(); tar->Close(); applog.Note() << "CLOSED: " << name; } - catch (std::runtime_error& x) + catch (const std::runtime_error& x) { applog.Note() << "INTERRUPTED: " << x.what(); src->Close(); @@ -196,7 +196,7 @@ class MediaBase med.name = name; // Ok, got this, so we can start transmission. - ThreadName tn(thread_name.c_str()); + srt::ThreadName tn(thread_name.c_str()); med.runner = thread( [&med]() { med.TransmissionLoop(); }); return med; @@ -577,7 +577,7 @@ int main( int argc, char** argv ) SrtModel m(up.host(), iport, up.parameters()); - ThreadName::set("main"); + srt::ThreadName::set("main"); // Note: for input, there must be an exactly defined // number of sources. The loop rolls up to all these sources. @@ -615,7 +615,7 @@ int main( int argc, char** argv ) break; } - ThreadName::set("main"); + srt::ThreadName::set("main"); } applog.Note() << "All local stream definitions covered. Waiting for interrupt/broken all connections."; diff --git a/testing/srt-test-relay.cpp b/testing/srt-test-relay.cpp index 1214125b7..323718b51 100755 --- a/testing/srt-test-relay.cpp +++ b/testing/srt-test-relay.cpp @@ -392,7 +392,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin void SrtMainLoop::InputRunner() { - ThreadName::set("InputRN"); + srt::ThreadName::set("InputRN"); // An extra thread with a loop that reads from the external input // and writes into the SRT medium. When echoback mode is used, // this thread isn't started at all and instead the SRT reading @@ -438,7 +438,7 @@ void SrtMainLoop::run() std::ostringstream tns; tns << "Input:" << this; - ThreadName tn(tns.str().c_str()); + srt::ThreadName tn(tns.str().c_str()); m_input_thr = thread([this] { try { InputRunner(); diff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp index 765d22ef6..53f42a9a1 100644 --- a/testing/testactivemedia.cpp +++ b/testing/testactivemedia.cpp @@ -3,7 +3,7 @@ void SourceMedium::Runner() { - ThreadName::set("SourceRN"); + srt::ThreadName::set("SourceRN"); Verb() << VerbLock << "Starting SourceMedium: " << this; for (;;) @@ -63,7 +63,7 @@ MediaPacket SourceMedium::Extract() void TargetMedium::Runner() { - ThreadName::set("TargetRN"); + srt::ThreadName::set("TargetRN"); auto on_return_set = OnReturnSet(running, false); Verb() << VerbLock << "Starting TargetMedium: " << this; for (;;) diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index 06a1cd922..fbb2f9dc8 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -58,7 +58,7 @@ struct Medium running = true; std::ostringstream tns; tns << typeid(*this).name() << ":" << this; - ThreadName tn(tns.str().c_str()); + srt::ThreadName tn(tns.str().c_str()); thr = thread( [this] { RunnerBase(); } ); } From df95ecb66be7ecffdfbe2f0b54b77ef7b7184d36 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Wed, 1 Sep 2021 13:50:36 -0500 Subject: [PATCH 086/124] [core] Fix atomic for MacOS, FreeBSD, GCC<4.7, Clang<6 (#2104) --- CMakeLists.txt | 7 ++ srtcore/atomic.h | 151 ++++++++++++++++++++++++++++++++++------- srtcore/atomic_clock.h | 91 +++++++++++++++++++++++++ srtcore/sync.h | 74 ++------------------ 4 files changed, 233 insertions(+), 90 deletions(-) create mode 100644 srtcore/atomic_clock.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3693b5b37..c5cfa1394 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,13 @@ option(ENABLE_SOCK_CLOEXEC "Enable setting SOCK_CLOEXEC on a socket" ON) 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 diff --git a/srtcore/atomic.h b/srtcore/atomic.h index 5cedd396d..caec84fe1 100644 --- a/srtcore/atomic.h +++ b/srtcore/atomic.h @@ -61,16 +61,54 @@ line)[(2 * static_cast(!!(condition))) - 1] _impl_UNUSED #endif -#if defined(__GNUC__) || defined(__clang__) || defined(__xlc__) -#define ATOMIC_USE_GCC_INTRINSICS +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + // NOTE: Defined at the top level. +#elif defined(__APPLE__) && (__cplusplus >= 201103L) + // NOTE: Does support c++11 std::atomic, but the compiler may or + // may not support GCC atomic intrinsics. So go ahead and use the + // std::atomic implementation. + #define ATOMIC_USE_CPP11_ATOMIC +#elif (defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5)) \ + || defined(__xlc__) + // NOTE: Clang <6 does not support GCC __atomic_* intrinsics. I am unsure + // about Clang6. Since Clang sets __GNUC__ and __GNUC_MINOR__ of this era + // to <4.5, older Clang will catch the setting below to use the + // POSIX Mutex Implementation. + #define ATOMIC_USE_GCC_INTRINSICS +#elif defined(__GNUC__) \ + && ( (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) ) + // NOTE: The __atomic_* family of intrisics were introduced in GCC-4.7.0. + // NOTE: This follows #if defined(__clang__), because most if, not all, + // versions of Clang define __GNUC__ and __GNUC_MINOR__ but often define + // them to 4.4 or an even earlier version. Most of the newish versions + // of Clang also support GCC Atomic Intrisics even if they set GCC version + // macros to <4.7. + #define ATOMIC_USE_GCC_INTRINSICS +#elif defined(__GNUC__) && !defined(ATOMIC_USE_SRT_SYNC_MUTEX) + // NOTE: GCC compiler built-ins for atomic operations are pure + // compiler extensions prior to GCC-4.7 and were grouped into the + // the __sync_* family of functions. GCC-4.7, both the c++11 and C11 + // standards had been finalized, and GCC updated their built-ins to + // better reflect the new memory model and the new functions grouped + // into the __atomic_* family. Also the memory models were defined + // differently, than in pre 4.7. + // TODO: PORT to the pre GCC-4.7 __sync_* intrinsics. In the meantime use + // the POSIX Mutex Implementation. + #define ATOMIC_USE_SRT_SYNC_MUTEX 1 #elif defined(_MSC_VER) -#define ATOMIC_USE_MSVC_INTRINSICS -#include "atomic_msvc.h" + #define ATOMIC_USE_MSVC_INTRINSICS + #include "atomic_msvc.h" #elif __cplusplus >= 201103L -#define ATOMIC_USE_CPP11_ATOMIC -#include + #define ATOMIC_USE_CPP11_ATOMIC #else -#error Unsupported compiler / system. + #error Unsupported compiler / system. +#endif +// Include any necessary headers for the selected Atomic Implementation. +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + #include "sync.h" +#endif +#if defined(ATOMIC_USE_CPP11_ATOMIC) + #include #endif namespace srt { @@ -82,31 +120,62 @@ class atomic { sizeof(T) == 8, "Only types of size 1, 2, 4 or 8 are supported"); - atomic() : value_(static_cast(0)) {} + atomic() + : value_(static_cast(0)) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + , mutex_() +#endif + { + // No-Op + } + + explicit atomic(const T value) + : value_(value) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + , mutex_() +#endif + { + // No-Op + } - explicit atomic(const T value) : value_(value) {} + ~atomic() + { + // No-Op + } /// @brief Performs an atomic increment operation (value + 1). /// @returns The new value of the atomic object. T operator++() { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + const T t = ++value_; + return t; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST); #elif defined(ATOMIC_USE_MSVC_INTRINSICS) return msvc::interlocked::increment(&value_); -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) return ++value_; +#else + #error "Implement Me." #endif } /// @brief Performs an atomic decrement operation (value - 1). /// @returns The new value of the atomic object. T operator--() { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + const T t = --value_; + return t; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST); #elif defined(ATOMIC_USE_MSVC_INTRINSICS) return msvc::interlocked::decrement(&value_); -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) return --value_; +#else + #error "Implement Me." #endif } @@ -119,7 +188,16 @@ class atomic { /// @param new_val The new value to write to the atomic object. /// @returns True if new_value was written to the atomic object. bool compare_exchange(const T expected_val, const T new_val) { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + bool result = false; + if (expected_val == value_) + { + value_ = new_val; + result = true; + } + return result; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) T e = expected_val; return __atomic_compare_exchange_n( &value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); @@ -127,9 +205,11 @@ class atomic { const T old_val = msvc::interlocked::compare_exchange(&value_, new_val, expected_val); return (old_val == expected_val); -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) T e = expected_val; return value_.compare_exchange_weak(e, new_val); +#else + #error "Implement Me." #endif } @@ -140,12 +220,17 @@ class atomic { /// /// @param new_val The new value to write to the atomic object. void store(const T new_val) { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + value_ = new_val; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) __atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST); #elif defined(ATOMIC_USE_MSVC_INTRINSICS) (void)msvc::interlocked::exchange(&value_, new_val); -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) value_.store(new_val); +#else + #error "Implement Me." #endif } @@ -153,13 +238,19 @@ class atomic { /// @note Be careful about how this is used, since any operations on the /// returned value are inherently non-atomic. T load() const { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + const T t = value_; + return t; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) return __atomic_load_n(&value_, __ATOMIC_SEQ_CST); #elif defined(ATOMIC_USE_MSVC_INTRINSICS) // TODO(m): Is there a better solution for MSVC? return value_; -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) return value_; +#else + #error "Implement Me." #endif } @@ -171,12 +262,19 @@ class atomic { /// @param new_val The new value to write to the atomic object. /// @returns the old value. T exchange(const T new_val) { -#if defined(ATOMIC_USE_GCC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + ScopedLock lg_(mutex_); + const T t = value_; + value_ = new_val; + return t; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST); #elif defined(ATOMIC_USE_MSVC_INTRINSICS) return msvc::interlocked::exchange(&value_, new_val); -#else +#elif defined(ATOMIC_USE_CPP11_ATOMIC) return value_.exchange(new_val); +#else + #error "Implement Me." #endif } @@ -190,10 +288,17 @@ class atomic { } private: -#if defined(ATOMIC_USE_GCC_INTRINSICS) || defined(ATOMIC_USE_MSVC_INTRINSICS) +#if defined(ATOMIC_USE_SRT_SYNC_MUTEX) && (ATOMIC_USE_SRT_SYNC_MUTEX == 1) + T value_; + mutable Mutex mutex_; +#elif defined(ATOMIC_USE_GCC_INTRINSICS) volatile T value_; -#else +#elif defined(ATOMIC_USE_MSVC_INTRINSICS) + volatile T value_; +#elif defined(ATOMIC_USE_CPP11_ATOMIC) std::atomic value_; +#else + #error "Implement Me. (value_ type)" #endif ATOMIC_DISALLOW_COPY(atomic) diff --git a/srtcore/atomic_clock.h b/srtcore/atomic_clock.h new file mode 100644 index 000000000..e01012313 --- /dev/null +++ b/srtcore/atomic_clock.h @@ -0,0 +1,91 @@ +/* + * SRT - Secure, Reliable, Transport + * Copyright (c) 2021 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_SYNC_ATOMIC_CLOCK_H +#define INC_SRT_SYNC_ATOMIC_CLOCK_H + +#include "sync.h" +#include "atomic.h" + +namespace srt +{ +namespace sync +{ + +template +class AtomicDuration +{ + atomic dur; + typedef typename Clock::duration duration_type; + typedef typename Clock::time_point time_point_type; +public: + + AtomicDuration() ATR_NOEXCEPT : dur(0) {} + + duration_type load() + { + int64_t val = dur.load(); + return duration_type(val); + } + + void store(const duration_type& d) + { + dur.store(d.count()); + } + + AtomicDuration& operator=(const duration_type& s) + { + dur = s.count(); + return *this; + } + + operator duration_type() const + { + return duration_type(dur); + } +}; + +template +class AtomicClock +{ + atomic dur; + typedef typename Clock::duration duration_type; + typedef typename Clock::time_point time_point_type; +public: + + AtomicClock() ATR_NOEXCEPT : dur(0) {} + + time_point_type load() const + { + int64_t val = dur.load(); + return time_point_type(duration_type(val)); + } + + void store(const time_point_type& d) + { + dur.store(uint64_t(d.time_since_epoch().count())); + } + + AtomicClock& operator=(const time_point_type& s) + { + dur = s.time_since_epoch().count(); + return *this; + } + + operator time_point_type() const + { + return time_point_type(duration_type(dur.load())); + } +}; + +} // namespace sync +} // namespace srt + +#endif // INC_SRT_SYNC_ATOMIC_CLOCK_H diff --git a/srtcore/sync.h b/srtcore/sync.h index d78aed980..00633da06 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -23,7 +23,6 @@ #define SRT_SYNC_CLOCK_STR "STDCXX_STEADY" #else #include -#include "atomic.h" // Defile clock type to use #ifdef IA32 @@ -233,72 +232,11 @@ inline Duration operator*(const int& lhs, const Duration -class AtomicDuration -{ - atomic dur; - typedef typename Clock::duration duration_type; - typedef typename Clock::time_point time_point_type; -public: - - AtomicDuration() ATR_NOEXCEPT : dur(0) {} - - duration_type load() - { - int64_t val = dur.load(); - return duration_type(val); - } - - void store(const duration_type& d) - { - dur.store(d.count()); - } - - AtomicDuration& operator=(const duration_type& s) - { - dur = s.count(); - return *this; - } - - operator duration_type() const - { - return duration_type(dur); - } -}; - -template -class AtomicClock -{ - atomic dur; - typedef typename Clock::duration duration_type; - typedef typename Clock::time_point time_point_type; -public: - - AtomicClock() ATR_NOEXCEPT : dur(0) {} - - time_point_type load() const - { - int64_t val = dur.load(); - return time_point_type(duration_type(val)); - } - - void store(const time_point_type& d) - { - dur.store(uint64_t(d.time_since_epoch().count())); - } - - AtomicClock& operator=(const time_point_type& s) - { - dur = s.time_since_epoch().count(); - return *this; - } - - operator time_point_type() const - { - return time_point_type(duration_type(dur.load())); - } -}; - +// NOTE: Moved the following class definitons to "atomic_clock.h" +// template +// class AtomicDuration; +// template +// class AtomicClock; /////////////////////////////////////////////////////////////////////////////// // @@ -939,4 +877,6 @@ int genRandomInt(int minVal, int maxVal); } // namespace sync } // namespace srt +#include "atomic_clock.h" + #endif // INC_SRT_SYNC_H From 2243388a0ddd3296c4264b3187901849c00adeb8 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 2 Sep 2021 13:07:35 +0200 Subject: [PATCH 087/124] [core] Removed ThreadName(const char*). (#2113) Now only string& can be passed to avoid checking for NULL. --- apps/srt-tunnel.cpp | 4 ++-- srtcore/api.cpp | 8 +++----- srtcore/core.cpp | 6 +++--- srtcore/sync.cpp | 4 ++-- srtcore/sync.h | 4 ++-- srtcore/threadname.h | 26 +++++++++++++------------- test/test_threadname.cpp | 4 ++-- testing/srt-test-multiplex.cpp | 2 +- testing/srt-test-relay.cpp | 2 +- testing/testactivemedia.hpp | 2 +- 10 files changed, 30 insertions(+), 32 deletions(-) diff --git a/apps/srt-tunnel.cpp b/apps/srt-tunnel.cpp index fd25fb998..fa08759a1 100644 --- a/apps/srt-tunnel.cpp +++ b/apps/srt-tunnel.cpp @@ -240,8 +240,8 @@ class Engine void Start() { Verb() << "START: " << media[DIR_IN]->uri() << " --> " << media[DIR_OUT]->uri(); - std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id(); - srt::ThreadName tn(thrn.c_str()); + const std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id(); + srt::ThreadName tn(thrn); thr = thread([this]() { Worker(); }); } diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 7f6d7ecaa..71386a566 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -154,9 +154,7 @@ bool srt::CUDTSocket::readReady() if (m_UDT.m_bConnected && m_UDT.m_pRcvBuffer->isRcvDataReady()) return true; if (m_UDT.m_bListening) - { - return m_QueuedSockets.size() > 0; - } + return !m_QueuedSockets.empty(); return broken(); } @@ -955,7 +953,7 @@ int srt::CUDTUnited::bind(CUDTSocket* s, UDPSOCKET udpsock) s->m_Status = SRTS_OPENED; // copy address information of local node - s->core().m_pSndQueue->m_pChannel->getSockAddr((s->m_SelfAddr)); + s->core().m_pSndQueue->m_pChannel->getSockAddr(s->m_SelfAddr); return 0; } @@ -1535,7 +1533,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i HLOGC(aclog.Debug, log << "groupConnect: connecting a new socket with ISN=" << isn); connectIn(ns, target_addr, isn); } - catch (CUDTException& e) + catch (const CUDTException& e) { LOGC(aclog.Error, log << "groupConnect: socket @" << sid << " in group " << pg->id() << " failed to connect"); // We know it does belong to a group. diff --git a/srtcore/core.cpp b/srtcore/core.cpp index c887218d9..a5fe649d8 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -9395,10 +9395,10 @@ int srt::CUDT::processData(CUnit* in_unit) const string& tn = tns2.str(); - ThreadName tnkeep(tn.c_str()); - const char* thname = tn.c_str(); + ThreadName tnkeep(tn); + const string& thname = tn; #else - const char* thname = "SRT:TsbPd"; + const string thname = "SRT:TsbPd"; #endif if (!StartThread(m_RcvTsbPdThread, CUDT::tsbpd, this, thname)) return -1; diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index 820e0a7f9..aa15c2471 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -79,9 +79,9 @@ std::string FormatTimeSys(const steady_clock::time_point& timestamp) #ifdef ENABLE_STDCXX_SYNC -bool StartThread(CThread& th, ThreadFunc&& f, void* args, const char* name) +bool StartThread(CThread& th, ThreadFunc&& f, void* args, const string& name) #else -bool StartThread(CThread& th, void* (*f) (void*), void* args, const char* name) +bool StartThread(CThread& th, void* (*f) (void*), void* args, const string& name) #endif { ThreadName tn(name); diff --git a/srtcore/sync.h b/srtcore/sync.h index 00633da06..cd0288ad4 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -843,9 +843,9 @@ namespace this_thread /// #ifdef ENABLE_STDCXX_SYNC typedef void* (&ThreadFunc) (void*); -bool StartThread(CThread& th, ThreadFunc&& f, void* args, const char* name); +bool StartThread(CThread& th, ThreadFunc&& f, void* args, const std::string& name); #else -bool StartThread(CThread& th, void* (*f) (void*), void* args, const char* name); +bool StartThread(CThread& th, void* (*f) (void*), void* args, const std::string& name); #endif //////////////////////////////////////////////////////////////////////////////// diff --git a/srtcore/threadname.h b/srtcore/threadname.h index a3dbb475e..3d60fbe4f 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -111,9 +111,9 @@ class ThreadName #endif } - ThreadNameImpl(const char* name) + explicit ThreadNameImpl(const char* name) + : reset(false) { - reset = false; tid = pthread_self(); if (!get(old_name)) @@ -140,6 +140,10 @@ class ThreadName if (tid == pthread_self()) set(old_name); } + + private: + ThreadNameImpl(ThreadNameImpl& other); + ThreadNameImpl& operator=(const ThreadNameImpl& other); private: bool reset; @@ -202,21 +206,17 @@ class ThreadName return ret; } - // note: set can fail if name is too long. The upper limit is platform - // dependent. strlen(name) <= 15 should work on most of the platform. - static bool set(const char* name) { return ThreadNameImpl::set(name); } - - static bool set(const std::string& name) { return set(name.c_str()); } - - ThreadName(const char* name) - : impl(name) - { - } + static bool set(const std::string& name) { return ThreadNameImpl::set(name.c_str()); } - ThreadName(const std::string& name) + explicit ThreadName(const std::string& name) : impl(name.c_str()) { } + +private: + ThreadName(const ThreadName&); + ThreadName(const char*); + ThreadName& operator=(const ThreadName& other); }; } // namespace srt diff --git a/test/test_threadname.cpp b/test/test_threadname.cpp index 67301f97b..0b03686a4 100644 --- a/test/test_threadname.cpp +++ b/test/test_threadname.cpp @@ -28,12 +28,12 @@ TEST(ThreadName, GetSet) TEST(ThreadName, AutoReset) { - std::string old_name("old"); + const std::string old_name("old"); std::string new_name("new-name"); if (ThreadName::DUMMY_IMPL) { // just make sure the API is correct - ThreadName t("test"); + ThreadName t(std::string("test")); return; } diff --git a/testing/srt-test-multiplex.cpp b/testing/srt-test-multiplex.cpp index e2d5c8b89..df810aea6 100644 --- a/testing/srt-test-multiplex.cpp +++ b/testing/srt-test-multiplex.cpp @@ -196,7 +196,7 @@ class MediaBase med.name = name; // Ok, got this, so we can start transmission. - srt::ThreadName tn(thread_name.c_str()); + srt::ThreadName tn(thread_name); med.runner = thread( [&med]() { med.TransmissionLoop(); }); return med; diff --git a/testing/srt-test-relay.cpp b/testing/srt-test-relay.cpp index 323718b51..0f72b8a1c 100755 --- a/testing/srt-test-relay.cpp +++ b/testing/srt-test-relay.cpp @@ -438,7 +438,7 @@ void SrtMainLoop::run() std::ostringstream tns; tns << "Input:" << this; - srt::ThreadName tn(tns.str().c_str()); + srt::ThreadName tn(tns.str()); m_input_thr = thread([this] { try { InputRunner(); diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index fbb2f9dc8..c7b11e583 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -58,7 +58,7 @@ struct Medium running = true; std::ostringstream tns; tns << typeid(*this).name() << ":" << this; - srt::ThreadName tn(tns.str().c_str()); + srt::ThreadName tn(tns.str()); thr = thread( [this] { RunnerBase(); } ); } From e8f4057590c0f5e7e05c7b8f76b763147f883bb7 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Fri, 3 Sep 2021 07:49:10 -0500 Subject: [PATCH 088/124] [build] Automatically link libatomic if needed. (#2116) --- CMakeLists.txt | 25 +++++- scripts/CheckCXXAtomic.cmake | 62 ++++++++++++++ scripts/CheckGCCAtomicIntrinsics.cmake | 110 +++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 scripts/CheckCXXAtomic.cmake create mode 100644 scripts/CheckGCCAtomicIntrinsics.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c5cfa1394..4e01e7e63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,6 +411,20 @@ else() # Compiler altered by WITH_COMPILER_TYPE/PREFIX - can't rely on CMAKE_CXX 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_GCCATOMIC_INTRINSICS +# HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC +# HAVE_GCCATOMIC_INTRINSICS_STATIC +# HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC +include(CheckGCCAtomicIntrinsics) +CheckGCCAtomicIntrinsics() +# HAVE_CXX_ATOMIC +# HAVE_CXX_ATOMIC_STATIC +include(CheckCXXAtomic) +CheckCXXAtomic() + if (DISABLE_CXX11) set (ENABLE_CXX11 0) elseif( DEFINED ENABLE_CXX11 ) @@ -877,8 +891,6 @@ if (srt_libspec_shared) target_link_libraries(${TARGET_srt}_shared PRIVATE wsock32.lib ws2_32.lib) elseif (APPLE) set_property(TARGET ${TARGET_srt}_shared PROPERTY MACOSX_RPATH ON) - elseif (ANDROID) - target_link_libraries(${TARGET_srt}_shared PRIVATE atomic) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_shared PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) @@ -913,8 +925,6 @@ if (srt_libspec_static) endif() elseif (MINGW) target_link_libraries(${TARGET_srt}_static PRIVATE wsock32 ws2_32) - elseif (ANDROID) - target_link_libraries(${TARGET_srt}_static PUBLIC atomic) endif() if (USE_GNUSTL) target_link_libraries(${TARGET_srt}_static PRIVATE ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS}) @@ -966,6 +976,13 @@ if (srt_libspec_shared) endif() endif() +# Required by some toolchains when statically linking this library if the +# GCC Atomic Intrinsics are being used. +if (HAVE_GCCATOMIC_INTRINSICS + AND HAVE_LIBATOMIC) + target_link_libraries(${TARGET_srt}_static PUBLIC atomic) +endif() + # Cygwin installs the *.dll libraries in bin directory and uses PATH. set (INSTALL_SHARED_DIR ${CMAKE_INSTALL_LIBDIR}) diff --git a/scripts/CheckCXXAtomic.cmake b/scripts/CheckCXXAtomic.cmake new file mode 100644 index 000000000..e071b78a3 --- /dev/null +++ b/scripts/CheckCXXAtomic.cmake @@ -0,0 +1,62 @@ +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021 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/. +# + +# Check for c++11 std::atomic. +# +# Sets: +# HAVE_CXX_ATOMIC +# HAVE_CXX_ATOMIC_STATIC + +include(CheckCXXSourceCompiles) +include(CheckLibraryExists) + +function(CheckCXXAtomic) + + unset(HAVE_CXX_ATOMIC) + unset(HAVE_CXX_ATOMIC PARENT_SCOPE) + unset(HAVE_CXX_ATOMIC CACHE) + + unset(HAVE_CXX_ATOMIC_STATIC) + unset(HAVE_CXX_ATOMIC_STATIC PARENT_SCOPE) + unset(HAVE_CXX_ATOMIC_STATIC CACHE) + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + + set(CheckCXXAtomic_CODE + " + #include + #include + int main(void) + { + std::atomic x(0); + std::atomic y(0); + return x + y; + } + ") + + set(CMAKE_REQUIRED_FLAGS "-std=c++11") + + check_cxx_source_compiles( + "${CheckCXXAtomic_CODE}" + HAVE_CXX_ATOMIC) + + if(HAVE_CXX_ATOMIC) + set(CMAKE_REQUIRED_LINK_OPTIONS "-static") + check_cxx_source_compiles( + "${CheckCXXAtomic_CODE}" + HAVE_CXX_ATOMIC_STATIC) + endif() + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + +endfunction(CheckCXXAtomic) diff --git a/scripts/CheckGCCAtomicIntrinsics.cmake b/scripts/CheckGCCAtomicIntrinsics.cmake new file mode 100644 index 000000000..164fb190e --- /dev/null +++ b/scripts/CheckGCCAtomicIntrinsics.cmake @@ -0,0 +1,110 @@ +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021 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/. +# + +# Check for GCC Atomic Intrinsics and whether libatomic is required. +# +# Sets: +# HAVE_LIBATOMIC +# HAVE_GCCATOMIC_INTRINSICS +# HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC +# HAVE_GCCATOMIC_INTRINSICS_STATIC +# HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC +# +# See +# https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html +# https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync + +include(CheckCSourceCompiles) +include(CheckLibraryExists) + +function(CheckGCCAtomicIntrinsics) + + unset(HAVE_LIBATOMIC) + unset(HAVE_LIBATOMIC PARENT_SCOPE) + unset(HAVE_LIBATOMIC CACHE) + + unset(HAVE_GCCATOMIC_INTRINSICS) + unset(HAVE_GCCATOMIC_INTRINSICS PARENT_SCOPE) + unset(HAVE_GCCATOMIC_INTRINSICS CACHE) + + unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC PARENT_SCOPE) + unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE) + + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC) + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC PARENT_SCOPE) + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC CACHE) + + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC) + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC PARENT_SCOPE) + unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC CACHE) + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + + set(CheckGCCAtomicIntrinsics_CODE + " + #include + #include + int main(void) + { + ptrdiff_t x = 0; + intmax_t y = 0; + __atomic_add_fetch(&x, 1, __ATOMIC_SEQ_CST); + __atomic_add_fetch(&y, 1, __ATOMIC_SEQ_CST); + return __atomic_sub_fetch(&x, 1, __ATOMIC_SEQ_CST) + + __atomic_sub_fetch(&y, 1, __ATOMIC_SEQ_CST); + } + ") + + check_library_exists( + atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC) + + check_c_source_compiles( + "${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS) + + if (NOT HAVE_GCCATOMIC_INTRINSICS + AND HAVE_LIBATOMIC) + set(CMAKE_REQUIRED_LIBRARIES "atomic") + check_c_source_compiles( + "${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + if (HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + set(HAVE_GCCATOMIC_INTRINSICS TRUE PARENT_SCOPE) + endif() + endif() + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + + if (HAVE_GCCATOMIC_INTRINSICS) + set(CMAKE_REQUIRED_LINK_OPTIONS "-static") + check_c_source_compiles( + "${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS_STATIC) + if (NOT HAVE_GCCATOMIC_INTRINSICS_STATIC + AND HAVE_LIBATOMIC) + set(CMAKE_REQUIRED_LIBRARIES "atomic") + check_c_source_compiles( + "${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS_STATIC) + if (HAVE_GCCATOMIC_INTRINSICS_STATIC) + set(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC TRUE PARENT_SCOPE) + endif() + endif() + endif() + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + +endfunction(CheckGCCAtomicIntrinsics) From 2e09a1696aba44e984e769eb2aa7c59a5905199a Mon Sep 17 00:00:00 2001 From: Thierry Lelegard Date: Mon, 6 Sep 2021 11:49:34 +0200 Subject: [PATCH 089/124] [build] Update Windows installer for alternate platform names (#2117) --- scripts/win-installer/libsrt.props | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/win-installer/libsrt.props b/scripts/win-installer/libsrt.props index d8de447c1..01e0b5dac 100644 --- a/scripts/win-installer/libsrt.props +++ b/scripts/win-installer/libsrt.props @@ -4,6 +4,25 @@ + + + + + Win32 + + + + + x64 + + + + + $(Platform) + + + + @@ -11,7 +30,7 @@ srt.lib;libssl.lib;libcrypto.lib;crypt32.lib;%(AdditionalDependencies) - $(LIBSRT)\lib\$(Configuration)-$(Platform);%(AdditionalLibraryDirectories) + $(LIBSRT)\lib\$(Configuration)-$(SrtPlatform);%(AdditionalLibraryDirectories) /ignore:4099 %(AdditionalOptions) From e98146a2f2f75370fa7715ccf5f8a581cdb6ace8 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 6 Sep 2021 14:37:40 +0200 Subject: [PATCH 090/124] [core] Avoid using strlen in ThreadName class --- srtcore/threadname.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/srtcore/threadname.h b/srtcore/threadname.h index 3d60fbe4f..4dade104a 100644 --- a/srtcore/threadname.h +++ b/srtcore/threadname.h @@ -111,7 +111,7 @@ class ThreadName #endif } - explicit ThreadNameImpl(const char* name) + explicit ThreadNameImpl(const std::string& name) : reset(false) { tid = pthread_self(); @@ -119,16 +119,16 @@ class ThreadName if (!get(old_name)) return; - reset = set(name); + reset = set(name.c_str()); if (reset) return; // Try with a shorter name. 15 is the upper limit supported by Linux, // other platforms should support a larger value. So 15 should works // on all platforms. - size_t max_len = 15; - if (std::strlen(name) > max_len) - reset = set(std::string(name, max_len).c_str()); + const size_t max_len = 15; + if (name.size() > max_len) + reset = set(name.substr(0, max_len).c_str()); } ~ThreadNameImpl() @@ -171,7 +171,7 @@ class ThreadName static bool set(const char*) { return false; } - ThreadNameImpl(const char*) {} + ThreadNameImpl(const std::string&) {} ~ThreadNameImpl() // just to make it "non-trivially-destructible" for compatibility with normal version { @@ -209,7 +209,7 @@ class ThreadName static bool set(const std::string& name) { return ThreadNameImpl::set(name.c_str()); } explicit ThreadName(const std::string& name) - : impl(name.c_str()) + : impl(name) { } From 34ba95157a0c27c85ee20450d4b481cec6c99f81 Mon Sep 17 00:00:00 2001 From: Maria Sharabayko Date: Tue, 7 Sep 2021 12:43:28 +0200 Subject: [PATCH 091/124] Improved Access Control general syntax description --- docs/features/access-control.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/features/access-control.md b/docs/features/access-control.md index d583f795b..e6f9124c8 100644 --- a/docs/features/access-control.md +++ b/docs/features/access-control.md @@ -41,23 +41,23 @@ The Stream ID uses UTF-8 encoding. ## General Syntax -This recommended syntax starts with the characters known as an executable -specification in POSIX: `#!`. +The recommended syntax starts with the characters known as an executable specification in POSIX: `#!`. -The next two characters are: +The next character defines the format used for the following key-value pair syntax. +At the moment, there is only one supported syntax identified by `:` and described below. -- `:` - marks the format of the following key-value pair syntax (the only one defined currently). -- The content format, which is either: - - `:` - the comma-separated keys with no nesting - - `{` - like above, but nesting is allowed and must end with `}` +Everything that comes after a syntax identifier is further referenced as the content of the Stream ID. -(Nesting means that you can have multiple level brace-enclosed parts inside.) +The content starts with a `:` or `{` character identifying its format: -The form of the key-value pair is: +- `:` : comma-separated key-value pairs with no nesting, +- `{` : a nested block with one or several key-value pairs that must end with a `}` character. Nesting means that multiple level brace-enclosed parts are allowed. -```js -key1=value1,key2=value2... -``` +The form of the key-value pair is + +~~~ +key1=value1,key2=value2,... +~~~ ## Standard Keys From b147d5ec9ab7134b3eb8b5ef2b11039cf8bdd883 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Wed, 8 Sep 2021 04:28:27 -0500 Subject: [PATCH 092/124] [core] Fix Solaris build. (#2115) --- CMakeLists.txt | 11 +++++++--- apps/srt-tunnel.cpp | 22 ++++++++++---------- apps/transmitmedia.cpp | 5 ++++- srtcore/common.cpp | 2 +- srtcore/epoll.cpp | 3 ++- srtcore/list.cpp | 8 ++++---- srtcore/srt_compat.c | 2 +- srtcore/sync.h | 22 ++++++++++---------- srtcore/sync_cxx11.cpp | 4 ++-- srtcore/utilities.h | 40 +++++++++++++++++++++++++++++++++++++ testing/testactivemedia.cpp | 6 +++--- testing/testactivemedia.hpp | 6 +++--- 12 files changed, 90 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e01e7e63..3cb8d82a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,8 +40,9 @@ 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(POSIX LINUX OR DARWIN OR BSD OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX)) -set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR CYGWIN OR GNU) +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) # Not sure what to do in case of compiling by MSVC. # This will make installdir in C:\Program Files\SRT then @@ -282,8 +283,9 @@ if (DEFINED HAVE_INET_PTON) add_definitions(-DHAVE_INET_PTON=1) endif() +# Defines HAVE_PTHREAD_GETNAME_* and HAVE_PTHREAD_SETNAME_* include(FindPThreadGetSetName) -FindPThreadGetSetName() # Defines HAVE_PTHREAD_GETNAME_* and HAVE_PTHREAD_SETNAME_* +FindPThreadGetSetName() if (ENABLE_MONOTONIC_CLOCK) if (NOT ENABLE_MONOTONIC_CLOCK_DEFAULT) @@ -617,6 +619,9 @@ elseif(CYGWIN) 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() diff --git a/apps/srt-tunnel.cpp b/apps/srt-tunnel.cpp index fa08759a1..ebc996c9a 100644 --- a/apps/srt-tunnel.cpp +++ b/apps/srt-tunnel.cpp @@ -94,7 +94,7 @@ class Medium bool m_eof = false; bool m_broken = false; - mutex access; // For closing + std::mutex access; // For closing template static Medium* CreateAcceptor(DerivedMedium* self, const sockaddr_any& sa, SocketType sock, size_t chunk) @@ -287,7 +287,7 @@ class Tunnel std::unique_ptr med_acp, med_clr; Engine acp_to_clr, clr_to_acp; volatile bool running = true; - mutex access; + std::mutex access; public: @@ -324,7 +324,7 @@ class Tunnel /* { - lock_guard lk(access); + lock_guard lk(access); if (acp_to_clr.stat() == -1 && clr_to_acp.stat() == -1) { Verb() << "Tunnel: Both engine decommissioned, will stop the tunnel."; @@ -438,7 +438,7 @@ class SrtMedium: public Medium void CloseSrt() { Verb() << "Closing SRT socket for " << uri(); - lock_guard lk(access); + lock_guard lk(access); if (m_socket == SRT_ERROR) return; srt_close(m_socket); @@ -528,7 +528,7 @@ class TcpMedium: public Medium void CloseTcp() { Verb() << "Closing TCP socket for " << uri(); - lock_guard lk(access); + lock_guard lk(access); if (m_socket == -1) return; tcp_close(m_socket); @@ -954,20 +954,20 @@ std::unique_ptr Medium::Create(const std::string& url, size_t chunk, Med struct Tunnelbox { list> tunnels; - mutex access; + std::mutex access; condition_variable decom_ready; bool main_running = true; thread thr; void signal_decommission() { - lock_guard lk(access); + lock_guard lk(access); decom_ready.notify_one(); } void install(std::unique_ptr&& acp, std::unique_ptr&& clr) { - lock_guard lk(access); + lock_guard lk(access); Verb() << "Tunnelbox: Starting tunnel: " << acp->uri() << " <-> " << clr->uri(); tunnels.emplace_back(new Tunnel(this, move(acp), move(clr))); @@ -992,7 +992,7 @@ struct Tunnelbox void CleanupWorker() { - unique_lock lk(access); + unique_lock lk(access); while (main_running) { @@ -1027,7 +1027,7 @@ void Tunnel::Stop() if (!running) return; // already stopped - lock_guard lk(access); + lock_guard lk(access); // Ok, you are the first to make the tunnel // not running and inform the tunnelbox. @@ -1037,7 +1037,7 @@ void Tunnel::Stop() bool Tunnel::decommission_if_dead(bool forced) { - lock_guard lk(access); + lock_guard lk(access); if (running && !forced) return false; // working, not to be decommissioned diff --git a/apps/transmitmedia.cpp b/apps/transmitmedia.cpp index e5f76206d..c61c703b8 100644 --- a/apps/transmitmedia.cpp +++ b/apps/transmitmedia.cpp @@ -22,9 +22,12 @@ #if !defined(_WIN32) #include #else -#include +#include #include #endif +#if defined(SUNOS) +#include +#endif #include "netinet_any.h" #include "apputil.hpp" diff --git a/srtcore/common.cpp b/srtcore/common.cpp index 0e19dc611..cd151116a 100644 --- a/srtcore/common.cpp +++ b/srtcore/common.cpp @@ -98,7 +98,7 @@ const char* CUDTException::getErrorMessage() const ATR_NOTHROW return srt::strerror_get_message(m_iMajor, m_iMinor); } -string CUDTException::getErrorString() const +std::string CUDTException::getErrorString() const { return getErrorMessage(); } diff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp index d4919ff39..20a9c0bbb 100644 --- a/srtcore/epoll.cpp +++ b/srtcore/epoll.cpp @@ -149,7 +149,8 @@ ENOMEM: There was insufficient memory to create the kernel object. if (localid < 0) throw CUDTException(MJ_SETUP, MN_NONE, errno); #else - // on Solaris, use /dev/poll + // TODO: Solaris, use port_getn() + // https://docs.oracle.com/cd/E86824_01/html/E54766/port-get-3c.html // on Windows, select #endif diff --git a/srtcore/list.cpp b/srtcore/list.cpp index c7ab7cfc8..e295fb8c8 100644 --- a/srtcore/list.cpp +++ b/srtcore/list.cpp @@ -100,13 +100,13 @@ void CSndLossList::traceState() const int pos = m_iHead; while (pos != SRT_SEQNO_NONE) { - ::cout << pos << ":[" << m_caSeq[pos].seqstart; + std::cout << pos << ":[" << m_caSeq[pos].seqstart; if (m_caSeq[pos].seqend != SRT_SEQNO_NONE) - ::cout << ", " << m_caSeq[pos].seqend; - ::cout << "], "; + std::cout << ", " << m_caSeq[pos].seqend; + std::cout << "], "; pos = m_caSeq[pos].inext; } - ::cout << "\n"; + std::cout << "\n"; } int CSndLossList::insert(int32_t seqno1, int32_t seqno2) diff --git a/srtcore/srt_compat.c b/srtcore/srt_compat.c index 32c8dd6fb..1473a7b94 100644 --- a/srtcore/srt_compat.c +++ b/srtcore/srt_compat.c @@ -23,7 +23,7 @@ written by #include #include #include -#if defined(__unix__) && !defined(BSD) +#if defined(__unix__) && !defined(BSD) && !defined(SUNOS) #include #endif diff --git a/srtcore/sync.h b/srtcore/sync.h index cd0288ad4..7cb0f63a9 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -60,7 +60,6 @@ namespace srt { namespace sync { -using namespace std; /////////////////////////////////////////////////////////////////////////////// // @@ -71,7 +70,7 @@ using namespace std; #if ENABLE_STDCXX_SYNC template -using Duration = chrono::duration; +using Duration = std::chrono::duration; #else @@ -130,13 +129,13 @@ class Duration #if ENABLE_STDCXX_SYNC -using steady_clock = chrono::steady_clock; +using steady_clock = std::chrono::steady_clock; template -using time_point = chrono::time_point; +using time_point = std::chrono::time_point; template -using TimePoint = chrono::time_point; +using TimePoint = std::chrono::time_point; template inline bool is_zero(const time_point &tp) @@ -212,8 +211,8 @@ class TimePoint inline void operator-=(const Duration& rhs) { m_timestamp -= rhs.count(); } public: // - static inline ATR_CONSTEXPR TimePoint min() { return TimePoint(numeric_limits::min()); } - static inline ATR_CONSTEXPR TimePoint max() { return TimePoint(numeric_limits::max()); } + static inline ATR_CONSTEXPR TimePoint min() { return TimePoint(std::numeric_limits::min()); } + static inline ATR_CONSTEXPR TimePoint max() { return TimePoint(std::numeric_limits::max()); } public: Duration time_since_epoch() const; @@ -311,9 +310,9 @@ inline bool is_zero(const TimePoint& t) /////////////////////////////////////////////////////////////////////////////// #if ENABLE_STDCXX_SYNC -using Mutex = mutex; -using UniqueLock = unique_lock; -using ScopedLock = lock_guard; +using Mutex = std::mutex; +using UniqueLock = std::unique_lock; +using ScopedLock = std::lock_guard; #else /// Mutex is a class wrapper, that should mimic the std::chrono::mutex class. /// At the moment the extra function ref() is temporally added to allow calls @@ -471,7 +470,7 @@ class Condition private: #if ENABLE_STDCXX_SYNC - condition_variable m_cv; + std::condition_variable m_cv; #else pthread_cond_t m_cv; #endif @@ -742,6 +741,7 @@ class CGlobEvent #ifdef ENABLE_STDCXX_SYNC typedef std::system_error CThreadException; using CThread = std::thread; +namespace this_thread = std::this_thread; #else // pthreads wrapper version typedef ::CUDTException CThreadException; diff --git a/srtcore/sync_cxx11.cpp b/srtcore/sync_cxx11.cpp index 56a63a4bd..4dae3563e 100644 --- a/srtcore/sync_cxx11.cpp +++ b/srtcore/sync_cxx11.cpp @@ -68,12 +68,12 @@ void srt::sync::Condition::wait(UniqueLock& lock) bool srt::sync::Condition::wait_for(UniqueLock& lock, const steady_clock::duration& rel_time) { // Another possible implementation is wait_until(steady_clock::now() + timeout); - return m_cv.wait_for(lock, rel_time) != cv_status::timeout; + return m_cv.wait_for(lock, rel_time) != std::cv_status::timeout; } bool srt::sync::Condition::wait_until(UniqueLock& lock, const steady_clock::time_point& timeout_time) { - return m_cv.wait_until(lock, timeout_time) != cv_status::timeout; + return m_cv.wait_until(lock, timeout_time) != std::cv_status::timeout; } void srt::sync::Condition::notify_one() diff --git a/srtcore/utilities.h b/srtcore/utilities.h index 60a286ec0..f787a579e 100644 --- a/srtcore/utilities.h +++ b/srtcore/utilities.h @@ -140,6 +140,46 @@ written by # define le64toh(x) letoh64(x) #endif +#elif defined(SUNOS) + + // SunOS/Solaris + + #include + #include + + #define __LITTLE_ENDIAN 1234 + #define __BIG_ENDIAN 4321 + + # if defined(_BIG_ENDIAN) + #define __BYTE_ORDER __BIG_ENDIAN + #define be64toh(x) (x) + #define be32toh(x) (x) + #define be16toh(x) (x) + #define le16toh(x) ((uint16_t)BSWAP_16(x)) + #define le32toh(x) BSWAP_32(x) + #define le64toh(x) BSWAP_64(x) + #define htobe16(x) (x) + #define htole16(x) ((uint16_t)BSWAP_16(x)) + #define htobe32(x) (x) + #define htole32(x) BSWAP_32(x) + #define htobe64(x) (x) + #define htole64(x) BSWAP_64(x) + # else + #define __BYTE_ORDER __LITTLE_ENDIAN + #define be64toh(x) BSWAP_64(x) + #define be32toh(x) ntohl(x) + #define be16toh(x) ntohs(x) + #define le16toh(x) (x) + #define le32toh(x) (x) + #define le64toh(x) (x) + #define htobe16(x) htons(x) + #define htole16(x) (x) + #define htobe32(x) htonl(x) + #define htole32(x) (x) + #define htobe64(x) BSWAP_64(x) + #define htole64(x) (x) + # endif + #elif defined(__WINDOWS__) # include diff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp index 53f42a9a1..7d062f49d 100644 --- a/testing/testactivemedia.cpp +++ b/testing/testactivemedia.cpp @@ -16,7 +16,7 @@ void SourceMedium::Runner() } LOGP(applog.Debug, "SourceMedium(", typeid(*med).name(), "): [", input.payload.size(), "] MEDIUM -> BUFFER. signal(", &ready, ")"); - lock_guard g(buffer_lock); + lock_guard g(buffer_lock); buffer.push_back(input); ready.notify_one(); } @@ -24,7 +24,7 @@ void SourceMedium::Runner() MediaPacket SourceMedium::Extract() { - unique_lock g(buffer_lock); + unique_lock g(buffer_lock); for (;;) { if (::transmit_int_state) @@ -70,7 +70,7 @@ void TargetMedium::Runner() { MediaPacket val; { - unique_lock lg(buffer_lock); + unique_lock lg(buffer_lock); if (buffer.empty()) { if (!running) diff --git a/testing/testactivemedia.hpp b/testing/testactivemedia.hpp index c7b11e583..f4bc360ba 100644 --- a/testing/testactivemedia.hpp +++ b/testing/testactivemedia.hpp @@ -150,7 +150,7 @@ struct TargetMedium: Medium bool Schedule(const MediaPacket& data) { LOGP(applog.Debug, "TargetMedium::Schedule LOCK ... "); - lock_guard lg(buffer_lock); + lock_guard lg(buffer_lock); LOGP(applog.Debug, "TargetMedium::Schedule LOCKED - checking: running=", running, " interrupt=", ::transmit_int_state); if (!running || ::transmit_int_state) { @@ -166,13 +166,13 @@ struct TargetMedium: Medium void Clear() { - lock_guard lg(buffer_lock); + lock_guard lg(buffer_lock); buffer.clear(); } void Interrupt() { - lock_guard lg(buffer_lock); + lock_guard lg(buffer_lock); running = false; ready.notify_one(); } From ad84c38e40ba36e18699dd5998684540620697a1 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 14 Sep 2021 12:11:22 +0200 Subject: [PATCH 093/124] [core] Fixed FileCC random decrease --- srtcore/congctl.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp index 2301dfc68..b394f8183 100644 --- a/srtcore/congctl.cpp +++ b/srtcore/congctl.cpp @@ -535,8 +535,7 @@ class FileCC : public SrtCongestionControlBase m_iLastDecSeq = m_parent->sndSeqNo(); - // remove global synchronization using randomization. - m_iDecRandom = genRandomInt(1, m_iAvgNAKNum); + m_iDecRandom = m_iAvgNAKNum > 1 ? genRandomInt(1, m_iAvgNAKNum) : 1; SRT_ASSERT(m_iDecRandom >= 1); HLOGC(cclog.Debug, log << "FileCC: LOSS:NEW lseqno=" << lossbegin << ", lastsentseqno=" << m_iLastDecSeq From 4d0fe6166768d524d28e35e35c72bc12de0d46b5 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Thu, 16 Sep 2021 05:00:15 -0500 Subject: [PATCH 094/124] [build] Fixes build with CMake <3.0.2. (#2123) --- scripts/CheckCXXAtomic.cmake | 10 +--- scripts/CheckGCCAtomicIntrinsics.cmake | 25 ++------ scripts/FindPThreadGetSetName.cmake | 80 ++++++++++++-------------- scripts/UnSetVariableFull.cmake | 27 +++++++++ 4 files changed, 72 insertions(+), 70 deletions(-) create mode 100644 scripts/UnSetVariableFull.cmake diff --git a/scripts/CheckCXXAtomic.cmake b/scripts/CheckCXXAtomic.cmake index e071b78a3..8c2d141a1 100644 --- a/scripts/CheckCXXAtomic.cmake +++ b/scripts/CheckCXXAtomic.cmake @@ -15,16 +15,12 @@ include(CheckCXXSourceCompiles) include(CheckLibraryExists) +include(UnSetVariableFull) function(CheckCXXAtomic) - unset(HAVE_CXX_ATOMIC) - unset(HAVE_CXX_ATOMIC PARENT_SCOPE) - unset(HAVE_CXX_ATOMIC CACHE) - - unset(HAVE_CXX_ATOMIC_STATIC) - unset(HAVE_CXX_ATOMIC_STATIC PARENT_SCOPE) - unset(HAVE_CXX_ATOMIC_STATIC CACHE) + UnSetVariableFull(HAVE_CXX_ATOMIC) + UnSetVariableFull(HAVE_CXX_ATOMIC_STATIC) unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_LIBRARIES) diff --git a/scripts/CheckGCCAtomicIntrinsics.cmake b/scripts/CheckGCCAtomicIntrinsics.cmake index 164fb190e..8af1bd091 100644 --- a/scripts/CheckGCCAtomicIntrinsics.cmake +++ b/scripts/CheckGCCAtomicIntrinsics.cmake @@ -22,28 +22,15 @@ include(CheckCSourceCompiles) include(CheckLibraryExists) +include(UnSetVariableFull) function(CheckGCCAtomicIntrinsics) - unset(HAVE_LIBATOMIC) - unset(HAVE_LIBATOMIC PARENT_SCOPE) - unset(HAVE_LIBATOMIC CACHE) - - unset(HAVE_GCCATOMIC_INTRINSICS) - unset(HAVE_GCCATOMIC_INTRINSICS PARENT_SCOPE) - unset(HAVE_GCCATOMIC_INTRINSICS CACHE) - - unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) - unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC PARENT_SCOPE) - unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE) - - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC) - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC PARENT_SCOPE) - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC CACHE) - - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC) - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC PARENT_SCOPE) - unset(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC CACHE) + UnSetVariableFull(HAVE_LIBATOMIC) + UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS) + UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_STATIC) + UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC) unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_LIBRARIES) diff --git a/scripts/FindPThreadGetSetName.cmake b/scripts/FindPThreadGetSetName.cmake index fa818fd73..c78bca2be 100644 --- a/scripts/FindPThreadGetSetName.cmake +++ b/scripts/FindPThreadGetSetName.cmake @@ -27,56 +27,48 @@ # add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) include(CheckSymbolExists) +include(UnSetVariableFull) function(FindPThreadGetSetName) - unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE) - unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H CACHE) - unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE) - unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H CACHE) + UnSetVariableFull(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + UnSetVariableFull(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + UnSetVariableFull(HAVE_PTHREAD_GETNAME_NP) + UnSetVariableFull(HAVE_PTHREAD_SETNAME_NP) - unset(HAVE_PTHREAD_GETNAME_NP) - unset(HAVE_PTHREAD_GETNAME_NP PARENT_SCOPE) - unset(HAVE_PTHREAD_GETNAME_NP CACHE) - unset(HAVE_PTHREAD_SETNAME_NP) - unset(HAVE_PTHREAD_SETNAME_NP PARENT_SCOPE) - unset(HAVE_PTHREAD_SETNAME_NP CACHE) + set(CMAKE_REQUIRED_DEFINITIONS + -D_GNU_SOURCE -D_DARWIN_C_SOURCE -D_POSIX_SOURCE=1) + set(CMAKE_REQUIRED_FLAGS "-pthread") - set(CMAKE_REQUIRED_DEFINITIONS - -D_GNU_SOURCE -D_DARWIN_C_SOURCE -D_POSIX_SOURCE=1) - set(CMAKE_REQUIRED_FLAGS "-pthread") + message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread_np.h':") + check_symbol_exists( + pthread_getname_np "pthread_np.h" HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1) + endif() + check_symbol_exists( + pthread_setname_np "pthread_np.h" HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1) + endif() - message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread_np.h':") - check_symbol_exists( - pthread_getname_np "pthread_np.h" HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1) - endif() - check_symbol_exists( - pthread_setname_np "pthread_np.h" HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1) - endif() + message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread.h':") + check_symbol_exists(pthread_getname_np "pthread.h" HAVE_PTHREAD_GETNAME_NP) + if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) + set(HAVE_PTHREAD_GETNAME_NP TRUE PARENT_SCOPE) + endif() + check_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) + if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) + set(HAVE_PTHREAD_SETNAME_NP TRUE PARENT_SCOPE) + endif() + if (HAVE_PTHREAD_GETNAME_NP) + add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1) + endif() + if (HAVE_PTHREAD_SETNAME_NP) + add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) + endif() - message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread.h':") - check_symbol_exists(pthread_getname_np "pthread.h" HAVE_PTHREAD_GETNAME_NP) - if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - set(HAVE_PTHREAD_GETNAME_NP TRUE PARENT_SCOPE) - endif() - check_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) - if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - set(HAVE_PTHREAD_SETNAME_NP TRUE PARENT_SCOPE) - endif() - if (HAVE_PTHREAD_GETNAME_NP) - add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1) - endif() - if (HAVE_PTHREAD_SETNAME_NP) - add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) - endif() - - unset(CMAKE_REQUIRED_DEFINITIONS) - unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_DEFINITIONS) + unset(CMAKE_REQUIRED_FLAGS) endfunction(FindPThreadGetSetName) diff --git a/scripts/UnSetVariableFull.cmake b/scripts/UnSetVariableFull.cmake new file mode 100644 index 000000000..f751374ee --- /dev/null +++ b/scripts/UnSetVariableFull.cmake @@ -0,0 +1,27 @@ +# +# SRT - Secure, Reliable, Transport +# Copyright (c) 2021 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/. +# + +# Notes: +# +# Macro that UnSets a variable in Cache, Local Scope, and Parent Scope. +# +# Usage: +# +# UnSetVariableFull() + +macro(UnSetVariableFull tVariable) + unset(tVariable) + unset(tVariable CACHE) + # unset(.... PARENT_SCOPE) was introduced in cmake-3.0.2. + if ("${CMAKE_VERSION}" VERSION_LESS "3.0.2") + set(tVariable "" PARENT_SCOPE) + else() + unset(tVariable PARENT_SCOPE) + endif() +endmacro() From f9a54a033bf0ece3071f0fb297eb1130b8d9de7d Mon Sep 17 00:00:00 2001 From: Yanko Kaneti Date: Sat, 18 Sep 2021 21:53:44 +0300 Subject: [PATCH 095/124] [build] Build but do not install test-srt --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cb8d82a6..d1e7929e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1062,10 +1062,14 @@ else() message(FATAL_ERROR "Either ENABLE_STATIC or ENABLE_SHARED has to be ON!") endif() -macro(srt_add_program name) +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}) install(TARGETS ${name} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endmacro() @@ -1276,7 +1280,7 @@ if (ENABLE_UNITTESTS AND ENABLE_CXX11) SOURCES SOURCES_unittests ) - srt_add_program(test-srt ${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}) From add40584757636ec99eef41ea3ea4687a43feb3f Mon Sep 17 00:00:00 2001 From: Thierry Lelegard Date: Mon, 20 Sep 2021 16:45:53 +0200 Subject: [PATCH 096/124] [core] Fixed 'undef' warning with gcc and clang (#2131) --- srtcore/platform_sys.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/srtcore/platform_sys.h b/srtcore/platform_sys.h index 79760080e..cb5d0afd9 100644 --- a/srtcore/platform_sys.h +++ b/srtcore/platform_sys.h @@ -45,7 +45,15 @@ #endif #else -#if __APPLE__ +#if defined(__APPLE__) && __APPLE__ +// Warning: please keep this test as it is, do not make it +// "#if __APPLE__" or "#ifdef __APPLE__". In applications with +// a strict "no warning policy", "#if __APPLE__" triggers an "undef" +// error. With GCC, an old & never fixed bug prevents muting this +// warning (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431). +// Before this fix, the solution was to "#define __APPLE__ 0" before +// including srt.h. So, don't use "#ifdef __APPLE__" either. + // XXX Check if this condition doesn't require checking of // also other macros, like TARGET_OS_IOS etc. From 1d862c43c87678b2f02415ce958dd822786572a2 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 22 Sep 2021 17:14:41 +0200 Subject: [PATCH 097/124] [build] Fixed a typo 'availabe' --- scripts/haiUtil.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/haiUtil.cmake b/scripts/haiUtil.cmake index 9e4fb4d56..222661989 100644 --- a/scripts/haiUtil.cmake +++ b/scripts/haiUtil.cmake @@ -252,7 +252,7 @@ function (test_requires_clock_gettime _enable _linklib) check_testcode_compiles(${code} "" HAVE_CLOCK_GETTIME_IN) if (HAVE_CLOCK_GETTIME_IN) - message(STATUS "CLOCK_MONOTONIC: availabe, no extra libs needed") + message(STATUS "CLOCK_MONOTONIC: available, no extra libs needed") set (${_enable} ON PARENT_SCOPE) set (${_linklib} "" PARENT_SCOPE) return() From 224042a5867b11a06ddb5fb0f40d93ffb2b22494 Mon Sep 17 00:00:00 2001 From: Maria Sharabayko Date: Wed, 22 Sep 2021 11:38:14 +0200 Subject: [PATCH 098/124] [docs] Updated SRTO_RETRANSMITALGO socket option description --- docs/API/API-socket-options.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md index 84606135a..7f85d6800 100644 --- a/docs/API/API-socket-options.md +++ b/docs/API/API-socket-options.md @@ -1277,17 +1277,20 @@ procedure of `srt_bind` and then `srt_connect` (or `srt_rendezvous`) to one anot | --------------------- | ----- | -------- | --------- | ------ | ------- | ------ | --- | ------ | | `SRTO_RETRANSMITALGO` | 1.4.2 | pre | `int32_t` | | 1 | [0, 1] | RW | GSD | -Retransmission algorithm to use (SENDER option): +An SRT sender option to choose between two retransmission algorithms: -- 0 - Retransmit on every loss report (higher overhead, but slightly higher chance to recover a lost packet). -- 1 - Reduced retransmissions (retransmit not more often than once per RTT); reduced - bandwidth consumption. +- 0 - an intensive retransmission algorithm (default until SRT v1.4.4), and +- 1 - a new efficient retransmission algorithm (introduced in SRT v1.4.2; default since SRT v1.4.4). -This option is effective only on the sending side. It influences the decision +The intensive 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. + +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. -The reduced retransmission algorithm (`SRTO_RETRANSMITALGO=1`) is only operational when receiver sends +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) From d8127a813d21909149fa94690845ec95d17977c8 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Thu, 23 Sep 2021 11:54:00 +0200 Subject: [PATCH 099/124] [build] Fixed CMake warning about string --- scripts/iOS.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/iOS.cmake b/scripts/iOS.cmake index 73544a29b..dfb6aeb97 100644 --- a/scripts/iOS.cmake +++ b/scripts/iOS.cmake @@ -151,10 +151,10 @@ if (NOT DEFINED IOS_ARCH) set (IOS_ARCH x86_64) endif (${IOS_PLATFORM} STREQUAL OS) endif(NOT DEFINED IOS_ARCH) -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") +set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS") # Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") +set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING "iOS find search path root") # default to searching for frameworks first set (CMAKE_FIND_FRAMEWORK FIRST) From 60891f31bb3f167497237e963b142fa777eecb50 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 28 Sep 2021 14:53:02 +0200 Subject: [PATCH 100/124] [core] Fixed 'atomic' linking for iOS target (#2137) Co-authored-by: Jose Santiago --- CMakeLists.txt | 20 +++++++------ scripts/CheckCXXAtomic.cmake | 12 +++++--- scripts/CheckGCCAtomicIntrinsics.cmake | 40 ++++---------------------- scripts/FindPThreadGetSetName.cmake | 13 ++++----- scripts/UnSetVariableFull.cmake | 27 ----------------- 5 files changed, 30 insertions(+), 82 deletions(-) delete mode 100644 scripts/UnSetVariableFull.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d1e7929e1..7200491df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,8 +418,6 @@ endif() # HAVE_LIBATOMIC # HAVE_GCCATOMIC_INTRINSICS # HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC -# HAVE_GCCATOMIC_INTRINSICS_STATIC -# HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC include(CheckGCCAtomicIntrinsics) CheckGCCAtomicIntrinsics() # HAVE_CXX_ATOMIC @@ -887,7 +885,7 @@ if (srt_libspec_shared) endif() if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PRIVATE ws2_32.lib) - if (OPENSSL_USE_STATIC_LIBS) + 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") @@ -925,7 +923,7 @@ if (srt_libspec_static) endif() if (MICROSOFT) target_link_libraries(${TARGET_srt}_static PRIVATE ws2_32.lib) - if (OPENSSL_USE_STATIC_LIBS) + if (OPENSSL_USE_STATIC_LIBS) target_link_libraries(${TARGET_srt}_static PRIVATE crypt32.lib) endif() elseif (MINGW) @@ -938,8 +936,8 @@ endif() target_include_directories(srt_virtual PRIVATE ${SSL_INCLUDE_DIRS}) -if (MICROSOFT) - if (OPENSSL_USE_STATIC_LIBS) +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) @@ -983,9 +981,13 @@ endif() # Required by some toolchains when statically linking this library if the # GCC Atomic Intrinsics are being used. -if (HAVE_GCCATOMIC_INTRINSICS - AND HAVE_LIBATOMIC) - target_link_libraries(${TARGET_srt}_static PUBLIC atomic) +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() endif() # Cygwin installs the *.dll libraries in bin directory and uses PATH. diff --git a/scripts/CheckCXXAtomic.cmake b/scripts/CheckCXXAtomic.cmake index 8c2d141a1..d3a3b9e71 100644 --- a/scripts/CheckCXXAtomic.cmake +++ b/scripts/CheckCXXAtomic.cmake @@ -15,12 +15,11 @@ include(CheckCXXSourceCompiles) include(CheckLibraryExists) -include(UnSetVariableFull) function(CheckCXXAtomic) - UnSetVariableFull(HAVE_CXX_ATOMIC) - UnSetVariableFull(HAVE_CXX_ATOMIC_STATIC) + unset(HAVE_CXX_ATOMIC CACHE) + unset(HAVE_CXX_ATOMIC_STATIC CACHE) unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_LIBRARIES) @@ -45,7 +44,12 @@ function(CheckCXXAtomic) HAVE_CXX_ATOMIC) if(HAVE_CXX_ATOMIC) - set(CMAKE_REQUIRED_LINK_OPTIONS "-static") + # CMAKE_REQUIRED_LINK_OPTIONS was introduced in CMake 3.14. + if(CMAKE_VERSION VERSION_LESS "3.14") + set(CMAKE_REQUIRED_LINK_OPTIONS "-static") + else() + set(CMAKE_REQUIRED_FLAGS "-std=c++11 -static") + endif() check_cxx_source_compiles( "${CheckCXXAtomic_CODE}" HAVE_CXX_ATOMIC_STATIC) diff --git a/scripts/CheckGCCAtomicIntrinsics.cmake b/scripts/CheckGCCAtomicIntrinsics.cmake index 8af1bd091..9429db12f 100644 --- a/scripts/CheckGCCAtomicIntrinsics.cmake +++ b/scripts/CheckGCCAtomicIntrinsics.cmake @@ -13,8 +13,6 @@ # HAVE_LIBATOMIC # HAVE_GCCATOMIC_INTRINSICS # HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC -# HAVE_GCCATOMIC_INTRINSICS_STATIC -# HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC # # See # https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html @@ -22,15 +20,12 @@ include(CheckCSourceCompiles) include(CheckLibraryExists) -include(UnSetVariableFull) function(CheckGCCAtomicIntrinsics) - UnSetVariableFull(HAVE_LIBATOMIC) - UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS) - UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) - UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_STATIC) - UnSetVariableFull(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC) + unset(HAVE_LIBATOMIC CACHE) + unset(HAVE_GCCATOMIC_INTRINSICS CACHE) + unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE) unset(CMAKE_REQUIRED_FLAGS) unset(CMAKE_REQUIRED_LIBRARIES) @@ -54,12 +49,12 @@ function(CheckGCCAtomicIntrinsics) check_library_exists( atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC) + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6 check_c_source_compiles( "${CheckGCCAtomicIntrinsics_CODE}" HAVE_GCCATOMIC_INTRINSICS) - if (NOT HAVE_GCCATOMIC_INTRINSICS - AND HAVE_LIBATOMIC) + if (NOT HAVE_GCCATOMIC_INTRINSICS AND HAVE_LIBATOMIC) set(CMAKE_REQUIRED_LIBRARIES "atomic") check_c_source_compiles( "${CheckGCCAtomicIntrinsics_CODE}" @@ -69,29 +64,4 @@ function(CheckGCCAtomicIntrinsics) endif() endif() - unset(CMAKE_REQUIRED_FLAGS) - unset(CMAKE_REQUIRED_LIBRARIES) - unset(CMAKE_REQUIRED_LINK_OPTIONS) - - if (HAVE_GCCATOMIC_INTRINSICS) - set(CMAKE_REQUIRED_LINK_OPTIONS "-static") - check_c_source_compiles( - "${CheckGCCAtomicIntrinsics_CODE}" - HAVE_GCCATOMIC_INTRINSICS_STATIC) - if (NOT HAVE_GCCATOMIC_INTRINSICS_STATIC - AND HAVE_LIBATOMIC) - set(CMAKE_REQUIRED_LIBRARIES "atomic") - check_c_source_compiles( - "${CheckGCCAtomicIntrinsics_CODE}" - HAVE_GCCATOMIC_INTRINSICS_STATIC) - if (HAVE_GCCATOMIC_INTRINSICS_STATIC) - set(HAVE_GCCATOMIC_INTRINSICS_STATIC_REQUIRES_LIBATOMIC TRUE PARENT_SCOPE) - endif() - endif() - endif() - - unset(CMAKE_REQUIRED_FLAGS) - unset(CMAKE_REQUIRED_LIBRARIES) - unset(CMAKE_REQUIRED_LINK_OPTIONS) - endfunction(CheckGCCAtomicIntrinsics) diff --git a/scripts/FindPThreadGetSetName.cmake b/scripts/FindPThreadGetSetName.cmake index c78bca2be..65685e1eb 100644 --- a/scripts/FindPThreadGetSetName.cmake +++ b/scripts/FindPThreadGetSetName.cmake @@ -27,14 +27,13 @@ # add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1) include(CheckSymbolExists) -include(UnSetVariableFull) function(FindPThreadGetSetName) - UnSetVariableFull(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - UnSetVariableFull(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - UnSetVariableFull(HAVE_PTHREAD_GETNAME_NP) - UnSetVariableFull(HAVE_PTHREAD_SETNAME_NP) + unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H CACHE) + unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H CACHE) + unset(HAVE_PTHREAD_GETNAME_NP CACHE) + unset(HAVE_PTHREAD_SETNAME_NP CACHE) set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE -D_DARWIN_C_SOURCE -D_POSIX_SOURCE=1) @@ -55,11 +54,11 @@ function(FindPThreadGetSetName) message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread.h':") check_symbol_exists(pthread_getname_np "pthread.h" HAVE_PTHREAD_GETNAME_NP) if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) - set(HAVE_PTHREAD_GETNAME_NP TRUE PARENT_SCOPE) + set(HAVE_PTHREAD_GETNAME_NP 1 CACHE INTERNAL "" FORCE) endif() check_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) - set(HAVE_PTHREAD_SETNAME_NP TRUE PARENT_SCOPE) + set(HAVE_PTHREAD_SETNAME_NP 1 CACHE INTERNAL "" FORCE) endif() if (HAVE_PTHREAD_GETNAME_NP) add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1) diff --git a/scripts/UnSetVariableFull.cmake b/scripts/UnSetVariableFull.cmake deleted file mode 100644 index f751374ee..000000000 --- a/scripts/UnSetVariableFull.cmake +++ /dev/null @@ -1,27 +0,0 @@ -# -# SRT - Secure, Reliable, Transport -# Copyright (c) 2021 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/. -# - -# Notes: -# -# Macro that UnSets a variable in Cache, Local Scope, and Parent Scope. -# -# Usage: -# -# UnSetVariableFull() - -macro(UnSetVariableFull tVariable) - unset(tVariable) - unset(tVariable CACHE) - # unset(.... PARENT_SCOPE) was introduced in cmake-3.0.2. - if ("${CMAKE_VERSION}" VERSION_LESS "3.0.2") - set(tVariable "" PARENT_SCOPE) - else() - unset(tVariable PARENT_SCOPE) - endif() -endmacro() From 6fda50220aa848145fb97d5382e66aa59cb81bff Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 28 Sep 2021 15:15:28 +0200 Subject: [PATCH 101/124] [build] Added iOS build to GitHub Actions CI (#2136) --- .github/workflows/iOS.yaml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/iOS.yaml diff --git a/.github/workflows/iOS.yaml b/.github/workflows/iOS.yaml new file mode 100644 index 000000000..60d1e8d3a --- /dev/null +++ b/.github/workflows/iOS.yaml @@ -0,0 +1,25 @@ +name: 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@v2 + - name: configure + run: | + mkdir _build && cd _build + cmake ../ -DENABLE_ENCRYPTION=OFF -DENABLE_STDCXX_SYNC=${{matrix.cxxstdsync}} -DENABLE_UNITTESTS=OFF -DENABLE_EXPERIMENTAL_BONDING=ON --toolchain scripts/iOS.cmake + - name: build + run: cd _build && cmake --build ./ From cdec1145c8430a66b535636a14139531e51d9cb1 Mon Sep 17 00:00:00 2001 From: Jose Santiago Date: Tue, 28 Sep 2021 16:45:36 +0200 Subject: [PATCH 102/124] [build] Fix build Android with NDK <17. Need to link against libatomic when compiling statically --- CMakeLists.txt | 10 +- scripts/CheckGCCAtomicIntrinsics.cmake | 136 +++++++++++++++++-------- 2 files changed, 100 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7200491df..21478c36a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -416,6 +416,8 @@ 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) @@ -973,7 +975,7 @@ endif() if (srt_libspec_shared) if (MICROSOFT) target_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib) - if (OPENSSL_USE_STATIC_LIBS) + if (OPENSSL_USE_STATIC_LIBS) target_link_libraries(${TARGET_srt}_shared PUBLIC crypt32.lib) endif() endif() @@ -988,6 +990,12 @@ if (HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC AND HAVE_LIBATOMIC) 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() endif() # Cygwin installs the *.dll libraries in bin directory and uses PATH. diff --git a/scripts/CheckGCCAtomicIntrinsics.cmake b/scripts/CheckGCCAtomicIntrinsics.cmake index 9429db12f..f47b14d61 100644 --- a/scripts/CheckGCCAtomicIntrinsics.cmake +++ b/scripts/CheckGCCAtomicIntrinsics.cmake @@ -1,67 +1,113 @@ # -# SRT - Secure, Reliable, Transport -# Copyright (c) 2021 Haivision Systems Inc. +# SRT - Secure, Reliable, Transport Copyright (c) 2021 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 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/. # # Check for GCC Atomic Intrinsics and whether libatomic is required. # # Sets: -# HAVE_LIBATOMIC -# HAVE_GCCATOMIC_INTRINSICS -# HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC +# HAVE_LIBATOMIC +# HAVE_LIBATOMIC_COMPILES +# HAVE_LIBATOMIC_COMPILES_STATIC +# HAVE_GCCATOMIC_INTRINSICS +# HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC # # See -# https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html -# https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync +# https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html +# https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync include(CheckCSourceCompiles) include(CheckLibraryExists) function(CheckGCCAtomicIntrinsics) - unset(HAVE_LIBATOMIC CACHE) - unset(HAVE_GCCATOMIC_INTRINSICS CACHE) - unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE) + unset(HAVE_LIBATOMIC CACHE) + unset(HAVE_LIBATOMIC_COMPILES CACHE) + unset(HAVE_LIBATOMIC_COMPILES_STATIC CACHE) + unset(HAVE_GCCATOMIC_INTRINSICS CACHE) + unset(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC CACHE) - unset(CMAKE_REQUIRED_FLAGS) - unset(CMAKE_REQUIRED_LIBRARIES) - unset(CMAKE_REQUIRED_LINK_OPTIONS) + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6 - set(CheckGCCAtomicIntrinsics_CODE - " - #include - #include - int main(void) - { - ptrdiff_t x = 0; - intmax_t y = 0; - __atomic_add_fetch(&x, 1, __ATOMIC_SEQ_CST); - __atomic_add_fetch(&y, 1, __ATOMIC_SEQ_CST); - return __atomic_sub_fetch(&x, 1, __ATOMIC_SEQ_CST) - + __atomic_sub_fetch(&y, 1, __ATOMIC_SEQ_CST); - } - ") + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) - check_library_exists( - atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC) + # Check for existance of libatomic and whether this symbol is present. + check_library_exists(atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC) - set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6 - check_c_source_compiles( - "${CheckGCCAtomicIntrinsics_CODE}" - HAVE_GCCATOMIC_INTRINSICS) + set(CheckLibAtomicCompiles_CODE + " + int main(void) + { + const int result = 0; + return result; + } + ") - if (NOT HAVE_GCCATOMIC_INTRINSICS AND HAVE_LIBATOMIC) - set(CMAKE_REQUIRED_LIBRARIES "atomic") - check_c_source_compiles( - "${CheckGCCAtomicIntrinsics_CODE}" - HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) - if (HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) - set(HAVE_GCCATOMIC_INTRINSICS TRUE PARENT_SCOPE) - endif() - endif() + set(CMAKE_REQUIRED_LIBRARIES "atomic") + + # Check that the compiler can build a simple application and link with + # libatomic. + check_c_source_compiles("${CheckLibAtomicCompiles_CODE}" + HAVE_LIBATOMIC_COMPILES) + if(NOT HAVE_LIBATOMIC_COMPILES) + set(HAVE_LIBATOMIC + 0 + CACHE INTERNAL "" FORCE) + endif() + if(HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES) + # CMAKE_REQUIRED_LINK_OPTIONS was introduced in CMake 3.14. + if(CMAKE_VERSION VERSION_LESS "3.14") + set(CMAKE_REQUIRED_LINK_OPTIONS "-static") + else() + set(CMAKE_REQUIRED_FLAGS "-static") + endif() + # Check that the compiler can build a simple application and statically link + # with libatomic. + check_c_source_compiles("${CheckLibAtomicCompiles_CODE}" + HAVE_LIBATOMIC_COMPILES_STATIC) + else() + set(HAVE_LIBATOMIC_COMPILES_STATIC + 0 + CACHE INTERNAL "" FORCE) + endif() + + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LIBRARIES) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + + set(CheckGCCAtomicIntrinsics_CODE + " + #include + #include + int main(void) + { + ptrdiff_t x = 0; + intmax_t y = 0; + __atomic_add_fetch(&x, 1, __ATOMIC_SEQ_CST); + __atomic_add_fetch(&y, 1, __ATOMIC_SEQ_CST); + return __atomic_sub_fetch(&x, 1, __ATOMIC_SEQ_CST) + + __atomic_sub_fetch(&y, 1, __ATOMIC_SEQ_CST); + } + ") + + set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6 + check_c_source_compiles("${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS) + + if(NOT HAVE_GCCATOMIC_INTRINSICS AND HAVE_LIBATOMIC) + set(CMAKE_REQUIRED_LIBRARIES "atomic") + check_c_source_compiles("${CheckGCCAtomicIntrinsics_CODE}" + HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + if(HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC) + set(HAVE_GCCATOMIC_INTRINSICS + 1 + CACHE INTERNAL "" FORCE) + endif() + endif() endfunction(CheckGCCAtomicIntrinsics) From 167b8e5031ee4e0aed9a49365a7f458e53c1f68b Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 29 Sep 2021 19:06:33 +0200 Subject: [PATCH 103/124] [core] Fixed group drift synchronization (#2139) --- srtcore/buffer.cpp | 13 +++++------ srtcore/buffer.h | 8 ++----- srtcore/core.cpp | 7 ++---- srtcore/group.cpp | 49 ++++++++++++------------------------------ srtcore/group.h | 5 ++++- srtcore/tsbpd_time.cpp | 8 +------ srtcore/tsbpd_time.h | 7 +----- 7 files changed, 29 insertions(+), 68 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index bbe41b7f6..c035ad936 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -1549,8 +1549,8 @@ CPacket* CRcvBuffer::getRcvReadyPacket(int32_t seqdistance) HLOGC(brlog.Debug, log << "getRcvReadyPacket: Sequence offset=" << seqdistance << " IS NOT RECEIVED."); return 0; } - IF_HEAVY_LOGGING(int nskipped = 0); + IF_HEAVY_LOGGING(int nskipped = 0); for (int i = m_iStartPos, n = m_iLastAckPos; i != n; i = shiftFwd(i)) { /* @@ -1559,8 +1559,8 @@ CPacket* CRcvBuffer::getRcvReadyPacket(int32_t seqdistance) if (m_pUnit[i] && m_pUnit[i]->m_iFlag == CUnit::GOOD) { HLOGC(brlog.Debug, - log << "getRcvReadyPacket: Found next packet seq=%" << m_pUnit[i]->m_Packet.getSeqNo() << " (" - << nskipped << " empty cells skipped)"); + log << "getRcvReadyPacket: Found next packet seq=%" << m_pUnit[i]->m_Packet.getSeqNo() << " (" + << nskipped << " empty cells skipped)"); return &m_pUnit[i]->m_Packet; } IF_HEAVY_LOGGING(++nskipped); @@ -1881,12 +1881,9 @@ void CRcvBuffer::setRcvTsbPdMode(const steady_clock::time_point& timebase, const m_tsbpd.setTsbPdMode(timebase, no_wrap_check, delay); } -bool CRcvBuffer::addRcvTsbPdDriftSample(uint32_t timestamp_us, - int rtt, - steady_clock::duration& w_udrift, - steady_clock::time_point& w_newtimebase) +bool CRcvBuffer::addRcvTsbPdDriftSample(uint32_t timestamp_us, int rtt) { - return m_tsbpd.addDriftSample(timestamp_us, rtt, w_udrift, w_newtimebase); + return m_tsbpd.addDriftSample(timestamp_us, rtt); } int CRcvBuffer::readMsg(char* data, int len) diff --git a/srtcore/buffer.h b/srtcore/buffer.h index 9bf02f216..2dc63d972 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -411,12 +411,8 @@ class CRcvBuffer /// Add packet timestamp for drift caclculation and compensation /// @param [in] timestamp packet time stamp - /// @param [out] w_udrift current drift value - /// @param [out] w_newtimebase current TSBPD base time - bool addRcvTsbPdDriftSample(uint32_t timestamp, - int rtt, - duration& w_udrift, - time_point& w_newtimebase); + /// @param [in] rtt RTT sample + bool addRcvTsbPdDriftSample(uint32_t timestamp, int rtt); #ifdef SRT_DEBUG_TSBPD_DRIFT void printDriftHistogram(int64_t iDrift); diff --git a/srtcore/core.cpp b/srtcore/core.cpp index a5fe649d8..ab1e7da9d 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -8324,17 +8324,14 @@ void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr // srt_recvfile (which doesn't make any sense), you'll have a deadlock. if (m_config.bDriftTracer) { - steady_clock::duration udrift(0); - steady_clock::time_point newtimebase; - const bool drift_updated SRT_ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), - rtt, (udrift), (newtimebase)); + const bool drift_updated SRT_ATR_UNUSED = m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), rtt); #if ENABLE_EXPERIMENTAL_BONDING if (drift_updated && m_parent->m_GroupOf) { ScopedLock glock(s_UDTUnited.m_GlobControlLock); if (m_parent->m_GroupOf) { - m_parent->m_GroupOf->synchronizeDrift(this, udrift, newtimebase); + m_parent->m_GroupOf->synchronizeDrift(this); } } #endif diff --git a/srtcore/group.cpp b/srtcore/group.cpp index e835453ea..bee5c2beb 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -2725,48 +2725,24 @@ const char* CUDTGroup::StateStr(CUDTGroup::GroupState st) return unknown; } -void CUDTGroup::synchronizeDrift(CUDT* cu, steady_clock::duration udrift, steady_clock::time_point newtimebase) +void CUDTGroup::synchronizeDrift(const srt::CUDT* srcMember) { + SRT_ASSERT(srcMember != NULL); ScopedLock glock(m_GroupLock); - - bool wrap_period = false; - - bool anycheck = false; - - for (gli_t gi = m_Group.begin(); gi != m_Group.end(); ++gi) - { - // Skip non-connected; these will be synchronized when ready - if (gi->laststatus != SRTS_CONNECTED) - continue; - - // Skip the entity that has reported this - if (cu == &gi->ps->core()) - continue; - - steady_clock::time_point this_timebase; - steady_clock::duration this_udrift(0); - bool wrp = false; - gi->ps->core().m_pRcvBuffer->getInternalTimeBase((this_timebase), (wrp), (this_udrift)); - - udrift = std::min(udrift, this_udrift); - steady_clock::time_point new_newtimebase = std::min(newtimebase, this_timebase); - if (new_newtimebase != newtimebase) - { - wrap_period = wrp; - } - newtimebase = new_newtimebase; - anycheck = true; - } - - if (!anycheck) + if (m_Group.size() <= 1) { HLOGC(grlog.Debug, log << "GROUP: synch uDRIFT NOT DONE, no other links"); return; } + steady_clock::time_point timebase; + steady_clock::duration udrift(0); + bool wrap_period = false; + srcMember->m_pRcvBuffer->getInternalTimeBase((timebase), (wrap_period), (udrift)); + HLOGC(grlog.Debug, - log << "GROUP: synch uDRIFT=" << FormatDuration(udrift) << " TB=" << FormatTime(newtimebase) << "(" - << (wrap_period ? "" : "NO ") << "wrap period)"); + log << "GROUP: synch uDRIFT=" << FormatDuration(udrift) << " TB=" << FormatTime(timebase) << "(" + << (wrap_period ? "" : "NO ") << "wrap period)"); // Now that we have the minimum timebase and drift calculated, apply this to every link, // INCLUDING THE REPORTER. @@ -2776,8 +2752,11 @@ void CUDTGroup::synchronizeDrift(CUDT* cu, steady_clock::duration udrift, steady // Skip non-connected; these will be synchronized when ready if (gi->laststatus != SRTS_CONNECTED) continue; + CUDT& member = gi->ps->core(); + if (srcMember == &member) + continue; - gi->ps->core().m_pRcvBuffer->applyGroupDrift(newtimebase, wrap_period, udrift); + member.m_pRcvBuffer->applyGroupDrift(timebase, wrap_period, udrift); } } diff --git a/srtcore/group.h b/srtcore/group.h index e4b2fb6ed..04c8e7e01 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -798,7 +798,10 @@ class CUDTGroup // Live state synchronization bool getBufferTimeBase(srt::CUDT* forthesakeof, time_point& w_tb, bool& w_wp, duration& w_dr); bool applyGroupSequences(SRTSOCKET, int32_t& w_snd_isn, int32_t& w_rcv_isn); - void synchronizeDrift(srt::CUDT* cu, duration udrift, time_point newtimebase); + + /// @brief Synchronize TSBPD base time and clock drift among members using the @a srcMember as a reference. + /// @param srcMember a reference for synchronization. + void synchronizeDrift(const srt::CUDT* srcMember); void updateLatestRcv(srt::CUDTSocket*); diff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp index 54a8c5df5..9b75d595e 100644 --- a/srtcore/tsbpd_time.cpp +++ b/srtcore/tsbpd_time.cpp @@ -103,10 +103,7 @@ drift_logger g_drift_logger; #endif // SRT_DEBUG_TRACE_DRIFT -bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, - int usRTTSample, - steady_clock::duration& w_udrift, - steady_clock::time_point& w_newtimebase) +bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, int usRTTSample) { if (!m_bTsbPdMode) return false; @@ -149,9 +146,6 @@ bool CTsbpdTime::addDriftSample(uint32_t usPktTimestamp, log << "DRIFT=" << FormatDuration(tdDrift) << " TB REMAINS: " << FormatTime(m_tsTsbPdTimeBase)); } - w_udrift = tdDrift; - w_newtimebase = m_tsTsbPdTimeBase; - #if SRT_DEBUG_TRACE_DRIFT g_drift_logger.trace(usPktTimestamp, usRTTSample, diff --git a/srtcore/tsbpd_time.h b/srtcore/tsbpd_time.h index b6cb770f5..dcaf05718 100644 --- a/srtcore/tsbpd_time.h +++ b/srtcore/tsbpd_time.h @@ -67,14 +67,9 @@ class CTsbpdTime /// /// @param [in] pktTimestamp Timestamp of the arrived ACKACK packet. /// @param [in] usRTTSample RTT sample from an ACK-ACKACK pair. - /// @param [out] w_udrift Current clock drift value. - /// @param [out] w_newtimebase Current TSBPD base time. /// /// @return true if TSBPD base time has changed, false otherwise. - bool addDriftSample(uint32_t pktTimestamp, - int usRTTSample, - steady_clock::duration& w_udrift, - steady_clock::time_point& w_newtimebase); + bool addDriftSample(uint32_t pktTimestamp, int usRTTSample); /// @brief Handle timestamp of data packet when 32-bit integer carryover is about to happen. /// When packet timestamp approaches CPacket::MAX_TIMESTAMP, the TSBPD base time should be From 8b32f3734ff6af7cc7b0fef272591cb80a2d1aae Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 1 Oct 2021 14:25:02 +0200 Subject: [PATCH 104/124] [core] Fixed seqno validity check by group receiver (#2142) --- srtcore/common.h | 14 +++++++++----- srtcore/group.cpp | 39 ++++++++++++++++++++++++++++++++++++++- test/test_seqno.cpp | 9 +++------ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/srtcore/common.h b/srtcore/common.h index f6fdba44a..530759dde 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -634,12 +634,16 @@ class CSeqNo /// WITH A PRECONDITION that certainly @a seq1 is earlier than @a seq2. /// This can also include an enormously large distance between them, /// that is, exceeding the m_iSeqNoTH value (can be also used to test - /// if this distance is larger). Prior to calling this function the - /// caller must be certain that @a seq2 is a sequence coming from a - /// later time than @a seq1, and still, of course, this distance didn't - /// exceed m_iMaxSeqNo. + /// if this distance is larger). + /// Prior to calling this function the caller must be certain that + /// @a seq2 is a sequence coming from a later time than @a seq1, + /// and that the distance does not exceed m_iMaxSeqNo. inline static int seqlen(int32_t seq1, int32_t seq2) - {return (seq1 <= seq2) ? (seq2 - seq1 + 1) : (seq2 - seq1 + m_iMaxSeqNo + 2);} + { + SRT_ASSERT(seq1 >= 0 && seq1 <= m_iMaxSeqNo); + SRT_ASSERT(seq2 >= 0 && seq2 <= m_iMaxSeqNo); + return (seq1 <= seq2) ? (seq2 - seq1 + 1) : (seq2 - seq1 + m_iMaxSeqNo + 2); + } /// This behaves like seq2 - seq1, with the precondition that the true /// distance between two sequence numbers never exceeds m_iSeqNoTH. diff --git a/srtcore/group.cpp b/srtcore/group.cpp index bee5c2beb..f05f49369 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -2148,6 +2148,43 @@ void CUDTGroup::updateWriteState() m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, true); } +/// Validate iPktSeqno is in range +/// (iBaseSeqno - m_iSeqNoTH/2; iBaseSeqno + m_iSeqNoTH). +/// +/// EXPECT_EQ(isValidSeqno(125, 124), true); // behind +/// EXPECT_EQ(isValidSeqno(125, 125), true); // behind +/// EXPECT_EQ(isValidSeqno(125, 126), true); // the next in order +/// +/// EXPECT_EQ(isValidSeqno(0, 0x3FFFFFFF - 2), true); // ahead, but ok. +/// EXPECT_EQ(isValidSeqno(0, 0x3FFFFFFF - 1), false); // too far ahead. +/// EXPECT_EQ(isValidSeqno(0x3FFFFFFF + 2, 0x7FFFFFFF), false); // too far ahead. +/// EXPECT_EQ(isValidSeqno(0x3FFFFFFF + 3, 0x7FFFFFFF), true); // ahead, but ok. +/// EXPECT_EQ(isValidSeqno(0x3FFFFFFF, 0x1FFFFFFF + 2), false); // too far (behind) +/// EXPECT_EQ(isValidSeqno(0x3FFFFFFF, 0x1FFFFFFF + 3), true); // behind, but ok +/// EXPECT_EQ(isValidSeqno(0x70000000, 0x0FFFFFFF), true); // ahead, but ok +/// EXPECT_EQ(isValidSeqno(0x70000000, 0x30000000 - 2), false); // too far ahead. +/// EXPECT_EQ(isValidSeqno(0x70000000, 0x30000000 - 3), true); // ahead, but ok +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0), true); +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0x7FFFFFFF), true); +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0x70000000), false); +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0x70000001), false); +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0x70000002), true); // behind by 536870910 +/// EXPECT_EQ(isValidSeqno(0x0FFFFFFF, 0x70000003), true); +/// +/// @return false if @a iPktSeqno is not inside the valid range; otherwise true. +static bool isValidSeqno(int32_t iBaseSeqno, int32_t iPktSeqno) +{ + const int32_t iLenAhead = CSeqNo::seqlen(iBaseSeqno, iPktSeqno); + if (iLenAhead >= 0 && iLenAhead < CSeqNo::m_iSeqNoTH) + return true; + + const int32_t iLenBehind = CSeqNo::seqlen(iPktSeqno, iBaseSeqno); + if (iLenBehind >= 0 && iLenBehind < CSeqNo::m_iSeqNoTH / 2) + return true; + + return false; +} + // The "app reader" version of the reading function. // This reads the packets from every socket treating them as independent // and prepared to work with the application. Then packets are sorted out @@ -2407,7 +2444,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) // embrace everything below. // We need to first qualify the sequence, just for a case - if (m_RcvBaseSeqNo != SRT_SEQNO_NONE && abs(m_RcvBaseSeqNo - mctrl.pktseq) > CSeqNo::m_iSeqNoTH) + if (m_RcvBaseSeqNo != SRT_SEQNO_NONE && !isValidSeqno(m_RcvBaseSeqNo, mctrl.pktseq)) { // This error should be returned if the link turns out // to be the only one, or set to the group data. diff --git a/test/test_seqno.cpp b/test/test_seqno.cpp index f3f50de62..f2e374f76 100644 --- a/test/test_seqno.cpp +++ b/test/test_seqno.cpp @@ -16,7 +16,6 @@ TEST(CSeqNo, constants) EXPECT_EQ(CSeqNo::m_iSeqNoTH, 0x3FFFFFFF); } - TEST(CSeqNo, seqcmp) { // Compare two seq#, considering the wraping. @@ -31,7 +30,6 @@ TEST(CSeqNo, seqcmp) EXPECT_EQ(CSeqNo::seqcmp(1, 0x7FFFFFFF), 0x7FFFFFFE); // 2147483646 } - TEST(CSeqNo, seqoff) { // seqoff: offset from the 2nd to the 1st seq# @@ -48,6 +46,9 @@ TEST(CSeqNo, seqlen) { EXPECT_EQ(CSeqNo::seqlen(125, 125), 1); EXPECT_EQ(CSeqNo::seqlen(125, 126), 2); + + EXPECT_EQ(CSeqNo::seqlen(2147483647, 0), 2); + EXPECT_EQ(CSeqNo::seqlen(0, 2147483647), -2147483648); } TEST(CUDT, getFlightSpan) @@ -74,7 +75,6 @@ TEST(CSeqNo, incseq) EXPECT_EQ(CSeqNo::incseq(0x3FFFFFFF), 0x40000000); } - TEST(CSeqNo, decseq) { // decseq: decrease the seq# by 1 @@ -84,7 +84,6 @@ TEST(CSeqNo, decseq) EXPECT_EQ(CSeqNo::decseq(0x40000000), 0x3FFFFFFF); } - TEST(CSeqNo, incseqint) { // incseq: increase the seq# by 1 @@ -98,7 +97,6 @@ TEST(CSeqNo, incseqint) EXPECT_EQ(CSeqNo::incseq(0x3FFFFFFF, 0x40000001), 0x00000000); } - TEST(CSeqNo, decseqint) { // decseq: decrease the seq# by 1 @@ -107,4 +105,3 @@ TEST(CSeqNo, decseqint) EXPECT_EQ(CSeqNo::decseq(0, 1), 0x7FFFFFFF); EXPECT_EQ(CSeqNo::decseq(0x40000000, 1), 0x3FFFFFFF); } - From 1a2aa05c159e72bf2530a7f25cb7a7d6891272df Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 21 Sep 2021 16:09:45 +0200 Subject: [PATCH 105/124] [apps] Print SRT version and clock type --- apps/apputil.cpp | 33 +++++++++++++++++++++++++++++++++ apps/apputil.hpp | 3 +++ apps/srt-file-transmit.cpp | 10 ++-------- apps/srt-live-transmit.cpp | 10 ++-------- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/apps/apputil.cpp b/apps/apputil.cpp index 611b99976..1389b748e 100644 --- a/apps/apputil.cpp +++ b/apps/apputil.cpp @@ -684,3 +684,36 @@ SrtStatsPrintFormat ParsePrintFormat(string pf, string& w_extras) return SRTSTATS_PROFMAT_INVALID; } + +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; +} diff --git a/apps/apputil.hpp b/apps/apputil.hpp index 5bac461e0..782412815 100644 --- a/apps/apputil.hpp +++ b/apps/apputil.hpp @@ -419,5 +419,8 @@ extern std::vector> g_SrtStatsTable; std::shared_ptr SrtStatsWriterFactory(SrtStatsPrintFormat printformat); +const char* SRTClockTypeStr(); +void PrintLibVersion(); + #endif // INC_SRT_APPCOMMON_H diff --git a/apps/srt-file-transmit.cpp b/apps/srt-file-transmit.cpp index d3ea92092..327ad6809 100644 --- a/apps/srt-file-transmit.cpp +++ b/apps/srt-file-transmit.cpp @@ -52,7 +52,6 @@ void OnINT_ForceExit(int) interrupt = true; } - struct FileTransmitConfig { unsigned long chunk_size; @@ -144,12 +143,7 @@ int parse_args(FileTransmitConfig &cfg, int argc, char** argv) if (print_help) { cout << "SRT sample application to transmit files.\n"; - 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 << endl; + PrintLibVersion(); cerr << "Usage: srt-file-transmit [options] \n"; cerr << "\n"; @@ -182,7 +176,7 @@ int parse_args(FileTransmitConfig &cfg, int argc, char** argv) if (Option(params, false, o_version)) { - cerr << "SRT Library version: " << SRT_VERSION << endl; + PrintLibVersion(); return 2; } diff --git a/apps/srt-live-transmit.cpp b/apps/srt-live-transmit.cpp index 9aad3209c..6d5ee18de 100644 --- a/apps/srt-live-transmit.cpp +++ b/apps/srt-live-transmit.cpp @@ -164,7 +164,6 @@ void PrintOptionHelp(const OptionName& opt_names, const string &value, const str cerr << "\t- " << desc << "\n"; } - int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) { const OptionName @@ -269,12 +268,7 @@ int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) } cout << "SRT sample application to transmit live streaming.\n"; - 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 << endl; + PrintLibVersion(); cerr << "Usage: srt-live-transmit [options] \n"; cerr << "\n"; #ifndef _WIN32 @@ -313,7 +307,7 @@ int parse_args(LiveTransmitConfig &cfg, int argc, char** argv) if (print_version) { - cerr << "SRT Library version: " << SRT_VERSION << endl; + PrintLibVersion(); return 2; } From 0c604c1ec51f8c4ed7918d664abf5dad7a0126bf Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Fri, 10 Sep 2021 15:56:16 +0200 Subject: [PATCH 106/124] [core] Moved SND and RCV buffers into the 'srt' namespace --- srtcore/buffer.cpp | 23 ++++++++++-------- srtcore/buffer.h | 60 ++++++++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/srtcore/buffer.cpp b/srtcore/buffer.cpp index c035ad936..329b054a0 100644 --- a/srtcore/buffer.cpp +++ b/srtcore/buffer.cpp @@ -59,10 +59,11 @@ modified by #include "core.h" // provides some constants #include "logging.h" +namespace srt { + using namespace std; using namespace srt_logging; -using namespace srt; -using namespace srt::sync; +using namespace sync; // You can change this value at build config by using "ENFORCE" options. #if !defined(SRT_MAVG_SAMPLING_RATE) @@ -318,7 +319,7 @@ void CSndBuffer::updateInputRate(const steady_clock::time_point& time, int pkts, if (early_update || period_us > m_InRatePeriod) { // Required Byte/sec rate (payload + headers) - m_iInRateBytesCount += (m_iInRatePktsCount * srt::CPacket::SRT_DATA_HDR_SIZE); + m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE); m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us); HLOGC(bslog.Debug, log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount @@ -411,7 +412,7 @@ steady_clock::time_point CSndBuffer::getSourceTime(const CSndBuffer::Block& bloc return block.m_tsOriginTime; } -int CSndBuffer::readData(srt::CPacket& w_packet, steady_clock::time_point& w_srctime, int kflgs) +int CSndBuffer::readData(CPacket& w_packet, steady_clock::time_point& w_srctime, int kflgs) { // No data to read if (m_pCurrBlock == m_pLastBlock) @@ -512,7 +513,7 @@ int32_t CSndBuffer::getMsgNoAt(const int offset) return p->getMsgSeq(); } -int CSndBuffer::readData(const int offset, srt::CPacket& w_packet, steady_clock::time_point& w_srctime, int& w_msglen) +int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time_point& w_srctime, int& w_msglen) { int32_t& msgno_bitset = w_packet.m_iMsgNo; @@ -605,7 +606,7 @@ int CSndBuffer::readData(const int offset, srt::CPacket& w_packet, steady_clock: return readlen; } -srt::sync::steady_clock::time_point CSndBuffer::getPacketRexmitTime(const int offset) +sync::steady_clock::time_point CSndBuffer::getPacketRexmitTime(const int offset) { ScopedLock bufferguard(m_BufLock); const Block* p = m_pFirstBlock; @@ -935,7 +936,7 @@ int CRcvBuffer::readBuffer(char* data, int len) return -1; } - const srt::CPacket& pkt = m_pUnit[p]->m_Packet; + const CPacket& pkt = m_pUnit[p]->m_Packet; if (bTsbPdEnabled) { @@ -1004,7 +1005,7 @@ int CRcvBuffer::readBufferToFile(fstream& ofs, int len) continue; } - const srt::CPacket& pkt = m_pUnit[p]->m_Packet; + const CPacket& pkt = m_pUnit[p]->m_Packet; #if ENABLE_LOGGING trace_seq = pkt.getSeqNo(); @@ -1476,7 +1477,7 @@ bool CRcvBuffer::isRcvDataReady(steady_clock::time_point& w_tsbpdtime, int32_t& if (m_tsbpd.isEnabled()) { - const srt::CPacket* pkt = getRcvReadyPacket(seqdistance); + const CPacket* pkt = getRcvReadyPacket(seqdistance); if (!pkt) { HLOGC(brlog.Debug, log << "isRcvDataReady: packet NOT extracted."); @@ -1613,7 +1614,7 @@ void CRcvBuffer::reportBufferStats() const uint64_t lower_time = low_ts; if (lower_time > upper_time) - upper_time += uint64_t(srt::CPacket::MAX_TIMESTAMP) + 1; + upper_time += uint64_t(CPacket::MAX_TIMESTAMP) + 1; int32_t timespan = upper_time - lower_time; int seqspan = 0; @@ -2287,3 +2288,5 @@ bool CRcvBuffer::scanMsg(int& w_p, int& w_q, bool& w_passack) return found; } + +} // namespace srt diff --git a/srtcore/buffer.h b/srtcore/buffer.h index 2dc63d972..8756a49d1 100644 --- a/srtcore/buffer.h +++ b/srtcore/buffer.h @@ -71,10 +71,12 @@ modified by // a +% b : shift a by b // a == b : equality is same as for just numbers +namespace srt { + /// The AvgBufSize class is used to calculate moving average of the buffer (RCV or SND) class AvgBufSize { - typedef srt::sync::steady_clock::time_point time_point; + typedef sync::steady_clock::time_point time_point; public: AvgBufSize() @@ -102,8 +104,8 @@ class AvgBufSize class CSndBuffer { - typedef srt::sync::steady_clock::time_point time_point; - typedef srt::sync::steady_clock::duration duration; + typedef sync::steady_clock::time_point time_point; + typedef sync::steady_clock::duration duration; public: // XXX There's currently no way to access the socket ID set for @@ -140,21 +142,19 @@ class CSndBuffer int addBufferFromFile(std::fstream& ifs, int len); /// Find data position to pack a DATA packet from the furthest reading point. - /// @param [out] data the pointer to the data position. - /// @param [out] msgno message number of the packet. - /// @param [out] origintime origin time stamp of the message - /// @param [in] kflags Odd|Even crypto key flag + /// @param [out] w_packet data packet buffer to fill. + /// @param [out] w_origintime origin time stamp of the message. + /// @param [in] kflags Odd|Even crypto key flag. /// @return Actual length of data read. - int readData(srt::CPacket& w_packet, time_point& w_origintime, int kflgs); + int readData(CPacket& w_packet, time_point& w_origintime, int kflgs); /// Find data position to pack a DATA packet for a retransmission. - /// @param [out] data the pointer to the data position. /// @param [in] offset offset from the last ACK point (backward sequence number difference) - /// @param [out] msgno message number of the packet. - /// @param [out] origintime origin time stamp of the message - /// @param [out] msglen length of the message + /// @param [out] w_packet data packet buffer to fill. + /// @param [out] w_origintime origin time stamp of the message + /// @param [out] w_msglen length of the message /// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded). - int readData(const int offset, srt::CPacket& w_packet, time_point& w_origintime, int& w_msglen); + int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen); /// Get the time of the last retransmission (if any) of the DATA packet. /// @param [in] offset offset from the last ACK point (backward sequence number difference) @@ -207,7 +207,7 @@ class CSndBuffer static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE; private: - srt::sync::Mutex m_BufLock; // used to synchronize buffer operation + sync::Mutex m_BufLock; // used to synchronize buffer operation struct Block { @@ -274,8 +274,8 @@ class CSndBuffer class CRcvBuffer { - typedef srt::sync::steady_clock::time_point time_point; - typedef srt::sync::steady_clock::duration duration; + typedef sync::steady_clock::time_point time_point; + typedef sync::steady_clock::duration duration; public: // XXX There's currently no way to access the socket ID set for @@ -288,7 +288,7 @@ class CRcvBuffer /// Construct the buffer. /// @param [in] queue CUnitQueue that actually holds the units (packets) /// @param [in] bufsize_pkts in units (packets) - CRcvBuffer(srt::CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE); + CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE); ~CRcvBuffer(); public: @@ -296,7 +296,7 @@ class CRcvBuffer /// @param [in] unit pointer to a data unit containing new packet /// @param [in] offset offset from last ACK point. /// @return 0 is success, -1 if data is repeated. - int addData(srt::CUnit* unit, int offset); + int addData(CUnit* unit, int offset); /// Read data into a user buffer. /// @param [in] data pointer to user buffer. @@ -402,7 +402,7 @@ class CRcvBuffer bool isRcvDataReady(); bool isRcvDataAvailable() { return m_iLastAckPos != m_iStartPos; } - srt::CPacket* getRcvReadyPacket(int32_t seqdistance); + CPacket* getRcvReadyPacket(int32_t seqdistance); /// Set TimeStamp-Based Packet Delivery Rx Mode /// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay @@ -464,7 +464,7 @@ class CRcvBuffer /// data. size_t freeUnitAt(size_t p) { - srt::CUnit* u = m_pUnit[p]; + CUnit* u = m_pUnit[p]; m_pUnit[p] = NULL; size_t rmbytes = u->m_Packet.getLength(); m_pUnitQueue->makeUnitFree(u); @@ -531,9 +531,9 @@ class CRcvBuffer } private: - srt::CUnit** m_pUnit; // Array of pointed units collected in the buffer + CUnit** m_pUnit; // Array of pointed units collected in the buffer const int m_iSize; // Size of the internal array of CUnit* items - srt::CUnitQueue* m_pUnitQueue; // the shared unit queue + CUnitQueue* m_pUnitQueue; // the shared unit queue int m_iStartPos; // HEAD: first packet available for reading int m_iLastAckPos; // the last ACKed position (exclusive), follows the last readable @@ -546,15 +546,15 @@ class CRcvBuffer // up to which data are already retrieved; // in message reading mode it's unused and always 0) - srt::sync::Mutex m_BytesCountLock; // used to protect counters operations - int m_iBytesCount; // Number of payload bytes in the buffer - int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer - int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer - unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation + sync::Mutex m_BytesCountLock; // used to protect counters operations + int m_iBytesCount; // Number of payload bytes in the buffer + int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer + int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer + unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation - srt::CTsbpdTime m_tsbpd; + CTsbpdTime m_tsbpd; - AvgBufSize m_mavg; + AvgBufSize m_mavg; private: CRcvBuffer(); @@ -562,4 +562,6 @@ class CRcvBuffer CRcvBuffer& operator=(const CRcvBuffer&); }; +} // namespace srt + #endif From 5b0811ca33cecb9cc2d1088ca6158277c599b317 Mon Sep 17 00:00:00 2001 From: quink-black Date: Mon, 4 Oct 2021 21:01:55 +0800 Subject: [PATCH 107/124] [core] Replaced global CUDTUnited with static local variable (#1913) A static local variable has the benefits of lazy initialization and avoids the initialization order problem of global variables. --- srtcore/api.cpp | 132 ++++++++++++++-------------- srtcore/core.cpp | 147 ++++++++++++++++++------------- srtcore/core.h | 5 +- srtcore/group.cpp | 162 +++++++++++++++++------------------ srtcore/group.h | 4 +- srtcore/queue.cpp | 2 +- test/test_fec_rebuilding.cpp | 4 +- 7 files changed, 241 insertions(+), 215 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 71386a566..38b86cf8c 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -846,7 +846,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen, const sockaddr_any& p // static forwarder int srt::CUDT::installAcceptHook(SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) { - return s_UDTUnited.installAcceptHook(lsn, hook, opaq); + return uglobal().installAcceptHook(lsn, hook, opaq); } int srt::CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq) @@ -867,7 +867,7 @@ int srt::CUDTUnited::installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_ int srt::CUDT::installConnectHook(SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq) { - return s_UDTUnited.installConnectHook(lsn, hook, opaq); + return uglobal().installConnectHook(lsn, hook, opaq); } int srt::CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_fn* hook, void* opaq) @@ -3210,22 +3210,22 @@ void* srt::CUDTUnited::garbageCollect(void* p) int srt::CUDT::startup() { - return s_UDTUnited.startup(); + return uglobal().startup(); } int srt::CUDT::cleanup() { - return s_UDTUnited.cleanup(); + return uglobal().cleanup(); } SRTSOCKET srt::CUDT::socket() { - if (!s_UDTUnited.m_bGCStatus) - s_UDTUnited.startup(); + if (!uglobal().m_bGCStatus) + uglobal().startup(); try { - return s_UDTUnited.newSocket(); + return uglobal().newSocket(); } catch (const CUDTException& e) { @@ -3264,21 +3264,21 @@ srt::CUDT::APIError::APIError(CodeMajor mj, CodeMinor mn, int syserr) // [[using locked(s_UDTUnited.m_GlobControlLock)]] srt::CUDTGroup& srt::CUDT::newGroup(const int type) { - const SRTSOCKET id = s_UDTUnited.generateSocketID(true); + const SRTSOCKET id = uglobal().generateSocketID(true); // Now map the group - return s_UDTUnited.addGroup(id, SRT_GROUP_TYPE(type)).set_id(id); + return uglobal().addGroup(id, SRT_GROUP_TYPE(type)).set_id(id); } SRTSOCKET srt::CUDT::createGroup(SRT_GROUP_TYPE gt) { // Doing the same lazy-startup as with srt_create_socket() - if (!s_UDTUnited.m_bGCStatus) - s_UDTUnited.startup(); + if (!uglobal().m_bGCStatus) + uglobal().startup(); try { - srt::sync::ScopedLock globlock (s_UDTUnited.m_GlobControlLock); + srt::sync::ScopedLock globlock (uglobal().m_GlobControlLock); return newGroup(gt).id(); // Note: potentially, after this function exits, the group // could be deleted, immediately, from a separate thread (tho @@ -3309,8 +3309,8 @@ int srt::CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) return APIError(MJ_NOTSUP, MN_INVAL, 0); // Find the socket and the group - CUDTSocket* s = s_UDTUnited.locateSocket(socket); - CUDTUnited::GroupKeeper k (s_UDTUnited, group, s_UDTUnited.ERH_RETURN); + CUDTSocket* s = uglobal().locateSocket(socket); + CUDTUnited::GroupKeeper k (uglobal(), group, CUDTUnited::ERH_RETURN); if (!s || !k.group) return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3331,7 +3331,7 @@ int srt::CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) } ScopedLock cg (s->m_ControlLock); - ScopedLock cglob (s_UDTUnited.m_GlobControlLock); + ScopedLock cglob (uglobal().m_GlobControlLock); if (g->closing()) return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3355,7 +3355,7 @@ int srt::CUDT::addSocketToGroup(SRTSOCKET socket, SRTSOCKET group) // groups. int srt::CUDT::removeSocketFromGroup(SRTSOCKET socket) { - CUDTSocket* s = s_UDTUnited.locateSocket(socket); + CUDTSocket* s = uglobal().locateSocket(socket); if (!s) return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3363,7 +3363,7 @@ int srt::CUDT::removeSocketFromGroup(SRTSOCKET socket) return APIError(MJ_NOTSUP, MN_INVAL, 0); ScopedLock cg (s->m_ControlLock); - ScopedLock glob_grd (s_UDTUnited.m_GlobControlLock); + ScopedLock glob_grd (uglobal().m_GlobControlLock); s->removeFromGroup(false); return 0; } @@ -3403,8 +3403,8 @@ SRTSOCKET srt::CUDT::getGroupOfSocket(SRTSOCKET socket) { // Lock this for the whole function as we need the group // to persist the call. - ScopedLock glock (s_UDTUnited.m_GlobControlLock); - CUDTSocket* s = s_UDTUnited.locateSocket_LOCKED(socket); + ScopedLock glock (uglobal().m_GlobControlLock); + CUDTSocket* s = uglobal().locateSocket_LOCKED(socket); if (!s || !s->m_GroupOf) return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3418,7 +3418,7 @@ int srt::CUDT::configureGroup(SRTSOCKET groupid, const char* str) return APIError(MJ_NOTSUP, MN_INVAL, 0); } - CUDTUnited::GroupKeeper k (s_UDTUnited, groupid, s_UDTUnited.ERH_RETURN); + CUDTUnited::GroupKeeper k (uglobal(), groupid, CUDTUnited::ERH_RETURN); if (!k.group) { return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3434,7 +3434,7 @@ int srt::CUDT::getGroupData(SRTSOCKET groupid, SRT_SOCKGROUPDATA* pdata, size_t* return APIError(MJ_NOTSUP, MN_INVAL, 0); } - CUDTUnited::GroupKeeper k (s_UDTUnited, groupid, s_UDTUnited.ERH_RETURN); + CUDTUnited::GroupKeeper k (uglobal(), groupid, CUDTUnited::ERH_RETURN); if (!k.group) { return APIError(MJ_NOTSUP, MN_INVAL, 0); @@ -3458,11 +3458,11 @@ int srt::CUDT::bind(SRTSOCKET u, const sockaddr* name, int namelen) // This is a user error. return APIError(MJ_NOTSUP, MN_INVAL, 0); } - CUDTSocket* s = s_UDTUnited.locateSocket(u); + CUDTSocket* s = uglobal().locateSocket(u); if (!s) return APIError(MJ_NOTSUP, MN_INVAL, 0); - return s_UDTUnited.bind(s, sa); + return uglobal().bind(s, sa); } catch (const CUDTException& e) { @@ -3485,11 +3485,11 @@ int srt::CUDT::bind(SRTSOCKET u, UDPSOCKET udpsock) { try { - CUDTSocket* s = s_UDTUnited.locateSocket(u); + CUDTSocket* s = uglobal().locateSocket(u); if (!s) return APIError(MJ_NOTSUP, MN_INVAL, 0); - return s_UDTUnited.bind(s, udpsock); + return uglobal().bind(s, udpsock); } catch (const CUDTException& e) { @@ -3511,7 +3511,7 @@ int srt::CUDT::listen(SRTSOCKET u, int backlog) { try { - return s_UDTUnited.listen(u, backlog); + return uglobal().listen(u, backlog); } catch (const CUDTException& e) { @@ -3533,7 +3533,7 @@ SRTSOCKET srt::CUDT::accept_bond(const SRTSOCKET listeners [], int lsize, int64_ { try { - return s_UDTUnited.accept_bond(listeners, lsize, msTimeOut); + return uglobal().accept_bond(listeners, lsize, msTimeOut); } catch (const CUDTException& e) { @@ -3558,7 +3558,7 @@ SRTSOCKET srt::CUDT::accept(SRTSOCKET u, sockaddr* addr, int* addrlen) { try { - return s_UDTUnited.accept(u, addr, addrlen); + return uglobal().accept(u, addr, addrlen); } catch (const CUDTException& e) { @@ -3584,7 +3584,7 @@ int srt::CUDT::connect( { try { - return s_UDTUnited.connect(u, name, tname, namelen); + return uglobal().connect(u, name, tname, namelen); } catch (const CUDTException& e) { @@ -3617,8 +3617,8 @@ int srt::CUDT::connectLinks(SRTSOCKET grp, try { - CUDTUnited::GroupKeeper k(s_UDTUnited, grp, s_UDTUnited.ERH_THROW); - return s_UDTUnited.groupConnect(k.group, targets, arraysize); + CUDTUnited::GroupKeeper k(uglobal(), grp, CUDTUnited::ERH_THROW); + return uglobal().groupConnect(k.group, targets, arraysize); } catch (CUDTException& e) { @@ -3642,7 +3642,7 @@ int srt::CUDT::connect( { try { - return s_UDTUnited.connect(u, name, namelen, forced_isn); + return uglobal().connect(u, name, namelen, forced_isn); } catch (const CUDTException &e) { @@ -3664,7 +3664,7 @@ int srt::CUDT::close(SRTSOCKET u) { try { - return s_UDTUnited.close(u); + return uglobal().close(u); } catch (const CUDTException& e) { @@ -3682,7 +3682,7 @@ int srt::CUDT::getpeername(SRTSOCKET u, sockaddr* name, int* namelen) { try { - s_UDTUnited.getpeername(u, name, namelen); + uglobal().getpeername(u, name, namelen); return 0; } catch (const CUDTException& e) @@ -3701,7 +3701,7 @@ int srt::CUDT::getsockname(SRTSOCKET u, sockaddr* name, int* namelen) { try { - s_UDTUnited.getsockname(u, name, namelen); + uglobal().getsockname(u, name, namelen); return 0; } catch (const CUDTException& e) @@ -3729,13 +3729,13 @@ int srt::CUDT::getsockopt( #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) { - CUDTUnited::GroupKeeper k(s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k(uglobal(), u, CUDTUnited::ERH_THROW); k.group->getOpt(optname, (pw_optval), (*pw_optlen)); return 0; } #endif - CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + CUDT& udt = uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core(); udt.getOpt(optname, (pw_optval), (*pw_optlen)); return 0; } @@ -3761,13 +3761,13 @@ int srt::CUDT::setsockopt(SRTSOCKET u, int, SRT_SOCKOPT optname, const void* opt #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) { - CUDTUnited::GroupKeeper k(s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k(uglobal(), u, CUDTUnited::ERH_THROW); k.group->setOpt(optname, optval, optlen); return 0; } #endif - CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + CUDT& udt = uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core(); udt.setOpt(optname, optval, optlen); return 0; } @@ -3810,12 +3810,12 @@ int srt::CUDT::sendmsg2( #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) { - CUDTUnited::GroupKeeper k (s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k (uglobal(), u, CUDTUnited::ERH_THROW); return k.group->send(buf, len, (w_m)); } #endif - return s_UDTUnited.locateSocket(u, CUDTUnited::ERH_THROW)->core().sendmsg2(buf, len, (w_m)); + return uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core().sendmsg2(buf, len, (w_m)); } catch (const CUDTException& e) { @@ -3855,12 +3855,12 @@ int srt::CUDT::recvmsg2(SRTSOCKET u, char* buf, int len, SRT_MSGCTRL& w_m) #if ENABLE_EXPERIMENTAL_BONDING if (u & SRTGROUP_MASK) { - CUDTUnited::GroupKeeper k(s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k(uglobal(), u, CUDTUnited::ERH_THROW); return k.group->recv(buf, len, (w_m)); } #endif - return s_UDTUnited.locateSocket(u, CUDTUnited::ERH_THROW)->core().recvmsg2(buf, len, (w_m)); + return uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core().recvmsg2(buf, len, (w_m)); } catch (const CUDTException& e) { @@ -3879,7 +3879,7 @@ int64_t srt::CUDT::sendfile( { try { - CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + CUDT& udt = uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core(); return udt.sendfile(ifs, offset, size, block); } catch (const CUDTException& e) @@ -3903,7 +3903,7 @@ int64_t srt::CUDT::recvfile( { try { - return s_UDTUnited.locateSocket(u, CUDTUnited::ERH_THROW)->core().recvfile(ofs, offset, size, block); + return uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core().recvfile(ofs, offset, size, block); } catch (const CUDTException& e) { @@ -3931,7 +3931,7 @@ int srt::CUDT::select( try { - return s_UDTUnited.select(readfds, writefds, exceptfds, timeout); + return uglobal().select(readfds, writefds, exceptfds, timeout); } catch (const CUDTException& e) { @@ -3963,7 +3963,7 @@ int srt::CUDT::selectEx( try { - return s_UDTUnited.selectEx(fds, readfds, writefds, exceptfds, msTimeOut); + return uglobal().selectEx(fds, readfds, writefds, exceptfds, msTimeOut); } catch (const CUDTException& e) { @@ -3985,7 +3985,7 @@ int srt::CUDT::epoll_create() { try { - return s_UDTUnited.epoll_create(); + return uglobal().epoll_create(); } catch (const CUDTException& e) { @@ -4003,7 +4003,7 @@ int srt::CUDT::epoll_clear_usocks(int eid) { try { - return s_UDTUnited.epoll_clear_usocks(eid); + return uglobal().epoll_clear_usocks(eid); } catch (const CUDTException& e) { @@ -4021,7 +4021,7 @@ int srt::CUDT::epoll_add_usock(const int eid, const SRTSOCKET u, const int* even { try { - return s_UDTUnited.epoll_add_usock(eid, u, events); + return uglobal().epoll_add_usock(eid, u, events); } catch (const CUDTException& e) { @@ -4039,7 +4039,7 @@ int srt::CUDT::epoll_add_ssock(const int eid, const SYSSOCKET s, const int* even { try { - return s_UDTUnited.epoll_add_ssock(eid, s, events); + return uglobal().epoll_add_ssock(eid, s, events); } catch (const CUDTException& e) { @@ -4058,7 +4058,7 @@ int srt::CUDT::epoll_update_usock( { try { - return s_UDTUnited.epoll_add_usock(eid, u, events); + return uglobal().epoll_add_usock(eid, u, events); } catch (const CUDTException& e) { @@ -4077,7 +4077,7 @@ int srt::CUDT::epoll_update_ssock( { try { - return s_UDTUnited.epoll_update_ssock(eid, s, events); + return uglobal().epoll_update_ssock(eid, s, events); } catch (const CUDTException& e) { @@ -4096,7 +4096,7 @@ int srt::CUDT::epoll_remove_usock(const int eid, const SRTSOCKET u) { try { - return s_UDTUnited.epoll_remove_usock(eid, u); + return uglobal().epoll_remove_usock(eid, u); } catch (const CUDTException& e) { @@ -4114,7 +4114,7 @@ int srt::CUDT::epoll_remove_ssock(const int eid, const SYSSOCKET s) { try { - return s_UDTUnited.epoll_remove_ssock(eid, s); + return uglobal().epoll_remove_ssock(eid, s); } catch (const CUDTException& e) { @@ -4138,7 +4138,7 @@ int srt::CUDT::epoll_wait( { try { - return s_UDTUnited.epoll_ref().wait( + return uglobal().epoll_ref().wait( eid, readfds, writefds, msTimeOut, lrfds, lwfds); } catch (const CUDTException& e) @@ -4161,7 +4161,7 @@ int srt::CUDT::epoll_uwait( { try { - return s_UDTUnited.epoll_uwait(eid, fdsSet, fdsSize, msTimeOut); + return uglobal().epoll_uwait(eid, fdsSet, fdsSize, msTimeOut); } catch (const CUDTException& e) { @@ -4181,7 +4181,7 @@ int32_t srt::CUDT::epoll_set( { try { - return s_UDTUnited.epoll_set(eid, flags); + return uglobal().epoll_set(eid, flags); } catch (const CUDTException& e) { @@ -4199,7 +4199,7 @@ int srt::CUDT::epoll_release(const int eid) { try { - return s_UDTUnited.epoll_release(eid); + return uglobal().epoll_release(eid); } catch (const CUDTException& e) { @@ -4227,7 +4227,7 @@ int srt::CUDT::bstats(SRTSOCKET u, CBytePerfMon* perf, bool clear, bool instanta try { - CUDT& udt = s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + CUDT& udt = uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core(); udt.bstats(perf, clear, instantaneous); return 0; } @@ -4248,7 +4248,7 @@ int srt::CUDT::groupsockbstats(SRTSOCKET u, CBytePerfMon* perf, bool clear) { try { - CUDTUnited::GroupKeeper k(s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k(uglobal(), u, CUDTUnited::ERH_THROW); k.group->bstatsSocket(perf, clear); return 0; } @@ -4271,7 +4271,7 @@ srt::CUDT* srt::CUDT::getUDTHandle(SRTSOCKET u) { try { - return &s_UDTUnited.locateSocket(u, s_UDTUnited.ERH_THROW)->core(); + return &uglobal().locateSocket(u, CUDTUnited::ERH_THROW)->core(); } catch (const CUDTException& e) { @@ -4290,8 +4290,8 @@ srt::CUDT* srt::CUDT::getUDTHandle(SRTSOCKET u) vector srt::CUDT::existingSockets() { vector out; - for (CUDTUnited::sockets_t::iterator i = s_UDTUnited.m_Sockets.begin(); - i != s_UDTUnited.m_Sockets.end(); ++i) + for (CUDTUnited::sockets_t::iterator i = uglobal().m_Sockets.begin(); + i != uglobal().m_Sockets.end(); ++i) { out.push_back(i->first); } @@ -4305,11 +4305,11 @@ SRT_SOCKSTATUS srt::CUDT::getsockstate(SRTSOCKET u) #if ENABLE_EXPERIMENTAL_BONDING if (isgroup(u)) { - CUDTUnited::GroupKeeper k(s_UDTUnited, u, s_UDTUnited.ERH_THROW); + CUDTUnited::GroupKeeper k(uglobal(), u, CUDTUnited::ERH_THROW); return k.group->getStatus(); } #endif - return s_UDTUnited.getStatus(u); + return uglobal().getStatus(u); } catch (const CUDTException& e) { diff --git a/srtcore/core.cpp b/srtcore/core.cpp index ab1e7da9d..53e4a28d5 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -70,6 +70,11 @@ modified by #include "logging_api.h" // Required due to containing extern srt_logger_config #include "logger_defs.h" +#if !HAVE_CXX11 +// for pthread_once +#include +#endif + // Again, just in case when some "smart guy" provided such a global macro #ifdef min #undef min @@ -83,10 +88,6 @@ using namespace srt; using namespace srt::sync; using namespace srt_logging; -namespace srt { - CUDTUnited CUDT::s_UDTUnited; -} - const SRTSOCKET UDT::INVALID_SOCK = srt::CUDT::INVALID_SOCK; const int UDT::ERROR = srt::CUDT::ERROR; @@ -222,6 +223,32 @@ const SrtOptionAction s_sockopt_action; } // namespace srt +#if HAVE_CXX11 + +CUDTUnited& srt::CUDT::uglobal() +{ + static CUDTUnited instance; + return instance; +} + +#else // !HAVE_CXX11 + +static pthread_once_t s_UDTUnitedOnce = PTHREAD_ONCE_INIT; + +static CUDTUnited *getInstance() +{ + static CUDTUnited instance; + return &instance; +} + +CUDTUnited& srt::CUDT::uglobal() +{ + // We don't want lock each time, pthread_once can be faster than mutex. + pthread_once(&s_UDTUnitedOnce, reinterpret_cast(getInstance)); + return *getInstance(); +} + +#endif void srt::CUDT::construct() { @@ -512,7 +539,7 @@ void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) break; case SRTO_STATE: - *(int32_t *)optval = s_UDTUnited.getStatus(m_SocketID); + *(int32_t *)optval = uglobal().getStatus(m_SocketID); optlen = sizeof(int32_t); break; @@ -1692,7 +1719,7 @@ bool srt::CUDT::createSrtHandshake( if (have_group) { // NOTE: See information about mutex ordering in api.h - ScopedLock gdrg (s_UDTUnited.m_GlobControlLock); + ScopedLock gdrg (uglobal().m_GlobControlLock); if (!m_parent->m_GroupOf) { // This may only happen if since last check of m_GroupOf pointer the socket was removed @@ -3039,7 +3066,7 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A return false; } - ScopedLock guard_group_existence (s_UDTUnited.m_GlobControlLock); + ScopedLock guard_group_existence (uglobal().m_GlobControlLock); if (m_SrtHsSide == HSD_INITIATOR) { @@ -3161,7 +3188,7 @@ SRTSOCKET srt::CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint3 // it right now so there's no need to lock s->m_ControlLock. // Check if there exists a group that this one is a peer of. - CUDTGroup* gp = s_UDTUnited.findPeerGroup_LOCKED(peergroup); + CUDTGroup* gp = uglobal().findPeerGroup_LOCKED(peergroup); bool was_empty = true; if (gp) { @@ -3192,7 +3219,7 @@ SRTSOCKET srt::CUDT::makeMePeerOf(SRTSOCKET peergroup, SRT_GROUP_TYPE gtp, uint3 if (!gp->applyFlags(link_flags, m_SrtHsSide)) { // Wrong settings. Must reject. Delete group. - s_UDTUnited.deleteGroup_LOCKED(gp); + uglobal().deleteGroup_LOCKED(gp); return -1; } @@ -4569,7 +4596,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, { #if ENABLE_EXPERIMENTAL_BONDING - ScopedLock cl (s_UDTUnited.m_GlobControlLock); + ScopedLock cl (uglobal().m_GlobControlLock); CUDTGroup* g = m_parent->m_GroupOf; if (g) { @@ -4619,7 +4646,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, // the socket could have been started removal before this function // has started. Do a sanity check before you continue with the // connection process. - CUDTSocket* s = s_UDTUnited.locateSocket(m_SocketID); + CUDTSocket* s = uglobal().locateSocket(m_SocketID); if (s) { // The socket could be closed at this very moment. @@ -4676,7 +4703,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, //int token = -1; #if ENABLE_EXPERIMENTAL_BONDING { - ScopedLock cl (s_UDTUnited.m_GlobControlLock); + ScopedLock cl (uglobal().m_GlobControlLock); CUDTGroup* g = m_parent->m_GroupOf; if (g) { @@ -4705,7 +4732,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous, s->m_Status = SRTS_CONNECTED; // acknowledde any waiting epolls to write - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_CONNECT, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_CONNECT, true); CGlobEvent::triggerEvent(); @@ -5150,7 +5177,7 @@ void * srt::CUDT::tsbpd(void *param) // which will ensure that the group will not be physically // deleted until this thread exits. // NOTE: DO NOT LEAD TO EVER CANCEL THE THREAD!!! - CUDTUnited::GroupKeeper gkeeper (self->s_UDTUnited, self->m_parent); + CUDTUnited::GroupKeeper gkeeper (self->uglobal(), self->m_parent); #endif UniqueLock recv_lock (self->m_RecvLock); @@ -5268,7 +5295,7 @@ void * srt::CUDT::tsbpd(void *param) /* * Set EPOLL_IN to wakeup any thread waiting on epoll */ - self->s_UDTUnited.m_EPoll.update_events(self->m_SocketID, self->m_sPollID, SRT_EPOLL_IN, true); + self->uglobal().m_EPoll.update_events(self->m_SocketID, self->m_sPollID, SRT_EPOLL_IN, true); #if ENABLE_EXPERIMENTAL_BONDING // If this is NULL, it means: // - the socket never was a group member @@ -5545,7 +5572,7 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any& { #if ENABLE_EXPERIMENTAL_BONDING - ScopedLock cl (s_UDTUnited.m_GlobControlLock); + ScopedLock cl (uglobal().m_GlobControlLock); CUDTGroup* g = m_parent->m_GroupOf; if (g) { @@ -5902,13 +5929,13 @@ bool srt::CUDT::closeInternal() // Make a copy under a lock because other thread might access it // at the same time. - enterCS(s_UDTUnited.m_EPoll.m_EPollLock); + enterCS(uglobal().m_EPoll.m_EPollLock); set epollid = m_sPollID; - leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); + leaveCS(uglobal().m_EPoll.m_EPollLock); // trigger any pending IO events. HLOGC(smlog.Debug, log << "close: SETTING ERR readiness on E" << Printable(epollid) << " of @" << m_SocketID); - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true); // then remove itself from all epoll monitoring int no_events = 0; for (set::iterator i = epollid.begin(); i != epollid.end(); ++i) @@ -5916,7 +5943,7 @@ bool srt::CUDT::closeInternal() HLOGC(smlog.Debug, log << "close: CLEARING subscription on E" << (*i) << " of @" << m_SocketID); try { - s_UDTUnited.m_EPoll.update_usock(*i, m_SocketID, &no_events); + uglobal().m_EPoll.update_usock(*i, m_SocketID, &no_events); } catch (...) { @@ -5933,9 +5960,9 @@ bool srt::CUDT::closeInternal() // IMPORTANT: there's theoretically little time between setting ERR readiness // and unsubscribing, however if there's an application waiting on this event, // it should be informed before this below instruction locks the epoll mutex. - enterCS(s_UDTUnited.m_EPoll.m_EPollLock); + enterCS(uglobal().m_EPoll.m_EPollLock); m_sPollID.clear(); - leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); + leaveCS(uglobal().m_EPoll.m_EPollLock); // XXX What's this, could any of the above actions make it !m_bOpened? if (!m_bOpened) @@ -6128,7 +6155,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) if (!m_pRcvBuffer->isRcvDataReady()) { // read is not available any more - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); } if ((res <= 0) && (m_config.iRcvTimeOut >= 0)) @@ -6515,7 +6542,7 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl) if (sndBuffersLeft() < 1) // XXX Not sure if it should test if any space in the buffer, or as requried. { // write is not available any more - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false); } } @@ -6638,7 +6665,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ if (!m_pRcvBuffer->isRcvDataReady()) { // read is not available any more - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); } if (res == 0) @@ -6679,7 +6706,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ } // Shut up EPoll if no more messages in non-blocking mode - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); // Forced to return 0 instead of throwing exception, in case of AGAIN/READ if (!by_exception) return 0; @@ -6700,7 +6727,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ } // Shut up EPoll if no more messages in non-blocking mode - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); // After signaling the tsbpd for ready data, report the bandwidth. #if ENABLE_HEAVY_LOGGING @@ -6819,7 +6846,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ } // Shut up EPoll if no more messages in non-blocking mode - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); } // Unblock when required @@ -6948,7 +6975,7 @@ int64_t srt::CUDT::sendfile(fstream &ifs, int64_t &offset, int64_t size, int blo if (sndBuffersLeft() <= 0) { // write is not available any more - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false); } } @@ -7074,7 +7101,7 @@ int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int blo if (!m_pRcvBuffer->isRcvDataReady()) { // read is not available any more - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); } return size - torecv; @@ -7745,7 +7772,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) // can be either never set, already reset, or ever set // and possibly dangling. The re-check after lock eliminates // the dangling case. - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); // Note that updateLatestRcv will lock m_GroupOf->m_GroupLock, // but this is an intended order. @@ -7797,13 +7824,13 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) // (4) receive thread: receive data and set SRT_EPOLL_IN to true // (5) user thread: set SRT_EPOLL_IN to false // 4. so , m_RecvLock must be used here to protect epoll event - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true); } #if ENABLE_EXPERIMENTAL_BONDING if (m_parent->m_GroupOf) { // See above explanation for double-checking - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { @@ -7953,7 +7980,7 @@ void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) m_pSndBuffer->ackData(offset); // acknowledde any waiting epolls to write - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); CGlobEvent::triggerEvent(); } @@ -7962,7 +7989,7 @@ void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno) { // m_RecvAckLock is ordered AFTER m_GlobControlLock, so this can only // be done now that m_RecvAckLock is unlocked. - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { HLOGC(inlog.Debug, log << "ACK: acking group sender buffer for #" << msgno_at_last_acked_seq); @@ -8111,7 +8138,7 @@ void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_ #if ENABLE_EXPERIMENTAL_BONDING if (m_parent->m_GroupOf) { - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { // Will apply m_GroupLock, ordered after m_GlobControlLock. @@ -8328,7 +8355,7 @@ void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr #if ENABLE_EXPERIMENTAL_BONDING if (drift_updated && m_parent->m_GroupOf) { - ScopedLock glock(s_UDTUnited.m_GlobControlLock); + ScopedLock glock(uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { m_parent->m_GroupOf->synchronizeDrift(this); @@ -8827,7 +8854,7 @@ void srt::CUDT::updateAfterSrtHandshake(int hsv) if (m_parent->m_GroupOf) { - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); grpspec = m_parent->m_GroupOf ? " group=$" + Sprint(m_parent->m_GroupOf->id()) : string(); @@ -9272,7 +9299,7 @@ void srt::CUDT::processClose() // Signal the sender and recver if they are waiting for data. releaseSynch(); // Unblock any call so they learn the connection_broken error - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_ERR, true); HLOGP(smlog.Debug, "processClose: triggering timer event to spread the bad news"); CGlobEvent::triggerEvent(); @@ -9547,7 +9574,7 @@ int srt::CUDT::processData(CUnit* in_unit) // reception sequence pointer stating that this link is not receiving. if (m_parent->m_GroupOf) { - ScopedLock protect_group_existence (s_UDTUnited.m_GlobControlLock); + ScopedLock protect_group_existence (uglobal().m_GlobControlLock); groups::SocketData* gi = m_parent->m_GroupMemberData; // This check is needed as after getting the lock the socket @@ -10563,7 +10590,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) { int error = SRT_REJ_UNKNOWN; CUDT* acpu = NULL; - int result = s_UDTUnited.newConnection(m_SocketID, addr, packet, (hs), (error), (acpu)); + int result = uglobal().newConnection(m_SocketID, addr, packet, (hs), (error), (acpu)); // This is listener - m_RejectReason need not be set // because listener has no functionality of giving the app @@ -10703,7 +10730,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet) // Note: not using SRT_EPOLL_CONNECT symbol because this is a procedure // executed for the accepted socket. - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); } } LOGC(cnlog.Note, log << "listen ret: " << hs.m_iReqType << " - " << RequestTypeStr(hs.m_iReqType)); @@ -11003,7 +11030,7 @@ void srt::CUDT::checkTimers() #if ENABLE_EXPERIMENTAL_BONDING if (m_parent->m_GroupOf) { - ScopedLock glock (s_UDTUnited.m_GlobControlLock); + ScopedLock glock (uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { // Pass socket ID because it's about changing group socket data @@ -11023,7 +11050,7 @@ void srt::CUDT::updateBrokenConnection() m_bClosing = true; releaseSynch(); // app can call any UDT API to learn the connection_broken error - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); CGlobEvent::triggerEvent(); } @@ -11034,7 +11061,7 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) #if ENABLE_EXPERIMENTAL_BONDING bool pending_broken = false; { - ScopedLock guard_group_existence (s_UDTUnited.m_GlobControlLock); + ScopedLock guard_group_existence (uglobal().m_GlobControlLock); if (m_parent->m_GroupOf) { token = m_parent->m_GroupMemberData->token; @@ -11066,7 +11093,7 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) // existence of the group will not be changed during // the operation. The attempt of group deletion will // have to wait until this operation completes. - ScopedLock lock(s_UDTUnited.m_GlobControlLock); + ScopedLock lock(uglobal().m_GlobControlLock); CUDTGroup* pg = m_parent->m_GroupOf; if (pg) { @@ -11079,8 +11106,8 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) // explicitly, otherwise they will never be deleted. if (pending_broken) { - // XXX This somehow can cause a deadlock, even without GlobControlLock - // s_UDTUnited.close(m_parent); + // XXX This somehow can cause a deadlock + // uglobal()->close(m_parent); m_parent->setBrokenClosed(); } #endif @@ -11088,9 +11115,9 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode) void srt::CUDT::addEPoll(const int eid) { - enterCS(s_UDTUnited.m_EPoll.m_EPollLock); + enterCS(uglobal().m_EPoll.m_EPollLock); m_sPollID.insert(eid); - leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); + leaveCS(uglobal().m_EPoll.m_EPollLock); if (!stillConnected()) return; @@ -11098,13 +11125,13 @@ void srt::CUDT::addEPoll(const int eid) enterCS(m_RecvLock); if (m_pRcvBuffer->isRcvDataReady()) { - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true); } leaveCS(m_RecvLock); if (m_config.iSndBufSize > m_pSndBuffer->getCurrBufSize()) { - s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); + uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, true); } } @@ -11114,14 +11141,14 @@ void srt::CUDT::removeEPollEvents(const int eid) // since this happens after the epoll ID has been removed, they cannot be set again set remove; remove.insert(eid); - s_UDTUnited.m_EPoll.update_events(m_SocketID, remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false); + uglobal().m_EPoll.update_events(m_SocketID, remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false); } void srt::CUDT::removeEPollID(const int eid) { - enterCS(s_UDTUnited.m_EPoll.m_EPollLock); + enterCS(uglobal().m_EPoll.m_EPollLock); m_sPollID.erase(eid); - leaveCS(s_UDTUnited.m_EPoll.m_EPollLock); + leaveCS(uglobal().m_EPoll.m_EPollLock); } void srt::CUDT::ConnectSignal(ETransmissionEvent evt, EventSlot sl) @@ -11150,7 +11177,7 @@ void srt::CUDT::EmitSignal(ETransmissionEvent tev, EventVariant var) int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) { - CUDTSocket *s = s_UDTUnited.locateSocket(u); + CUDTSocket *s = uglobal().locateSocket(u); if (!s) return -1; @@ -11173,7 +11200,7 @@ int srt::CUDT::getsndbuffer(SRTSOCKET u, size_t *blocks, size_t *bytes) int srt::CUDT::rejectReason(SRTSOCKET u) { - CUDTSocket* s = s_UDTUnited.locateSocket(u); + CUDTSocket* s = uglobal().locateSocket(u); if (!s) return SRT_REJ_UNKNOWN; @@ -11182,7 +11209,7 @@ int srt::CUDT::rejectReason(SRTSOCKET u) int srt::CUDT::rejectReason(SRTSOCKET u, int value) { - CUDTSocket* s = s_UDTUnited.locateSocket(u); + CUDTSocket* s = uglobal().locateSocket(u); if (!s) return APIError(MJ_NOTSUP, MN_SIDINVAL); @@ -11195,7 +11222,7 @@ int srt::CUDT::rejectReason(SRTSOCKET u, int value) int64_t srt::CUDT::socketStartTime(SRTSOCKET u) { - CUDTSocket* s = s_UDTUnited.locateSocket(u); + CUDTSocket* s = uglobal().locateSocket(u); if (!s) return APIError(MJ_NOTSUP, MN_SIDINVAL); @@ -11316,7 +11343,7 @@ void srt::CUDT::handleKeepalive(const char* /*data*/, size_t /*size*/) // existence of the group will not be changed during // the operation. The attempt of group deletion will // have to wait until this operation completes. - ScopedLock lock(s_UDTUnited.m_GlobControlLock); + ScopedLock lock(uglobal().m_GlobControlLock); CUDTGroup* pg = m_parent->m_GroupOf; if (pg) { diff --git a/srtcore/core.h b/srtcore/core.h index a9d2f9dc3..1fd5f6730 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -409,8 +409,8 @@ class CUDT return genRandomInt(0, CSeqNo::m_iMaxSeqNo); } - // For SRT_tsbpdLoop - static CUDTUnited* uglobal() { return &s_UDTUnited; } // needed by tsbpdLoop + static CUDTUnited& uglobal(); // UDT global management base + std::set& pollset() { return m_sPollID; } CSrtConfig m_config; @@ -697,7 +697,6 @@ class CUDT static loss_seqs_t defaultPacketArrival(void* vself, CPacket& pkt); static loss_seqs_t groupPacketArrival(void* vself, CPacket& pkt); - static CUDTUnited s_UDTUnited; // UDT global management base private: // Identification CUDTSocket* const m_parent; // Temporary, until the CUDTSocket class is merged with CUDT diff --git a/srtcore/group.cpp b/srtcore/group.cpp index f05f49369..c27ae2cbe 100644 --- a/srtcore/group.cpp +++ b/srtcore/group.cpp @@ -248,7 +248,7 @@ CUDTGroup::SocketData* CUDTGroup::add(SocketData data) } CUDTGroup::CUDTGroup(SRT_GROUP_TYPE gtype) - : m_pGlobal(&CUDT::s_UDTUnited) + : m_Global(CUDT::uglobal()) , m_GroupID(-1) , m_PeerGroupID(-1) , m_selfManaged(true) @@ -282,8 +282,8 @@ CUDTGroup::CUDTGroup(SRT_GROUP_TYPE gtype) setupMutex(m_GroupLock, "Group"); setupMutex(m_RcvDataLock, "RcvData"); setupCond(m_RcvDataCond, "RcvData"); - m_RcvEID = m_pGlobal->m_EPoll.create(&m_RcvEpolld); - m_SndEID = m_pGlobal->m_EPoll.create(&m_SndEpolld); + m_RcvEID = m_Global.m_EPoll.create(&m_RcvEpolld); + m_SndEID = m_Global.m_EPoll.create(&m_SndEpolld); m_stats.init(); @@ -869,7 +869,7 @@ SRT_SOCKSTATUS CUDTGroup::getStatus() if (i->second == SRTS_NONEXIST) { // Otherwise find at least one socket, which's state isn't broken. - i->second = m_pGlobal->getStatus(i->first); + i->second = m_Global.getStatus(i->first); if (pending_state == SRTS_NONEXIST) pending_state = i->second; } @@ -920,7 +920,7 @@ void CUDTGroup::close() vector ids; { - ScopedLock glob(CUDT::s_UDTUnited.m_GlobControlLock); + ScopedLock glob(CUDT::uglobal().m_GlobControlLock); ScopedLock g(m_GroupLock); // A non-managed group may only be closed if there are no @@ -941,7 +941,7 @@ void CUDTGroup::close() ids.push_back(ig->id); // Immediately cut ties to this group. // Just for a case, redispatch the socket, to stay safe. - CUDTSocket* s = CUDT::s_UDTUnited.locateSocket_LOCKED(ig->id); + CUDTSocket* s = CUDT::uglobal().locateSocket_LOCKED(ig->id); if (!s) { HLOGC(smlog.Debug, log << "group/close: IPE(NF): group member @" << ig->id << " already deleted"); @@ -963,7 +963,7 @@ void CUDTGroup::close() { // Global EPOLL lock must be applied to access any socket's epoll set. // This is a set of all epoll ids subscribed to it. - ScopedLock elock (CUDT::s_UDTUnited.m_EPoll.m_EPollLock); + ScopedLock elock (CUDT::uglobal().m_EPoll.m_EPollLock); epollid = m_sPollID; // use move() in C++11 m_sPollID.clear(); } @@ -974,7 +974,7 @@ void CUDTGroup::close() HLOGC(smlog.Debug, log << "close: CLEARING subscription on E" << (*i) << " of $" << id()); try { - CUDT::s_UDTUnited.m_EPoll.update_usock(*i, id(), &no_events); + CUDT::uglobal().m_EPoll.update_usock(*i, id(), &no_events); } catch (...) { @@ -994,7 +994,7 @@ void CUDTGroup::close() { try { - CUDT::s_UDTUnited.close(*i); + CUDT::uglobal().close(*i); } catch (CUDTException&) { @@ -1026,7 +1026,7 @@ void CUDTGroup::close() // CSync::lock_signal(m_RcvDataCond, m_RcvDataLock); } -// [[using locked(m_pGlobal->m_GlobControlLock)]] +// [[using locked(m_Global->m_GlobControlLock)]] // [[using locked(m_GroupLock)]] void CUDTGroup::send_CheckValidSockets() { @@ -1035,7 +1035,7 @@ void CUDTGroup::send_CheckValidSockets() for (gli_t d = m_Group.begin(), d_next = d; d != m_Group.end(); d = d_next) { ++d_next; // it's now safe to erase d - CUDTSocket* revps = m_pGlobal->locateSocket_LOCKED(d->id); + CUDTSocket* revps = m_Global.locateSocket_LOCKED(d->id); if (revps != d->ps) { // Note: the socket might STILL EXIST, just in the trash, so @@ -1104,12 +1104,12 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) vector activeLinks; // First, acquire GlobControlLock to make sure all member sockets still exist - enterCS(m_pGlobal->m_GlobControlLock); + enterCS(m_Global.m_GlobControlLock); ScopedLock guard(m_GroupLock); if (m_bClosing) { - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); } @@ -1117,7 +1117,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // LOCKED: GlobControlLock, GroupLock (RIGHT ORDER!) send_CheckValidSockets(); - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); // LOCKED: GroupLock (only) // Since this moment GlobControlLock may only be locked if GroupLock is unlocked first. @@ -1355,7 +1355,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // at the connecting stage. CEPoll::fmap_t sready; - if (m_pGlobal->m_EPoll.empty(*m_SndEpolld)) + if (m_Global.m_EPoll.empty(*m_SndEpolld)) { // Sanity check - weird pending reported. LOGC(gslog.Error, @@ -1368,7 +1368,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) InvertedLock ug(m_GroupLock); THREAD_PAUSED(); - m_pGlobal->m_EPoll.swait( + m_Global.m_EPoll.swait( *m_SndEpolld, sready, 0, false /*report by retval*/); // Just check if anything happened THREAD_RESUMED(); } @@ -1391,7 +1391,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // Failed socket. Move d to wipeme. Remove from eid. wipeme.push_back(*i); int no_events = 0; - m_pGlobal->m_EPoll.update_usock(m_SndEID, *i, &no_events); + m_Global.m_EPoll.update_usock(m_SndEID, *i, &no_events); } } @@ -1401,7 +1401,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // as redundant links at the connecting stage and became // writable (connected) before this function had a chance // to check them. - m_pGlobal->m_EPoll.clear_ready_usocks(*m_SndEpolld, SRT_EPOLL_CONNECT); + m_Global.m_EPoll.clear_ready_usocks(*m_SndEpolld, SRT_EPOLL_CONNECT); } } @@ -1446,7 +1446,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) { { InvertedLock ung (m_GroupLock); - enterCS(CUDT::s_UDTUnited.m_GlobControlLock); + enterCS(CUDT::uglobal().m_GlobControlLock); HLOGC(gslog.Debug, log << "grp/sendBroadcast: Locked GlobControlLock, locking back GroupLock"); } @@ -1454,7 +1454,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // the Sendstate::it field shall not be used here! for (vector::iterator is = sendstates.begin(); is != sendstates.end(); ++is) { - CUDTSocket* ps = CUDT::s_UDTUnited.locateSocket_LOCKED(is->id); + CUDTSocket* ps = CUDT::uglobal().locateSocket_LOCKED(is->id); // Is the socket valid? If not, simply SKIP IT. Nothing to be done with it, // it's already deleted. @@ -1498,7 +1498,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) } // Now you can leave GlobControlLock, while GroupLock is still locked. - leaveCS(CUDT::s_UDTUnited.m_GlobControlLock); + leaveCS(CUDT::uglobal().m_GlobControlLock); } // Re-check after the waiting lock has been reacquired @@ -1535,7 +1535,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) if (was_blocked) { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); if (!m_bSynSending) { throw CUDTException(MJ_AGAIN, MN_WRAVAIL, 0); @@ -1554,7 +1554,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) { HLOGC(gslog.Debug, log << "Will block on blocked socket @" << (*b)->id << " as only blocked socket remained"); - CUDT::s_UDTUnited.epoll_add_usock_INTERNAL(m_SndEID, (*b)->ps, &modes); + CUDT::uglobal().epoll_add_usock_INTERNAL(m_SndEID, (*b)->ps, &modes); } const int blocklen = blocked.size(); @@ -1569,7 +1569,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) // m_iSndTimeOut is -1 by default, which matches the meaning of waiting forever THREAD_PAUSED(); - blst = m_pGlobal->m_EPoll.swait(*m_SndEpolld, sready, m_iSndTimeOut); + blst = m_Global.m_EPoll.swait(*m_SndEpolld, sready, m_iSndTimeOut); THREAD_RESUMED(); // NOTE EXCEPTIONS: @@ -1671,8 +1671,8 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) if (none_succeeded) { HLOGC(gslog.Debug, log << "grp/sendBroadcast: all links broken (none succeeded to send a payload)"); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); // Reparse error code, if set. // It might be set, if the last operation was failed. // If any operation succeeded, this will not be executed anyway. @@ -1725,7 +1725,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc) if (!ready_again) { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); } return rstat; @@ -1871,7 +1871,7 @@ void CUDTGroup::fillGroupData(SRT_MSGCTRL& w_out, // MSGCTRL to be written w_out.grpdata = grpdata; } -// [[using locked(CUDT::s_UDTUnited.m_GlobControLock)]] +// [[using locked(CUDT::uglobal()->m_GlobControLock)]] // [[using locked(m_GroupLock)]] struct FLookupSocketWithEvent_LOCKED { @@ -1978,7 +1978,7 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& // which requires lock on m_GlobControlLock, while this lock cannot be applied without // first unlocking m_GroupLock. const int read_modes = SRT_EPOLL_IN | SRT_EPOLL_ERR; - CUDT::s_UDTUnited.epoll_add_usock_INTERNAL(m_RcvEID, *i, &read_modes); + CUDT::uglobal().epoll_add_usock_INTERNAL(m_RcvEID, *i, &read_modes); } // Here we need to make an additional check. @@ -2014,11 +2014,11 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& // This call may wait indefinite time, so GroupLock must be unlocked. InvertedLock ung (m_GroupLock); THREAD_PAUSED(); - nready = m_pGlobal->m_EPoll.swait(*m_RcvEpolld, sready, timeout, false /*report by retval*/); + nready = m_Global.m_EPoll.swait(*m_RcvEpolld, sready, timeout, false /*report by retval*/); THREAD_RESUMED(); // HERE GlobControlLock is locked first, then GroupLock is applied back - enterCS(CUDT::s_UDTUnited.m_GlobControlLock); + enterCS(CUDT::uglobal().m_GlobControlLock); } // BOTH m_GlobControlLock AND m_GroupLock are locked here. @@ -2028,7 +2028,7 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& { // GlobControlLock is applied manually, so unlock manually. // GroupLock will be unlocked as per scope. - leaveCS(CUDT::s_UDTUnited.m_GlobControlLock); + leaveCS(CUDT::uglobal().m_GlobControlLock); // This can only happen when 0 is passed as timeout and none is ready. // And 0 is passed only in non-blocking mode. So this is none ready in // non-blocking mode. @@ -2049,7 +2049,7 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& /*FROM*/ sready.begin(), sready.end(), /*TO*/ std::inserter(w_broken, w_broken.begin()), - /*VIA*/ FLookupSocketWithEvent_LOCKED(m_pGlobal, SRT_EPOLL_ERR)); + /*VIA*/ FLookupSocketWithEvent_LOCKED(&m_Global, SRT_EPOLL_ERR)); // If this set is empty, it won't roll even once, therefore output @@ -2081,7 +2081,7 @@ vector CUDTGroup::recv_WaitForReadReady(const vector& } } - leaveCS(CUDT::s_UDTUnited.m_GlobControlLock); + leaveCS(CUDT::uglobal().m_GlobControlLock); return readReady; } @@ -2132,7 +2132,7 @@ void CUDTGroup::updateReadState(SRTSOCKET /* not sure if needed */, int32_t sequ if (ready) { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, true); } } @@ -2145,7 +2145,7 @@ int32_t CUDTGroup::getRcvBaseSeqNo() void CUDTGroup::updateWriteState() { ScopedLock lg(m_GroupLock); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, true); } /// Validate iPktSeqno is in range @@ -2199,7 +2199,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) size_t output_size = 0; // First, acquire GlobControlLock to make sure all member sockets still exist - enterCS(m_pGlobal->m_GlobControlLock); + enterCS(m_Global.m_GlobControlLock); ScopedLock guard(m_GroupLock); if (m_bClosing) @@ -2209,13 +2209,13 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) // must fist wait for being able to acquire this lock. // The group will not be deleted now because it is added usage counter // by this call, but will be released once it exits. - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); } // Now, still under lock, check if all sockets still can be dispatched send_CheckValidSockets(); - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); if (m_bClosing) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); @@ -2254,7 +2254,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) // We predict to have only one packet ahead, others are pending to be reported by tsbpd. // This will be "re-enabled" if the later check puts any new packet into ahead. - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); return len; } @@ -2543,7 +2543,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) InvertedLock ung (m_GroupLock); for (set::iterator b = broken.begin(); b != broken.end(); ++b) { - CUDT::s_UDTUnited.close(*b); + CUDT::uglobal().close(*b); } } @@ -2551,7 +2551,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) { // All broken HLOGC(grlog.Debug, log << "group/recv: All sockets broken"); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); } @@ -2586,7 +2586,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) { // Don't clear the read-readinsess state if you have a packet ahead because // if you have, the next read call will return it. - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); } HLOGC(grlog.Debug, @@ -2697,7 +2697,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc) { // Don't clear the read-readinsess state if you have a packet ahead because // if you have, the next read call will return it. - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false); } return len; } @@ -3452,7 +3452,7 @@ void CUDTGroup::sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, c // at the connecting stage. CEPoll::fmap_t sready; - if (m_pGlobal->m_EPoll.empty(*m_SndEpolld)) + if (m_Global.m_EPoll.empty(*m_SndEpolld)) { // Sanity check - weird pending reported. LOGC(gslog.Error, log << "grp/send*: IPE: reported pending sockets, but EID is empty - wiping pending!"); @@ -3461,7 +3461,7 @@ void CUDTGroup::sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, c { InvertedLock ug(m_GroupLock); - m_pGlobal->m_EPoll.swait( + m_Global.m_EPoll.swait( *m_SndEpolld, sready, 0, false /*report by retval*/); // Just check if anything has happened } @@ -3472,7 +3472,7 @@ void CUDTGroup::sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, c } // Some sockets could have been closed in the meantime. - if (m_pGlobal->m_EPoll.empty(*m_SndEpolld)) + if (m_Global.m_EPoll.empty(*m_SndEpolld)) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); HLOGC(gslog.Debug, log << "grp/send*: RDY: " << DisplayEpollResults(sready)); @@ -3493,7 +3493,7 @@ void CUDTGroup::sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, c sendBackup_AssignBackupState(member->pSocketData->ps->core(), BKUPST_BROKEN, currtime); const int no_events = 0; - m_pGlobal->m_EPoll.update_usock(m_SndEID, sockid, &no_events); + m_Global.m_EPoll.update_usock(m_SndEID, sockid, &no_events); } // After that, all sockets that have been reported @@ -3502,7 +3502,7 @@ void CUDTGroup::sendBackup_CheckPendingSockets(SendBackupCtx& w_sendBackupCtx, c // as redundant links at the connecting stage and became // writable (connected) before this function had a chance // to check them. - m_pGlobal->m_EPoll.clear_ready_usocks(*m_SndEpolld, SRT_EPOLL_OUT); + m_Global.m_EPoll.clear_ready_usocks(*m_SndEpolld, SRT_EPOLL_OUT); } // [[using locked(this->m_GroupLock)]] @@ -3560,11 +3560,11 @@ void CUDTGroup::send_CloseBrokenSockets(vector& w_wipeme) // With unlocked GroupLock, we can now lock GlobControlLock. // This is needed prevent any of them be deleted from the container // at the same time. - ScopedLock globlock(CUDT::s_UDTUnited.m_GlobControlLock); + ScopedLock globlock(CUDT::uglobal().m_GlobControlLock); for (vector::iterator p = w_wipeme.begin(); p != w_wipeme.end(); ++p) { - CUDTSocket* s = CUDT::s_UDTUnited.locateSocket_LOCKED(*p); + CUDTSocket* s = CUDT::uglobal().locateSocket_LOCKED(*p); // If the socket has been just moved to ClosedSockets, it means that // the object still exists, but it will be no longer findable. @@ -3597,7 +3597,7 @@ void CUDTGroup::sendBackup_CloseBrokenSockets(SendBackupCtx& w_sendBackupCtx) // With unlocked GroupLock, we can now lock GlobControlLock. // This is needed prevent any of them be deleted from the container // at the same time. - ScopedLock globlock(CUDT::s_UDTUnited.m_GlobControlLock); + ScopedLock globlock(CUDT::uglobal().m_GlobControlLock); typedef vector::const_iterator const_iter_t; for (const_iter_t member = w_sendBackupCtx.memberStates().begin(); member != w_sendBackupCtx.memberStates().end(); ++member) @@ -3607,7 +3607,7 @@ void CUDTGroup::sendBackup_CloseBrokenSockets(SendBackupCtx& w_sendBackupCtx) // m_GroupLock is unlocked, therefore member->pSocketData can't be used. const SRTSOCKET sockid = member->socketID; - CUDTSocket* s = CUDT::s_UDTUnited.locateSocket_LOCKED(sockid); + CUDTSocket* s = CUDT::uglobal().locateSocket_LOCKED(sockid); // If the socket has been just moved to ClosedSockets, it means that // the object still exists, but it will be no longer findable. @@ -3674,10 +3674,10 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx // Note: GroupLock is set already, skip locks and checks getGroupData_LOCKED((w_mc.grpdata), (&w_mc.grpdata_size)); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); - if (m_pGlobal->m_EPoll.empty(*m_SndEpolld)) + if (m_Global.m_EPoll.empty(*m_SndEpolld)) { // wipeme wiped, pending sockets checked, it can only mean that // all sockets are broken. @@ -3713,7 +3713,7 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx RetryWaitBlocked: { // Some sockets could have been closed in the meantime. - if (m_pGlobal->m_EPoll.empty(*m_SndEpolld)) + if (m_Global.m_EPoll.empty(*m_SndEpolld)) { HLOGC(gslog.Debug, log << "grp/sendBackup: no more sockets available for sending - group broken"); throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); @@ -3723,7 +3723,7 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx HLOGC(gslog.Debug, log << "grp/sendBackup: swait call to get at least one link alive up to " << m_iSndTimeOut << "us"); THREAD_PAUSED(); - brdy = m_pGlobal->m_EPoll.swait(*m_SndEpolld, (sready), m_iSndTimeOut); + brdy = m_Global.m_EPoll.swait(*m_SndEpolld, (sready), m_iSndTimeOut); THREAD_RESUMED(); if (brdy == 0) // SND timeout exceeded @@ -3741,13 +3741,13 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx if (i->second & SRT_EPOLL_ERR) { SRTSOCKET id = i->first; - CUDTSocket* s = m_pGlobal->locateSocket(id, CUDTUnited::ERH_RETURN); // << LOCKS m_GlobControlLock! + CUDTSocket* s = m_Global.locateSocket(id, CUDTUnited::ERH_RETURN); // << LOCKS m_GlobControlLock! if (s) { HLOGC(gslog.Debug, log << "grp/sendBackup: swait/ex on @" << (id) << " while waiting for any writable socket - CLOSING"); - CUDT::s_UDTUnited.close(s); // << LOCKS m_GlobControlLock, then GroupLock! + CUDT::uglobal().close(s); // << LOCKS m_GlobControlLock, then GroupLock! } else { @@ -3771,8 +3771,8 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx& w_sendBackupCtx LOGC(gslog.Error, log << "grp/sendBackup: swait=>" << brdy << " nlinks=" << nlinks << " ndead=" << ndead << " - looxlike all links broken"); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); // You can safely throw here - nothing to fill in when all sockets down. // (timeout was reported by exception in the swait call). throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); @@ -3939,18 +3939,18 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc) // [[using assert(this->m_pSndBuffer != nullptr)]]; // First, acquire GlobControlLock to make sure all member sockets still exist - enterCS(m_pGlobal->m_GlobControlLock); + enterCS(m_Global.m_GlobControlLock); ScopedLock guard(m_GroupLock); if (m_bClosing) { - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); } // Now, still under lock, check if all sockets still can be dispatched send_CheckValidSockets(); - leaveCS(m_pGlobal->m_GlobControlLock); + leaveCS(m_Global.m_GlobControlLock); steady_clock::time_point currtime = steady_clock::now(); @@ -4011,8 +4011,8 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc) if (none_succeeded) { HLOGC(gslog.Debug, log << "grp/sendBackup: all links broken (none succeeded to send a payload)"); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); // Reparse error code, if set. // It might be set, if the last operation was failed. // If any operation succeeded, this will not be executed anyway. @@ -4062,7 +4062,7 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc) if (!ready_again) { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false); } HLOGC(gslog.Debug, @@ -4416,7 +4416,7 @@ void CUDTGroup::setGroupConnected() if (!m_bConnected) { // Switch to connected state and give appropriate signal - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_CONNECT, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_CONNECT, true); m_bConnected = true; } } @@ -4493,19 +4493,19 @@ void CUDTGroup::activateUpdateEvent(bool still_have_items) // was deleted from the group. This might make the group empty. if (!still_have_items) // empty, or removal of unknown socket attempted - set error on group { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); } else { - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_UPDATE, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_UPDATE, true); } } void CUDTGroup::addEPoll(int eid) { - enterCS(m_pGlobal->m_EPoll.m_EPollLock); + enterCS(m_Global.m_EPoll.m_EPollLock); m_sPollID.insert(eid); - leaveCS(m_pGlobal->m_EPoll.m_EPollLock); + leaveCS(m_Global.m_EPoll.m_EPollLock); bool any_read = false; bool any_write = false; @@ -4543,14 +4543,14 @@ void CUDTGroup::addEPoll(int eid) // because we know it is, as we just added it. But it's not performance // critical, sockets are not being often added during transmission. if (any_read) - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, true); if (any_write) - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, true); // Set broken if none is non-broken (pending, read-ready or write-ready) if (any_broken && !any_pending) - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true); } void CUDTGroup::removeEPollEvents(const int eid) @@ -4559,14 +4559,14 @@ void CUDTGroup::removeEPollEvents(const int eid) // since this happens after the epoll ID has been removed, they cannot be set again set remove; remove.insert(eid); - m_pGlobal->m_EPoll.update_events(id(), remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false); + m_Global.m_EPoll.update_events(id(), remove, SRT_EPOLL_IN | SRT_EPOLL_OUT, false); } void CUDTGroup::removeEPollID(const int eid) { - enterCS(m_pGlobal->m_EPoll.m_EPollLock); + enterCS(m_Global.m_EPoll.m_EPollLock); m_sPollID.erase(eid); - leaveCS(m_pGlobal->m_EPoll.m_EPollLock); + leaveCS(m_Global.m_EPoll.m_EPollLock); } void CUDTGroup::updateFailedLink() @@ -4588,7 +4588,7 @@ void CUDTGroup::updateFailedLink() { // No healthy links, set ERR on epoll. HLOGC(gmlog.Debug, log << "group/updateFailedLink: All sockets broken"); - m_pGlobal->m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); + m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); } else { @@ -4597,7 +4597,7 @@ void CUDTGroup::updateFailedLink() } #if ENABLE_HEAVY_LOGGING -// [[using maybe_locked(CUDT::s_UDTUnited.m_GlobControlLock)]] +// [[using maybe_locked(CUDT::uglobal()->m_GlobControlLock)]] void CUDTGroup::debugGroup() { ScopedLock gg(m_GroupLock); diff --git a/srtcore/group.h b/srtcore/group.h index 04c8e7e01..9927a2f6d 100644 --- a/srtcore/group.h +++ b/srtcore/group.h @@ -395,7 +395,7 @@ class CUDTGroup // If so, grab the status of all member sockets. void getGroupCount(size_t& w_size, bool& w_still_alive); - class srt::CUDTUnited* m_pGlobal; + srt::CUDTUnited& m_Global; srt::sync::Mutex m_GroupLock; SRTSOCKET m_GroupID; @@ -655,7 +655,7 @@ class CUDTGroup void recv_CollectAliveAndBroken(std::vector& w_alive, std::set& w_broken); /// The function polls alive member sockets and retrieves a list of read-ready. - /// [acquires lock for CUDT::s_UDTUnited.m_GlobControlLock] + /// [acquires lock for CUDT::uglobal()->m_GlobControlLock] /// [[using locked(m_GroupLock)]] temporally unlocks-locks internally /// /// @returns list of read-ready sockets diff --git a/srtcore/queue.cpp b/srtcore/queue.cpp index 03ba97e47..62d158af7 100644 --- a/srtcore/queue.cpp +++ b/srtcore/queue.cpp @@ -1004,7 +1004,7 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst // be normally closed by the application, after it is done with them. // app can call any UDT API to learn the connection_broken error - CUDT::s_UDTUnited.m_EPoll.update_events( + CUDT::uglobal().m_EPoll.update_events( i->u->m_SocketID, i->u->m_sPollID, SRT_EPOLL_IN | SRT_EPOLL_OUT | SRT_EPOLL_ERR, true); i->u->completeBrokenConnectionDependencies(i->errorcode); diff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp index 1cfdf8ff9..46afd8981 100644 --- a/test/test_fec_rebuilding.cpp +++ b/test/test_fec_rebuilding.cpp @@ -211,7 +211,7 @@ TEST(TestFEC, ConfigExchange) CUDTSocket* s1; - SRTSOCKET sid1 = CUDT::uglobal()->newSocket(&s1); + SRTSOCKET sid1 = CUDT::uglobal().newSocket(&s1); TestMockCUDT m1; m1.core = &s1->core(); @@ -243,7 +243,7 @@ TEST(TestFEC, ConfigExchangeFaux) CUDTSocket* s1; - SRTSOCKET sid1 = CUDT::uglobal()->newSocket(&s1); + SRTSOCKET sid1 = CUDT::uglobal().newSocket(&s1); const char* fec_config_wrong [] = { "FEC,Cols:20", // D: unknown filter From 790b7831fb7ec4851111e38ce601e4a13548847c Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 16 Aug 2021 16:18:26 +0200 Subject: [PATCH 108/124] [core] Small refax of CUDTUnited::channelSettingsMatch(..) --- srtcore/api.cpp | 127 ++++++++++++++++++++++++------------------------ srtcore/api.h | 10 +++- srtcore/core.h | 7 ++- 3 files changed, 76 insertions(+), 68 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index 38b86cf8c..dd8266f5c 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -1816,71 +1816,69 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, int32_t forced_isn) { - ScopedLock cg(s->m_ControlLock); - // a socket can "connect" only if it is in the following states: - // - OPENED: assume the socket binding parameters are configured - // - INIT: configure binding parameters here - // - any other (meaning, already connected): report error - - if (s->m_Status == SRTS_INIT) - { - if (s->core().m_config.bRendezvous) - throw CUDTException(MJ_NOTSUP, MN_ISRENDUNBOUND, 0); - - // If bind() was done first on this socket, then the - // socket will not perform this step. This actually does the - // same thing as bind() does, just with empty address so that - // the binding parameters are autoselected. - - s->core().open(); - sockaddr_any autoselect_sa (target_addr.family()); - // This will create such a sockaddr_any that - // will return true from empty(). - updateMux(s, autoselect_sa); // <<---- updateMux - // -> C(Snd|Rcv)Queue::init - // -> pthread_create(...C(Snd|Rcv)Queue::worker...) - s->m_Status = SRTS_OPENED; - } - else - { - if (s->m_Status != SRTS_OPENED) - throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0); + ScopedLock cg(s->m_ControlLock); + // a socket can "connect" only if it is in the following states: + // - OPENED: assume the socket binding parameters are configured + // - INIT: configure binding parameters here + // - any other (meaning, already connected): report error - // status = SRTS_OPENED, so family should be known already. - if (target_addr.family() != s->m_SelfAddr.family()) - { - LOGP(cnlog.Error, "srt_connect: socket is bound to a different family than target address"); - throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); - } - } + if (s->m_Status == SRTS_INIT) + { + if (s->core().m_config.bRendezvous) + throw CUDTException(MJ_NOTSUP, MN_ISRENDUNBOUND, 0); + + // If bind() was done first on this socket, then the + // socket will not perform this step. This actually does the + // same thing as bind() does, just with empty address so that + // the binding parameters are autoselected. + + s->core().open(); + sockaddr_any autoselect_sa (target_addr.family()); + // This will create such a sockaddr_any that + // will return true from empty(). + updateMux(s, autoselect_sa); // <<---- updateMux + // -> C(Snd|Rcv)Queue::init + // -> pthread_create(...C(Snd|Rcv)Queue::worker...) + s->m_Status = SRTS_OPENED; + } + else + { + if (s->m_Status != SRTS_OPENED) + throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0); + // status = SRTS_OPENED, so family should be known already. + if (target_addr.family() != s->m_SelfAddr.family()) + { + LOGP(cnlog.Error, "srt_connect: socket is bound to a different family than target address"); + throw CUDTException(MJ_NOTSUP, MN_INVAL, 0); + } + } - // connect_complete() may be called before connect() returns. - // So we need to update the status before connect() is called, - // otherwise the status may be overwritten with wrong value - // (CONNECTED vs. CONNECTING). - s->m_Status = SRTS_CONNECTING; - /* - * In blocking mode, connect can block for up to 30 seconds for - * rendez-vous mode. Holding the s->m_ControlLock prevent close - * from cancelling the connect - */ - try - { - // record peer address - s->m_PeerAddr = target_addr; - s->core().startConnect(target_addr, forced_isn); - } - catch (CUDTException& e) // Interceptor, just to change the state. - { - s->m_Status = SRTS_OPENED; - throw e; - } + // connect_complete() may be called before connect() returns. + // So we need to update the status before connect() is called, + // otherwise the status may be overwritten with wrong value + // (CONNECTED vs. CONNECTING). + s->m_Status = SRTS_CONNECTING; - // ScopedLock destructor will delete cg and unlock s->m_ControlLock + /* + * In blocking mode, connect can block for up to 30 seconds for + * rendez-vous mode. Holding the s->m_ControlLock prevent close + * from cancelling the connect + */ + try + { + // record peer address + s->m_PeerAddr = target_addr; + s->core().startConnect(target_addr, forced_isn); + } + catch (CUDTException& e) // Interceptor, just to change the state. + { + s->m_Status = SRTS_OPENED; + throw e; + } - return 0; + return 0; } @@ -2857,9 +2855,9 @@ uint16_t srt::CUDTUnited::installMuxer(CUDTSocket* w_s, CMultiplexer& fw_sm) return sa.hport(); } -bool srt::CUDTUnited::channelSettingsMatch(const CMultiplexer& m, const CUDTSocket* s) +bool srt::CUDTUnited::channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket) { - return m.m_mcfg.bReuseAddr && m.m_mcfg == s->core().m_config; + return cfgMuxer.bReuseAddr && cfgMuxer == cfgSocket; } void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/) @@ -2876,6 +2874,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U // If not, we need to see if there exist already a multiplexer bound // to the same endpoint. const int port = addr.hport(); + const CSrtConfig& cfgSocket = s->core().m_config; bool reuse_attempt = false; for (map::iterator i = m_mMultiplexer.begin(); @@ -2912,14 +2911,14 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U // Still, for ANY you need either the same family, or open // for families. - if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != s->core().m_config.iIpV6Only) + if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != cfgSocket.iIpV6Only) { LOGC(smlog.Error, log << "bind: Address: " << addr.str() << " conflicts with existing IPv6 wildcard binding: " << sa.str()); throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0); } - if ((m.m_mcfg.iIpV6Only == 0 || s->core().m_config.iIpV6Only == 0) && m.m_iIPversion != addr.family()) + if ((m.m_mcfg.iIpV6Only == 0 || cfgSocket.iIpV6Only == 0) && m.m_iIPversion != addr.family()) { LOGC(smlog.Error, log << "bind: Address: " << addr.str() << " conflicts with IPv6 wildcard binding: " << sa.str() @@ -2955,7 +2954,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U if (reuse_attempt) { // - if the channel settings match, it can be reused - if (channelSettingsMatch(m, s)) + if (channelSettingsMatch(m.m_mcfg, cfgSocket)) { HLOGC(smlog.Debug, log << "bind: reusing multiplexer for port " << port); // reuse the existing multiplexer diff --git a/srtcore/api.h b/srtcore/api.h index a1bfbffd7..516322292 100644 --- a/srtcore/api.h +++ b/srtcore/api.h @@ -123,7 +123,8 @@ class CUDTSocket void construct(); - srt::sync::atomic m_Status; //< current socket state + SRT_ATTR_GUARDED_BY(m_ControlLock) + sync::atomic m_Status; //< current socket state /// Time when the socket is closed. /// When the socket is closed, it is not removed immediately from the list @@ -441,7 +442,12 @@ friend class CRendezvousQueue; // Utility functions for updateMux void configureMuxer(CMultiplexer& w_m, const CUDTSocket* s, int af); uint16_t installMuxer(CUDTSocket* w_s, CMultiplexer& sm); - bool channelSettingsMatch(const CMultiplexer& m, const CUDTSocket* s); + + /// @brief Checks if channel configuration matches the socket configuration. + /// @param cfgMuxer multiplexer configuration. + /// @param cfgSocket socket configuration. + /// @return tru if configurations match, false otherwise. + static bool channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket); private: std::map m_mMultiplexer; // UDP multiplexer diff --git a/srtcore/core.h b/srtcore/core.h index 1fd5f6730..e74c58c6e 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -499,14 +499,17 @@ class CUDT SRT_ATR_NODISCARD size_t fillSrtHandshake_HSRSP(uint32_t* srtdata, size_t srtlen, int hs_version); SRT_ATR_NODISCARD size_t fillSrtHandshake(uint32_t* srtdata, size_t srtlen, int msgtype, int hs_version); - SRT_ATR_NODISCARD bool createSrtHandshake(int srths_cmd, int srtkm_cmd, const uint32_t* data, size_t datalen, + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + bool createSrtHandshake(int srths_cmd, int srtkm_cmd, const uint32_t* data, size_t datalen, CPacket& w_reqpkt, CHandShake& w_hs); SRT_ATR_NODISCARD size_t fillHsExtConfigString(uint32_t *pcmdspec, int cmd, const std::string &str); #if ENABLE_EXPERIMENTAL_BONDING SRT_ATR_NODISCARD size_t fillHsExtGroup(uint32_t *pcmdspec); #endif - SRT_ATR_NODISCARD size_t fillHsExtKMREQ(uint32_t *pcmdspec, size_t ki); + SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock) + size_t fillHsExtKMREQ(uint32_t *pcmdspec, size_t ki); + SRT_ATR_NODISCARD size_t fillHsExtKMRSP(uint32_t *pcmdspec, const uint32_t *kmdata, size_t kmdata_wordsize); SRT_ATR_NODISCARD size_t prepareSrtHsMsg(int cmd, uint32_t* srtdata, size_t size); From 2031b2c696f5f1bbffddf54b24c747c0db7d0a63 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 16 Aug 2021 16:20:16 +0200 Subject: [PATCH 109/124] [core] Do not set peerAddress in connectIn(..). CUDT::startConnect(..) sets it itself. --- srtcore/api.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index dd8266f5c..e35d637a5 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -1868,8 +1868,6 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i */ try { - // record peer address - s->m_PeerAddr = target_addr; s->core().startConnect(target_addr, forced_isn); } catch (CUDTException& e) // Interceptor, just to change the state. From ce2742b9ce6546a5252367b23c63404bfbfeb7f1 Mon Sep 17 00:00:00 2001 From: Sektor van Skijlen Date: Tue, 5 Oct 2021 10:55:47 +0200 Subject: [PATCH 110/124] [apps] Split off stats writer from apputil.cpp (#2130) --- apps/apputil.cpp | 334 +---------------------------------- apps/apputil.hpp | 87 ---------- apps/statswriter.cpp | 355 ++++++++++++++++++++++++++++++++++++++ apps/statswriter.hpp | 107 ++++++++++++ apps/support.maf | 1 + apps/transmitbase.hpp | 1 + testing/srt-test-live.maf | 1 + testing/testmedia.hpp | 1 + 8 files changed, 467 insertions(+), 420 deletions(-) create mode 100644 apps/statswriter.cpp create mode 100644 apps/statswriter.hpp diff --git a/apps/apputil.cpp b/apps/apputil.cpp index 1389b748e..68a9c4670 100644 --- a/apps/apputil.cpp +++ b/apps/apputil.cpp @@ -16,6 +16,7 @@ #include #include +#include "srt.h" // Required for SRT_SYNC_CLOCK_* definitions. #include "apputil.hpp" #include "netinet_any.h" #include "srt_compat.h" @@ -352,339 +353,6 @@ string OptionHelpItem(const OptionName& o) return out; } -// Stats module - -// Note: std::put_time is supported only in GCC 5 and higher -#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ >= 5) -#define HAS_PUT_TIME -#endif - -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 HAS_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 HAS_PUT_TIME. -string SrtStatsWriter::print_timestamp() -{ return ""; } -#endif // HAS_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 HAS_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 HAS_PUT_TIME - output << "Timepoint,"; -#endif - output << "Time,SocketID"; - - for (auto& i: g_SrtStatsTable) - { - output << "," << i->longname; - } - output << endl; - first_line_printed = true; - } - - // Values -#ifdef HAS_PUT_TIME - // HDR: Timepoint - output << print_timestamp() << ","; -#endif // HAS_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; -} - const char* SRTClockTypeStr() { const int clock_type = srt_clock_type(); diff --git a/apps/apputil.hpp b/apps/apputil.hpp index 782412815..7737c05f7 100644 --- a/apps/apputil.hpp +++ b/apps/apputil.hpp @@ -77,8 +77,6 @@ inline void SysCleanupNetwork() {} #endif -#include "srt.h" // Required for stats module - #ifdef _WIN32 inline int SysError() { return ::GetLastError(); } const int SysAGAIN = WSAEWOULDBLOCK; @@ -335,92 +333,7 @@ inline bool OptionPresent(const options_t& options, const std::set& options_t ProcessOptions(char* const* argv, int argc, std::vector scheme); std::string OptionHelpItem(const OptionName& o); -// Statistics module - -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); - const char* SRTClockTypeStr(); void PrintLibVersion(); - #endif // INC_SRT_APPCOMMON_H diff --git a/apps/statswriter.cpp b/apps/statswriter.cpp new file mode 100644 index 000000000..c176248ab --- /dev/null +++ b/apps/statswriter.cpp @@ -0,0 +1,355 @@ +/* + * 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" + +// Note: std::put_time is supported only in GCC 5 and higher +#if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ >= 5) +#define HAS_PUT_TIME +#endif + +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 HAS_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 HAS_PUT_TIME. +string SrtStatsWriter::print_timestamp() +{ return ""; } +#endif // HAS_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 HAS_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 HAS_PUT_TIME + output << "Timepoint,"; +#endif + output << "Time,SocketID"; + + for (auto& i: g_SrtStatsTable) + { + output << "," << i->longname; + } + output << endl; + first_line_printed = true; + } + + // Values +#ifdef HAS_PUT_TIME + // HDR: Timepoint + output << print_timestamp() << ","; +#endif // HAS_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; +} diff --git a/apps/statswriter.hpp b/apps/statswriter.hpp new file mode 100644 index 000000000..e15b902b7 --- /dev/null +++ b/apps/statswriter.hpp @@ -0,0 +1,107 @@ +/* + * 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 diff --git a/apps/support.maf b/apps/support.maf index 19ac894b4..e5aa77b8e 100644 --- a/apps/support.maf +++ b/apps/support.maf @@ -9,6 +9,7 @@ SOURCES apputil.cpp +statswriter.cpp logsupport.cpp logsupport_appdefs.cpp socketoptions.cpp diff --git a/apps/transmitbase.hpp b/apps/transmitbase.hpp index 3b3c7d0b9..007f4aaee 100644 --- a/apps/transmitbase.hpp +++ b/apps/transmitbase.hpp @@ -19,6 +19,7 @@ #include "srt.h" #include "uriparser.hpp" #include "apputil.hpp" +#include "statswriter.hpp" typedef std::vector bytevector; extern bool transmit_total_stats; diff --git a/testing/srt-test-live.maf b/testing/srt-test-live.maf index 17368a660..e80d79ec7 100644 --- a/testing/srt-test-live.maf +++ b/testing/srt-test-live.maf @@ -4,6 +4,7 @@ SOURCES srt-test-live.cpp testmedia.cpp ../apps/apputil.cpp +../apps/statswriter.cpp ../apps/verbose.cpp ../apps/socketoptions.cpp ../apps/uriparser.cpp diff --git a/testing/testmedia.hpp b/testing/testmedia.hpp index d3447a0d0..ec378080e 100644 --- a/testing/testmedia.hpp +++ b/testing/testmedia.hpp @@ -18,6 +18,7 @@ #include #include "apputil.hpp" +#include "statswriter.hpp" #include "testmediabase.hpp" #include // Needs access to CUDTException #include From 73b49feb9031d78828ac18d412c196e2b3d05b57 Mon Sep 17 00:00:00 2001 From: Sergei Ignatov Date: Wed, 6 Oct 2021 19:44:36 +1000 Subject: [PATCH 111/124] [build] Support NDK r23, OpenSSL v3 (#2148) --- scripts/build-android/build-android | 18 ++++---- scripts/build-android/mkssl | 68 +++++------------------------ 2 files changed, 20 insertions(+), 66 deletions(-) diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android index 0d56a8f01..f2d596847 100755 --- a/scripts/build-android/build-android +++ b/scripts/build-android/build-android @@ -3,16 +3,16 @@ echo_help() { echo "Usage: $0 [options...]" - echo " -n Specify NDK root path for the build." - echo " -a Select target API level." - echo " -t Select target architectures." - echo " Android supports the following architectures: armeabi-v7a arm64-v8a x86 x86_64." + echo " -n NDK root path for the build" + echo " -a Target API level" + echo " -t Space-separated list of target architectures" + echo " Android supports the following architectures: armeabi-v7a arm64-v8a x86 x86_64" echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls" - echo " -o Select OpenSSL (1.1.1 series) version. E.g. 1.1.1h" - echo " -m Select Mbed TLS version. E.g. v2.26.0" - echo " -s Select SRT version. E.g. v1.4.3" + echo " -o OpenSSL version. E.g. 1.1.1l" + echo " -m Mbed TLS version. E.g. v2.26.0" + echo " -s SRT version. E.g. v1.4.4" echo - echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/21.4.7075529 -a 28 -t \"armeabi-v7a arm64-v8a x86 x86_64\" -o 1.1.1h -s v1.4.3" + echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/23.0.7599858 -a 28 -t \"arm64-v8a x86_64\"" echo } @@ -20,7 +20,7 @@ echo_help() NDK_ROOT="" API_LEVEL=28 BUILD_TARGETS="armeabi-v7a arm64-v8a x86 x86_64" -OPENSSL_VERSION=1.1.1h +OPENSSL_VERSION=1.1.1l SRT_VERSION="" ENC_LIB=openssl MBEDTLS_VERSION=v2.26.0 diff --git a/scripts/build-android/mkssl b/scripts/build-android/mkssl index 4e9d0df28..ad6547261 100755 --- a/scripts/build-android/mkssl +++ b/scripts/build-android/mkssl @@ -29,48 +29,22 @@ fi cd openssl-${OPENSSL_VERSION} || exit 128 -##### Prepare Files ##### -sed -i.bak 's/.*-mandroid.*//' Configurations/15-android.conf -patch -p1 -N <{\$lib}. \$shlibvariant. '\$(SHLIB_EXT)'; -+ -+ if (windowsdll()) { -+ return \$lib . '\$(SHLIB_EXT_IMPORT)'; -+ } -+ return \$lib . '\$(SHLIB_EXT_SIMPLE)'; - } -- sub shlib_simple { -+ -+ sub shlib { - my \$lib = shift; - return () if \$disabled{shared} || \$lib =~ /\\.a$/; - -EOP - -##### remove output-directory ##### -#rm -rf $OUT_DIR - ##### export ndk directory. Required by openssl-build-scripts ##### -export ANDROID_NDK +case ${OPENSSL_VERSION} in + 1.1.1*) + export ANDROID_NDK_HOME=$ANDROID_NDK + ;; + *) + export ANDROID_NDK_ROOT=$ANDROID_NDK + ;; +esac + +export PATH=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin:$PATH ##### build-function ##### build_the_thing() { - TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG - export PATH=$TOOLCHAIN/$TRIBLE/bin:$TOOLCHAIN/bin:"$PATH" -echo $PATH make clean - #./Configure $SSL_TARGET $OPTIONS -fuse-ld="$TOOLCHAIN/$TRIBLE/bin/ld" "-gcc-toolchain $TOOLCHAIN" && \ - ./Configure $SSL_TARGET $OPTIONS -fuse-ld="$TOOLCHAIN/$TRIBLE/bin/ld" && \ + ./Configure $SSL_TARGET -D__ANDROID_API__=$API_LEVEL && \ make && \ make install DESTDIR=$DESTDIR || exit 128 } @@ -79,39 +53,19 @@ echo $PATH for build_target in $BUILD_TARGETS do case $build_target in - armeabi) - TRIBLE="arm-linux-androideabi" - TC_NAME="arm-linux-androideabi-4.9" - #OPTIONS="--target=armv5te-linux-androideabi -mthumb -fPIC -latomic -D__ANDROID_API__=$API_LEVEL" - OPTIONS="--target=armv5te-linux-androideabi -mthumb -fPIC -latomic -D__ANDROID_API__=$API_LEVEL" - DESTDIR="$BUILD_DIR/armeabi" - SSL_TARGET="android-arm" - ;; armeabi-v7a) - TRIBLE="arm-linux-androideabi" - TC_NAME="arm-linux-androideabi-4.9" - OPTIONS="--target=armv7a-linux-androideabi -Wl,--fix-cortex-a8 -fPIC -D__ANDROID_API__=$API_LEVEL" DESTDIR="$BUILD_DIR/armeabi-v7a" SSL_TARGET="android-arm" ;; x86) - TRIBLE="i686-linux-android" - TC_NAME="x86-4.9" - OPTIONS="-fPIC -D__ANDROID_API__=${API_LEVEL}" DESTDIR="$BUILD_DIR/x86" SSL_TARGET="android-x86" ;; x86_64) - TRIBLE="x86_64-linux-android" - TC_NAME="x86_64-4.9" - OPTIONS="-fPIC -D__ANDROID_API__=${API_LEVEL}" DESTDIR="$BUILD_DIR/x86_64" SSL_TARGET="android-x86_64" ;; arm64-v8a) - TRIBLE="aarch64-linux-android" - TC_NAME="aarch64-linux-android-4.9" - OPTIONS="-fPIC -D__ANDROID_API__=${API_LEVEL}" DESTDIR="$BUILD_DIR/arm64-v8a" SSL_TARGET="android-arm64" ;; From 2fb3c9ab06574b042590ff044a5ac06ad278e0b6 Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Mon, 11 Oct 2021 19:01:45 +0530 Subject: [PATCH 112/124] [api] Use the SOCKET type for any WIN32 environment (#2152) including MinGW. --- srtcore/srt.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/srtcore/srt.h b/srtcore/srt.h index 496112249..4cc2a377f 100644 --- a/srtcore/srt.h +++ b/srtcore/srt.h @@ -152,11 +152,7 @@ typedef int32_t SRTSOCKET; static const int32_t SRTGROUP_MASK = (1 << 30); #ifdef _WIN32 - #ifndef __MINGW32__ - typedef SOCKET SYSSOCKET; - #else - typedef int SYSSOCKET; - #endif + typedef SOCKET SYSSOCKET; #else typedef int SYSSOCKET; #endif From 6886bfaa6d23ffe74756fdf7ec3b4e7f89ae860d Mon Sep 17 00:00:00 2001 From: hondaxiao Date: Tue, 12 Oct 2021 11:15:20 +0800 Subject: [PATCH 113/124] [build] Add enable-experimental-bonding opt in configure --- configure-data.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/configure-data.tcl b/configure-data.tcl index 5c0ee2ee7..ab9dfd635 100644 --- a/configure-data.tcl +++ b/configure-data.tcl @@ -54,6 +54,7 @@ set cmake_options { enable-getnameinfo "In-logs sockaddr-to-string should do rev-dns (default: OFF)" enable-unittests "Enable unit tests (default: OFF)" enable-thread-check "Enable #include that implements THREAD_* macros" + enable-experimental-bonding "Enable experimental bonding (default: OFF)" openssl-crypto-library= "Path to a library." openssl-include-dir= "Path to a file." openssl-ssl-library= "Path to a library." From 86d1eb2d98491c71313e887c1bedcecce0932f90 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 5 Oct 2021 17:12:44 +0200 Subject: [PATCH 114/124] [core] Added CUDT::isRcvReady() with mutex lock. Added CUDT::getAvailRcvBufferSize() function with and without mutex lock. --- srtcore/common.h | 2 +- srtcore/core.cpp | 66 ++++++++++++++++++++++++++++++------------------ srtcore/core.h | 28 ++++++++++++++------ srtcore/sync.h | 14 +++++----- 4 files changed, 68 insertions(+), 42 deletions(-) diff --git a/srtcore/common.h b/srtcore/common.h index 530759dde..3e2ce9363 100644 --- a/srtcore/common.h +++ b/srtcore/common.h @@ -616,7 +616,7 @@ class CSeqNo /// This behaves like seq1 - seq2, in comparison to numbers, /// and with the statement that only the sign of the result matters. - /// That is, it returns a negative value if seq1 < seq2, + /// Returns a negative value if seq1 < seq2, /// positive if seq1 > seq2, and zero if they are equal. /// The only correct application of this function is when you /// compare two values and it works faster than seqoff. However diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 53e4a28d5..b3b1d374c 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -551,7 +551,7 @@ void srt::CUDT::getOpt(SRT_SOCKOPT optName, void *optval, int &optlen) else { enterCS(m_RecvLock); - if (m_pRcvBuffer && m_pRcvBuffer->isRcvDataReady()) + if (m_pRcvBuffer && isRcvBufferReady()) event |= SRT_EPOLL_IN; leaveCS(m_RecvLock); if (m_pSndBuffer && (m_config.iSndBufSize > m_pSndBuffer->getCurrBufSize())) @@ -5211,7 +5211,6 @@ void * srt::CUDT::tsbpd(void *param) { int32_t skiptoseqno = SRT_SEQNO_NONE; bool passack = true; // Get next packet to wait for even if not acked - rxready = self->m_pRcvBuffer->getRcvFirstMsg((tsbpdtime), (passack), (skiptoseqno), (current_pkt_seq), rcv_base_seq); HLOGC(tslog.Debug, @@ -6052,7 +6051,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) UniqueLock recvguard(m_RecvLock); - if ((m_bBroken || m_bClosing) && !m_pRcvBuffer->isRcvDataReady()) + if ((m_bBroken || m_bClosing) && !isRcvBufferReady()) { if (m_bShutdown) { @@ -6084,7 +6083,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) CSync rcond (m_RecvDataCond, recvguard); CSync tscond (m_RcvTsbPdCond, recvguard); - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { if (!m_config.bSynRecving) { @@ -6096,7 +6095,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) if (m_config.iRcvTimeOut < 0) { THREAD_PAUSED(); - while (stillConnected() && !m_pRcvBuffer->isRcvDataReady()) + while (stillConnected() && !isRcvBufferReady()) { // Do not block forever, check connection status each 1 sec. rcond.wait_for(seconds_from(1)); @@ -6108,7 +6107,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) const steady_clock::time_point exptime = steady_clock::now() + milliseconds_from(m_config.iRcvTimeOut); THREAD_PAUSED(); - while (stillConnected() && !m_pRcvBuffer->isRcvDataReady()) + while (stillConnected() && !isRcvBufferReady()) { if (!rcond.wait_until(exptime)) // NOT means "not received a signal" break; // timeout @@ -6122,7 +6121,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) if (!m_bConnected) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); - if ((m_bBroken || m_bClosing) && !m_pRcvBuffer->isRcvDataReady()) + if ((m_bBroken || m_bClosing) && !isRcvBufferReady()) { // See at the beginning if (!m_config.bMessageAPI && m_bShutdown) @@ -6152,7 +6151,7 @@ int srt::CUDT::receiveBuffer(char *data, int len) HLOGP(tslog.Debug, "NOT pinging TSBPD - not set"); } - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { // read is not available any more uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); @@ -6607,6 +6606,23 @@ int srt::CUDT::recvmsg2(char* data, int len, SRT_MSGCTRL& w_mctrl) return receiveBuffer(data, len); } +size_t srt::CUDT::getAvailRcvBufferSizeLock() const +{ + ScopedLock lck(m_RcvBufferLock); + return m_pRcvBuffer->getAvailBufSize(); +} + +size_t srt::CUDT::getAvailRcvBufferSizeNoLock() const +{ + return m_pRcvBuffer->getAvailBufSize(); +} + +bool srt::CUDT::isRcvBufferReady() const +{ + ScopedLock lck(m_RcvBufferLock); + return m_pRcvBuffer->isRcvDataReady(); +} + // int by_exception: accepts values of CUDTUnited::ErrorHandling: // - 0 - by return value // - 1 - by exception @@ -6647,7 +6663,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ { HLOGC(arlog.Debug, log << CONID() << "receiveMessage: CONNECTION BROKEN - reading from recv buffer just for formality"); enterCS(m_RcvBufferLock); - int res = m_pRcvBuffer->readMsg(data, len); + const int res = m_pRcvBuffer->readMsg(data, len); leaveCS(m_RcvBufferLock); w_mctrl.srctime = 0; @@ -6662,7 +6678,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ HLOGP(tslog.Debug, "NOT pinging TSBPD - not set"); } - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { // read is not available any more uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); @@ -6713,7 +6729,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0); } - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { // Kick TsbPd thread to schedule next wakeup (if running) if (m_bTsbPd) @@ -6792,12 +6808,12 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ { HLOGP(tslog.Debug, "receiveMessage: DATA COND: KICKED."); } - } while (stillConnected() && !timeout && (!m_pRcvBuffer->isRcvDataReady())); + } while (stillConnected() && !timeout && (!isRcvBufferReady())); THREAD_RESUMED(); HLOGC(tslog.Debug, log << CONID() << "receiveMessage: lock-waiting loop exited: stillConntected=" << stillConnected() - << " timeout=" << timeout << " data-ready=" << m_pRcvBuffer->isRcvDataReady()); + << " timeout=" << timeout << " data-ready=" << isRcvBufferReady()); } /* XXX DEBUG STUFF - enable when required @@ -6829,7 +6845,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_ } } while ((res == 0) && !timeout); - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { // Falling here means usually that res == 0 && timeout == true. // res == 0 would repeat the above loop, unless there was also a timeout. @@ -6990,7 +7006,7 @@ int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int blo { if (!m_bConnected || !m_CongCtl.ready()) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); - else if ((m_bBroken || m_bClosing) && !m_pRcvBuffer->isRcvDataReady()) + else if ((m_bBroken || m_bClosing) && !isRcvBufferReady()) { if (!m_config.bMessageAPI && m_bShutdown) return 0; @@ -7072,14 +7088,14 @@ int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int blo CSync rcond (m_RecvDataCond, recvguard); THREAD_PAUSED(); - while (stillConnected() && !m_pRcvBuffer->isRcvDataReady()) + while (stillConnected() && !isRcvBufferReady()) rcond.wait(); THREAD_RESUMED(); } if (!m_bConnected) throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0); - else if ((m_bBroken || m_bClosing) && !m_pRcvBuffer->isRcvDataReady()) + else if ((m_bBroken || m_bClosing) && !isRcvBufferReady()) { if (!m_config.bMessageAPI && m_bShutdown) return 0; @@ -7098,7 +7114,7 @@ int64_t srt::CUDT::recvfile(fstream &ofs, int64_t &offset, int64_t size, int blo } } - if (!m_pRcvBuffer->isRcvDataReady()) + if (!isRcvBufferReady()) { // read is not available any more uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, false); @@ -7239,7 +7255,7 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) if (m_pRcvBuffer) { - perf->byteAvailRcvBuf = m_pRcvBuffer->getAvailBufSize() * m_config.iMSS; + perf->byteAvailRcvBuf = getAvailRcvBufferSizeLock() * m_config.iMSS; if (instantaneous) // no need for historical API for Rcv side { perf->pktRcvBuf = m_pRcvBuffer->getRcvDataSize(perf->byteRcvBuf, perf->msRcvBuf); @@ -7489,7 +7505,7 @@ void srt::CUDT::releaseSynch() // [[using locked(m_RcvBufferLock)]]; int32_t srt::CUDT::ackDataUpTo(int32_t ack) { - int acksize = CSeqNo::seqoff(m_iRcvLastSkipAck, ack); + const int acksize = CSeqNo::seqoff(m_iRcvLastSkipAck, ack); HLOGC(xtlog.Debug, log << "ackDataUpTo: %" << ack << " vs. current %" << m_iRcvLastSkipAck << " (signing off " << acksize << " packets)"); @@ -7691,7 +7707,7 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) { SRT_ASSERT(ctrlpkt.getMsgTimeStamp() != 0); - int32_t ack; + int32_t ack; // First unacknowledged packet seqnuence number (acknowledge up to ack). int nbsent = 0; int local_prevack = 0; @@ -7881,7 +7897,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size) data[ACKD_RCVLASTACK] = m_iRcvLastAck; data[ACKD_RTT] = m_iSRTT; data[ACKD_RTTVAR] = m_iRTTVar; - data[ACKD_BUFFERLEFT] = m_pRcvBuffer->getAvailBufSize(); + data[ACKD_BUFFERLEFT] = getAvailRcvBufferSizeNoLock(); // a minimum flow window of 2 is used, even if buffer is full, to break potential deadlock if (data[ACKD_BUFFERLEFT] < 2) data[ACKD_BUFFERLEFT] = 2; @@ -9666,7 +9682,7 @@ int srt::CUDT::processData(CUnit* in_unit) continue; } - const int avail_bufsize = m_pRcvBuffer->getAvailBufSize(); + const int avail_bufsize = getAvailRcvBufferSizeNoLock(); if (offset >= avail_bufsize) { // This is already a sequence discrepancy. Probably there could be found @@ -9773,7 +9789,7 @@ int srt::CUDT::processData(CUnit* in_unit) LOGC(qrlog.Debug, log << CONID() << "RECEIVED: seq=" << rpkt.m_iSeqNo << " offset=" << offset << " BUFr=" << avail_bufsize - << " avail=" << m_pRcvBuffer->getAvailBufSize() + << " avail=" << getAvailRcvBufferSizeNoLock() << " buffer=(" << m_iRcvLastSkipAck << ":" << m_iRcvCurrSeqNo // -1 = size to last index << "+" << CSeqNo::incseq(m_iRcvLastSkipAck, m_pRcvBuffer->capacity()-1) @@ -11123,7 +11139,7 @@ void srt::CUDT::addEPoll(const int eid) return; enterCS(m_RecvLock); - if (m_pRcvBuffer->isRcvDataReady()) + if (isRcvBufferReady()) { uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_IN, true); } diff --git a/srtcore/core.h b/srtcore/core.h index e74c58c6e..2bbc7b069 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -692,6 +692,9 @@ class CUDT return m_stats.tsStartTime; } + SRT_ATTR_EXCLUDES(m_RcvBufferLock) + bool isRcvBufferReady() const; + // TSBPD thread main function. static void* tsbpd(void* param); @@ -863,17 +866,17 @@ class CUDT int32_t m_iReXmitCount; // Re-Transmit Count since last ACK private: // Receiving related data - CRcvBuffer* m_pRcvBuffer; // Receiver buffer - CRcvLossList* m_pRcvLossList; // Receiver loss list - std::deque m_FreshLoss; // Lost sequence already added to m_pRcvLossList, but not yet sent UMSG_LOSSREPORT for. - int m_iReorderTolerance; // Current value of dynamic reorder tolerance - int m_iConsecEarlyDelivery; // Increases with every OOO packet that came m_FreshLoss; //< Lost sequence already added to m_pRcvLossList, but not yet sent UMSG_LOSSREPORT for. + int m_iReorderTolerance; //< Current value of dynamic reorder tolerance + int m_iConsecEarlyDelivery; //< Increases with every OOO packet that came m_ACKWindow; // ACK history window CPktTimeWindow<16, 64> m_RcvTimeWindow; // Packet arrival time window - int32_t m_iRcvLastAck; // Last sent ACK + int32_t m_iRcvLastAck; // First unacknowledged packet seqno sent in the latest ACK. #ifdef ENABLE_LOGGING int32_t m_iDebugPrevLastAck; #endif @@ -921,7 +924,7 @@ class CUDT sync::Condition m_SendBlockCond; // used to block "send" call sync::Mutex m_SendBlockLock; // lock associated to m_SendBlockCond - sync::Mutex m_RcvBufferLock; // Protects the state of the m_pRcvBuffer + mutable sync::Mutex m_RcvBufferLock; // Protects the state of the m_pRcvBuffer // Protects access to m_iSndCurrSeqNo, m_iSndLastAck sync::Mutex m_RecvAckLock; // Protects the state changes while processing incomming ACK (SRT_EPOLL_OUT) @@ -1033,6 +1036,15 @@ class CUDT int32_t ackDataUpTo(int32_t seq); void handleKeepalive(const char* data, size_t lenghth); + /// Locks m_RcvBufferLock and retrieves the available size of the receiver buffer. + SRT_ATTR_EXCLUDES(m_RcvBufferLock) + size_t getAvailRcvBufferSizeLock() const; + + /// Retrieves the available size of the receiver buffer. + /// Expects that m_RcvBufferLock is locked. + SRT_ATTR_REQUIRES(m_RcvBufferLock) + size_t getAvailRcvBufferSizeNoLock() const; + private: // Trace struct CoreStats { diff --git a/srtcore/sync.h b/srtcore/sync.h index 7cb0f63a9..b68061cf6 100644 --- a/srtcore/sync.h +++ b/srtcore/sync.h @@ -357,27 +357,25 @@ class SRT_ATTR_SCOPED_CAPABILITY ScopedLock class SRT_ATTR_SCOPED_CAPABILITY UniqueLock { friend class SyncEvent; + int m_iLocked; + Mutex& m_Mutex; public: - SRT_ATTR_ACQUIRE(m_Mutex) + SRT_ATTR_ACQUIRE(m) UniqueLock(Mutex &m); - SRT_ATTR_RELEASE(m_Mutex) + SRT_ATTR_RELEASE() ~UniqueLock(); public: - SRT_ATTR_ACQUIRE(m_Mutex) + SRT_ATTR_ACQUIRE() void lock(); - SRT_ATTR_RELEASE(m_Mutex) + SRT_ATTR_RELEASE() void unlock(); SRT_ATTR_RETURN_CAPABILITY(m_Mutex) Mutex* mutex(); // reflects C++11 unique_lock::mutex() - -private: - int m_iLocked; - Mutex& m_Mutex; }; #endif // ENABLE_STDCXX_SYNC From ac6ec62a9071b0f7c4410b211a9005792e5d3394 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 11 Oct 2021 17:06:27 +0200 Subject: [PATCH 115/124] [tests] Improved the TestConnection.Multiple test. Using std::array. Try to bind SRT directly instead of UDP. --- srtcore/channel.cpp | 2 +- test/test_many_connections.cpp | 80 +++++++++++++++------------------- 2 files changed, 37 insertions(+), 45 deletions(-) diff --git a/srtcore/channel.cpp b/srtcore/channel.cpp index 92fd6b991..85c39ba95 100644 --- a/srtcore/channel.cpp +++ b/srtcore/channel.cpp @@ -584,7 +584,7 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const if (dcounter > 8) { // Make a random number in the range between 8 and 24 - const int rnd = srt::sync::getRandomInt(8, 24); + const int rnd = srt::sync::genRandomInt(8, 24); if (dcounter > rnd) { diff --git a/test/test_many_connections.cpp b/test/test_many_connections.cpp index cca42ecf0..99bc5925c 100644 --- a/test/test_many_connections.cpp +++ b/test/test_many_connections.cpp @@ -1,8 +1,10 @@ #define _CRT_RAND_S // For Windows, rand_s #include +#include #include #include +#include #ifdef _WIN32 #include @@ -49,40 +51,36 @@ class TestConnection m_sa.sin_family = AF_INET; m_sa.sin_addr.s_addr = INADDR_ANY; - m_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - ASSERT_NE(m_udp_sock, -1); - // Find unused a port not used by any other service. - // Otherwise srt_connect may actually connect. - int bind_res = -1; + m_server_sock = srt_create_socket(); + ASSERT_NE(m_server_sock, SRT_INVALID_SOCK); + + // Find a port not used by another service. + int bind_res = 0; const sockaddr* psa = reinterpret_cast(&m_sa); - for (int port = 5000; port <= 5555; ++port) + for (int port = 5000; port <= 5100; ++port) { m_sa.sin_port = htons(port); - bind_res = ::bind(m_udp_sock, psa, sizeof m_sa); - if (bind_res >= 0) + + bind_res = srt_bind(m_server_sock, psa, sizeof m_sa); + if (bind_res == 0) { cerr << "Running test on port " << port << "\n"; break; } } - // Close the socket to free the port. - ASSERT_NE(closesocket(m_udp_sock), -1); - ASSERT_GE(bind_res, 0); + ASSERT_GE(bind_res, 0) << "srt_bind returned " << bind_res << ": " << srt_getlasterror_str(); ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &m_sa.sin_addr), 1); // Fill the buffer with random data - time_t now; - time(&now); - unsigned int randseed = now % 255; - srand(randseed); - for (int i = 0; i < SRT_LIVE_DEF_PLSIZE; ++i) - buf[i] = rand_r(&randseed) % 255; + std::random_device rnd_device; + std::mt19937 gen(rnd_device()); + std::uniform_int_distribution dis(-128, 127); + std::generate(m_buf.begin(), m_buf.end(), [dis, gen]() mutable { return (char)dis(gen); }); - m_server_sock = srt_create_socket(); + cout << "Generated: " << static_cast(m_buf[0]) << ", " << static_cast(m_buf[1]) << std::endl; - ASSERT_NE(srt_bind(m_server_sock, psa, sizeof m_sa), -1); ASSERT_NE(srt_listen(m_server_sock, NSOCK), -1); } @@ -93,7 +91,6 @@ class TestConnection void AcceptLoop() { - //cerr << "[T] Accepting connections\n"; for (;;) { sockaddr_any addr; @@ -102,18 +99,16 @@ class TestConnection if (acp == -1) { cerr << "[T] Accept error at " << m_accepted.size() - << "/" << NSOCK << ": " << srt_getlasterror_str() << endl; + << "/" << NSOCK << ": " << srt_getlasterror_str() << endl; break; } - //cerr << "[T] Got new acp @" << acp << endl; m_accepted.push_back(acp); } - m_accept_exit = true; - cerr << "[T] Closing those accepted ones\n"; + m_accept_exit = true; - for (auto s: m_accepted) + for (const auto s : m_accepted) { srt_close(s); } @@ -122,12 +117,11 @@ class TestConnection } protected: - SOCKET m_udp_sock = INVALID_SOCKET; sockaddr_in m_sa = sockaddr_in(); SRTSOCKET m_server_sock = SRT_INVALID_SOCK; vector m_accepted; - char buf[SRT_LIVE_DEF_PLSIZE]; - SRTSOCKET srt_socket_list[NSOCK]; + std::array m_buf; + SRTSOCKET m_connections[NSOCK]; volatile bool m_accept_exit = false; }; @@ -135,55 +129,53 @@ class TestConnection TEST_F(TestConnection, Multiple) { - size_t size = SRT_LIVE_DEF_PLSIZE; - - sockaddr_in lsa = m_sa; - + const sockaddr_in lsa = m_sa; const sockaddr* psa = reinterpret_cast(&lsa); auto ex = std::async([this] { return AcceptLoop(); }); - cout << "Opening " << NSOCK << " connections\n"; + cerr << "Opening " << NSOCK << " connections\n"; for (size_t i = 0; i < NSOCK; i++) { - srt_socket_list[i] = srt_create_socket(); + m_connections[i] = srt_create_socket(); + EXPECT_NE(m_connections[i], SRT_INVALID_SOCK); // Give it 60s timeout, many platforms fail to process // so many connections in a short time. int conntimeo = 60; - srt_setsockflag(srt_socket_list[i], SRTO_CONNTIMEO, &conntimeo, sizeof conntimeo); + srt_setsockflag(m_connections[i], SRTO_CONNTIMEO, &conntimeo, sizeof conntimeo); //cerr << "Connecting #" << i << " to " << sockaddr_any(psa).str() << "...\n"; //cerr << "Connecting to: " << sockaddr_any(psa).str() << endl; - ASSERT_NE(srt_connect(srt_socket_list[i], psa, sizeof lsa), SRT_ERROR); + ASSERT_NE(srt_connect(m_connections[i], psa, sizeof lsa), SRT_ERROR); // Set now async sending so that sending isn't blocked int no = 0; - ASSERT_NE(srt_setsockflag(srt_socket_list[i], SRTO_SNDSYN, &no, sizeof no), -1); + ASSERT_NE(srt_setsockflag(m_connections[i], SRTO_SNDSYN, &no, sizeof no), -1); } for (size_t j = 1; j <= 100; j++) { for (size_t i = 0; i < NSOCK; i++) { - EXPECT_GT(srt_send(srt_socket_list[i], buf, size), 0); + EXPECT_GT(srt_send(m_connections[i], m_buf.data(), (int) m_buf.size()), 0); } } - cout << "Sending finished, closing caller sockets\n"; + cerr << "Sending finished, closing caller sockets\n"; for (size_t i = 0; i < NSOCK; i++) { - EXPECT_EQ(srt_close(srt_socket_list[i]), SRT_SUCCESS); + EXPECT_EQ(srt_close(m_connections[i]), SRT_SUCCESS); } - // Up to this moment the server sock should survive - cout << "Closing server socket\n"; - - EXPECT_EQ(m_accept_exit, false); + EXPECT_FALSE(m_accept_exit) << "AcceptLoop already broken for some reason!"; + // Up to this moment the server sock should survive + cerr << "Closing server socket\n"; // Close server socket to break the accept loop EXPECT_EQ(srt_close(m_server_sock), 0); + cerr << "Synchronize with the accepting thread\n"; ex.wait(); } From 489c5fc6c6853531d62b9888e0b2bb019c70e358 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 12 Oct 2021 16:01:29 +0200 Subject: [PATCH 116/124] [core] Use Mersenne Twister engine with C++11 instead of the std::random_device. Fixed max value probability for the default (C++03) rand(). --- srtcore/sync.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/srtcore/sync.cpp b/srtcore/sync.cpp index aa15c2471..fdf5a0b66 100644 --- a/srtcore/sync.cpp +++ b/srtcore/sync.cpp @@ -283,10 +283,11 @@ bool srt::sync::CGlobEvent::waitForEvent() namespace srt { #if HAVE_CXX11 -static std::random_device& randomDevice() +static std::mt19937& randomGen() { static std::random_device s_RandomDevice; - return s_RandomDevice; + static std::mt19937 s_GenMT19937(s_RandomDevice()); + return s_GenMT19937; } #elif defined(_WIN32) && defined(__MINGW32__) static void initRandSeed() @@ -300,7 +301,7 @@ static pthread_once_t s_InitRandSeedOnce = PTHREAD_ONCE_INIT; static unsigned int genRandSeed() { // Duration::count() does not depend on any global objects, - // therefore it is preferred over count)microseconds(..). + // therefore it is preferred over count_microseconds(..). const int64_t seed = sync::steady_clock::now().time_since_epoch().count(); return (unsigned int) seed; } @@ -325,7 +326,7 @@ int srt::sync::genRandomInt(int minVal, int maxVal) sync::ScopedLock lck(s_mtxRandomDevice); #if HAVE_CXX11 uniform_int_distribution<> dis(minVal, maxVal); - return dis(randomDevice()); + return dis(randomGen()); #else #if defined(__MINGW32__) // No rand_r(..) for MinGW. @@ -342,9 +343,13 @@ int srt::sync::genRandomInt(int minVal, int maxVal) #endif // Map onto [minVal, maxVal]. - // Note. The probablity to get maxVal as the result is minuscule. - const int res = minVal + static_cast((maxVal - minVal) * rand_0_1); - return res; + // Note. There is a minuscule probablity to get maxVal+1 as the result. + // So we have to use long long to handle cases when maxVal = INT32_MAX. + // Also we must check 'res' does not exceed maxVal, + // which may happen if rand_0_1 = 1, even though the chances are low. + const long long llMaxVal = maxVal; + const int res = minVal + static_cast((llMaxVal + 1 - minVal) * rand_0_1); + return min(res, maxVal); #endif // HAVE_CXX11 } From fa1c3736cfd3a76f7892f186955aa57cbaaaa290 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Tue, 12 Oct 2021 16:02:14 +0200 Subject: [PATCH 117/124] [tests] Added check for a minimal value of the uniform distribution. --- test/test_many_connections.cpp | 5 +++- test/test_sync.cpp | 50 ++++++++++++++++++++++------------ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/test/test_many_connections.cpp b/test/test_many_connections.cpp index 99bc5925c..52d9be773 100644 --- a/test/test_many_connections.cpp +++ b/test/test_many_connections.cpp @@ -126,7 +126,10 @@ class TestConnection }; - +// This test establishes multiple connections to a single SRT listener on a localhost port. +// Packets are submitted for sending to all those connections in a non-blocking mode. +// Then all connections are closed. Some sockets may potentially still have undelivered packets. +// This test tries to reproduce the issue described in #1182, and fixed by #1315. TEST_F(TestConnection, Multiple) { const sockaddr_in lsa = m_sa; diff --git a/test/test_sync.cpp b/test/test_sync.cpp index 6fa59c137..5e08cd30b 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -1,4 +1,5 @@ #include "gtest/gtest.h" +#include #include #include #include @@ -15,14 +16,6 @@ using namespace std; using namespace srt::sync; -// GNUC supports C++14 starting from version 5 -//#if defined(__GNUC__) && (__GNUC__ < 5) -////namespace srt -// constexpr chrono::milliseconds operator"" ms( -// unsigned long long _Val) { // return integral milliseconds -// return chrono::milliseconds(_Val); -//} -//#endif TEST(SyncDuration, BasicChecks) { @@ -159,23 +152,44 @@ TEST(SyncDuration, OperatorMultIntEq) TEST(SyncRandom, GenRandomInt) { - vector mn(64); + array mn = {}; - for (int i = 0; i < 2048; ++i) + // Check generated values are in the specified range. + const size_t n = 2048; + for (size_t i = 0; i < n; ++i) { - const int rand_val = genRandomInt(0, 63); + const int rand_val = genRandomInt(0, mn.size() - 1); ASSERT_GE(rand_val, 0); - ASSERT_LE(rand_val, 63); + ASSERT_LT(rand_val, mn.size()); ++mn[rand_val]; } + // Check the distribution is more or less uniform. + // 100% uniform if each value is generated (n / (2 * mn.size())) times. + // We expect at least half of that value for a random uniform distribution. + const int min_value = n / (2 * mn.size()) - 1; + cout << "min value: " << min_value << endl; + for (size_t i = 0; i < mn.size(); ++i) + { + EXPECT_GE(mn[i], min_value) << "i=" << i << ". Ok-ish if the count is non-zero."; + } + // Uncomment to see the distribution. - // for (size_t i = 0; i < mn.size(); ++i) - // { - // cout << i << '\t'; - // for (int j=0; j Date: Wed, 13 Oct 2021 02:57:21 -0500 Subject: [PATCH 118/124] [build] Fix build with default configuration for GCC <4.7 (#2160) --- CMakeLists.txt | 6 +++++- docs/build/build-options.md | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21478c36a..0bebae3cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,7 +123,11 @@ endif() # options option(CYGWIN_USE_POSIX "Should the POSIX API be used for cygwin. Ignored if the system isn't cygwin." OFF) -option(ENABLE_CXX11 "Should the c++11 parts (srt-live-transmit) be enabled" ON) +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_EXPERIMENTAL_BONDING "Should the EXPERIMENTAL bonding functionality be enabled?" OFF) option(ENABLE_TESTING "Should the Developer Test Applications be Built?" OFF) diff --git a/docs/build/build-options.md b/docs/build/build-options.md index 938d925d2..d8c1d757a 100644 --- a/docs/build/build-options.md +++ b/docs/build/build-options.md @@ -74,7 +74,7 @@ The `pkg-confg` file (`srt.pc`) will be generated with the `libstdc++` library as a dependency. This may be required in some cases where you have an application written in C which therefore won't link against `libstdc++` by default. -**`--enable-c++11`** (default: ON) +**`--enable-c++11`** (default: ON except for GCC<4.7) Enable compiling in C++11 mode for those parts that may require it. Parts that don't require it will still be compiled in C++03 mode, From 2da63dc284aca2a90e4d9a21080cc8bcdd27968e Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 13 Oct 2021 16:08:56 +0200 Subject: [PATCH 119/124] [build] Add Android build action to GitHub CI (#2149) Also corrected the 'build-android.sh' script. Co-authored-by: Sergei Ignatov --- .github/workflows/android.yaml | 26 ++++++++++++++++++++++++++ scripts/build-android/build-android | 16 ++++------------ 2 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/android.yaml diff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml new file mode 100644 index 000000000..3cdb0c79e --- /dev/null +++ b/.github/workflows/android.yaml @@ -0,0 +1,26 @@ +name: Android + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + name: NDK-R23 + runs-on: ubuntu-18.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@v2 + - name: build + run: | + cd ./scripts/build-android/ + echo ${{ steps.setup-ndk.outputs.ndk-path }} + source ./build-android -n ${{ steps.setup-ndk.outputs.ndk-path }} diff --git a/scripts/build-android/build-android b/scripts/build-android/build-android index f2d596847..b1c7363a9 100755 --- a/scripts/build-android/build-android +++ b/scripts/build-android/build-android @@ -10,7 +10,6 @@ echo_help() echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls" echo " -o OpenSSL version. E.g. 1.1.1l" echo " -m Mbed TLS version. E.g. v2.26.0" - echo " -s SRT version. E.g. v1.4.4" echo echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/23.0.7599858 -a 28 -t \"arm64-v8a x86_64\"" echo @@ -21,7 +20,6 @@ NDK_ROOT="" API_LEVEL=28 BUILD_TARGETS="armeabi-v7a arm64-v8a x86 x86_64" OPENSSL_VERSION=1.1.1l -SRT_VERSION="" ENC_LIB=openssl MBEDTLS_VERSION=v2.26.0 @@ -56,10 +54,8 @@ SCRIPT_DIR=$(pwd) HOST_TAG='unknown' unamestr=$(uname -s) if [ "$unamestr" = 'Linux' ]; then - SCRIPT_DIR=$(readlink -f $0 | xargs dirname) HOST_TAG='linux-x86_64' elif [ "$unamestr" = 'Darwin' ]; then - SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) if [ $(uname -p) = 'arm' ]; then echo "NDK does not currently support ARM64" exit 128 @@ -93,12 +89,8 @@ else exit 128 fi -if [ ! -d $BASE_DIR/srt ]; then - git clone https://github.com/Haivision/srt srt - if [ ! -z "$SRT_VERSION" ]; then - git -C $BASE_DIR/srt checkout $SRT_VERSION - fi -fi +# Build working copy of srt repository +REPO_DIR="../.." for build_target in $BUILD_TARGETS; do LIB_DIR=$BASE_DIR/$build_target/lib @@ -113,7 +105,7 @@ for build_target in $BUILD_TARGETS; do cp $LIB_DIR/libmbedx509.so $JNI_DIR/libmbedx509.so fi - git -C $BASE_DIR/srt clean -fd - $SCRIPT_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $BASE_DIR/srt -i $BASE_DIR/$build_target + git -C $REPO_DIR clean -fd -e scripts + $SCRIPT_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $REPO_DIR -i $BASE_DIR/$build_target cp $LIB_DIR/libsrt.so $JNI_DIR/libsrt.so done From 8bcf30bfd8f1a85d2147ae930f9eed5c1467076d Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 13 Oct 2021 12:43:25 +0200 Subject: [PATCH 120/124] [tests] More RCV buffer unit tests --- test/test_buffer.cpp | 253 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 242 insertions(+), 11 deletions(-) diff --git a/test/test_buffer.cpp b/test/test_buffer.cpp index d2e7b39f6..a08aa2406 100644 --- a/test/test_buffer.cpp +++ b/test/test_buffer.cpp @@ -1,20 +1,23 @@ #include #include "gtest/gtest.h" #include "buffer.h" +#include using namespace srt; +using namespace std; - +// Check the available size of the receiver buffer. TEST(CRcvBuffer, Create) { const int buffer_size_pkts = 128; CUnitQueue unit_queue; CRcvBuffer rcv_buffer(&unit_queue, buffer_size_pkts); - - EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size_pkts - 1); // logic + // One buffer cell is always unavailable as it is use to distinguish + // two buffer states: empty and full. + EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size_pkts - 1); } - +// Fill the buffer full, and check adding more data results in an error. TEST(CRcvBuffer, FullBuffer) { const int buffer_size_pkts = 16; @@ -51,10 +54,10 @@ TEST(CRcvBuffer, FullBuffer) } } - +// BUG!!! // In this test case a packet is added to receiver buffer with offset 1, // thus leaving offset 0 with an empty pointer. -// The buffer sais it is not empty, and the data is available +// The buffer says it is not empty, and the data is available // to be read, but reading should cause error. TEST(CRcvBuffer, ReadDataIPE) { @@ -73,18 +76,19 @@ TEST(CRcvBuffer, ReadDataIPE) EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size_pkts - 1); EXPECT_FALSE(rcv_buffer.isRcvDataAvailable()); + + // BUG. Acknowledging an empty position must not result in a read-readiness. rcv_buffer.ackData(1); EXPECT_TRUE(rcv_buffer.isRcvDataAvailable()); + EXPECT_TRUE(rcv_buffer.isRcvDataReady()); EXPECT_EQ(rcv_buffer.getAvailBufSize(), buffer_size_pkts - 2); - - std::cerr << "Expecting IPE message: \n"; - std::array buff; + cerr << "Expecting IPE message: \n"; + array buff; const int res = rcv_buffer.readBuffer(buff.data(), buff.size()); EXPECT_EQ(res, -1); } - TEST(CRcvBuffer, ReadData) { const int buffer_size_pkts = 16; @@ -112,7 +116,6 @@ TEST(CRcvBuffer, ReadData) EXPECT_EQ(size_t(res), payload_size); } - TEST(CRcvBuffer, AddData) { const int buffer_size_pkts = 16; @@ -159,4 +162,232 @@ TEST(CRcvBuffer, AddData) EXPECT_EQ(rcv_buffer.addData(unit, 1), -1); } +TEST(CRcvBuffer, OneMessageInSeveralPackets) +{ + const int buffer_size_pkts = 16; + CUnitQueue unit_queue; + unit_queue.init(buffer_size_pkts, 1500, AF_INET); + CRcvBuffer rcv_buffer(&unit_queue, buffer_size_pkts); + + const int initial_seqno = 1000; + const int message_len_in_pkts = 4; + const size_t payload_size = 1456; + // Add a number of units (packets) to the buffer + // equal to the buffer size in packets + for (int i = 0; i < message_len_in_pkts; ++i) + { + CUnit* unit = unit_queue.getNextAvailUnit(); + EXPECT_NE(unit, nullptr); + + CPacket& packet = unit->m_Packet; + packet.setLength(payload_size); + packet.m_iSeqNo = initial_seqno + i; + packet.m_iMsgNo = PacketBoundaryBits(PB_SUBSEQUENT); + if (i == 0) + packet.m_iMsgNo |= PacketBoundaryBits(PB_FIRST); + const bool is_last_packet = (i == message_len_in_pkts - 1); + if (is_last_packet) + packet.m_iMsgNo |= PacketBoundaryBits(PB_LAST); + + EXPECT_EQ(rcv_buffer.addData(unit, i), 0); + } + + rcv_buffer.ackData(message_len_in_pkts); + + cout << "Buffer size before reading: " << rcv_buffer.getAvailBufSize() << endl; + std::array buff; + cout << "Reading one packet of the 4-packet message" << endl; + const int res = rcv_buffer.readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, payload_size); + cout << "Buffer size after reading: " << rcv_buffer.getAvailBufSize() << endl; +} + +class TestRcvBufferRead + : public ::testing::Test +{ +protected: + TestRcvBufferRead() + { + // initialization code here + } + + ~TestRcvBufferRead() + { + // cleanup any pending stuff, but no exceptions allowed + } +protected: + // SetUp() is run immediately before a test starts. + void SetUp() override + { + // make_unique is unfortunatelly C++14 + m_unit_queue = unique_ptr(new CUnitQueue); + m_unit_queue->init(m_buff_size_pkts, 1500, AF_INET); + m_rcv_buffer = unique_ptr(new CRcvBuffer(m_unit_queue.get(), m_buff_size_pkts)); + } + + void TearDown() override + { + // Code here will be called just after the test completes. + // OK to throw exceptions from here if needed. + m_unit_queue.reset(); + m_rcv_buffer.reset(); + } + +public: + void addMessage(size_t msg_len_pkts, int start_seqno, bool out_of_order = false) + { + const int msg_offset = start_seqno - m_init_seqno; + + for (size_t i = 0; i < msg_len_pkts; ++i) + { + CUnit* unit = m_unit_queue->getNextAvailUnit(); + EXPECT_NE(unit, nullptr); + + CPacket& packet = unit->m_Packet; + packet.setLength(m_payload_sz); + packet.m_iSeqNo = start_seqno + i; + packet.m_iMsgNo = PacketBoundaryBits(PB_SUBSEQUENT); + if (i == 0) + packet.m_iMsgNo |= PacketBoundaryBits(PB_FIRST); + const bool is_last_packet = (i == (msg_len_pkts - 1)); + if (is_last_packet) + packet.m_iMsgNo |= PacketBoundaryBits(PB_LAST); + + if (!out_of_order) + { + packet.m_iMsgNo |= MSGNO_PACKET_INORDER::wrap(1); + EXPECT_TRUE(packet.getMsgOrderFlag()); + } + + EXPECT_EQ(m_rcv_buffer->addData(unit, msg_offset + i), 0); + } + } + +protected: + unique_ptr m_unit_queue; + unique_ptr m_rcv_buffer; + const int m_buff_size_pkts = 16; + const int m_init_seqno = 1000; + static const size_t m_payload_sz = 1456; +}; + +TEST_F(TestRcvBufferRead, OnePacket) +{ + const size_t msg_pkts = 1; + // Adding one message without acknowledging + addMessage(msg_pkts, m_init_seqno, false); + + const size_t msg_bytelen = msg_pkts * m_payload_sz; + array buff; + + EXPECT_FALSE(m_rcv_buffer->isRcvDataAvailable()); + + int res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, 0); + + // Full ACK + m_rcv_buffer->ackData(msg_pkts); + + EXPECT_TRUE(m_rcv_buffer->isRcvDataAvailable()); + + res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, msg_bytelen); +} + +TEST_F(TestRcvBufferRead, OnePacketWithGap) +{ + const size_t msg_pkts = 1; + // Adding one message without acknowledging + addMessage(msg_pkts, m_init_seqno + 1, false); + + const size_t msg_bytelen = msg_pkts * m_payload_sz; + array buff; + + EXPECT_FALSE(m_rcv_buffer->isRcvDataAvailable()); + + int res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, 0); + + // ACK first missing packet + m_rcv_buffer->ackData(msg_pkts); + + EXPECT_TRUE(m_rcv_buffer->isRcvDataAvailable()); + + res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, 0); + + m_rcv_buffer->ackData(msg_pkts); + EXPECT_TRUE(m_rcv_buffer->isRcvDataAvailable()); + + res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, msg_bytelen); +} + +// Check reading the whole message (consisting of several packets) from the buffer. +TEST_F(TestRcvBufferRead, MsgAcked) +{ + const size_t msg_pkts = 4; + // Adding one message without acknowledging + addMessage(msg_pkts, m_init_seqno, false); + + const size_t msg_bytelen = msg_pkts * m_payload_sz; + array buff; + + // Acknowledge all packets of the message. + m_rcv_buffer->ackData(4); + // Now the whole message can be read. + EXPECT_TRUE(m_rcv_buffer->isRcvDataReady()); + EXPECT_TRUE(m_rcv_buffer->isRcvDataAvailable()); + const int res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, msg_bytelen); +} + +// BUG!!! +// Checks signalling of read-readiness of a half-acknowledged message. +// The RCV buffer implementation has an issue here: when only half of the message is +// acknowledged, the RCV buffer signals read-readiness, even though +// the message can't be read, and reading returns 0. +TEST_F(TestRcvBufferRead, MsgHalfAck) +{ + const size_t msg_pkts = 4; + // Adding one message without acknowledging + addMessage(msg_pkts, m_init_seqno, false); + + // Nothing to read (0 for zero bytes read). + const size_t msg_bytelen = msg_pkts * m_payload_sz; + array buff; + EXPECT_FALSE(m_rcv_buffer->isRcvDataReady()); + EXPECT_FALSE(m_rcv_buffer->isRcvDataAvailable()); + int res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, 0); + + // ACK half of the message and check read-readiness. + m_rcv_buffer->ackData(2); + // FIXME: Sadly RCV buffer says the data is ready to be read. + // EXPECT_FALSE(m_rcv_buffer->isRcvDataReady()); + // EXPECT_FALSE(m_rcv_buffer->isRcvDataAvailable()); + EXPECT_TRUE(m_rcv_buffer->isRcvDataReady()); + EXPECT_TRUE(m_rcv_buffer->isRcvDataAvailable()); + + // Actually must be nothing to read (can't read half a message). + res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, 0); +} + +// BUG!!! +// Adding a message with the out-of-order flag set. +// RCV buffer does not signal read-readiness, but actually the packet can be read. +TEST_F(TestRcvBufferRead, OutOfOrderMsgNoACK) +{ + const size_t msg_pkts = 4; + // Adding one message with the Out-Of-Order flag set, but without acknowledging. + addMessage(msg_pkts, m_init_seqno, true); + + EXPECT_FALSE(m_rcv_buffer->isRcvDataReady()); + EXPECT_FALSE(m_rcv_buffer->isRcvDataAvailable()); + const size_t msg_bytelen = msg_pkts * m_payload_sz; + array buff; + const int res = m_rcv_buffer->readMsg(buff.data(), buff.size()); + EXPECT_EQ(res, msg_bytelen); +} From 6e896399e3b4fdf09bd11179ecd02145727fd5ee Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Wed, 13 Oct 2021 16:07:42 +0200 Subject: [PATCH 121/124] [tests] Fixed async launch TestConnection.Multiple --- test/test_many_connections.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_many_connections.cpp b/test/test_many_connections.cpp index 52d9be773..759b6a461 100644 --- a/test/test_many_connections.cpp +++ b/test/test_many_connections.cpp @@ -79,8 +79,6 @@ class TestConnection std::uniform_int_distribution dis(-128, 127); std::generate(m_buf.begin(), m_buf.end(), [dis, gen]() mutable { return (char)dis(gen); }); - cout << "Generated: " << static_cast(m_buf[0]) << ", " << static_cast(m_buf[1]) << std::endl; - ASSERT_NE(srt_listen(m_server_sock, NSOCK), -1); } @@ -135,7 +133,7 @@ TEST_F(TestConnection, Multiple) const sockaddr_in lsa = m_sa; const sockaddr* psa = reinterpret_cast(&lsa); - auto ex = std::async([this] { return AcceptLoop(); }); + auto ex = std::async(std::launch::async, [this] { return AcceptLoop(); }); cerr << "Opening " << NSOCK << " connections\n"; @@ -180,6 +178,7 @@ TEST_F(TestConnection, Multiple) cerr << "Synchronize with the accepting thread\n"; ex.wait(); + cerr << "Synchronization done\n"; } From a5b61db5b8e2e6f906665e31d7ec8179175846ed Mon Sep 17 00:00:00 2001 From: Thierry Lelegard Date: Mon, 18 Oct 2021 09:30:06 +0200 Subject: [PATCH 122/124] [build] Fixed missing ws2_32 lib in Windows installer (#2169) The property file libsrt.props did not reference ws2_32.lib. For large applications which already reference the Windows socket library, there is no difference. In small test applications which reference libsrt only, there were undefined symbols. --- scripts/win-installer/libsrt.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/win-installer/libsrt.props b/scripts/win-installer/libsrt.props index 01e0b5dac..b1da74879 100644 --- a/scripts/win-installer/libsrt.props +++ b/scripts/win-installer/libsrt.props @@ -29,7 +29,7 @@ $(LIBSRT)\include;%(AdditionalIncludeDirectories) - srt.lib;libssl.lib;libcrypto.lib;crypt32.lib;%(AdditionalDependencies) + srt.lib;libssl.lib;libcrypto.lib;crypt32.lib;ws2_32.lib;%(AdditionalDependencies) $(LIBSRT)\lib\$(Configuration)-$(SrtPlatform);%(AdditionalLibraryDirectories) /ignore:4099 %(AdditionalOptions) From c1fdb61292358c604cb956fef3d6e768d7e43be6 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 18 Oct 2021 15:47:14 +0200 Subject: [PATCH 123/124] [core] Changed lock order in bstats (#2168) --- srtcore/core.cpp | 242 ++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 120 deletions(-) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index b3b1d374c..787533cea 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -7130,98 +7130,129 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) if (m_bBroken || m_bClosing) throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0); - ScopedLock statsguard(m_StatsLock); - - const steady_clock::time_point currtime = steady_clock::now(); - - perf->msTimeStamp = count_milliseconds(currtime - m_stats.tsStartTime); - perf->pktSent = m_stats.traceSent; - perf->pktSentUnique = m_stats.traceSentUniq; - perf->pktRecv = m_stats.traceRecv; - perf->pktRecvUnique = m_stats.traceRecvUniq; - perf->pktSndLoss = m_stats.traceSndLoss; - perf->pktRcvLoss = m_stats.traceRcvLoss; - perf->pktRetrans = m_stats.traceRetrans; - perf->pktRcvRetrans = m_stats.traceRcvRetrans; - perf->pktSentACK = m_stats.sentACK; - perf->pktRecvACK = m_stats.recvACK; - perf->pktSentNAK = m_stats.sentNAK; - perf->pktRecvNAK = m_stats.recvNAK; - perf->usSndDuration = m_stats.sndDuration; - perf->pktReorderDistance = m_stats.traceReorderDistance; - perf->pktReorderTolerance = m_iReorderTolerance; - perf->pktRcvAvgBelatedTime = m_stats.traceBelatedTime; - perf->pktRcvBelated = m_stats.traceRcvBelated; - - perf->pktSndFilterExtra = m_stats.sndFilterExtra; - perf->pktRcvFilterExtra = m_stats.rcvFilterExtra; - perf->pktRcvFilterSupply = m_stats.rcvFilterSupply; - perf->pktRcvFilterLoss = m_stats.rcvFilterLoss; - - /* perf byte counters include all headers (SRT+UDP+IP) */ const int pktHdrSize = CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE; - perf->byteSent = m_stats.traceBytesSent + (m_stats.traceSent * pktHdrSize); - perf->byteSentUnique = m_stats.traceBytesSentUniq + (m_stats.traceSentUniq * pktHdrSize); - perf->byteRecv = m_stats.traceBytesRecv + (m_stats.traceRecv * pktHdrSize); - perf->byteRecvUnique = m_stats.traceBytesRecvUniq + (m_stats.traceRecvUniq * pktHdrSize); - perf->byteRetrans = m_stats.traceBytesRetrans + (m_stats.traceRetrans * pktHdrSize); - perf->byteRcvLoss = m_stats.traceRcvBytesLoss + (m_stats.traceRcvLoss * pktHdrSize); - - perf->pktSndDrop = m_stats.traceSndDrop; - perf->pktRcvDrop = m_stats.traceRcvDrop + m_stats.traceRcvUndecrypt; - perf->byteSndDrop = m_stats.traceSndBytesDrop + (m_stats.traceSndDrop * pktHdrSize); - perf->byteRcvDrop = - m_stats.traceRcvBytesDrop + (m_stats.traceRcvDrop * pktHdrSize) + m_stats.traceRcvBytesUndecrypt; - perf->pktRcvUndecrypt = m_stats.traceRcvUndecrypt; - perf->byteRcvUndecrypt = m_stats.traceRcvBytesUndecrypt; - - perf->pktSentTotal = m_stats.sentTotal; - perf->pktSentUniqueTotal = m_stats.sentUniqTotal; - perf->pktRecvTotal = m_stats.recvTotal; - perf->pktRecvUniqueTotal = m_stats.recvUniqTotal; - perf->pktSndLossTotal = m_stats.sndLossTotal; - perf->pktRcvLossTotal = m_stats.rcvLossTotal; - perf->pktRetransTotal = m_stats.retransTotal; - perf->pktSentACKTotal = m_stats.sentACKTotal; - perf->pktRecvACKTotal = m_stats.recvACKTotal; - perf->pktSentNAKTotal = m_stats.sentNAKTotal; - perf->pktRecvNAKTotal = m_stats.recvNAKTotal; - perf->usSndDurationTotal = m_stats.m_sndDurationTotal; - - perf->byteSentTotal = m_stats.bytesSentTotal + (m_stats.sentTotal * pktHdrSize); - perf->byteSentUniqueTotal = m_stats.bytesSentUniqTotal + (m_stats.sentUniqTotal * pktHdrSize); - perf->byteRecvTotal = m_stats.bytesRecvTotal + (m_stats.recvTotal * pktHdrSize); - perf->byteRecvUniqueTotal = m_stats.bytesRecvUniqTotal + (m_stats.recvUniqTotal * pktHdrSize); - perf->byteRetransTotal = m_stats.bytesRetransTotal + (m_stats.retransTotal * pktHdrSize); - perf->pktSndFilterExtraTotal = m_stats.sndFilterExtraTotal; - perf->pktRcvFilterExtraTotal = m_stats.rcvFilterExtraTotal; - perf->pktRcvFilterSupplyTotal = m_stats.rcvFilterSupplyTotal; - perf->pktRcvFilterLossTotal = m_stats.rcvFilterLossTotal; - - perf->byteRcvLossTotal = m_stats.rcvBytesLossTotal + (m_stats.rcvLossTotal * pktHdrSize); - perf->pktSndDropTotal = m_stats.sndDropTotal; - perf->pktRcvDropTotal = m_stats.rcvDropTotal + m_stats.m_rcvUndecryptTotal; - perf->byteSndDropTotal = m_stats.sndBytesDropTotal + (m_stats.sndDropTotal * pktHdrSize); - perf->byteRcvDropTotal = - m_stats.rcvBytesDropTotal + (m_stats.rcvDropTotal * pktHdrSize) + m_stats.m_rcvBytesUndecryptTotal; - perf->pktRcvUndecryptTotal = m_stats.m_rcvUndecryptTotal; - perf->byteRcvUndecryptTotal = m_stats.m_rcvBytesUndecryptTotal; - - const double interval = (double) count_microseconds(currtime - m_stats.tsLastSampleTime); - perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval; - perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval; - perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval.load()); - perf->pktFlowWindow = m_iFlowWindowSize.load(); - perf->pktCongestionWindow = (int)m_dCongestionWindow; - perf->pktFlightSize = getFlightSpan(); - perf->msRTT = (double)m_iSRTT / 1000.0; - perf->msSndTsbPdDelay = m_bPeerTsbPd ? m_iPeerTsbPdDelay_ms : 0; - perf->msRcvTsbPdDelay = isOPT_TsbPd() ? m_iTsbPdDelay_ms : 0; - perf->byteMSS = m_config.iMSS; - - perf->mbpsMaxBW = m_config.llMaxBW > 0 ? Bps2Mbps(m_config.llMaxBW) - : m_CongCtl.ready() ? Bps2Mbps(m_CongCtl->sndBandwidth()) - : 0; + { + ScopedLock statsguard(m_StatsLock); + + const steady_clock::time_point currtime = steady_clock::now(); + + perf->msTimeStamp = count_milliseconds(currtime - m_stats.tsStartTime); + perf->pktSent = m_stats.traceSent; + perf->pktSentUnique = m_stats.traceSentUniq; + perf->pktRecv = m_stats.traceRecv; + perf->pktRecvUnique = m_stats.traceRecvUniq; + perf->pktSndLoss = m_stats.traceSndLoss; + perf->pktRcvLoss = m_stats.traceRcvLoss; + perf->pktRetrans = m_stats.traceRetrans; + perf->pktRcvRetrans = m_stats.traceRcvRetrans; + perf->pktSentACK = m_stats.sentACK; + perf->pktRecvACK = m_stats.recvACK; + perf->pktSentNAK = m_stats.sentNAK; + perf->pktRecvNAK = m_stats.recvNAK; + perf->usSndDuration = m_stats.sndDuration; + perf->pktReorderDistance = m_stats.traceReorderDistance; + perf->pktReorderTolerance = m_iReorderTolerance; + perf->pktRcvAvgBelatedTime = m_stats.traceBelatedTime; + perf->pktRcvBelated = m_stats.traceRcvBelated; + + perf->pktSndFilterExtra = m_stats.sndFilterExtra; + perf->pktRcvFilterExtra = m_stats.rcvFilterExtra; + perf->pktRcvFilterSupply = m_stats.rcvFilterSupply; + perf->pktRcvFilterLoss = m_stats.rcvFilterLoss; + + /* perf byte counters include all headers (SRT+UDP+IP) */ + perf->byteSent = m_stats.traceBytesSent + (m_stats.traceSent * pktHdrSize); + perf->byteSentUnique = m_stats.traceBytesSentUniq + (m_stats.traceSentUniq * pktHdrSize); + perf->byteRecv = m_stats.traceBytesRecv + (m_stats.traceRecv * pktHdrSize); + perf->byteRecvUnique = m_stats.traceBytesRecvUniq + (m_stats.traceRecvUniq * pktHdrSize); + perf->byteRetrans = m_stats.traceBytesRetrans + (m_stats.traceRetrans * pktHdrSize); + perf->byteRcvLoss = m_stats.traceRcvBytesLoss + (m_stats.traceRcvLoss * pktHdrSize); + + perf->pktSndDrop = m_stats.traceSndDrop; + perf->pktRcvDrop = m_stats.traceRcvDrop + m_stats.traceRcvUndecrypt; + perf->byteSndDrop = m_stats.traceSndBytesDrop + (m_stats.traceSndDrop * pktHdrSize); + perf->byteRcvDrop = + m_stats.traceRcvBytesDrop + (m_stats.traceRcvDrop * pktHdrSize) + m_stats.traceRcvBytesUndecrypt; + perf->pktRcvUndecrypt = m_stats.traceRcvUndecrypt; + perf->byteRcvUndecrypt = m_stats.traceRcvBytesUndecrypt; + + perf->pktSentTotal = m_stats.sentTotal; + perf->pktSentUniqueTotal = m_stats.sentUniqTotal; + perf->pktRecvTotal = m_stats.recvTotal; + perf->pktRecvUniqueTotal = m_stats.recvUniqTotal; + perf->pktSndLossTotal = m_stats.sndLossTotal; + perf->pktRcvLossTotal = m_stats.rcvLossTotal; + perf->pktRetransTotal = m_stats.retransTotal; + perf->pktSentACKTotal = m_stats.sentACKTotal; + perf->pktRecvACKTotal = m_stats.recvACKTotal; + perf->pktSentNAKTotal = m_stats.sentNAKTotal; + perf->pktRecvNAKTotal = m_stats.recvNAKTotal; + perf->usSndDurationTotal = m_stats.m_sndDurationTotal; + + perf->byteSentTotal = m_stats.bytesSentTotal + (m_stats.sentTotal * pktHdrSize); + perf->byteSentUniqueTotal = m_stats.bytesSentUniqTotal + (m_stats.sentUniqTotal * pktHdrSize); + perf->byteRecvTotal = m_stats.bytesRecvTotal + (m_stats.recvTotal * pktHdrSize); + perf->byteRecvUniqueTotal = m_stats.bytesRecvUniqTotal + (m_stats.recvUniqTotal * pktHdrSize); + perf->byteRetransTotal = m_stats.bytesRetransTotal + (m_stats.retransTotal * pktHdrSize); + perf->pktSndFilterExtraTotal = m_stats.sndFilterExtraTotal; + perf->pktRcvFilterExtraTotal = m_stats.rcvFilterExtraTotal; + perf->pktRcvFilterSupplyTotal = m_stats.rcvFilterSupplyTotal; + perf->pktRcvFilterLossTotal = m_stats.rcvFilterLossTotal; + + perf->byteRcvLossTotal = m_stats.rcvBytesLossTotal + (m_stats.rcvLossTotal * pktHdrSize); + perf->pktSndDropTotal = m_stats.sndDropTotal; + perf->pktRcvDropTotal = m_stats.rcvDropTotal + m_stats.m_rcvUndecryptTotal; + perf->byteSndDropTotal = m_stats.sndBytesDropTotal + (m_stats.sndDropTotal * pktHdrSize); + perf->byteRcvDropTotal = + m_stats.rcvBytesDropTotal + (m_stats.rcvDropTotal * pktHdrSize) + m_stats.m_rcvBytesUndecryptTotal; + perf->pktRcvUndecryptTotal = m_stats.m_rcvUndecryptTotal; + perf->byteRcvUndecryptTotal = m_stats.m_rcvBytesUndecryptTotal; + + // TODO: The following class members must be protected with a different mutex, not the m_StatsLock. + const double interval = (double) count_microseconds(currtime - m_stats.tsLastSampleTime); + perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval; + perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval; + perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval.load()); + perf->pktFlowWindow = m_iFlowWindowSize.load(); + perf->pktCongestionWindow = (int)m_dCongestionWindow; + perf->pktFlightSize = getFlightSpan(); + perf->msRTT = (double)m_iSRTT / 1000.0; + perf->msSndTsbPdDelay = m_bPeerTsbPd ? m_iPeerTsbPdDelay_ms : 0; + perf->msRcvTsbPdDelay = isOPT_TsbPd() ? m_iTsbPdDelay_ms : 0; + perf->byteMSS = m_config.iMSS; + + perf->mbpsMaxBW = m_config.llMaxBW > 0 ? Bps2Mbps(m_config.llMaxBW) + : m_CongCtl.ready() ? Bps2Mbps(m_CongCtl->sndBandwidth()) + : 0; + + if (clear) + { + m_stats.traceSndDrop = 0; + m_stats.traceRcvDrop = 0; + m_stats.traceSndBytesDrop = 0; + m_stats.traceRcvBytesDrop = 0; + m_stats.traceRcvUndecrypt = 0; + m_stats.traceRcvBytesUndecrypt = 0; + m_stats.traceBytesSent = m_stats.traceBytesRecv = m_stats.traceBytesRetrans = 0; + m_stats.traceBytesSentUniq = m_stats.traceBytesRecvUniq = 0; + m_stats.traceSent = m_stats.traceRecv + = m_stats.traceSentUniq = m_stats.traceRecvUniq + = m_stats.traceSndLoss = m_stats.traceRcvLoss = m_stats.traceRetrans + = m_stats.sentACK = m_stats.recvACK = m_stats.sentNAK = m_stats.recvNAK = 0; + m_stats.sndDuration = 0; + m_stats.traceRcvRetrans = 0; + m_stats.traceRcvBelated = 0; + m_stats.traceRcvBytesLoss = 0; + + m_stats.sndFilterExtra = 0; + m_stats.rcvFilterExtra = 0; + + m_stats.rcvFilterSupply = 0; + m_stats.rcvFilterLoss = 0; + + m_stats.tsLastSampleTime = currtime; + } + } const int64_t availbw = m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth.load(); @@ -7242,7 +7273,6 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) perf->pktSndBuf = m_pSndBuffer->getAvgBufSize((perf->byteSndBuf), (perf->msSndBuf)); } perf->byteSndBuf += (perf->pktSndBuf * pktHdrSize); - //< perf->byteAvailSndBuf = (m_config.iSndBufSize - perf->pktSndBuf) * m_config.iMSS; } else @@ -7285,34 +7315,6 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) perf->byteRcvBuf = 0; perf->msRcvBuf = 0; } - - if (clear) - { - m_stats.traceSndDrop = 0; - m_stats.traceRcvDrop = 0; - m_stats.traceSndBytesDrop = 0; - m_stats.traceRcvBytesDrop = 0; - m_stats.traceRcvUndecrypt = 0; - m_stats.traceRcvBytesUndecrypt = 0; - m_stats.traceBytesSent = m_stats.traceBytesRecv = m_stats.traceBytesRetrans = 0; - m_stats.traceBytesSentUniq = m_stats.traceBytesRecvUniq = 0; - m_stats.traceSent = m_stats.traceRecv - = m_stats.traceSentUniq = m_stats.traceRecvUniq - = m_stats.traceSndLoss = m_stats.traceRcvLoss = m_stats.traceRetrans - = m_stats.sentACK = m_stats.recvACK = m_stats.sentNAK = m_stats.recvNAK = 0; - m_stats.sndDuration = 0; - m_stats.traceRcvRetrans = 0; - m_stats.traceRcvBelated = 0; - m_stats.traceRcvBytesLoss = 0; - - m_stats.sndFilterExtra = 0; - m_stats.rcvFilterExtra = 0; - - m_stats.rcvFilterSupply = 0; - m_stats.rcvFilterLoss = 0; - - m_stats.tsLastSampleTime = currtime; - } } bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg) From 3f2945caff59c50e1e66c5719e473aea5f8ad4e0 Mon Sep 17 00:00:00 2001 From: Maxim Sharabayko Date: Mon, 18 Oct 2021 18:45:28 +0200 Subject: [PATCH 124/124] [core] Reduced nesting of checkBrokenSockets() --- srtcore/api.cpp | 106 ++++++++++++++++++++++-------------------------- srtcore/core.h | 3 +- 2 files changed, 51 insertions(+), 58 deletions(-) diff --git a/srtcore/api.cpp b/srtcore/api.cpp index e35d637a5..59399a4b3 100644 --- a/srtcore/api.cpp +++ b/srtcore/api.cpp @@ -2572,10 +2572,6 @@ void srt::CUDTUnited::checkBrokenSockets() { ScopedLock cg(m_GlobControlLock); - // set of sockets To Be Closed and To Be Removed - vector tbc; - vector tbr; - #if ENABLE_EXPERIMENTAL_BONDING vector delgids; @@ -2600,74 +2596,70 @@ void srt::CUDTUnited::checkBrokenSockets() { m_ClosedGroups.erase(*di); } - #endif - for (sockets_t::iterator i = m_Sockets.begin(); - i != m_Sockets.end(); ++ i) + // set of sockets To Be Closed and To Be Removed + vector tbc; + vector tbr; + + for (sockets_t::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++ i) { - CUDTSocket* s = i->second; + CUDTSocket* s = i->second; + if (!s->core().m_bBroken) + continue; - // check broken connection - if (s->core().m_bBroken) + if (s->m_Status == SRTS_LISTENING) { - if (s->m_Status == SRTS_LISTENING) - { - const steady_clock::duration elapsed = steady_clock::now() - s->m_tsClosureTimeStamp; - // for a listening socket, it should wait an extra 3 seconds - // in case a client is connecting - if (elapsed < milliseconds_from(CUDT::COMM_CLOSE_BROKEN_LISTENER_TIMEOUT_MS)) + const steady_clock::duration elapsed = steady_clock::now() - s->m_tsClosureTimeStamp; + // A listening socket should wait an extra 3 seconds + // in case a client is connecting. + if (elapsed < milliseconds_from(CUDT::COMM_CLOSE_BROKEN_LISTENER_TIMEOUT_MS)) + continue; + } + else if ((s->core().m_pRcvBuffer != NULL) + // FIXED: calling isRcvDataAvailable() just to get the information + // whether there are any data waiting in the buffer, + // NOT WHETHER THEY ARE ALSO READY TO PLAY at the time when + // this function is called (isRcvDataReady also checks if the + // available data is "ready to play"). + && s->core().m_pRcvBuffer->isRcvDataAvailable()) + { + const int bc = s->core().m_iBrokenCounter.load(); + if (bc > 0) { + // if there is still data in the receiver buffer, wait longer + s->core().m_iBrokenCounter.store(bc - 1); continue; } - } - else if ((s->core().m_pRcvBuffer != NULL) - // FIXED: calling isRcvDataAvailable() just to get the information - // whether there are any data waiting in the buffer, - // NOT WHETHER THEY ARE ALSO READY TO PLAY at the time when - // this function is called (isRcvDataReady also checks if the - // available data is "ready to play"). - && s->core().m_pRcvBuffer->isRcvDataAvailable()) - { - const int bc = s->core().m_iBrokenCounter.load(); - if (bc > 0) - { - // HLOGF(smlog.Debug, "STILL KEEPING socket (still have data): - // %d\n", i->first); - // if there is still data in the receiver buffer, wait longer - s->core().m_iBrokenCounter.store(bc - 1); - continue; - } - } + } #if ENABLE_EXPERIMENTAL_BONDING - if (s->m_GroupOf) - { - LOGC(smlog.Note, log << "@" << s->m_SocketID << " IS MEMBER OF $" << s->m_GroupOf->id() << " - REMOVING FROM GROUP"); - s->removeFromGroup(true); - } + if (s->m_GroupOf) + { + LOGC(smlog.Note, log << "@" << s->m_SocketID << " IS MEMBER OF $" << s->m_GroupOf->id() << " - REMOVING FROM GROUP"); + s->removeFromGroup(true); + } #endif - HLOGC(smlog.Debug, log << "checkBrokenSockets: moving BROKEN socket to CLOSED: @" << i->first); + HLOGC(smlog.Debug, log << "checkBrokenSockets: moving BROKEN socket to CLOSED: @" << i->first); - //close broken connections and start removal timer - s->setClosed(); - tbc.push_back(i->first); - m_ClosedSockets[i->first] = s; + //close broken connections and start removal timer + s->setClosed(); + tbc.push_back(i->first); + m_ClosedSockets[i->first] = s; - // remove from listener's queue - sockets_t::iterator ls = m_Sockets.find(s->m_ListenSocket); - if (ls == m_Sockets.end()) - { - ls = m_ClosedSockets.find(s->m_ListenSocket); - if (ls == m_ClosedSockets.end()) - continue; - } - - enterCS(ls->second->m_AcceptLock); - ls->second->m_QueuedSockets.erase(s->m_SocketID); - leaveCS(ls->second->m_AcceptLock); + // remove from listener's queue + sockets_t::iterator ls = m_Sockets.find(s->m_ListenSocket); + if (ls == m_Sockets.end()) + { + ls = m_ClosedSockets.find(s->m_ListenSocket); + if (ls == m_ClosedSockets.end()) + continue; } + + enterCS(ls->second->m_AcceptLock); + ls->second->m_QueuedSockets.erase(s->m_SocketID); + leaveCS(ls->second->m_AcceptLock); } for (sockets_t::iterator j = m_ClosedSockets.begin(); diff --git a/srtcore/core.h b/srtcore/core.h index 2bbc7b069..523118fce 100644 --- a/srtcore/core.h +++ b/srtcore/core.h @@ -749,7 +749,8 @@ class CUDT sync::atomic m_bPeerHealth; // If the peer status is normal sync::atomic m_RejectReason; bool m_bOpened; // If the UDT entity has been opened - sync::atomic m_iBrokenCounter; // A counter (number of GC checks) to let the GC tag this socket as disconnected + // A counter (number of GC checks happening every 1s) to let the GC tag this socket as closed. + sync::atomic m_iBrokenCounter; // If a broken socket still has data in the receiver buffer, it is not marked closed until the counter is 0. int m_iEXPCount; // Expiration counter sync::atomic m_iBandwidth; // Estimated bandwidth, number of packets per second