{"base_revision":"git-v1:b65fc42932cacde807f4923d3cbae99c18b23546","content":"diff --git a/.github/blocked-workflows/ubuntu-c++11-crypto.yml b/.github/blocked-workflows/ubuntu-c++11-crypto.yml\ndeleted file mode 100644\nindex bfe62a8..0000000\n--- a/.github/blocked-workflows/ubuntu-c++11-crypto.yml\n+++ /dev/null\n@@ -1,37 +0,0 @@\n-name: Linux\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-    types: [opened, synchronize, reopened]\n-jobs:\n-  build:\n-    strategy:\n-      matrix:\n-        crypto: [OFF, openssl, openssl-evp, gnutls, mbedtls, botan]\n-\n-    name: Build Crypto=${{ matrix.crypto }} C++11\n-    runs-on: [ubuntu-latest, ubuntu-slim, ubuntu-24.04-arm]\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: Configure packages and system\n-      run: |\n-        sudo apt install -y tcl cmake libssl-dev libgnutls28-dev libmbedtls-dev libbotan-2-dev gdb\n-        echo \"core.%e\" | sudo tee /proc/sys/kernel/core_pattern\n-    - name: Configure\n-      run: |\n-        mkdir _build && cd _build\n-        if [[ ${{ matrix.crypto }} != OFF ]]; then CRYPTO_OPTIONS=-DUSE_ENCLIB=${{ matrix.crypto }}; else CRYPTO_OPTIONS=-DENABLE_ENCRYPTION=OFF; fi\n-        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DUSE_CXX_STD=11 -DENABLE_STDCXX_SYNC=ON $CRYPTO_OPTIONS -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_HEAVY_LOGGING=ON  -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DENABLE_CODE_COVERAGE=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n-    - name: Build\n-      run: cd _build && make -j -k\n-    - name: test\n-      run: |\n-        ulimit -c unlimited\n-        cd _build && ctest --extra-verbose\n-        SUCCESS=$?\n-        if [ -f core.test-srt ]; then gdb -batch ./test-srt -c core -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n-        test $SUCCESS == 0;\n-        \ndiff --git a/.github/blocked-workflows/ubuntu-matrix.yml b/.github/blocked-workflows/ubuntu-matrix.yml\ndeleted file mode 100644\nindex c820e59..0000000\n--- a/.github/blocked-workflows/ubuntu-matrix.yml\n+++ /dev/null\n@@ -1,67 +0,0 @@\n-name: Linux\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-    types: [opened, synchronize, reopened]\n-jobs:\n-  build_options:\n-    strategy:\n-      matrix:\n-        cxxstdsync: [OFF, ON]\n-        logging:  [OFF, ON]\n-        bonding: [OFF, ON]\n-        cxxstd: [\"03\", \"11\"]\n-        exclude:\n-          - cxxstd: \"11\"\n-            logging: ON\n-            bonding: ON\n-          - cxxstd: \"03\"\n-            cxxstdsync: ON\n-            bonding: OFF\n-    name: Build C++${{ matrix.cxxstd }} C++sync=${{ matrix.cxxstdsync }} Bonding=${{ matrix.bonding }} Logging=${{ matrix.logging }}\n-    runs-on: [ubuntu-latest, ubuntu-slim, ubuntu-24.04-arm]\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: Configure packages and system\n-      run: |\n-        sudo apt install -y tcl cmake libssl-dev libmbedtls-dev libbotan-2-dev gdb\n-        echo \"core.%e\" | sudo tee /proc/sys/kernel/core_pattern\n-    - name: Configure\n-      run: |\n-        mkdir _build && cd _build\n-        # NOTE > Crypto options are default - enabled, openssl\n-        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DUSE_CXX_STD=${{ matrix.cxxstd }} -DENABLE_STDCXX_SYNC=${{ matrix.cxxstdsync }} -DENABLE_UNITTESTS=ON -DENABLE_BONDING=${{ matrix.bonding }} -DENABLE_LOGGING=${{ matrix.logging }} -DENABLE_HEAVY_LOGGING=${{ matrix.logging }} -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DENABLE_CODE_COVERAGE=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n-    - name: Build\n-      run: cd _build && make -j -k\n-    - name: test\n-      run: |\n-        ulimit -c unlimited\n-        cd _build && ctest --extra-verbose\n-        SUCCESS=$?\n-        if [ -f core.test-srt ]; then gdb -batch ./test-srt -c core -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n-        test $SUCCESS == 0;\n-        \n-    - name: codecov\n-      run: |\n-        source ./scripts/collect-gcov.sh\n-        bash <(curl -s https://codecov.io/bash)\n-    \n-  build_mingw:                                                                                                         \n-    name: Build Mingw32\n-    runs-on: ubuntu-latest\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: Dependencies\n-      run: |\n-        sudo apt install -y g++-mingw-w64-x86-64-posix gcc-mingw-w64-x86-64-posix\n-    - name: Configure\n-      run: |\n-        mkdir _build && cd _build\n-        export CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix \n-        # NOTE > Temporarily blocked encryption due to problems with enclib\n-        cmake .. -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=OFF -DUSE_OPENSSL_PC=OFF -DCMAKE_SYSTEM_NAME=Windows\n-    - name: Build\n-      run: cd _build && make -j -k\ndiff --git a/.github/workflows/abi.yml b/.github/workflows/abi.yml\nindex 846dbbb..2c05cc0 100644\n--- a/.github/workflows/abi.yml\n+++ b/.github/workflows/abi.yml\n@@ -2,152 +2,60 @@ name: ABI checks\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n \n env:\n   SRT_BASE: v1.5.0\n \n jobs:\n-  build_pr:\n-    name: Build current version\n-    runs-on: ubuntu-latest\n+  build:\n+    name: ABI checks\n+    runs-on: ubuntu-20.04\n \n-    outputs:\n-       base_version: ${{ steps.build.outputs.SRT_BASE }}\n-       tag_version: ${{ steps.build.outputs.SRT_TAG_VERSION }}\n     steps:\n     - uses: actions/checkout@v3\n       with:\n-        path: gitview_pr\n-    - id: configure\n-      name: Configure (cmake)\n+        path: pull_request\n+    - name: configure\n       run: |\n-        cd gitview_pr\n+        cd pull_request\n         mkdir _build && cd _build\n-        cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_BONDING=1 -DENABLE_PKTINFO=1 -DENABLE_MAXREXMITBW=1 ../\n-    - id: build\n-      name: Build and dump\n+        cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITTESTS=ON ../\n+    - name: build\n       run: |\n-        sudo apt install -y abi-dumper abi-compliance-checker tcl\n-        cd gitview_pr\n-        cd _build && cmake --build ./\n+        sudo apt install -y abi-dumper\n+        cd pull_request/_build && cmake --build ./\n         make install DESTDIR=./installdir\n-        SRT_TAG_VERSION=v$(../scripts/get-build-version.tcl full)\n-        echo \"SRT_TAG_VERSION=$SRT_TAG_VERSION\" >> \"$GITHUB_OUTPUT\"\n-        SRT_TAG=${SRT_TAG_VERSION}dev-$(git rev-parse --short HEAD)\n-        echo \"TAGGING PR BUILD: $SRT_TAG\"\n-        abi-dumper libsrt.so -o libsrt-pr.dump -public-headers installdir/usr/local/include/srt/ -lver $SRT_TAG\n-        ls -ld libsrt-pr.dump\n-        sha256sum libsrt-pr.dump\n-        SRT_BASE=v$(../scripts/get-build-version.tcl base)\n-        if [[ $SRT_TAG_VERSION == $SRT_BASE ]]; then\n-            echo \"NOT CHECKING ABI: base version is being built: $SRT_TAG  (not emitting SRT_BASE)\"\n-            #echo \"SRT_BASE=''\" >> \"$GITHUB_OUTPUT\"\n-        else\n-            echo \"WILL CHECK ABI changes $SRT_BASE - $SRT_TAG_VERSION\"\n-            echo \"SRT_BASE=$SRT_BASE\" >> \"$GITHUB_OUTPUT\"\n-        fi\n-        echo \"--- GITHUB_OUTPUT ---\"\n-        cat $GITHUB_OUTPUT\n-        echo \"---------------------\"\n-    - id: upload_pr_dump\n-      uses: actions/upload-artifact@v4\n-      with:\n-        name: abidump_pr\n-        path: gitview_pr/_build/libsrt-pr.dump\n-\n-  build_base:\n-    name: Build base version\n-    runs-on: ubuntu-latest\n-    needs: build_pr\n-    if: ${{ needs.build_pr.outputs.base_version != '' }}\n-\n-    env:\n-       SRT_BASE: ${{ needs.build_pr.outputs.base_version }}\n-       SRT_TAG_VERSION: ${{ needs.build_pr.outputs.tag_version }}\n-    steps:\n+        SRT_TAG_VERSION=$(cat version.h |grep SRT_VERSION_MINOR |head -n1 |awk {'print $3'})\n+        abi-dumper libsrt.so -o libsrt-pr.dump -public-headers installdir/usr/local/include/srt/ -lver 0\n+        SRT_BASE=\"v1.$SRT_TAG_VERSION.0\"\n+        echo \"SRT_BASE=$SRT_BASE\" >> \"$GITHUB_ENV\"\n     - uses: actions/checkout@v3\n       with:\n-        path: gitview_base\n+        path: tag\n         ref: ${{ env.SRT_BASE }}\n-    - id: configure_tag\n-      name: Configure (cmake)\n+    - name: configure_tag\n       run: |\n-        echo \"TAG:$SRT_TAG_VERSION BASE:$SRT_BASE\"\n-\n-        #This is currently a paranoid check - the if should do the job\n-        if [[ -z $SRT_BASE ]]; then\n-            echo \"NO BASE DEFINED. NOT BUILDING\"\n-            exit 1\n-        fi\n-        cd gitview_base\n+        echo $SRT_TAG_VERSION\n+        cd tag\n         mkdir _build && cd _build\n-        cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_BONDING=1 -DENABLE_PKTINFO=1 -DENABLE_MAXREXMITBW=1 ../\n-    - id: build_tag\n-      name: Build and dump\n-      if: ${{ success() }}\n+        cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNITTESTS=ON ../\n+    - name: build_tag\n       run: |\n-        sudo apt install -y abi-dumper\n-        sudo apt install -y tcl\n-        cd gitview_base      \n+        cd tag      \n         cd _build && cmake --build ./\n         make install DESTDIR=./installdir\n-        echo \"TAGGING BASE BUILD: $SRT_BASE\"\n-        abi-dumper libsrt.so -o libsrt-base.dump -public-headers installdir/usr/local/include/srt/ -lver $SRT_BASE\n-        ls -ld libsrt-base.dump\n-        sha256sum libsrt-base.dump\n-    - id: upload_base_dump\n-      uses: actions/upload-artifact@v4\n-      with:\n-        name: abidump_base\n-        path: gitview_base/_build/libsrt-base.dump\n-\n-  check_abi:\n-    name: Compare ABI\n-    runs-on: ubuntu-latest\n-    needs: [build_pr, build_base]\n-    env:\n-       SRT_BASE: ${{ needs.build_pr.outputs.base_version }}\n-\n-    steps:\n-    - name: Download base dump\n-      uses: actions/download-artifact@v4\n-      with:\n-        name: abidump_base\n-        path: .\n-    - name: Download pr dump\n-      uses: actions/download-artifact@v4\n-      with:\n-        name: abidump_pr\n-        path: .\n+        abi-dumper libsrt.so -o libsrt-tag.dump -public-headers installdir/usr/local/include/srt/ -lver 1\n     - name: abi-check\n       run: |\n-        sudo apt install -y abi-dumper abi-compliance-checker tcl\n-        echo \"FILESYSTEM state before running abi-check at $PWD\"\n-        ls -l\n-        sha256sum libsrt-base.dump\n-        sha256sum libsrt-pr.dump\n-        RES=0\n-        abi-compliance-checker -l libsrt -old libsrt-base.dump -new libsrt-pr.dump || RES=$?\n-        # Flatten the report for download-preview\n-        cd compat_reports\n-        REPORT=$(find . -name *.html)\n-        cp $REPORT compat_report.html\n-        cd ..\n-        if (( $RES != 0 )); then\n-           echo \"ABI/API Compatibility check failed with value $?\"\n-           echo \"RES=$RES\" >>$GITHUB_ENV\n-           exit 0\n-        fi\n-    - name: Download report\n-      uses: actions/upload-artifact@v7\n-      with:\n-        name: abi-compliance-report\n-        path: compat_reports/compat_report.html\n-        archive: false\n-    - name: Final result\n-      run: |\n-        echo \"Final result: $RES\"\n-        exit $RES\n+         git clone https://github.com/lvc/abi-compliance-checker.git\n+         cd abi-compliance-checker && sudo make install && cd ../\n+         abi-compliance-checker -l libsrt -old tag/_build/libsrt-tag.dump -new pull_request/_build/libsrt-pr.dump\n+         RES=$?\n+         if (( $RES != 0 ))\n+          then\n+            echo \"ABI/API Compatibility check failed with value $?\"\n+            exit $RES\n+          fi\ndiff --git a/.github/workflows/android.yaml b/.github/workflows/android.yaml\nindex c94c0bb..0af85fd 100644\n--- a/.github/workflows/android.yaml\n+++ b/.github/workflows/android.yaml\n@@ -2,14 +2,14 @@ name: Android\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n \n jobs:\n   build:\n     name: NDK-R23\n-    runs-on: ubuntu-latest\n+    runs-on: ubuntu-20.04\n \n     steps:\n     - name: Setup Android NDK R23\ndiff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml\nindex f7f4172..4a337b6 100644\n--- a/.github/workflows/codeql.yml\n+++ b/.github/workflows/codeql.yml\n@@ -2,9 +2,9 @@ name: \"CodeQL\"\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ \"master\", \"experimental/socket-groups\" ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ \"master\" ]\n \n jobs:\n   analyze:\ndiff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml\ndeleted file mode 100644\nindex d19a0ca..0000000\n--- a/.github/workflows/codespell.yml\n+++ /dev/null\n@@ -1,21 +0,0 @@\n-name: codespell\n-\n-on: pull_request\n-\n-jobs:\n-  spellcheck:\n-    runs-on: ubuntu-22.04\n-    steps:\n-      - name: Checkout\n-        uses: actions/checkout@v4\n-\n-      - name: Setup Python\n-        uses: actions/setup-python@v5\n-        with:\n-          python-version: '3.10'\n-\n-      - name: Install dependencies with pip\n-        run: pip install --no-warn-script-location --user codespell\n-\n-      - name: Spellcheck\n-        run: codespell --config scripts/codespell/codespell.cfg\ndiff --git a/.github/workflows/cxx11-macos.yaml b/.github/workflows/cxx11-macos.yaml\nnew file mode 100644\nindex 0000000..e3e6b1f\n--- /dev/null\n+++ b/.github/workflows/cxx11-macos.yaml\n@@ -0,0 +1,25 @@\n+name: cxx11\n+\n+on:\n+  push:\n+    branches: [ master ]\n+  pull_request:\n+    branches: [ master ]\n+\n+jobs:\n+  build:\n+    name: macos\n+    runs-on: macos-latest\n+\n+    steps:\n+    - name: GoogleTest\n+      run: brew install googletest\n+    - uses: actions/checkout@v3\n+    - name: configure\n+      run: |\n+        mkdir _build && cd _build\n+        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DUSE_CXX_STD=14\n+    - name: build\n+      run: cd _build && cmake --build ./\n+    - name: test\n+      run: cd _build && ctest --extra-verbose\ndiff --git a/.github/workflows/cxx11-ubuntu.yaml b/.github/workflows/cxx11-ubuntu.yaml\nnew file mode 100644\nindex 0000000..918bbcd\n--- /dev/null\n+++ b/.github/workflows/cxx11-ubuntu.yaml\n@@ -0,0 +1,38 @@\n+name: cxx11\n+\n+on:\n+  push:\n+    branches: [ master ]\n+  pull_request:\n+    branches: [ master ]\n+    types: [opened, synchronize, reopened]\n+jobs:\n+  build:\n+    name: ubuntu\n+    runs-on: ubuntu-20.04\n+    env:\n+      BUILD_WRAPPER_OUT_DIR: sonar-output # Directory where build-wrapper output will be placed\n+    steps:\n+    - uses: actions/checkout@v3\n+    - name: Install sonar-scanner and build-wrapper\n+      uses: sonarsource/sonarcloud-github-c-cpp@v2\n+    - name: configure\n+      run: |\n+        mkdir _build && cd _build\n+        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=ON -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DENABLE_CODE_COVERAGE=ON\n+    - name: build\n+      run: cd _build && build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build .\n+    - name: test\n+      run: |\n+        cd _build && ctest --extra-verbose\n+    - name: codecov\n+      run: |\n+        source ./scripts/collect-gcov.sh\n+        bash <(curl -s https://codecov.io/bash)\n+    - name: Run SonarCloud Scan for C and C++\n+      if: ${{ !github.event.pull_request.head.repo.fork }}\n+      env:\n+        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n+        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n+      # Consult https://docs.sonarcloud.io/advanced-setup/ci-based-analysis/sonarscanner-cli/ for more information and options.\n+      run: sonar-scanner --define sonar.cfamily.build-wrapper-output=_build/\"${{ env.BUILD_WRAPPER_OUT_DIR }}\"\ndiff --git a/.github/workflows/windows-msvc-noenc.yml b/.github/workflows/cxx11-win.yaml\nsimilarity index 70%\nrename from .github/workflows/windows-msvc-noenc.yml\nrename to .github/workflows/cxx11-win.yaml\nindex a2c97cf..f155405 100644\n--- a/.github/workflows/windows-msvc-noenc.yml\n+++ b/.github/workflows/cxx11-win.yaml\n@@ -1,15 +1,15 @@\n-name: Windows\n+name: cxx11\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n \n jobs:\n   build:\n \n-    name:  C++11 noenc\n+    name: windows\n     runs-on: windows-latest\n \n     steps:\n@@ -17,7 +17,7 @@ jobs:\n     - name: configure\n       run: |\n         md _build && cd _build\n-        cmake ../ -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_LOCALIF_WIN32=ON -DUSE_CXX_STD=c++11\n+        cmake ../ -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DUSE_CXX_STD=c++11\n     - name: build\n       run: cd _build && cmake --build ./ --config Release --verbose\n     - name: test\ndiff --git a/.github/workflows/iOS.yaml b/.github/workflows/iOS.yaml\nindex 9ae9e91..0fb1154 100644\n--- a/.github/workflows/iOS.yaml\n+++ b/.github/workflows/iOS.yaml\n@@ -2,9 +2,9 @@ name: iOS\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n \n jobs:\n   build:\n@@ -17,13 +17,9 @@ jobs:\n \n     steps:\n     - uses: actions/checkout@v3\n-    - name: Install dependency packages\n-      run: |\n-         brew install make llvm\n     - name: configure\n       run: |\n         mkdir _build && cd _build\n-        export PATH=\"/opt/homebrew/opt/llvm/bin:$PATH\" CC=clang CXX=clang++\n-        cmake .. -DCMAKE_MAKE_PROGRAM=gmake -DENABLE_ENCRYPTION=OFF -DENABLE_STDCXX_SYNC=${{matrix.cxxstdsync}} -DENABLE_MONOTONIC_CLOCK=OFF -DENABLE_UNITTESTS=OFF -DUSE_CXX_STD=c++11 -DENABLE_BONDING=ON --toolchain scripts/iOS.cmake\n+        cmake ../ -DENABLE_ENCRYPTION=OFF -DENABLE_STDCXX_SYNC=${{matrix.cxxstdsync}} -DENABLE_UNITTESTS=OFF -DENABLE_BONDING=ON --toolchain scripts/iOS.cmake\n     - name: build\n       run: cd _build && cmake --build ./\ndiff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml\ndeleted file mode 100644\nindex d8b1f3b..0000000\n--- a/.github/workflows/macos.yml\n+++ /dev/null\n@@ -1,32 +0,0 @@\n-name: MacOS\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-\n-jobs:\n-  build:\n-    name: C++11 noenc\n-    runs-on: macos-latest\n-\n-    steps:\n-    - name: GoogleTest\n-      run: |\n-        brew tap-new Haivision/gt-local\n-        brew extract --version=1.12.1 --force googletest Haivision/gt-local\n-        brew trust Haivision/gt-local\n-        brew install googletest@1.12.1\n-        # NOTE: 1.12.1 is the last version that requires C++11; might need update later\n-        # curl -o googletest.rb https://raw.githubusercontent.com/Homebrew/homebrew-core/23e7fb4dc0cc73facc3772815741e1deb87d6406/Formula/googletest.rb\n-        # brew install -s googletest.rb\n-    - uses: actions/checkout@v3\n-    - name: configure\n-      run: |\n-        mkdir _build && cd _build\n-        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DUSE_CXX_STD=17\n-    - name: build\n-      run: cd _build && cmake --build ./\n-    - name: test\n-      run: cd _build && ctest --extra-verbose\ndiff --git a/.github/workflows/s390x-focal.yaml b/.github/workflows/s390x-focal.yaml\nindex d919914..f1b6c75 100644\n--- a/.github/workflows/s390x-focal.yaml\n+++ b/.github/workflows/s390x-focal.yaml\n@@ -2,9 +2,9 @@ name: QEMU to run s390x-focal\n \n on:\n   push:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n   pull_request:\n-    branches: [ \"master\", \"dev\" ]\n+    branches: [ master ]\n \n jobs:\n   Tests:\ndiff --git a/.github/workflows/ubuntu-c++03.yml b/.github/workflows/ubuntu-c++03.yml\ndeleted file mode 100644\nindex 8b9b685..0000000\n--- a/.github/workflows/ubuntu-c++03.yml\n+++ /dev/null\n@@ -1,41 +0,0 @@\n-name: Ubuntu C++03\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-    types: [opened, synchronize, reopened]\n-jobs:\n-  build:\n-    strategy:\n-      matrix:\n-        logging: [OFF, ON]\n-        bonding: [OFF, ON]\n-        exclude:\n-            - bonding: OFF\n-              logging: OFF\n-    name:  logging=${{ matrix.logging }} bonding=${{ matrix.bonding }}\n-    runs-on: ubuntu-latest\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: prepare\n-      run: |\n-        sudo apt update\n-        sudo apt install -y tcl cmake libssl-dev gdb\n-    - name: configure\n-      run: |\n-        mkdir _build && cd _build\n-        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_STDCXX_SYNC=OFF -DUSE_CXX_STD=03 -DENABLE_ENCRYPTION=ON -DENABLE_UNITTESTS=ON -DENABLE_BONDING=${{ matrix.bonding }} -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_LOGGING=${{ matrix.logging }}\n-    - name: build\n-      # That below is likely SonarQube remains, which was removed earlier.\n-      #run: cd _build && build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build .\n-      run: cd _build && cmake --build .\n-    - name: test\n-      run: |\n-        echo \"core.%e\" | sudo tee /proc/sys/kernel/core_pattern\n-        ulimit -c unlimited\n-        cd _build && ctest --extra-verbose\n-        SUCCESS=$?\n-        if [ -f core.test-srt ]; then gdb -batch ./test-srt -c core.test-srt -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n-        test $SUCCESS == 0;\ndiff --git a/.github/workflows/ubuntu-c++11.yml b/.github/workflows/ubuntu-c++11.yml\ndeleted file mode 100644\nindex e0152a0..0000000\n--- a/.github/workflows/ubuntu-c++11.yml\n+++ /dev/null\n@@ -1,53 +0,0 @@\n-name: Linux C++11\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-    types: [opened, synchronize, reopened]\n-jobs:\n-  build:\n-    strategy:\n-        matrix:\n-            # machine: [ubuntu-latest, ubuntu-slim, ubuntu-24.04-arm]\n-            # ubuntu-slim excluded because it doesn't have cmake and installation not allowed\n-            machine: [ubuntu-latest, ubuntu-24.04-arm]\n-    name: ON ${{ matrix.machine }}\n-    runs-on: \"${{ matrix.machine }}\"\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: prepare\n-      run: |\n-        sudo apt update\n-        RUNON=${{ matrix.machine }}\n-        if [[ $RUNON == ubuntu-latest ]]; then\n-            sudo apt install -y gdb\n-        fi\n-        sudo apt install -y tcl cmake\n-        [[ $RUNON == ubuntu-24.04-arm ]] || sudo apt install libssl-dev\n-    - name: configure\n-      run: |\n-        RUNON=${{ matrix.machine }}\n-        ENCRYPTION=ON\n-        [[ $RUNON == ubuntu-24.04-arm ]] && ENCRYPTION=OFF\n-        mkdir _build && cd _build\n-        cmake ../ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DUSE_CXX_STD=11 -DENABLE_STDCXX_SYNC=ON -DENABLE_ENCRYPTION=$ENCRYPTION -DENABLE_UNITTESTS=ON -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DENABLE_EXAMPLES=ON -DENABLE_DEBUG=ON -DENABLE_CODE_COVERAGE=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n-    - name: build\n-      run: cd _build && cmake --build .\n-    - name: test\n-      run: |\n-        echo \"core.%e\" | sudo tee /proc/sys/kernel/core_pattern\n-        ulimit -c unlimited\n-        cd _build && ctest --extra-verbose\n-        SUCCESS=$?\n-        if [ -f core.test-srt ]; then gdb -batch ./test-srt -c core.test-srt -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n-        test $SUCCESS == 0;\n-    - name: codecov\n-      uses: codecov/codecov-action@v4\n-      with:\n-          token: ${{ secrets.CODECOV_TOKEN }} \n-    # name: codecov\n-    # run: |\n-    #   ./scripts/codecov/update.sh\n-    #   ./scripts/codecov/codecov upload-process ${CODECOV_TOKEN} --search-dir _build\ndiff --git a/.github/workflows/ubuntu-mingw.yml b/.github/workflows/ubuntu-mingw.yml\ndeleted file mode 100644\nindex f9df4bc..0000000\n--- a/.github/workflows/ubuntu-mingw.yml\n+++ /dev/null\n@@ -1,27 +0,0 @@\n-name: Ubuntu MinGW\n-\n-on:\n-  push:\n-    branches: [ \"master\", \"dev\" ]\n-  pull_request:\n-    branches: [ \"master\", \"dev\" ]\n-    types: [opened, synchronize, reopened]\n-jobs:\n-  build:\n-    name:  noenc\n-    runs-on: ubuntu-latest\n-    steps:\n-    - uses: actions/checkout@v3\n-    - name: Dependencies\n-      run: |\n-        sudo apt install -y g++-mingw-w64-x86-64-posix gcc-mingw-w64-x86-64-posix\n-    - name: Configure\n-      run: |\n-        mkdir _build && cd _build\n-        export CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix \n-        #cmake .. -DCMAKE_COMPILE_WARNING_AS_ERROR=ON -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=OFF -DUSE_OPENSSL_PC=OFF -DCMAKE_SYSTEM_NAME=Windows -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n-        # Warn-on-error turned off because there's a warning about epoll about unimplemented system fd subscription system\n-        cmake .. -DENABLE_ENCRYPTION=OFF -DENABLE_UNITTESTS=OFF -DUSE_OPENSSL_PC=OFF -DCMAKE_SYSTEM_NAME=Windows -DENABLE_BONDING=ON -DENABLE_TESTING=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n-    - name: Build\n-      run: cd _build && make -j -k\n-\ndiff --git a/.gitignore b/.gitignore\nindex 5fc34a6..b4e22ff 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -47,4 +47,3 @@ compile_commands.json\n # ignore files generated by clion and cmake\n .idea/\n cmake-build-debug/\n-tags\ndiff --git a/.gitmodules b/.gitmodules\ndeleted file mode 100644\nindex 0c81e92..0000000\n--- a/.gitmodules\n+++ /dev/null\n@@ -1,3 +0,0 @@\n-[submodule \"submodules/abi-compliance-checker\"]\n-\tpath = submodules/abi-compliance-checker\n-\turl = https://github.com/lvc/abi-compliance-checker.git\ndiff --git a/.travis.yml b/.travis.yml\nindex 5c54148..94d5dac 100644\n--- a/.travis.yml\n+++ b/.travis.yml\n@@ -1,10 +1,3 @@\n-# TRAVIS Configuration file\n-#\n-# XXX MIND SYNTAX TRICKS:\n-#    - Keep column consistency\n-#    - TAB characters NOT ALLOWED anywhere\n-#    - COLON characters (in freestanding strings) not allowed in the script\n-\n language: cpp\n dist: xenial\n \n@@ -23,27 +16,27 @@ addons:\n         packages:\n         - openssl\n \n-jobs:\n+matrix:\n     include:\n         - os: linux\n           env:\n-          - BUILD_TYPE=Debug CFG=\"monotonic openssl werror\"\n-          - CMAKE_OPTS='-DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS=\"-Werror\"'\n+          - BUILD_TYPE=Debug\n+          - BUILD_OPTS='-DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS=\"-Werror\"'\n         - env:\n-          - BUILD_TYPE=Debug CFG=\"nologging mbedtls monotonic werror\"\n-          - CMAKE_OPTS='-DENABLE_LOGGING=OFF -DUSE_ENCLIB=mbedtls -DENABLE_MONOTONIC_CLOCK=ON -DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS=\"-Werror\"'\n+          - BUILD_TYPE=Debug\n+          - BUILD_OPTS='-DENABLE_LOGGING=OFF -DUSE_ENCLIB=mbedtls -DENABLE_MONOTONIC_CLOCK=ON -DENABLE_BONDING=ON -DCMAKE_CXX_FLAGS=\"-Werror\"'\n         - os: linux\n-          env: BUILD_TYPE=Release CFG=default\n-#       - os: osx\n-#         osx_image: xcode11.1\n-#         env:\n-#         - BUILD_TYPE=Debug CFG=werror\n-#         - CMAKE_OPTS='-DCMAKE_CXX_FLAGS=\"-Werror\"'\n-#       - os: osx\n-#         osx_image: xcode11.1\n-#         env:\n-#         - BUILD_TYPE=Release CFG=werror\n-#         - CMAKE_OPTS='-DCMAKE_CXX_FLAGS=\"-Werror\"'\n+          env: BUILD_TYPE=Release\n+        - os: osx\n+          osx_image: xcode11.1\n+          env:\n+          - BUILD_TYPE=Debug\n+          - BUILD_OPTS='-DCMAKE_CXX_FLAGS=\"-Werror\"'\n+        - os: osx\n+          osx_image: xcode11.1\n+          env:\n+          - BUILD_TYPE=Release\n+          - BUILD_OPTS='-DCMAKE_CXX_FLAGS=\"-Werror\"'\n         - os: linux\n           compiler: x86_64-w64-mingw32-g++\n           addons:\n@@ -60,70 +53,33 @@ jobs:\n             - ./Configure --cross-compile-prefix=x86_64-w64-mingw32- mingw64\n             - make\n             - cd ..\n-          env: BUILD_TYPE=Release CFG=no-UT\n+          env: BUILD_TYPE=Release\n \n          # Power jobs\n-         # Forcing Focal distro because Xenial\n-         # has somehow outdated CMake\n         - os: linux\n           arch: ppc64le\n-          dist: focal\n           env:\n-          - ARCH=PowerPC BUILD_TYPE=Debug\n+          - BUILD_TYPE=Debug\n         - arch: ppc64le\n-          dist: focal\n           env:\n-          - ARCH=PowerPC BUILD_TYPE=Release CFG=monotonic\n-          - CMAKE_OPTS='-DENABLE_MONOTONIC_CLOCK=ON'\n+          - BUILD_TYPE=Release\n+          - BUILD_OPTS='-DENABLE_MONOTONIC_CLOCK=ON'\n script:\n-    - CMAKE_VERSION=$(cmake --version | head -1 | awk '{print $3}')\n-    - echo CMAKE version $CMAKE_VERSION\n-    - CMAKE_VERSION_OK=$(echo \"puts [package vcompare $CMAKE_VERSION 3.10]\" | tclsh);\n-    - if [ \"$CMAKE_VERSION_OK\" == \"-1\" ]; then\n-          echo \"ERROR - cmake version too old, >=3.10 required\";\n-          exit 1;\n-      fi;\n-    - export REQUIRE_UNITTESTS=1\n     - if [ \"$TRAVIS_COMPILER\" == \"x86_64-w64-mingw32-g++\" ]; then\n-        CMAKE_OPTS+=\" -DCMAKE_C_COMPILER=x86_64-w64-mingw32-gcc\";\n-        CMAKE_OPTS+=\" -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++\";\n-        CMAKE_OPTS+=\" -DENABLE_STDCXX_SYNC=OFF -DENABLE_LOCALIF_WIN32=OFF -DENABLE_UNITTESTS=OFF -DUSE_OPENSSL_PC=OFF\";\n-        CMAKE_OPTS+=\" -DOPENSSL_ROOT_DIR=$PWD/openssl\";\n-        CMAKE_OPTS+=\" -DOPENSSL_CRYPTO_LIBRARY=$PWD/openssl/libcrypto-1_1-x64.dll\";\n-        CMAKE_OPTS+=\" -DCMAKE_SYSTEM_NAME=Windows\";\n-        REQUIRE_UNITTESTS=0;\n-      fi;\n-      if [ \"$TRAVIS_OS_NAME\" == \"osx\" ]; then\n-        export PKG_CONFIG_PATH=\"$(brew --prefix openssl)/lib/pkgconfig\";\n-      fi;\n-      if (( $REQUIRE_UNITTESTS )); then\n-        CMAKE_OPTS+=\" -DENABLE_UNITTESTS=ON\";\n-      fi;\n-    - echo COMPILER $TRAVIS_COMPILER\n-    - echo SYSTEM $TRAVIS_OS_NAME\n-    - echo BUILD_TYPE $BUILD_TYPE\n-    - echo CMAKE_OPTS $CMAKE_OPTS\n-    - export SUCCESS=0\n-    - cmake . --debug-output -DCMAKE_MESSAGE_LOG_LEVEL=VERBOSE -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE_OPTS 2>&1 || SUCCESS=$?;\n-    - if (($SUCCESS == 0)); then\n-         echo \"Configure OK\";\n-      else\n-         echo \"-- OUTPUT --\";\n-         cat CMakeFiles/CMakeOutput.log || echo \"NO OUTPUT\";\n-         echo \"-- ERRORS --\";\n-         cat CMakeFiles/CMakeError.log || echo \"NO LOGS\";\n-         exit 1;\n-      fi;\n-    - make VERBOSE=1 -j$(nproc);\n-    - if (( $REQUIRE_UNITTESTS )); then\n+        export CC=\"x86_64-w64-mingw32-gcc\";\n+        export CXX=\"x86_64-w64-mingw32-g++\";\n+        cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS=\"OFF\" -DUSE_OPENSSL_PC=\"OFF\" -DOPENSSL_ROOT_DIR=\"$PWD/openssl\" -DCMAKE_SYSTEM_NAME=\"Windows\";\n+      elif [ \"$TRAVIS_OS_NAME\" == \"linux\" ]; then\n+        cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS=\"ON\";\n+      elif [ \"$TRAVIS_OS_NAME\" == \"osx\" ]; then\n+        export PKG_CONFIG_PATH=$(brew --prefix openssl)\"/lib/pkgconfig\";\n+        cmake . -DCMAKE_BUILD_TYPE=$BUILD_TYPE $BUILD_OPTS -DENABLE_UNITTESTS=\"ON\";\n+      fi\n+    - make -j$(nproc);\n+    - if [ \"$TRAVIS_COMPILER\" != \"x86_64-w64-mingw32-g++\" ]; then\n         ulimit -c unlimited;\n-        if [ ! -f ./test-srt ]; then\n-          echo \"ERROR - UT application not found\";\n-          false;\n-        else\n-          ./test-srt -disable-ipv6;\n-          SUCCESS=$?;\n-          if [ -f core ]; then gdb -batch ./test-srt -c core -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n-          test $SUCCESS == 0;\n-        fi;\n-      fi;\n+        ./test-srt -disable-ipv6;\n+        SUCCESS=$?;\n+        if [ -f core ]; then gdb -batch ./test-srt -c core -ex bt -ex \"info thread\" -ex quit; else echo \"NO CORE - NO CRY!\"; fi;\n+        test $SUCCESS == 0;\n+      fi\ndiff --git a/CMakeLists.txt b/CMakeLists.txt\nold mode 100755\nnew mode 100644\nindex 4933de2..7ed11ef\n--- a/CMakeLists.txt\n+++ b/CMakeLists.txt\n@@ -7,11 +7,10 @@\n # file, You can obtain one at http://mozilla.org/MPL/2.0/.\n #\n \n-cmake_minimum_required (VERSION 3.5 FATAL_ERROR)\n-set (SRT_VERSION 1.5.7)\n+cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)\n+set (SRT_VERSION 1.5.4)\n \n set (CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/scripts\")\n-include(CheckSymbolExists)\n include(haiUtil) # needed for set_version_variables\n # CMake version 3.0 introduced the VERSION option of the project() command\n # to specify a project version as well as the name.\n@@ -44,12 +43,11 @@ set_if(DARWIN\t   (${CMAKE_SYSTEM_NAME} MATCHES \"Darwin\")\n set_if(LINUX       ${CMAKE_SYSTEM_NAME} MATCHES \"Linux\")\n set_if(BSD         ${SYSNAME_LC} MATCHES \"bsd$\")\n set_if(MICROSOFT   WIN32 AND (NOT MINGW AND NOT CYGWIN))\n-set_if(GNU_OS       ${CMAKE_SYSTEM_NAME} MATCHES \"GNU\") # Use GNU_OS to not confuse with gcc\n+set_if(GNU         ${CMAKE_SYSTEM_NAME} MATCHES \"GNU\")\n set_if(ANDROID     ${SYSNAME_LC} MATCHES \"android\")\n-set_if(OHOS        ${CMAKE_SYSTEM_NAME} MATCHES \"OHOS\")\n set_if(SUNOS       \"${SYSNAME_LC}\" MATCHES \"sunos\")\n-set_if(POSIX       LINUX OR DARWIN OR BSD OR SUNOS OR ANDROID OR OHOS OR (CYGWIN AND CYGWIN_USE_POSIX) OR GNU_OS)\n-set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR SUNOS OR CYGWIN OR GNU_OS)\n+set_if(POSIX       LINUX OR DARWIN OR BSD OR SUNOS OR ANDROID OR (CYGWIN AND CYGWIN_USE_POSIX))\n+set_if(SYMLINKABLE LINUX OR DARWIN OR BSD OR SUNOS OR CYGWIN OR GNU)\n set_if(NEED_DESTINATION  ${CMAKE_VERSION} VERSION_LESS \"3.14.0\")\n \n include(GNUInstallDirs)\n@@ -122,25 +120,6 @@ endforeach()\n # SRT_MAVG_SAMPLING_RATE 40       /* Max sampling rate */\n # SRT_ENABLE_FREQUENT_LOG_TRACE 0 : set to 1 to enable printing reason for suppressed freq logs\n \n-# Blocked by a general enabler, LIBSRT_ENABLE_IMPORT_VARIABLES, to prevent accidental use.\n-if ( (DEFINED LIBSRT_ENABLE_IMPORT_VARIABLES) AND (LIBSRT_ENABLE_IMPORT_VARIABLES EQUAL 1))\n-\tunset(LIBSRT_ENABLE_IMPORT_VARIABLES)\n-\n-\t# CMake offers sometimes OLD behavior, where names that are defined below with\n-\t# option() function, will be deleted if they are not in cache or do not have set\n-\t# type - so effectively options provided through LIBSRT_* prefix would be rejected.\n-\t# We do want these variables, obviously.\n-\t# NOTE: This is introduced in cmake 3.13, so the namespaced-option feature will not\n-\t# work properly in the old cmake.\n-\tif (CMAKE_VERSION VERSION_GREATER 3.12)\n-\t\tcmake_policy(SET CMP0077 NEW)\n-\tendif()\n-\n-\t# Import all options preceded with LIBSRT_ likely from a parent scope.\n-\t# Names are not being checked, at worst it will set an unused variable.\n-\tsrt_import_parent_options()\n-endif()\n-\n # option defaults\n set(ENABLE_HEAVY_LOGGING_DEFAULT OFF)\n \n@@ -172,7 +151,6 @@ else()\n endif()\n option(ENABLE_APPS \"Should the Support Applications be Built?\" ON)\n option(ENABLE_BONDING \"Should the bonding functionality be enabled?\" OFF)\n-option(ENABLE_EXAMPLES \"Compile also examples (NOTE: MAY BE UNSAFE!)\" OFF)\n option(ENABLE_TESTING \"Should the Developer Test Applications be Built?\" OFF)\n option(ENABLE_PROFILE \"Should instrument the code for profiling. Ignored for non-GNU compiler.\" $ENV{HAI_BUILD_PROFILE})\n option(ENABLE_LOGGING \"Should logging be enabled\" ON)\n@@ -184,7 +162,6 @@ option(ENABLE_PKTINFO \"Enable using IP_PKTINFO to allow the listener extracting\n option(ENABLE_RELATIVE_LIBPATH \"Should application contain relative library paths, like ../lib\" OFF)\n option(ENABLE_GETNAMEINFO \"In-logs sockaddr-to-string should do rev-dns\" OFF)\n option(ENABLE_UNITTESTS \"Enable unit tests\" OFF)\n-option(ENABLE_UNITTESTS_DISCOVERY \"Do unit test discovery when unit tests enabled\" ON)\n option(ENABLE_ENCRYPTION \"Enable encryption in SRT\" ON)\n option(ENABLE_AEAD_API_PREVIEW \"Enable AEAD API preview in SRT\" Off)\n option(ENABLE_MAXREXMITBW \"Enable SRTO_MAXREXMITBW (v1.6.0 API preview)\" Off)\n@@ -195,7 +172,7 @@ option(ENABLE_CODE_COVERAGE \"Enable code coverage reporting\" OFF)\n option(ENABLE_MONOTONIC_CLOCK \"Enforced clock_gettime with monotonic clock on GC CV\" ${ENABLE_MONOTONIC_CLOCK_DEFAULT})\n option(ENABLE_STDCXX_SYNC \"Use C++11 chrono and threads for timing instead of pthreads\" ${ENABLE_STDCXX_SYNC_DEFAULT})\n option(USE_OPENSSL_PC \"Use pkg-config to find OpenSSL libraries\" ON)\n-option(SRT_USE_OPENSSL_STATIC_LIBS \"Link OpenSSL libraries statically.\" OFF)\n+option(OPENSSL_USE_STATIC_LIBS \"Link OpenSSL libraries statically.\" OFF)\n option(USE_BUSY_WAITING \"Enable more accurate sending times at a cost of potentially higher CPU load\" OFF)\n option(USE_GNUSTL \"Get c++ library/headers from the gnustl.pc\" OFF)\n option(ENABLE_SOCK_CLOEXEC \"Enable setting SOCK_CLOEXEC on a socket\" ON)\n@@ -203,14 +180,8 @@ option(ENABLE_SHOW_PROJECT_CONFIG \"Enable show Project Configuration\" OFF)\n \n option(ENABLE_CLANG_TSA \"Enable Clang Thread Safety Analysis\" OFF)\n \n-if (DEFINED OPENSSL_USE_STATIC_LIBS AND \"${OPENSSL_USE_STATIC_LIBS}\" STREQUAL \"ON\")\n-\tmessage(WARNING \"Use of OPENSSL_USE_STATIC_LIBS as SRT build option here is deprecated.\n-Please use SRT_USE_OPENSSL_STATIC_LIBS instead.\")\n-\tset(SRT_USE_OPENSSL_STATIC_LIBS ${OPENSSL_USE_STATIC_LIBS})\n-endif()\n-\n # NOTE: Use ATOMIC_USE_SRT_SYNC_MUTEX and will override the auto-detection of the\n-#  Atomic implementation in srtcore/atomic.h.\n+#  Atomic implemetation in srtcore/atomic.h.\n option(ATOMIC_USE_SRT_SYNC_MUTEX \"Use srt::sync::Mutex to Implement Atomics\" OFF)\n if (ATOMIC_USE_SRT_SYNC_MUTEX)\n    add_definitions(-DATOMIC_USE_SRT_SYNC_MUTEX=1)\n@@ -274,7 +245,7 @@ endif()\n set(USE_ENCLIB \"${USE_ENCLIB}\" CACHE STRING \"The crypto library that SRT uses\")\n set_property(CACHE USE_ENCLIB PROPERTY STRINGS \"openssl\" \"openssl-evp\" \"gnutls\" \"mbedtls\" \"botan\")\n \n-# Make sure DLLs and executables go to the same path regardless of subdirectory\n+# Make sure DLLs and executabes go to the same path regardles of subdirectory\n set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})\n set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})\n set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})\n@@ -418,7 +389,7 @@ if (ENABLE_ENCRYPTION)\n \t\t# fall back to find_package method otherwise\n \t\tif (USE_OPENSSL_PC)\n \t\t\tpkg_check_modules(SSL ${SSL_REQUIRED_MODULES})\n-\t\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n+\t\t\tif (OPENSSL_USE_STATIC_LIBS)\n \t\t\t\t# use `pkg-config --static xxx` found libs\n \t\t\t\tset(SSL_LIBRARIES ${SSL_STATIC_LIBRARIES})\n \t\t\tendif()\n@@ -442,11 +413,6 @@ if (ENABLE_ENCRYPTION)\n \t\t\t)\n \t\t\tmessage(STATUS \"SSL via pkg-config: -L ${SSL_LIBRARY_DIRS} -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}\")\n \t\telse()\n-\t\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n-\t\t\t\t# use `pkg-config --static xxx` found libs\n-\t\t\t\tset(OPENSSL_USE_STATIC_LIBS True)\n-\t\t\t\tset(OPENSSL_MSVC_STATIC_RT True)\n-\t\t\tendif()\n \t\t\tfind_package(OpenSSL REQUIRED)\n \t\t\tset (SSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})\n \t\t\tset (SSL_LIBRARIES ${OPENSSL_LIBRARIES})\n@@ -500,10 +466,6 @@ if (ENABLE_ENCRYPTION)\n \t\t# fall back to find_package method otherwise\n \t\tif (USE_OPENSSL_PC)\n \t\t\tpkg_check_modules(SSL ${SSL_REQUIRED_MODULES})\n-\t\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n-\t\t\t\t# use `pkg-config --static xxx` found libs\n-\t\t\t\tset(SSL_LIBRARIES ${SSL_STATIC_LIBRARIES})\n-\t\t\tendif()\n \t\tendif()\n \t\tif (SSL_FOUND)\n \t\t\t# We have some cases when pkg-config is improperly configured\n@@ -524,11 +486,6 @@ if (ENABLE_ENCRYPTION)\n \t\t\t)\n \t\t\tmessage(STATUS \"SSL via pkg-config: -L ${SSL_LIBRARY_DIRS} -I ${SSL_INCLUDE_DIRS} -l;${SSL_LIBRARIES}\")\n \t\telse()\n-\t\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n-\t\t\t\t# use `pkg-config --static xxx` found libs\n-\t\t\t\tset(OPENSSL_USE_STATIC_LIBS True)\n-\t\t\t\tset(OPENSSL_MSVC_STATIC_RT True)\n-\t\t\tendif()\n \t\t\tfind_package(OpenSSL REQUIRED)\n \t\t\tset (SSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})\n \t\t\tset (SSL_LIBRARIES ${OPENSSL_LIBRARIES})\n@@ -814,9 +771,6 @@ elseif(LINUX)\n elseif(ANDROID)\n \tadd_definitions(-DLINUX=1)\n \tmessage(STATUS \"DETECTED SYSTEM: ANDROID;  LINUX=1\" )\n-elseif(OHOS)\n-\tadd_definitions(-DLINUX=1)\n-\tmessage(STATUS \"DETECTED SYSTEM: OHOS;  LINUX=1\" )\n elseif(CYGWIN)\n \tadd_definitions(-DCYGWIN=1)\n \tmessage(STATUS \"DETECTED SYSTEM: CYGWIN (posix mode); CYGWIN=1\")\n@@ -911,22 +865,13 @@ if (ENABLE_PROFILE)\n endif()\n \n if (ENABLE_CODE_COVERAGE)\n-\tif (NOT HAVE_COMPILER_GNU_COMPAT)\n-\t\tmessage(FATAL_ERROR \"ENABLE_CODE_COVERAGE: option is not supported on this platform\")\n-\tendif()\n-\n-\tif (ENABLE_DEBUG EQUAL 2)\n-\telseif (NOT ENABLE_DEBUG)\n+\tif (HAVE_COMPILER_GNU_COMPAT)\n+\t\tadd_definitions(-g -O0 --coverage)\n+\t\tlink_libraries(--coverage)\n+\t\tmessage(STATUS \"ENABLE_CODE_COVERAGE: ON\")\n \telse()\n-\t\tset (ENABLE_STRICTLY_DEBUG_MODE 1)\n-\tendif()\n-\tif (NOT ENABLE_STRICTLY_DEBUG_MODE)\n-\t\tmessage(FATAL_ERROR \"ENABLE_CODE_COVERAGE: requires ENABLE_DEBUG or Debug build type\")\n+\t\tmessage(FATAL_ERROR \"ENABLE_CODE_COVERAGE: option is not supported on this platform\")\n \tendif()\n-\n-\tadd_definitions(--coverage)\n-\tlink_libraries(--coverage)\n-\tmessage(STATUS \"ENABLE_CODE_COVERAGE: ON\")\n endif()\n \n # On Linux pthreads have to be linked even when using C++11 threads\n@@ -936,9 +881,6 @@ elseif (PTHREAD_LIBRARY AND PTHREAD_INCLUDE_DIR)\n \tmessage(STATUS \"Pthread library: ${PTHREAD_LIBRARY}\")\n \tmessage(STATUS \"Pthread include dir: ${PTHREAD_INCLUDE_DIR}\")\n elseif (MICROSOFT)\n-\n-\tmessage(WARNING \"DEPRECATION WARNING!\\nUsing POSIX thread API with Windows is deprecated and will be removed\")\n-\n \tfind_package(pthreads QUIET)\n \n \tif (NOT PTHREAD_INCLUDE_DIR OR NOT PTHREAD_LIBRARY)\n@@ -992,28 +934,8 @@ elseif (MICROSOFT)\n else ()\n \tfind_package(Threads REQUIRED)\n \tset(PTHREAD_LIBRARY ${CMAKE_THREAD_LIBS_INIT})\n-\tmessage(STATUS \"Pthread library: ${PTHREAD_LIBRARY}\")\n endif()\n \n-set(CMAKE_REQUIRED_LIBRARIES \"${PTHREAD_LIBRARY};${CMAKE_REQUIRED_LIBRARIES}\")\n-unset(CMAKE_REQUIRED_QUIET)\n-\n-check_symbol_exists(pthread_atfork \"pthread.h\" HAVE_PTHREAD_ATFORK)\n-if (\"${HAVE_PTHREAD_ATFORK}\" STREQUAL \"1\")\n-    add_definitions(-DHAVE_PTHREAD_ATFORK=1)\n-endif ()\n-\n-# To avoid the need for other judgments when ENABLE_STDCXX_SYNC is OFF in the future, this is a separate conditional statement.\n-if (NOT ENABLE_STDCXX_SYNC AND ENABLE_MONOTONIC_CLOCK)\n-\tcheck_symbol_exists(pthread_condattr_setclock \"pthread.h\" HAVE_PTHREAD_CONDATTR_SETCLOCK)\n-\tmessage(STATUS \"Checking pthread_condattr_setclock: '${HAVE_PTHREAD_CONDATTR_SETCLOCK}'\")\n-\tif (\"${HAVE_PTHREAD_CONDATTR_SETCLOCK}\" STREQUAL \"1\")\n-\t\tmessage(STATUS \"FOUND pthread_condattr_setclock - pthread_cond_timedwait will use monotonic clock\")\n-\t\tadd_definitions(-DHAVE_PTHREAD_CONDATTR_SETCLOCK=1)\n-\telse ()\n-\t\tmessage(WARNING \"NOT FOUND pthread_cond_timedwait. pthread_cond_timedwait will use system clock. Recommended -DENABLE_STDCXX_SYNC=ON\")\n-\tendif ()\n-endif ()\n # This is required in some projects that add some other sources\n # to the SRT library to be compiled together (aka \"virtual library\").\n if (DEFINED SRT_EXTRA_LIB_INC)\n@@ -1157,7 +1079,7 @@ if (srt_libspec_shared)\n \tif (MICROSOFT)\n \t\ttarget_link_libraries(${TARGET_srt}_shared PRIVATE ws2_32.lib)\n \t\tif (NOT (ENABLE_ENCRYPTION AND \"${USE_ENCLIB}\" STREQUAL \"botan\"))\n-\t\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n+\t\t\tif (OPENSSL_USE_STATIC_LIBS)\n \t\t\t\ttarget_link_libraries(${TARGET_srt}_shared PRIVATE crypt32.lib)\n \t\t\telse()\n \t\t\t\tset_target_properties(${TARGET_srt}_shared PROPERTIES LINK_FLAGS \"/DELAYLOAD:libeay32.dll\")\n@@ -1196,7 +1118,7 @@ if (srt_libspec_static)\n \tendif()\n \tif (MICROSOFT)\n \t\ttarget_link_libraries(${TARGET_srt}_static PRIVATE ws2_32.lib)\n-\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n+\t\tif (OPENSSL_USE_STATIC_LIBS)\n \t\t\ttarget_link_libraries(${TARGET_srt}_static PRIVATE crypt32.lib)\n \t\tendif()\n \telseif (MINGW)\n@@ -1210,7 +1132,7 @@ endif()\n target_include_directories(srt_virtual PRIVATE  ${SSL_INCLUDE_DIRS})\n \n if (MICROSOFT)\n-\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n+\tif (OPENSSL_USE_STATIC_LIBS)\n \t\tset (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ws2_32.lib crypt32.lib)\n \telse()\n \t\tset (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ws2_32.lib)\n@@ -1252,7 +1174,7 @@ endif()\n if (srt_libspec_shared)\n \tif (MICROSOFT)\n \t\ttarget_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib)\n-\t\tif (SRT_USE_OPENSSL_STATIC_LIBS)\n+\t\tif (OPENSSL_USE_STATIC_LIBS)\n \t\t\ttarget_link_libraries(${TARGET_srt}_shared PUBLIC crypt32.lib)\n \t\tendif()\n \tendif()\n@@ -1403,7 +1325,7 @@ macro(srt_make_application name)\n \n \tif (LINUX AND ENABLE_RELATIVE_LIBPATH AND NOT srt_libspec_static)\n \t\t# This is only needed on Linux, on Windows (including Cygwin) the library file will\n-\t\t# be placed into the binary directory anyway.\n+\t\t# be placed into the binrary directory anyway.\n \t\t# XXX not sure about Mac.\n \t\t# See this name used already in install(${TARGET_srt} LIBRARY DESTINATION...).\n \t\tset(FORCE_RPATH LINK_FLAGS -Wl,-rpath,.,-rpath,../${CMAKE_INSTALL_LIBDIR} BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH_USE_LINK_PATH TRUE)\n@@ -1604,7 +1526,6 @@ if (ENABLE_UNITTESTS AND ENABLE_CXX11)\n \tsrt_add_program_dont_install(test-srt ${SOURCES_unittests})\n \tsrt_make_application(test-srt)\n \ttarget_include_directories(test-srt PRIVATE  ${SSL_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})\n-\ttarget_compile_definitions(test-srt PRIVATE \"-DSRT_TEST_SYSTEM_NAME=\\\"${CMAKE_SYSTEM_NAME}\\\"\")\n \n \ttarget_link_libraries(\n \t\ttest-srt\n@@ -1621,9 +1542,7 @@ if (ENABLE_UNITTESTS AND ENABLE_CXX11)\n \t\t#set_tests_properties(test-srt PROPERTIES RUN_SERIAL TRUE)\n \telse()\n \t\tset_tests_properties(${tests_srt} PROPERTIES RUN_SERIAL TRUE)\n-\t\tif (ENABLE_UNITTESTS_DISCOVERY)\n-\t\t\tgtest_discover_tests(test-srt)\n-\t\tendif()\n+\t\tgtest_discover_tests(test-srt)\n \tendif()\n \n \tenable_testing()\ndiff --git a/README.md b/README.md\nindex 7e8c654..0bf8101 100644\n--- a/README.md\n+++ b/README.md\n@@ -4,16 +4,18 @@\n \n <p align=\"left\">\n   <a href=\"http://srtalliance.org/\">\n-    <img alt=\"SRT\" src=\"https://srtalliance.org/wp-content/uploads/2025/11/srt-long.svg\" width=\"500\"/>\n+    <img alt=\"SRT\" src=\"http://www.srtalliance.org/wp-content/uploads/SRT_text_hor_logo_grey.png\" width=\"500\"/>\n   </a>\n </p>\n \n [![License: MPLv2.0][license-badge]](./LICENSE)\n [![Latest release][release-badge]][github releases]\n+[![Quality Gate Status][sonarcloud-badge]][sonarcloud-project]\n [![codecov][codecov-badge]][codecov-project]\n+[![Build Status Linux and macOS][travis-badge]][travis]\n [![Build Status Windows][appveyor-badge]][appveyor]\n \n-[![Ubuntu 24.04][Ubuntu-badge]][Ubuntu-package]\n+[![Ubuntu 23.04][Ubuntu-badge]][Ubuntu-package]\n [![Fedora 37][fedora-badge]][fedora-package]\n [![Debian][debian-badge]][debian-package]\n [![Homebrew][Homebrew-badge]][Homebrew-package]\n@@ -147,7 +149,7 @@ In live streaming configurations, the SRT protocol maintains a constant end-to-e\n |:-----------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------:|\n | [The SRT API](./docs#srt-api-documents)                                                                                       | [IETF Internet Draft](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) | [Sample Apps](./docs#sample-applications)                                         |\n | Reference documentation for the SRT library API                                                                               | The SRT Protocol Internet Draft                                                      | Instructions for using test apps (`srt-live-transmit`, `srt-file-transmit`, etc.) |\n-| [SRT Technical Overview](https://github.com/Haivision/srt/files/2489142/SRT_Protocol_TechnicalOverview_DRAFT_2018-10-17.pdf)  | [SRT Deployment Guide](https://www3.haivision.com/srt-deployment-guide/)            | [SRT CookBook](https://srtlab.github.io/srt-cookbook)                             |\n+| [SRT Technical Overview](https://github.com/Haivision/srt/files/2489142/SRT_Protocol_TechnicalOverview_DRAFT_2018-10-17.pdf)  | [SRT Deployment Guide](https://www.srtalliance.org/srt-deployment-guide/)            | [SRT CookBook](https://srtlab.github.io/srt-cookbook)                             |\n | Early draft technical overview (precursor to the Internet Draft)                                                              | A comprehensive overview of the protocol with deployment guidelines                  | Development notes on the SRT protocol                                             |\n | [Innovation Labs Blog](https://medium.com/innovation-labs-blog/tagged/secure-reliable-transport)                              | [SRTLab YouTube Channel](https://www.youtube.com/channel/UCr35JJ32jKKWIYymR1PTdpA)   | [Slack](https://srtalliance.slack.com)                                            |\n | The blog on Medium with SRT-related technical articles                                                                        | Technical YouTube channel with useful videos                                         | Slack channels to get the latest updates and ask questions <br />[Join SRT Alliance on Slack](https://slackin-srtalliance.azurewebsites.net/) |\n@@ -156,9 +158,8 @@ In live streaming configurations, the SRT protocol maintains a constant end-to-e\n \n - [Why SRT?](./docs/misc/why-srt-was-created.md) - A brief history and rationale for SRT by Marc Cymontkowski.\n - [RTMP vs. SRT: Comparing Latency and Maximum Bandwidth](https://www.haivision.com/resources/white-paper/srt-versus-rtmp/) White Paper.\n-- [Documentation on GitHub](./docs#documentation-overview) with SRT API documents, features descriptions, etc.\n+- [Documentation on GitHub](./docs#documentation-overview) with SRT API documents, features decsriptions, etc.\n - The SRT Protocol Internet Draft: [Datatracker](https://datatracker.ietf.org/doc/draft-sharabayko-srt/) | [Latest Version](https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-01) | [Latest Working Copy](https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html) | [GitHub Repo](https://github.com/Haivision/srt-rfc)\n-- If you are curious about live streaming using SRT with QUIC datagrams as an alternative to UDP transport, take a look at the following [blog post](https://medium.com/innovation-labs-blog/live-streaming-using-srt-with-quic-datagrams-7896f7ce7bf3?source=friends_link&sk=d0a00e79861d89673e27a04260f279b5) on Medium.\n \n ## Build Instructions\n \n@@ -215,13 +216,18 @@ By contributing code to the SRT project, you agree to license your contribution\n \n [appveyor-badge]: https://img.shields.io/appveyor/ci/Haivision/srt/master.svg?label=Windows\n [appveyor]: https://ci.appveyor.com/project/Haivision/srt\n+[travis-badge]: https://img.shields.io/travis/Haivision/srt/master.svg?label=Linux/macOS\n+[travis]: https://travis-ci.org/Haivision/srt\n [license-badge]: https://img.shields.io/badge/License-MPLv2.0-blue\n \n [Vcpkg-package]: https://repology.org/project/srt/versions\n [Vcpkg-badge]: https://repology.org/badge/version-for-repo/vcpkg/srt.svg\n \n-[ConanCenter-package]: https://conan.io/center/recipes/srt\n-[ConanCenter-badge]: https://img.shields.io/conan/v/srt\n+[ConanCenter-package]: https://repology.org/project/srt/versions\n+[ConanCenter-badge]: https://repology.org/badge/version-for-repo/conancenter/srt.svg\n+\n+[sonarcloud-project]: https://sonarcloud.io/project/overview?id=srt\n+[sonarcloud-badge]: https://sonarcloud.io/api/project_badges/measure?project=srt&metric=alert_status\n \n [codecov-project]: https://codecov.io/gh/haivision/srt\n [codecov-badge]: https://codecov.io/gh/haivision/srt/branch/master/graph/badge.svg\n@@ -233,10 +239,10 @@ By contributing code to the SRT project, you agree to license your contribution\n [debian-package]: https://packages.debian.org/testing/libs/libsrt1.5-gnutls\n \n [fedora-package]: https://repology.org/project/srt/versions\n-[fedora-badge]: https://repology.org/badge/version-for-repo/fedora_43/srt.svg\n+[fedora-badge]: https://repology.org/badge/version-for-repo/fedora_37/srt.svg\n \n [homebrew-package]: https://repology.org/project/srt/versions\n [homebrew-badge]: https://repology.org/badge/version-for-repo/homebrew/srt.svg\n \n [Ubuntu-package]: https://repology.org/project/srt/versions\n-[Ubuntu-badge]: https://repology.org/badge/version-for-repo/ubuntu_26_04/srt.svg\n+[Ubuntu-badge]: https://repology.org/badge/version-for-repo/ubuntu_23_04/srt.svg\ndiff --git a/apps/apputil.cpp b/apps/apputil.cpp\nindex 7c37d8e..22c3152 100644\n--- a/apps/apputil.cpp\n+++ b/apps/apputil.cpp\n@@ -37,7 +37,7 @@ using namespace srt;\n // See:\n //    https://msdn.microsoft.com/en-us/library/windows/desktop/ms742214(v=vs.85).aspx\n //    http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedInternet3b.html\n-#if defined(_WIN32) && !defined(HAVE_INET_PTON) && !defined(InetPton)\n+#if defined(_WIN32) && !defined(HAVE_INET_PTON)\n namespace // Prevent conflict in case when still defined\n {\n int inet_pton(int af, const char * src, void * dst)\ndiff --git a/apps/socketoptions.hpp b/apps/socketoptions.hpp\nindex ee8f159..b8aa67b 100644\n--- a/apps/socketoptions.hpp\n+++ b/apps/socketoptions.hpp\n@@ -58,18 +58,14 @@ struct SocketOption\n     bool applyt(Object socket, std::string value) const;\n \n     template <Domain D, typename Object>\n-    static int setso(Object , int , int , const void* , size_t )\n-    {\n-        typename Object::something something = Object::something;\n-        return -1;\n-    }\n+    static int setso(Object socket, int protocol, int symbol, const void* data, size_t size);\n \n     template<Type T>\n     bool extract(std::string value, OptionValue& val) const;\n };\n \n template<>\n-inline int SocketOption::setso<SocketOption::SRT, SRTSOCKET>(SRTSOCKET socket, int /*ignored*/, int sym, const void* data, size_t size)\n+inline int SocketOption::setso<SocketOption::SRT, int>(int socket, int /*ignored*/, int sym, const void* data, size_t size)\n {\n     return srt_setsockopt(socket, 0, SRT_SOCKOPT(sym), data, (int) size);\n }\n@@ -84,7 +80,7 @@ inline int SocketOption::setso<SocketOption::SRT, SRT_SOCKOPT_CONFIG*>(SRT_SOCKO\n \n \n template<>\n-inline int SocketOption::setso<SocketOption::SYSTEM, SYSSOCKET>(SYSSOCKET socket, int proto, int sym, const void* data, size_t size)\n+inline int SocketOption::setso<SocketOption::SYSTEM, int>(int socket, int proto, int sym, const void* data, size_t size)\n {\n     return ::setsockopt(socket, proto, sym, (const char *)data, (int) size);\n }\ndiff --git a/apps/srt-file-transmit.cpp b/apps/srt-file-transmit.cpp\nindex aa3696d..327ad68 100644\n--- a/apps/srt-file-transmit.cpp\n+++ b/apps/srt-file-transmit.cpp\n@@ -465,12 +465,6 @@ bool DoDownload(UriParser& us, string directory, string filename,\n     bool connected = false;\n     int pollid = -1;\n     string id;\n-    // This will be set to TRUE if the ID has been obtained from the socket,\n-    // while as caller socket it was set to this option beforehand. If it remains\n-    // false, it means that it was the ID passed from the caller and extracted\n-    // from the accepted socket - and as such the name can't be trusted, so\n-    // if a file with this name exists, it will be not overwritten.\n-    bool id_is_local = false;\n     ofstream ofile;\n     SRT_SOCKSTATUS status;\n     SRTSOCKET efd;\n@@ -554,7 +548,6 @@ bool DoDownload(UriParser& us, string directory, string filename,\n                     cerr << \"Source connected (caller), id [\"\n                         << id << \"]\" << endl;\n                     connected = true;\n-                    id_is_local = true;\n                 }\n             }\n             break;\n@@ -586,58 +579,10 @@ bool DoDownload(UriParser& us, string directory, string filename,\n \n             if (!ofile.is_open())\n             {\n-                std::string fn;\n-                bool overwrite = false;\n-                if (id.empty())\n-                {\n-                    fn = filename;\n-                    overwrite = true;\n-                }\n-                else\n-                {\n-                    fn = id;\n-                    if (id_is_local)\n-                        overwrite = true;\n-                }\n+                const char * fn = id.empty() ? filename.c_str() : id.c_str();\n                 directory.append(\"/\");\n                 directory.append(fn);\n-\n-                std::ios::openmode flags = ios::out | ios::binary;\n-                if (overwrite)\n-                    flags = flags | ios::trunc;\n-                else\n-                {\n-                    struct stat state;\n-                    int st = stat(directory.c_str(), &state);\n-                    if (st == 0) // File can be obtained\n-                    {\n-                        cerr << \"Error: File exists: \" << directory << endl;\n-                        cerr << \"Error: As the name is remote-provided, overwriting denied for security reasons.\" << endl;\n-                        goto exit;\n-                    }\n-\n-                    // Additionally check if the path is PWD-based;\n-                    // reject any foreign-defined paths that are not\n-                    // effectively local.\n-\n-                    // NOTE: The file is always copied to the directory\n-                    // specified locally, with the original filename. Therefore\n-                    // it is not allowed that the file contain a path.\n-\n-                    static const size_t notfound = std::string::npos;\n-                    if (       fn.find('/') != notfound\n-                            || fn.find('\\\\') != notfound\n-                            || fn.find(':') != notfound\n-                            || fn.find(\"..\") != notfound) // Any parent-referring\n-                    {\n-                        cerr << \"Error: the foreign-specified path reaches outside PWD - REJECTED\\n\";\n-                        cerr << \"Path: \" << directory << endl;\n-                        cerr << \"NOTE: remote path is only allowed to point inside the current directory\\n\";\n-                        goto exit;\n-                    }\n-                }\n-\n-                ofile.open(directory, flags);\n+                ofile.open(directory.c_str(), ios::out | ios::trunc | ios::binary);\n \n                 if (!ofile.is_open())\n                 {\ndiff --git a/apps/srt-live-transmit.cpp b/apps/srt-live-transmit.cpp\nindex e496876..0a918e6 100644\n--- a/apps/srt-live-transmit.cpp\n+++ b/apps/srt-live-transmit.cpp\n@@ -514,7 +514,6 @@ int main(int argc, char** argv)\n                     return 1;\n                 }\n                 int events = SRT_EPOLL_IN | SRT_EPOLL_ERR;\n-\n                 switch (src->uri.type())\n                 {\n                 case UriParser::SRT:\n@@ -538,18 +537,14 @@ int main(int argc, char** argv)\n                     }\n                     break;\n                 case UriParser::FILE:\n+                    if (srt_epoll_add_ssock(pollid,\n+                        src->GetSysSocket(), &events))\n                     {\n-                        const int con = src->GetSysSocket();\n-                        // try to make the standard input non blocking\n-                        if (srt_epoll_add_ssock(pollid, con, &events))\n-                        {\n-                            cerr << \"Failed to add FILE source to poll, \"\n-                                << src->GetSysSocket() << endl;\n-                            return 1;\n-                        }\n-                        break;\n-\n+                        cerr << \"Failed to add FILE source to poll, \"\n+                            << src->GetSysSocket() << endl;\n+                        return 1;\n                     }\n+                    break;\n                 default:\n                     break;\n                 }\n@@ -594,7 +589,6 @@ int main(int argc, char** argv)\n             SRTSOCKET srtrwfds[4] = {SRT_INVALID_SOCK, SRT_INVALID_SOCK , SRT_INVALID_SOCK , SRT_INVALID_SOCK };\n             int sysrfdslen = 2;\n             SYSSOCKET sysrfds[2];\n-\n             if (srt_epoll_wait(pollid,\n                 &srtrwfds[0], &srtrfdslen, &srtrwfds[2], &srtwfdslen,\n                 100,\n@@ -777,34 +771,12 @@ int main(int argc, char** argv)\n                     break;\n                 }\n \n-\n-                bool srcReady = false;\n-\n-                if (src.get() && src->IsOpen() && !src->End())\n-                {\n-                    if (srtrfdslen > 0)\n-                    {\n-                        SRTSOCKET sock = src->GetSRTSocket();\n-                        if (sock != SRT_INVALID_SOCK)\n-                        {\n-                            for (int n = 0; n < srtrfdslen && !(srcReady = (sock == srtrwfds[n])); n ++);\n-                        }\n-                    }\n-                    if (!srcReady && sysrfdslen > 0)\n-                    {\n-                        SYSSOCKET sock = src->GetSysSocket();\n-                        if (sock != SYSSOCKET_INVALID)\n-                        {\n-                            for (int n = 0; n < sysrfdslen && !(srcReady = (sock == sysrfds[n])); n++);\n-                        }\n-                    }\n-                }\n                 // read a few chunks at a time in attempt to deplete\n                 // read buffers as much as possible on each read event\n                 // note that this implies live streams and does not\n                 // work for cached/file sources\n                 std::list<std::shared_ptr<MediaPacket>> dataqueue;\n-                if (srcReady)\n+                if (src.get() && src->IsOpen() && (srtrfdslen || sysrfdslen))\n                 {\n                     while (dataqueue.size() < cfg.buffering)\n                     {\n@@ -828,10 +800,9 @@ int main(int argc, char** argv)\n \n                         dataqueue.push_back(pkt);\n                         receivedBytes += pkt->payload.size();\n-                        if (src->MayBlock())\n-                            break;\n                     }\n                 }\n+\n                 // if there is no target, let the received data be lost\n                 while (!dataqueue.empty())\n                 {\n@@ -899,7 +870,7 @@ void TestLogHandler(void* opaque, int level, const char* file, int line, const c\n \n #ifdef _MSC_VER\n     // That's something weird that happens on Microsoft Visual Studio 2013\n-    // Trying to keep portability, while every version of MSVS is a different platform.\n+    // Trying to keep portability, while every version of MSVS is a different plaform.\n     // On MSVS 2015 there's already a standard-compliant snprintf, whereas _snprintf\n     // is available on backward compatibility and it doesn't work exactly the same way.\n #define snprintf _snprintf\ndiff --git a/apps/srt-tunnel.cpp b/apps/srt-tunnel.cpp\nindex 9ca3e2c..90bd43e 100644\n--- a/apps/srt-tunnel.cpp\n+++ b/apps/srt-tunnel.cpp\n@@ -387,7 +387,7 @@ void Engine::Worker()\n                 throw Medium::ReadEOF(\"\");\n \n             case Medium::RD_AGAIN:\n-                // Theoretically RD_AGAIN should not be reported\n+                // Theoreticall RD_AGAIN should not be reported\n                 // because it should be taken care of internally by\n                 // repeated sending - unless we get m_broken set.\n                 // If it is, however, it should be handled just like error.\ndiff --git a/apps/transmitbase.hpp b/apps/transmitbase.hpp\nindex 4590877..bd0af91 100644\n--- a/apps/transmitbase.hpp\n+++ b/apps/transmitbase.hpp\n@@ -70,8 +70,7 @@ public:\n     };\n \n     virtual SRTSOCKET GetSRTSocket() const { return SRT_INVALID_SOCK; }\n-    virtual SYSSOCKET GetSysSocket() const { return -1; }\n-    virtual bool MayBlock() const { return false; }\n+    virtual int GetSysSocket() const { return -1; }\n     virtual bool AcceptNewClient() { return false; }\n };\n \n@@ -87,7 +86,7 @@ public:\n     virtual ~Target() {}\n \n     virtual SRTSOCKET GetSRTSocket() const { return SRT_INVALID_SOCK; }\n-    virtual SYSSOCKET GetSysSocket() const { return -1; }\n+    virtual int GetSysSocket() const { return -1; }\n     virtual bool AcceptNewClient() { return false; }\n };\n \ndiff --git a/apps/transmitmedia.cpp b/apps/transmitmedia.cpp\nindex 7a158c9..2752951 100644\n--- a/apps/transmitmedia.cpp\n+++ b/apps/transmitmedia.cpp\n@@ -704,15 +704,9 @@ Iface* CreateSrt(const string& host, int port, const map<string,string>& par) {\n \n class ConsoleSource: public Source\n {\n-    const bool may_block = true;\n public:\n \n     ConsoleSource()\n-#ifdef _WIN32\n-    : may_block(true)\n-#else\n-    : may_block(fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) | O_NONBLOCK) < 0)\n-#endif\n     {\n #ifdef _WIN32\n         // The default stdin mode on windows is text.\n@@ -726,8 +720,9 @@ public:\n         if (pkt.payload.size() < chunk)\n             pkt.payload.resize(chunk);\n \n-        const int ret = ::read(GetSysSocket(), pkt.payload.data(), chunk);\n-        if (ret <= 0)\n+        bool st = cin.read(pkt.payload.data(), chunk).good();\n+        chunk = cin.gcount();\n+        if (chunk == 0 || !st)\n         {\n             pkt.payload.clear();\n             return 0;\n@@ -736,15 +731,14 @@ public:\n         // Save this time to potentially use it for SRT target.\n         pkt.time = srt_time_now();\n         if (chunk < pkt.payload.size())\n-            pkt.payload.resize(ret);\n+            pkt.payload.resize(chunk);\n \n-        return ret;\n+        return (int) chunk;\n     }\n \n     bool IsOpen() override { return cin.good(); }\n-    bool MayBlock() const final { return may_block; }\n     bool End() override { return cin.eof(); }\n-    SYSSOCKET GetSysSocket() const override { return fileno(stdin); };\n+    int GetSysSocket() const override { return 0; };\n };\n \n class ConsoleTarget: public Target\n@@ -773,7 +767,7 @@ public:\n \n     bool IsOpen() override { return cout.good(); }\n     bool Broken() override { return cout.eof(); }\n-    SYSSOCKET GetSysSocket() const override { return fileno(stdout); };\n+    int GetSysSocket() const override { return 0; };\n };\n \n template <class Iface> struct Console;\n@@ -804,17 +798,15 @@ static inline bool IsMulticast(in_addr adr)\n class UdpCommon\n {\n protected:\n-    SYSSOCKET m_sock = SYSSOCKET_INVALID;\n+    int m_sock = -1;\n+    sockaddr_any sadr;\n     string adapter;\n-    sockaddr_any        interface_addr;\n-    sockaddr_any        target_addr;\n-    bool                is_multicast = false;\n     map<string, string> m_options;\n \n     void Setup(string host, int port, map<string,string> attr)\n     {\n-        m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n-        if (m_sock == SYSSOCKET_INVALID)\n+        m_sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n+        if (m_sock == -1)\n             Error(SysError(), \"UdpCommon::Setup: socket\");\n \n         int yes = 1;\n@@ -823,35 +815,33 @@ protected:\n         // set non-blocking mode\n #if defined(_WIN32)\n         unsigned long ulyes = 1;\n-        const bool ioctl_error = (ioctlsocket(m_sock, FIONBIO, &ulyes) == SOCKET_ERROR);\n+        if (ioctlsocket(m_sock, FIONBIO, &ulyes) == SOCKET_ERROR)\n #else\n-        const bool ioctl_error = (ioctl(m_sock, FIONBIO, (const char *)&yes) == -1);\n+        if (ioctl(m_sock, FIONBIO, (const char *)&yes) < 0)\n #endif\n-        if (ioctl_error)\n         {\n             Error(SysError(), \"UdpCommon::Setup: ioctl FIONBIO\");\n         }\n \n-        interface_addr = CreateAddr(\"\", port, AF_INET);\n-        target_addr = CreateAddr(host, port);\n+        sadr = CreateAddr(host, port);\n \n-        is_multicast = false;\n+        bool is_multicast = false;\n \n         if (attr.count(\"multicast\"))\n         {\n             // XXX: Here provide support for IPv6 multicast #1479\n-            if (target_addr.family() != AF_INET)\n+            if (sadr.family() != AF_INET)\n             {\n                 throw std::runtime_error(\"UdpCommon: Multicast on IPv6 is not yet supported\");\n             }\n \n-            if (!IsMulticast(target_addr.sin.sin_addr))\n+            if (!IsMulticast(sadr.sin.sin_addr))\n             {\n                 throw std::runtime_error(\"UdpCommon: requested multicast for a non-multicast-type IP address\");\n             }\n             is_multicast = true;\n         }\n-        else if (target_addr.family() == AF_INET && IsMulticast(target_addr.sin.sin_addr))\n+        else if (sadr.family() == AF_INET && IsMulticast(sadr.sin.sin_addr))\n         {\n             is_multicast = true;\n         }\n@@ -859,19 +849,23 @@ protected:\n         if (is_multicast)\n         {\n             ip_mreq mreq;\n+            sockaddr_any maddr (AF_INET);\n             int opt_name;\n-            const char* mreq_arg_ptr;\n+            void* mreq_arg_ptr;\n             socklen_t mreq_arg_size;\n \n             adapter = attr.count(\"adapter\") ? attr.at(\"adapter\") : string();\n-            if (adapter == \"\")\n+            if ( adapter == \"\" )\n             {\n                 Verb() << \"Multicast: home address: INADDR_ANY:\" << port;\n+                maddr.sin.sin_family = AF_INET;\n+                maddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);\n+                maddr.sin.sin_port = htons(port); // necessary for temporary use\n             }\n             else\n             {\n                 Verb() << \"Multicast: home address: \" << adapter << \":\" << port;\n-                interface_addr = CreateAddr(adapter, port);\n+                maddr = CreateAddr(adapter, port);\n             }\n \n             if (attr.count(\"source\"))\n@@ -880,11 +874,11 @@ protected:\n                 ip_mreq_source mreq_ssm;\n                 /* this is an ssm.  we need to use the right struct and opt */\n                 opt_name = IP_ADD_SOURCE_MEMBERSHIP;\n-                mreq_ssm.imr_multiaddr.s_addr = target_addr.sin.sin_addr.s_addr;\n-                mreq_ssm.imr_interface.s_addr = interface_addr.sin.sin_addr.s_addr;\n+                mreq_ssm.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr;\n+                mreq_ssm.imr_interface.s_addr = maddr.sin.sin_addr.s_addr;\n                 inet_pton(AF_INET, attr.at(\"source\").c_str(), &mreq_ssm.imr_sourceaddr);\n                 mreq_arg_size = sizeof(mreq_ssm);\n-                mreq_arg_ptr = (const char*)&mreq_ssm;\n+                mreq_arg_ptr = &mreq_ssm;\n #else\n                 throw std::runtime_error(\"UdpCommon: source-filter multicast not supported by OS\");\n #endif\n@@ -892,20 +886,39 @@ protected:\n             else\n             {\n                 opt_name = IP_ADD_MEMBERSHIP;\n-                mreq.imr_multiaddr.s_addr = target_addr.sin.sin_addr.s_addr;\n-                mreq.imr_interface.s_addr = interface_addr.sin.sin_addr.s_addr;\n+                mreq.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr;\n+                mreq.imr_interface.s_addr = maddr.sin.sin_addr.s_addr;\n                 mreq_arg_size = sizeof(mreq);\n-                mreq_arg_ptr = (const char*)&mreq;\n+                mreq_arg_ptr = &mreq;\n             }\n \n #ifdef _WIN32\n+            const char* mreq_arg = (const char*)mreq_arg_ptr;\n             const auto status_error = SOCKET_ERROR;\n #else\n+            const void* mreq_arg = mreq_arg_ptr;\n             const auto status_error = -1;\n #endif\n-            auto res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg_ptr, mreq_arg_size);\n \n-            if (res == status_error)\n+#if defined(_WIN32) || defined(__CYGWIN__)\n+            // On Windows it somehow doesn't work when bind()\n+            // is called with multicast address. Write the address\n+            // that designates the network device here.\n+            // Also, sets port sharing when working with multicast\n+            sadr = maddr;\n+            int reuse = 1;\n+            int shareAddrRes = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&reuse), sizeof(reuse));\n+            if (shareAddrRes == status_error)\n+            {\n+                throw runtime_error(\"marking socket for shared use failed\");\n+            }\n+            Verb() << \"Multicast(Windows): will bind to home address\";\n+#else\n+            Verb() << \"Multicast(POSIX): will bind to IGMP address: \" << host;\n+#endif\n+            int res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg, mreq_arg_size);\n+\n+            if ( res == status_error )\n             {\n                 Error(errno, \"adding to multicast membership failed\");\n             }\n@@ -957,7 +970,7 @@ protected:\n     ~UdpCommon()\n     {\n #ifdef _WIN32\n-        if (m_sock != SYSSOCKET_INVALID)\n+        if (m_sock != -1)\n         {\n            shutdown(m_sock, SD_BOTH);\n            closesocket(m_sock);\n@@ -979,35 +992,8 @@ public:\n     UdpSource(string host, int port, const map<string,string>& attr)\n     {\n         Setup(host, port, attr);\n-\n-        // On Windows it somehow doesn't work when bind()\n-        // is called with multicast address. Write the address\n-        // that designates the network device here, always.\n-\n-        // Hance we have two fields holding the address:\n-        // * target_addr: address from which reading will be done\n-        //   * unicast: local address of the interface\n-        //   * multicast: the IGMP address\n-        // * interface_addr: address of the local interface\n-        //   (same as target_addr for unicast)\n-\n-        // In case of multicast, binding should be done:\n-        // On most POSIX systems, to the multicast address (target_addr in this case)\n-        // On Windows, to a local address (hence use interface_addr, as in this\n-        // case it differs to target_addr).\n-\n-#if defined(_WIN32) || defined(__CYGWIN__)\n-        sockaddr_any baddr = is_multicast ? interface_addr : target_addr;\n-        static const char* const sysname = \"Windows\";\n-#else\n-        static const char* const sysname = \"POSIX\";\n-        sockaddr_any baddr = target_addr;\n-#endif\n-        Verb(\"UDP:\", is_multicast ? \"Multicast\" : \"Unicast\", \"(\", sysname,\n-                \"): will bind to: \", baddr.str());\n-        int stat = ::bind(m_sock, baddr.get(), baddr.size());\n-\n-        if (stat == -1)\n+        int stat = ::bind(m_sock, sadr.get(), sadr.size());\n+        if ( stat == -1 )\n             Error(SysError(), \"Binding address for UDP\");\n         eof = false;\n     }\n@@ -1017,7 +1003,7 @@ public:\n         if (pkt.payload.size() < chunk)\n             pkt.payload.resize(chunk);\n \n-        sockaddr_any sa(target_addr.family());\n+        sockaddr_any sa(sadr.family());\n         socklen_t si = sa.size();\n         int stat = recvfrom(m_sock, pkt.payload.data(), (int) chunk, 0, sa.get(), &si);\n         if (stat < 1)\n@@ -1038,10 +1024,10 @@ public:\n         return stat;\n     }\n \n-    bool IsOpen() override { return m_sock != SYSSOCKET_INVALID; }\n+    bool IsOpen() override { return m_sock != -1; }\n     bool End() override { return eof; }\n \n-    SYSSOCKET GetSysSocket() const override { return m_sock; };\n+    int GetSysSocket() const override { return m_sock; };\n };\n \n class UdpTarget: public Target, public UdpCommon\n@@ -1053,14 +1039,15 @@ public:\n             cerr << \"\\nWARN Host for UDP target is not provided. Will send to localhost:\" << port << \".\\n\";\n \n         Setup(host, port, attr);\n-        if (is_multicast && interface_addr.isany() == false)\n+        if (adapter != \"\")\n         {\n-            if (interface_addr.family() != AF_INET)\n+            sockaddr_any maddr = CreateAddr(adapter, 0);\n+            if (maddr.family() != AF_INET)\n             {\n                 Error(0, \"UDP/target: IPv6 multicast not supported in the application\");\n             }\n \n-            in_addr addr = interface_addr.sin.sin_addr;\n+            in_addr addr = maddr.sin.sin_addr;\n \n             int res = setsockopt(m_sock, IPPROTO_IP, IP_MULTICAST_IF, reinterpret_cast<const char*>(&addr), sizeof(addr));\n             if (res == -1)\n@@ -1073,7 +1060,7 @@ public:\n \n     int Write(const char* data, size_t len, int64_t src_time SRT_ATR_UNUSED,  ostream & ignored SRT_ATR_UNUSED = cout) override\n     {\n-        int stat = sendto(m_sock, data, (int)len, 0, target_addr.get(), target_addr.size());\n+        int stat = sendto(m_sock, data, (int) len, 0, sadr.get(), sadr.size());\n         if ( stat == -1 )\n         {\n             if ((false))\n@@ -1083,10 +1070,10 @@ public:\n         return stat;\n     }\n \n-    bool IsOpen() override { return m_sock != SYSSOCKET_INVALID; }\n+    bool IsOpen() override { return m_sock != -1; }\n     bool Broken() override { return false; }\n \n-    SYSSOCKET GetSysSocket() const override { return m_sock; };\n+    int GetSysSocket() const override { return m_sock; };\n };\n \n template <class Iface> struct Udp;\ndiff --git a/common/win/unistd.h b/common/win/unistd.h\nindex 063f2a0..9c61cad 100644\n--- a/common/win/unistd.h\n+++ b/common/win/unistd.h\n@@ -3,7 +3,7 @@\n \n /* This file intended to serve as a drop-in replacement for \n  *  unistd.h on Windows\n- *  Please add functionality as needed\n+ *  Please add functionality as neeeded \n  */\n \n #include <stdlib.h>\ndiff --git a/configure-data.tcl b/configure-data.tcl\nindex 0faec42..3510a96 100644\n--- a/configure-data.tcl\n+++ b/configure-data.tcl\n@@ -34,49 +34,47 @@ set internal_options {\n \n # Options that refer directly to variables used in CMakeLists.txt\n set cmake_options {\n-    atomic-use-srt-sync-mutex \"Use mutex to implement atomics (alias: --with-atomic=sync-mutex) (default: OFF)\"\n     cygwin-use-posix \"Should the POSIX API be used for cygwin. Ignored if the system isn't cygwin. (default: OFF)\"\n-    enable-aead-api-preview \"Enable AEAD API preview in SRT (default: OFF)\"\n+    enable-c++11 \"Should the c++11 parts (srt-live-transmit) be enabled (default: ON, with gcc < 4.7 OFF)\"\n     enable-apps \"Should the Support Applications be Built? (default: ON)\"\n     enable-bonding \"Enable 'bonding' SRT feature (default: OFF)\"\n-    enable-c++11 \"Should the c++11 parts (srt-live-transmit) be enabled (default: ON, with gcc < 4.7 OFF)\"\n-    enable-c++-deps \"Extra library dependencies in srt.pc for C language (default: ON)\"\n-    enable-clang-tsa \"Enable Clang's Thread-Safety-Analysis (default: OFF)\"\n-    enable-code-coverage \"Enable code coverage reporting (default: OFF)\"\n-    enable-debug=<0,1,2> \"Enable debug mode (0=disabled, 1=debug, 2=rel-with-debug)\"\n-    enable-encryption \"Should encryption features be enabled (default: ON)\"\n-    enable-getnameinfo \"In-logs sockaddr-to-string should do rev-dns (default: OFF)\"\n-    enable-haicrypt-logging \"Should logging in haicrypt be enabled (default: OFF)\"\n-    enable-heavy-logging \"Should heavy debug logging be enabled (default: OFF)\"\n-    enable-inet-pton \"Set to OFF to prevent usage of inet_pton when building against modern SDKs (default: ON)\"\n+    enable-testing \"Should developer testing applications be built (default: OFF)\"\n+    enable-profile \"Should instrument the code for profiling. Ignored for non-GNU compiler. (default: OFF)\"\n     enable-logging \"Should logging be enabled (default: ON)\"\n-    enable-maxrexmitbw \"Enable SRTO_MAXREXMITBW (v1.6.0 API preview) (default: OFF)\"\n-    enable-monotonic-clock \"Enforced clock_gettime with monotonic clock on GC CV /temporary fix for #729/ (default: OFF)\"\n+    enable-heavy-logging \"Should heavy debug logging be enabled (default: OFF)\"\n+    enable-haicrypt-logging \"Should logging in haicrypt be enabled (default: OFF)\"\n     enable-pktinfo \"Should pktinfo reading and using be enabled (POSIX only) (default: OFF)\"\n-    enable-profile \"Should instrument the code for profiling. Ignored for non-GNU compiler. (default: OFF)\"\n-    enable-relative-libpath \"Should applications contain relative library paths, like ../lib (default: OFF)\"\n     enable-shared \"Should libsrt be built as a shared library (default: ON)\"\n-    enable-show-project-config \"Enables use of ShowProjectConfig() in cmake (default: OFF)\"\n-    enable-sock-cloexec \"Enable setting SOCK_CLOEXEC on a socket (default: ON)\"\n     enable-static \"Should libsrt be built as a static library (default: ON)\"\n-    enable-stdc++-sync \"Use standard C++11 chrono/threads instead of pthread wrapper (default: OFF, on Windows: ON)\"\n-    enable-testing \"Should developer testing applications be built (default: OFF)\"\n-    enable-thread-check \"Enable #include <threadcheck.h> that implements THREAD_* macros\"\n-    enable-unittests-discovery \"Enable UT Discovery (will run when building) (default: ON)\"\n+    enable-relative-libpath \"Should applications contain relative library paths, like ../lib (default: OFF)\"\n+    enable-getnameinfo \"In-logs sockaddr-to-string should do rev-dns (default: OFF)\"\n     enable-unittests \"Enable Unit Tests (will download Google UT) (default: OFF)\"\n+    enable-encryption \"Should encryption features be enabled (default: ON)\"\n+    enable-c++-deps \"Extra library dependencies in srt.pc for C language (default: ON)\"\n+    use-static-libstdc++ \"Should use static rather than shared libstdc++ (default: OFF)\"\n+    enable-inet-pton \"Set to OFF to prevent usage of inet_pton when building against modern SDKs (default: ON)\"\n+    enable-code-coverage \"Enable code coverage reporting (default: OFF)\"\n+    enable-monotonic-clock \"Enforced clock_gettime with monotonic clock on GC CV /temporary fix for #729/ (default: OFF)\"\n+    enable-thread-check \"Enable #include <threadcheck.h> that implements THREAD_* macros\"\n+    enable-stdc++-sync \"Use standard C++11 chrono/threads instead of pthread wrapper (default: OFF, on Windows: ON)\"\n+    use-openssl-pc \"Use pkg-config to find OpenSSL libraries (default: ON)\"\n+    openssl-use-static-libs \"Link OpenSSL statically (default: OFF).\"\n+    use-busy-waiting \"Enable more accurate sending times at a cost of potentially higher CPU load (default: OFF)\"\n+    use-gnustl \"Get c++ library/headers from the gnustl.pc\"\n+    enable-sock-cloexec \"Enable setting SOCK_CLOEXEC on a socket (default: ON)\"\n+    enable-show-project-config \"Enables use of ShowProjectConfig() in cmake (default: OFF)\"\n+    enable-new-rcvbuffer \"Enables the new receiver buffer implementation (default: ON)\"\n+    enable-clang-tsa \"Enable Clang's Thread-Safety-Analysis (default: OFF)\"\n+    atomic-use-srt-sync-mutex \"Use mutex to implement atomics (alias: --with-atomic=sync-mutex) (default: OFF)\"\n+\n+    use-enclib \"Encryption library to be used: openssl(default), gnutls, mbedtls, botan\"\n+    enable-debug=<0,1,2> \"Enable debug mode (0=disabled, 1=debug, 2=rel-with-debug)\"\n+    pkg-config-executable=<filepath> \"pkg-config executable\"\n     openssl-crypto-library=<filepath> \"OpenSSL: Path to a libcrypto library.\"\n     openssl-include-dir=<path> \"OpenSSL: Path to includes.\"\n     openssl-ssl-library=<filepath> \"OpenSSL: Path to a libssl library.\"\n-    openssl-use-static-libs \"Link OpenSSL statically (default: OFF).\"\n-    pkg-config-executable=<filepath> \"pkg-config executable\"\n     pthread-include-dir=<path> \"PThread: Path to includes\"\n     pthread-library=<filepath> \"PThread: Path to the pthread library.\"\n-    srt-use-openssl-static-libs \"Link OpenSSL libraries statically. (default: OFF)\"\n-    use-busy-waiting \"Enable more accurate sending times at a cost of potentially higher CPU load (default: OFF)\"\n-    use-enclib \"Encryption library to be used: openssl(default), gnutls, mbedtls, botan\"\n-    use-gnustl \"Get c++ library/headers from the gnustl.pc\"\n-    use-openssl-pc \"Use pkg-config to find OpenSSL libraries (default: ON)\"\n-    use-static-libstdc++ \"Should use static rather than shared libstdc++ (default: OFF)\"\n }\n \n set options $internal_options$cmake_options\ndiff --git a/debian/changelog b/debian/changelog\nindex 771cb11..04c8e0a 100644\n--- a/debian/changelog\n+++ b/debian/changelog\n@@ -1,30 +1,3 @@\n-srt (1.5.7-1) unstable; urgency=medium\n-\n-  * [ed2b0bf] New upstream version 1.5.7\n-  * [8f14dc8] d/patches/: refresh for new upstream release\n-\n- -- Florian Ernst <florian@debian.org>  Fri, 11 Sep 2026 16:53:38 +0200\n-\n-srt (1.5.6-1) unstable; urgency=medium\n-\n-  * [426c1cc] New upstream version 1.5.6, resolving\n-    - CVE-2026-55869: Heap-Based Buffer Overflow in KMREQ Handling\n-    - CVE-2026-55868: Encryption State Machine Downgrade\n-\n- -- Florian Ernst <florian@debian.org>  Mon, 20 Jul 2026 20:44:02 +0200\n-\n-srt (1.5.5-1) unstable; urgency=medium\n-\n-  * [81ff101] New upstream version 1.5.5\n-  * [c9924e6] d/copyright: update years\n-  * [de1b14d] d/patches/: drop obsolete 001-multiarch-rpath.patch, refresh\n-    remaining\n-  * [7e33d0f] d/tests/: s#pkg-config#pkgconf#\n-  * [fbeecfa] d/control: Standards-Version: 4.7.4 (no further changes\n-    required)\n-\n- -- Florian Ernst <florian@debian.org>  Tue, 28 Apr 2026 16:40:54 +0200\n-\n srt (1.5.4-3) unstable; urgency=medium\n \n   * [16dd739] d/{control,rules}: check the nocheck profile, fixing a FTCBFS.\ndiff --git a/debian/control b/debian/control\nindex 593b2d0..f03eac0 100644\n--- a/debian/control\n+++ b/debian/control\n@@ -9,7 +9,7 @@ Build-Depends: debhelper-compat (= 13),\n  libssl-dev,\n  pkgconf,\n Build-Depends-Indep: python3-sphinx\n-Standards-Version: 4.7.4\n+Standards-Version: 4.7.2\n Section: libs\n Homepage: https://github.com/Haivision/srt\n Vcs-Browser: https://salsa.debian.org/debian/libsrt\ndiff --git a/debian/copyright b/debian/copyright\nindex bd99117..a79582f 100644\n--- a/debian/copyright\n+++ b/debian/copyright\n@@ -66,7 +66,7 @@ License: LGPL-2.1+\n \n Files: debian/*\n Copyright: 2018, Federico Ceratto <federico@debian.org>\n-  2022-2026, Florian Ernst <florian@debian.org>\n+  2022-2024, Florian Ernst <florian@debian.org>\n License: MPL-2.0\n \n License: MPL-2.0\ndiff --git a/debian/patches/001-multiarch-rpath.patch b/debian/patches/001-multiarch-rpath.patch\nindex 905492f..d7e0774 100644\n--- a/debian/patches/001-multiarch-rpath.patch\n+++ b/debian/patches/001-multiarch-rpath.patch\n@@ -6,7 +6,7 @@ Index: git/CMakeLists.txt\n ===================================================================\n --- git.orig/CMakeLists.txt\n +++ git/CMakeLists.txt\n-@@ -1411,6 +1411,8 @@ macro(srt_make_application name)\n+@@ -1333,6 +1333,8 @@ macro(srt_make_application name)\n  \t\tset_target_properties(${name} PROPERTIES ${FORCE_RPATH})\n  \tendif()\n  \ndiff --git a/debian/patches/FTBFS_with_CMake_4.patch b/debian/patches/FTBFS_with_CMake_4.patch\nnew file mode 100644\nindex 0000000..5207c14\n--- /dev/null\n+++ b/debian/patches/FTBFS_with_CMake_4.patch\n@@ -0,0 +1,19 @@\n+Description: Fix FTBFS with CMake 4\n+Author: Sam Umbach\n+Origin: upstream, https://github.com/Haivision/srt/commit/0def1b1a1094fc57752f241250e9a1aed71bbffd\n+Bug-Debian: http://bugs.debian.org/1113542\n+Forwarded: not-needed\n+\n+diff --git a/CMakeLists.txt b/CMakeLists.txt\n+index 847b6f23f..847564d03 100755\n+--- a/CMakeLists.txt\n++++ b/CMakeLists.txt\n+@@ -7,7 +7,7 @@\n+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.\n+ #\n+ \n+-cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)\n++cmake_minimum_required (VERSION 3.5 FATAL_ERROR)\n+ set (SRT_VERSION 1.5.4)\n+ \n+ set (CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/scripts\")\ndiff --git a/debian/patches/series b/debian/patches/series\nindex 4dbac28..bef7d95 100644\n--- a/debian/patches/series\n+++ b/debian/patches/series\n@@ -1,2 +1,3 @@\n+FTBFS_with_CMake_4.patch\n 001-multiarch-rpath.patch\n test_failures.patch\ndiff --git a/docs/API/API-functions.md b/docs/API/API-functions.md\nindex 0e6da34..2fdb8a6 100644\n--- a/docs/API/API-functions.md\n+++ b/docs/API/API-functions.md\n@@ -269,24 +269,14 @@ exiting the application that uses the SRT library. This cleanup function will st\n be called from the C++ global destructor, if not called by the application, although\n relying on this behavior is strongly discouraged.\n \n-**IMPORTANT NOTES**:\n-\n-1. This function must be called from within `main()`, preferably at the end.\n-Calling it from any C++ global destructor is pointless, as SRT does it by\n-itself. But relying on it is strongly discouraged - at best only if you are\n-completely certain that all resources in the application are maintained in the\n-strict creation-destruction order, including threads. If this condition isn't\n-satisfied, then the behavior of the cleanup outside of `main()` is undefined.\n-\n-2. The startup/cleanup calls have an instance counter.  This means that if you\n-call [`srt_startup`](#srt_startup) multiple times, you need to call the\n-`srt_cleanup` function exactly the same number of times.\n-\n |      Returns                  |                                                                 |\n |:----------------------------- |:--------------------------------------------------------------- |\n |         0                     | A possibility to return other values is reserved for future use |\n | <img width=240px height=1px/>       | <img width=710px height=1px/>                      |\n \n+**IMPORTANT**: Note that the startup/cleanup calls have an instance counter.\n+This means that if you call [`srt_startup`](#srt_startup) multiple times, you need to call the\n+`srt_cleanup` function exactly the same number of times.\n \n \n [:arrow_up: &nbsp; Back to List of Functions & Structures](#srt-api-functions)\n@@ -622,10 +612,9 @@ the listener socket to accept group connections\n | [`SRT_EINVPARAM`](#srt_einvparam)       | Value of `backlog` is 0 or negative.                                                         |\n | [`SRT_EINVSOCK`](#srt_einvsock)         | Socket [`u`](#u) indicates no valid SRT socket.                                              |\n | [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) | [`srt_bind`](#srt_bind) has not yet been called on that socket.                              |\n-| [`SRT_ESCLOSED`](#srt_esclosed)         | The socket has been closed                                                                   |\n | [`SRT_ERDVNOSERV`](#srt_erdvnoserv)     | [`SRTO_RENDEZVOUS`](API-socket-options.md#SRTO_RENDEZVOUS) flag is set to true on specified socket. |\n | [`SRT_EINVOP`](#srt_einvop)             | Internal error (should not happen when [`SRT_EUNBOUNDSOCK`](#srt_eunboundsock) is reported). |\n-| [`SRT_ECONNSOCK`](#srt_econnsock)       | The socket is currently being used to establish a connection (like by `srt_connect`)         |\n+| [`SRT_ECONNSOCK`](#srt_econnsock)       | The socket is already connected.                                                             |\n | [`SRT_EDUPLISTEN`](#srt_eduplisten)     | The address used in [`srt_bind`](#srt_bind) by this socket is already occupied by another listening socket. <br/> Binding multiple sockets to one IP address and port is allowed, as long as <br/> [`SRTO_REUSEADDR`](API-socket-options.md#SRTO_REUSEADDRS) is set to true, but only one of these sockets can be set up as a listener.  |\n | <img width=240px height=1px/>           | <img width=710px height=1px/>                      |\n \n@@ -2852,13 +2841,13 @@ associated with the last error. The system error is:\n const char* srt_strerror(int code, int errnoval);\n ```\n \n-Returns a string message that represents a given SRT error code.\n+Returns a string message that represents a given SRT error code and possibly the\n+`errno` value, if not 0.\n \n-**NOTE:** *The `errnoval` parameter is ignored. This function's old version\n-was intended to get both the SRT error description and system error description,\n-but this requires resolution of the reentrancy problem and dynamic strings.\n-For getting the error description for a system error, you need to use the\n-`strerror` function or some of its reentrant version.*\n+**NOTE:** *This function isn't thread safe. It uses a static variable to hold the\n+error description. There's no problem with using it in a multithreaded environment,\n+as long as only one thread in the whole application calls this function at the\n+moment*\n \n \n [:arrow_up: &nbsp; Back to List of Functions & Structures](#srt-api-functions)\ndiff --git a/docs/API/API-socket-options.md b/docs/API/API-socket-options.md\nindex aaa1401..3291f6e 100644\n--- a/docs/API/API-socket-options.md\n+++ b/docs/API/API-socket-options.md\n@@ -201,16 +201,16 @@ The following table lists SRT API socket options in alphabetical order. Option d\n \n | Option Name                                             | Since | Restrict | Type      | Units   | Default           | Range    | Dir |Entity |\n | :------------------------------------------------------ | :---: | :------: | :-------: | :-----: | :---------------: | :------: |:---:|:-----:|\n-| [`SRTO_BINDTODEVICE`](#SRTO_BINDTODEVICE)               | 1.4.2 | pre-bind | `string`  |         | \"\"                | \\*       | RW  | S     |\n+| [`SRTO_BINDTODEVICE`](#SRTO_BINDTODEVICE)               | 1.4.2 | pre-bind | `string`  |         |                   |          | RW  | GSD+  |\n | [`SRTO_CONGESTION`](#SRTO_CONGESTION)                   | 1.3.0 | pre      | `string`  |         | \"live\"            | \\*       | W   | S     |\n | [`SRTO_CONNTIMEO`](#SRTO_CONNTIMEO)                     | 1.1.2 | pre      | `int32_t` | ms      | 3000              | 0..      | W   | GSD+  |\n-| [`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE)                   | 1.5.2 | pre      | `int32_t` |         | 0 (Auto)          | [0, 2]   | W   | GSD   |\n+| [`SRTO_CRYPTOMODE`](#SRTO_CRYPTOMODE)                   | 1.5.2 | pre      | `int32_t` |     | 0 (Auto)          | [0, 2]   | W   | GSD   |\n | [`SRTO_DRIFTTRACER`](#SRTO_DRIFTTRACER)                 | 1.4.2 | post     | `bool`    |         | true              |          | RW  | GSD   |\n | [`SRTO_ENFORCEDENCRYPTION`](#SRTO_ENFORCEDENCRYPTION)   | 1.3.2 | pre      | `bool`    |         | true              |          | W   | GSD   |\n | [`SRTO_EVENT`](#SRTO_EVENT)                             |       |          | `int32_t` | flags   |                   |          | R   | S     |\n | [`SRTO_FC`](#SRTO_FC)                                   |       | pre      | `int32_t` | pkts    | 25600             | 32..     | RW  | GSD   |\n | [`SRTO_GROUPCONNECT`](#SRTO_GROUPCONNECT)               | 1.5.0 | pre      | `int32_t` |         | 0                 | 0...1    | W   | S     |\n-| [`SRTO_GROUPMINSTABLETIMEO`](#SRTO_GROUPMINSTABLETIMEO) | 1.5.0 | pre      | `int32_t` | ms      | 60                | 60-...   | W   | GDI   |\n+| [`SRTO_GROUPMINSTABLETIMEO`](#SRTO_GROUPMINSTABLETIMEO) | 1.5.0 | pre      | `int32_t` | ms      | 60                | 60-...   | W   | GDI+  |\n | [`SRTO_GROUPTYPE`](#SRTO_GROUPTYPE)                     | 1.5.0 |          | `int32_t` | enum    |                   |          | R   | S     |\n | [`SRTO_INPUTBW`](#SRTO_INPUTBW)                         | 1.0.5 | post     | `int64_t` | B/s     | 0                 | 0..      | RW  | GSD   |\n | [`SRTO_IPTOS`](#SRTO_IPTOS)                             | 1.0.5 | pre-bind | `int32_t` |         | (system)          | 0..255   | RW  | GSD   |\n@@ -263,55 +263,13 @@ The following table lists SRT API socket options in alphabetical order. Option d\n | [`SRTO_UDP_SNDBUF`](#SRTO_UDP_SNDBUF)                   |       | pre-bind | `int32_t` | bytes   | 65536             | \\*       | RW  | GSD+  |\n | [`SRTO_VERSION`](#SRTO_VERSION)                         | 1.1.0 |          | `int32_t` |         |                   |          | R   | S     |\n \n-### Short summary for some general options' characteristics\n-\n-The following options cannot be set on a group:\n-\n-* [`SRTO_BINDTODEVICE`](#SRTO_BINDTODEVICE) - link-specific\n-* [`SRTO_CONGESTION`](#SRTO_CONGESTION) - \"live\" mode is the only supported for groups\n-* [`SRTO_GROUPCONNECT`](#SRTO_GROUPCONNECT) - to be set for a listener only\n-* [`SRTO_RENDEZVOUS`](#SRTO_RENDEZVOUS) - groups support only caller-listener mode\n-* [`SRTO_SENDER`](#SRTO_SENDER) - legacy option for <1.3.0, not available for bonding\n-* [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) - live mode (default) is the only supported for groups\n-* [`SRTO_TSBPDMODE`](#SRTO_TSBPDMODE)\n-\n-The following options cannot be retrieved from a group:\n-\n-* [`SRTO_EVENT`](#SRTO_EVENT) - not supported\n-* [`SRTO_GROUPTYPE`](#SRTO_GROUPTYPE) - this is information for an incoming socket only\n-* [`SRTO_ISN`](#SRTO_ISN) - socket-specific\n-* [`SRTO_KMSTATE`](#SRTO_KMSTATE) - connection-specific\n-* [`SRTO_RCVDATA`](#SRTO_RCVDATA) - socket-specific\n-* [`SRTO_RCVKMSTATE`](#SRTO_RCVKMSTATE) - connection-specific\n-* [`SRTO_SNDDATA`](#SRTO_SNDDATA) - socket-specific (sender buffer is still one per socket, also in groups)\n-* [`SRTO_SNDKMSTATE`](#SRTO_SNDKMSTATE) - connection-specific\n-* [`SRTO_STATE`](#SRTO_STATE) - socket-specific state for the connection\n-* [`SRTO_VERSION`](#SRTO_VERSION) - not supported\n-\n-The following options can be set on a socket or on a group, but for\n-a group it has a different meaning than for a socket and they also\n-cannot be set on a group member socket. The reason for all of them\n-is such that the socket usually has this option set as required for\n-the group internals to work properly, while a member socket cannot\n-be used for reading and writing operations.\n-\n-* [`SRTO_RCVSYN`](#SRTO_RCVSYN)\n-* [`SRTO_RCVTIMEO`](#SRTO_RCVTIMEO) \n-* [`SRTO_SNDSYN`](#SRTO_SNDSYN)\n-* [`SRTO_SNDTIMEO`](#SRTO_SNDTIMEO)\n-\n-The following options can be set only on a group and not on a socket:\n-\n-* [`SRTO_GROUPMINSTABLETIMEO`](#SRTO_GROUPMINSTABLETIMEO) - specific for a group of type `SRT_GTYPE_BACKUP`.\n-\n-\n ### Option Descriptions\n \n #### SRTO_BINDTODEVICE\n \n | OptName               | Since | Restrict | Type     | Units  | Default  | Range  | Dir |Entity|\n | --------------------- | ----- | -------- | -------- | ------ | -------- | ------ |-----|------|\n-| `SRTO_BINDTODEVICE`   | 1.4.2 | pre-bind | `string` |        |          |        | RW  | S    |\n+| `SRTO_BINDTODEVICE`   | 1.4.2 | pre-bind | `string` |        |          |        | RW  | GSD+ |\n \n Refers to the `SO_BINDTODEVICE` system socket option for `SOL_SOCKET` level.\n This effectively limits the packets received by this socket to only those\n@@ -346,7 +304,7 @@ if an appropriate instruction was given in the Stream ID.\n Currently supported congestion controllers are designated as \"live\" and \"file\",\n which correspond to the Live and File modes.\n \n-Note that it is not recommended to change this option directly, but you should\n+Note that it is not recommended to change this option manually, but you should\n rather change the whole set of options using the [`SRTO_TRANSTYPE`](#SRTO_TRANSTYPE) option.\n \n [Return to list](#list-of-options)\n@@ -359,11 +317,9 @@ rather change the whole set of options using the [`SRTO_TRANSTYPE`](#SRTO_TRANST\n | ------------------ | ----- | -------- | --------- | ------ | -------- | ------ | --- | ------ |\n | `SRTO_CONNTIMEO`   | 1.1.2 | pre      | `int32_t` | msec   | 3000     | 0..    | W   | GSD+   |\n \n-Connection timeout value in milliseconds. This is the time up to which the connecting\n-facility will attempt to connect and wait for the response from the remote endpoint\n-before giving up with error status. The value applies for both caller and\n-rendezvous modes. For the rendezvous mode (see `SRTO_RENDEZVOUS`) the effective\n-connection timeout will be 10 times the value set with `SRTO_CONNTIMEO`.\n+Connect timeout. This option applies to the caller and rendezvous connection\n+modes. For the rendezvous mode (see `SRTO_RENDEZVOUS`) the effective connection timeout\n+will be 10 times the value set with `SRTO_CONNTIMEO`.\n \n [Return to list](#list-of-options)\n \n@@ -658,8 +614,6 @@ See [`SRTO_INPUTBW`](#SRTO_INPUTBW).\n IPv4 Type of Service (see `IP_TOS` option for IP) or IPv6 Traffic Class (see `IPV6_TCLASS`\n of IPv6) depending on socket address family. Applies to sender only.\n \n-NOTE: This option has been tested to work correctly on Linux only.\n-\n When *getting*, the returned value is the user preset for non-connected sockets\n and the actual value for connected sockets.\n \n@@ -678,8 +632,6 @@ and the actual value for connected sockets.\n IPv4 Time To Live (see `IP_TTL` option for IP) or IPv6 unicast hops (see\n `IPV6_UNICAST_HOPS` for IPv6) depending on socket address family. Applies to sender only.\n \n-NOTE: This option has been tested to work correctly on Linux only.\n-\n When *getting*, the returned value is the user preset for non-connected sockets\n and the actual value for connected sockets.\n \n@@ -1112,7 +1064,7 @@ For details, see [SRT Packet Filtering & FEC](../features/packet-filtering-and-f\n \n Sets the passphrase for encryption. This enables encryption on this party (or\n disables it, if an empty passphrase is passed). The password must be minimum\n-10 and maximum 80 characters long.\n+10 and maximum 79 characters long.\n \n The passphrase is the shared secret between the sender and the receiver. It is\n used to generate the Key Encrypting Key using [PBKDF2](http://en.wikipedia.org/wiki/PBKDF2)\n@@ -1651,7 +1603,7 @@ will be able to retrieve this stream ID from the socket that is returned from\n `srt_accept` (for a connected socket with that stream ID). You usually use SET\n on the socket used for `srt_connect`, and GET on the socket retrieved from\n `srt_accept`. This string can be used completely free-form. However, it's highly\n-recommended to follow the [SRT Access Control (Stream ID) Guidelines](../features/access-control.md).\n+recommended to follow the [SRT Access Control (Stream ID) Guidlines](../features/access-control.md).\n \n - As this uses internally the `std::string` type, there are additional functions\n for it in the legacy/C++ API (udt.h): `srt::setstreamid` and `srt::getstreamid`.\ndiff --git a/docs/API/statistics.md b/docs/API/statistics.md\nindex 0e4b2d3..bc34ecc 100644\n--- a/docs/API/statistics.md\n+++ b/docs/API/statistics.md\n@@ -182,7 +182,7 @@ If the packet `s` is received out of order (`s < next_exp`), the statistic is no\n \n Note that only original (not retransmitted) SRT DATA packets are taken into account. Refer to [pktRcvRetransTotal](#pktRcvRetransTotal) for the formula for obtaining the total number of lost retransmitted packets.\n \n-In SRT v1.4.0, v1.4.1, the `pktRcvLossTotal` statistic includes packets that failed to be decrypted. To receive the number of presently missing packets, subtract [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) from the current one. This is going to be fixed in SRT v.1.5.0.\n+In SRT v1.4.0, v1.4.1, the `pktRcvLossTotal` statistic includes packets that failed to be decrypted. To receive the number of presently missing packets, substract [pktRcvUndecryptTotal](#pktRcvUndecryptTotal) from the current one. This is going to be fixed in SRT v.1.5.0.\n \n #### pktRetransTotal\n \n@@ -245,7 +245,7 @@ Packets may be dropped conditionally when both `SRTO_TSBPDMODE` and `SRTO_TLPKTD\n #### pktRcvUndecryptTotal\n \n The total number of packets that failed to be decrypted at the receiver side. Available for receiver.\n-The statistic also counts unencrypted packets that were expected to be unencrypted on a secured connection (see [SRTO_KM_S_SECURED](API-socket-options.md#srt_km_state))\n+The statistic also counts unencrypted packets that were expected to be uncrypted on a secured connection (see [SRTO_KM_S_SECURED](API-socket-options.md#srt_km_state))\n and hence dropped as not encrypted (undecrypted).\n \n #### pktSndFilterExtraTotal\n@@ -657,7 +657,7 @@ Instantaneous (current) value of `pktRcvBuf`, expressed in bytes, including payl\n \n The timespan (msec) of acknowledged packets in the receiver's buffer. Receiver side.\n \n-If TSBPD mode is enabled (default for **live mode**),\n+If TSBPD mode is enabled (defualt for **live mode**),\n a packet can be acknowledged, but not yet ready to play.\n This range includes all packets regardless of whether\n they are ready to play or not.\ndiff --git a/docs/README.md b/docs/README.md\nindex 83baf25..8c07ee5 100644\n--- a/docs/README.md\n+++ b/docs/README.md\n@@ -7,7 +7,7 @@\n | [SRT API](API/API.md)                                       | [API](API/)                   | [API.md](API/API.md)                                           | Detailed description of the SRT C API.               |\n | [SRT API Functions](API/API-functions.md)                   | [API](API/)                   | [API-functions.md](API/API-functions.md)                       | Reference document for SRT API functions.            |\n | [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. |\n-| [SRT Rejection Codes](API/rejection-codes.md)               | [API](API/)                   | [rejection-codes.md](API/rejection-codes.md)                   | The list of SRT rejections codes. |\n+| [SRT Rejection Codes](API/rejections-codes.md)              | [API](API/)                   | [rejection-codes.md](API/rejection-codes.md)                   | The list of SRT rejections codes. |\n | [SRT Statistics](API/statistics.md)                         | [API](API/)                   | [statistics.md](API/statistics.md)                             | How to use SRT socket and socket group statistics.   |\n | [Configuration Guidelines](API/configuration-guidelines.md) | [API](API/)                   | [configuration-guidelines.md](API/configuration-guidelines.md) | How to configure SRT buffers.                        |\n | <img width=200px height=1px/>                               | <img width=100px height=1px/> | <img width=200px height=1px/>                                  | <img width=500px height=1px/>                        |\ndiff --git a/docs/apps/srt-file-transmit.md b/docs/apps/srt-file-transmit.md\nindex 04afb1c..2bf3b11 100644\n--- a/docs/apps/srt-file-transmit.md\n+++ b/docs/apps/srt-file-transmit.md\n@@ -40,7 +40,7 @@ If you use sender in listener mode, then you start it with specifying either the\n full filename path, or only the directory where the file is located; in the latter\n case the filename will be tried from the `streamid` option extracted from the\n connected socket (as set by the other side's caller). If the full filename was\n-specified, it must match the rootname extracted from this option, or otherwise\n+specified, it must match the rootname extraced from this option, or otherwise\n transmission will not be done.\n \n If you use receiver in listener mode, then you start it with specifying either\ndiff --git a/docs/apps/srt-live-transmit.md b/docs/apps/srt-live-transmit.md\nindex 718508b..48741df 100644\n--- a/docs/apps/srt-live-transmit.md\n+++ b/docs/apps/srt-live-transmit.md\n@@ -236,7 +236,7 @@ the presence of the **adapter** parameter:\n * Caller mode: if you specify *host* part, but not **adapter** parameter:\n    - `srt://remote.host.com:1234`\n * Rendezvous mode: if you specify *host* AND **adapter** parameter:\n-   - `srt://remote.host.com:1234?adapter=my.remote.addr`\n+   - `srt://remote.host.com:1234&adapter=my.remote.addr`\n \n Sometimes the required parameter specification results in a different mode\n than desired; in this case you should specify the mode explicitly.\ndiff --git a/docs/build/build-android.md b/docs/build/build-android.md\nindex da35414..7c13c94 100644\n--- a/docs/build/build-android.md\n+++ b/docs/build/build-android.md\n@@ -1,6 +1,6 @@\n # Building SRT on Android\n \n-**NOTE:** The scripts are located in [scripts/build-android](../../scripts/build-android/) folder.\n+**NOTE:** The scripts have been moved to [scripts/build-android](../../scripts/build-android/) folder.\n \n ## Install the NDK and CMake\n \ndiff --git a/docs/build/build-iOS.md b/docs/build/build-iOS.md\nindex c6d5884..a1fd48b 100644\n--- a/docs/build/build-iOS.md\n+++ b/docs/build/build-iOS.md\n@@ -1,28 +1,44 @@\n-# Building SRT on iOS/tvOS\n-\n-**NOTE:** The scripts are located in [scripts/build-ios](../../scripts/build-ios/) folder.\n+# Building SRT on iOS\n \n ## Prerequisites\n * Xcode should be installed. Check in terminal whether `xcode-select -p` points to **/Applications/Xcode.app/Contents/Developer**\n * Install Homebrew according to instructions on [https://brew.sh/](https://brew.sh/)\n-* Install CMake with Homebrew:\n+* Install CMake and pkg-config with Homebrew:\n ```\n brew install cmake\n+brew install pkg-config\n ```\n \n ## Building OpenSSL\n-There is [OpenSSL-Universal](https://github.com/krzyzanowskim/OpenSSL) project which has all necessary to build OpenSSL for our needs. It fetches OpenSSL code by itself, so you don't need to download it separately. Build it with command:\n+There is [OpenSSL for iPhone](https://github.com/x2on/OpenSSL-for-iPhone) project which have all necessary to build OpenSSL for our needs. It fetches OpenSSL code by itself, so you don't need to download it separately. So simply clone it and build with command:\n ```\n-./mkssl-xcf.sh\n+./build-libssl.sh --archs=\"arm64\"\n ```\n \n+Results (both libraries and headers) will be placed in bin/&lt;SDK_VERSION&gt;-&lt;ARCH&gt;.sdk directory (for example, *bin/iPhoneOS11.2-arm64.sdk*). We assume you set **IOS_OPENSSL** variable to this path (e.g. `export IOS_OPENSSL=\"/Users/johndoe/sources/OpenSSL-for-iPhone/bin/iPhoneOS11.2-arm64.sdk\"`).\n+\n ## Building SRT code\n-Now you can build SRT with command:\n+Now you can build SRT providing path to OpenSSL library and toolchain file for iOS\n+\n ```\n-./mksrt-xcf.sh\n+./configure --cmake-prefix-path=$IOS_OPENSSL --use-openssl-pc=OFF --cmake-toolchain-file=scripts/iOS.cmake\n+make\n ```\n \n+Optionally you may add following iOS-specifc settings to configure:\n+\n+* `--ios-disable-bitcode=1` - disable embedding bitcode to library.\n+* `--ios-arch=armv7|armv7s|arm64` - specify if you want to build for specific architecture (arm64 by default)\n+* `--ios-platform=OS|SIMULATOR|SIMULATOR64` - specify for build simulator code\n+* `--cmake-ios-developer-root=&lt;path&gt;`- specify path for platform directory; {XCODE_ROOT}/Platforms/iPhoneOS.platform/Developer by default\n+* `--cmake-ios-sdk-root=<path>` - by default searches for latest SDK version within {CMAKE_IOS_DEVELOPER_ROOT}/SDKs, set if you want to use another SDK version\n+\n+Note that resulting .dylib file has install path @executable_path/Frameworks/libsrt.1.dylib, so if you need to place it in some other place with your application, you may change it with *install_name_tool* command: ``install_name_tool -id \"<install_path>\" <library_file>``, for example ``install_name_tool -id \"@executable_path/Frameworks/libsrt.1.3.0.dylib\" libsrt.1.3.0.dylib``\n+\n ## Adding to Xcode project\n-Results (libcrypto.xcframework and libsrt.xcframework) will be placed in [scripts/build-ios](../../scripts/build-ios/) folder.\n+In Xcode project settings in General tab, add libsrt to **Linked Frameworks and Libraries** section - click Plus sign, then click \"Add Other\" and find libsrt.1.dylib\n+\n+Click plus sign in **Embedded binaries** section and choose Frameworks/libsrt.1.dylib\n \n-Follow [these steps](https://developer.apple.com/documentation/xcode/creating-a-static-framework#Embed-your-framework-in-an-app) to embed frameworks in your app. Choose the Do Not Embed option from the Embed value list.\n+In **Build settings** tab find **Header Search Paths** setting\n+and add paths to SRT library sources (you should add srt, srt/common and srt/common directories).\ndiff --git a/docs/build/build-options.md b/docs/build/build-options.md\nindex 2ec4d45..529bd5c 100644\n--- a/docs/build/build-options.md\n+++ b/docs/build/build-options.md\n@@ -17,50 +17,6 @@ Additional information on building for Windows is available in the\n document and in the [SRT CookBook](https://srtlab.github.io/srt-cookbook/getting-started/build-on-windows/).\n \n \n-## Building as a subproject\n-\n-The CMake tool offers the ability to add a complete project as a subdirectory.\n-If you do this with SRT, note that all variables that can be optionally set\n-will get values from the parent configuration file including the one from SRT.\n-\n-To allow isolation of these variables and setting them explicitly to desired\n-values in case when the parent project uses variables with the same names,\n-there's a special feature provided: set the desired variables for the SRT\n-project using `LIBSRT_` prefix - this way they will get the values to the\n-right variables, visible only in the scope of the SRT build configuration.\n-\n-NOTE: This feature needs to be generally enabled by:\n-\n-```\n-set (LIBSRT_ENABLE_IMPORT_VARIABLES 1)\n-```\n-\n-otherwise all other variables with `LIBSRT_` prefix will be ignored.\n-\n-This will not prevent the variables from being seen as derived in SRT project\n-scope, but if you explicitly set a variable this way, it will be set to the\n-desired value inside the SRT project. It will not set the same variable in the\n-parent project, and it will also override (locally in SRT project only) any\n-value of a variable with the same name in the parent project.\n-\n-For example, if you want to set `ENABLE_SHARED=OFF` in the parent project,\n-add this before importing the SRT project:\n-\n-```\n-set (LIBSRT_ENABLE_IMPORT_VARIABLES 1)\n-set (LIBSRT_ENABLE_SHARED OFF)\n-```\n-\n-If you already have a variable named `ENABLE_SHARED` in your project (existing\n-before the call to `add_subdirectory` with SRT), its value will be derived in\n-the SRT project, unless you override it by setting `LIBSRT_ENABLE_SHARED` to a\n-different value.\n-\n-Note that the trick works simply by getting the actual variable name through\n-cutting off the `LIBSRT_` prefix; the check whether this variable is of any use\n-will be done after that.\n-\n-\n ## List of Build Options\n \n The following table lists available build options in alphabetical order.\n@@ -108,7 +64,7 @@ Option details are given further below.\n | [`USE_ENCLIB`](#use_enclib)                                  | 1.3.3 | `STRING`  | openssl    | Encryption library to be used (`openssl`, `openssl-evp` (since 1.5.1), `gnutls`, `mbedtls`, `botan` (since 1.6.0)).                                                         |\n | [`USE_GNUSTL`](#use_gnustl)                                  | 1.3.4 | `BOOL`    | OFF        | Use `pkg-config` with the `gnustl` package name to extract the header and library path for the C++ standard library.                                 |\n | [`USE_OPENSSL_PC`](#use_openssl_pc)                          | 1.3.0 | `BOOL`    | ON         | Use `pkg-config` to find OpenSSL libraries.                                                                                                          |\n-| [`SRT_USE_OPENSSL_STATIC_LIBS`](#srt_use_openssl_static_libs)| 1.5.0 | `BOOL`    | OFF        | Link OpenSSL statically.                                                                                                                             |\n+| [`OPENSSL_USE_STATIC_LIBS`](#openssl_use_static_libs)        | 1.5.0 | `BOOL`    | OFF        | Link OpenSSL statically.                                                                                                                             |\n | [`USE_STATIC_LIBSTDCXX`](#use_static_libstdcxx)              | 1.2.0 | `BOOL`    | OFF        | Enforces linking the SRT library against the static `libstdc++` library.                                                                             |\n | [`WITH_COMPILER_PREFIX`](#with_compiler_prefix)              | 1.3.0 | `STRING`  | OFF        | Sets C/C++ toolchains as `<prefix><c-compiler>` and `<prefix><c++-compiler>`, overriding the default compiler.                                       |\n | [`WITH_COMPILER_TYPE`](#with_compiler_type)                  | 1.3.0 | `STRING`  | OFF        | Sets the compiler type to be used (values: gcc, cc, clang, etc.).                                                                                    |\n@@ -662,8 +618,8 @@ built-in one).\n When ON, uses `pkg-config` to find OpenSSL libraries. You can turn this OFF to\n force `cmake` to find OpenSSL by its own preferred method.\n \n-### SRT_USE_OPENSSL_STATIC_LIBS\n-**`--srt-use-openssl-static-libs`** (default: OFF)\n+### OPENSSL_USE_STATIC_LIBS\n+**`--openssl-use-static-libs`** (default: OFF)\n \n When ON, OpenSSL libraries are linked statically.\n When `pkg-config`(`-DUSE_OPENSSL_PC=ON`) is used, static OpenSSL libraries are listed in `SSL_STATIC_LIBRARIES`. See `<prefix>_STATIC` in [CMake's FindPkgConfig](https://cmake.org/cmake/help/latest/module/FindPkgConfig.html).\ndiff --git a/docs/build/build-win.md b/docs/build/build-win.md\nindex 1a7d7a7..e8a1e63 100644\n--- a/docs/build/build-win.md\n+++ b/docs/build/build-win.md\n@@ -2,34 +2,33 @@\n \n <!-- TOC -->\n \n-- [Building SRT on Windows](#building-srt-on-windows)\n-  - [1. Prerequisites](#1-prerequisites)\n-    - [1.1. Build Tool Dependencies](#11-build-tool-dependencies)\n-    - [1.2. External Library Dependencies](#12-external-library-dependencies)\n-      - [1.2.1. Cryptographic Library](#121-cryptographic-library)\n-      - [1.2.2. Threading Library](#122-threading-library)\n-    - [1.3. Package Managers](#13-package-managers)\n-      - [1.3.1. VCpkg Packet Manager (optional)](#131-vcpkg-packet-manager-optional)\n-      - [1.3.2. NuGet Manager (optional)](#132-nuget-manager-optional)\n-  - [2. Preparing Dependencies](#2-preparing-dependencies)\n-    - [2.1 Cryptographic Library](#21-cryptographic-library)\n-      - [2.1.1. Install OpenSSL](#211-install-openssl)\n-        - [2.1.1.1. Using vcpkg](#2111-using-vcpkg)\n-        - [2.1.1.2. Using Installer (Windows)](#2112-using-installer-windows)\n-        - [2.1.1.3. Build from Sources](#2113-build-from-sources)\n-      - [2.1.2. Install MbedTLS](#212-install-mbedtls)\n-      - [2.1.3. Install LibreSSL](#213-install-libressl)\n-    - [2.2. Threading Library](#22-threading-library)\n-      - [2.2.1. Using C++11 Threading](#221-using-c11-threading)\n-      - [2.2.2. Building PThreads](#222-building-pthreads)\n-        - [2.2.2.1. Using vcpkg](#2221-using-vcpkg)\n-        - [2.2.2.2. Using NuGet](#2222-using-nuget)\n-        - [2.2.2.3. Build pthreads4w from Sources](#2223-build-pthreads4w-from-sources)\n-        - [2.2.2.4. Build pthread-win32 from Sources](#2224-build-pthread-win32-from-sources)\n-  - [3. Building SRT](#3-building-srt)\n-    - [3.1. Cloning the Source Code](#31-cloning-the-source-code)\n-    - [3.2. Generate Build Files](#32-generate-build-files)\n-    - [3.3. Build SRT](#33-build-srt)\n+- [1. Prerequisites](#1-prerequisites)\n+  - [1.1. Build Tool Dependencies](#11-build-tool-dependencies)\n+  - [1.2. External Library Dependencies](#12-external-library-dependencies)\n+    - [1.2.1. Cryptographic Library](#121-cryptographic-library)\n+    - [1.2.2. Threading Library](#122-threading-library)\n+  - [1.3. Package Managers](#13-package-managers)\n+    - [1.3.1. VCpkg Packet Manager (optional)](#131-vcpkg-packet-manager-optional)\n+    - [1.3.2. NuGet Manager (optional)](#132-nuget-manager-optional)\n+- [2. Preparing Dependencies](#2-preparing-dependencies)\n+  - [2.1. Cryptographic Library](#21-cryptographic-library)\n+    - [2.1.1. Install OpenSSL](#211-install-openssl)\n+      - [2.1.1.1. Using vcpkg](#2111-using-vcpkg)\n+      - [2.1.1.2. Using Installer](#2112-using-installer-windows)\n+      - [2.1.1.3. Build from Sources](#2113-build-from-sources)\n+    - [2.1.2. Install MbedTLS](#212-install-mbedtls)\n+    - [2.1.3. Install LibreSSL](#213-install-libressl)\n+  - [2.2. Threading Library](#22-threading-library)\n+    - [2.2.1. Using C++11 Threading](#221-using-c11-threading)\n+    - [2.2.2. Building PThreads](#222-building-pthreads)\n+      - [2.2.2.1. Using vcpkg](#2221-using-vcpkg)\n+      - [2.2.2.2. Using NuGet](#2222-using-nuget)\n+      - [2.2.2.3. Build pthreads4w from Sources](#2223-build-pthreads4w-from-sources)\n+      - [2.2.2.4. Build pthread-win32 from Sources](#2224-build-pthread-win32-from-sources)\n+- [3. Building SRT](#3-building-srt)\n+  - [3.1. Cloning the Source Code](#31-cloning-the-source-code)\n+  - [3.2. Generate Build Files](#32-generate-build-files)\n+  - [3.3. Build SRT](#33-build-srt)\n \n <!-- /TOC -->\n \n@@ -297,7 +296,7 @@ In case vcpkg was used to build pthreads or OpenSSL, provide:\n \n - `-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\\\\scripts\\\\buildsystems\\\\vcpkg.cmake`\n \n-In case NuGet was used to get pre-built pthreads library, provide:\n+In case NuGet was used to get pre-built pthreads libray, provide:\n \n - `-DPTHREAD_INCLUDE_DIR`\n - `-DPTHREAD_LIBRARY`\ndiff --git a/docs/features/access-control.md b/docs/features/access-control.md\nindex 297295f..6375802 100644\n--- a/docs/features/access-control.md\n+++ b/docs/features/access-control.md\n@@ -82,9 +82,9 @@ password.\n - `r`: **Resource Name** identifies the name of the resource and facilitates\n selection should the listener party be able to serve multiple resources.\n - `h`: **Host Name** identifies the hostname of the resource. For example,\n-to request a stream with the URI `somehost.com/videos/query.php?vid=366` the\n+to request a stream with the URI `somehost.com/videos/querry.php?vid=366` the\n `hostname` field should have `somehost.com`, and the resource name can have\n-`videos/query.php?vid=366` or simply `366`. Note that this is still a key to be\n+`videos/querry.php?vid=366` or simply `366`. Note that this is still a key to be\n specified explicitly. Support tools that apply simplifications and URI extraction\n are expected to insert only the host portion of the URI here.\n - `s`: **Session ID** is a temporary resource identifier negotiated with\ndiff --git a/docs/features/bonding-main-backup.md b/docs/features/bonding-main-backup.md\nindex 0e0190f..b56df78 100644\n--- a/docs/features/bonding-main-backup.md\n+++ b/docs/features/bonding-main-backup.md\n@@ -26,7 +26,7 @@ Transmission happens over the main link until it is considered broken or is pres\n \n ### Sensitivity Levels\n \n-The only sensitivity level implemented at the moment is a **preemptive switch** to a backup path from an unstable main path before it breaks. The goal is to predict an upcoming link breakage before it happens, and to be ready to switch to an activated backup link while losing as few packets as possible.\n+The only sensitivity level implemented at the moment is a **pre-emptive switch** to a backup path from an unstable main path before it breaks. The goal is to predict an upcoming link breakage before it happens, and to be ready to switch to an activated backup link while losing as few packets as possible.\n \n An additional sensitivity level (**handover switch**) may be added in the future for cases where low latency and packet loss is not critical. The switch would take place once the link is actually broken, without trying to predict it thereby reducing processing overhead. Since the main path in this case is already broken, there would be a delay associated with activating the backup path resulting in a discontinuity in streaming (data loss during the switch).\n \ndiff --git a/docs/features/handshake.md b/docs/features/handshake.md\nindex 4b2daa0..f8ce9b5 100644\n--- a/docs/features/handshake.md\n+++ b/docs/features/handshake.md\n@@ -7,32 +7,31 @@ Last updated: 2018-06-28\n \n **Contents**\n \n-- [SRT Handshake](#srt-handshake)\n-  - [Overview](#overview)\n-  - [Short Introduction to SRT Packet Structure](#short-introduction-to-srt-packet-structure)\n-  - [Handshake Structure](#handshake-structure)\n-  - [The \"UDT Legacy\" and \"SRT Extended\" Handshakes](#the-udt-legacy-and-srt-extended-handshakes)\n-    - [UDT Legacy Handshake](#udt-legacy-handshake)\n-    - [Initiator and Responder](#initiator-and-responder)\n-    - [The Request Type Field](#the-request-type-field)\n-    - [The Type Field](#the-type-field)\n-  - [The Caller-Listener Handshake](#the-caller-listener-handshake)\n-    - [The Induction Phase](#the-induction-phase)\n-    - [The Conclusion Phase](#the-conclusion-phase)\n-  - [The Rendezvous Handshake](#the-rendezvous-handshake)\n-    - [HSv4 Rendezvous Process](#hsv4-rendezvous-process)\n-    - [HSv5 Rendezvous Process](#hsv5-rendezvous-process)\n-      - [Serial Handshake Flow](#serial-handshake-flow)\n-      - [Parallel Handshake Flow](#parallel-handshake-flow)\n-    - [Rendezvous Between Different Versions](#rendezvous-between-different-versions)\n-  - [The SRT Extended Handshake](#the-srt-extended-handshake)\n-    - [HSv4 Extended Handshake Process](#hsv4-extended-handshake-process)\n-    - [HSv5 Extended Handshake Process](#hsv5-extended-handshake-process)\n-    - [SRT Extension Commands](#srt-extension-commands)\n-      - [HSREQ and HSRSP](#hsreq-and-hsrsp)\n-      - [KMREQ and KMRSP](#kmreq-and-kmrsp)\n-      - [Congestion controller](#congestion-controller)\n-      - [Stream ID (SID)](#stream-id-sid)\n+- [Overview](#overview)\n+- [Short Introduction to SRT Packet Structure](#short-introduction-to-srt-packet-structure)\n+- [Handshake Structure](#handshake-structure)\n+- [The \"UDT Legacy\" and \"SRT Extended\" Handshakes](#the-udt-legacy-and-srt-extended-handshakes)\n+  - [UDT Legacy Handshake](#udt-legacy-handshake)\n+  - [Initiator and Responder](#initiator-and-responder)\n+  - [The Request Type Field](#the-request-type-field)\n+  - [The Type Field](#the-type-field)\n+- [The Caller-Listener Handshake](#the-caller-listener-handshake)\n+  - [The Induction Phase](#the-induction-phase)\n+  - [The Conclusion Phase](#the-conclusion-phase)\n+- [The Rendezvous Handshake](#the-rendezvous-handshake)\n+  - [HSv4 Rendezvous Process](#hsv4-rendezvous-process)\n+  - [HSv5 Rendezvous Process](#hsv5-rendezvous-process)\n+    - [Serial Handshake Flow](#serial-handshake-flow)\n+    - [Parallel Handshake Flow](#parallel-handshake-flow)\n+  - [Rendezvous Between Different Versions](#rendezvous-between-different-versions)\n+- [The SRT Extended Handshake](#the-srt-extended-handshake)\n+  - [HSv4 Extended Handshake Process](#hsv4-extended-handshake-process)\n+  - [HSv5 Extended Handshake Process](#hsv5-extended-handshake-process)\n+  - [SRT Extension Commands](#srt-extension-commands)\n+    - [HSREQ and HSRSP](#hsreq-and-hsrsp)\n+    - [KMREQ and KMRSP](#kmreq-and-kmrsp)\n+    - [Congestion controller](#congestion-controller)\n+    - [Stream ID (SID)](#stream-id-sid)\n \n \n ## Overview\n@@ -1553,7 +1552,7 @@ the user's choice that can be passed from the Caller to the Listener. The\n symbol for this extension is `SRT_CMD_SID`.\n \n The extension block for this extension is encoded the same way as described\n-for Congestion Controller above.\n+for Congestion Controler above.\n \n The Stream ID is a string of up to 512 characters that a Caller can pass to a\n Listener (it's actually passed from an Initiator to a Responder in general, but\n@@ -1562,4 +1561,4 @@ application should set it on a Caller socket using the `SRTO_STREAMID` option.\n Upon connection, the accepted socket on the Listener side will have exactly the\n same value set, and it can be retrieved using the same option. For more details\n about the prospective use of this option, please refer to the\n-[SRT API Socket Options](../API/API-socket-options.md) and [SRT Access Control (Stream ID) Guidelines](access-control.md).\n+[SRT API Socket Options](../API/API-socket-options.md) and [SRT Access Control (Stream ID) Guidlines](access-control.md).\ndiff --git a/docs/features/live-streaming.md b/docs/features/live-streaming.md\nindex 659e806..434f4c2 100644\n--- a/docs/features/live-streaming.md\n+++ b/docs/features/live-streaming.md\n@@ -33,7 +33,7 @@ However, the transmission must still satisfy the Live Streaming Requirements.\n \n The MPEG-TS stream, as a good example, consists of Frames. Each\n Frame is a portion of data assigned to a particular stream (usually you have\n-multiple streams interleaved, at least video and audio). The video stream always has\n+multipe streams interleaved, at least video and audio). The video stream always has\n its playing speed expressed in fps (frames per second) units. This\n value maps to a duration for one video frame. So, for example, 60 fps means that\n one video frame should be \"displayed\" for a duration of 1/60 of a second. You can\ndiff --git a/docs/features/socket-groups.md b/docs/features/socket-groups.md\nindex 359c2aa..cef0ee9 100644\n--- a/docs/features/socket-groups.md\n+++ b/docs/features/socket-groups.md\n@@ -113,7 +113,7 @@ time to realize that the link might be broken and time required for resending\n all unacknowledged packets, before the time to play comes for the received\n packets. If this time isn't met, packets will be dropped and your advantage\n of having the backup link might be impaired. According to the tests on the\n-local network it turns out that the most sensible instability timeout is about\n+local network it turns out that the most sensible unstability timeout is about\n 50ms, while normally ACK timeout is 30ms, so extra 100ms latency tax seems to\n be an absolute minimum.\n \n@@ -431,7 +431,7 @@ to maintain, whether the list is constant or can be dynamically modified, or\n whether a dead link is not to be revived by some reason - all these things are\n out of the interest of the library. It's up to the application to decide\n when and by what reason the connection is to be established. All that your\n-application has to do is to monitor the connections (that is, be conscious\n+application has to do is to monitor the conenctions (that is, be conscious\n about that particular links are up and running or get broken) and take\n appropriate action in response.\n \n@@ -514,7 +514,7 @@ by `srt_sendmsg2` or `srt_recvmsg2`.\n This is very simple. Call the sending function (recommended is `srt_sendmsg2`)\n to send the data, passing group ID in the place of socket ID. By recognizing\n the ID as group ID, this will be resolved internally as sending the payload\n-by appropriately using the bonded links as defined for particular group type.\n+by approprately using the bonded links as defined for particular group type.\n \n The current implementation for most of the bonding groups (broadcast and\n backup) relies on synchronizing the sequence numbers of the packets so that\n@@ -539,7 +539,7 @@ This is also simple from the user's perspective. Simply call the reading\n function, such as `srt_recvmsg2`, passing the group ID instead of socket\n ID.\n \n-Also the dilemma of blocking and nonblocking is the same thing. With blocking\n+Also the dillema of blocking and nonblocking is the same thing. With blocking\n mode (`SRTO_RCVSYN`), simply wait until your payload is retrieved. The internal\n group reading facility will take care that you get your payload in the right\n order and at the time to play, and the redundant payloads retrieved over\ndiff --git a/examples/fork-test/Makefile b/examples/fork-test/Makefile\ndeleted file mode 100644\nindex 57e9f3a..0000000\n--- a/examples/fork-test/Makefile\n+++ /dev/null\n@@ -1,9 +0,0 @@\n-TARGETS=srt_server srt_client\n-\n-all: $(TARGETS)\n-\n-%: %.c\n-\t$(CC) $< `pkg-config --cflags --libs srt` -o `basename $< .c`\n-\n-clean:\n-\trm -f $(TARGETS)\ndiff --git a/examples/fork-test/README.md b/examples/fork-test/README.md\ndeleted file mode 100644\nindex 59752ad..0000000\n--- a/examples/fork-test/README.md\n+++ /dev/null\n@@ -1,7 +0,0 @@\n-The `srt_server` and `srt_client` apps should be compiled using\n-external installation of SRT (e.g. in the local directory), each\n-one as a single program. This is not compiled as a part of SRT.\n-\n-If you want to use a local installation, simply set `PKG_CONFIG_PATH`\n-environment variable to point to the local installation directory with\n-\"lib/pkgconfig\" or \"lib64/pkgconfig\" suffix.\ndiff --git a/examples/fork-test/srt_client.c b/examples/fork-test/srt_client.c\ndeleted file mode 100644\nindex ab69d59..0000000\n--- a/examples/fork-test/srt_client.c\n+++ /dev/null\n@@ -1,55 +0,0 @@\n-#include <srt/srt.h>\n-#include <stdio.h>\n-#include <stdlib.h>\n-#include <string.h>\n-#include <arpa/inet.h>\n-#include <unistd.h>\n-#include <sys/types.h>\n-#include <sys/wait.h>\n-#define SERVER_IP \"127.0.0.1\"\n-#define SERVER_PORT 9000\n-int main() {\n-    if (srt_startup() != 0) {\n-        fprintf(stderr, \"Error initializing SRT.\\n\");\n-        return 1;\n-    }\n-    SRTSOCKET client_sock = srt_create_socket();\n-    if (client_sock == SRT_INVALID_SOCK) {\n-        fprintf(stderr, \"Error creating a socket: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    struct sockaddr_in sa;\n-    memset(&sa, 0, sizeof sa);\n-    sa.sin_family = AF_INET;\n-    sa.sin_port = htons(SERVER_PORT);\n-    inet_pton(AF_INET, SERVER_IP, &sa.sin_addr);\n-    if (srt_connect(client_sock, (struct sockaddr*)&sa, sizeof(sa)) == SRT_ERROR) {\n-        fprintf(stderr, \"Error: srt_connect: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    printf(\"Connected to SRT server %s:%d\\n\", SERVER_IP, SERVER_PORT);\n-    const char* message = \"Hello from SRT client!\";\n-    int bytes = srt_send(client_sock, message, strlen(message));\n-    if (bytes == SRT_ERROR) {\n-        fprintf(stderr, \"Sending error: %s\\n\", srt_getlasterror_str());\n-    } else {\n-        printf(\"Message sent: %s\\n\", message);\n-    }\n-\n-    while (1)\n-    {\n-        char buffer[1500];\n-        int nb = srt_recv(client_sock, buffer, sizeof(buffer));\n-        if (nb <= 0)\n-        {\n-            printf(\"Closed from the server !\\n\");\n-            srt_close(client_sock);\n-            break;\n-        }\n-        buffer[nb] = 0;\n-        printf(\"Server has sent: %s\\n\", buffer);\n-    }\n-    srt_cleanup();\n-    return 0;\n-}\n-\ndiff --git a/examples/fork-test/srt_server.c b/examples/fork-test/srt_server.c\ndeleted file mode 100644\nindex 168b9c1..0000000\n--- a/examples/fork-test/srt_server.c\n+++ /dev/null\n@@ -1,118 +0,0 @@\n-#include <srt/srt.h>\n-#include <stdio.h>\n-#include <stdlib.h>\n-#include <string.h>\n-#include <unistd.h>\n-#include <sys/types.h>\n-#include <sys/wait.h>\n-#include <pthread.h>\n-#define PORT 9000\n-\n-int run(char *command) {\n-    pid_t pid = fork();\n-    if (pid < 0) {\n-        perror(\"fork (intermediate)\");\n-        exit(EXIT_FAILURE);\n-    }\n-    if (pid > 0) {\n-        // Parent process\n-        printf(\"[GRANDPARENT %d] waiting for grand-child process pid=%d to finish...\\n\",\n-                             getpid(),                               pid);\n-        waitpid(pid, NULL, 0);  // Wait for intermediate child\n-        printf(\"[GRANDPARENT] returning\\n\");\n-        return 0;\n-    }\n-    // Intermediate process\n-    //srt_cleanup();\n-    if (setsid() < 0) {\n-        perror(\"setsid\");\n-        exit(EXIT_FAILURE);\n-    }\n-    pid_t grandchild_pid = fork();\n-    if (grandchild_pid < 0) {\n-        perror(\"fork (grandchild)\");\n-        exit(EXIT_FAILURE);\n-    }\n-    if (grandchild_pid > 0) {\n-        printf(\"[PARENT %d] waiting for 10s with child process pid=%d ...\\n\",\n-                        getpid(),                                  grandchild_pid);\n-        // Intermediate process exits immediately\n-        sleep(10);\n-        printf(\"[PARENT] exiting\\n\");\n-        exit(0);\n-    }\n-    // Grandchild process\n-    // Redirect stdin to /dev/null\n-    printf(\"[CHILD %d] Preparing descriptors...\\n\", getpid());\n-    int devnull = open(\"/dev/null\", O_RDONLY);\n-    if (devnull >= 0) {\n-        dup2(devnull, STDIN_FILENO);\n-        close(devnull);\n-    } else {\n-        perror(\"open /dev/null\");\n-    }\n-    // Redirect stdout to stderr\n-    dup2(STDERR_FILENO, STDOUT_FILENO);\n-    // Execute the command\n-    printf(\"[CHILD] Executing process '%s'...\\n\", command);\n-    execl(\"/bin/sh\", \"sh\", \"-c\", command, (char *)NULL);\n-    // If execl fails\n-    perror(\"execl\");\n-    exit(EXIT_FAILURE);\n-}\n-\n-int main() {\n-    if (srt_startup() != 0) {\n-        fprintf(stderr, \"Error initializing SRT.\\n\");\n-        return 1;\n-    }\n-\n-    SRTSOCKET serv_sock = srt_create_socket();\n-    if (serv_sock == SRT_INVALID_SOCK) {\n-        fprintf(stderr, \"Error creating SRT socket: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    struct sockaddr_in sa;\n-    memset(&sa, 0, sizeof sa);\n-    sa.sin_family = AF_INET;\n-    sa.sin_port = htons(PORT);\n-    sa.sin_addr.s_addr = INADDR_ANY;\n-    if (srt_bind(serv_sock, (struct sockaddr*)&sa, sizeof sa) == SRT_ERROR) {\n-        fprintf(stderr, \"Error: srt_bind: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    if (srt_listen(serv_sock, 5) == SRT_ERROR) {\n-        fprintf(stderr, \"Error: srt_listen: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    printf(\"SRT server is listening on port %d...\\n\", PORT);\n-    struct sockaddr_in client_addr;\n-    int addr_len = sizeof(client_addr);\n-    SRTSOCKET client_sock = srt_accept(serv_sock, (struct sockaddr*)&client_addr, &addr_len);\n-    if (client_sock == SRT_INVALID_SOCK) {\n-        fprintf(stderr, \"Error: srt_accept: %s\\n\", srt_getlasterror_str());\n-        return 1;\n-    }\n-    printf(\"Client connected via SRT !\\n\");\n-    char buffer[1500];\n-    int bytes = srt_recv(client_sock, buffer, sizeof(buffer));\n-    if (bytes > 0) {\n-        buffer[bytes] = '\\0';\n-        printf(\"Message received: %s\\n\", buffer);\n-        const char resp [] = \"We read you!\";\n-        srt_send(client_sock, resp, (sizeof resp)-1);\n-    } else {\n-        printf(\"Error: reading from srt_recv: %s.\\n\", srt_getlasterror_str());\n-    }\n-    run(\"date > /tmp/res\");\n-    printf(\"Server: sleep(1)\\n\");\n-    sleep(1);\n-    // Nettoyage\n-    printf(\"Server: closing SRT sockets\\n\");\n-    srt_close(client_sock);\n-    srt_close(serv_sock);\n-    printf(\"Server: cleanup\\n\");\n-    srt_cleanup();\n-    printf(\"Server: exit\\n\");\n-    return 0;\n-}\ndiff --git a/haicrypt/cryspr-botan.h b/haicrypt/cryspr-botan.h\nindex 6de59c8..704d296 100644\n--- a/haicrypt/cryspr-botan.h\n+++ b/haicrypt/cryspr-botan.h\n@@ -46,7 +46,7 @@ typedef struct botan_aes_context\n #define CRYSPR_HAS_PBKDF2 1\n \n /*\n-#define CRYSPR_AESCTX to the CRYSPR-specific AES key context object.\n+#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object.\n This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK\n It is set from the keystring through CRYSPR_methods.aes_set_key and passed\n to CRYSPR_methods.aes_XXX.\ndiff --git a/haicrypt/cryspr-gnutls.c b/haicrypt/cryspr-gnutls.c\nindex b8cecf3..95eaf28 100644\n--- a/haicrypt/cryspr-gnutls.c\n+++ b/haicrypt/cryspr-gnutls.c\n@@ -187,7 +187,7 @@ CRYSPR_methods *crysprGnuTLS(void)\n         crysprGnuTLS_methods.aes_ecb_cipher = crysprGnuTLS_AES_EcbCipher;\n     #endif\n     #if !CRYSPR_HAS_PBKDF2\n-        crysprGnuTLS_methods.sha1_msg_digest= crysprGnuTLS_SHA1_MsgDigest; //Only required if using generic KmPbkdf2\n+        crysprGnuTLS_methods.sha1_msg_digest= crysprGnuTLS_SHA1_MsgDigest; //Onl required if using generic KmPbkdf2\n     #endif\n \n     //--Crypto Session (Top API)\ndiff --git a/haicrypt/cryspr-gnutls.h b/haicrypt/cryspr-gnutls.h\nindex 53ae72c..78f7c86 100644\n--- a/haicrypt/cryspr-gnutls.h\n+++ b/haicrypt/cryspr-gnutls.h\n@@ -48,9 +48,9 @@ written by\n #define CRYSPR_HAS_PBKDF2 1\n \n /*\n-#define CRYSPR_AESCTX to the CRYSPR-specific AES key context object.\n+#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object.\n This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK\n-It is set from the keystring through CRYSPR_methods.aes_set_key and passed\n+It is set from hte keystring through CRYSPR_methods.aes_set_key and passed\n to CRYSPR_methods.aes_XXX.\n */\n typedef struct aes_ctx CRYSPR_AESCTX;   /* CRYpto Service PRovider AES key context */\ndiff --git a/haicrypt/cryspr-mbedtls.c b/haicrypt/cryspr-mbedtls.c\nindex 5b3d2db..a961cca 100644\n--- a/haicrypt/cryspr-mbedtls.c\n+++ b/haicrypt/cryspr-mbedtls.c\n@@ -246,7 +246,7 @@ CRYSPR_methods *crysprMbedtls(void)\n     crysprMbedtls_methods.aes_ecb_cipher = crysprMbedtls_AES_EcbCipher;\n #endif\n #if !CRYSPR_HAS_PBKDF2\n-    crysprMbedtls_methods.sha1_msg_digest= crysprMbedtls_SHA1_MsgDigest; //Only required if using generic KmPbkdf2\n+    crysprMbedtls_methods.sha1_msg_digest= crysprMbedtls_SHA1_MsgDigest; //Onl required if using generic KmPbkdf2\n #endif\n \n     //--Crypto Session (Top API)\ndiff --git a/haicrypt/cryspr-mbedtls.h b/haicrypt/cryspr-mbedtls.h\nindex aff218a..f62b32e 100644\n--- a/haicrypt/cryspr-mbedtls.h\n+++ b/haicrypt/cryspr-mbedtls.h\n@@ -50,7 +50,7 @@ written by\n #endif\n \n /*\n-#define CRYSPR_AESCTX to the CRYSPR-specific AES key context object.\n+#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object.\n This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK\n It is set from the keystring through CRYSPR_methods.aes_set_key and passed\n to CRYSPR_methods.aes_XXX.\ndiff --git a/haicrypt/cryspr-openssl-evp.c b/haicrypt/cryspr-openssl-evp.c\nindex 02cfb59..3e87e9a 100644\n--- a/haicrypt/cryspr-openssl-evp.c\n+++ b/haicrypt/cryspr-openssl-evp.c\n@@ -385,7 +385,7 @@ CRYSPR_methods* crysprOpenSSL_EVP(void)\n #if !(CRYSPR_HAS_AESCTR && CRYSPR_HAS_AESKWRAP)\n         /* AES-ECB only required if cryspr has no AES-CTR and no AES KeyWrap */\n         /* OpenSSL has both AESCTR and AESKWRP and the AESECB wrapper is only used\n-           to test the fallback methods */\n+           to test the falback methods */\n         crysprOpenSSL_EVP_methods.aes_ecb_cipher = crysprOpenSSL_EVP_AES_EcbCipher;\n #endif\n #if !CRYSPR_HAS_PBKDF2\ndiff --git a/haicrypt/cryspr-openssl-evp.h b/haicrypt/cryspr-openssl-evp.h\nindex 3e2932e..a1fb0b9 100644\n--- a/haicrypt/cryspr-openssl-evp.h\n+++ b/haicrypt/cryspr-openssl-evp.h\n@@ -55,9 +55,9 @@ written by\n #define CRYSPR_HAS_PBKDF2 1 /* Define to 1 if CRYSPR has Password-based Key Derivaion Function 2 */\n \n /*\n-#define CRYSPR_AESCTX to the CRYSPR-specific AES key context object.\n+#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object.\n This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK\n-It is set from the keystring through CRYSPR_methods.aes_set_key and passed\n+It is set from hte keystring through CRYSPR_methods.aes_set_key and passed\n to CRYSPR_methods.aes_*.\n */\n typedef EVP_CIPHER_CTX CRYSPR_AESCTX; /* CRYpto Service PRovider AES key context */\ndiff --git a/haicrypt/cryspr-openssl.c b/haicrypt/cryspr-openssl.c\nindex 2839d0e..87eb535 100644\n--- a/haicrypt/cryspr-openssl.c\n+++ b/haicrypt/cryspr-openssl.c\n@@ -207,7 +207,7 @@ CRYSPR_methods *crysprOpenSSL(void)\n     #if !(CRYSPR_HAS_AESCTR && CRYSPR_HAS_AESKWRAP)\n         /* AES-ECB only required if cryspr has no AES-CTR and no AES KeyWrap */\n         /* OpenSSL has both AESCTR and AESKWRP and the AESECB wrapper is only used\n-           to test the fallback methods */\n+           to test the falback methods */\n         crysprOpenSSL_methods.aes_ecb_cipher = crysprOpenSSL_AES_EcbCipher;\n     #endif\n     #if !CRYSPR_HAS_PBKDF2\ndiff --git a/haicrypt/cryspr-openssl.h b/haicrypt/cryspr-openssl.h\nindex 2ebfe75..75a5251 100644\n--- a/haicrypt/cryspr-openssl.h\n+++ b/haicrypt/cryspr-openssl.h\n@@ -52,9 +52,9 @@ written by\n #define CRYSPR_HAS_PBKDF2 1             /* Define to 1 if CRYSPR has Password-based Key Derivaion Function 2 */\n \n /*\n-#define CRYSPR_AESCTX to the CRYSPR-specific AES key context object.\n+#define CRYSPR_AESCTX to the CRYSPR specifix AES key context object.\n This type reserves room in the CRYPSPR control block for Haicrypt KEK and SEK\n-It is set from the keystring through CRYSPR_methods.aes_set_key and passed\n+It is set from hte keystring through CRYSPR_methods.aes_set_key and passed\n to CRYSPR_methods.aes_*.\n */\n typedef AES_KEY CRYSPR_AESCTX;          /* CRYpto Service PRovider AES key context */\ndiff --git a/haicrypt/cryspr.h b/haicrypt/cryspr.h\nindex febde4a..42426f4 100644\n--- a/haicrypt/cryspr.h\n+++ b/haicrypt/cryspr.h\n@@ -148,7 +148,7 @@ typedef struct tag_CRYSPR_methods {\n \n         /*\n         * km_setkey:\n-        * Set the Key Encrypting Key for Wrap (Encryption) or UnWrap (Decryption).\n+        * Set the Key Encypting Key for Wrap (Encryption) or UnWrap (Decryption).\n         * Context (ctx) tells if it's for Wrap or Unwrap\n         * A Context flags (ctx->flags) also tells if this is for wrap(encryption) or unwrap(decryption) context (HCRYPT_CTX_F_ENCRYPT)\n         */\ndiff --git a/haicrypt/haicrypt.h b/haicrypt/haicrypt.h\nindex 573efbf..da0ad34 100644\n--- a/haicrypt/haicrypt.h\n+++ b/haicrypt/haicrypt.h\n@@ -106,9 +106,6 @@ int  HaiCrypt_Tx_Process(HaiCrypt_Handle hhc, unsigned char *in, size_t in_len,\n int  HaiCrypt_Rx_Process(HaiCrypt_Handle hhc, unsigned char *in, size_t in_len,\n                          void *out_p[], size_t out_len_p[], int maxout);\n \n-// Length not needed, as long as it's pre-verified that it's at least SALT length.\n-int  HaiCrypt_GetKeyIndex(HaiCrypt_Handle hhc, unsigned char *in);\n-\n int  HaiCrypt_Tx_GetKeyFlags(HaiCrypt_Handle hhc);\n int  HaiCrypt_Tx_ManageKeys(HaiCrypt_Handle hhc, void *out_p[], size_t out_len_p[], int maxout);\n int  HaiCrypt_Tx_Data(HaiCrypt_Handle hhc, unsigned char *pfx, unsigned char *data, size_t data_len);\ndiff --git a/haicrypt/hcrypt.c b/haicrypt/hcrypt.c\nindex 62fb6de..a2b81d8 100644\n--- a/haicrypt/hcrypt.c\n+++ b/haicrypt/hcrypt.c\n@@ -91,7 +91,7 @@ static hcrypt_Session* sHaiCrypt_PrepareHandle(const HaiCrypt_Cfg* cfg, HaiCrypt\n     crypto->km.refresh_rate = cfg->km_refresh_rate_pkt;\n     crypto->km.pre_announce = cfg->km_pre_announce_pkt;\n \n-    /* Identify each context */\n+    /* Indentify each context */\n     crypto->ctx_pair[0].flags = HCRYPT_MSG_F_eSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);\n     crypto->ctx_pair[1].flags = HCRYPT_MSG_F_oSEK | (tx ? HCRYPT_CTX_F_ENCRYPT : 0);\n     /* Point to each other */\n@@ -307,7 +307,7 @@ int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handl\n         timerclear(&cryptoClone->km.tx_last);\n \n         /* Adjust pointers  pointing into cryproSrc after copy\n-           msg_info and crysprs are extern static so this is ok*/\n+           msg_info and crysprs are extern statics so this is ok*/\n         cryptoClone->ctx_pair[0].alt = &cryptoClone->ctx_pair[1];\n         cryptoClone->ctx_pair[1].alt = &cryptoClone->ctx_pair[0];\n \n@@ -327,7 +327,7 @@ int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handl\n         }\n \n         /* Clear salt to force later regeneration of KEK as AES decrypting key,\n-           copied one is encrypting key */\n+           copyed one is encrypting key */\n         cryptoClone->ctx_pair[0].flags &= ~HCRYPT_CTX_F_ENCRYPT;\n         cryptoClone->ctx_pair[1].flags &= ~HCRYPT_CTX_F_ENCRYPT;\n         memset(cryptoClone->ctx_pair[0].salt, 0, sizeof(cryptoClone->ctx_pair[0].salt));\ndiff --git a/haicrypt/hcrypt_ctx_rx.c b/haicrypt/hcrypt_ctx_rx.c\nindex 907acdf..2b67490 100644\n--- a/haicrypt/hcrypt_ctx_rx.c\n+++ b/haicrypt/hcrypt_ctx_rx.c\n@@ -152,25 +152,24 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m\n \t\treturn(-1);\n \t}\n \n-\thcrypt_Ctx new_ctx = *ctx;\n \t/* Check Salt and get if new */\n-\tif ((salt_len != new_ctx.salt_len)\n-\t||  (0 != memcmp(new_ctx.salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len))) {\n+\tif ((salt_len != ctx->salt_len)\n+\t||  (0 != memcmp(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len))) {\n \t\t/* Salt changed (or 1st KMmsg received) */\n-\t\tmemcpy(new_ctx.salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);\n-\t\tnew_ctx.salt_len = salt_len;\n+\t\tmemcpy(ctx->salt, &km_msg[HCRYPT_MSG_KM_OFS_SALT], salt_len);\n+\t\tctx->salt_len = salt_len;\n \t\tdo_pbkdf = 1; /* Impact on password derived kek */\n \t}\n \n \t/* Check SEK length and get if new */\n-\tif (sek_len != new_ctx.sek_len) {\n+\tif (sek_len != ctx->sek_len) {\n \t\t/* Key length changed or 1st KMmsg received */\n-\t\tnew_ctx.sek_len = sek_len;\n+\t\tctx->sek_len = sek_len;\n \t\tdo_pbkdf = 1; /* Impact on password derived kek */\n \t}\n \n \t/* Check cipher mode */\n-\tif (new_ctx.mode != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])\n+\tif (ctx->mode != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])\n \t{\n \t\tHCRYPT_LOG(LOG_WARNING, \"%s\", \"cipher mode mismatch\\n\");\n \t\treturn(-3);\n@@ -180,32 +179,21 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m\n \t * Regenerate KEK if it is password derived\n \t * and Salt or SEK length changed\n \t */\n-\tint rollback_kek = 0;\n-\tif (new_ctx.cfg.pwd_len && do_pbkdf) {\n-\t\tif (hcryptCtx_GenSecret(crypto, &new_ctx)) {\n+\tif (ctx->cfg.pwd_len && do_pbkdf) {\n+\t\tif (hcryptCtx_GenSecret(crypto, ctx)) {\n \t\t\treturn(-1);\n \t\t}\n-\t\tnew_ctx.status = HCRYPT_CTX_S_SARDY;\n+\t\tctx->status = HCRYPT_CTX_S_SARDY;\n \t\tkek_len = sek_len;\t/* KEK changed */\n-\t\trollback_kek = 1;\n \t}\n \n \t/* Unwrap SEK(s) and set in context */\n-\tunsigned int msglen = (sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ;\n-\tint wrc = crypto->cryspr->km_unwrap(crypto->cryspr_cb, seks,\n-\t\t\t&km_msg[HCRYPT_MSG_KM_OFS_SALT + salt_len], msglen);\n-\n-\tif (wrc < 0) {\n-\t\tHCRYPT_LOG(LOG_WARNING, \"%s%s\\n\", \"unwrap key failed - internal KEK: \", rollback_kek ? \"ROLLBACK\" : \"unchanged\");\n-\t\t// Rollback the call to hcryptCtx_GenSecret done on the new_ctx,\n-\t\t// and restore the old secret from old ctx. GenSecret is required by\n-\t\t// km_unwrap, but only after failed call we know this should remain unchanged.\n-\t\tif (rollback_kek) {\n-\t\t\thcryptCtx_GenSecret(crypto, ctx);\n-\t\t}\n+\tif (0 > crypto->cryspr->km_unwrap(crypto->cryspr_cb, seks,\n+\t\t&km_msg[HCRYPT_MSG_KM_OFS_SALT + salt_len], \n+\t\t(unsigned int)((sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ))) {\n+\t\tHCRYPT_LOG(LOG_WARNING, \"%s\", \"unwrap key failed\\n\");\n \t\treturn(-2); //Report unmatched shared secret\n \t}\n-    *ctx = new_ctx;\n \t/*\n \t * First SEK in KMmsg is eSEK if both SEK present\n \t */\ndiff --git a/haicrypt/hcrypt_ctx_tx.c b/haicrypt/hcrypt_ctx_tx.c\nindex 75f861c..e66c949 100644\n--- a/haicrypt/hcrypt_ctx_tx.c\n+++ b/haicrypt/hcrypt_ctx_tx.c\n@@ -110,7 +110,7 @@ int hcryptCtx_Tx_CloneKey(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const hcrypt_\n \tconst hcrypt_Ctx* ctxSrc = cryptoSrc->ctx;\n \tif (!ctxSrc)\n \t{\n-\t\t/* Probably the context is not yet completely initialized, so\n+\t\t/* Probbly the context is not yet completely initialized, so\n \t\t * use blindly the first context from the pair\n \t\t */\n \t\tctxSrc = &cryptoSrc->ctx_pair[0];\ndiff --git a/haicrypt/hcrypt_msg.h b/haicrypt/hcrypt_msg.h\nindex 0249975..c35ddd0 100644\n--- a/haicrypt/hcrypt_msg.h\n+++ b/haicrypt/hcrypt_msg.h\n@@ -42,7 +42,7 @@ typedef uint32_t hcrypt_Pki;\n \n #define HCRYPT_MSG_PT_MS    1       /* Media stream */\n #define HCRYPT_MSG_PT_KM    2       /* Keying Material */\n-#define HCRYPT_MSG_PT_RESV7 7       /* Reserved to discriminate MPEG-TS packet (SyncByte=0x47) */\n+#define HCRYPT_MSG_PT_RESV7 7       /* Reserved to dicriminate MPEG-TS packet (SyncByte=0x47) */\n \n \n #define HCRYPT_MSG_F_eSEK   0x01    /* Even Stream Encrypting Key */\ndiff --git a/haicrypt/hcrypt_rx.c b/haicrypt/hcrypt_rx.c\nindex 4cb3f84..2f7e847 100644\n--- a/haicrypt/hcrypt_rx.c\n+++ b/haicrypt/hcrypt_rx.c\n@@ -61,29 +61,6 @@ int HaiCrypt_Rx_Data(HaiCrypt_Handle hhc,\n \treturn(nb);\n }\n \n-int HaiCrypt_GetKeyIndex(HaiCrypt_Handle hhc, unsigned char* in_msg)\n-{\n-\thcrypt_Session *crypto = (hcrypt_Session *)hhc;\n-\tint msg_type;\n-\n-\tif ((NULL == crypto)\n-\t||  (NULL == in_msg)) {\n-\n-\t\tHCRYPT_LOG(LOG_ERR, \"%s\", \"invalid parameters\\n\");\n-\t\treturn(-1);\n-\t}\n-\n-\t/* Validate HaiCrypt message */\n-\tif (0 > (msg_type = hcryptMsg_SRT_ParseMsg(crypto->msg_info, in_msg))) {\n-\t\treturn(-1);\n-\t}\n-\n-    if (msg_type != HCRYPT_MSG_PT_KM)\n-        return -1;\n-\n-    return hcryptMsg_GetKeyIndex(crypto->msg_info, in_msg);\n-}\n-\n int HaiCrypt_Rx_Process(HaiCrypt_Handle hhc, \n \tunsigned char *in_msg, size_t in_len, \n \tvoid *out_p[], size_t out_len_p[], int maxout)\n@@ -122,13 +99,6 @@ int HaiCrypt_Rx_Process(HaiCrypt_Handle hhc,\n \t\t\tHCRYPT_LOG(LOG_ERR, \"%s\", \"cryspr had no decryptor\\n\");\n \t\t\tnbout = -1;\n \t\t} else if (ctx->status >= HCRYPT_CTX_S_KEYED) {\n-            if ((int)(in_len) <= crypto->msg_info->pfx_len)\n-            {\n-                // XXX NOTE: SRT doesn't use this type of messages, so it shouldn't\n-                // be a danger, but then you can still find something like that on the wire.\n-                HCRYPT_LOG(LOG_ERR, \"%s%d\", \"Invalid enc data packet: \", in_len);\n-                return -1;\n-            }\n \t\t\thcrypt_DataDesc indata;\n \t\t\tindata.pfx      = in_msg;\n \t\t\tindata.payload  = &in_msg[crypto->msg_info->pfx_len];\ndiff --git a/scripts/ShowProjectConfig.cmake b/scripts/ShowProjectConfig.cmake\nindex 9fc275b..108dde5 100644\n--- a/scripts/ShowProjectConfig.cmake\n+++ b/scripts/ShowProjectConfig.cmake\n@@ -166,7 +166,7 @@ function(ShowProjectConfig)\n       \"    ENABLE_MONOTONIC_CLOCK: ${ENABLE_MONOTONIC_CLOCK}\\n\"\n       \"    ENABLE_STDCXX_SYNC: ${ENABLE_STDCXX_SYNC}\\n\"\n       \"    USE_OPENSSL_PC: ${USE_OPENSSL_PC}\\n\"\n-      \"    SRT_USE_OPENSSL_STATIC_LIBS: ${SRT_USE_OPENSSL_STATIC_LIBS}\\n\"\n+      \"    OPENSSL_USE_STATIC_LIBS: ${OPENSSL_USE_STATIC_LIBS}\\n\"\n       \"    USE_BUSY_WAITING: ${USE_BUSY_WAITING}\\n\"\n       \"    USE_GNUSTL: ${USE_GNUSTL}\\n\"\n       \"    ENABLE_SOCK_CLOEXEC: ${ENABLE_SOCK_CLOEXEC}\\n\"\ndiff --git a/scripts/abi-check.tcl b/scripts/abi-check.tcl\ndeleted file mode 100644\nindex 7f9c70e..0000000\n--- a/scripts/abi-check.tcl\n+++ /dev/null\n@@ -1,76 +0,0 @@\n-#!/usr/bin/tclsh\n-\n-set here [file dirname $argv0] ;# points to [git top]/scripts\n-set top [file normalize $here/..]\n-\n-set abichecker [file normalize [file join $top submodules abi-compliance-checker abi-compliance-checker.pl]]\n-\n-if { ![file exists $abichecker] } {\n-\tputs stderr \"Please update submodules first (compliance checker not found in the current view)\"\n-\texit 1\n-}\n-\n-# Check if abi-dumper is installed\n-\n-set abidumper [auto_execok abi-dumper]\n-if {$abidumper == \"\"} {\n-\tset installer \"\"\n-\tforeach ii {zypper dnf apt} {\n-\t\tif {[auto_execok $ii] != \"\"} {\n-\t\t\tset installer $ii\n-\t\t\tbreak\n-\t\t}\n-\t}\n-\tif {$installer != \"\"} {\n-\t\tputs stderr \"ABI dumper not installed. Use such commands to install\\n\"\n-\t\tputs stderr \" $installer install abi-dumper\"\n-\t} else {\n-\t\tputs stderr \"ABI dumper not installed. Find out how to install abi-dumper in your system.\"\n-\t}\n-\texit 1\n-}\n-\n-# Arguments:\n-# <abi-check> [directory-with-base] [directory-with-pr]\n-\n-# NOTE: ABI dump will be done in every build directory as specified.\n-\n-proc generate-abi-dump {directory lver} {\n-\tset wd [pwd]\n-\tcd $directory\n-\tglobal top\n-\n-\t# You should have libsrt.so in this directory.\n-\t# Use [glob] to use exception if no file exists\n-\tglob libsrt.so\n-\n-    exec >@stdout 2>@stderr abi-dumper libsrt.so -o libsrt-abi.dump -public-headers $top/srtcore -lver $lver\n-\tcd $wd\n-}\n-\n-set olddir [lindex $argv 0]\n-set newdir [lindex $argv 1]\n-\n-if {![file isdirectory $olddir] || ![file isdirectory $newdir]} {\n-\tputs stderr \"Wrong arguments. Required <old> <new> build directory\"\n-\texit 1\n-}\n-\n-set wd [pwd]\n-cd $olddir\n-set base_ver [exec $top/scripts/get-build-version.tcl]\n-cd $wd\n-cd $newdir\n-set new_ver [exec $top/scripts/get-build-version.tcl]\n-cd $wd\n-\n-generate-abi-dump $olddir $base_ver\n-generate-abi-dump $newdir $new_ver\n-\n-set res [catch {exec >@stdout 2>@stderr $abichecker -l libsrt -old $olddir/libsrt-abi.dump -new $newdir/libsrt-abi.dump} out]\n-\n-if {$res} {\n-\tputs stderr \"ABI compat problems found!!!\\nSee the HTML report\"\n-}\n-\n-\ndiff --git a/scripts/build-ios/README.md b/scripts/build-ios/README.md\ndeleted file mode 100644\nindex 6398628..0000000\n--- a/scripts/build-ios/README.md\n+++ /dev/null\n@@ -1,3 +0,0 @@\n-## Scripts for building SRT for iOS/tvOS\n-\n-See [Building SRT for iOS/tvOS](../../docs/build/build-iOS.md) for the instructions.\ndiff --git a/scripts/build-ios/mksrt-xcf.sh b/scripts/build-ios/mksrt-xcf.sh\ndeleted file mode 100755\nindex 59022cd..0000000\n--- a/scripts/build-ios/mksrt-xcf.sh\n+++ /dev/null\n@@ -1,60 +0,0 @@\n-#!/bin/zsh\n-\n-# Determine the path of the executing script\n-BASE_DIR=$(readlink -f $0 | xargs dirname)\n-\n-srt=\"../..\"\n-ssl=$BASE_DIR/OpenSSL\n-out=$BASE_DIR/libsrt\n-target=13.0\n-tv_target=14.0\n-tvos_sdk=`xcrun -sdk appletvos --show-sdk-version`\n-lib=libsrt.a\n-\n-ios_archs=('arm64' 'arm64' 'x86_64' 'arm64' 'arm64' 'x86_64')\n-ios_platforms=('OS' 'ARM_SIMULATOR' 'SIMULATOR64' 'TV' 'TV_ARM_SIMULATOR' 'TV_SIMULATOR' )\n-ios_targets=('iOS-arm64' 'iOS-simArm' 'iOS-simIntel64' 'tvOS' 'tvOS_simArm' 'tvOS_simIntel64')\n-ssl_folders=('iphoneos' 'iphonesimulator' 'iphonesimulator' 'appletvos' 'appletvsimulator' 'appletvsimulator')\n-rm -rf $out\n-\n-cd $srt\n-\n-for idx in {1..$#ios_archs}\n-do\n- ios_arch=${ios_archs[$idx]}\n- ios_platform=${ios_platforms[$idx]}\n- dest=${ios_targets[$idx]}\n- ssl_path=${ssl}/${ssl_folders[$idx]}\n-\n- git clean -fd -e scripts\n- echo '********************************************************************************'\n- echo SSL_PATH $ssl_path ARCH $ios_arch PLATFORM $ios_platform\n-\n- CMAKE_GENERATOR=Xcode ./configure \\\n- --enable-shared=OFF --enable-apps=OFF \\\n- --cmake-toolchain-file=scripts/iOS.cmake --ios-arch=$ios_arch --ios-platform=$ios_platform \\\n- --cmake-xcode-attribute-iphoneos-deployment-target=$target \\\n- --cmake-xcode-attribute-tvos-deployment-target=$tv_target \\\n- --cmake-prefix-path=$ssl_path --use-openssl-pc=OFF \\\n- --cmake_install_prefix=$out/$dest\n-\n- cmake --build . --target install --config Release\n- echo '********************************************************************************'\n-done\n-\n-git clean -fd -e scripts\n-\n-lipo -create $out/iOS-simArm/lib/$lib $out/iOS-simIntel64/lib/$lib -output $out/libsrt-ios-sim.a\n-lipo -create $out/tvOS_simArm/lib/$lib $out/tvOS_simIntel64/lib/$lib -output $out/libsrt-tv-sim.a\n-\n-srt_headers=$out/iOS-arm64/include\n-rm -rf $BASE_DIR/libsrt.xcframework\n-\n-echo '####### create XCFramework bundle #######'\n-\n-xcodebuild -create-xcframework \\\n- -library $out/iOS-arm64/lib/$lib -headers $srt_headers \\\n- -library $out/libsrt-ios-sim.a -headers $srt_headers \\\n- -library $out/tvOS/lib/$lib -headers $srt_headers \\\n- -library $out/libsrt-tv-sim.a -headers $srt_headers \\\n- -output $BASE_DIR/libsrt.xcframework\ndiff --git a/scripts/build-ios/mkssl-xcf.sh b/scripts/build-ios/mkssl-xcf.sh\ndeleted file mode 100755\nindex c7283d7..0000000\n--- a/scripts/build-ios/mkssl-xcf.sh\n+++ /dev/null\n@@ -1,22 +0,0 @@\n-#!/bin/zsh\n-\n-# Determine the path of the executing script\n-BASE_DIR=$(readlink -f $0 | xargs dirname)\n-\n-REPO_DIR=OpenSSL\n-SSL_DIR=$BASE_DIR/$REPO_DIR\n-\n-if [ ! -d $REPO_DIR ]\n-then\n-  git clone https://github.com/krzyzanowskim/OpenSSL\n-fi\n-cd $REPO_DIR\n-make build\n-\n-rm -rf $BASE_DIR/libcrypto.xcframework\n-xcodebuild -create-xcframework \\\n- -library $SSL_DIR/iphoneos/lib/libcrypto.a \\\n- -library $SSL_DIR/iphonesimulator/lib/libcrypto.a \\\n- -library $SSL_DIR/appletvos/lib/libcrypto.a \\\n- -library $SSL_DIR/appletvsimulator/lib/libcrypto.a \\\n- -output $BASE_DIR/libcrypto.xcframework\ndiff --git a/scripts/build-windows.ps1 b/scripts/build-windows.ps1\nindex a65247c..6658615 100644\n--- a/scripts/build-windows.ps1\n+++ b/scripts/build-windows.ps1\n@@ -17,7 +17,6 @@ param (\n     [Parameter()][String]$STATIC_LINK_SSL = \"OFF\",\r\n     [Parameter()][String]$CXX11 = \"ON\",\r\n     [Parameter()][String]$BUILD_APPS = \"ON\",\r\n-    [Parameter()][String]$BUILD_TESTAPPS = \"OFF\",\r\n     [Parameter()][String]$UNIT_TESTS = \"OFF\",\r\n     [Parameter()][String]$BUILD_DIR = \"_build\",\r\n     [Parameter()][String]$VCPKG_OPENSSL = \"OFF\",\r\n@@ -49,25 +48,11 @@ if ( $Env:APPVEYOR ) {\n     \r\n     $CONFIGURATION = $Env:CONFIGURATION\r\n \r\n-\t# See https://www.appveyor.com/docs/windows-images-software/#visual-studio-2022\r\n-\t# According to AppVeyor environment definition:\r\n-\t#\r\n-\t# 2013 - 2017: C:\\OpenSSL-Win*: v1.0.2p, C:\\OpenSSL-v111-Win*: v1.1.1 (v1.1.1d for 2015+)\r\n-\t# 2019 - 2022: C:\\OpenSSL-Win*: v1.1.1w  and C:\\OpenSSL-v3* with version 3+\r\n-\t# SO:\r\n-\t# For 2013 - 2017: Delete C:\\OpenSSL-Win* and replace it with contents of C:\\OpenSSL-v111-Win*\r\n-\t# For 2019 - 2022: Do nothing.\r\n-\t# Note: No guarantee that C:\\OpenSSL-Win* directories will always contain version v1.1.1+ in\r\n-\t# any future versions for AppVeyor Windows environment, but then probably the SRT project\r\n-\t# would have to be adjusted to this version anyway.\r\n-\r\n-\tif ($VS_VERSION -lt 2019) {\r\n-\t\t#appveyor has many openssl installations - place the latest one in the default location unless VS2013\r\n-\t\tRemove-Item -Path \"C:\\OpenSSL-Win32\" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null\r\n-\t\tRemove-Item -Path \"C:\\OpenSSL-Win64\" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null\r\n-\t\tCopy-Item -Path \"C:\\OpenSSL-v111-Win32\" \"C:\\OpenSSL-Win32\" -Recurse | Out-Null\r\n-\t\tCopy-Item -Path \"C:\\OpenSSL-v111-Win64\" \"C:\\OpenSSL-Win64\" -Recurse | Out-Null\r\n-\t}\r\n+    #appveyor has many openssl installations - place the latest one in the default location unless VS2013\r\n+    Remove-Item -Path \"C:\\OpenSSL-Win32\" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null\r\n+    Remove-Item -Path \"C:\\OpenSSL-Win64\" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null\r\n+    Copy-Item -Path \"C:\\OpenSSL-v111-Win32\" \"C:\\OpenSSL-Win32\" -Recurse | Out-Null\r\n+    Copy-Item -Path \"C:\\OpenSSL-v111-Win64\" \"C:\\OpenSSL-Win64\" -Recurse | Out-Null\r\n }\r\n \r\n # persist VS_VERSION so it can be used in an artifact name later\r\n@@ -150,7 +135,6 @@ $cmakeFlags = \"-DCMAKE_BUILD_TYPE=$CONFIGURATION \" +\n                 \"-DENABLE_APPS=$BUILD_APPS \" + \r\n                 \"-DENABLE_ENCRYPTION=$ENABLE_ENCRYPTION \" +\r\n                 \"-DENABLE_BONDING=$BONDING \" +\r\n-\t\t\t\t\"-DENABLE_TESTING=$BUILD_TESTAPPS \" +\r\n                 \"-DENABLE_UNITTESTS=$UNIT_TESTS\"\r\n \r\n # if VCPKG is flagged to provide OpenSSL, checkout VCPKG and install package\r\n@@ -191,7 +175,7 @@ if ( $VCPKG_OPENSSL -eq 'ON' ) {\n     $cmakeFlags += \" -DCMAKE_TOOLCHAIN_FILE=$projectRoot\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake\"\r\n }\r\n else {    \r\n-    $cmakeFlags += \" -DSRT_USE_OPENSSL_STATIC_LIBS=$STATIC_LINK_SSL \"\r\n+    $cmakeFlags += \" -DOPENSSL_USE_STATIC_LIBS=$STATIC_LINK_SSL \"\r\n }\r\n \r\n # cmake uses a flag for architecture from vs2019, so add that as a suffix\r\ndiff --git a/scripts/codecov/update.sh b/scripts/codecov/update.sh\ndeleted file mode 100755\nindex 2d2b8b6..0000000\n--- a/scripts/codecov/update.sh\n+++ /dev/null\n@@ -1,46 +0,0 @@\n-#!/bin/bash\n-HERE=`dirname $0`\n-cd $HERE\n-\n-VERSION=hardcoded\n-if [[ -n $1 ]]; then\n-\tVERSION=$1\n-fi\n-\n-if [[ $VERSION == latest ]]; then\n-\tBASEURL=https://cli.codecov.io/latest/linux/codecov\n-\tSHA=\n-else\n-\tBASEURL=https://cli.codecov.io/v11.3.1/linux/codecov\n-\tSHA=\"ca1d64196d2d34771084afe76ea657d581bf628e31d993ff8e52ea09cc88a56d  codecov\"\n-\techo 'USING HARDCODED VERSION: 11.3.1. Use \"update.sh latest\" to get the latest version'\n-\techo 'NOTE: Using the latest version is unsafe as SHA is also downloaded over the network'\n-fi\n-\n-echo \"DOWNLOADING: $BASEURL\"\n-rm -f codecov || { echo \"Can't delete 'codecov'; please delete manually\" ; exit 1; }\n-\n-curl -L -o codecov $BASEURL\n-FILESHA=$(sha256sum codecov)\n-\n-if [[ -z $SHA ]]; then\n-\techo \"DOWNLOADING HASH: ${BASEURL}.SHA256SUM\"\n-\tcurl -L -o codecov.SHA256SUM ${BASEURL}.SHA256SUM\n-\tSHA=$(cat codecov.SHA256SUM)\n-\techo \"Downloaded HASH: $SHA\"\n-else\n-\techo \"Hardcoded HASH: $SHA\"\n-fi\n-\n-if [[ \"$FILESHA\" == \"$SHA\" ]]; then\n-\techo \"Checksum SHA256 matches.\"\n-else\n-\techo \"ERROR: WRONG SHA256 CHECKSUM:\"\n-\techo \"EXPECTED: $SHA\"\n-\techo \"RECEIVED: $FILESHA\"\n-\trm codecov\n-\techo \"Corrupt file deleted\"\n-\texit 1\n-fi\n-\n-chmod +x codecov\ndiff --git a/scripts/codespell/codespell.cfg b/scripts/codespell/codespell.cfg\ndeleted file mode 100644\nindex 44f2ec9..0000000\n--- a/scripts/codespell/codespell.cfg\n+++ /dev/null\n@@ -1,16 +0,0 @@\n-[codespell]\n-\n-# Enable built-in dictionaries/rules.\n-# See more details for https://github.com/codespell-project/codespell/tree/main/codespell_lib/data.\n-builtin = clear,rare,informal,code\n-\n-# Ignore words listed in this file.\n-ignore-words = ./scripts/codespell/codespell_whitelist.txt\n-ignore-regex = TEST\\(.*\\)\n-\n-# Add custom dictionary file.\n-dictionary = ./scripts/codespell/codespell_dictionary.txt,-\n-\n-# Skip checking files or directories.\n-skip = ./build/*,./.git/*\n-\ndiff --git a/scripts/codespell/codespell_dictionary.txt b/scripts/codespell/codespell_dictionary.txt\ndeleted file mode 100644\nindex e69de29..0000000\ndiff --git a/scripts/codespell/codespell_whitelist.txt b/scripts/codespell/codespell_whitelist.txt\ndeleted file mode 100644\nindex 6e845b7..0000000\n--- a/scripts/codespell/codespell_whitelist.txt\n+++ /dev/null\n@@ -1,30 +0,0 @@\n-AnyOther\n-ANS\n-CAS\n-connectIn\n-deque\n-dur\n-endcode\n-fo\n-inout\n-kinda\n-lene\n-lets\n-lite\n-LITE\n-mane\n-mut\n-MUSL\n-nd\n-numer\n-od\n-RO\n-stdio\n-stoll\n-snd\n-Snd\n-SND\n-uint\n-unsecure\n-UNSECURE\n-ws\ndiff --git a/scripts/collect-gcov.sh b/scripts/collect-gcov.sh\nnew file mode 100644\nindex 0000000..7b458e6\n--- /dev/null\n+++ b/scripts/collect-gcov.sh\n@@ -0,0 +1,7 @@\n+#!/bin/bash\n+shopt -s globstar\n+gcov_data_dir=\".\"\n+for x in ./**/*.o; do\n+  echo \"x: $x\"\n+  gcov \"$gcov_data_dir/$x\"\n+done\ndiff --git a/scripts/generate-error-types.tcl b/scripts/generate-error-types.tcl\nindex a24fd62..e4d29c6 100755\n--- a/scripts/generate-error-types.tcl\n+++ b/scripts/generate-error-types.tcl\n@@ -109,17 +109,17 @@ set errortypes {\n     NOTSUP \"Operation not supported\" {\n         NONE           \"\"\n         ISBOUND        \"Cannot do this operation on a BOUND socket\"\n-        ISCONNECTED    \"Cannot do this operation on a CONNECTED or LISTENING socket\"\n+        ISCONNECTED    \"Cannot do this operation on a CONNECTED socket\"\n         INVAL          \"Bad parameters\"\n         SIDINVAL       \"Invalid socket ID\"\n         ISUNBOUND      \"Cannot do this operation on an UNBOUND socket\"\n         NOLISTEN       \"Socket is not in listening state\"\n         ISRENDEZVOUS   \"Listen/accept is not supported in rendezvous connection setup\"\n         ISRENDUNBOUND  \"Cannot call connect on UNBOUND socket in rendezvous connection setup\"\n-        INVALMSGAPI    \"Incorrect use of Message API (sendmsg/recvmsg)\"\n-        INVALBUFFERAPI \"Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile)\"\n+        INVALMSGAPI    \"Incorrect use of Message API (sendmsg/recvmsg).\"\n+        INVALBUFFERAPI \"Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile).\"\n         BUSY           \"Another socket is already listening on the same port\"\n-        XSIZE          \"Message too large to send (exceeds send buffer size)\"\n+        XSIZE          \"Message is too large to send (it must be less than the SRT send buffer size)\"\n         EIDINVAL       \"Invalid epoll ID\"\n         EEMPTY         \"All sockets removed from epoll, waiting would deadlock\"\n         BUSYPORT       \"Another socket is bound to that port and is not reusable for requested settings\"\n@@ -169,7 +169,7 @@ const char* strerror_get_message(size_t major, size_t minor)\n     }\n \n     const char** array = strerror_array_major[major];\n-    const size_t size = strerror_array_sizes[major];\n+    size_t size = strerror_array_sizes[major];\n \n     if (minor >= size)\n     {\ndiff --git a/scripts/generate-logging-defs.tcl b/scripts/generate-logging-defs.tcl\nindex 6662267..a86ab9a 100755\n--- a/scripts/generate-logging-defs.tcl\n+++ b/scripts/generate-logging-defs.tcl\n@@ -36,7 +36,7 @@ set loggers {\n \tRSRC       rs  5  \"System resource allocation and management\"\n \tCONGEST    cc  7  \"Congestion control module\"\n \tPFILTER    pf  8  \"Packet filter module\"\n-\tAPI_CTRL   ac  11 \"API part for socket and library management\"\n+\tAPI_CTRL   ac  11 \"API part for socket and library managmenet\"\n \tQUE_CTRL   qc  13 \"Queue control activities\"\n \tEPOLL_UPD  ei  16 \"EPoll, internal update activities\"\n \n@@ -140,7 +140,7 @@ proc GenerateModelForSrtH {} {\n \t\t\t\tcontinue\n \t\t\t}\n \n-\t\t\t# End of generated section. Switch back to pass-through.\n+\t\t\t# End of generated section. Switch back to pass-thru.\n \n \t\t\t# First fill the gap\n \t\t\tappend contents \"\\n\\$entries\\n\\n\"\ndiff --git a/scripts/get-build-version.tcl b/scripts/get-build-version.tcl\ndeleted file mode 100755\nindex fafda06..0000000\n--- a/scripts/get-build-version.tcl\n+++ /dev/null\n@@ -1,47 +0,0 @@\n-#!/usr/bin/tclsh\n-\n-if {![file exists version.h]} {\n-\tputs stderr \"No version.h file found - run this in the build directory!\"\n-\texit 1\n-}\n-\n-set fd [open version.h r]\n-\n-set version \"\"\n-set line \"\"\n-while {[gets $fd line] != -1} {\n-\t# Use regexp because this is safer to avoid\n-\t# unexpected list interpretation mistakes\n-\tif {[regexp {#define SRT_VERSION_STRING} $line]} {\n-\t\t# Once matched this way, we can safely use tcl-list-like access\n-\t\tset version [lindex $line 2 0]\n-\t\tbreak\n-\t}\n-}\n-close $fd\n-\n-if {$version == \"\"} {\n-\tputs stderr \"No version extracted (no SRT_VERSION_STRING found)\"\n-\texit 1\n-}\n-\n-lassign $argv model part\n-\n-if {$model == \"\"} {\n-\tset model current\n-}\n-\n-lassign [split $version .] major minor patch\n-\n-if {$part == \"minor\"} {\n-\tset prefix \"$minor\"\n-} else {\n-\tset prefix \"$major.$minor\"\n-}\n-\n-if {$model == \"base\"} {\n-\tputs \"$prefix.0\"\n-} else {\n-\tputs \"$prefix.$patch\"\n-}\n-\ndiff --git a/scripts/googletest-download.cmake b/scripts/googletest-download.cmake\nindex f1f6d49..7469f4f 100644\n--- a/scripts/googletest-download.cmake\n+++ b/scripts/googletest-download.cmake\n@@ -1,7 +1,7 @@\n # code copied from https://crascit.com/2015/07/25/cmake-gtest/\n-cmake_minimum_required(VERSION 3.10 FATAL_ERROR)\n+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)\n \n-project(GOOGLETEST_DOWNLOAD)\n+project(googletest-download NONE)\n \n include(ExternalProject)\n \n@@ -11,7 +11,7 @@ ExternalProject_Add(\n \tBINARY_DIR \"@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build\"\n \tGIT_REPOSITORY\n \thttps://github.com/google/googletest.git\n-\tGIT_TAG release-1.12.1\n+\tGIT_TAG release-1.10.0\n \tCONFIGURE_COMMAND \"\"\n \tBUILD_COMMAND \"\"\n \tINSTALL_COMMAND \"\"\ndiff --git a/scripts/googletest.cmake b/scripts/googletest.cmake\nindex 96115dd..57e5c93 100644\n--- a/scripts/googletest.cmake\n+++ b/scripts/googletest.cmake\n@@ -24,7 +24,7 @@ macro(fetch_googletest _download_module_path _download_root)\n \t\t\t${_download_root}\n \t\t)\n \n-\t# adds the targets: gtest, gtest_main, gmock, gmock_main\n+\t# adds the targers: gtest, gtest_main, gmock, gmock_main\n \tadd_subdirectory(\n \t\t${_download_root}/googletest-src\n \t\t${_download_root}/googletest-build\ndiff --git a/scripts/haiUtil.cmake b/scripts/haiUtil.cmake\nindex 312480e..2226619 100644\n--- a/scripts/haiUtil.cmake\n+++ b/scripts/haiUtil.cmake\n@@ -288,16 +288,3 @@ function (parse_compiler_type wct _type _suffix)\n \t\tendif()\n \tendif()\n endfunction()\n-\n-macro (srt_import_parent_options)\n-\tgetVarsWith(LIBSRT_ extoptions)\n-\tforeach(ef ${extoptions})\n-\t\tset (val ${${ef}})\n-\t\tstring(LENGTH LIBSRT_ pflen)\n-\t\tstring(LENGTH ${ef} eflen)\n-\t\tmath(EXPR alen ${eflen}-${pflen})\n-\t\tstring(SUBSTRING ${ef} ${pflen} ${alen} ef)\n-\t\tmessage(STATUS \"IMPORTED OPTION: ${ef}='${val}'\")\n-\t\tset (${ef} \"${val}\")\n-\tendforeach()\n-endmacro()\ndiff --git a/scripts/iOS.cmake b/scripts/iOS.cmake\nindex ed3743d..1f2a04b 100644\n--- a/scripts/iOS.cmake\n+++ b/scripts/iOS.cmake\n@@ -8,10 +8,8 @@\n #   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders\n #   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.\n #   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.\n-#   TV - used to build for tvOS devices\n-#   TV_SIMULATOR - used to build for tvOS Simulator platforms, which have an x86 arch.\n #\n-# IOS_ARCH = arm64 (default for OS and TV), armv7, armv7s, i386 (default for SIMULATOR), x86_64 (default for SIMULATOR64 and TV_SIMULATOR)\n+# IOS_ARCH = arm64 (default for OS), armv7, armv7s, i386 (default for SIMULATOR), x86_64 (default for SIMULATOR64)\n #\n # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder\n #   By default this location is automatcially chosen based on the IOS_PLATFORM value above.\n@@ -21,6 +19,8 @@\n #   By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.\n #   In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.\n #   If set manually, this will force the use of a specific SDK version\n+#\n+# IOS_DISABLE_BITCODE - set to 1 if you want to disable bitcode generation\n \n # Standard settings\n set (CMAKE_SYSTEM_NAME Darwin)\n@@ -29,16 +29,14 @@ set (UNIX True)\n set (APPLE True)\n set (IOS True)\n \n-# With Xcode 16, Apple has deprecated bitcode for all platforms\n-set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE \"NO\")\n-\n # Required as of cmake 2.8.10\n set (CMAKE_OSX_DEPLOYMENT_TARGET \"\" CACHE STRING \"Force unset of the deployment target for iOS\" FORCE)\n \n # Determine the cmake host system version so we know where to find the iOS SDKs\n find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)\n if (CMAKE_UNAME)\n-\texecute_process(COMMAND uname -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)\n+\texecute_process(COMMAND uname -r\n+\t\t\tOUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)\n \tstring (REGEX REPLACE \"^([0-9]+)\\\\.([0-9]+).*$\" \"\\\\1\" DARWIN_MAJOR_VERSION \"${CMAKE_HOST_SYSTEM_VERSION}\")\n endif (CMAKE_UNAME)\n \n@@ -51,6 +49,10 @@ set (CMAKE_C_OSX_CURRENT_VERSION_FLAG \"-current_version \")\n set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG \"${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}\")\n set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG \"${CMAKE_C_OSX_CURRENT_VERSION_FLAG}\")\n \n+if (NOT DEFINED IOS_DISABLE_BITCODE)\n+\tset (EMBED_OPTIONS \"-fembed-bitcode\")\n+endif(NOT DEFINED IOS_DISABLE_BITCODE)\n+\n if (CMAKE_BUILD_TYPE STREQUAL \"Debug\" OR ENABLE_DEBUG)\n \tset(IOS_DEBUG_OPTIONS \"-glldb -gmodules\")\n else()\n@@ -100,12 +102,6 @@ if (${IOS_PLATFORM} STREQUAL OS)\n \n \t# This causes the installers to properly locate the output libraries\n \tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphoneos\")\n-elseif (${IOS_PLATFORM} STREQUAL TV)\n-\tset (IOS_PLATFORM_LOCATION \"AppleTVOS.platform\")\n-\tunset(CMAKE_IOS_DEVELOPER_ROOT CACHE)\n-\tunset(CMAKE_IOS_SDK_ROOT CACHE)\n-\t# This causes the installers to properly locate the output libraries\n-\tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-appletvos\")\n elseif (${IOS_PLATFORM} STREQUAL SIMULATOR)\n     set (SIMULATOR true)\n \tset (IOS_PLATFORM_LOCATION \"iPhoneSimulator.platform\")\n@@ -118,35 +114,15 @@ elseif (${IOS_PLATFORM} STREQUAL SIMULATOR64)\n \n \t# This causes the installers to properly locate the output libraries\n \tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphonesimulator\")\n-elseif (${IOS_PLATFORM} STREQUAL ARM_SIMULATOR)\n-    set (SIMULATOR true)\n-\tset (IOS_PLATFORM_LOCATION \"iPhoneSimulator.platform\")\n-\n-\t# This causes the installers to properly locate the output libraries\n-\tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphonesimulator\")\n-elseif (${IOS_PLATFORM} STREQUAL TV_SIMULATOR)\n-    set (SIMULATOR true)\n-\tset (IOS_PLATFORM_LOCATION \"AppleTVSimulator.platform\")\n-\tunset(CMAKE_IOS_DEVELOPER_ROOT CACHE)\n-\tunset(CMAKE_IOS_SDK_ROOT CACHE)\n-\n-\t# This causes the installers to properly locate the output libraries\n-\tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-appletvsimulator\")\n-elseif (${IOS_PLATFORM} STREQUAL TV_ARM_SIMULATOR)\n-    set (SIMULATOR true)\n-\tset (IOS_PLATFORM_LOCATION \"AppleTVSimulator.platform\")\n-\tunset(CMAKE_IOS_DEVELOPER_ROOT CACHE)\n-\tunset(CMAKE_IOS_SDK_ROOT CACHE)\n-\n-\t# This causes the installers to properly locate the output libraries\n-\tset (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-appletvsimulator\")\n else (${IOS_PLATFORM} STREQUAL OS)\n-\tmessage (FATAL_ERROR \"Unsupported IOS_PLATFORM value selected. Please choose OS, TV or SIMULATOR\")\n+\tmessage (FATAL_ERROR \"Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR\")\n endif (${IOS_PLATFORM} STREQUAL OS)\n \n # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT\n if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)\n-\texecute_process(COMMAND /usr/bin/xcode-select -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)\n+\texecute_process(COMMAND /usr/bin/xcode-select -print-path\n+\t\t\tOUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR)\n+\tstring(STRIP \"${CMAKE_XCODE_DEVELOPER_DIR}\" CMAKE_XCODE_DEVELOPER_DIR) # FIXED: remove new line character, otherwise it complain no iOS SDK's found in default search path\n \tset (CMAKE_IOS_DEVELOPER_ROOT \"${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer\")\n endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)\n set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH \"Location of iOS Platform\")\n@@ -176,10 +152,6 @@ if (NOT DEFINED IOS_ARCH)\n \t\tset (IOS_ARCH i386)\n \telseif (${IOS_PLATFORM} STREQUAL SIMULATOR64)\n \t\tset (IOS_ARCH x86_64)\n-\telseif (${IOS_PLATFORM} STREQUAL ARM_SIMULATOR)\n-\t\tset (IOS_ARCH arm64)\n-\telseif (${IOS_PLATFORM} STREQUAL TV_ARM_SIMULATOR)\n-\t\tset (IOS_ARCH arm64)\n \tendif (${IOS_PLATFORM} STREQUAL OS)\n endif(NOT DEFINED IOS_ARCH)\n set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING \"Build architecture for iOS\")\n@@ -197,8 +169,8 @@ set (CMAKE_SYSTEM_FRAMEWORK_PATH\n \t${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks\n )\n \n-# only search the iOS sdks, not the remainder of the host filesystem\n-set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)\n+# only search the iOS sdks, not the remainder of the host filesystem (except for programs, so that we can still find Python if needed)\n+set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)\n set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\n set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n \ndiff --git a/scripts/srt-dev.lua b/scripts/srt-dev.lua\nindex efb875d..a90ac48 100644\n--- a/scripts/srt-dev.lua\n+++ b/scripts/srt-dev.lua\n@@ -65,7 +65,7 @@ local msg_type_select = {\n \t[0x7FFF] = \"[Message Extension Type]\"\n }\n fields.msg_type = ProtoField.uint16(\"srt_dev.msg_type\", \"Message Type\", base.HEX, msg_type_select, 0x7FFF)\n-fields.msg_ext_type = ProtoField.uint16(\"srt_dev.msg_ext_type\", \"Message Extended Type\", base.DEC)\n+fields.msg_ext_type = ProtoField.uint16(\"srt_dev.msg_ext_type\", \"Message Extented Type\", base.DEC)\n \n local flag_state_select = {\n \t[0] = \"Unset\",\n@@ -281,7 +281,7 @@ function srt_dev.dissector (tvb, pinfo, tree)\n \t\t\t\t\t\t\tsubtree:add(fields.ext_fld, tvb(offset, 2)):append_text(\" [HSv5 MAGIC]\")\n \t\t\t\t\t\telse\n \t\t\t\t\t\t\t-- Extension Field is HS_EXT_prefix\n-\t\t\t\t\t\t\t-- The define is in file handshake.h\n+\t\t\t\t\t\t\t-- The define is in fiel handshake.h\n \t\t\t\t\t\t\tlocal ext_fld_tree = subtree:add(fields.ext_fld_tree, tvb(offset, 2))\n \t\t\t\t\t\t\tlocal str_table = { \" [\" }\n \t\t\t\t\t\t\text_fld_tree:add(fields.hsreq, tvb(offset, 2))\ndiff --git a/scripts/srt-proxy.py b/scripts/srt-proxy.py\ndeleted file mode 100755\nindex 27bbed0..0000000\n--- a/scripts/srt-proxy.py\n+++ /dev/null\n@@ -1,168 +0,0 @@\n-#!/usr/bin/python3\n-\n-# This script is a testing tool that inserts a packet interceptor for\n-# a bond between two local ports and modify a packet that is sent over\n-# the UDP link used by the SRT connection.\n-\n-# Provided by:\n-# https://github.com/FelixSodermanNeti\n-\n-import socket, select, argparse\n-\n-class UDPProxy:\n-    def __init__(self, caller_host, caller_port, listener_host, listener_port, break_at_pkt_NAK, break_at_pkt_ACK):\n-\n-        # Listening socket configuration\n-        self.caller_host = caller_host\n-        self.caller_port = caller_port\n-        self.caller_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n-        self.caller_socket.bind((self.caller_host, self.caller_port))\n-\n-        # Forwarding destination configuration\n-        self.listener_host = listener_host\n-        self.listener_port = listener_port\n-\n-        # Client address tracking\n-        self.client_address = None\n-\n-        # Proxy state\n-        self.running = False\n-\n-        # Break SRT\n-        self.sentPacketCounter = 0\n-        self.recivedAckCounter = 0\n-        self.PACKETBREAK_NAK = break_at_pkt_NAK\n-        self.PACKETBREAK_ACK = break_at_pkt_ACK\n-\n-    def start(self):\n-        try:\n-            self.running = True\n-            print(\n-                f\"UDP Proxy started. Listening on {self.caller_host}:{self.caller_port}. \"\n-                f\"Forwarding to {self.listener_host}:{self.listener_port}\"\n-            )\n-\n-            # Create forward socket\n-            listener_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n-\n-            # Use select for non-blocking I/O\n-            while self.running:\n-                readable, _, _ = select.select([self.caller_socket, listener_socket], [], [], 1)\n-\n-                for sock in readable:\n-                    if sock == self.caller_socket:\n-                        # Receive from client\n-                        data, addr = sock.recvfrom(65535)\n-                        self.client_address = addr\n-\n-                        #Modify the NAK\n-                        processedData = data\n-                        # NAK\n-                        if(data[1] == 0x03 and len(data) == 24 and self.PACKETBREAK_NAK != 0): # IS A NAK, This should check for a 1 in the first byte as well.\n-                            print(\"Modifying NAK.\")\n-                            newBytes = b\"\\xff\\xff\\xff\\xff\"\n-                            processedData =  data[:20] + newBytes + data[20 + len(newBytes):]\n-                            \"\"\"\n-                            print(\"NAK BEFORE:\")\n-                            print(string_bytearray_in_rows(data=data))\n-                            print(\"\\n\\nModifying NAK.\\n\\n\")\n-                            print(\"ŃAK AFTER:\")\n-                            print(string_bytearray_in_rows(data=processedData))\n-                            \"\"\"\n-\n-                        # ACK\n-                        if(data[1] == 0x02 and len(data) == 44): # IS A ACK\n-                            self.recivedAckCounter += 1\n-                            if (self.PACKETBREAK_ACK != 0 and self.recivedAckCounter == self.PACKETBREAK_ACK):\n-                                print(\"Modifying ACK.\")\n-                                newBytes = b\"\\x7f\\xff\\xff\\xff\"\n-                                offset = 16\n-                                processedData =  data[:offset] + newBytes + data[offset + len(newBytes):]\n-                                \"\"\"\n-                                print(\"ACK BEFORE:\")\n-                                print(string_bytearray_in_rows(data=data))\n-                                print(\"\\n\\nModifying ACK.\\n\\n\")\n-                                print(\"ACK AFTER:\")\n-                                print(string_bytearray_in_rows(data=processedData))\n-                                \"\"\"\n-                        listener_socket.sendto(\n-                            processedData,\n-                            (self.listener_host, self.listener_port)\n-                        )\n-\n-                    elif sock == listener_socket:\n-                        # Receive from server\n-                        data, addr = sock.recvfrom(65535)\n-                        \n-                        # Drop a sequence of data packets (as to at least 3 to trigger an NAK with a range)\n-                        if len(data) == 1332: # Packet with data\n-                            self.sentPacketCounter += 1\n-                            if (self.PACKETBREAK_NAK != 0 and self.sentPacketCounter in range(self.PACKETBREAK_NAK, self.PACKETBREAK_NAK+5)):\n-                                print(\"Discarding packet.\")\n-                                continue\n-\n-                        if not self.client_address:\n-                            print(\"No client to send data to!\")\n-                            continue\n-\n-                        self.caller_socket.sendto(\n-                            data,\n-                            self.client_address\n-                        )\n-\n-        except Exception as e:\n-            print(f\"Proxy error: {e}\")\n-\n-        finally:\n-            self.stop()\n-\n-    def stop(self):\n-        self.running = False\n-        self.caller_socket.close()\n-        print(\"UDP Proxy stopped.\")\n-\n-\n-def string_bytearray_in_rows(data, bytes_per_row=4):\n-    tmpString = \"\\n\"\n-    for i in range(0, len(data), bytes_per_row):\n-        row = data[i:i+bytes_per_row]\n-        tmpString += f\"{i}: \"\n-        tmpString += (\" \".join(f\"{byte:02x}\" for byte in row))\n-        tmpString += \"\\n\"\n-    tmpString += \"\\n\"\n-    return tmpString\n-\n-def main():\n-    # Parse command-line arguments\n-    parser = argparse.ArgumentParser(description='UDP Proxy')\n-    parser.add_argument('--caller-host', default='127.0.0.1',\n-                        help='Host to listen on (srt caller) (default: 127.0.0.1)')\n-    parser.add_argument('--caller-port', type=int, required=True,\n-                        help='Port to listen on (srt caller)')\n-    parser.add_argument('--listener-host', default='127.0.0.1',\n-                        help='Destination host to forward packets (srt listener)')\n-    parser.add_argument('--listener-port', type=int, required=True,\n-                        help='Destination port to forward packets (srt listener)')\n-    parser.add_argument('--break-at-pkt-NAK', type=int, default=0,\n-                        help='At what datapacket should the NAK -1 be sent (0=never)')\n-    parser.add_argument('--break-at-pkt-ACK', type=int, default=0,\n-                        help='At what datapacket should the ACK -1 be sent (0=never)')\n-    args = parser.parse_args()\n-\n-    # Create and start proxy\n-    proxy = UDPProxy(\n-        args.caller_host,\n-        args.caller_port,\n-        args.listener_host,\n-        args.listener_port,\n-        args.break_at_pkt_NAK,\n-        args.break_at_pkt_ACK\n-    )\n-\n-    try:\n-        proxy.start()\n-    except KeyboardInterrupt:\n-        proxy.stop()\n-\n-if __name__ == '__main__':\n-    main()\ndiff --git a/scripts/visionOS.cmake b/scripts/visionOS.cmake\nindex cfb6006..0f0f60b 100644\n--- a/scripts/visionOS.cmake\n+++ b/scripts/visionOS.cmake\n@@ -9,7 +9,7 @@\n #   OS - the default, used to build for Vision Pro physical device, which have an arm arch.\n #   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.\n #\n-# VISIONOS_ARCH = arm64 (default for OS), x86_64 (additional support for SIMULATOR64)\n+# VISIONOS_ARCH = arm64 (default for OS), x86_64 (addiitonal support for SIMULATOR64)\n #\n # CMAKE_VISIONOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder\n #   By default this location is automatcially chosen based on the VISIONOS_PLATFORM value above.\ndiff --git a/scripts/win-installer/ATTIC/old-install-nsis.ps1 b/scripts/win-installer/ATTIC/old-install-nsis.ps1\ndeleted file mode 100644\nindex 0bf58af..0000000\n--- a/scripts/win-installer/ATTIC/old-install-nsis.ps1\n+++ /dev/null\n@@ -1,128 +0,0 @@\n-﻿#-----------------------------------------------------------------------------\n-#\n-#  SRT - Secure, Reliable, Transport\n-#  Copyright (c) 2021, Thierry Lelegard\n-# \n-#  This Source Code Form is subject to the terms of the Mozilla Public\n-#  License, v. 2.0. If a copy of the MPL was not distributed with this\n-#  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n-#\n-#-----------------------------------------------------------------------------\n-\n-<#\n- .DESCRIPTION\n-\n-  Download, expand and install NSIS, the NullSoft Installer Scripting.\n-\n-  IMPORTANT NOTE: This is the old version, left for historical reasons. Usage\n-  of this script is discouraged because this scripts doesn't check the MD5\n-  checksum on the downloaded file and therefore is considered unsafe.\n-\n- .PARAMETER ForceDownload\n-\n-  Force a download even if NSIS is already downloaded.\n-\n- .PARAMETER NoInstall\n-\n-  Do not install the NSIS package. By default, NSIS is installed.\n-\n- .PARAMETER NoPause\n-\n-  Do not wait for the user to press <enter> at end of execution. By default,\n-  execute a \"pause\" instruction at the end of execution, which is useful\n-  when the script was run from Windows Explorer.\n-#>\n-[CmdletBinding(SupportsShouldProcess=$true)]\n-param(\n-    [switch]$ForceDownload = $false,\n-    [switch]$NoInstall = $false,\n-    [switch]$NoPause = $false\n-)\n-\n-Write-Output \"NSIS download and installation procedure\"\n-$NSISPage = \"https://nsis.sourceforge.io/Download\"\n-$FallbackURL = \"http://prdownloads.sourceforge.net/nsis/nsis-3.05-setup.exe?download\"\n-\n-# A function to exit this script.\n-function Exit-Script([string]$Message = \"\")\n-{\n-    $Code = 0\n-    if ($Message -ne \"\") {\n-        Write-Output \"ERROR: $Message\"\n-        $Code = 1\n-    }\n-    if (-not $NoPause) {\n-        pause\n-    }\n-    exit $Code\n-}\n-\n-# Local file names.\n-$RootDir = $PSScriptRoot\n-$TmpDir = \"$RootDir\\tmp\"\n-\n-# Create the directory for external products when necessary.\n-[void] (New-Item -Path $TmpDir -ItemType Directory -Force)\n-\n-# Without this, Invoke-WebRequest is awfully slow.\n-$ProgressPreference = 'SilentlyContinue'\n-\n-# Get the HTML page for NSIS downloads.\n-$status = 0\n-$message = \"\"\n-$Ref = $null\n-try {\n-    $response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $NSISPage\n-    $status = [int] [Math]::Floor($response.StatusCode / 100)\n-}\n-catch {\n-    $message = $_.Exception.Message\n-}\n-\n-if ($status -ne 1 -and $status -ne 2) {\n-    # Error fetch NSIS download page.\n-    if ($message -eq \"\" -and (Test-Path variable:response)) {\n-        Write-Output \"Status code $($response.StatusCode), $($response.StatusDescription)\"\n-    }\n-    else {\n-        Write-Output \"#### Error accessing ${NSISPage}: $message\"\n-    }\n-}\n-else {\n-    # Parse HTML page to locate the latest installer.\n-    $Ref = $response.Links.href | Where-Object { $_ -like \"*/nsis-*-setup.exe?download\" } | Select-Object -First 1\n-}\n-\n-if (-not $Ref) {\n-    # Could not find a reference to NSIS installer.\n-    $Url = [System.Uri]$FallbackURL\n-}\n-else {\n-    # Build the absolute URL's from base URL (the download page) and href links.\n-    $Url = New-Object -TypeName 'System.Uri' -ArgumentList ([System.Uri]$NSISPage, $Ref)\n-}\n-\n-Write-Output \"DOWNLOADING: $Url\"\n-\n-$InstallerName = (Split-Path -Leaf $Url.LocalPath)\n-$InstallerPath = \"$TmpDir\\$InstallerName\"\n-\n-# Download installer\n-if (-not $ForceDownload -and (Test-Path $InstallerPath)) {\n-    Write-Output \"$InstallerName already downloaded, use -ForceDownload to download again\"\n-}\n-else {\n-    Write-Output \"Downloading $Url ...\"\n-    Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $InstallerPath\n-    if (-not (Test-Path $InstallerPath)) {\n-        Exit-Script \"$Url download failed\"\n-    }\n-}\n-\n-# Install NSIS\n-if (-not $NoInstall) {\n-    Write-Output \"Installing $InstallerName\"\n-    Start-Process -FilePath $InstallerPath -ArgumentList @(\"/S\") -Wait\n-}\n-\n-Exit-Script\ndiff --git a/scripts/win-installer/README.md b/scripts/win-installer/README.md\nindex 135071b..ff54df2 100644\n--- a/scripts/win-installer/README.md\n+++ b/scripts/win-installer/README.md\n@@ -7,21 +7,12 @@ libsrt on Windows systems for Visual Studio applications using SRT.\n \n ### Prerequisites\n \n-These initial steps need to be executed once only.\n+These first two steps need to be executed once only.\n \n-- Prerequisite 1: Install Visual Studio. The free Community Edition is recommended\n-  for open-source software. See https://visualstudio.microsoft.com/. Be sure to\n-  install the compilation tools for the all target architectures, including 64-bit Arm.\n-  In the Visual Studio Installer program, select \"Modify\" -> \"Individual Components\".\n-  In section \"Compilers, build tools, and runtimes\", select \"MSVC v143 - VS2022 C++\n-  ARM64/ARM64EC build tools (latest)\" (the exact version may vary).\n-\n-- Prerequisite 2: Install OpenSSL for Windows, 64-bit Intel, 32-bit Intel, 64-bit Arm.\n+- Prerequisite 1: Install OpenSSL for Windows, both 64 and 32 bits.\n   This can be done automatically by running the PowerShell script `install-openssl.ps1`.\n-  If you are interested in more information about OpenSSL for Windows, scroll to the\n-  appendix at the end of this page.\n \n-- Prerequisite 3: Install NSIS, the NullSoft Installation Scripting system.\n+- Prerequisite 2: Install NSIS, the NullSoft Installation Scripting system.\n   This can be done automatically by running the PowerShell script `install-nsis.ps1`.\n \n ### Building the libsrt installer\n@@ -35,7 +26,7 @@ Optional parameters:\n - `-Version name` :\n   Use the specified string as version number for libsrt. By default, if the\n   current commit has a tag, use that tag (initial \"v\" removed, for instance\n-  `1.4.3`). Otherwise, the default version is a detailed version number (most\n+  `1.4.3`). Otherwise, the defaut version is a detailed version number (most\n   recent version, number of commits since then, short commit SHA, for instance\n   `1.4.3-32-g22cc924`). Use that option if necessary to specify some other\n   non-standard form of version string.\n@@ -130,80 +121,3 @@ This directory contains the following files:\n | libsrt.nsi              | NSIS installation script (used to build the installer).\n | libsrt.props            | Visual Studio property files to use libsrt (embedded in the installer).\n | README.md               | This text file.\n-\n-## Appendix: Using OpenSSL on Windows\n-\n-The SRT protocol uses encryption. Internally, `libsrt` can use multiple cryptographic\n-libraries but OpenSSL is the default choice on all platforms, including Windows.\n-\n-OpenSSL is not part of the base installation of a Windows platform and should be\n-separately installed. OpenSSL is neither \"Windows-friendly\" and the OpenSSL team\n-does not provide Windows binaries.\n-\n-The production of OpenSSL binaries for Windows is delegated to Shining Light\n-Productions (http://slproweb.com/). Binaries for all architectures are available\n-here: http://slproweb.com/products/Win32OpenSSL.html\n-\n-### How to grab OpenSSL installers for Windows\n-\n-This is automatically done by the PowerShell script `install-openssl.ps1` in\n-this directory. Let's see what's behind the scene.\n-\n-First, the script determines which installers should be downloaded and where\n-to get them from.\n-\n-Initially, the HTML for the [slproweb](http://slproweb.com/products/Win32OpenSSL.html)\n-page was built on server-side. Our script grabbed the URL content, parsed the HTML\n-and extracted the URL of the binaries for the latest OpenSSL packages from the\n-\"href\" of the links.\n-\n-At some point in 2024, the site changed policy. The Web page was no longer\n-built on server-side, but on client-side. The downloaded HTML contains some\n-JavaScript which dynamically builds the URL of the binaries for the latest\n-OpenSSL binaries. The previous method now finds no valid package URL from\n-the downloaded page (a full browser is needed to execute the JavaScript).\n-The JavaScript downloads a JSON file which contains all references to\n-the OpenSSL binaries.\n-\n-Therefore, the script `install-openssl.ps1` now uses the same method:\n-download that JSON file and parse it.\n-\n-### Multi-architecture builds\n-\n-The `libsrt` installer contains static libraries for all three architectures\n-which are supported by Windows: x86, x64, Arm64. The corresponding static\n-libraries for OpenSSL are also needed and included in the installer.\n-\n-Because Visual Studio can build libraries and executables for all three\n-architectures, on any build system, we need to install the OpenSSL headers\n-and libraries for all three architectures, on the build system.\n-\n-This is what the script `install-openssl.ps1` does. However, the way to\n-do this has changed over time.\n-\n-As a starting point, there are three installers, one per architecture.\n-All installers are x86 executables which can be run on any Windows system\n-(Arm64 Windows emulates x86 and x64 when necessary). Additionally, the\n-three sets of files are installed side by side, without overlap.\n-\n-- x86: `C:\\Program Files (x86)\\OpenSSL-Win32`\n-- x64: `C:\\Program Files\\OpenSSL-Win64`\n-- Arm64: `C:\\Program Files\\OpenSSL-Win64-ARM`\n-\n-So, the script `install-openssl.ps1` installed them all and `libsrt` could\n-be built for all architecture.\n-\n-However, it works only on Arm64 systems. On x86 and x64 system, the OpenSSL\n-installer for Arm64 fails. The installer executable can run but there is an\n-explicit check in the installation process to abort when running on Intel\n-systems.\n-\n-Since most Windows build servers are Intel systems, this approach was no\n-longer appropriate.\n-\n-At some point, the producers of the OpenSSL binaries acknowledged the problem\n-and they created an additional form of installer: the \"universal\" one. This\n-package can be installed on any system and the binaries and headers are installed\n-for all architectures, in one single location.\n-\n-- Universal: `C:\\Program Files (x86)\\OpenSSL-WinUniversal`\ndiff --git a/scripts/win-installer/build-win-installer.ps1 b/scripts/win-installer/build-win-installer.ps1\nold mode 100755\nnew mode 100644\nindex 4778426..d08ee18\n--- a/scripts/win-installer/build-win-installer.ps1\n+++ b/scripts/win-installer/build-win-installer.ps1\n@@ -1,5 +1,4 @@\n-﻿#!/usr/bin/env PowerShell\n-#-----------------------------------------------------------------------------\n+﻿#-----------------------------------------------------------------------------\n #\n #  SRT - Secure, Reliable, Transport\n #  Copyright (c) 2021, Thierry Lelegard\n@@ -19,14 +18,9 @@\n \n   Use the specified string as version number from libsrt. By default, if\n   the current commit has a tag, use that tag (initial 'v' removed). Otherwise,\n-  the default version is a detailed version number (most recent version, number\n+  the defaut version is a detailed version number (most recent version, number\n   of commits since then, short commit SHA).\n \n- .PARAMETER NoBuild\n-\n-  Do not rebuild the SRT libraries. Assume that they are already built.\n-  Only build the installer.\n-\n  .PARAMETER NoPause\n \n   Do not wait for the user to press <enter> at end of execution. By default,\n@@ -37,9 +31,7 @@\n [CmdletBinding()]\n param(\n     [string]$Version = \"\",\n-    [switch]$NoBuild = $false,\n-    [switch]$NoPause = $false,\n-\t[string]$OnlyPlatform = \"\"\n+    [switch]$NoPause = $false\n )\n Write-Output \"Building the SRT static libraries installer for Windows\"\n \n@@ -97,36 +89,50 @@ Write-Output \"Windows version info: $VersionInfo\"\n #-----------------------------------------------------------------------------\n \n # Locate OpenSSL root from local installation.\n-# We now requires the \"universal\" OpenSSL installer (see README.md).\n-# The universal OpenSSL installer is installed in $SSL.\n-# $ARCH translates between VC \"platform\" names to subdirectory names inside $SSL.\n-# $LIBDIR translates between VC \"configuration\" names to library subdirectory names.\n-\n-$SSL = \"C:\\Program Files (x86)\\OpenSSL-WinUniversal\"\n-$ARCH = @{x64 = \"x64\"; Win32 = \"x86\"; ARM64 = \"arm64\"}\n-$LIBDIR = @{Release = \"MD\"; Debug = \"MDd\"}\n-$LIBFILE = @{crypto = \"libcrypto_static.lib\"; ssl = \"libssl_static.lib\"}\n-\n-function ssl-include($pf) { return \"$SSL\\include\\$($ARCH.$pf)\" }\n-function ssl-libdir($pf, $conf) { return \"$SSL\\lib\\VC\\$($ARCH.$pf)\\$($LIBDIR.$conf)\" }\n-function ssl-lib($pf, $conf, $lib) { return \"$(ssl-libdir $pf $conf)\\$($LIBFILE.$lib)\" }\n+# After version 3.something, OpenSSL has changed its installation layout.\n+# We have to look for OpenSSL libraries in various locations.\n+$SSL = @{\n+    \"x64\" = @{\n+        \"alt\" = \"Win64\";\n+        \"bits\" = 64;\n+        \"root\" = \"C:\\Program Files\\OpenSSL-Win64\"\n+    };\n+    \"Win32\" = @{\n+        \"alt\" = \"x86\";\n+        \"bits\" = 32;\n+        \"root\" = \"C:\\Program Files (x86)\\OpenSSL-Win32\"\n+    }\n+}\n \n # Verify OpenSSL directories and static libraries.\n Write-Output \"Searching OpenSSL libraries ...\"\n $Missing = 0\n-foreach ($Platform in $SSL.Keys) {\n-\tif ($OnlyPlatform -ne \"\" -and $Platform -ne $OnlyPlatform) {\n-\t\tcontinue\n-\t}\n-    if (-not (Test-Path -PathType Container $(ssl-include $Platform))) {\n-        Write-Output \"**** Missing $(ssl-include $Platform)\"\n+foreach ($arch in @(\"x64\", \"Win32\")) {\n+    $root = $SSL[$arch][\"root\"]\n+    $bits = $SSL[$arch][\"bits\"]\n+    $alt = $SSL[$arch][\"alt\"]\n+    if (-not (Test-Path $root)) {\n+        Write-Output \"**** Missing $root\"\n         $Missing = $Missing + 1\n     }\n-    foreach ($lib in $LIBFILE.Keys) {\n-        foreach ($conf in $LIBDIR.Keys) {\n-            if (-not (Test-Path $(ssl-lib $Platform $conf $lib))) {\n-                Write-Output \"**** Missing $(ssl-lib $Platform $conf $lib)\"\n-                $Missing = $Missing + 1\n+    else {\n+        foreach ($lib in @(\"ssl\", \"crypto\")) {\n+            foreach ($conf in @(\"MD\", \"MDd\")) {\n+                $name = \"lib${lib}${conf}\"\n+                $SSL[$arch][$name] = \"\"\n+                foreach ($try in @(\"$root\\lib\\VC\\static\\lib${lib}${bits}${conf}.lib\",\n+                                   \"$root\\lib\\VC\\${arch}\\${conf}\\lib${lib}_static.lib\",\n+                                   \"$root\\lib\\VC\\${alt}\\${conf}\\lib${lib}_static.lib\")) {\n+                    if (Test-Path $try) {\n+                        $SSL[$arch][$name] = $try\n+                        New-Variable \"lib${lib}${bits}${conf}\" \"$try\"\n+                        break\n+                    }\n+                }\n+                if (-not $SSL[$arch][$name]) {\n+                    Write-Output \"**** OpenSSL static library for $name not found\"\n+                    $Missing = $Missing + 1\n+                }\n             }\n         }\n     }\n@@ -174,70 +180,45 @@ Write-Output \"NSIS: $NSIS\"\n \n \n #-----------------------------------------------------------------------------\n-# Configure and build SRT library using CMake on all architectures.\n+# Configure and build SRT library using CMake on two architectures.\n #-----------------------------------------------------------------------------\n \n-if (-not $NoBuild) {\n-\tWrite-Output \"BUILD ENABLED - configuring build\"\n-\tif ($OnlyPlatform -ne \"\") {\n-\t\tWrite-Output \"LIMIT TO PLATFORM: $OnlyPlatform\"\n-\t}\n-    foreach ($Platform in $ARCH.Keys) {\n-\t\tif ($OnlyPlatform -ne \"\" -and $Platform -ne $OnlyPlatform) {\n-\t\t\tWrite-Output \"Skipping platform $Platform.\"\n-\t\t\tcontinue\n-\t\t}\n-\t\tWrite-Output \"Preparing platform $Platform.\"\n-        # Build directory. Cleanup to force a fresh cmake config.\n-        $BuildDir = \"$TmpDir\\build.$Platform\"\n-        Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $BuildDir\n-        [void](New-Item -Path $BuildDir -ItemType Directory -Force)\n-\n-        # Run CMake.\n-        Write-Output \"Configuring build for platform $Platform ...\"\n-\t\t$params = @(\"-S\", \"$RepoDir\",\n-\t\t\t\t\t\"-B\", \"$BuildDir\",\n-\t\t\t\t\t\"-A\", \"$Platform\",\n-\t\t\t\t\t\"-DENABLE_STDCXX_SYNC=ON\",\n-\t\t\t\t\t\"-DOPENSSL_INCLUDE_DIR=$(ssl-include $Platform)\",\n-\t\t\t\t\t\"-DOPENSSL_ROOT_DIR=$(ssl-libdir $Platform Release)\"\n-\t\t\t\t\t)\n-\t\tWrite-Output \"Running: cmake $params\"\n-        & $CMake $params\n-        # Patch version string in version.h\n-        Get-Content \"$BuildDir\\version.h\" |\n-            ForEach-Object {\n-                $_ -replace \"#define *SRT_VERSION_STRING .*\",\"#define SRT_VERSION_STRING `\"$Version`\"\"\n-            } |\n-            Out-File \"$BuildDir\\version.new\" -Encoding ascii\n-        Move-Item \"$BuildDir\\version.new\" \"$BuildDir\\version.h\" -Force\n-\n-        # Compile SRT.\n-        Write-Output \"Building for platform $Platform ...\"\n-        foreach ($Conf in $LIBDIR.Keys) {\n-           # The solution file format depends on the CMake version.\n-           # Try new XML solution file format first.\n-           $SolFile = \"$BuildDir\\SRT.slnx\"\n-           if (-not (Test-Path $SolFile)) {\n-               # Try legacy solution file format.\n-               $SolFile = \"$BuildDir\\SRT.sln\"\n-           }\n-           if (-not (Test-Path $SolFile)) {\n-               Exit-Script \"Solution file $BuildDir\\SRT.sln[x] not found, check CMake output\"\n-           }\n-           & $MSBuild $SolFile /nologo /maxcpucount /property:Configuration=$Conf /property:Platform=$Platform /target:srt_static\n-        }\n+foreach ($Platform in @(\"x64\", \"Win32\")) {\n+\n+    # Build directory. Cleanup to force a fresh cmake config.\n+    $BuildDir = \"$TmpDir\\build.$Platform\"\n+    Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $BuildDir\n+    [void](New-Item -Path $BuildDir -ItemType Directory -Force)\n+\n+    # Run CMake.\n+    Write-Output \"Configuring build for platform $Platform ...\"\n+    $SRoot = $SSL[$Platform][\"root\"]\n+    & $CMake -S $RepoDir -B $BuildDir -A $Platform `\n+        -DENABLE_STDCXX_SYNC=ON `\n+        -DOPENSSL_ROOT_DIR=\"$SRoot\" `\n+        -DOPENSSL_LIBRARIES=\"$SRoot\\lib\\libssl_static.lib;$SRoot\\lib\\libcrypto_static.lib\" `\n+        -DOPENSSL_INCLUDE_DIR=\"$SRoot\\include\"\n+\n+    # Patch version string in version.h\n+    Get-Content \"$BuildDir\\version.h\" |\n+        ForEach-Object {\n+            $_ -replace \"#define *SRT_VERSION_STRING .*\",\"#define SRT_VERSION_STRING `\"$Version`\"\"\n+        } |\n+        Out-File \"$BuildDir\\version.new\" -Encoding ascii\n+    Move-Item \"$BuildDir\\version.new\" \"$BuildDir\\version.h\" -Force\n+\n+    # Compile SRT.\n+    Write-Output \"Building for platform $Platform ...\"\n+    foreach ($Conf in @(\"Release\", \"Debug\")) {\n+        & $MSBuild \"$BuildDir\\SRT.sln\" /nologo /maxcpucount /property:Configuration=$Conf /property:Platform=$Platform /target:srt_static\n     }\n }\n \n # Verify the presence of compiled libraries.\n Write-Output \"Checking compiled libraries ...\"\n $Missing = 0\n-foreach ($Conf in $LIBDIR.Keys) {\n-    foreach ($Platform in $SSL.Keys) {\n-\t\tif ($OnlyPlatform -ne \"\" -and $Platform -ne $OnlyPlatform) {\n-\t\t\tcontinue\n-\t\t}\n+foreach ($Conf in @(\"Release\", \"Debug\")) {\n+    foreach ($Platform in @(\"x64\", \"Win32\")) {\n         $Path = \"$TmpDir\\build.$Platform\\$Conf\\srt_static.lib\"\n         if (-not (Test-Path $Path)) {\n             Write-Output \"**** Missing $Path\"\n@@ -264,18 +245,14 @@ Write-Output \"Building installer ...\"\n     /DOutDir=\"$OutDir\" `\n     /DBuildRoot=\"$TmpDir\" `\n     /DRepoDir=\"$RepoDir\" `\n-    /DlibsslWin32Release=\"$(ssl-lib Win32 Release ssl)\" `\n-    /DlibsslWin32Debug=\"$(ssl-lib Win32 Debug ssl)\" `\n-    /DlibcryptoWin32Release=\"$(ssl-lib Win32 Release crypto)\" `\n-    /DlibcryptoWin32Debug=\"$(ssl-lib Win32 Debug crypto)\" `\n-    /DlibsslWin64Release=\"$(ssl-lib x64 Release ssl)\" `\n-    /DlibsslWin64Debug=\"$(ssl-lib x64 Debug ssl)\" `\n-    /DlibcryptoWin64Release=\"$(ssl-lib x64 Release crypto)\" `\n-    /DlibcryptoWin64Debug=\"$(ssl-lib x64 Debug crypto)\" `\n-    /DlibsslArm64Release=\"$(ssl-lib Arm64 Release ssl)\" `\n-    /DlibsslArm64Debug=\"$(ssl-lib Arm64 Debug ssl)\" `\n-    /DlibcryptoArm64Release=\"$(ssl-lib Arm64 Release crypto)\" `\n-    /DlibcryptoArm64Debug=\"$(ssl-lib Arm64 Debug crypto)\" `\n+    /Dlibssl32MD=\"$libssl32MD\" `\n+    /Dlibssl32MDd=\"$libssl32MDd\" `\n+    /Dlibcrypto32MD=\"$libcrypto32MD\" `\n+    /Dlibcrypto32MDd=\"$libcrypto32MDd\" `\n+    /Dlibssl64MD=\"$libssl64MD\" `\n+    /Dlibssl64MDd=\"$libssl64MDd\" `\n+    /Dlibcrypto64MD=\"$libcrypto64MD\" `\n+    /Dlibcrypto64MDd=\"$libcrypto64MDd\" `\n     \"$ScriptDir\\libsrt.nsi\" \n \n if (-not (Test-Path $InstallExe)) {\ndiff --git a/scripts/win-installer/install-libsrt.ps1 b/scripts/win-installer/install-libsrt.ps1\nold mode 100755\nnew mode 100644\nindex 4aacb08..ae1b813\n--- a/scripts/win-installer/install-libsrt.ps1\n+++ b/scripts/win-installer/install-libsrt.ps1\n@@ -1,5 +1,4 @@\n-﻿#!/usr/bin/env PowerShell\n-# SRT library download and install for Windows.\n+﻿# SRT library download and install for Windows.\n # Copyright (c) 2021, Thierry Lelegard\n # All rights reserved.\n \ndiff --git a/scripts/win-installer/install-nsis.ps1 b/scripts/win-installer/install-nsis.ps1\nold mode 100755\nnew mode 100644\nindex ea48d14..14879b5\n--- a/scripts/win-installer/install-nsis.ps1\n+++ b/scripts/win-installer/install-nsis.ps1\n@@ -1,163 +1,122 @@\n-#!/usr/bin/env PowerShell\r\n-#-----------------------------------------------------------------------------\r\n-#\r\n-#  SRT - Secure, Reliable, Transport\r\n-#  Copyright (c) 2021, Thierry Lelegard\r\n-# \r\n-#  This Source Code Form is subject to the terms of the Mozilla Public\r\n-#  License, v. 2.0. If a copy of the MPL was not distributed with this\r\n-#  file, You can obtain one at http://mozilla.org/MPL/2.0/.\r\n-#\r\n-#-----------------------------------------------------------------------------\r\n-\r\n-<#\r\n- .DESCRIPTION\r\n-\r\n-  Download, expand and install NSIS, the NullSoft Installer Scripting.\r\n-\r\n- .PARAMETER ForceDownload\r\n-\r\n-  Force a download even if NSIS is already downloaded. By default the\r\n-  installer file is not redownloaded, if already found, although the\r\n-  MD5 sum will still be checked.\r\n-\r\n- .PARAMETER NoInstall\r\n-\r\n-  Do not install the NSIS package. By default, NSIS is installed.\r\n-\r\n- .PARAMETER NoPause\r\n-\r\n-  Do not wait for the user to press <enter> at end of execution. By default,\r\n-  execute a \"pause\" instruction at the end of execution, which is useful\r\n-  when the script was run from Windows Explorer.\r\n-#>\r\n-[CmdletBinding(SupportsShouldProcess=$true)]\r\n-param(\r\n-    [switch]$ForceDownload = $false,\r\n-    [switch]$NoInstall = $false,\r\n-    [switch]$NoPause = $false,\r\n-\t[switch]$Latest = $false\r\n-)\r\n-\r\n-# A function to exit this script.\r\n-function Exit-Script([string]$Message = \"\")\r\n-{\r\n-    $Code = 0\r\n-    if ($Message -ne \"\") {\r\n-        Write-Output \"ERROR: $Message\"\r\n-        $Code = 1\r\n-    }\r\n-    if (-not $NoPause) {\r\n-        pause\r\n-    }\r\n-    exit $Code\r\n-}\r\n-\r\n-# Local file names.\r\n-$RootDir = $PSScriptRoot\r\n-$TmpDir = \"$RootDir\\tmp\"\r\n-\r\n-# Create the directory for external products when necessary.\r\n-[void] (New-Item -Path $TmpDir -ItemType Directory -Force)\r\n-\r\n-# Without this, Invoke-WebRequest is awfully slow.\r\n-$ProgressPreference = 'SilentlyContinue'\r\n-\r\n-# 1. Define Project URLs\r\n-$ProjectUrl  = \"https://sourceforge.net/projects/nsis/files/NSIS%203/\"\r\n-$UserAgent   = \"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"\r\n-$DownloadHead = \"https://prdownloads.sourceforge.net/nsis/\"\r\n-\r\n-# Latest download, on-demand only. Default is a hardcoded version.\r\n-if ($Latest) {\r\n-\t# 2. Find the Latest Version Folder\r\n-\tWrite-Host \"Checking for the latest NSIS version...\"\r\n-\t$ProjectPage = Invoke-WebRequest -Uri $ProjectUrl -UserAgent $UserAgent -UseBasicParsing\r\n-\t# Matches version folders like \"3.10\", \"3.12\", etc.\r\n-\t$Versions    = [regex]::matches($ProjectPage.Content, 'title=\"([\\d\\.]+)\"') |\r\n-\t\tForEach-Object { $_.Groups[1].Value } |\r\n-\t\tSort-Object {[version]$_} -Descending\r\n-\t$LatestVer   = $Versions[0]\r\n-\tWrite-Host \"Latest version found: $LatestVer\"\r\n-\r\n-\t# 3. Build Folder and File Target URLs\r\n-\t$FolderUrl   = \"${ProjectUrl}${LatestVer}/\"\r\n-\t$FolderPage  = Invoke-WebRequest -Uri $FolderUrl -UserAgent $UserAgent -UseBasicParsing\r\n-\r\n-\t# Find the exact .exe installer filename (e.g., nsis-3.12-setup.exe)\r\n-\t$FileMatch   = [regex]::match($FolderPage.Content, \"nsis-${LatestVer}-setup\\.exe\")\r\n-\tif (-not $FileMatch.Success) {\r\n-\t\tthrow \"Could not find the setup.exe file for version $LatestVer\"\r\n-\t}\r\n-\t$FileName    = $FileMatch.Value\r\n-\r\n-\t# 4. Extract the Official MD5 Checksum\r\n-\tWrite-Host \"Extracting official MD5 checksum...\"\r\n-\t# SourceForge stores file metadata in a JSON-like 'data-files' attribute or specific table rows\r\n-\t# This regex extracts the MD5 hash associated directly with the target filename\r\n-\t#$HashPattern = 'tr[^>]*?data-name=\"' + [regex]::Escape($FileName) + '\"[^>]*?md5\">([^<]+)'\r\n-\t#$MD5Match    = [regex]::match($FolderPage.Content, $HashPattern)\r\n-\r\n-\t$filedata_inpage = [regex]::match($FolderPage.Content, \"net.sf.files = ([^;]+);\")\r\n-\tif (-not $filedata_inpage.Success) {\r\n-\t\tExit-Script \"net.sf.files not found\"\r\n-\t}\r\n-\r\n-\t$filedata_json = $filedata_inpage.Groups[1].Value.Trim().ToLower()\r\n-\r\n-\t$filedata = ConvertFrom-Json $filedata_json\r\n-\r\n-\t$ExpectedMD5 = $filedata.$FileName.md5\r\n-\r\n-\tif ($ExpectedMD5 -eq $null) {\r\n-\t\tExit-Script \"MD5 not found for $FileName\"\r\n-\t}\r\n-\r\n-\tWrite-Host \"MD5: $ExpectedMD5\"\r\n-} else {\r\n-\tWrite-Host \"USING PREDEFINED VERSION with hardcoded MD5: 3.12\"\r\n-\tWrite-Host \"Use -Latest to force latest version; note that this can be prone to MITM attacks.\"\r\n-\r\n-\t$ExpectedMD5 = \"d5d54c2a96c1bcb25764adc9f9ff97f2\"\r\n-\t$FileName = \"nsis-3.12-setup.exe\"\r\n-}\r\n-\r\n-# 5. Download the File\r\n-$DownloadUrl = \"$DownloadHead$FileName\" + \"?download\"\r\n-$OutputPath  = \"$TmpDir\\$FileName\"\r\n-\r\n-Write-Host \"Installer path: $OutputPath\"\r\n-\r\n-if (-not $ForceDownload -and (Test-Path $OutputPath)) {\r\n-    Write-Host \"Already downloaded, use -ForceDownload to download anyway.\"\r\n-} else {\r\n-    Write-Host \"Downloading from: $DownloadUrl\"\r\n-    Invoke-WebRequest -Uri $DownloadUrl -UserAgent Download -UseBasicParsing -OutFile $OutputPath\r\n-}\r\n-\r\n-# 6. Verify the MD5 Checksum\r\n-Write-Host \"Verifying checksum...\"\r\n-$LocalMD5 = (Get-FileHash -Path $OutputPath -Algorithm MD5).Hash.ToLower()\r\n-\r\n-if ($LocalMD5 -eq $ExpectedMD5) {\r\n-    Write-Host \"Checksum OK.\" -ForegroundColor Green\r\n-} else {\r\n-    Write-Error \"ERROR: Checksum mismatch!\"\r\n-    Write-Host \"Expected: $ExpectedMD5\" -ForegroundColor Red\r\n-    Write-Host \"Got:      $LocalMD5\" -ForegroundColor Red\r\n-    Remove-Item -Path $OutputPath -Force\r\n-    Write-Host \"Corrupted file removed.\"\r\n-\tExit-Script \"Installation not possible\"\r\n-}\r\n-\r\n-if (-not $NoInstall) {\r\n-    Write-Host \"Installing $FileName\"\r\n-    Start-Process -FilePath $OutputPath -ArgumentList @(\"/S\") -Wait\r\n-} else {\r\n-\tWrite-Host \"Installation not requested.\"\r\n-}\r\n-\r\n-Exit-Script\r\n-\r\n-\r\n-\r\n+﻿#-----------------------------------------------------------------------------\n+#\n+#  SRT - Secure, Reliable, Transport\n+#  Copyright (c) 2021, Thierry Lelegard\n+# \n+#  This Source Code Form is subject to the terms of the Mozilla Public\n+#  License, v. 2.0. If a copy of the MPL was not distributed with this\n+#  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n+#\n+#-----------------------------------------------------------------------------\n+\n+<#\n+ .SYNOPSIS\n+\n+  Download, expand and install NSIS, the NullSoft Installer Scripting.\n+\n+ .PARAMETER ForceDownload\n+\n+  Force a download even if NSIS is already downloaded.\n+\n+ .PARAMETER NoInstall\n+\n+  Do not install the NSIS package. By default, NSIS is installed.\n+\n+ .PARAMETER NoPause\n+\n+  Do not wait for the user to press <enter> at end of execution. By default,\n+  execute a \"pause\" instruction at the end of execution, which is useful\n+  when the script was run from Windows Explorer.\n+#>\n+[CmdletBinding(SupportsShouldProcess=$true)]\n+param(\n+    [switch]$ForceDownload = $false,\n+    [switch]$NoInstall = $false,\n+    [switch]$NoPause = $false\n+)\n+\n+Write-Output \"NSIS download and installation procedure\"\n+$NSISPage = \"https://nsis.sourceforge.io/Download\"\n+$FallbackURL = \"http://prdownloads.sourceforge.net/nsis/nsis-3.05-setup.exe?download\"\n+\n+# A function to exit this script.\n+function Exit-Script([string]$Message = \"\")\n+{\n+    $Code = 0\n+    if ($Message -ne \"\") {\n+        Write-Output \"ERROR: $Message\"\n+        $Code = 1\n+    }\n+    if (-not $NoPause) {\n+        pause\n+    }\n+    exit $Code\n+}\n+\n+# Local file names.\n+$RootDir = $PSScriptRoot\n+$TmpDir = \"$RootDir\\tmp\"\n+\n+# Create the directory for external products when necessary.\n+[void] (New-Item -Path $TmpDir -ItemType Directory -Force)\n+\n+# Without this, Invoke-WebRequest is awfully slow.\n+$ProgressPreference = 'SilentlyContinue'\n+\n+# Get the HTML page for NSIS downloads.\n+$status = 0\n+$message = \"\"\n+$Ref = $null\n+try {\n+    $response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $NSISPage\n+    $status = [int] [Math]::Floor($response.StatusCode / 100)\n+}\n+catch {\n+    $message = $_.Exception.Message\n+}\n+\n+if ($status -ne 1 -and $status -ne 2) {\n+    # Error fetch NSIS download page.\n+    if ($message -eq \"\" -and (Test-Path variable:response)) {\n+        Write-Output \"Status code $($response.StatusCode), $($response.StatusDescription)\"\n+    }\n+    else {\n+        Write-Output \"#### Error accessing ${NSISPage}: $message\"\n+    }\n+}\n+else {\n+    # Parse HTML page to locate the latest installer.\n+    $Ref = $response.Links.href | Where-Object { $_ -like \"*/nsis-*-setup.exe?download\" } | Select-Object -First 1\n+}\n+\n+if (-not $Ref) {\n+    # Could not find a reference to NSIS installer.\n+    $Url = [System.Uri]$FallbackURL\n+}\n+else {\n+    # Build the absolute URL's from base URL (the download page) and href links.\n+    $Url = New-Object -TypeName 'System.Uri' -ArgumentList ([System.Uri]$NSISPage, $Ref)\n+}\n+\n+$InstallerName = (Split-Path -Leaf $Url.LocalPath)\n+$InstallerPath = \"$TmpDir\\$InstallerName\"\n+\n+# Download installer\n+if (-not $ForceDownload -and (Test-Path $InstallerPath)) {\n+    Write-Output \"$InstallerName already downloaded, use -ForceDownload to download again\"\n+}\n+else {\n+    Write-Output \"Downloading $Url ...\"\n+    Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $InstallerPath\n+    if (-not (Test-Path $InstallerPath)) {\n+        Exit-Script \"$Url download failed\"\n+    }\n+}\n+\n+# Install NSIS\n+if (-not $NoInstall) {\n+    Write-Output \"Installing $InstallerName\"\n+    Start-Process -FilePath $InstallerPath -ArgumentList @(\"/S\") -Wait\n+}\n+\n+Exit-Script\ndiff --git a/scripts/win-installer/install-openssl.ps1 b/scripts/win-installer/install-openssl.ps1\nold mode 100755\nnew mode 100644\nindex d0a95fb..e24cecc\n--- a/scripts/win-installer/install-openssl.ps1\n+++ b/scripts/win-installer/install-openssl.ps1\n@@ -1,5 +1,4 @@\n-﻿#!/usr/bin/env PowerShell\n-#-----------------------------------------------------------------------------\n+﻿#-----------------------------------------------------------------------------\n #\n #  SRT - Secure, Reliable, Transport\n #  Copyright (c) 2021-2024, Thierry Lelegard\n@@ -33,13 +32,29 @@\n param(\n     [switch]$ForceDownload = $false,\n     [switch]$NoInstall = $false,\n-    [switch]$NoPause = $false,\n-\t[switch]$Latest = $false\n+    [switch]$NoPause = $false\n )\n \n Write-Output \"OpenSSL download and installation procedure\"\n \n-# The list of OpenSSL packages is available in a JSON file. See more details in README.md.\n+# A bit of history: Where to load OpenSSL binaries from?\n+#\n+# The packages are built by \"slproweb\". The binaries are downloadable from\n+# their Web page at: http://slproweb.com/products/Win32OpenSSL.html\n+#\n+# Initially, the HTML for this page was built on server-side. This script\n+# grabbed the URL content, parse the HTML and extracted the URL of the\n+# binaries for the latest OpenSSL packages from the \"href\" of the links.\n+#\n+# At some point in 2024, the site changed policy. The Web page is no longer\n+# built on server-side, but on client-side. The downloaded HTML contains some\n+# JavaScript which dynamically builds the URL of the binaries for the latest\n+# OpenSSL binaries. The previous method now finds no valid package URL from\n+# the downloaded page (a full browser is needed to execute the JavaScript).\n+# The JavaScript downloads a JSON file which contains all references to\n+# the OpenSSL binaries. This script now uses the same method: download that\n+# JSON file and parse it.\n+\n $PackageList = \"https://github.com/slproweb/opensslhashes/raw/master/win32_openssl_hashes.json\"\n \n # A function to exit this script.\n@@ -66,86 +81,60 @@ $TmpDir = \"$RootDir\\tmp\"\n # Without this, Invoke-WebRequest is awfully slow.\n $ProgressPreference = 'SilentlyContinue'\n \n-if ($Latest) {\n-\n-\t# Get the JSON configuration file for OpenSSL downloads.\n-\t$status = 0\n-\t$message = \"\"\n-\ttry {\n-\t\tWrite-Output \"Getting file index: $PackageList\"\n-\t\t$response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $PackageList\n-\t\t$status = [int] [Math]::Floor($response.StatusCode / 100)\n-\t}\n-\tcatch {\n-\t\t$message = $_.Exception.Message\n-\t}\n-\tif ($status -ne 1 -and $status -ne 2) {\n-\t\tif ($message -eq \"\" -and (Test-Path variable:response)) {\n-\t\t\tExit-Script \"Status code $($response.StatusCode), $($response.StatusDescription)\"\n-\t\t}\n-\t\telse {\n-\t\t\tExit-Script \"#### Error accessing ${PackageList}: $message\"\n-\t\t}\n-\t}\n-\t$config = ConvertFrom-Json $Response.Content\n-\n-\tWrite-Output \"Getting installer file with .light and .installer =~ 'exe' and .arch =~ 'Universal'\"\n-\n-\t# Find the URL of the latest \"universal\" installer in the JSON config file.\n-\t#$Url =\n-\t$have = 0\n-\t$config.files | Get-Member | ForEach-Object {\n-\t\t$name = $_.name\n-\t\t$info = $config.files.$($_.name)\n-\t\tif (-not $info.light -and $info.installer -like \"exe\" -and $info.arch -like \"universal\") {\n-\t\t\t$found_info = $info\n-\t\t\t$have = 1\n-\t\t}\n-\t} # | Select-Object -Last 1\n-\tif (-not $have) {\n-\t\tExit-Script \"#### No universal installer found\"\n-\t}\n-\n-\t$Url = $found_info.url\n-\t$xsum = $found_info.md5\n-} else {\n-\n-\tWrite-Host \"USING PREDEFINED VERSION with hardcoded MD5: 4.0.1\"\n-\tWrite-Host \"Use -Latest to force latest version; note that this can be prone to MITM attacks.\"\n-\t\n-\t$Url = \"https://slproweb.com/download/WinUniversalOpenSSL-4_0_1.exe\"\n-\t$xsum = \"34051060e0e9f48e63cfc1f3356191f6\"\n+# Get the JSON configuration file for OpenSSL downloads.\n+$status = 0\n+$message = \"\"\n+try {\n+    $response = Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $PackageList\n+    $status = [int] [Math]::Floor($response.StatusCode / 100)\n }\n-\n-$ExeName = (Split-Path -Leaf $Url)\n-$ExePath = \"$TmpDir\\$ExeName\"\n-\n-if (-not $ForceDownload -and (Test-Path $ExePath)) {\n-    Write-Output \"$ExeName already downloaded, use -ForceDownload to download again\"\n+catch {\n+    $message = $_.Exception.Message\n }\n-else {\n-    Write-Output \"Downloading $Url ...\"\n-    Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $ExePath\n-}\n-\n-if (-not (Test-Path $ExePath)) {\n-    Exit-Script \"$Url download failed\"\n+if ($status -ne 1 -and $status -ne 2) {\n+    if ($message -eq \"\" -and (Test-Path variable:response)) {\n+        Exit-Script \"Status code $($response.StatusCode), $($response.StatusDescription)\"\n+    }\n+    else {\n+        Exit-Script \"#### Error accessing ${PackageList}: $message\"\n+    }\n }\n+$config = ConvertFrom-Json $Response.Content\n+\n+# Download and install MSI packages for 32 and 64 bit.\n+foreach ($bits in @(32, 64)) {\n+\n+    # Get the URL of the MSI installer from the JSON config.\n+    $Url = $config.files | Get-Member | ForEach-Object {\n+        $name = $_.name\n+        $info = $config.files.$($_.name)\n+        if (-not $info.light -and $info.installer -like \"msi\" -and $info.bits -eq $bits -and $info.arch -like \"intel\") {\n+            $info.url\n+        }\n+    } | Select-Object -Last 1\n+    if (-not $Url) {\n+        Exit-Script \"#### No MSI installer found for Win${bits}\"\n+    }\n \n-Write-Output \"Will check tmp\\$ExeName for MD5: $xsum ...\"\n+    $MsiName = (Split-Path -Leaf $Url)\n+    $MsiPath = \"$TmpDir\\$MsiName\"\n \n-$filehash = get-filehash $ExePath -algorithm md5\n+    if (-not $ForceDownload -and (Test-Path $MsiPath)) {\n+        Write-Output \"$MsiName already downloaded, use -ForceDownload to download again\"\n+    }\n+    else {\n+        Write-Output \"Downloading $Url ...\"\n+        Invoke-WebRequest -UseBasicParsing -UserAgent Download -Uri $Url -OutFile $MsiPath\n+    }\n \n-if ($filehash.Hash -ne $xsum) {\n-\tExit-Script \"$ExePath MD5: $filehash - NOT MATCHING\"\n-}\n+    if (-not (Test-Path $MsiPath)) {\n+        Exit-Script \"$Url download failed\"\n+    }\n \n-if (-not $NoInstall) {\n-    Write-Output \"CHECKSUM MATCHES. Installing $ExeName\"\n-    Start-Process -FilePath $ExePath -ArgumentList @(\"/VERYSILENT\", \"/SUPPRESSMSGBOXES\", \"/NORESTART\", \"/ALLUSERS\") -Wait\n-} else {\n-\tWrite-Output \"Installation not requested.\"\n+    if (-not $NoInstall) {\n+        Write-Output \"Installing $MsiName\"\n+        Start-Process msiexec.exe -ArgumentList @(\"/i\", $MsiPath, \"/qn\", \"/norestart\") -Wait\n+    }\n }\n \n-\n Exit-Script\ndiff --git a/scripts/win-installer/libsrt.nsi b/scripts/win-installer/libsrt.nsi\nindex 66ff147..022ceb6 100644\n--- a/scripts/win-installer/libsrt.nsi\n+++ b/scripts/win-installer/libsrt.nsi\n@@ -28,10 +28,9 @@ Caption \"SRT Libraries Installer\"\n !include \"x64.nsh\"\n !verbose pop\n \n-!define ProductName   \"libsrt\"\n-!define BuildWin32Dir \"${BuildRoot}\\build.Win32\"\n-!define BuildWin64Dir \"${BuildRoot}\\build.x64\"\n-!define BuildArm64Dir \"${BuildRoot}\\build.ARM64\"\n+!define ProductName \"libsrt\"\n+!define Build32Dir  \"${BuildRoot}\\build.Win32\"\n+!define Build64Dir  \"${BuildRoot}\\build.x64\"\n \n ; Installer file information.\n VIProductVersion ${VersionInfo}\n@@ -94,7 +93,6 @@ functionEnd\n function un.onInit\n     ; In 64-bit installers, don't use registry redirection.\n     ${If} ${RunningX64}\n-    ${OrIf} ${IsNativeARM64}\n         SetRegView 64\n     ${EndIf}\n functionEnd\n@@ -130,7 +128,7 @@ Section \"Install\"\n     File \"${RepoDir}\\srtcore\\platform_sys.h\"\n     File \"${RepoDir}\\srtcore\\srt.h\"\n     File \"${RepoDir}\\srtcore\\udt.h\"\n-    File \"${BuildWin64Dir}\\version.h\"\n+    File \"${Build64Dir}\\version.h\"\n \n     CreateDirectory \"$INSTDIR\\include\\win\"\n     SetOutPath \"$INSTDIR\\include\\win\"\n@@ -141,39 +139,27 @@ Section \"Install\"\n     \n     CreateDirectory \"$INSTDIR\\lib\\Release-x64\"\n     SetOutPath \"$INSTDIR\\lib\\Release-x64\"\n-    File /oname=srt.lib       \"${BuildWin64Dir}\\Release\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoWin64Release}\"\n-    File /oname=libssl.lib    \"${libsslWin64Release}\"\n+    File /oname=srt.lib       \"${Build64Dir}\\Release\\srt_static.lib\"\n+    File /oname=libcrypto.lib \"${libcrypto64MD}\"\n+    File /oname=libssl.lib    \"${libssl64MD}\"\n \n     CreateDirectory \"$INSTDIR\\lib\\Debug-x64\"\n     SetOutPath \"$INSTDIR\\lib\\Debug-x64\"\n-    File /oname=srt.lib       \"${BuildWin64Dir}\\Debug\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoWin64Debug}\"\n-    File /oname=libssl.lib    \"${libsslWin64Debug}\"\n+    File /oname=srt.lib       \"${Build64Dir}\\Debug\\srt_static.lib\"\n+    File /oname=libcrypto.lib \"${libcrypto64MDd}\"\n+    File /oname=libssl.lib    \"${libssl64MDd}\"\n \n     CreateDirectory \"$INSTDIR\\lib\\Release-Win32\"\n     SetOutPath \"$INSTDIR\\lib\\Release-Win32\"\n-    File /oname=srt.lib       \"${BuildWin32Dir}\\Release\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoWin32Release}\"\n-    File /oname=libssl.lib    \"${libsslWin32Release}\"\n+    File /oname=srt.lib       \"${Build32Dir}\\Release\\srt_static.lib\"\n+    File /oname=libcrypto.lib \"${libcrypto32MD}\"\n+    File /oname=libssl.lib    \"${libssl32MD}\"\n \n     CreateDirectory \"$INSTDIR\\lib\\Debug-Win32\"\n     SetOutPath \"$INSTDIR\\lib\\Debug-Win32\"\n-    File /oname=srt.lib       \"${BuildWin32Dir}\\Debug\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoWin32Debug}\"\n-    File /oname=libssl.lib    \"${libsslWin32Debug}\"\n-\n-    CreateDirectory \"$INSTDIR\\lib\\Release-Arm64\"\n-    SetOutPath \"$INSTDIR\\lib\\Release-Arm64\"\n-    File /oname=srt.lib       \"${BuildArm64Dir}\\Release\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoArm64Release}\"\n-    File /oname=libssl.lib    \"${libsslArm64Release}\"\n-\n-    CreateDirectory \"$INSTDIR\\lib\\Debug-Arm64\"\n-    SetOutPath \"$INSTDIR\\lib\\Debug-Arm64\"\n-    File /oname=srt.lib       \"${BuildArm64Dir}\\Debug\\srt_static.lib\"\n-    File /oname=libcrypto.lib \"${libcryptoArm64Debug}\"\n-    File /oname=libssl.lib    \"${libsslArm64Debug}\"\n+    File /oname=srt.lib       \"${Build32Dir}\\Debug\\srt_static.lib\"\n+    File /oname=libcrypto.lib \"${libcrypto32MDd}\"\n+    File /oname=libssl.lib    \"${libssl32MDd}\"\n \n     ; Add an environment variable to installation root.\n     WriteRegStr HKLM ${EnvironmentKey} \"LIBSRT\" \"$INSTDIR\"\ndiff --git a/sonar-project.properties b/sonar-project.properties\nnew file mode 100644\nindex 0000000..d11323d\n--- /dev/null\n+++ b/sonar-project.properties\n@@ -0,0 +1,36 @@\n+# must be unique in a given SonarQube instance\n+sonar.projectKey=srt\n+sonar.organization=haivision\n+\n+# --- optional properties ---\n+\n+# This is the name and version displayed in the SonarCloud UI.\n+#sonar.projectName=srt\n+#sonar.projectVersion=1.0\n+ \n+# Path is relative to the sonar-project.properties file. Replace \"\\\" by \"/\" on Windows.\n+#sonar.sources=.\n+ \n+# Encoding of the source code. Default is default system encoding\n+#sonar.sourceEncoding=UTF-8\n+\n+# =====================================================\n+#   Meta-data for the project\n+# =====================================================\n+\n+sonar.links.homepage=https://github.com/Haivision/srt\n+sonar.links.scm=https://github.com/Haivision/srt\n+sonar.links.issue=https://github.com/Haivision/srt/issues\n+\n+\n+# =====================================================\n+#   Properties that will be shared amongst all modules\n+# =====================================================\n+\n+# SQ standard properties\n+sonar.sources=srtcore/,apps/,common/,examples/,haicrypt/,scripts/,testing/\n+sonar.tests=test/\n+\n+# Properties specific to the C/C++ analyzer:\n+sonar.cfamily.build-wrapper-output=_build/sonar-output\n+sonar.cfamily.gcov.reportsPath=.\ndiff --git a/srtcore/api.cpp b/srtcore/api.cpp\nindex c01eaa2..bb5dd64 100644\n--- a/srtcore/api.cpp\n+++ b/srtcore/api.cpp\n@@ -99,12 +99,6 @@ srt::CUDTSocket::~CUDTSocket()\n     releaseMutex(m_ControlLock);\n }\n \n-void srt::CUDTSocket::resetAtFork()\n-{\n-    m_UDT.resetAtFork();\n-    resetCond(m_AcceptCond);\n-}\n-\n SRT_SOCKSTATUS srt::CUDTSocket::getStatus()\n {\n     // TTL in CRendezvousQueue::updateConnStatus() will set m_bConnecting to false.\n@@ -195,23 +189,11 @@ srt::CUDTUnited::CUDTUnited()\n     // XXX An unlikely exception thrown from the below calls\n     // might destroy the application before `main`. This shouldn't\n     // be a problem in general.\n-    setupMutex(m_GCStartLock, \"GCStart\");\n     setupMutex(m_GCStopLock, \"GCStop\");\n     setupCond(m_GCStopCond, \"GCStop\");\n     setupMutex(m_GlobControlLock, \"GlobControl\");\n     setupMutex(m_IDLock, \"ID\");\n     setupMutex(m_InitLock, \"Init\");\n-    // Global initialization code\n-#ifdef _WIN32\n-    WORD    wVersionRequested;\n-    WSADATA wsaData;\n-    wVersionRequested = MAKEWORD(2, 2);\n-\n-    if (0 != WSAStartup(wVersionRequested, &wsaData))\n-        throw CUDTException(MJ_SETUP, MN_NONE, WSAGetLastError());\n-#endif\n-    CCryptoControl::globalInit();\n-    HLOGC(inlog.Debug, log << \"SRT Clock Type: \" << SRT_SYNC_CLOCK_STR);\n }\n \n srt::CUDTUnited::~CUDTUnited()\n@@ -219,12 +201,11 @@ srt::CUDTUnited::~CUDTUnited()\n     // Call it if it wasn't called already.\n     // This will happen at the end of main() of the application,\n     // when the user didn't call srt_cleanup().\n-    enterCS(m_InitLock);\n-    stopGarbageCollector();\n-    leaveCS(m_InitLock);\n+    if (m_bGCStatus)\n+    {\n+        cleanup();\n+    }\n \n-    // DO NOT call closeAllSockets() here; instead rely on that\n-    // all sockets have been closed when exiting the GC.\n     releaseMutex(m_GlobControlLock);\n     releaseMutex(m_IDLock);\n     releaseMutex(m_InitLock);\n@@ -238,11 +219,8 @@ srt::CUDTUnited::~CUDTUnited()\n     releaseCond(m_GCStopCond);\n #endif\n     releaseMutex(m_GCStopLock);\n-    releaseMutex(m_GCStartLock);\n+\n     delete m_pCache;\n-#ifdef _WIN32\n-    WSACleanup();\n-#endif\n }\n \n string srt::CUDTUnited::CONID(SRTSOCKET sock)\n@@ -255,183 +233,38 @@ string srt::CUDTUnited::CONID(SRTSOCKET sock)\n     return os.str();\n }\n \n-bool srt::CUDTUnited::startGarbageCollector()\n-{\n-\n-    ScopedLock guard(m_GCStartLock);\n-    if (!m_bGCStatus)\n-    {\n-        m_bClosing = false;\n-        m_bGCStatus = StartThread(m_GCThread, garbageCollect, this, \"SRT:GC\");\n-    }\n-    return m_bGCStatus;\n-}\n-\n-void srt::CUDTUnited::stopGarbageCollector()\n+int srt::CUDTUnited::startup()\n {\n-\n-    ScopedLock guard(m_GCStartLock);\n+    ScopedLock gcinit(m_InitLock);\n     if (m_bGCStatus)\n-    {\n-        m_bGCStatus = false;\n-        {\n-            CUniqueSync gclock (m_GCStopLock, m_GCStopCond);\n-            m_bClosing = true;\n-            gclock.notify_all();\n-        }\n-        m_GCThread.join();\n-    }\n-}\n-\n-void srt::CUDTUnited::cleanupAllSockets()\n-{\n-    for (sockets_t::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++i)\n-    {\n-        CUDTSocket* s = i->second;\n+        return 1;\n \n-#if ENABLE_BONDING\n-        if (s->m_GroupOf)\n-        {\n-            s->removeFromGroup(false);\n-        }\n-#endif\n+    if (m_iInstanceCount++ > 0)\n+        return 1;\n \n-        // remove from listener's queue\n-        sockets_t::iterator ls = m_Sockets.find(s->m_ListenSocket);\n-        if (ls == m_Sockets.end())\n-        {\n-            ls = m_ClosedSockets.find(s->m_ListenSocket);\n-        }\n-        if (ls != m_ClosedSockets.end())\n-        {\n-            ls->second->m_QueuedSockets.erase(s->m_SocketID);\n-        }\n-        s->core().closeAtFork();\n-        s->resetAtFork();\n-        delete(s);\n-    }\n-    m_Sockets.clear();\n-\n-#if ENABLE_BONDING\n-    for (groups_t::iterator j = m_Groups.begin(); j != m_Groups.end(); ++j)\n-    {\n-        delete j->second;\n-    }\n-    m_Groups.clear();\n-#endif\n-    for (map<int, CMultiplexer>::iterator i = m_mMultiplexer.begin(); i != m_mMultiplexer.end(); ++i)\n-    {\n-        CMultiplexer &multiplexer = i->second;\n-        multiplexer.resetAtFork();\n-    }\n-    m_mMultiplexer.clear();\n-}\n-\n-\n-void srt::CUDTUnited::closeAllSockets()\n-{\n-    // remove all sockets and multiplexers\n-    HLOGC(inlog.Debug, log << \"GC: GLOBAL EXIT - releasing all pending sockets. Acquiring control lock...\");\n-\n-    {\n-        // Pre-closing: run over all open sockets and close them.\n-        SharedLock glock(m_GlobControlLock);\n-\n-        for (sockets_t::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++i)\n-        {\n-            CUDTSocket* s = i->second;\n-            s->breakSocket_LOCKED();\n-\n-#if ENABLE_BONDING\n-            if (s->m_GroupOf)\n-            {\n-                HLOGC(smlog.Debug,\n-                      log << \"@\" << s->m_SocketID << \" IS MEMBER OF $\" << s->m_GroupOf->id()\n-                          << \" (IPE?) - REMOVING FROM GROUP\");\n-                s->removeFromGroup(false);\n-            }\n-#endif\n-        }\n-    }\n-\n-    {\n-        ExclusiveLock glock(m_GlobControlLock);\n-\n-        for (sockets_t::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++i)\n-        {\n-            CUDTSocket* s = i->second;\n-\n-            m_ClosedSockets[i->first] = s;\n-\n-            // remove from listener's queue\n-            sockets_t::iterator ls = m_Sockets.find(s->m_ListenSocket);\n-            if (ls == m_Sockets.end())\n-            {\n-                ls = m_ClosedSockets.find(s->m_ListenSocket);\n-                if (ls == m_ClosedSockets.end())\n-                    continue;\n-            }\n-\n-            enterCS(ls->second->m_AcceptLock);\n-            ls->second->m_QueuedSockets.erase(s->m_SocketID);\n-            leaveCS(ls->second->m_AcceptLock);\n-        }\n-        m_Sockets.clear();\n-\n-        for (sockets_t::iterator j = m_ClosedSockets.begin(); j != m_ClosedSockets.end(); ++j)\n-        {\n-            j->second->m_tsClosureTimeStamp = steady_clock::time_point();\n-        }\n+        // Global initialization code\n+#ifdef _WIN32\n+    WORD    wVersionRequested;\n+    WSADATA wsaData;\n+    wVersionRequested = MAKEWORD(2, 2);\n \n-#if ENABLE_BONDING\n-        for (groups_t::iterator j = m_Groups.begin(); j != m_Groups.end(); ++j)\n-        {\n-            SRTSOCKET id = j->second->m_GroupID;\n-            m_ClosedGroups[id] = j->second;\n-        }\n-        m_Groups.clear();\n+    if (0 != WSAStartup(wVersionRequested, &wsaData))\n+        throw CUDTException(MJ_SETUP, MN_NONE, WSAGetLastError());\n #endif\n-    }\n \n-    HLOGC(inlog.Debug, log << \"GC: GLOBAL EXIT - releasing all CLOSED sockets.\");\n-    while (true)\n-    {\n-        checkBrokenSockets();\n-\n-        enterCS(m_GlobControlLock);\n-        bool empty = m_ClosedSockets.empty();\n-        leaveCS(m_GlobControlLock);\n+    CCryptoControl::globalInit();\n \n-        if (empty)\n-            break;\n+    PacketFilter::globalInit();\n \n-        HLOGC(inlog.Debug, log << \"GC: checkBrokenSockets didn't wipe all sockets, repeating after 1s sleep\");\n-        srt::sync::this_thread::sleep_for(milliseconds_from(1));\n-    }\n+    m_bClosing = false;\n \n+    if (!StartThread(m_GCThread, garbageCollect, this, \"SRT:GC\"))\n+        return -1;\n \n-}\n-\n+    m_bGCStatus = true;\n \n-int srt::CUDTUnited::startup()\n-{\n-    ScopedLock gcinit(m_InitLock);\n-    m_iInstanceCount++;\n-    if (m_bGCStatus)\n-        return (m_iInstanceCount == 1) ? 1 : 0;\n-    else\n-        return startGarbageCollector() ? 0 : -1; \n-}\n+    HLOGC(inlog.Debug, log << \"SRT Clock Type: \" << SRT_SYNC_CLOCK_STR);\n \n-int srt::CUDTUnited::cleanupAtFork()\n-{\n-    cleanupAllSockets();\n-    resetThread(&m_GCThread);\n-    resetCond(m_GCStopCond);\n-    m_GCStopLock.unlock();\n-    setupCond(m_GCStopCond, \"GCStop\");\n-    m_iInstanceCount=0;\n-    m_bGCStatus = false;\n     return 0;\n }\n \n@@ -450,8 +283,28 @@ int srt::CUDTUnited::cleanup()\n     if (--m_iInstanceCount > 0)\n         return 0;\n \n-    stopGarbageCollector();\n-    closeAllSockets();\n+    if (!m_bGCStatus)\n+        return 0;\n+\n+    {\n+        UniqueLock gclock(m_GCStopLock);\n+        m_bClosing = true;\n+    }\n+    // NOTE: we can do relaxed signaling here because\n+    // waiting on m_GCStopCond has a 1-second timeout,\n+    // after which the m_bClosing flag is cheched, which\n+    // is set here above. Worst case secenario, this\n+    // pthread_join() call will block for 1 second.\n+    CSync::notify_one_relaxed(m_GCStopCond);\n+    m_GCThread.join();\n+\n+    m_bGCStatus = false;\n+\n+    // Global destruction code\n+#ifdef _WIN32\n+    WSACleanup();\n+#endif\n+\n     return 0;\n }\n \n@@ -594,7 +447,7 @@ SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps)\n         HLOGC(smlog.Debug, log << CONID(ns->m_SocketID) << \"newSocket: mapping socket \" << ns->m_SocketID);\n \n         // protect the m_Sockets structure.\n-        ExclusiveLock cs(m_GlobControlLock);\n+        ScopedLock cs(m_GlobControlLock);\n         m_Sockets[ns->m_SocketID] = ns;\n     }\n     catch (...)\n@@ -605,19 +458,12 @@ SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps)\n         throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);\n     }\n \n-    startGarbageCollector();\n     if (pps)\n         *pps = ns;\n \n     return ns->m_SocketID;\n }\n \n-// XXX NOTE: TSan reports here false positive against the call\n-// to CRcvQueue::removeListener. This here will apply shared\n-// lock on m_GlobControlLock in the call of locateSocket, while\n-// having applied a shared lock on CRcvQueue::m_pListener in\n-// CRcvQueue::worker_ProcessConnectionRequest. As this thread\n-// locks both mutexes as shared, it doesn't form a deadlock.\n int srt::CUDTUnited::newConnection(const SRTSOCKET     listen,\n                                    const sockaddr_any& peer,\n                                    const CPacket&      hspkt,\n@@ -682,11 +528,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET     listen,\n     }\n \n     // exceeding backlog, refuse the connection request\n-\n-    enterCS(ls->m_AcceptLock);\n-    size_t backlog = ls->m_QueuedSockets.size();\n-    leaveCS(ls->m_AcceptLock);\n-    if (backlog >= ls->m_uiBackLog)\n+    if (ls->m_QueuedSockets.size() >= ls->m_uiBackLog)\n     {\n         w_error = SRT_REJ_BACKLOG;\n         LOGC(cnlog.Note, log << \"newConnection: listen backlog=\" << ls->m_uiBackLog << \" EXCEEDED\");\n@@ -757,7 +599,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET     listen,\n         HLOGC(cnlog.Debug, log <<\n                 \"newConnection: incoming \" << peer.str() << \", mapping socket \" << ns->m_SocketID);\n         {\n-            ExclusiveLock cg(m_GlobControlLock);\n+            ScopedLock cg(m_GlobControlLock);\n             m_Sockets[ns->m_SocketID] = ns;\n         }\n \n@@ -806,7 +648,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET     listen,\n \n     {\n         // protect the m_PeerRec structure (and group existence)\n-        ExclusiveLock glock(m_GlobControlLock);\n+        ScopedLock glock(m_GlobControlLock);\n         try\n         {\n             HLOGC(cnlog.Debug, log << \"newConnection: mapping peer \" << ns->m_PeerID\n@@ -872,10 +714,10 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET     listen,\n                 g->m_bConnected = true;\n             }\n \n-            // XXX PROBLEM!!! These events are subscribed here so that this is done once, lazily,\n+            // XXX PROLBEM!!! These events are subscribed here so that this is done once, lazily,\n             // but groupwise connections could be accepted from multiple listeners for the same group!\n             // m_listener MUST BE A CONTAINER, NOT POINTER!!!\n-            // ALSO: Maybe checking \"the same listener\" is not necessary as subscription may be done\n+            // ALSO: Maybe checking \"the same listener\" is not necessary as subscruption may be done\n             // multiple times anyway?\n             if (!g->m_listener)\n             {\n@@ -980,7 +822,7 @@ ERR_ROLLBACK:\n         // connect() in UDT code) may fail, in which case this socket should not be\n         // further processed and should be removed.\n         {\n-            ExclusiveLock cg(m_GlobControlLock);\n+            ScopedLock cg(m_GlobControlLock);\n \n #if ENABLE_BONDING\n             if (ns->m_GroupOf)\n@@ -1055,7 +897,7 @@ int srt::CUDTUnited::installConnectHook(const SRTSOCKET u, srt_connect_callback_\n SRT_SOCKSTATUS srt::CUDTUnited::getStatus(const SRTSOCKET u)\n {\n     // protects the m_Sockets structure\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n \n     sockets_t::const_iterator i = m_Sockets.find(u);\n \n@@ -1146,34 +988,27 @@ int srt::CUDTUnited::listen(const SRTSOCKET u, int backlog)\n     // it could have changed the state. It could be also set listen in another\n     // thread, so check it out.\n \n+    // do nothing if the socket is already listening\n+    if (s->m_Status == SRTS_LISTENING)\n+        return 0;\n+\n+    // a socket can listen only if is in OPENED status\n+    if (s->m_Status != SRTS_OPENED)\n+        throw CUDTException(MJ_NOTSUP, MN_ISUNBOUND, 0);\n+\n+    // [[using assert(s->m_Status == OPENED)]];\n+\n+    // listen is not supported in rendezvous connection setup\n     if (s->core().m_config.bRendezvous)\n         throw CUDTException(MJ_NOTSUP, MN_ISRENDEZVOUS, 0);\n \n-    switch(s->m_Status)\n-    {\n-        case SRTS_INIT:\n-            throw CUDTException(MJ_NOTSUP, MN_ISUNBOUND, 0);\n-            break;\n-        case SRTS_OPENED:\n-            s->m_uiBackLog = backlog;\n-            s->core().setListenState(); // propagates CUDTException,\n-            s->m_Status = SRTS_LISTENING;\n-            break;\n-        case SRTS_LISTENING:\n-            s->m_uiBackLog = backlog;\n-            break;\n-        case SRTS_CONNECTING:\n-        case SRTS_CONNECTED:\n-            throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);\n-            break;\n-        case SRTS_BROKEN:\n-        case SRTS_CLOSING:\n-        case SRTS_CLOSED:\n-        case SRTS_NONEXIST:\n-            throw CUDTException(MJ_SETUP, MN_CLOSED, 0);\n-            break;\n-    }\n+    s->m_uiBackLog = backlog;\n+\n+    // [[using assert(s->m_Status == OPENED)]]; // (still, unchanged)\n \n+    s->core().setListenState(); // propagates CUDTException,\n+                                // if thrown, remains in OPENED state if so.\n+    s->m_Status = SRTS_LISTENING;\n \n     return 0;\n }\n@@ -1336,7 +1171,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int\n     {\n         // Put a lock to protect the group against accidental deletion\n         // in the meantime.\n-        SharedLock glock(m_GlobControlLock);\n+        ScopedLock glock(m_GlobControlLock);\n         // Check again; it's unlikely to happen, but\n         // it's a theoretically possible scenario\n         if (s->m_GroupOf)\n@@ -1616,13 +1451,13 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n         }\n \n         {\n-            ExclusiveLock cs(m_GlobControlLock);\n+            ScopedLock cs(m_GlobControlLock);\n             if (m_Sockets.count(sid) == 0)\n             {\n                 HLOGC(aclog.Debug, log << \"srt_connect_group: socket @\" << sid << \" deleted in process\");\n                 // Someone deleted the socket in the meantime?\n                 // Unlikely, but possible in theory.\n-                // Don't delete anything - it's already done.\n+                // Don't delete anyhting - it's alreay done.\n                 continue;\n             }\n \n@@ -1668,7 +1503,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n             }\n         }\n \n-        // XXX This should be re-enabled later, this should\n+        // XXX This should be reenabled later, this should\n         // be probably still in use to exchange information about\n         // packets asymmetrically lost. But for no other purpose.\n         /*\n@@ -1722,7 +1557,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n             targets[tii].errorcode = e.getErrorCode();\n             targets[tii].id        = CUDT::INVALID_SOCK;\n \n-            ExclusiveLock cl(m_GlobControlLock);\n+            ScopedLock cl(m_GlobControlLock);\n             ns->removeFromGroup(false);\n             m_Sockets.erase(ns->m_SocketID);\n             // Intercept to delete the socket on failure.\n@@ -1734,7 +1569,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n             LOGC(aclog.Fatal, log << \"groupConnect: IPE: UNKNOWN EXCEPTION from connectIn\");\n             targets[tii].errorcode = SRT_ESYSOBJ;\n             targets[tii].id        = CUDT::INVALID_SOCK;\n-            ExclusiveLock cl(m_GlobControlLock);\n+            ScopedLock cl(m_GlobControlLock);\n             ns->removeFromGroup(false);\n             m_Sockets.erase(ns->m_SocketID);\n             // Intercept to delete the socket on failure.\n@@ -1798,7 +1633,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n             // pending, about to be broken, and srt_connect() is called again?\n             // SHOULD BLOCK the latter, even though is OPEN.\n             // Or, OPEN should be removed from here and srt_connect(_group)\n-            // should block always if the group doesn't have neither 1 connected link\n+            // should block always if the group doesn't have neither 1 conencted link\n             g.m_bOpened = true;\n \n             g.m_stats.tsLastSampleTime = steady_clock::now();\n@@ -1994,7 +1829,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i\n     // function will still be polling sockets to determine the last man\n     // standing. Each one could, however, break by a different reason,\n     // for example, one by timeout, another by wrong passphrase. Check\n-    // the `errorcode` field to determine the reason for particular link.\n+    // the `errorcode` field to determine the reaon for particular link.\n     if (retval == -1)\n         throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);\n \n@@ -2031,12 +1866,7 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i\n     }\n     else\n     {\n-        // Only SRTS_OPENED status is otherwise expected.\n-        // Although depending on the state, different type of errors\n-        if (int(s->m_Status) >= SRTS_BROKEN) // BROKEN, CLOSING, CLOSED, NONEXIST\n-            throw CUDTException(MJ_SETUP, MN_CLOSED, 0);\n-\n-        if (s->m_Status != SRTS_OPENED) // LISTENING, CONNECTING, CONNECTED\n+        if (s->m_Status != SRTS_OPENED)\n             throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);\n \n         // status = SRTS_OPENED, so family should be known already.\n@@ -2113,7 +1943,7 @@ void srt::CUDTUnited::deleteGroup(CUDTGroup* g)\n {\n     using srt_logging::gmlog;\n \n-    srt::sync::ExclusiveLock cg(m_GlobControlLock);\n+    srt::sync::ScopedLock cg(m_GlobControlLock);\n     return deleteGroup_LOCKED(g);\n }\n \n@@ -2158,9 +1988,6 @@ void srt::CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g)\n \n int srt::CUDTUnited::close(CUDTSocket* s)\n {\n-    // Set the closing flag BEFORE you attempt to acquire\n-    s->setBreaking();\n-\n     HLOGC(smlog.Debug, log << s->core().CONID() << \"CLOSE. Acquiring control lock\");\n     ScopedLock socket_cg(s->m_ControlLock);\n     HLOGC(smlog.Debug, log << s->core().CONID() << \"CLOSING (removing from listening, closing CUDT)\");\n@@ -2207,7 +2034,7 @@ int srt::CUDTUnited::close(CUDTSocket* s)\n         HLOGC(smlog.Debug,\n               log << \"@\" << u << \"U::close done. GLOBAL CLOSE: \" << s->core().CONID()\n                   << \"Acquiring GLOBAL control lock\");\n-        ExclusiveLock manager_cg(m_GlobControlLock);\n+        ScopedLock manager_cg(m_GlobControlLock);\n         // since \"s\" is located before m_GlobControlLock, locate it again in case\n         // it became invalid\n         // XXX This is very weird; if we state that the CUDTSocket object\n@@ -2278,7 +2105,7 @@ int srt::CUDTUnited::close(CUDTSocket* s)\n             // Done the other way, but still done. You can stop waiting.\n             bool isgone = false;\n             {\n-                SharedLock manager_cg(m_GlobControlLock);\n+                ScopedLock manager_cg(m_GlobControlLock);\n                 isgone = m_ClosedSockets.count(u) == 0;\n             }\n             if (!isgone)\n@@ -2680,7 +2507,7 @@ int srt::CUDTUnited::epoll_release(const int eid)\n \n srt::CUDTSocket* srt::CUDTUnited::locateSocket(const SRTSOCKET u, ErrorHandling erh)\n {\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock  cg(m_GlobControlLock);\n     CUDTSocket* s = locateSocket_LOCKED(u);\n     if (!s)\n     {\n@@ -2708,7 +2535,7 @@ srt::CUDTSocket* srt::CUDTUnited::locateSocket_LOCKED(SRTSOCKET u)\n #if ENABLE_BONDING\n srt::CUDTGroup* srt::CUDTUnited::locateAcquireGroup(SRTSOCKET u, ErrorHandling erh)\n {\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n \n     const groups_t::iterator i = m_Groups.find(u);\n     if (i == m_Groups.end())\n@@ -2725,7 +2552,7 @@ srt::CUDTGroup* srt::CUDTUnited::locateAcquireGroup(SRTSOCKET u, ErrorHandling e\n \n srt::CUDTGroup* srt::CUDTUnited::acquireSocketsGroup(CUDTSocket* s)\n {\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n     CUDTGroup* g = s->m_GroupOf;\n     if (!g)\n         return NULL;\n@@ -2739,7 +2566,7 @@ srt::CUDTGroup* srt::CUDTUnited::acquireSocketsGroup(CUDTSocket* s)\n \n srt::CUDTSocket* srt::CUDTUnited::locateAcquireSocket(SRTSOCKET u, ErrorHandling erh)\n {\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n \n     CUDTSocket* s = locateSocket_LOCKED(u);\n     if (!s)\n@@ -2762,7 +2589,7 @@ bool srt::CUDTUnited::acquireSocket(CUDTSocket* s)\n     // directly from m_Sockets, or even better, has been acquired\n     // by some other functionality already, which is only about to\n     // be released earlier than you need.\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n     s->apiAcquire();\n     // Keep the lock so that no one changes anything in the meantime.\n     // If the socket m_Status == SRTS_CLOSED (set by setClosed()), then\n@@ -2778,7 +2605,7 @@ bool srt::CUDTUnited::acquireSocket(CUDTSocket* s)\n \n srt::CUDTSocket* srt::CUDTUnited::locatePeer(const sockaddr_any& peer, const SRTSOCKET id, int32_t isn)\n {\n-    SharedLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n \n     map<int64_t, set<SRTSOCKET> >::iterator i = m_PeerRec.find(CUDTSocket::getPeerSpec(id, isn));\n     if (i == m_PeerRec.end())\n@@ -2802,7 +2629,7 @@ srt::CUDTSocket* srt::CUDTUnited::locatePeer(const sockaddr_any& peer, const SRT\n \n void srt::CUDTUnited::checkBrokenSockets()\n {\n-    ExclusiveLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n \n #if ENABLE_BONDING\n     vector<SRTSOCKET> delgids;\n@@ -2834,66 +2661,36 @@ void srt::CUDTUnited::checkBrokenSockets()\n     vector<SRTSOCKET> tbc;\n     vector<SRTSOCKET> tbr;\n \n-    bool forced_closing = m_bClosing;\n-\n     for (sockets_t::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++i)\n     {\n         CUDTSocket* s = i->second;\n         if (!s->core().m_bBroken)\n-        {\n-            if (!forced_closing)\n-            {\n-                continue;\n-            }\n-            else\n-            {\n-                // Set forcefully, we are in cleanup and close everything\n-                LOGC(smlog.Warn, log << \"CLEANUP: Forcefully breaking socket @\" << s->m_SocketID);\n-                s->core().m_bBroken = true;\n-            }\n-        }\n+            continue;\n \n         if (s->m_Status == SRTS_LISTENING)\n         {\n-            if (!forced_closing)\n-            {\n-                const steady_clock::duration elapsed = steady_clock::now() - s->m_tsClosureTimeStamp.load();\n-                // A listening socket should wait an extra 3 seconds\n-                // in case a client is connecting.\n-                if (elapsed < milliseconds_from(CUDT::COMM_CLOSE_BROKEN_LISTENER_TIMEOUT_MS))\n-                    continue;\n-            }\n+            const steady_clock::duration elapsed = steady_clock::now() - s->m_tsClosureTimeStamp.load();\n+            // A listening socket should wait an extra 3 seconds\n+            // in case a client is connecting.\n+            if (elapsed < milliseconds_from(CUDT::COMM_CLOSE_BROKEN_LISTENER_TIMEOUT_MS))\n+                continue;\n         }\n         else\n         {\n             CUDT& u = s->core();\n \n-            // For decent closing, just keep it as long as it still\n-            // has data in the buffer.\n-            if (!forced_closing)\n-            {\n-                enterCS(u.m_RcvBufferLock);\n-                bool has_avail_packets = u.m_pRcvBuffer && u.m_pRcvBuffer->hasAvailablePackets();\n-                leaveCS(u.m_RcvBufferLock);\n+            enterCS(u.m_RcvBufferLock);\n+            bool has_avail_packets = u.m_pRcvBuffer && u.m_pRcvBuffer->hasAvailablePackets();\n+            leaveCS(u.m_RcvBufferLock);\n \n-                if (has_avail_packets)\n-                {\n-                    const int bc = u.m_iBrokenCounter.load();\n-                    if (bc > 0)\n-                    {\n-                        // if there is still data in the receiver buffer, wait longer\n-                        s->core().m_iBrokenCounter.store(bc - 1);\n-                        continue;\n-                    }\n-                }\n-            }\n-            else\n+            if (has_avail_packets)\n             {\n-                // Forced closing: any data still in the buffer - delete them.\n-                ScopedLock cgb (u.m_RcvBufferLock);\n-                if (u.m_pRcvBuffer && u.m_pRcvBuffer->hasAvailablePackets())\n+                const int bc = u.m_iBrokenCounter.load();\n+                if (bc > 0)\n                 {\n-                    u.m_pRcvBuffer->dropAll();\n+                    // if there is still data in the receiver buffer, wait longer\n+                    s->core().m_iBrokenCounter.store(bc - 1);\n+                    continue;\n                 }\n             }\n         }\n@@ -2920,8 +2717,7 @@ void srt::CUDTUnited::checkBrokenSockets()\n         {\n             ls = m_ClosedSockets.find(s->m_ListenSocket);\n             if (ls == m_ClosedSockets.end())\n-                continue; // END LOOP AS NOT FOUND\n-            // OTHERWISE PROCEED with erasing as queued\n+                continue;\n         }\n \n         enterCS(ls->second->m_AcceptLock);\n@@ -2942,9 +2738,6 @@ void srt::CUDTUnited::checkBrokenSockets()\n         // other conditions applying on the socket that prevent it from being deleted.\n         if (ps->isStillBusy())\n         {\n-            // NOTE: you can't use forced_closing to prevent it because isStillBusy\n-            // means that some facility has acquired it and is going to use it for\n-            // operations; forced deletion may lead to UB/crash.\n             HLOGC(smlog.Debug, log << \"checkBrokenSockets: @\" << ps->m_SocketID << \" is still busy, SKIPPING THIS CYCLE.\");\n             continue;\n         }\n@@ -3024,7 +2817,7 @@ void srt::CUDTUnited::removeSocket(const SRTSOCKET u)\n         return;\n     }\n \n-    HLOGC(smlog.Note, log << \"@\" << s->m_SocketID << \" busy=\" << s->isStillBusy());\n+    LOGC(smlog.Note, log << \"@\" << s->m_SocketID << \" busy=\" << s->isStillBusy());\n \n #if ENABLE_BONDING\n     if (s->m_GroupOf)\n@@ -3190,9 +2983,8 @@ bool srt::CUDTUnited::channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, cons\n \n void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, const UDPSOCKET* udpsock /*[[nullable]]*/)\n {\n-    const int         port      = reqaddr.hport();\n-    ExclusiveLock cg(m_GlobControlLock);\n-  \n+    ScopedLock cg(m_GlobControlLock);\n+\n     // If udpsock is provided, then this socket will be simply\n     // taken for binding as a good deal. It would be nice to make\n     // a sanity check to see if this UDP socket isn't already installed\n@@ -3202,6 +2994,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n     {\n         // If not, we need to see if there exist already a multiplexer bound\n         // to the same endpoint.\n+        const int         port      = reqaddr.hport();\n         const CSrtConfig& cfgSocket = s->core().m_config;\n \n         // This loop is going to check the attempted binding of\n@@ -3369,7 +3162,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n             {\n                 LOGC(smlog.Error,\n                      log << \"bind: Wildcard address: \" << reqaddr.str()\n-                         << \" conflicts with existing IP binding: \" << mux_addr.str());\n+                         << \" conflicts with existting IP binding: \" << mux_addr.str());\n                 throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);\n             }\n             // If this is bound to a certain address, AND:\n@@ -3419,8 +3212,6 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n         }\n     }\n \n-\n-\n     // a new multiplexer is needed\n     CMultiplexer m;\n     configureMuxer((m), s, reqaddr.family());\n@@ -3471,16 +3262,12 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n         m.m_pSndQueue = new CSndQueue;\n         m.m_pSndQueue->init(m.m_pChannel, m.m_pTimer);\n         m.m_pRcvQueue = new CRcvQueue;\n-\n-        // NOTE: Receiver Queue packet size must be of the maximum possible because you never\n-        // know what kind of packet will come over the network, while this must accept any kind\n-        // of packet.\n-        m.m_pRcvQueue->init(128, s->core().controlPayloadSize(reqaddr.family()), m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer);\n+        m.m_pRcvQueue->init(128, s->core().maxPayloadSize(), m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer);\n \n         // Rewrite the port here, as it might be only known upon return\n         // from CChannel::open.\n         m.m_iPort               = installMuxer((s), m);\n-        swap(m_mMultiplexer[m.m_iID],m);\n+        m_mMultiplexer[m.m_iID] = m;\n     }\n     catch (const CUDTException&)\n     {\n@@ -3493,7 +3280,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n         throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);\n     }\n \n-    HLOGC(smlog.Debug, log << \"bind: creating new multiplexer for port \" << port);\n+    HLOGC(smlog.Debug, log << \"bind: creating new multiplexer for port \" << m.m_iPort);\n }\n \n // This function is going to find a multiplexer for the port contained\n@@ -3503,7 +3290,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, cons\n // multiplexer wasn't found by id, the search by port number continues.\n bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls)\n {\n-    ExclusiveLock cg(m_GlobControlLock);\n+    ScopedLock cg(m_GlobControlLock);\n     const int  port = ls->m_SelfAddr.hport();\n \n     HLOGC(smlog.Debug,\n@@ -3596,33 +3383,74 @@ void* srt::CUDTUnited::garbageCollect(void* p)\n \n     UniqueLock gclock(self->m_GCStopLock);\n \n-    for (;;)\n+    while (!self->m_bClosing)\n     {\n         INCREMENT_THREAD_ITERATIONS();\n         self->checkBrokenSockets();\n \n-        if (self->m_bClosing)\n+        HLOGC(inlog.Debug, log << \"GC: sleep 1 s\");\n+        self->m_GCStopCond.wait_for(gclock, seconds_from(1));\n+    }\n+\n+    // remove all sockets and multiplexers\n+    HLOGC(inlog.Debug, log << \"GC: GLOBAL EXIT - releasing all pending sockets. Acquring control lock...\");\n+\n+    {\n+        ScopedLock glock(self->m_GlobControlLock);\n+\n+        for (sockets_t::iterator i = self->m_Sockets.begin(); i != self->m_Sockets.end(); ++i)\n         {\n-            // If GC is requested to close, it means the global cleanup\n-            // was requested. But before exiting make sure all sockets\n-            // and multiplexers are closed. \n+            CUDTSocket* s = i->second;\n+            s->breakSocket_LOCKED();\n \n+#if ENABLE_BONDING\n+            if (s->m_GroupOf)\n             {\n-                SharedLock glock(self->m_GlobControlLock);\n-                if (self->m_Sockets.empty() && self->m_ClosedSockets.empty())\n-                    break;\n+                HLOGC(smlog.Debug,\n+                      log << \"@\" << s->m_SocketID << \" IS MEMBER OF $\" << s->m_GroupOf->id()\n+                          << \" (IPE?) - REMOVING FROM GROUP\");\n+                s->removeFromGroup(false);\n+            }\n+#endif\n+            self->m_ClosedSockets[i->first] = s;\n \n-                HLOGC(smlog.Debug, log << \"GC: REQUESTED CLOSE, DELAYING EXIT - still \"\n-                        << self->m_Sockets.size() << \" running and \"\n-                        << self->m_ClosedSockets.size() << \" closed sockets\");\n+            // remove from listener's queue\n+            sockets_t::iterator ls = self->m_Sockets.find(s->m_ListenSocket);\n+            if (ls == self->m_Sockets.end())\n+            {\n+                ls = self->m_ClosedSockets.find(s->m_ListenSocket);\n+                if (ls == self->m_ClosedSockets.end())\n+                    continue;\n             }\n-            self->m_GCStopCond.wait_for(gclock, milliseconds_from(200));\n-            continue;\n+\n+            enterCS(ls->second->m_AcceptLock);\n+            ls->second->m_QueuedSockets.erase(s->m_SocketID);\n+            leaveCS(ls->second->m_AcceptLock);\n         }\n+        self->m_Sockets.clear();\n \n-        HLOGC(inlog.Debug, log << \"GC: sleep 1 s\");\n-        self->m_GCStopCond.wait_for(gclock, seconds_from(1));\n+        for (sockets_t::iterator j = self->m_ClosedSockets.begin(); j != self->m_ClosedSockets.end(); ++j)\n+        {\n+            j->second->m_tsClosureTimeStamp = steady_clock::time_point();\n+        }\n     }\n+\n+    HLOGC(inlog.Debug, log << \"GC: GLOBAL EXIT - releasing all CLOSED sockets.\");\n+    while (true)\n+    {\n+        self->checkBrokenSockets();\n+\n+        enterCS(self->m_GlobControlLock);\n+        bool empty = self->m_ClosedSockets.empty();\n+        leaveCS(self->m_GlobControlLock);\n+\n+        if (empty)\n+            break;\n+\n+        HLOGC(inlog.Debug, log << \"GC: checkBrokenSockets didn't wipe all sockets, repeating after 1s sleep\");\n+        srt::sync::this_thread::sleep_for(milliseconds_from(1));\n+    }\n+\n     THREAD_EXIT();\n     return NULL;\n }\n@@ -3631,14 +3459,6 @@ void* srt::CUDTUnited::garbageCollect(void* p)\n \n int srt::CUDT::startup()\n {\n-#if HAVE_PTHREAD_ATFORK\n-    static bool registered = false;\n-    if (!registered)\n-    {\n-        pthread_atfork(NULL, NULL, (void (*)()) srt::CUDT::cleanupAtFork);\n-        registered = true;\n-    }\n-#endif \n     return uglobal().startup();\n }\n \n@@ -3647,17 +3467,10 @@ int srt::CUDT::cleanup()\n     return uglobal().cleanup();\n }\n \n-int srt::CUDT::cleanupAtFork()\n-{\n-    CUDTUnited &context = uglobal();\n-    context.cleanupAtFork();\n-    new (&context) CUDTUnited();\n-\n-    return context.startup();\n-}\n-\n SRTSOCKET srt::CUDT::socket()\n {\n+    uglobal().startup();\n+\n     try\n     {\n         return uglobal().newSocket();\n@@ -3705,12 +3518,15 @@ srt::CUDTGroup& srt::CUDT::newGroup(const int type)\n \n SRTSOCKET srt::CUDT::createGroup(SRT_GROUP_TYPE gt)\n {\n+    // Doing the same lazy-startup as with srt_create_socket()\n+    uglobal().startup();\n+\n     try\n     {\n-        srt::sync::ExclusiveLock globlock(uglobal().m_GlobControlLock);\n+        srt::sync::ScopedLock globlock(uglobal().m_GlobControlLock);\n         return newGroup(gt).id();\n         // Note: potentially, after this function exits, the group\n-        // could be deleted, immediately, from a separate thread (though\n+        // could be deleted, immediately, from a separate thread (tho\n         // unlikely because the other thread would need some handle to\n         // keep it). But then, the first call to any API function would\n         // return invalid ID error.\n@@ -3763,7 +3579,7 @@ SRTSOCKET srt::CUDT::getGroupOfSocket(SRTSOCKET socket)\n {\n     // Lock this for the whole function as we need the group\n     // to persist the call.\n-    SharedLock glock(uglobal().m_GlobControlLock);\n+    ScopedLock  glock(uglobal().m_GlobControlLock);\n     CUDTSocket* s = uglobal().locateSocket_LOCKED(socket);\n     if (!s || !s->m_GroupOf)\n         return APIError(MJ_NOTSUP, MN_INVAL, 0);\ndiff --git a/srtcore/api.h b/srtcore/api.h\nindex 96302f1..48e7827 100644\n--- a/srtcore/api.h\n+++ b/srtcore/api.h\n@@ -120,7 +120,6 @@ public:\n     }\n \n     ~CUDTSocket();\n-    void resetAtFork();\n \n     void construct();\n \n@@ -216,11 +215,6 @@ public:\n         core().m_bClosing = true;\n     }\n \n-    void setBreaking()\n-    {\n-        core().m_bBreaking = true;\n-    }\n-\n     /// This does the same as setClosed, plus sets the m_bBroken to true.\n     /// Such a socket can still be read from so that remaining data from\n     /// the receiver buffer can be read, but no longer sends anything.\n@@ -245,7 +239,6 @@ class CUDTUnited\n     friend class CUDTGroup;\n     friend class CRendezvousQueue;\n     friend class CCryptoControl;\n-    friend class TestMockCUDT;\n \n public:\n     CUDTUnited();\n@@ -270,7 +263,6 @@ public:\n     /// release the UDT library.\n     /// @return 0 if success, otherwise -1 is returned.\n     int cleanup();\n-    int cleanupAtFork();\n \n     /// Create a new UDT socket.\n     /// @param [out] pps Variable (optional) to which the new socket will be written, if succeeded\n@@ -415,7 +407,7 @@ private:\n     groups_t m_Groups;\n #endif\n \n-    sync::SharedMutex m_GlobControlLock; // used to synchronize UDT API\n+    sync::Mutex m_GlobControlLock; // used to synchronize UDT API\n \n     sync::Mutex m_IDLock; // used to synchronize ID generation\n \n@@ -470,10 +462,6 @@ private:\n \n     CUDTSocket* locateAcquireSocket(SRTSOCKET u, ErrorHandling erh = ERH_RETURN);\n     bool acquireSocket(CUDTSocket* s);\n-    bool startGarbageCollector();\n-    void stopGarbageCollector();\n-    void cleanupAllSockets();\n-    void closeAllSockets();\n \n public:\n     struct SocketKeeper\n@@ -530,7 +518,7 @@ private:\n     /// @brief Checks if channel configuration matches the socket configuration.\n     /// @param cfgMuxer multiplexer configuration.\n     /// @param cfgSocket socket configuration.\n-    /// @return true if configurations match, false otherwise.\n+    /// @return tru if configurations match, false otherwise.\n     static bool channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket);\n     static bool inet6SettingsCompat(const sockaddr_any& muxaddr, const CSrtMuxerConfig& cfgMuxer,\n         const sockaddr_any& reqaddr, const CSrtMuxerConfig& cfgSocket);\n@@ -546,7 +534,6 @@ private:\n \n private:\n     srt::sync::atomic<bool> m_bClosing;\n-    sync::Mutex             m_GCStartLock;\n     sync::Mutex             m_GCStopLock;\n     sync::Condition         m_GCStopCond;\n \ndiff --git a/srtcore/atomic.h b/srtcore/atomic.h\nindex 6f510be..f391be9 100644\n--- a/srtcore/atomic.h\n+++ b/srtcore/atomic.h\n@@ -75,11 +75,11 @@\n    #define ATOMIC_USE_GCC_INTRINSICS\n #elif defined(__GNUC__) \\\n    && ( (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) )\n-   // NOTE: The __atomic_* family of intrinsics were introduced in GCC-4.7.0.\n+   // NOTE: The __atomic_* family of intrisics were introduced in GCC-4.7.0.\n    // NOTE: This follows #if defined(__clang__), because most if, not all,\n    //    versions of Clang define __GNUC__ and __GNUC_MINOR__ but often define\n    //    them to 4.4 or an even earlier version. Most of the newish versions\n-   //    of Clang also support GCC Atomic Intrinsics even if they set GCC version\n+   //    of Clang also support GCC Atomic Intrisics even if they set GCC version\n    //    macros to <4.7.\n    #define ATOMIC_USE_GCC_INTRINSICS\n #elif defined(__GNUC__) && !defined(ATOMIC_USE_SRT_SYNC_MUTEX)\ndiff --git a/srtcore/buffer_rcv.cpp b/srtcore/buffer_rcv.cpp\nindex 88f9410..e74d48c 100644\n--- a/srtcore/buffer_rcv.cpp\n+++ b/srtcore/buffer_rcv.cpp\n@@ -276,10 +276,10 @@ int CRcvBuffer::dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno, Dro\n     // Drop by packet seqno range to also wipe those packets that do not exist in the buffer.\n     const int offset_a = CSeqNo::seqoff(m_iStartSeqNo, seqnolo);\n     const int offset_b = CSeqNo::seqoff(m_iStartSeqNo, seqnohi);\n-    if (offset_b < 0 || offset_a >= (int) m_szSize)\n+    if (offset_b < 0)\n     {\n         LOGC(rbuflog.Debug, log << \"CRcvBuffer.dropMessage(): nothing to drop. Requested [\" << seqnolo << \"; \"\n-            << seqnohi << \"]. Buffer start \" << m_iStartSeqNo << \" size \" << m_szSize << \".\");\n+            << seqnohi << \"]. Buffer start \" << m_iStartSeqNo << \".\");\n         return 0;\n     }\n \n@@ -483,7 +483,7 @@ int CRcvBuffer::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)\n \n     if (!m_tsbpd.isEnabled())\n         // We need updateFirstReadableOutOfOrder() here even if we are reading inorder,\n-        // in case readable inorder packets are all read out.\n+        // incase readable inorder packets are all read out.\n         updateFirstReadableOutOfOrder();\n \n     const int bytes_read = int(dst - data);\ndiff --git a/srtcore/buffer_rcv.h b/srtcore/buffer_rcv.h\nindex eac1c7c..c5fca42 100644\n--- a/srtcore/buffer_rcv.h\n+++ b/srtcore/buffer_rcv.h\n@@ -94,7 +94,7 @@ public:\n     /// @param seqnolo sequence number of the first packet in the dropping range.\n     /// @param seqnohi sequence number of the last packet in the dropping range.\n     /// @param msgno message number to drop (0 if unknown)\n-    /// @param actionOnExisting Should an existing SOLO packet be dropped from the buffer or preserved?\n+    /// @param actionOnExisting Should an exising SOLO packet be dropped from the buffer or preserved?\n     /// @return the number of packets actually dropped.\n     int dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno, DropActionIfExists actionOnExisting);\n \n@@ -162,7 +162,7 @@ public:\n     int getRcvDataSize() const;\n \n     /// Get the number of packets, bytes and buffer timespan.\n-    /// Differs from getRcvDataSize() that it counts all packets in the buffer, not only continuous.\n+    /// Differs from getRcvDataSize() that it counts all packets in the buffer, not only continious.\n     int getRcvDataSize(int& bytes, int& timespan) const;\n \n     struct PacketInfo\n@@ -221,7 +221,7 @@ public:\n \n     /// Return buffer capacity.\n     /// One slot had to be empty in order to tell the difference between \"empty buffer\" and \"full buffer\".\n-    /// E.g. m_iFirstNonreadPos would again point to m_iStartPos if m_szSize entries are added continuously.\n+    /// E.g. m_iFirstNonreadPos would again point to m_iStartPos if m_szSize entries are added continiously.\n     /// TODO: Old receiver buffer capacity returns the actual size. Check for conflicts.\n     size_t capacity() const\n     {\ndiff --git a/srtcore/buffer_snd.cpp b/srtcore/buffer_snd.cpp\nindex 7b8c44f..ef1bc49 100644\n--- a/srtcore/buffer_snd.cpp\n+++ b/srtcore/buffer_snd.cpp\n@@ -202,7 +202,7 @@ void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl)\n             s->m_iMsgNoBitset |= PacketBoundaryBits(PB_FIRST);\n         if (i == iNumBlocks - 1)\n             s->m_iMsgNoBitset |= PacketBoundaryBits(PB_LAST);\n-        // NOTE: if i is neither 0 nor size-1, it results with PB_SUBSEQUENT.\n+        // NOTE: if i is neither 0 nor size-1, it resuls with PB_SUBSEQUENT.\n         //       if i == 0 == size-1, it results with PB_SOLO.\n         // Packets assigned to one message can be:\n         // [PB_FIRST] [PB_SUBSEQUENT] [PB_SUBSEQUENT] [PB_LAST] - 4 packets per message\n@@ -550,13 +550,6 @@ void CSndBuffer::ackData(int offset)\n {\n     ScopedLock bufferguard(m_BufLock);\n \n-    if (offset > m_iCount)\n-    {\n-        LOGC(bslog.Warn, log << \"ackData: offset=\" << offset << \" > count=\" << m_iCount\n-                << \" - adjusting\");\n-        offset = m_iCount;\n-    }\n-\n     bool move = false;\n     for (int i = 0; i < offset; ++i)\n     {\ndiff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h\nindex 1c90a56..8847982 100644\n--- a/srtcore/buffer_tools.h\n+++ b/srtcore/buffer_tools.h\n@@ -198,133 +198,6 @@ private:\n     int        m_iRateBps;          //< Rate in Bytes/sec.\n };\n \n-// Utility class for bandwidth limitation\n-class CShaper\n-{\n-public:\n-    static double SHAPER_RESOLUTION_US() { return 1000000.; } // micro seconds\n-    static double BURSTPERIOD_DEFAULT() { return 100; }\n-\n-    typedef sync::steady_clock::time_point time_point;\n-    typedef sync::steady_clock::duration duration;\n-    CShaper (double min_tokens_capacity):\n-        m_BurstPeriod(sync::milliseconds_from(BURSTPERIOD_DEFAULT())),\n-        m_rate_Bps(0),\n-        m_tokens(0),\n-        m_tokensCapacity(0),\n-        m_minTokensCapacity(min_tokens_capacity)\n-    {\n-\n-    }\n-\n-    // Token capacity should be settable later\n-    void setMinimumTokenCapacity(double cap)\n-    {\n-        m_minTokensCapacity = cap;\n-        updateLimits();\n-    }\n-\n-private:\n-    duration m_BurstPeriod;\n-    double m_rate_Bps;      // current_bitrate in Bytes per second\n-    double m_tokens;       // in bytes\n-    double m_tokensCapacity;   // in bytes\n-    double m_minTokensCapacity;\n-    time_point m_UpdateTime;\n-    void setTokenCapacity(double tokens)\n-    {\n-        m_tokensCapacity = std::max(0., tokens);\n-    }\n-\n-    void setTokens(double tokens)\n-    {\n-        // It is allowed to set the negative number of tokens,\n-        // just not less than the negative maximum\n-        m_tokens = Bounds(1 - m_tokensCapacity, tokens, m_tokensCapacity);\n-    }\n-\n-    static double periodToTokens(double rate_Bps, duration period)\n-    {\n-        double seconds = double(sync::count_microseconds(period)) / SHAPER_RESOLUTION_US();\n-        return rate_Bps * seconds;\n-    }\n-\n-    static duration tokensToPeriod(double rate_Bps, double tokens)\n-    {\n-        double seconds = tokens / rate_Bps;\n-        return sync::microseconds_from(seconds * SHAPER_RESOLUTION_US());\n-    }\n-\n-    void updateLimits()\n-    {\n-        double token_cap = periodToTokens(m_rate_Bps, m_BurstPeriod);\n-        if (token_cap < m_minTokensCapacity)\n-        {\n-            // We have a too small value; recalculate the burst period to reach the minimum.\n-            duration minperiod = tokensToPeriod(m_rate_Bps, m_minTokensCapacity);\n-            token_cap = m_minTokensCapacity;\n-            m_BurstPeriod = minperiod;\n-        }\n-        setTokenCapacity(token_cap);\n-    }\n-\n-public:\n-    void setBitrate(double bw_Bps)\n-    {\n-        // NOTE: comparison on double to check the PREVIOUSLY\n-        // SET value (m_rate_Bps), not recalculated value.\n-        if (bw_Bps != m_rate_Bps)\n-        {\n-            m_rate_Bps = bw_Bps;\n-            updateLimits();\n-        }\n-    }\n-\n-    void setMinimumBurstPeriod(duration hp)\n-    {\n-        if (m_BurstPeriod < hp)\n-        {\n-            setBurstPeriod(hp);\n-        }\n-    }\n-\n-    void setBurstPeriod(duration bp)\n-    {\n-        if (bp != m_BurstPeriod)\n-        {\n-            m_BurstPeriod = bp;\n-            updateLimits();\n-        }\n-    }\n-\n-    // Note that tick() must be always called after setBitrate.\n-    void tick(const time_point& now)\n-    {\n-        duration delta = now - m_UpdateTime;\n-        m_UpdateTime = now;\n-\n-        double update_tokens = periodToTokens(m_rate_Bps, delta);\n-        setTokens(update_tokens + m_tokens);\n-    }\n-\n-    bool enoughTokens(double len) const { return len <= m_tokens; }\n-    void consumeTokens(double len) { setTokens(m_tokens - len); }\n-\n-\n-    // For debug purposes\n-    int ntokens() const { return m_tokens; }\n-    duration burstPeriod() const { return m_BurstPeriod; }\n-    int maxTokens() const { return m_tokensCapacity; }\n-    // TOKENS = BITRATE * BURST_PERIOD / (SHAPER_UNIT * SHAPER_RESOLUTION_US)\n-    // TOKENS * SHAPER_UNIT * SHAPER_RESOLUTION_US = BITRATE * BURST_PERIOD\n-    // BITRATE = (TOKENS * SHAPER_UNIT * SHAPER_RESOLUTION_US) / (BURST_PERIOD)\n-    double tokenRate_Bps(double tokens) const\n-    {\n-        return (tokens * SHAPER_RESOLUTION_US()) / (sync::count_microseconds(m_BurstPeriod));\n-    }\n-    double availRate_Bps() const { return tokenRate_Bps(m_tokens); }\n-    double usedRate_Bps() const { return tokenRate_Bps(m_tokensCapacity - m_tokens); }\n-};\n } // namespace srt\n \n #endif\ndiff --git a/srtcore/channel.cpp b/srtcore/channel.cpp\nindex 9c8babe..9967d7d 100644\n--- a/srtcore/channel.cpp\n+++ b/srtcore/channel.cpp\n@@ -289,20 +289,6 @@ void srt::CChannel::attach(UDPSOCKET udpsock, const sockaddr_any& udpsocks_addr)\n     setUDPSockOpt();\n }\n \n-static inline string fmt_opt(bool value, const string& label)\n-{\n-    string out;\n-    out.reserve(label.size() + 2);\n-    out = value ? \"+\" : \"-\";\n-    out += label;\n-    return out;\n-}\n-\n-static inline string fmt_alt(bool value, const string& label, const string& unlabel)\n-{\n-    return value ? label : unlabel;\n-}\n-\n void srt::CChannel::setUDPSockOpt()\n {\n #if defined(SUNOS)\n@@ -311,13 +297,13 @@ void srt::CChannel::setUDPSockOpt()\n         // Retrieve starting SND/RCV Buffer sizes.\n         int startRCVBUF = 0;\n         optSize         = sizeof(startRCVBUF);\n-        if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&startRCVBUF, &optSize))\n+        if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&startRCVBUF, &optSize))\n         {\n             startRCVBUF = -1;\n         }\n         int startSNDBUF = 0;\n         optSize         = sizeof(startSNDBUF);\n-        if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (void*)&startSNDBUF, &optSize))\n+        if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (void*)&startSNDBUF, &optSize))\n         {\n             startSNDBUF = -1;\n         }\n@@ -326,12 +312,13 @@ void srt::CChannel::setUDPSockOpt()\n         //   maximum value.\n         // However, do not reduce the buffer size.\n         const int maxsize = 64000;\n-        if (-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF,\n-                    (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize))\n+        if (0 !=\n+            ::setsockopt(\n+                m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize))\n         {\n             int currentRCVBUF = 0;\n             optSize           = sizeof(currentRCVBUF);\n-            if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&currentRCVBUF, &optSize))\n+            if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&currentRCVBUF, &optSize))\n             {\n                 currentRCVBUF = -1;\n             }\n@@ -340,12 +327,13 @@ void srt::CChannel::setUDPSockOpt()\n                 ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&maxsize, sizeof maxsize);\n             }\n         }\n-        if (-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF,\n-                    (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))\n+        if (0 !=\n+            ::setsockopt(\n+                m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))\n         {\n             int currentSNDBUF = 0;\n             optSize           = sizeof(currentSNDBUF);\n-            if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&currentSNDBUF, &optSize))\n+            if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&currentSNDBUF, &optSize))\n             {\n                 currentSNDBUF = -1;\n             }\n@@ -358,13 +346,13 @@ void srt::CChannel::setUDPSockOpt()\n         // Retrieve ending SND/RCV Buffer sizes.\n         int endRCVBUF = 0;\n         optSize       = sizeof(endRCVBUF);\n-        if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&endRCVBUF, &optSize))\n+        if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (void*)&endRCVBUF, &optSize))\n         {\n             endRCVBUF = -1;\n         }\n         int endSNDBUF = 0;\n         optSize       = sizeof(endSNDBUF);\n-        if (-1 == ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (void*)&endSNDBUF, &optSize))\n+        if (0 != ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (void*)&endSNDBUF, &optSize))\n         {\n             endSNDBUF = -1;\n         }\n@@ -380,137 +368,90 @@ void srt::CChannel::setUDPSockOpt()\n #elif defined(BSD) || TARGET_OS_MAC\n     // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value\n     int maxsize = 64000;\n-    if (-1 == ::setsockopt(\n+    if (0 != ::setsockopt(\n                  m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize))\n         ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&maxsize, sizeof maxsize);\n-    if (-1 == ::setsockopt(\n+    if (0 != ::setsockopt(\n                  m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize))\n         ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&maxsize, sizeof maxsize);\n #else\n-    // for other systems, if requested is greater than maximum, the maximum value will be automatically used\n-    if ((-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF,\n-                    (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize))\n-        ||\n-        (-1 == ::setsockopt( m_iSocket, SOL_SOCKET, SO_SNDBUF,\n-                    (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize)))\n+    // for other systems, if requested is greated than maximum, the maximum value will be automactally used\n+    if ((0 !=\n+         ::setsockopt(\n+             m_iSocket, SOL_SOCKET, SO_RCVBUF, (const char*)&m_mcfg.iUDPRcvBufSize, sizeof m_mcfg.iUDPRcvBufSize)) ||\n+        (0 != ::setsockopt(\n+                  m_iSocket, SOL_SOCKET, SO_SNDBUF, (const char*)&m_mcfg.iUDPSndBufSize, sizeof m_mcfg.iUDPSndBufSize)))\n         throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n #endif\n \n-    bool is_set = false;\n-    bool adr_unspec = false, adr_mapped = false, adr_v6 = false;\n-    if (m_BindAddr.family() == AF_INET)\n-    {\n-        adr_unspec = m_BindAddr.isany();\n-    }\n-    else\n-    {\n-        adr_unspec = IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr);\n-        adr_mapped = IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr);\n-        adr_v6 = true;\n-    }\n-\n     if (m_mcfg.iIpTTL != -1)\n     {\n-        if (!adr_v6)\n+        if (m_BindAddr.family() == AF_INET)\n         {\n-            if (-1 == ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n-            {\n-                LOGC(kmlog.Error, log << \"setsockopt(IP_TTL): \" << SysStrError(NET_ERROR));\n+            if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n                 throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n-            }\n-            is_set = true;\n         }\n         else\n         {\n             // If IPv6 address is unspecified, set BOTH IP_TTL and IPV6_UNICAST_HOPS.\n \n             // For specified IPv6 address, set IPV6_UNICAST_HOPS ONLY UNLESS it's an IPv4-mapped-IPv6\n-            if (adr_unspec || !adr_mapped)\n+            if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) ||\n+                !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr))\n             {\n-                if (-1 == ::setsockopt( m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS,\n-                            (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n+                if (0 !=\n+                    ::setsockopt(\n+                        m_iSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n                 {\n-                    LOGC(kmlog.Error, log << \"setsockopt(IPV6_UNICAST_HOPS): \" << SysStrError(NET_ERROR));\n                     throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n                 }\n-                is_set = true;\n             }\n             // For specified IPv6 address, set IP_TTL ONLY WHEN it's an IPv4-mapped-IPv6\n-            if (!is_set) // adr_mapped (because adr_unspec was handled above)\n+            if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr))\n             {\n-                if (-1 == ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n+                if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TTL, (const char*)&m_mcfg.iIpTTL, sizeof m_mcfg.iIpTTL))\n                 {\n-                    LOGC(kmlog.Error, log << \"setsockopt(IP_TTL): \" << SysStrError(NET_ERROR)\n-                            << fmt_alt(adr_unspec, \" (v6 unspec)\", \" (v6 mapped v4)\"));\n                     throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n                 }\n-                is_set = true;\n             }\n         }\n-\n-        if (!is_set)\n-        {\n-            LOGC(kmlog.Error, log << \"srt_setsockflag(SRTO_IPTTL): No suitable condition for adr=\" << m_BindAddr.str()\n-                    << \" : \" << fmt_opt(adr_v6, \"v6 \") << fmt_opt(adr_unspec, \"unspec \") << fmt_opt(adr_mapped, \"mapped\"));\n-            throw CUDTException(MJ_SETUP, MN_INVAL, 0);\n-        }\n     }\n \n-    is_set = false;\n     if (m_mcfg.iIpToS != -1)\n     {\n         if (m_BindAddr.family() == AF_INET)\n         {\n-            if (-1 == ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n-            {\n-                LOGC(kmlog.Error, log << \"setsockopt(IP_TOS): \" << SysStrError(NET_ERROR));\n+            if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n                 throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n-            }\n-            is_set = true;\n         }\n         else\n         {\n             // If IPv6 address is unspecified, set BOTH IP_TOS and IPV6_TCLASS.\n \n-            SRT_ATR_UNUSED bool using_tclass = false;\n #ifdef IPV6_TCLASS\n-            using_tclass = true;\n             // For specified IPv6 address, set IPV6_TCLASS ONLY UNLESS it's an IPv4-mapped-IPv6\n-            if (adr_unspec || !adr_mapped)\n+            if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) ||\n+                !IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr))\n             {\n-                if (-1 == ::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_TCLASS,\n-                            (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n+                if (0 != ::setsockopt(\n+                             m_iSocket, IPPROTO_IPV6, IPV6_TCLASS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n                 {\n-                    LOGC(kmlog.Error, log << \"setsockopt(IPV6_TCLASS): \" << SysStrError(NET_ERROR));\n                     throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n                 }\n-                is_set = true;\n             }\n #endif\n \n             // For specified IPv6 address, set IP_TOS ONLY WHEN it's an IPv4-mapped-IPv6\n-            if (!is_set && (adr_unspec || adr_mapped))\n+            if (IN6_IS_ADDR_UNSPECIFIED(&m_BindAddr.sin6.sin6_addr) || IN6_IS_ADDR_V4MAPPED(&m_BindAddr.sin6.sin6_addr))\n             {\n-                if (-1 == ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n+                if (0 != ::setsockopt(m_iSocket, IPPROTO_IP, IP_TOS, (const char*)&m_mcfg.iIpToS, sizeof m_mcfg.iIpToS))\n                 {\n-                    LOGC(kmlog.Error, log << \"setsockopt(IP_TOS): \" << SysStrError(NET_ERROR)\n-                            << (adr_unspec ? \" (v6 unspecified)\" : \" (v6 mapped v4)\")\n-                            << (using_tclass ? \"(fallback to IP_TOS)\" : \"\"));\n                     throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n                 }\n-                is_set = true;\n             }\n         }\n-\n-        if (!is_set)\n-        {\n-            LOGC(kmlog.Error, log << \"srt_setsockflag(SRTO_IPTOS): No suitable condition for adr=\" << m_BindAddr.str()\n-                    << \" : \" << fmt_opt(adr_v6, \"v6 \") << fmt_opt(adr_unspec, \"unspec \") << fmt_opt(adr_mapped, \"mapped\"));\n-            throw CUDTException(MJ_SETUP, MN_INVAL, 0);\n-        }\n     }\n \n-\n #ifdef SRT_ENABLE_BINDTODEVICE\n     if (!m_mcfg.sBindToDevice.empty())\n     {\n@@ -520,10 +461,14 @@ void srt::CChannel::setUDPSockOpt()\n             throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n         }\n \n-        if (-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_BINDTODEVICE,\n-                    m_mcfg.sBindToDevice.c_str(), m_mcfg.sBindToDevice.size()))\n+        if (0 != ::setsockopt(\n+                     m_iSocket, SOL_SOCKET, SO_BINDTODEVICE, m_mcfg.sBindToDevice.c_str(), m_mcfg.sBindToDevice.size()))\n         {\n-            LOGC(kmlog.Error, log << \"setsockopt(SRTO_BINDTODEVICE): \" << SysStrError(NET_ERROR));\n+#if ENABLE_LOGGING\n+            char        buf[255];\n+            const char* err = SysStrError(NET_ERROR, buf, 255);\n+            LOGC(kmlog.Error, log << \"setsockopt(SRTO_BINDTODEVICE): \" << err);\n+#endif // ENABLE_LOGGING\n             throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n         }\n     }\n@@ -537,7 +482,7 @@ void srt::CChannel::setUDPSockOpt()\n         throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n #elif defined(_WIN32)\n     u_long nonBlocking = 1;\n-    if (-1 == ioctlsocket(m_iSocket, FIONBIO, &nonBlocking))\n+    if (0 != ioctlsocket(m_iSocket, FIONBIO, &nonBlocking))\n         throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n #else\n     timeval tv;\n@@ -550,11 +495,7 @@ void srt::CChannel::setUDPSockOpt()\n     tv.tv_usec = 100;\n #endif\n     // Set receiving time-out value\n-    if (-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval)))\n-        throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n-    // Set sending time-out, too; O_NONBLOCK sets it in both directions,\n-    // so both should be also set here for consistency.\n-    if (-1 == ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(timeval)))\n+    if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval)))\n         throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);\n #endif\n \n@@ -879,9 +820,7 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const socka\n             if (bCompleted)\n                 res = 0;\n             else\n-            {\n                 LOGC(kslog.Warn, log << \"CChannel::sendto call on ::WSAGetOverlappedResult failed with error: \" << NET_ERROR);\n-            }\n             lEvent.reset();\n         }\n         else\ndiff --git a/srtcore/common.cpp b/srtcore/common.cpp\nindex b301b80..2e94668 100644\n--- a/srtcore/common.cpp\n+++ b/srtcore/common.cpp\n@@ -67,7 +67,6 @@ modified by\n #include \"logging.h\"\n #include \"packet.h\"\n #include \"threadname.h\"\n-#include \"logger_defs.h\"\n \n using namespace std;\n using namespace srt::sync;\n@@ -93,9 +92,6 @@ m_iMinor(minor)\n        m_iErrno = NET_ERROR;\n    else\n       m_iErrno = err;\n-   // XXX No logging allowed because this constructor can be also used for\n-   // initializing global object. That problem should be solved separately.\n-   // HLOGC(aclog.Debug, log << \"CREATED SRT EXCEPTION: \" << (1000*major+minor) << \" errno=\" << m_iErrno);\n }\n \n const char* srt::CUDTException::getErrorMessage() const ATR_NOTHROW\n@@ -468,12 +464,12 @@ bool SrtParseConfig(const string& s, SrtConfig& w_config)\n     return true;\n }\n \n-string FormatLossArray(const vector< pair<int32_t, int32_t> >& lra)\n+std::string FormatLossArray(const std::vector< std::pair<int32_t, int32_t> >& lra)\n {\n-    ostringstream os;\n+    std::ostringstream os;\n \n     os << \"[ \";\n-    for (vector< pair<int32_t, int32_t> >::const_iterator i = lra.begin(); i != lra.end(); ++i)\n+    for (std::vector< std::pair<int32_t, int32_t> >::const_iterator i = lra.begin(); i != lra.end(); ++i)\n     {\n         int len = CSeqNo::seqoff(i->first, i->second);\n         os << \"%\" << i->first;\n@@ -486,16 +482,6 @@ string FormatLossArray(const vector< pair<int32_t, int32_t> >& lra)\n     return os.str();\n }\n \n-string FormatValue(int value, int factor, const char* unit)\n-{\n-    ostringstream out;\n-    double showval = value;\n-    showval /= factor;\n-    out << std::fixed << showval << unit;\n-    return out.str();\n-}\n-\n-\n ostream& PrintEpollEvent(ostream& os, int events, int et_events)\n {\n     static pair<int, const char*> const namemap [] = {\ndiff --git a/srtcore/common.h b/srtcore/common.h\nindex 3d9bf65..ff84c3f 100644\n--- a/srtcore/common.h\n+++ b/srtcore/common.h\n@@ -95,12 +95,6 @@ modified by\n #define SRT_STATIC_ASSERT(cond, msg)\n #endif\n \n-#if HAVE_FULL_CXX11\n-#define FUNID() __func__\n-#else\n-#define FUNID() __FUNCTION__\n-#endif\n-\n #include <exception>\n \n namespace srt_logging\n@@ -571,7 +565,7 @@ struct EventSlot\n \n // UDT Sequence Number 0 - (2^31 - 1)\n \n-// seqcmp: compare two seq#, considering the wrapping\n+// seqcmp: compare two seq#, considering the wraping\n // seqlen: length from the 1st to the 2nd seq#, including both\n // seqoff: offset from the 2nd to the 1st seq#\n // incseq: increase the seq# by 1\n@@ -607,7 +601,7 @@ public:\n        return seqcmp(value, other.value) <= 0;\n    }\n \n-   // circular arithmetic\n+   // circular arithmetics\n    friend int operator-(const CSeqNo& c1, const CSeqNo& c2)\n    {\n        return seqoff(c2.value, c1.value);\n@@ -1443,7 +1437,6 @@ inline bool checkMappedIPv4(const sockaddr_in6& sa)\n \n std::string FormatLossArray(const std::vector< std::pair<int32_t, int32_t> >& lra);\n std::ostream& PrintEpollEvent(std::ostream& os, int events, int et_events = 0);\n-std::string FormatValue(int value, int factor, const char* unit);\n \n } // namespace srt\n \ndiff --git a/srtcore/congctl.cpp b/srtcore/congctl.cpp\nindex 8de14d8..85d4cda 100644\n--- a/srtcore/congctl.cpp\n+++ b/srtcore/congctl.cpp\n@@ -60,7 +60,7 @@ void SrtCongestion::Check()\n \n class LiveCC: public SrtCongestionControlBase\n {\n-    srt::sync::atomic<int64_t>  m_llSndMaxBW;          //Max bandwidth (bytes/sec)\n+    int64_t  m_llSndMaxBW;          //Max bandwidth (bytes/sec)\n     srt::sync::atomic<size_t>   m_zSndAvgPayloadSize;  //Average Payload Size of packets to xmit\n     size_t   m_zMaxPayloadSize;\n     size_t   m_zHeaderSize;\n@@ -79,10 +79,10 @@ public:\n         m_llSndMaxBW = BW_INFINITE;    // 1 Gbbps in Bytes/sec BW_INFINITE\n         m_zMaxPayloadSize = parent->OPT_PayloadSize();\n         if (m_zMaxPayloadSize == 0)\n-            m_zMaxPayloadSize = parent->maxDataPayloadSize();\n+            m_zMaxPayloadSize = parent->maxPayloadSize();\n         m_zSndAvgPayloadSize = m_zMaxPayloadSize;\n \n-        m_zHeaderSize = parent->m_config.iMSS - parent->maxDataPayloadSize();\n+        m_zHeaderSize = parent->m_config.iMSS - parent->maxPayloadSize();\n \n         m_iMinNakInterval_us = 20000;   //Minimum NAK Report Period (usec)\n         m_iNakReportAccel = 2;       //Default NAK Report Period (RTT) accelerator (send periodic NAK every RTT/2)\n@@ -319,7 +319,7 @@ public:\n     /// and request ACK to be sent immediately.\n     bool needsQuickACK(const CPacket& pkt) ATR_OVERRIDE\n     {\n-        if (pkt.getLength() < m_parent->maxDataPayloadSize())\n+        if (pkt.getLength() < m_parent->maxPayloadSize())\n         {\n             // This is not a regular fixed size packet...\n             // an irregular sized packet usually indicates the end of a message, so send an ACK immediately\ndiff --git a/srtcore/core.cpp b/srtcore/core.cpp\nindex 9379da5..eca2b20 100644\n--- a/srtcore/core.cpp\n+++ b/srtcore/core.cpp\n@@ -93,7 +93,7 @@ const SRTSOCKET UDT::INVALID_SOCK = srt::CUDT::INVALID_SOCK;\n const int       UDT::ERROR        = srt::CUDT::ERROR;\n \n //#define SRT_CMD_HSREQ       1           /* SRT Handshake Request (sender) */\n-#define SRT_CMD_HSREQ_MINSZ 8 /* Minimum Compatible (1.x.x) packet size (bytes) */\n+#define SRT_CMD_HSREQ_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */\n #define SRT_CMD_HSREQ_SZ 12   /* Current version packet size */\n #if SRT_CMD_HSREQ_SZ > SRT_CMD_MAXSZ\n #error SRT_CMD_MAXSZ too small\n@@ -106,7 +106,7 @@ const int       UDT::ERROR        = srt::CUDT::ERROR;\n */\n \n //#define SRT_CMD_HSRSP       2           /* SRT Handshake Response (receiver) */\n-#define SRT_CMD_HSRSP_MINSZ 8 /* Minimum Compatible (1.x.x) packet size (bytes) */\n+#define SRT_CMD_HSRSP_MINSZ 8 /* Minumum Compatible (1.x.x) packet size (bytes) */\n #define SRT_CMD_HSRSP_SZ 12   /* Current version packet size */\n #if SRT_CMD_HSRSP_SZ > SRT_CMD_MAXSZ\n #error SRT_CMD_MAXSZ too small\n@@ -259,134 +259,6 @@ CUDTUnited& srt::CUDT::uglobal()\n \n #endif\n \n-#ifdef ENABLE_RATE_MEASUREMENT\n-void srt::RateMeasurement::pickup(const clock_time& time)\n-{\n-    // Check if the time has passed the period.\n-    clock_interval diff;\n-    if (!passedInterval(time, (diff)))\n-    {\n-        HLOGC(bslog.Debug, log << \"RateMeasurement: too early, \" << FormatDuration<DUNIT_MS>(diff)\n-                << \" with begin TS=\" << FormatTime(m_beginTime) << \" now=\" << FormatTime(time));\n-        // Still collect data for the current period.\n-        return;\n-    }\n-\n-    // Doesn't matter what `diff` really is. Enough that we have\n-    // this time aligned with 10ms resolution calls 10 times.\n-\n-    Slice slice;\n-    {\n-        // Lock for the moment of taking the data\n-        sync::ScopedLock lk (m_lock);\n-\n-        slice.packets = m_nInstaPackets;\n-        slice.bytes = m_nInstaBytes;\n-        slice.begin_time = m_beginTime;\n-\n-        m_nInstaPackets = 0;\n-        m_nInstaBytes = 0;\n-        m_beginTime = time;\n-    }\n-\n-    HLOGC(bslog.Debug, log << \"RateMeasurement: passed \" << FormatDuration<DUNIT_MS>(diff)\n-            << \" extracted packets=\" << slice.packets << \" bytes=\" << slice.bytes\n-            << \" now beginTS=\" << FormatTime(m_beginTime));\n-\n-    // Ok, now stickpile the slice.\n-    // If the container is empty, do not stockpile empty slices.\n-    if (m_slices.empty() && slice.bytes == 0)\n-    {\n-        HLOGC(bslog.Debug, log << \"... NOT COLLECTING packet with \" << slice.bytes << \" bytes to \" << m_slices.size() << \" total\");\n-        // Empty-to-empty: DO NOT stockpile.\n-        // NOTE: the container is never cleared when it has\n-        // any older data, so this situation is only possible:\n-        // - in the beginning\n-        // - in the long run if it happened that 10 slices in\n-        //   a row were empty.\n-        // So in this case we simply wait for having the first\n-        // packets with something notified. We also know that\n-        // the rate was initially 0 and it remains so now.\n-        return;\n-    }\n-\n-    // We either have something and have pushed an empty slice\n-    // or we have pushed filled slice onto the empty container.\n-    // Still, we need at least 5 samples to start measuring.\n-    m_slices.push_back(slice);\n-\n-    // NOTE: this is also a situation that might have happened\n-    // in the beginning, or after a long period without sending.\n-    // If that period happens, the sending rate is also cleared,\n-    // in any case we need to wait for the minimum samples.\n-    if (m_slices.size() < MIN_SLICES)\n-    {\n-        HLOGC(bslog.Debug, log << \"... NOT MEASURING: still \" << m_slices.size() << \" < 5 slices\");\n-        return;\n-    }\n-\n-    // Keep track of only 10 last slices\n-    if (m_slices.size() > MAX_SLICES)\n-    {\n-        m_slices.pop_front();\n-\n-        // After a slice was removed, there's already a chance\n-        // that all other slices are also 0. Check the minimum\n-        // number of slices + 1 and drop all that are empty\n-        size_t end_range = 0; // default: nothing to delete\n-        for (size_t i = 0; i < m_slices.size(); ++i)\n-        {\n-            if (i > MIN_SLICES + 1)\n-                break;\n-\n-            if (m_slices[i].bytes > 0)\n-                break;\n-\n-            // This can be skipped and check the next one.\n-            end_range = i;\n-        }\n-\n-        // PARANOID\n-        if (end_range >= m_slices.size())\n-            end_range = m_slices.size() - 1; // at least 1 element must stay\n-\n-        m_slices.erase(m_slices.begin(), m_slices.begin() + end_range);\n-\n-        m_beginTime = m_slices[0].begin_time;\n-        HLOGC(bslog.Debug, log << \"... Dropping 1 oldest + \" << end_range << \" empty slices, TS=\" << FormatTime(m_beginTime));\n-    }\n-\n-    // Check also if the begin time is older than 2* period; if so,\n-    // reset it to that value\n-    if (m_slices.size() > 1) // with 1 always m_beginTime = m_slices[0].begin_time\n-    {\n-        clock_time earliest = m_slices[1].begin_time - milliseconds_from(SLICE_INTERVAL_MS*2);\n-        if (m_beginTime < earliest)\n-        {\n-            HLOGC(bslog.Debug, log << \"... BEGIN TIME too old TS=\" << FormatTime(m_beginTime)\n-                    << \" - fixed to \" << FormatTime(earliest));\n-            m_beginTime = earliest;\n-            m_slices[0].begin_time = earliest;\n-        }\n-    }\n-\n-    // Ok, so we have enough samples to record the measurement.\n-    // (so we have at least one)\n-    Summary sum (m_slices[0].begin_time);\n-\n-    for (size_t i = 0; i < m_slices.size(); ++i)\n-    {\n-        sum.consume(m_slices[i]);\n-    }\n-\n-    m_currentPktRate = sum.ratePackets(time);\n-    m_currentByteRate = sum.rateBytes(time, m_SysHeaderSize + CPacket::HDR_SIZE);\n-\n-    HLOGC(bslog.Debug, log << \"... CALCULATED from \" << m_slices.size() << \" slices: total TD=\" << FormatDuration(time - m_slices[0].begin_time)\n-            << \" packets=\" << sum.packets << \" bytes=\" << sum.bytes << \" pkt-rate=\" << m_currentPktRate << \" byte-rate=\" << m_currentByteRate);\n-}\n-#endif\n-\n void srt::CUDT::construct()\n {\n     m_pSndBuffer           = NULL;\n@@ -414,7 +286,6 @@ void srt::CUDT::construct()\n     m_bConnected          = false;\n     m_bClosing            = false;\n     m_bShutdown           = false;\n-    m_bBreaking           = false;\n     m_bBroken             = false;\n     m_bBreakAsUnstable    = false;\n     // TODO: m_iBrokenCounter should be still set to some default.\n@@ -432,13 +303,7 @@ void srt::CUDT::construct()\n     m_bPeerTLPktDrop      = false;\n     m_bBufferWasFull      = false;\n \n-    // Will be updated on first send\n-#ifdef ENABLE_MAXREXMITBW\n-    m_zSndAveragePacketSize = 0;\n-    m_zSndMaxPacketSize = 0;\n-#endif\n-\n-    // Initialize mutex and condition variables.\n+    // Initilize mutex and condition variables.\n     initSynch();\n \n     // TODO: Uncomment when the callback is implemented.\n@@ -448,8 +313,7 @@ void srt::CUDT::construct()\n srt::CUDT::CUDT(CUDTSocket* parent)\n     : m_parent(parent)\n #ifdef ENABLE_MAXREXMITBW\n-    // , m_SndRexmitRate(sync::steady_clock::now())\n-    , m_SndRexmitShaper(CSrtConfig::DEF_MSS)\n+    , m_SndRexmitRate(sync::steady_clock::now())\n #endif\n     , m_iISN(-1)\n     , m_iPeerISN(-1)\n@@ -478,8 +342,7 @@ srt::CUDT::CUDT(CUDTSocket* parent)\n srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor)\n     : m_parent(parent)\n #ifdef ENABLE_MAXREXMITBW\n-    // , m_SndRexmitRate(sync::steady_clock::now())\n-    , m_SndRexmitShaper(CSrtConfig::DEF_MSS)\n+    , m_SndRexmitRate(sync::steady_clock::now())\n #endif\n     , m_iISN(-1)\n     , m_iPeerISN(-1)\n@@ -520,7 +383,7 @@ srt::CUDT::CUDT(CUDTSocket* parent, const CUDT& ancestor)\n \n srt::CUDT::~CUDT()\n {\n-    // release mutex/condition variables\n+    // release mutex/condtion variables\n     destroySynch();\n \n     // destroy the data structures\n@@ -1042,17 +905,17 @@ string srt::CUDT::getstreamid(SRTSOCKET u)\n void srt::CUDT::clearData()\n {\n     const size_t full_hdr_size = CPacket::UDP_HDR_SIZE - CPacket::HDR_SIZE;\n-    m_iMaxDataPayloadSize = m_config.iMSS - full_hdr_size;\n-    HLOGC(cnlog.Debug, log << CONID() << \"clearData: PAYLOAD SIZE: \" << m_iMaxDataPayloadSize);\n+    m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size;\n+    HLOGC(cnlog.Debug, log << CONID() << \"clearData: PAYLOAD SIZE: \" << m_iMaxSRTPayloadSize);\n \n-    m_SndTimeWindow.initialize(full_hdr_size, m_iMaxDataPayloadSize);\n-    m_RcvTimeWindow.initialize(full_hdr_size, m_iMaxDataPayloadSize);\n+    m_SndTimeWindow.initialize(full_hdr_size, m_iMaxSRTPayloadSize);\n+    m_RcvTimeWindow.initialize(full_hdr_size, m_iMaxSRTPayloadSize);\n \n     m_iEXPCount  = 1;\n     m_iBandwidth = 1; // pkts/sec\n     // XXX use some constant for this 16\n     m_iDeliveryRate     = 16;\n-    m_iByteDeliveryRate = 16 * m_iMaxDataPayloadSize;\n+    m_iByteDeliveryRate = 16 * m_iMaxSRTPayloadSize;\n     m_iAckSeqNo         = 0;\n     m_tsLastAckTime     = steady_clock::now();\n \n@@ -1149,6 +1012,8 @@ void srt::CUDT::open()\n \n void srt::CUDT::setListenState()\n {\n+    ScopedLock cg(m_ConnectionLock);\n+\n     if (!m_bOpened)\n         throw CUDTException(MJ_NOTSUP, MN_NONE, 0);\n \n@@ -1156,42 +1021,14 @@ void srt::CUDT::setListenState()\n         throw CUDTException(MJ_NOTSUP, MN_ISCONNECTED, 0);\n \n     // listen can be called more than once\n-    // If two threads call srt_listen at the same time, only\n-    // one will pass this condition; others will be rejected.\n-    // If it was called ever once, none will pass.\n-    for (;;)\n-    {\n-        if (m_bListening.compare_exchange(false, true))\n-        {\n-            // if there is already another socket listening on the same port\n-            if (!m_pRcvQueue->setListener(this))\n-            {\n-                // Failed here, so \n-                m_bListening = false;\n-                throw CUDTException(MJ_NOTSUP, MN_BUSY, 0);\n-            }\n-        }\n-        else\n-        {\n-            // Ok, this thread could have been blocked access,\n-            // but still the other thread that attempted to set\n-            // the listener could have failed. Therefore check\n-            // again if the listener was set successfully, and\n-            // if the listening point is still free, try again.\n-            CUDT* current = m_pRcvQueue->getListener();\n-            if (current == NULL)\n-            {\n-                continue;\n-            }\n-            else if (current != this)\n-            {\n-                // Some other listener already set it\n-                throw CUDTException(MJ_NOTSUP, MN_BUSY, 0);\n-            }\n-            // If it was you who set this, just return with no exception.\n-        }\n-        break;\n-    }\n+    if (m_bListening)\n+        return;\n+\n+    // if there is already another socket listening on the same port\n+    if (m_pRcvQueue->setListener(this) < 0)\n+        throw CUDTException(MJ_NOTSUP, MN_BUSY, 0);\n+\n+    m_bListening = true;\n }\n \n size_t srt::CUDT::fillSrtHandshake(uint32_t *aw_srtdata, size_t srtlen, int msgtype, int hs_version)\n@@ -1628,7 +1465,7 @@ bool srt::CUDT::createSrtHandshake(\n \n     // Once you are certain that the version is HSv5, set the enc type flags\n     // to advertise pbkeylen. Otherwise make sure that the old interpretation\n-    // will correctly pick up the type field. PBKEYLEN should be advertised\n+    // will correctly pick up the type field. PBKEYLEN should be advertized\n     // regardless of what URQ stage the handshake is (note that in case of rendezvous\n     // CONCLUSION might be the FIRST MESSAGE EVER RECEIVED by a party).\n     if (w_hs.m_iVersion > HS_VERSION_UDT4)\n@@ -1784,7 +1621,7 @@ bool srt::CUDT::createSrtHandshake(\n     // it was an abnormal interrupt during the processing so the handshake process should be aborted\n     // anyway, and that's what will be done.\n \n-    // LOCKING INFORMATION: accessing this field just for NULL check doesn't\n+    // LOCKING INFORMATION: accesing this field just for NULL check doesn't\n     // hurt, even if this field could be dangling in the moment. This will be\n     // followed by an additional check, done this time under lock, and there will\n     // be no dangling pointers at this time.\n@@ -1822,7 +1659,7 @@ bool srt::CUDT::createSrtHandshake(\n \n     // Now use the original function to store the actual SRT_HS data\n     // ra_size after that\n-    // NOTE: so far, ra_size is controlPayloadSize() expressed in number of elements.\n+    // NOTE: so far, ra_size is m_iMaxSRTPayloadSize expressed in number of elements.\n     // WILL BE CHANGED HERE.\n     ra_size   = fillSrtHandshake((p + offset), total_ra_size - offset, srths_cmd, HS_VERSION_SRT1);\n     *pcmdspec = HS_CMDSPEC_CMD::wrap(srths_cmd) | HS_CMDSPEC_SIZE::wrap((uint32_t) ra_size);\n@@ -1837,7 +1674,7 @@ bool srt::CUDT::createSrtHandshake(\n         // Now prepare the string with 4-byte alignment. The string size is limited\n         // to half the payload size. Just a sanity check to not pack too much into\n         // the conclusion packet.\n-        size_t size_limit = controlPayloadSize() / 2;\n+        size_t size_limit = m_iMaxSRTPayloadSize / 2;\n \n         if (m_config.sStreamName.size() >= size_limit)\n         {\n@@ -1886,7 +1723,7 @@ bool srt::CUDT::createSrtHandshake(\n #if ENABLE_BONDING\n     // Note that this will fire in both cases:\n     // - When the group has been set by the user on a socket (or socket was created as a part of the group),\n-    //   and the handshake request is to be sent with informing the peer that this connection belongs to a group\n+    //   and the handshake request is to be sent with informing the peer that this conenction belongs to a group\n     // - When the agent received a HS request with a group, has created its mirror group on its side, and\n     //   now sends the HS response to the peer, with ITS OWN group id (the mirror one).\n     //\n@@ -1897,7 +1734,7 @@ bool srt::CUDT::createSrtHandshake(\n     if (have_group)\n     {\n         // NOTE: See information about mutex ordering in api.h\n-        SharedLock gdrg (uglobal().m_GlobControlLock);\n+        ScopedLock gdrg (uglobal().m_GlobControlLock);\n         if (!m_parent->m_GroupOf)\n         {\n             // This may only happen if since last check of m_GroupOf pointer the socket was removed\n@@ -2184,10 +2021,8 @@ bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)\n         {\n             uint32_t srtdata_out[SRTDATA_MAXSIZE];\n             size_t   len_out = 0;\n-\n             res = m_pCryptoControl->processSrtMsg_KMREQ(srtdata, len, CUDT::HS_VERSION_UDT4, m_uPeerSrtVersion,\n-                        (srtdata_out), (len_out));\n-\n+                    (srtdata_out), (len_out));\n             if (res == SRT_CMD_KMRSP)\n             {\n                 if (len_out == 1)\n@@ -2210,11 +2045,11 @@ bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)\n                 }\n                 sendSrtMsg(SRT_CMD_KMRSP, srtdata_out, len_out);\n             }\n-            // NOTE: processSrtMsg_KMREQ doesn't return any other value now.\n-            // But this may be a result of the size check EPE.\n+            // XXX Dead code. processSrtMsg_KMREQ now doesn't return any other value now.\n+            // Please review later.\n             else\n             {\n-                LOGC(cnlog.Warn, log << CONID() << \"EPE: KMREQ failed to process the request - ignoring\");\n+                LOGC(cnlog.Warn, log << CONID() << \"KMREQ failed to process the request - ignoring\");\n             }\n \n             return true; // already done what's necessary\n@@ -2223,7 +2058,7 @@ bool srt::CUDT::processSrtMsg(const CPacket *ctrlpkt)\n     case SRT_CMD_KMRSP:\n     {\n         // KMRSP doesn't expect any following action\n-        m_pCryptoControl->processSrtMsg_KMRSP(srtdata, len, m_uPeerSrtVersion, false);\n+        m_pCryptoControl->processSrtMsg_KMRSP(srtdata, len, m_uPeerSrtVersion);\n         return true; // nothing to do\n     }\n \n@@ -2628,7 +2463,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             m_RejectReason = SRT_REJ_VERSION;\n             // This means that a version with minimum 1.3.0 that features HSv5 is required,\n             // hence all HSv4 clients should be rejected.\n-            LOGP(cnlog.Error, string(FUNID()) + \": minimum peer version 1.3.0 (HSv5 only), rejecting HSv4 client\");\n+            LOGP(cnlog.Error, \"interpretSrtHandshake: minimum peer version 1.3.0 (HSv5 only), rejecting HSv4 client\");\n             return false;\n         }\n         return true; // do nothing\n@@ -2666,7 +2501,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n \n     if (IsSet(ext_flags, CHandShake::HS_EXT_HSREQ))\n     {\n-        HLOGC(cnlog.Debug, log << CONID() << FUNID() << \": extracting HSREQ/RSP type extension\");\n+        HLOGC(cnlog.Debug, log << CONID() << \"interpretSrtHandshake: extracting HSREQ/RSP type extension\");\n         uint32_t *begin    = p;\n         uint32_t *next     = 0;\n         size_t    length   = size / sizeof(uint32_t);\n@@ -2698,7 +2533,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                 {\n                     // m_RejectReason already set\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": process HSREQ returned unexpected value \" << rescmd);\n+                         log << CONID() << \"interpretSrtHandshake: process HSREQ returned unexpected value \" << rescmd);\n                     return false;\n                 }\n                 handshakeDone();\n@@ -2729,7 +2564,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                     if (m_RejectReason == SRT_REJ_UNKNOWN)\n                         m_RejectReason = SRT_REJ_ROGUE;\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": process HSRSP returned unexpected value \" << rescmd);\n+                         log << CONID() << \"interpretSrtHandshake: process HSRSP returned unexpected value \" << rescmd);\n                     return false;\n                 }\n                 handshakeDone();\n@@ -2739,7 +2574,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             {\n                 m_RejectReason = SRT_REJ_ROGUE;\n                 LOGC(cnlog.Warn,\n-                     log << CONID() << FUNID() << \": no HSREQ/HSRSP block found in the handshake msg!\");\n+                     log << CONID() << \"interpretSrtHandshake: no HSREQ/HSRSP block found in the handshake msg!\");\n                 // This means that there can be no more processing done by FindExtensionBlock().\n                 // And we haven't found what we need - otherwise one of the above cases would pass\n                 // and lead to exit this loop immediately.\n@@ -2758,7 +2593,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n         }\n     }\n \n-    HLOGC(cnlog.Debug, log << CONID() << FUNID() << \": HSREQ done, checking KMREQ\");\n+    HLOGC(cnlog.Debug, log << CONID() << \"interpretSrtHandshake: HSREQ done, checking KMREQ\");\n \n     // Now check the encrypted\n \n@@ -2766,7 +2601,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n \n     if (IsSet(ext_flags, CHandShake::HS_EXT_KMREQ))\n     {\n-        HLOGC(cnlog.Debug, log << CONID() << FUNID() << \": extracting KMREQ/RSP type extension\");\n+        HLOGC(cnlog.Debug, log << CONID() << \"interpretSrtHandshake: extracting KMREQ/RSP type extension\");\n \n #ifdef SRT_ENABLE_ENCRYPTION\n         if (!m_pCryptoControl->hasPassphrase())\n@@ -2799,7 +2634,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             int cmd = FindExtensionBlock(begin, length, (blocklen), (next));\n \n             HLOGC(cnlog.Debug,\n-                  log << CONID() << FUNID() << \": found extension: (\" << cmd << \") \"\n+                  log << CONID() << \"interpretSrtHandshake: found extension: (\" << cmd << \") \"\n                       << MessageTypeStr(UMSG_EXT, cmd));\n \n             size_t bytelen = blocklen * sizeof(uint32_t);\n@@ -2819,7 +2654,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                     m_RejectReason = SRT_REJ_IPE;\n                     // Something went wrong.\n                     HLOGC(cnlog.Debug,\n-                          log << CONID() << FUNID() << \": IPE/EPE KMREQ processing failed - returned \"\n+                          log << CONID() << \"interpretSrtHandshake: IPE/EPE KMREQ processing failed - returned \"\n                               << res);\n                     return false;\n                 }\n@@ -2832,7 +2667,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                         m_RejectReason = SRT_REJ_CRYPTO;\n                         LOGC(cnlog.Error,\n                              log << CONID()\n-                                 << FUNID() << \": KMREQ result: Bad crypto mode - rejecting\");\n+                                 << \"interpretSrtHandshake: KMREQ result: Bad crypto mode - rejecting\");\n                         return false;\n                     }\n #endif\n@@ -2851,7 +2686,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                         }\n                         LOGC(cnlog.Error,\n                              log << CONID()\n-                                 << FUNID() << \": KMREQ result abnornal - rejecting per enforced encryption\");\n+                                 << \"interpretSrtHandshake: KMREQ result abnornal - rejecting per enforced encryption\");\n                         return false;\n                     }\n                 }\n@@ -2859,12 +2694,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             }\n             else if (cmd == SRT_CMD_KMRSP)\n             {\n-                // Normally this is a handshake, but this one can be also called through\n-                // the in-connected dispatcher and processCtrlHS(). The is_handshake can be\n-                // still potentially set back to true inside when the KMX was detected as\n-                // not done for the sake of HSv4.\n-                bool is_handshake = m_parent->m_Status != SRTS_CONNECTED;\n-                int res = m_pCryptoControl->processSrtMsg_KMRSP(begin + 1, bytelen, m_uPeerSrtVersion, is_handshake);\n+                int res = m_pCryptoControl->processSrtMsg_KMRSP(begin + 1, bytelen, m_uPeerSrtVersion);\n                 if (m_config.bEnforcedEnc && res == -1)\n                 {\n                     if (m_pCryptoControl->m_SndKmState == SRT_KM_S_BADSECRET)\n@@ -2889,7 +2719,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             }\n             else\n             {\n-                HLOGC(cnlog.Debug, log << CONID() << FUNID() << \": ... skipping \" << MessageTypeStr(UMSG_EXT, cmd));\n+                HLOGC(cnlog.Debug, log << CONID() << \"interpretSrtHandshake: ... skipping \" << MessageTypeStr(UMSG_EXT, cmd));\n                 if (NextExtensionBlock((begin), next, (length)))\n                     continue;\n             }\n@@ -2931,7 +2761,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n \n     if (IsSet(ext_flags, CHandShake::HS_EXT_CONFIG))\n     {\n-        HLOGC(cnlog.Debug, log << CONID() << FUNID() << \": extracting various CONFIG extensions\");\n+        HLOGC(cnlog.Debug, log << CONID() << \"interpretSrtHandshake: extracting various CONFIG extensions\");\n \n         uint32_t *begin    = p;\n         uint32_t *next     = 0;\n@@ -2943,7 +2773,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             int cmd = FindExtensionBlock(begin, length, (blocklen), (next));\n \n             HLOGC(cnlog.Debug,\n-                  log << CONID() << FUNID() << \": found extension: (\" << cmd << \") \"\n+                  log << CONID() << \"interpretSrtHandshake: found extension: (\" << cmd << \") \"\n                       << MessageTypeStr(UMSG_EXT, cmd));\n \n             const size_t bytelen = blocklen * sizeof(uint32_t);\n@@ -2952,7 +2782,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                 if (!bytelen || bytelen > CSrtConfig::MAX_SID_LENGTH)\n                 {\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": STREAMID length \" << bytelen << \" is 0 or > \"\n+                         log << CONID() << \"interpretSrtHandshake: STREAMID length \" << bytelen << \" is 0 or > \"\n                              << +CSrtConfig::MAX_SID_LENGTH << \" - PROTOCOL ERROR, REJECTING\");\n                     return false;\n                 }\n@@ -3002,7 +2832,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                 if (!bytelen || bytelen > CSrtConfig::MAX_CONG_LENGTH)\n                 {\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": CONGESTION-control type length \" << bytelen\n+                         log << CONID() << \"interpretSrtHandshake: CONGESTION-control type length \" << bytelen\n                              << \" is 0 or > \" << +CSrtConfig::MAX_CONG_LENGTH << \" - PROTOCOL ERROR, REJECTING\");\n                     return false;\n                 }\n@@ -3045,7 +2875,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                 if (!bytelen || bytelen > CSrtConfig::MAX_PFILTER_LENGTH)\n                 {\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": packet-filter type length \" << bytelen\n+                         log << CONID() << \"interpretSrtHandshake: packet-filter type length \" << bytelen\n                              << \" is 0 or > \" << +CSrtConfig::MAX_PFILTER_LENGTH << \" - PROTOCOL ERROR, REJECTING\");\n                     return false;\n                 }\n@@ -3087,10 +2917,9 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n                     LOGC(cnlog.Error, log << CONID() << \"PEER'S GROUP wrong size: \" << (bytelen/GRPD_FIELD_SIZE));\n                     return false;\n                 }\n-                size_t used_bytelen = std::min(bytelen, sizeof(groupdata));\n-                size_t groupdata_size = used_bytelen / GRPD_FIELD_SIZE;\n+                size_t groupdata_size = bytelen / GRPD_FIELD_SIZE;\n \n-                memcpy(groupdata, begin+1, used_bytelen);\n+                memcpy(groupdata, begin+1, bytelen);\n                 if (!interpretGroup(groupdata, groupdata_size, hsreq_type_cmd) )\n                 {\n                     // m_RejectReason handled inside interpretGroup().\n@@ -3111,7 +2940,7 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n             {\n                 // Found some block that is not interesting here. Skip this and get the next one.\n                 HLOGC(cnlog.Debug,\n-                      log << CONID() << FUNID() << \": ... skipping \" << MessageTypeStr(UMSG_EXT, cmd));\n+                      log << CONID() << \"interpretSrtHandshake: ... skipping \" << MessageTypeStr(UMSG_EXT, cmd));\n             }\n \n             if (!NextExtensionBlock((begin), next, (length)))\n@@ -3156,34 +2985,6 @@ bool srt::CUDT::interpretSrtHandshake(const CHandShake& hs,\n         return false;\n     }\n \n-    // Check if the filter was configured on agent,\n-    // but the peer responded with no filter.\n-    if (!m_config.sPacketFilterConfig.empty() && !have_filter)\n-    {\n-        if (m_SrtHsSide == HSD_INITIATOR)\n-        {\n-            // IMPORTANT:\n-            // If agent didn't set the packet filter in the configuration, the peer\n-            // could have responded with its own configuration and enforce the packet filter\n-            // setting here locally. In this case the sPacketFilterConfig will not be empty\n-            // at the moment, even if it was empty initially.\n-\n-            // The situation caught here is that the configuration for packet filter was set,\n-            // but the peer responded as if it didn't understand it, or simply didn't accept it.\n-            // In such a situation the configuration should be rejected because if the\n-            // peer doesn't support packet filter, the caller side should not have set it.\n-            m_RejectReason = SRT_REJ_FILTER;\n-            LOGC(cnlog.Error, log << CONID()\n-                    << \"HS EXT: Agent has configured packetfilter, but peer didn't respond.\");\n-            return false;\n-        }\n-\n-        // Responder: we are the listener that has configured packetfilter,\n-        // but the caller didn't request packetfilter.\n-        m_config.sPacketFilterConfig.set(\"\");\n-        LOGC(cnlog.Warn, log << CONID() << \"HS EXT: Agent has configured packetfilter, but peer didn't request it\");\n-    }\n-\n #if ENABLE_BONDING\n     // m_GroupOf and locking info: NULL check won't hurt here. If the group\n     // was deleted in the meantime, it will be found out later anyway and result with error.\n@@ -3359,19 +3160,10 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A\n         return false;\n     }\n \n+    ScopedLock guard_group_existence (uglobal().m_GlobControlLock);\n+\n     if (m_SrtHsSide == HSD_INITIATOR)\n     {\n-        // Here we'll be only using a pre-existing group, so shared is enough.\n-        SharedLock guard_group_existence (uglobal().m_GlobControlLock);\n-\n-        // Recheck broken flags after acquisition\n-        if (m_bClosing || m_bBroken)\n-        {\n-            m_RejectReason = SRT_REJ_CLOSE;\n-            LOGC(cnlog.Error, log << CONID() << \"interpretGroup: closure during handshake, interrupting\");\n-            return false;\n-        }\n-\n         // This is a connection initiator that has requested the peer to make a\n         // mirror group and join it, then respond its mirror group id. The\n         // `grpid` variable contains this group ID; map this as your peer\n@@ -3390,81 +3182,64 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A\n             return false;\n         }\n \n-        {\n-            // XXX Consider moving this to another function to avoid\n-            // exposing group lock.\n-\n-            // Group existence is guarded, so we can now lock the group as well.\n-            ScopedLock gl(*pg->exp_groupLock());\n+        // Group existence is guarded, so we can now lock the group as well.\n+        ScopedLock gl(*pg->exp_groupLock());\n \n-            // Now we know the group exists, but it might still be closed\n-            if (pg->closing())\n-            {\n-                LOGC(cnlog.Error, log << CONID() << \"HS/RSP: group was closed in the process, can't continue connecting\");\n-                m_RejectReason = SRT_REJ_IPE;\n-                return false;\n-            }\n+        // Now we know the group exists, but it might still be closed\n+        if (pg->closing())\n+        {\n+            LOGC(cnlog.Error, log << CONID() << \"HS/RSP: group was closed in the process, can't continue connecting\");\n+            m_RejectReason = SRT_REJ_IPE;\n+            return false;\n+        }\n \n-            SRTSOCKET peer = pg->peerid();\n-            if (peer == SRT_INVALID_SOCK)\n-            {\n-                // This is the first connection within this group, so this group\n-                // has just been informed about the peer membership. Accept it.\n-                pg->set_peerid(grpid);\n-                HLOGC(cnlog.Debug,\n-                        log << CONID() << \"HS/RSP: group $\" << pg->id() << \" -> peer $\" << pg->peerid()\n-                        << \", copying characteristic data\");\n+        SRTSOCKET peer = pg->peerid();\n+        if (peer == -1)\n+        {\n+            // This is the first connection within this group, so this group\n+            // has just been informed about the peer membership. Accept it.\n+            pg->set_peerid(grpid);\n+            HLOGC(cnlog.Debug,\n+                  log << CONID() << \"HS/RSP: group $\" << pg->id() << \" -> peer $\" << pg->peerid()\n+                      << \", copying characteristic data\");\n \n-                // The call to syncWithSocket is copying\n-                // some interesting data from the first connected\n-                // socket. This should be only done for the first successful connection.\n-                pg->syncWithSocket(*this, HSD_INITIATOR);\n-            }\n-            // Otherwise the peer id must be the same as existing, otherwise\n-            // this group is considered already bound to another peer group.\n-            // (Note that the peer group is peer-specific, and peer id numbers\n-            // may repeat among sockets connected to groups established on\n-            // different peers).\n-            else if (peer != grpid)\n-            {\n-                LOGC(cnlog.Error,\n-                        log << CONID() << \"IPE: HS/RSP: group membership responded for peer $\" << grpid\n-                        << \" but the current socket's group $\" << pg->id() << \" has already a peer $\" << peer);\n-                m_RejectReason = SRT_REJ_GROUP;\n-                return false;\n-            }\n-            else\n-            {\n-                HLOGC(cnlog.Debug,\n-                        log << CONID() << \"HS/RSP: group $\" << pg->id() << \" ALREADY MAPPED to peer mirror $\"\n-                        << pg->peerid());\n-            }\n+            // The call to syncWithSocket is copying\n+            // some interesting data from the first connected\n+            // socket. This should be only done for the first successful connection.\n+            pg->syncWithSocket(*this, HSD_INITIATOR);\n         }\n-        m_parent->m_GroupOf->debugGroup();\n-    }\n-    else\n-    {\n-        // Here we'll be potentially creating a new group, hence exclusive is needed.\n-        ExclusiveLock guard_group_existence (uglobal().m_GlobControlLock);\n-\n-        // Recheck broken flags after acquisition\n-        if (m_bClosing || m_bBroken)\n+        // Otherwise the peer id must be the same as existing, otherwise\n+        // this group is considered already bound to another peer group.\n+        // (Note that the peer group is peer-specific, and peer id numbers\n+        // may repeat among sockets connected to groups established on\n+        // different peers).\n+        else if (peer != grpid)\n         {\n-            m_RejectReason = SRT_REJ_CLOSE;\n-            LOGC(cnlog.Error, log << CONID() << \"interpretGroup: closure during handshake, interrupting\");\n+            LOGC(cnlog.Error,\n+                 log << CONID() << \"IPE: HS/RSP: group membership responded for peer $\" << grpid\n+                     << \" but the current socket's group $\" << pg->id() << \" has already a peer $\" << peer);\n+            m_RejectReason = SRT_REJ_GROUP;\n             return false;\n         }\n-\n+        else\n+        {\n+            HLOGC(cnlog.Debug,\n+                  log << CONID() << \"HS/RSP: group $\" << pg->id() << \" ALREADY MAPPED to peer mirror $\"\n+                      << pg->peerid());\n+        }\n+    }\n+    else\n+    {\n         // This is a connection responder that has been requested to make a\n         // mirror group and join it. Later on, the HS response will be sent\n         // and its group ID will be added to the HS extensions as mirror group\n         // ID to the peer.\n \n         SRTSOCKET lgid = makeMePeerOf(grpid, gtp, link_flags);\n-        if (lgid == 0)\n+        if (!lgid)\n             return true; // already done\n \n-        if (lgid == SRT_INVALID_SOCK)\n+        if (lgid == -1)\n         {\n             // NOTE: This error currently isn't reported by makeMePeerOf,\n             // so this is left to handle a possible error introduced in future.\n@@ -3485,9 +3260,10 @@ bool srt::CUDT::interpretGroup(const int32_t groupdata[], size_t data_size SRT_A\n         f->weight = link_weight;\n         f->agent = m_parent->m_SelfAddr;\n         f->peer = m_PeerAddr;\n-        m_parent->m_GroupOf->debugGroup();\n     }\n \n+    m_parent->m_GroupOf->debugGroup();\n+\n     // That's all. For specific things concerning group\n     // types, this will be later.\n     return true;\n@@ -3797,8 +3573,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n     // Inform the server my configurations.\n     CPacket reqpkt;\n     reqpkt.setControl(UMSG_HANDSHAKE);\n-    size_t hs_size = controlPayloadSize(serv_addr.family());\n-    reqpkt.allocate(hs_size);\n+    reqpkt.allocate(m_iMaxSRTPayloadSize);\n     // XXX NOTE: Now the memory for the payload part is allocated automatically,\n     // and such allocated memory is also automatically deallocated in the\n     // destructor. If you use CPacket::allocate, remember that you must not:\n@@ -3813,6 +3588,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n     // ID = 0, connection request\n     reqpkt.set_id(0);\n \n+    size_t hs_size = m_iMaxSRTPayloadSize;\n     m_ConnReq.store_to((reqpkt.m_pcData), (hs_size));\n \n     // Note that CPacket::allocate() sets also the size\n@@ -3869,7 +3645,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n     // next incoming packet.\n     CPacket response;\n     response.setControl(UMSG_HANDSHAKE);\n-    response.allocate(controlPayloadSize(serv_addr.family()));\n+    response.allocate(m_iMaxSRTPayloadSize);\n \n     CUDTException  e;\n     EConnectStatus cst = CONN_CONTINUE;\n@@ -3877,7 +3653,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n     // We can't record this address yet until the cookie-confirmation is done, for safety reasons.\n     sockaddr_any use_source_adr(serv_addr.family());\n \n-    while (!m_bClosing && !m_bBreaking)\n+    while (!m_bClosing)\n     {\n         const steady_clock::time_point local_tnow = steady_clock::now();\n         const steady_clock::duration tdiff = local_tnow - m_tsLastReqTime.load();\n@@ -3921,7 +3697,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n         }\n \n         cst = CONN_CONTINUE;\n-        response.setLength(controlPayloadSize(serv_addr.family()));\n+        response.setLength(m_iMaxSRTPayloadSize);\n         if (m_pRcvQueue->recvfrom(m_SocketID, (response)) > 0)\n         {\n             use_source_adr = response.udpDestAddr();\n@@ -3974,7 +3750,7 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n                         m_RejectReason = SRT_REJ_ROGUE;\n \n                     // rejection or erroneous code.\n-                    reqpkt.setLength(controlPayloadSize(serv_addr.family()));\n+                    reqpkt.setLength(m_iMaxSRTPayloadSize);\n                     reqpkt.setControl(UMSG_HANDSHAKE);\n                     sendRendezvousRejection(serv_addr, (reqpkt));\n                 }\n@@ -4002,12 +3778,12 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n             // Now serialize the handshake again to the existing buffer so that it's\n             // then sent later in this loop.\n \n-            // First, set the size back to the original size, controlPayloadSize() because\n+            // First, set the size back to the original size, m_iMaxSRTPayloadSize because\n             // this is the size of the originally allocated space. It might have been\n             // shrunk by serializing the INDUCTION handshake (which was required before\n             // sending this packet to the output queue) and therefore be too\n             // small to store the CONCLUSION handshake (with HSv5 extensions).\n-            reqpkt.setLength(controlPayloadSize(serv_addr.family()));\n+            reqpkt.setLength(m_iMaxSRTPayloadSize);\n \n             HLOGC(cnlog.Debug,\n                   log << CONID() << \"startConnect: creating HS CONCLUSION: buffer size=\" << reqpkt.getLength());\n@@ -4075,14 +3851,14 @@ void srt::CUDT::startConnect(const sockaddr_any& serv_addr, int32_t forced_isn)\n \n     if (e.getErrorCode() == 0)\n     {\n-        if (m_bClosing || m_bBreaking)                     // if the socket is closed before connection...\n+        if (m_bClosing)                                    // if the socket is closed before connection...\n             e = CUDTException(MJ_SETUP, MN_CLOSED, 0);\n         else if (m_ConnRes.m_iReqType > URQ_FAILURE_TYPES) // connection request rejected\n         {\n             m_RejectReason = RejectReasonForURQ(m_ConnRes.m_iReqType);\n             e              = CUDTException(MJ_SETUP, MN_REJECTED, 0);\n         }\n-        else if ((!m_config.bRendezvous) && (m_ConnRes.m_iISN != m_iISN)) // security check\n+        else if ((!m_config.bRendezvous) && (m_ConnRes.m_iISN != m_iISN)) // secuity check\n             e = CUDTException(MJ_SETUP, MN_SECURITY, 0);\n     }\n \n@@ -4137,7 +3913,7 @@ bool srt::CUDT::processAsyncConnectRequest(EReadStatus         rst,\n \n     CPacket reqpkt;\n     reqpkt.setControl(UMSG_HANDSHAKE);\n-    reqpkt.allocate(controlPayloadSize(serv_addr.family()));\n+    reqpkt.allocate(m_iMaxSRTPayloadSize);\n     const steady_clock::time_point now = steady_clock::now();\n     setPacketTS(reqpkt, now);\n \n@@ -4247,69 +4023,65 @@ void srt::CUDT::sendRendezvousRejection(const sockaddr_any& serv_addr, CPacket&\n     m_pSndQueue->sendto(serv_addr, r_rsppkt, m_SourceAddr);\n }\n \n-enum HandshakeSide srt::CUDT::compareCookies(int32_t req, int32_t res)\n+void srt::CUDT::cookieContest()\n {\n-    if (req < res)\n-    {\n-        LOGC(gglog.Note, log << hex << setfill('0') << uppercase\n-                << \"REQ: \" << setw(8) << req\n-                << \" RES: \" << setw(8) << res << \" - result: RESPONDER\");\n-        return HSD_RESPONDER;\n-    }\n-    else if (req > res)\n+    if (m_SrtHsSide != HSD_DRAW)\n+        return;\n+\n+    LOGC(cnlog.Debug,\n+         log << CONID() << \"cookieContest: agent=\" << m_ConnReq.m_iCookie << \" peer=\" << m_ConnRes.m_iCookie);\n+\n+    // Here m_ConnReq.m_iCookie is a local cookie value sent in connection request to the peer.\n+    // m_ConnRes.m_iCookie is a cookie value sent by the peer in its connection request.\n+    if (m_ConnReq.m_iCookie == 0 || m_ConnRes.m_iCookie == 0)\n     {\n-        LOGC(gglog.Note, log << hex << setfill('0') << uppercase\n-                << \"REQ: \" << setw(8) << req\n-                << \" RES: \" << setw(8) << res << \" - result: INITIATOR\");\n-        return HSD_INITIATOR;\n+        // Note that it's virtually impossible that Agent's cookie is not ready, this\n+        // shall be considered IPE.\n+        // Not all cookies are ready, don't start the contest.\n+        return;\n     }\n-    return HSD_DRAW;\n-}\n-\n-enum HandshakeSide srt::CUDT::backwardCompatibleCookieContest(int32_t req, int32_t res)\n-{\n-    const int64_t xreq = int64_t(req);\n-    const int64_t xres = int64_t(res);\n-    const int64_t contest = xreq - xres;\n \n-    LOGC(cnlog.Debug, log << \"cookieContest: agent=\" << req\n-                          << \" peer=\" << res\n-                          << hex << uppercase << setfill('0') // PERSISTENT flags\n-                          << \" X64: \"<< setw(16) << xreq\n-                          << \" vs. \" << setw(16) << xres\n-                          << \" DIFF: \" << setw(16) << contest);\n+    // INITIATOR/RESPONDER role is resolved by COOKIE CONTEST.\n+    //\n+    // The cookie contest must be repeated every time because it\n+    // may change the state at some point.\n+    // \n+    // In SRT v1.4.3 and prior the below subtraction was performed in 32-bit arithmetic.\n+    // The result of subtraction can overflow 32-bits. \n+    // Example\n+    // m_ConnReq.m_iCookie = -1480577720;\n+    // m_ConnRes.m_iCookie = 811599203;\n+    // int64_t llBetterCookie = -1480577720 - 811599203 = -2292176923 (FFFF FFFF 7760 27E5);\n+    // int32_t iBetterCookie  = 2002790373 (7760 27E5);\n+    // \n+    // Now 64-bit arithmetic is used to calculate the actual result of subtraction.\n+    // The 31-st bit is then checked to check if the resulting is negative in 32-bit aritmetics.\n+    // This way the old contest behavior is preserved, and potential compiler optimisations are avoided.\n+    const int64_t contest = int64_t(m_ConnReq.m_iCookie) - int64_t(m_ConnRes.m_iCookie);\n \n     if ((contest & 0xFFFFFFFF) == 0)\n     {\n-        return HSD_DRAW;\n-    }\n-    if (contest & 0x80000000)\n-    {\n-        const int64_t revert = xres - xreq;\n-        if (revert & 0x80000000 && req > res)\n-            return HSD_INITIATOR;\n-        return HSD_RESPONDER;\n-    }\n+        // DRAW! The only way to continue would be to force the\n+        // cookies to be regenerated and to start over. But it's\n+        // not worth a shot - this is an extremely rare case.\n+        // This can simply do reject so that it can be started again.\n \n-    return HSD_INITIATOR;\n-}\n+        // Pretend then that the cookie contest wasn't done so that\n+        // it's done again. Cookies are baked every time anew, however\n+        // the successful initial contest remains valid no matter how\n+        // cookies will change.\n \n-void srt::CUDT::cookieContest()\n-{\n-    if (m_SrtHsSide != HSD_DRAW)\n+        m_SrtHsSide = HSD_DRAW;\n         return;\n+    }\n \n-    // Here m_ConnReq.m_iCookie is a local cookie value sent in connection request to the peer.\n-    // m_ConnRes.m_iCookie is a cookie value sent by the peer in its connection request.\n-    if (m_ConnReq.m_iCookie == 0 || m_ConnRes.m_iCookie == 0)\n+    if (contest & 0x80000000)\n     {\n-        LOGC(cnlog.Debug, log << CONID() << \"cookieContest: agent=\" << m_ConnReq.m_iCookie << \" peer=\" << m_ConnRes.m_iCookie\n-                              << \" - ERROR: zero not allowed!\");\n-\n+        m_SrtHsSide = HSD_RESPONDER;\n         return;\n     }\n-    m_SrtHsSide = backwardCompatibleCookieContest(m_ConnReq.m_iCookie, m_ConnRes.m_iCookie);\n \n+    m_SrtHsSide = HSD_INITIATOR;\n }\n \n // This function should complete the data for KMX needed for an out-of-band\n@@ -4455,7 +4227,7 @@ EConnectStatus srt::CUDT::processRendezvous(\n     m_ConnReq.m_iReqType  = rsp_type;\n     m_ConnReq.m_extension = needs_extension;\n \n-    // This must be done before prepareConnectionObjects(), because it sets ISN needed to create buffers.\n+    // This must be done before prepareConnectionObjects(), because it sets ISN and m_iMaxSRTPayloadSize needed to create buffers.\n     if (!applyResponseSettings(pResponse))\n     {\n         LOGC(cnlog.Error, log << CONID() << \"processRendezvous: peer settings rejected\");\n@@ -4519,7 +4291,7 @@ EConnectStatus srt::CUDT::processRendezvous(\n               log << CONID()\n                   << \"processRendezvous: HSREQ extension ok, creating HSRSP response. kmdatasize=\" << kmdatasize);\n \n-        w_reqpkt.setLength(controlPayloadSize(serv_addr.family()));\n+        w_reqpkt.setLength(m_iMaxSRTPayloadSize);\n         if (!createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP,\n                     kmdata, kmdatasize,\n                     (w_reqpkt), (m_ConnReq)))\n@@ -4551,7 +4323,7 @@ EConnectStatus srt::CUDT::processRendezvous(\n             HLOGC(\n                 cnlog.Debug,\n                 log << CONID()\n-                    << \"processRendezvous: no INCOMING packet, NOT interpreting extensions (relying on existing data)\");\n+                    << \"processRendezvous: no INCOMING packet, NOT interpreting extensions (relying on exising data)\");\n         }\n         else\n         {\n@@ -4596,7 +4368,7 @@ EConnectStatus srt::CUDT::processRendezvous(\n     // serialization.\n     m_ConnReq.m_extension = needs_extension;\n \n-    w_reqpkt.setLength(controlPayloadSize(serv_addr.family()));\n+    w_reqpkt.setLength(m_iMaxSRTPayloadSize);\n     if (m_RdvState == CHandShake::RDV_CONNECTED)\n     {\n         int cst = postConnect(pResponse, true, 0);\n@@ -4666,7 +4438,7 @@ EConnectStatus srt::CUDT::processRendezvous(\n         // the request time must be updated so that the next handshake can be sent out immediately\n         HLOGC(cnlog.Debug,\n               log << \"processRendezvous: rsp=\" << RequestTypeStr(m_ConnReq.m_iReqType)\n-                  << \" REQ-TIME: LOW to send immediately, consider yourself connected\");\n+                  << \" REQ-TIME: LOW to send immediately, consider yourself conencted\");\n         m_tsLastReqTime = steady_clock::time_point();\n     }\n     else\n@@ -4939,24 +4711,6 @@ EConnectStatus srt::CUDT::processConnectResponse(const CPacket& response, CUDTEx\n     return postConnect(&response, false, eout);\n }\n \n-static size_t MinimumMSS(int family)\n-{\n-    const size_t full_hdr_size = CPacket::UDP_HDR_SIZE + CPacket::HDR_SIZE;\n-    const size_t full_hdr_size_i6 = CPacket::UDP_HDR_SIZE_IPv6 + CPacket::HDR_SIZE;\n-\n-    size_t min_mss_size = 4; // initial: required for passing any data\n-    if (family == AF_INET6)\n-    {\n-        min_mss_size += full_hdr_size_i6;\n-    }\n-    else\n-    {\n-        min_mss_size += full_hdr_size;\n-    }\n-\n-    return min_mss_size;\n-}\n-\n bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) ATR_NOEXCEPT\n {\n     if (!m_ConnRes.valid())\n@@ -4970,10 +4724,12 @@ bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) AT\n     m_config.iMSS        = m_ConnRes.m_iMSS;\n \n     const size_t full_hdr_size = CPacket::UDP_HDR_SIZE + CPacket::HDR_SIZE;\n-    m_iMaxDataPayloadSize = m_config.iMSS - full_hdr_size;\n-    HLOGC(cnlog.Debug, log << CONID() << \"applyResponseSettings: PAYLOAD SIZE: \" << m_iMaxDataPayloadSize);\n+    m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size;\n+    HLOGC(cnlog.Debug, log << CONID() << \"applyResponseSettings: PAYLOAD SIZE: \" << m_iMaxSRTPayloadSize);\n \n     m_iFlowWindowSize    = m_ConnRes.m_iFlightFlagSize;\n+    const int udpsize    = m_config.iMSS - CPacket::UDP_HDR_SIZE;\n+    m_iMaxSRTPayloadSize = udpsize - CPacket::HDR_SIZE;\n     m_iPeerISN           = m_ConnRes.m_iISN;\n \n     setInitialRcvSeq(m_iPeerISN);\n@@ -4985,7 +4741,7 @@ bool srt::CUDT::applyResponseSettings(const CPacket* pHspkt /*[[nullable]]*/) AT\n         m_SourceAddr = pHspkt->udpDestAddr();\n \n     HLOGC(cnlog.Debug,\n-          log << CONID() << \"applyResponseSettings: HANDSHAKE CONCLUDED. SETTING: payload-size=\" << m_iMaxDataPayloadSize\n+          log << CONID() << \"applyResponseSettings: HANSHAKE CONCLUDED. SETTING: payload-size=\" << m_iMaxSRTPayloadSize\n               << \" mss=\" << m_ConnRes.m_iMSS << \" flw=\" << m_ConnRes.m_iFlightFlagSize << \" peer-ISN=\" << m_ConnRes.m_iISN\n               << \" local-ISN=\" << m_iISN\n               << \" peerID=\" << m_ConnRes.m_iID\n@@ -5059,7 +4815,7 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous,\n \n     {\n #if ENABLE_BONDING\n-        SharedLock cl (uglobal().m_GlobControlLock);\n+        ScopedLock cl (uglobal().m_GlobControlLock);\n         CUDTGroup* g = m_parent->m_GroupOf;\n         if (g)\n         {\n@@ -5166,11 +4922,10 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous,\n     //int token = -1;\n #if ENABLE_BONDING\n     {\n-        SharedLock cl (uglobal().m_GlobControlLock);\n+        ScopedLock cl (uglobal().m_GlobControlLock);\n         CUDTGroup* g = m_parent->m_GroupOf;\n         if (g)\n         {\n-            ScopedLock gl (*g->exp_groupLock());\n             // XXX this might require another check of group type.\n             // For redundancy group, at least, update the status in the group.\n \n@@ -5196,11 +4951,6 @@ EConnectStatus srt::CUDT::postConnect(const CPacket* pResponse, bool rendezvous,\n     s->m_Status = SRTS_CONNECTED;\n \n     // acknowledde any waiting epolls to write\n-    // This must be done AFTER the group member status is upgraded to IDLE because\n-    // this state change will trigger the waiting function in blocking-mode groupConnect\n-    // and this may be immediately followed by exit from connect and start sending function,\n-    // which must see this very link already as IDLE, not PENDING, which will make this\n-    // link unable to be used and therefore the sending call would fail.\n     uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_CONNECT, true);\n \n     CGlobEvent::triggerEvent();\n@@ -5791,12 +5541,6 @@ void * srt::CUDT::tsbpd(void* param)\n                     gkeeper.group->updateLatestRcv(self->m_parent);\n                 }\n             }\n-\n-            // After re-acquisition of the m_RecvLock, re-check the closing flag\n-            if (self->m_bClosing)\n-            {\n-                break;\n-            }\n #endif\n             CGlobEvent::triggerEvent();\n             tsNextDelivery = steady_clock::time_point(); // Ready to read, nothing to wait for.\n@@ -5822,7 +5566,6 @@ void * srt::CUDT::tsbpd(void* param)\n             THREAD_PAUSED();\n             bWokeUpOnSignal = tsbpd_cc.wait_until(tsNextDelivery);\n             THREAD_RESUMED();\n-            HLOGC(tslog.Debug, log << self->CONID() << \"tsbpd: WAKE UP on \" << (bWokeUpOnSignal? \"SIGNAL\" : \"TIMEOUIT\") << \"!!!\");\n         }\n         else\n         {\n@@ -5964,17 +5707,16 @@ bool srt::CUDT::prepareBuffers(CUDTException* eout)\n     \n     try\n     {\n-        // CryptoControl has to be initialized and in case of RESPONDER\n-        // the KM REQ must be processed (interpretSrtHandshake(..)) for the crypto mode to be deduced.\n+        // CryptoControl has to be initialized and in case of RESPONDER the KM REQ must be processed (interpretSrtHandshake(..)) for the crypto mode to be deduced.\n         const int authtag = getAuthTagSize();\n \n-        SRT_ASSERT(m_iMaxDataPayloadSize != 0);\n+        SRT_ASSERT(m_iMaxSRTPayloadSize != 0);\n \n-        HLOGC(rslog.Debug, log << CONID() << \"Creating buffers: snd-plsize=\" << m_iMaxDataPayloadSize\n+        HLOGC(rslog.Debug, log << CONID() << \"Creating buffers: snd-plsize=\" << m_iMaxSRTPayloadSize\n                 << \" snd-bufsize=\" << 32\n                 << \" authtag=\" << authtag);\n \n-        m_pSndBuffer = new CSndBuffer(AF_INET, 32, m_iMaxDataPayloadSize, authtag);\n+        m_pSndBuffer = new CSndBuffer(AF_INET, 32, m_iMaxSRTPayloadSize, authtag);\n         SRT_ASSERT(m_iPeerISN != -1);\n         m_pRcvBuffer = new srt::CRcvBuffer(m_iPeerISN, m_config.iRcvBufSize, m_pRcvQueue->m_pUnitQueue, m_config.bMessageAPI);\n         // After introducing lite ACK, the sndlosslist may not be cleared in time, so it requires twice a space.\n@@ -6019,23 +5761,13 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any&\n \n     m_tsRcvPeerStartTime = steady_clock::time_point(); // will be set correctly at SRT HS\n \n-    const size_t full_hdr_size = CPacket::UDP_HDR_SIZE + CPacket::HDR_SIZE;\n     // Uses the smaller MSS between the peers\n-    size_t mss_size = std::min(m_config.iMSS, w_hs.m_iMSS);\n-    if (mss_size < MinimumMSS(peer.family()))\n-    {\n-        HLOGC(cnlog.Debug, log << CONID() << \"acceptAndRespond: peer's MSS=\" << w_hs.m_iMSS\n-                << \" is too small, can't accept the connection\");\n-        m_RejectReason = SRT_REJ_ROGUE;\n-        w_hs.m_iReqType = URQFailure(m_RejectReason);\n-        throw CUDTException(MJ_SETUP, MN_REJECTED, 0);\n-    }\n+    m_config.iMSS = std::min(m_config.iMSS, w_hs.m_iMSS);\n \n-    m_config.iMSS = mss_size;\n-\n-    m_iMaxDataPayloadSize = m_config.iMSS - full_hdr_size;\n+    const size_t full_hdr_size = CPacket::UDP_HDR_SIZE + CPacket::HDR_SIZE;\n+    m_iMaxSRTPayloadSize = m_config.iMSS - full_hdr_size;\n \n-    HLOGC(cnlog.Debug, log << CONID() << \"acceptAndRespond: PAYLOAD SIZE: \" << m_iMaxDataPayloadSize);\n+    HLOGC(cnlog.Debug, log << CONID() << \"acceptAndRespond: PAYLOAD SIZE: \" << m_iMaxSRTPayloadSize);\n \n     // exchange info for maximum flow window size\n     m_iFlowWindowSize = w_hs.m_iFlightFlagSize;\n@@ -6058,6 +5790,7 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any&\n \n     rewriteHandshakeData(peer, (w_hs));\n \n+\n     // Prepare all structures\n     if (!prepareConnectionObjects(w_hs, HSD_DRAW, 0))\n     {\n@@ -6185,7 +5918,7 @@ void srt::CUDT::acceptAndRespond(const sockaddr_any& agent, const sockaddr_any&\n     // TODO: Here create CONCLUSION RESPONSE with:\n     // - just the UDT handshake, if HS_VERSION_UDT4,\n     // - if higher, the UDT handshake, the SRT HSRSP, the SRT KMRSP.\n-    size_t size = controlPayloadSize(peer.family());\n+    size_t size = m_iMaxSRTPayloadSize;\n     // Allocate the maximum possible memory for an SRT payload.\n     // This is a maximum you can send once.\n     CPacket rsppkt;\n@@ -6313,7 +6046,7 @@ SRT_REJECT_REASON srt::CUDT::setupCC()\n \n     // XXX Not sure about that. May happen that AGENT wants\n     // tsbpd mode, but PEER doesn't, even in bidirectional mode.\n-    // This way, the reception side should get precedence.\n+    // This way, the reception side should get precedense.\n     // if (bidirectional || m_config.bDataSender || m_bTwoWayData)\n     //    m_bPeerTsbPd = m_bTSBPD;\n \n@@ -6373,13 +6106,6 @@ SRT_REJECT_REASON srt::CUDT::setupCC()\n     m_tsLastRspAckTime = currtime;\n     m_tsLastSndTime.store(currtime);\n \n-#ifdef ENABLE_RATE_MEASUREMENT\n-    // XXX NOTE: use IPv4 or IPv6 as applicable!\n-    HLOGC(bslog.Debug, log << CONID() << \"RATE-MEASUREMENT: initializing time TS=\" << FormatTime(currtime));\n-    m_SndRegularMeasurement.init(currtime, CPacket::UDP_HDR_SIZE);\n-    m_SndRexmitMeasurement.init(currtime, CPacket::UDP_HDR_SIZE);\n-#endif\n-\n     HLOGC(rslog.Debug,\n           log << CONID() << \"setupCC: setting parameters: mss=\" << m_config.iMSS << \" maxCWNDSize/FlowWindowSize=\"\n               << m_iFlowWindowSize << \" rcvrate=\" << m_iDeliveryRate << \"p/s (\" << m_iByteDeliveryRate << \"B/S)\"\n@@ -6387,7 +6113,7 @@ SRT_REJECT_REASON srt::CUDT::setupCC()\n \n     if (!updateCC(TEV_INIT, EventVariant(TEV_INIT_RESET)))\n     {\n-        LOGC(rslog.Error, log << CONID() << \"setupCC: IPE: resources not yet initialized!\");\n+        LOGC(rslog.Error, log << CONID() << \"setupCC: IPE: resrouces not yet initialized!\");\n         return SRT_REJ_IPE;\n     }\n     return SRT_REJ_UNKNOWN;\n@@ -6602,7 +6328,7 @@ bool srt::CUDT::closeInternal() ATR_NOEXCEPT\n     // Inform the threads handler to stop.\n     m_bClosing = true;\n \n-    HLOGC(smlog.Debug, log << CONID() << \"CLOSING STATE (closing=true). Acquiring connection lock\");\n+    HLOGC(smlog.Debug, log << CONID() << \"CLOSING STATE. Acquiring connection lock\");\n \n     ScopedLock connectguard(m_ConnectionLock);\n \n@@ -6614,11 +6340,7 @@ bool srt::CUDT::closeInternal() ATR_NOEXCEPT\n     if (m_bListening)\n     {\n         m_bListening = false;\n-        bool removed SRT_ATR_UNUSED = m_pRcvQueue->removeListener(this);\n-        if (!removed)\n-        {\n-            LOGC(smlog.Error, log << CONID() << \"CLOSING: IPE: listening=true but listener removal failed!\");\n-        }\n+        m_pRcvQueue->removeListener(this);\n     }\n     else if (m_bConnecting)\n     {\n@@ -6672,12 +6394,6 @@ bool srt::CUDT::closeInternal() ATR_NOEXCEPT\n     return true;\n }\n \n-bool srt::CUDT::closeAtFork() ATR_NOEXCEPT\n-{\n-    m_bShutdown = true;\n-    return closeInternal();\n-}\n-\n int srt::CUDT::receiveBuffer(char *data, int len)\n {\n     if (!m_CongCtl->checkTransArgs(SrtCongestion::STA_BUFFER, SrtCongestion::STAD_RECV, data, len, SRT_MSGTTL_INF, false))\n@@ -6819,7 +6535,7 @@ int srt::CUDT::sndDropTooLate()\n \n     // high threshold (msec) at tsbpd_delay plus sender/receiver reaction time (2 * 10ms)\n     // Minimum value must accommodate an I-Frame (~8 x average frame size)\n-    // >>need picture rate or app to set min threshold\n+    // >>need picture rate or app to set min treshold\n     // >>using 1 sec for worse case 1 frame using all bit budget.\n     // picture rate would be useful in auto SRT setting for min latency\n     // XXX Make SRT_TLPKTDROP_MINTHRESHOLD_MS option-configurable\n@@ -6965,11 +6681,11 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)\n     //   out a message of a length that exceeds the total size of the sending\n     //   buffer (configurable by SRTO_SNDBUF).\n \n-    if (m_config.bMessageAPI && len > int(m_config.iSndBufSize * m_iMaxDataPayloadSize))\n+    if (m_config.bMessageAPI && len > int(m_config.iSndBufSize * m_iMaxSRTPayloadSize))\n     {\n         LOGC(aslog.Error,\n              log << CONID() << \"Message length (\" << len << \") exceeds the size of sending buffer: \"\n-                 << (m_config.iSndBufSize * m_iMaxDataPayloadSize) << \". Use SRTO_SNDBUF if needed.\");\n+                 << (m_config.iSndBufSize * m_iMaxSRTPayloadSize) << \". Use SRTO_SNDBUF if needed.\");\n         throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);\n     }\n \n@@ -7053,7 +6769,7 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)\n \n         /*\n          * The code below is to return ETIMEOUT when blocking mode could not get free buffer in time.\n-         * If no free buffer available in non-blocking mode, we already returned. If buffer available,\n+         * If no free buffer available in non-blocking mode, we alredy returned. If buffer available,\n          * we test twice if this code is outside the else section.\n          * This fix move it in the else (blocking-mode) section\n          */\n@@ -7100,7 +6816,7 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)\n         // Just return how many bytes were actually scheduled for writing.\n         // XXX May be reasonable to add a flag that requires that the function\n         // not return until the buffer is sent completely.\n-        size = min(len, sndBuffersLeft() * m_iMaxDataPayloadSize);\n+        size = min(len, sndBuffersLeft() * m_iMaxSRTPayloadSize);\n     }\n \n     {\n@@ -7140,7 +6856,7 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)\n         w_mctrl.pktseq = seqno;\n \n         // Now seqno is the sequence to which it was scheduled\n-        // XXX Conversion from w_mctrl.srctime -> steady_clock::time_point need not be accurate.\n+        // XXX Conversion from w_mctrl.srctime -> steady_clock::time_point need not be accurrate.\n         HLOGC(aslog.Debug, log << CONID() << \"buf:SENDING (BEFORE) srctime:\"\n                 << (w_mctrl.srctime ? FormatTime(ts_srctime) : \"none\")\n                 << \" DATA SIZE: \" << size << \" sched-SEQUENCE: \" << seqno\n@@ -7175,7 +6891,7 @@ int srt::CUDT::sendmsg2(const char *data, int len, SRT_MSGCTRL& w_mctrl)\n               << \" size=\" << size << \" #\" << w_mctrl.msgno << \" SCHED %\" << orig_seqno\n               << \"(>> %\" << seqno << \") !\" << BufferStamp(data, size));\n \n-        if (sndBuffersLeft() < 1) // XXX Not sure if it should test if any space in the buffer, or as required.\n+        if (sndBuffersLeft() < 1) // XXX Not sure if it should test if any space in the buffer, or as requried.\n         {\n             // write is not available any more\n             uglobal().m_EPoll.update_events(m_SocketID, m_sPollID, SRT_EPOLL_OUT, false);\n@@ -7392,7 +7108,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_\n \n             // After signaling the tsbpd for ready data, report the bandwidth.\n #if ENABLE_HEAVY_LOGGING\n-            double bw = Bps2Mbps(int64_t(m_iBandwidth) * m_iMaxDataPayloadSize );\n+            double bw = Bps2Mbps(int64_t(m_iBandwidth) * m_iMaxSRTPayloadSize );\n             HLOGC(arlog.Debug, log << CONID() << \"CURRENT BANDWIDTH: \" << bw << \"Mbps (\" << m_iBandwidth << \" buffers per second)\");\n #endif\n         }\n@@ -7432,7 +7148,7 @@ int srt::CUDT::receiveMessage(char* data, int len, SRT_MSGCTRL& w_mctrl, int by_\n             {\n                 // `wait_for(recv_timeout)` wouldn't be correct here. Waiting should be\n                 // only until the time that is now + timeout since the first moment\n-                // when this started, or sliced-waiting for 1 second, if timeout is\n+                // when this started, or sliced-waiting for 1 second, if timtout is\n                 // higher than this.\n                 const steady_clock::time_point exptime = steady_clock::now() + recv_timeout;\n \n@@ -7884,7 +7600,7 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous)\n \n     const int64_t availbw = m_iBandwidth == 1 ? m_RcvTimeWindow.getBandwidth() : m_iBandwidth.load();\n \n-    perf->mbpsBandwidth = Bps2Mbps(availbw * (m_iMaxDataPayloadSize + pktHdrSize));\n+    perf->mbpsBandwidth = Bps2Mbps(availbw * (m_iMaxSRTPayloadSize + pktHdrSize));\n \n     if (tryEnterCS(m_ConnectionLock))\n     {\n@@ -7984,7 +7700,7 @@ bool srt::CUDT::updateCC(ETransmissionEvent evt, const EventVariant arg)\n             // Use the values:\n             // - if SRTO_MAXBW is >0, use it.\n             // - if SRTO_MAXBW == 0, use SRTO_INPUTBW + SRTO_OHEADBW\n-            // - if SRTO_INPUTBW == 0, pass 0 to request in-buffer sampling\n+            // - if SRTO_INPUTBW == 0, pass 0 to requst in-buffer sampling\n             // Bytes/s\n             const int64_t bw = m_config.llMaxBW != 0 ? m_config.llMaxBW :                   // When used SRTO_MAXBW\n                                m_config.llInputBW != 0 ? withOverhead(m_config.llInputBW) : // SRTO_INPUTBW + SRT_OHEADBW\n@@ -8104,21 +7820,10 @@ void srt::CUDT::destroySynch()\n     m_RcvTsbPdCond.notify_all();\n     releaseCond(m_RcvTsbPdCond);\n }\n-void srt::CUDT::resetAtFork()\n-{\n-    resetCond(m_SendBlockCond);\n-    resetCond(m_RecvDataCond);\n-    resetCond(m_RcvTsbPdCond);\n-}\n \n void srt::CUDT::releaseSynch()\n {\n     SRT_ASSERT(m_bClosing);\n-    if (!m_bClosing)\n-    {\n-        LOGC(smlog.Error, log << \"releaseSynch: IPE: m_bClosing not set to false, TSBPD might hangup!\");\n-        m_bClosing = true;\n-    }\n     // wake up user calls\n     CSync::lock_notify_one(m_SendBlockCond, m_SendBlockLock);\n \n@@ -8126,8 +7831,8 @@ void srt::CUDT::releaseSynch()\n     leaveCS(m_SendLock);\n \n     // Awake tsbpd() and srt_recv*(..) threads for them to check m_bClosing.\n-    CSync::lock_notify_all(m_RecvDataCond, m_RecvLock);\n-    CSync::lock_notify_all(m_RcvTsbPdCond, m_RecvLock);\n+    CSync::lock_notify_one(m_RecvDataCond, m_RecvLock);\n+    CSync::lock_notify_one(m_RcvTsbPdCond, m_RecvLock);\n \n     // Azquiring m_RcvTsbPdStartupLock protects race in starting\n     // the tsbpd() thread in CUDT::processData().\n@@ -8224,18 +7929,22 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp\n             // this is periodically NAK report; make sure NAK cannot be sent back too often\n \n             // read loss list from the local receiver loss list\n-            FixedArray<int32_t> data (m_iMaxDataPayloadSize / sizeof(int32_t));\n-            int losslen = m_pRcvLossList->getLossArray(data);\n-            if (losslen > 0)\n+            int32_t *data = new int32_t[m_iMaxSRTPayloadSize / 4];\n+            int      losslen;\n+            m_pRcvLossList->getLossArray(data, losslen, m_iMaxSRTPayloadSize / 4);\n+\n+            if (0 < losslen)\n             {\n-                ctrlpkt.pack(pkttype, /*lparam*/ NULL, data.data(), losslen * sizeof(int32_t));\n+                ctrlpkt.pack(pkttype, NULL, data, losslen * 4);\n                 ctrlpkt.set_id(m_PeerID);\n-                nbsent = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);\n+                nbsent        = m_pSndQueue->sendto(m_PeerAddr, ctrlpkt, m_SourceAddr);\n \n                 enterCS(m_StatsLock);\n                 m_stats.rcvr.sentNak.count(1);\n                 leaveCS(m_StatsLock);\n             }\n+\n+            delete[] data;\n         }\n \n         // update next NAK time, which should wait enough time for the retansmission, but not too long\n@@ -8279,7 +7988,7 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp\n         break;\n \n     case UMSG_SHUTDOWN: // 101 - Shutdown\n-        if (m_PeerID == 0) // Don't send SHUTDOWN if we don't know peer ID.\n+        if (m_PeerID == 0) // Dont't send SHUTDOWN if we don't know peer ID.\n             break;\n         ctrlpkt.pack(pkttype);\n         ctrlpkt.set_id(m_PeerID);\n@@ -8301,7 +8010,7 @@ void srt::CUDT::sendCtrl(UDTMessageType pkttype, const int32_t* lparam, void* rp\n \n         break;\n \n-    case UMSG_EXT: // 0x7FFF - Reserved for future use\n+    case UMSG_EXT: // 0x7FFF - Resevered for future use\n         break;\n \n     default:\n@@ -8459,7 +8168,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)\n             // can be either never set, already reset, or ever set\n             // and possibly dangling. The re-check after lock eliminates\n             // the dangling case.\n-            SharedLock glock (uglobal().m_GlobControlLock);\n+            ScopedLock glock (uglobal().m_GlobControlLock);\n \n             // Note that updateLatestRcv will lock m_GroupOf->m_GroupLock,\n             // but this is an intended order.\n@@ -8520,7 +8229,7 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)\n             if (group_read_seq != SRT_SEQNO_NONE && m_parent->m_GroupOf)\n             {\n                 // See above explanation for double-checking\n-                SharedLock glock (uglobal().m_GlobControlLock);\n+                ScopedLock glock (uglobal().m_GlobControlLock);\n \n                 if (m_parent->m_GroupOf)\n                 {\n@@ -8582,12 +8291,11 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)\n             data[ACKD_RCVSPEED] = m_RcvTimeWindow.getPktRcvSpeed((rcvRate));\n             data[ACKD_BANDWIDTH] = m_RcvTimeWindow.getBandwidth();\n \n-            // XXX Likely this can be removed already.\n             //>>Patch while incompatible (1.0.2) receiver floating around\n             if (m_uPeerSrtVersion == SrtVersion(1, 0, 2))\n             {\n                 data[ACKD_RCVRATE] = rcvRate;                                     // bytes/sec\n-                data[ACKD_XMRATE_VER102_ONLY] = data[ACKD_BANDWIDTH] * m_iMaxDataPayloadSize; // bytes/sec\n+                data[ACKD_XMRATE_VER102_ONLY] = data[ACKD_BANDWIDTH] * m_iMaxSRTPayloadSize; // bytes/sec\n                 ctrlsz = ACKD_FIELD_SIZE * ACKD_TOTAL_SIZE_VER102_ONLY;\n             }\n             else if (m_uPeerSrtVersion >= SrtVersion(1, 0, 3))\n@@ -8605,7 +8313,6 @@ int srt::CUDT::sendCtrlAck(CPacket& ctrlpkt, int size)\n         {\n             ctrlpkt.pack(UMSG_ACK, &m_iAckSeqNo, data, ACKD_FIELD_SIZE * ACKD_TOTAL_SIZE_SMALL);\n         }\n-        bufflock.unlock();\n \n         ctrlpkt.set_id(m_PeerID);\n         setPacketTS(ctrlpkt, steady_clock::now());\n@@ -8678,7 +8385,7 @@ void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno)\n     {\n         // m_RecvAckLock is ordered AFTER m_GlobControlLock, so this can only\n         // be done now that m_RecvAckLock is unlocked.\n-        SharedLock glock (uglobal().m_GlobControlLock);\n+        ScopedLock glock (uglobal().m_GlobControlLock);\n         if (m_parent->m_GroupOf)\n         {\n             HLOGC(inlog.Debug, log << CONID() << \"ACK: acking group sender buffer for #\" << msgno_at_last_acked_seq);\n@@ -8714,24 +8421,9 @@ void srt::CUDT::updateSndLossListOnACK(int32_t ackdata_seqno)\n     leaveCS(m_StatsLock);\n }\n \n-bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point& currtime)\n+void srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_point& currtime)\n {\n-    // Valid ACK payloads are either LITE (just an ack seqno) or at least SMALL\n-    // (RCVLASTACK + RTT + RTTVAR + BUFFERLEFT = 16 B). Anything else would OOB-read.\n-    const size_t pktlen = ctrlpkt.getLength();\n-    const bool isLiteAck = pktlen == size_t(SEND_LITE_ACK);\n-    if (!isLiteAck && pktlen < ACKD_TOTAL_SIZE_SMALL * ACKD_FIELD_SIZE)\n-    {\n-        LOGC(inlog.Warn, log << CONID() << \"ACK: EPE: wrong payload size=\" << pktlen\n-                             << \" expected 4 or at least SMALL (\"\n-                             << (ACKD_TOTAL_SIZE_SMALL * ACKD_FIELD_SIZE)\n-                             << \") - rejecting\");\n-        return false;\n-    }\n-\n     const int32_t* ackdata       = (const int32_t*)ctrlpkt.m_pcData;\n-\n-    // Note: minimum of one 4-byte field is granted before the call.\n     const int32_t  ackdata_seqno = ackdata[ACKD_RCVLASTACK];\n \n     // Check the value of ACK in case when it was some rogue peer\n@@ -8743,9 +8435,10 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n         // This check MUST BE DONE before making any operation on this number.\n         LOGC(inlog.Error, log << CONID() << \"ACK: IPE/EPE: received invalid ACK value: \" << ackdata_seqno\n                 << \" \" << std::hex << ackdata_seqno << \" (IGNORED)\");\n-        return false;\n+        return;\n     }\n \n+    const bool isLiteAck = ctrlpkt.getLength() == (size_t)SEND_LITE_ACK;\n     HLOGC(inlog.Debug,\n           log << CONID() << \"ACK covers: \" << m_iSndLastDataAck << \" - \" << ackdata_seqno << \" [ACK=\" << m_iSndLastAck\n               << \"]\" << (isLiteAck ? \"[LITE]\" : \"[FULL]\"));\n@@ -8764,16 +8457,7 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n             m_tsLastRspAckTime = currtime;\n             m_iReXmitCount         = 1; // Reset re-transmit count since last ACK\n         }\n-        return true;\n-    }\n-\n-    const size_t acksize   = pktlen / ACKD_FIELD_SIZE; // ACTUAL VALUE\n-\n-    // Check minimum size acceptable. If less, reject it.\n-    if (acksize < ACKD_TOTAL_SIZE_SMALL)\n-    {\n-        LOGC(inlog.Error, log << CONID() << \"EPE: ACK msg received with too small size: \" << pktlen);\n-        return false;\n+        return;\n     }\n \n     // Decide to send ACKACK or not\n@@ -8799,44 +8483,39 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n \n     // Protect packet retransmission\n     {\n-        UniqueLock ack_lock(m_RecvAckLock);\n+        ScopedLock ack_lock(m_RecvAckLock);\n \n         // Check the validation of the ack\n         if (CSeqNo::seqcmp(ackdata_seqno, CSeqNo::incseq(m_iSndCurrSeqNo)) > 0)\n         {\n-            ack_lock.unlock();\n-\n             // this should not happen: attack or bug\n             LOGC(gglog.Error,\n                     log << CONID() << \"ATTACK/IPE: incoming ack seq \" << ackdata_seqno << \" exceeds current \"\n                     << m_iSndCurrSeqNo << \" by \" << (CSeqNo::seqoff(m_iSndCurrSeqNo, ackdata_seqno) - 1) << \"!\");\n             m_bBroken        = true;\n             m_iBrokenCounter = 0;\n-\n-            updateBrokenConnection();\n-            completeBrokenConnectionDependencies(SRT_ESECFAIL); // LOCKS!\n-            return false;\n+            return;\n         }\n \n-        if (CSeqNo::seqcmp(ackdata_seqno, m_iSndLastAck) >= 0)\n-        {\n-            const int cwnd1   = std::min<int>(m_iFlowWindowSize, m_iCongestionWindow);\n-            const bool bWasStuck = cwnd1<= getFlightSpan();\n-            // Update Flow Window Size, must update before and together with m_iSndLastAck\n-            m_iFlowWindowSize = ackdata[ACKD_BUFFERLEFT];\n-            m_iSndLastAck     = ackdata_seqno;\n-            m_tsLastRspAckTime  = currtime;\n-            m_iReXmitCount    = 1; // Reset re-transmit count since last ACK\n+    if (CSeqNo::seqcmp(ackdata_seqno, m_iSndLastAck) >= 0)\n+    {\n+        const int cwnd1   = std::min<int>(m_iFlowWindowSize, m_iCongestionWindow);\n+        const bool bWasStuck = cwnd1<= getFlightSpan();\n+        // Update Flow Window Size, must update before and together with m_iSndLastAck\n+        m_iFlowWindowSize = ackdata[ACKD_BUFFERLEFT];\n+        m_iSndLastAck     = ackdata_seqno;\n+        m_tsLastRspAckTime  = currtime;\n+        m_iReXmitCount    = 1; // Reset re-transmit count since last ACK\n \n-            const int cwnd    = std::min<int>(m_iFlowWindowSize, m_iCongestionWindow);\n-            if (bWasStuck && cwnd > getFlightSpan())\n-            {\n-                m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);\n-                HLOGC(gglog.Debug,\n-                        log << CONID() << \"processCtrlAck: could reschedule SND. iFlowWindowSize \" << m_iFlowWindowSize\n-                        << \" SPAN \" << getFlightSpan() << \" ackdataseqno %\" << ackdata_seqno);\n-            }\n+        const int cwnd    = std::min<int>(m_iFlowWindowSize, m_iCongestionWindow);\n+        if (bWasStuck && cwnd > getFlightSpan())\n+        {\n+            m_pSndQueue->m_pSndUList->update(this, CSndUList::DONT_RESCHEDULE);\n+            HLOGC(gglog.Debug,\n+                    log << CONID() << \"processCtrlAck: could reschedule SND. iFlowWindowSize \" << m_iFlowWindowSize\n+                    << \" SPAN \" << getFlightSpan() << \" ackdataseqno %\" << ackdata_seqno);\n         }\n+    }\n \n         /*\n          * We must not ignore full ack received by peer\n@@ -8844,14 +8523,14 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n          * Therefore, a distinct ack state is used for received Ack (iSndLastFullAck)\n          * and ack position in send buffer (m_iSndLastDataAck).\n          * Otherwise, when severe congestion causing packet drops (and m_iSndLastDataAck update)\n-         * occurs, we drop received acks (as duplicates) and do not update stats like RTT,\n+         * occures, we drop received acks (as duplicates) and do not update stats like RTT,\n          * which may go crazy and stay there, preventing proper stream recovery.\n          */\n \n         if (CSeqNo::seqoff(m_iSndLastFullAck, ackdata_seqno) <= 0)\n         {\n             // discard it if it is a repeated ACK\n-            return true;\n+            return;\n         }\n         m_iSndLastFullAck = ackdata_seqno;\n     }\n@@ -8861,7 +8540,7 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n #if ENABLE_BONDING\n     if (m_parent->m_GroupOf)\n     {\n-        SharedLock glock (uglobal().m_GlobControlLock);\n+        ScopedLock glock (uglobal().m_GlobControlLock);\n         if (m_parent->m_GroupOf)\n         {\n             // Will apply m_GroupLock, ordered after m_GlobControlLock.\n@@ -8871,12 +8550,24 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n     }\n #endif\n \n+    size_t acksize   = ctrlpkt.getLength(); // TEMPORARY VALUE FOR CHECKING\n+    bool   wrongsize = 0 != (acksize % ACKD_FIELD_SIZE);\n+    acksize          = acksize / ACKD_FIELD_SIZE; // ACTUAL VALUE\n+\n+    if (wrongsize)\n+    {\n+        // Issue a log, but don't do anything but skipping the \"odd\" bytes from the payload.\n+        LOGC(inlog.Warn,\n+             log << CONID() << \"Received UMSG_ACK payload is not evened up to 4-byte based field size - cutting to \"\n+                 << acksize << \" fields\");\n+    }\n+\n     // Start with checking the base size.\n     if (acksize < ACKD_TOTAL_SIZE_SMALL)\n     {\n         LOGC(inlog.Warn, log << CONID() << \"Invalid ACK size \" << acksize << \" fields - less than minimum required!\");\n         // Ack is already interpreted, just skip further parts.\n-        return false;\n+        return;\n     }\n     // This check covers fields up to ACKD_BUFFERLEFT.\n \n@@ -8965,11 +8656,10 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n         /* SRT v1.0.2 Bytes-based stats: bandwidth (pcData[ACKD_XMRATE_VER102_ONLY]) and delivery rate (pcData[ACKD_RCVRATE]) in\n          * bytes/sec instead of pkts/sec */\n         /* SRT v1.0.3 Bytes-based stats: only delivery rate (pcData[ACKD_RCVRATE]) in bytes/sec instead of pkts/sec */\n-        // XXX v1.0.2 handling can be likely deleted.\n         if (acksize > ACKD_TOTAL_SIZE_UDTBASE)\n             bytesps = ackdata[ACKD_RCVRATE];\n         else\n-            bytesps = pktps * m_iMaxDataPayloadSize;\n+            bytesps = pktps * m_iMaxSRTPayloadSize;\n \n         m_iBandwidth        = avg_iir<8>(m_iBandwidth.load(), bandwidth);\n         m_iDeliveryRate     = avg_iir<8>(m_iDeliveryRate.load(), pktps);\n@@ -8987,11 +8677,9 @@ bool srt::CUDT::processCtrlAck(const CPacket &ctrlpkt, const steady_clock::time_\n     enterCS(m_StatsLock);\n     m_stats.sndr.recvdAck.count(1);\n     leaveCS(m_StatsLock);\n-\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival)\n+void srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival)\n {\n     int32_t ack = 0;\n \n@@ -9017,14 +8705,14 @@ bool srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr\n             }\n #endif\n \n-            return false;\n+            return;\n         }\n \n         LOGC(inlog.Error,\n              log << CONID() << \"ACK record not found, can't estimate RTT \"\n                  << \"(ACK number: \" << ctrlpkt.getAckSeqNo() << \", last ACK sent: \" << m_iAckSeqNo\n                  << \", RTT (EWMA): \" << m_iSRTT << \")\");\n-        return false;\n+        return;\n     }\n \n     if (rtt <= 0)\n@@ -9032,7 +8720,7 @@ bool srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr\n         LOGC(inlog.Error,\n             log << CONID() << \"IPE: invalid RTT estimate \" << rtt\n             << \", possible time shift. Clock: \" << SRT_SYNC_CLOCK_STR);\n-        return false;\n+        return;\n     }\n \n     // If increasing delay is detected.\n@@ -9073,7 +8761,7 @@ bool srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr\n     if (m_config.bDriftTracer)\n     {\n #if ENABLE_BONDING\n-        ExclusiveLock glock(uglobal().m_GlobControlLock); // XXX not too excessive?\n+        ScopedLock glock(uglobal().m_GlobControlLock); // XXX not too excessive?\n         const bool drift_updated =\n #endif\n         m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), tsArrival, rtt);\n@@ -9087,13 +8775,12 @@ bool srt::CUDT::processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsAr\n     // Update last ACK that has been received by the sender\n     if (CSeqNo::seqcmp(ack, m_iRcvLastAckAck) > 0)\n         m_iRcvLastAckAck = ack;\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)\n+void srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)\n {\n     const int32_t* losslist = (int32_t*)(ctrlpkt.m_pcData);\n-    const size_t   losslist_len = ctrlpkt.getLength() / sizeof(int32_t);\n+    const size_t   losslist_len = ctrlpkt.getLength() / 4;\n \n     bool secure = true;\n \n@@ -9111,14 +8798,6 @@ bool srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)\n             // IF the loss is a range <LO, HI>\n             if (IsSet(losslist[i], LOSSDATA_SEQNO_RANGE_FIRST))\n             {\n-                // The range-first marker means the next cell holds HI. Reject if it isn't present\n-                // in the body — otherwise losslist[i+1] reads past the wire payload.\n-                if (i + 1 >= n)\n-                {\n-                    LOGC(inlog.Warn, log << CONID() << \"rcv LOSSREPORT: trailing range-first word with no HI - DISCARDING\");\n-                    secure = false;\n-                    break;\n-                }\n                 // Then it's this is a <LO, HI> specification with HI in a consecutive cell.\n                 const int32_t losslist_lo = SEQNO_VALUE::unwrap(losslist[i]);\n                 const int32_t losslist_hi = losslist[i + 1];\n@@ -9245,10 +8924,7 @@ bool srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)\n         // this should not happen: attack or bug\n         m_bBroken = true;\n         m_iBrokenCounter = 0;\n-\n-        updateBrokenConnection();\n-        completeBrokenConnectionDependencies(SRT_ESECFAIL); // LOCKS!\n-        return false;\n+        return;\n     }\n \n     // the lost packet (retransmission) should be sent out immediately\n@@ -9257,22 +8933,16 @@ bool srt::CUDT::processCtrlLossReport(const CPacket& ctrlpkt)\n     enterCS(m_StatsLock);\n     m_stats.sndr.recvdNak.count(1);\n     leaveCS(m_StatsLock);\n-\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlHS(const CPacket& ctrlpkt)\n+void srt::CUDT::processCtrlHS(const CPacket& ctrlpkt)\n {\n     CHandShake req;\n-    if (-1 == req.load_from(ctrlpkt.m_pcData, ctrlpkt.getLength()))\n-    {\n-        LOGC(inlog.Error, log << CONID() << \"processCtrlHS: EPE: Handshake has wrong size: \" << ctrlpkt.getLength());\n-        return false;\n-    }\n+    req.load_from(ctrlpkt.m_pcData, ctrlpkt.getLength());\n \n     HLOGC(inlog.Debug, log << CONID() << \"processCtrl: got HS: \" << req.show());\n \n-    if ((req.m_iReqType > URQ_INDUCTION_TYPES) // actually it catches URQ_INDUCTION and URQ_ERROR_* symbols...???\n+    if ((req.m_iReqType > URQ_INDUCTION_TYPES) // acually it catches URQ_INDUCTION and URQ_ERROR_* symbols...???\n         || (m_config.bRendezvous && (req.m_iReqType != URQ_AGREEMENT))) // rnd sends AGREEMENT in rsp to CONCLUSION\n     {\n         // The peer side has not received the handshake message, so it keeps querying\n@@ -9354,7 +9024,7 @@ bool srt::CUDT::processCtrlHS(const CPacket& ctrlpkt)\n \n         CPacket rsppkt;\n         rsppkt.setControl(UMSG_HANDSHAKE);\n-        rsppkt.allocate(controlPayloadSize());\n+        rsppkt.allocate(m_iMaxSRTPayloadSize);\n \n         // If createSrtHandshake failed, don't send anything. Actually it can only fail on IPE.\n         // There is also no possible IPE condition in case of HSv4 - for this version it will always return true.\n@@ -9371,61 +9041,17 @@ bool srt::CUDT::processCtrlHS(const CPacket& ctrlpkt)\n                 m_tsLastSndTime.store(steady_clock::now());\n             }\n         }\n-\n-        // If a REJECTION HS has been sent, break also the connection locally.\n-        if (initdata.m_iReqType >= URQ_FAILURE_TYPES)\n-        {\n-            processCtrlShutdown(); // always returns true\n-        }\n     }\n     else\n     {\n         HLOGC(inlog.Debug, log << CONID() << \"processCtrl: ... not INDUCTION, not ERROR, not rendezvous - IGNORED.\");\n-        return false;\n     }\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt)\n+void srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt)\n {\n-    // dropdata[0..1] are indexed unconditionally below.\n-    if (ctrlpkt.getLength() < 2 * sizeof(int32_t))\n-    {\n-        LOGC(inlog.Warn, log << CONID() << \"DROPREQ: payload \" << ctrlpkt.getLength()\n-                             << \" bytes < \" << (2 * sizeof(int32_t)) << \" - rejecting\");\n-        return false;\n-    }\n-\n     const int32_t* dropdata = (const int32_t*) ctrlpkt.m_pcData;\n \n-    // The wire format carries a (lo, hi) seqno range. Reject reversed\n-    // ranges: dropMessage walks a circular buffer from offset(lo) to\n-    // offset(hi)+1 via incPos(); when seqcmp(lo, hi) > 0 the loop wraps\n-    // and clears nearly the entire receive buffer (DoS primitive). The\n-    // analogous LOSSREPORT path already rejects reversed ranges.\n-\n-    // This is for check only - one packet read will not spoil it\n-    m_RcvBufferLock.lock();\n-    const int32_t hookseq_begin = m_pRcvBuffer->getStartSeqNo();\n-    m_RcvBufferLock.unlock();\n-\n-    int dist_begin = CSeqNo::seqoff(dropdata[0], hookseq_begin);\n-    int dist_rel = CSeqNo::seqoff(dropdata[0], dropdata[1]);\n-\n-    if (abs(dist_begin) > CSeqNo::m_iSeqNoTH/2)\n-    {\n-        LOGC(inlog.Warn, log << CONID() << \"EPE: rcv DROPREQ low rng %\"\n-            << dropdata[0] << \" - too distant to receiver buffer %\" << hookseq_begin\n-            << \" by \" << dist_begin << \" (exceeds threshold)\");\n-        return false;\n-    }\n-    if (dist_rel < 0 || dist_rel > CSeqNo::m_iSeqNoTH/2)\n-    {\n-        LOGC(inlog.Warn, log << CONID() << \"EPE: rcv DROPREQ rng %\"\n-            << dropdata[0] << \" - %\" << dropdata[1] << \" - REVERSED RANGE, DISCARDING\");\n-        return false;\n-    }\n-\n     {\n         CUniqueSync rcvtscc (m_RecvLock, m_RcvTsbPdCond);\n         // With both TLPktDrop and TsbPd enabled, a message always consists only of one packet.\n@@ -9487,11 +9113,9 @@ bool srt::CUDT::processCtrlDropReq(const CPacket& ctrlpkt)\n         HLOGC(inlog.Debug, log << CONID() << \"DROPREQ: dropping %\"\n             << dropdata[0] << \"-\" << dropdata[1] << \" current %\" << m_iRcvCurrSeqNo);\n     }\n-\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlShutdown()\n+void srt::CUDT::processCtrlShutdown()\n {\n     m_bShutdown = true;\n     m_bClosing = true;\n@@ -9502,10 +9126,9 @@ bool srt::CUDT::processCtrlShutdown()\n     // just we know about this state prematurely thanks to this message.\n     updateBrokenConnection();\n     completeBrokenConnectionDependencies(SRT_ECONNLOST); // LOCKS!\n-    return true;\n }\n \n-bool srt::CUDT::processCtrlUserDefined(const CPacket& ctrlpkt)\n+void srt::CUDT::processCtrlUserDefined(const CPacket& ctrlpkt)\n {\n     HLOGC(inlog.Debug, log << CONID() << \"CONTROL EXT MSG RECEIVED:\"\n         << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType())\n@@ -9533,44 +9156,31 @@ bool srt::CUDT::processCtrlUserDefined(const CPacket& ctrlpkt)\n     {\n         updateCC(TEV_CUSTOM, EventVariant(&ctrlpkt));\n     }\n-    return true;\n }\n \n-bool srt::CUDT::processCtrl(const CPacket &ctrlpkt)\n+void srt::CUDT::processCtrl(const CPacket &ctrlpkt)\n {\n     // Just heard from the peer, reset the expiration count.\n     m_iEXPCount = 1;\n     const steady_clock::time_point currtime = steady_clock::now();\n     m_tsLastRspTime = currtime;\n \n-    // Extra check for the payload size:\n-    // - must be aligned to int32_t\n-    // - cannot be 0 (msgs with no args use 4-byte zero-filled padding).\n-    size_t pktlen = ctrlpkt.getLength();\n-    if (!pktlen || pktlen % sizeof(int32_t) != 0)\n-    {\n-        LOGC(inlog.Error, log << CONID() << \"EPE: incoming UMSG: \" << ctrlpkt.getType() << \" INVALID SIZE: \" << pktlen\n-                << \" (expected > 0 and aligned to \" << sizeof(int32_t) << \" bytes)\");\n-        return false;\n-    }\n-\n     HLOGC(inlog.Debug,\n           log << CONID() << \"incoming UMSG:\" << ctrlpkt.getType() << \" (\"\n               << MessageTypeStr(ctrlpkt.getType(), ctrlpkt.getExtendedType()) << \") socket=%\" << ctrlpkt.id());\n \n-    bool result = false;\n     switch (ctrlpkt.getType())\n     {\n     case UMSG_ACK: // 010 - Acknowledgement\n-        result = processCtrlAck(ctrlpkt, currtime);\n+        processCtrlAck(ctrlpkt, currtime);\n         break;\n \n     case UMSG_ACKACK: // 110 - Acknowledgement of Acknowledgement\n-        result = processCtrlAckAck(ctrlpkt, currtime);\n+        processCtrlAckAck(ctrlpkt, currtime);\n         break;\n \n     case UMSG_LOSSREPORT: // 011 - Loss Report\n-        result = processCtrlLossReport(ctrlpkt);\n+        processCtrlLossReport(ctrlpkt);\n         break;\n \n     case UMSG_CGWARNING: // 100 - Delay Warning\n@@ -9584,40 +9194,38 @@ bool srt::CUDT::processCtrl(const CPacket &ctrlpkt)\n         break;\n \n     case UMSG_KEEPALIVE: // 001 - Keep-alive\n-        result = processKeepalive(ctrlpkt, currtime);\n+        processKeepalive(ctrlpkt, currtime);\n         break;\n \n     case UMSG_HANDSHAKE: // 000 - Handshake\n-        result = processCtrlHS(ctrlpkt);\n+        processCtrlHS(ctrlpkt);\n         break;\n \n     case UMSG_SHUTDOWN: // 101 - Shutdown\n-        result = processCtrlShutdown();\n+        processCtrlShutdown();\n         break;\n \n     case UMSG_DROPREQ: // 111 - Msg drop request\n-        result = processCtrlDropReq(ctrlpkt);\n+        processCtrlDropReq(ctrlpkt);\n         break;\n \n     case UMSG_PEERERROR: // 1000 - An error has happened to the peer side\n         // int err_type = packet.getAddInfo();\n \n         // currently only this error is signalled from the peer side\n-        // if recvfile() fails (e.g., due to disk fail), blocked sendfile/send should return immediately\n+        // if recvfile() failes (e.g., due to disk fail), blcoked sendfile/send should return immediately\n         // giving the app a chance to fix the issue\n         m_bPeerHealth = false;\n-        result = true;\n \n         break;\n \n     case UMSG_EXT: // 0x7FFF - reserved and user defined messages\n-        result = processCtrlUserDefined(ctrlpkt);\n+        processCtrlUserDefined(ctrlpkt);\n         break;\n \n     default:\n         break;\n     }\n-    return result;\n }\n \n void srt::CUDT::updateSrtRcvSettings()\n@@ -9696,7 +9304,7 @@ void srt::CUDT::updateAfterSrtHandshake(int hsv)\n \n     if (m_parent->m_GroupOf)\n     {\n-        SharedLock glock (uglobal().m_GlobControlLock);\n+        ScopedLock glock (uglobal().m_GlobControlLock);\n         grpspec = m_parent->m_GroupOf\n             ? \" group=$\" + Sprint(m_parent->m_GroupOf->id())\n             : string();\n@@ -9727,157 +9335,80 @@ void srt::CUDT::updateAfterSrtHandshake(int hsv)\n     }\n }\n \n-// XXX During sender buffer refax turn this into either returning\n-// a sequence number or move it to the sender buffer facility.\n-// [[using locked (m_RecvAckLock)]]\n-std::pair<int32_t, int> srt::CUDT::getCleanRexmitOffset()\n+int srt::CUDT::packLostData(CPacket& w_packet)\n {\n-    // This function is required to look into the loss list and\n-    // drop all sequences that are already revoked from the sender\n-    // buffer, send the drop request if needed, and return the sender\n-    // buffer offset for the next packet to retransmit, or -1 if\n-    // there is no retransmission candidate at the moment.\n+    // protect m_iSndLastDataAck from updating by ACK processing\n+    UniqueLock ackguard(m_RecvAckLock);\n+    const steady_clock::time_point time_now = steady_clock::now();\n+    const steady_clock::time_point time_nak = time_now - microseconds_from(m_iSRTT - 4 * m_iRTTVar);\n \n     for (;;)\n     {\n-        // REPEATABLE because we might need to drop this scheduled seq.\n-\n-        // Pick up the first sequence.\n-        int32_t seq = m_pSndLossList->popLostSeq();\n-        if (seq == SRT_SEQNO_NONE)\n-        {\n-            // No loss reports, we are clear here.\n-            return std::make_pair(SRT_SEQNO_NONE, -1);\n-        }\n+        w_packet.set_seqno(m_pSndLossList->popLostSeq());\n+        if (w_packet.seqno() == SRT_SEQNO_NONE)\n+            break;\n \n-        int offset = CSeqNo::seqoff(m_iSndLastDataAck, seq);\n+        // XXX See the note above the m_iSndLastDataAck declaration in core.h\n+        // This is the place where the important sequence numbers for\n+        // sender buffer are actually managed by this field here.\n+        const int offset = CSeqNo::seqoff(m_iSndLastDataAck, w_packet.seqno());\n         if (offset < 0)\n         {\n             // XXX Likely that this will never be executed because if the upper\n             // sequence is not in the sender buffer, then most likely the loss \n             // was completely ignored.\n-            LOGC(qslog.Error, log << CONID()\n-                    << \"IPE/EPE: packLostData: LOST packet negative offset: seqoff(seqno() \"\n-                    << seq << \", m_iSndLastDataAck \" << m_iSndLastDataAck << \")=\" << offset\n-                    << \". Continue, request DROP\");\n-\n-            int32_t oldest_outdated_seq = seq;\n-            // We have received the first outdated sequence.\n-            // Loop on to find out more.\n-            // Interrupt on the first non-outdated sequence\n-            // or when the loss list gets empty.\n-\n-            for (;;)\n-            {\n-                seq = m_pSndLossList->popLostSeq();\n-                if (seq == SRT_SEQNO_NONE)\n-                {\n-                    offset = -1; // set it because this will be returned.\n-                    break;\n-                }\n-\n-                offset = CSeqNo::seqoff(m_iSndLastDataAck, seq);\n-                if (offset >= 0)\n-                    break;\n-            }\n-\n-            // Now we have 'seq' that is either non-sequence\n-            // or a valid sequence. We can safely exit with this\n-            // value from this branch. We just need to manage\n-            // the drop report.\n+            LOGC(qrlog.Error,\n+                 log << CONID() << \"IPE/EPE: packLostData: LOST packet negative offset: seqoff(seqno() \"\n+                     << w_packet.seqno() << \", m_iSndLastDataAck \" << m_iSndLastDataAck << \")=\" << offset\n+                     << \". Continue, request DROP\");\n \n             // No matter whether this is right or not (maybe the attack case should be\n             // considered, and some LOSSREPORT flood prevention), send the drop request\n             // to the peer.\n             int32_t seqpair[2] = {\n-                oldest_outdated_seq,\n+                w_packet.seqno(),\n                 CSeqNo::decseq(m_iSndLastDataAck)\n             };\n \n-            HLOGC(qslog.Debug,\n-                    log << CONID() << \"PEER reported LOSS not from the sending buffer - requesting DROP: %(\"\n-                    << seqpair[0] << \" - \" << seqpair[1] << \") (\" << (-offset) << \" packets)\");\n+            HLOGC(qrlog.Debug,\n+                  log << CONID() << \"PEER reported LOSS not from the sending buffer - requesting DROP: #\"\n+                      << MSGNO_SEQ::unwrap(w_packet.msgflags()) << \" SEQ:\" << seqpair[0] << \" - \" << seqpair[1] << \"(\"\n+                      << (-offset) << \" packets)\");\n \n             // See interpretation in processCtrlDropReq(). We don't know the message number,\n             // so we request that the drop be exclusively sequence number based.\n             int32_t msgno = SRT_MSGNO_CONTROL;\n-            sendCtrl(UMSG_DROPREQ, &msgno, seqpair, sizeof(seqpair));\n-        }\n \n-        // We have exit anyway with the right sequence or no sequence.\n-        if (seq == SRT_SEQNO_NONE)\n-            return std::make_pair(SRT_SEQNO_NONE, -1);\n-\n-        // For the right sequence though check also the right time.\n-        const steady_clock::time_point time_now = steady_clock::now();\n-        if (!checkRexmitRightTime(offset, time_now))\n-        {\n-            // Ignore this, even though valid, sequence, and pick up\n-            // the next from the list.\n+            sendCtrl(UMSG_DROPREQ, &msgno, seqpair, sizeof(seqpair));\n             continue;\n         }\n \n-        // Ok, we have what we needed one way or another.\n-        return std::make_pair(seq, offset);\n-    }\n-}\n-\n-// [[using locked (m_RecvAckLock)]]\n-bool srt::CUDT::checkRexmitRightTime(int offset, const srt::sync::steady_clock::time_point& current_time)\n-{\n-    // If not configured, the time is always right\n-    if (!m_bPeerNakReport || m_config.iRetransmitAlgo == 0)\n-        return true;\n-\n-    const steady_clock::time_point time_nak = current_time - microseconds_from(m_iSRTT - 4 * m_iRTTVar);\n-    const steady_clock::time_point tsLastRexmit = m_pSndBuffer->getPacketRexmitTime(offset);\n-\n-    if (tsLastRexmit >= time_nak)\n-    {\n-#if ENABLE_HEAVY_LOGGING\n-        ostringstream last_rextime;\n-        if (is_zero(tsLastRexmit))\n+        if (m_bPeerNakReport && m_config.iRetransmitAlgo != 0)\n         {\n-            last_rextime << \"REXMIT FIRST TIME\";\n-        }\n-        else\n-        {\n-            last_rextime << \"REXMITTED \" << FormatDuration<DUNIT_US>(current_time - tsLastRexmit)\n-                << \" ago at \" << FormatTime(tsLastRexmit);\n+            const steady_clock::time_point tsLastRexmit = m_pSndBuffer->getPacketRexmitTime(offset);\n+            if (tsLastRexmit >= time_nak)\n+            {\n+                HLOGC(qrlog.Debug, log << CONID() << \"REXMIT: ignoring seqno \"\n+                    << w_packet.seqno() << \", last rexmit \" << (is_zero(tsLastRexmit) ? \"never\" : FormatTime(tsLastRexmit))\n+                    << \" RTT=\" << m_iSRTT << \" RTTVar=\" << m_iRTTVar\n+                    << \" now=\" << FormatTime(time_now));\n+                continue;\n+            }\n         }\n-        HLOGC(qslog.Debug, log << CONID() << \"REXMIT: ignoring %\" << CSeqNo::incseq(m_iSndLastDataAck, offset)\n-                << \" \" << last_rextime.str()\n-                << \", RTT: ~\" << FormatValue(m_iSRTT, 1000, \"ms\")\n-                << \" <>\" << FormatValue(m_iRTTVar, 1000, \"\")\n-                << \" now=\" << FormatTime(current_time));\n-#endif\n-        return false;\n-    }\n \n-    return true;\n-}\n-\n-\n-// [[using locked (m_RecvAckLock)]]\n-int srt::CUDT::extractCleanRexmitPacket(int32_t seqno, int offset, CPacket& w_packet,\n-        srt::sync::steady_clock::time_point& w_tsOrigin)\n-{\n-    // REPEATABLE BLOCK (not a real loop)\n-    for (;;)\n-    {\n         typedef CSndBuffer::DropRange DropRange;\n-        DropRange buffer_drop;\n-        w_packet.set_seqno(seqno);\n \n-        const int payload = m_pSndBuffer->readData(offset, (w_packet), (w_tsOrigin), (buffer_drop));\n+        DropRange buffer_drop;\n+        steady_clock::time_point tsOrigin;\n+        const int payload = m_pSndBuffer->readData(offset, (w_packet), (tsOrigin), (buffer_drop));\n         if (payload == CSndBuffer::READ_DROP)\n         {\n             SRT_ASSERT(CSeqNo::seqoff(buffer_drop.seqno[DropRange::BEGIN], buffer_drop.seqno[DropRange::END]) >= 0);\n \n-            HLOGC(qslog.Debug,\n-                    log << CONID() << \"loss-reported packets expired in SndBuf - requesting DROP: #\"\n-                    << buffer_drop.msgno << \" %(\" << buffer_drop.seqno[DropRange::BEGIN] << \" - \"\n-                    << buffer_drop.seqno[DropRange::END] << \")\");\n+            HLOGC(qrlog.Debug,\n+                  log << CONID() << \"loss-reported packets expired in SndBuf - requesting DROP: #\"\n+                      << buffer_drop.msgno << \" %(\" << buffer_drop.seqno[DropRange::BEGIN] << \" - \"\n+                      << buffer_drop.seqno[DropRange::END] << \")\");\n             sendCtrl(UMSG_DROPREQ, &buffer_drop.msgno, buffer_drop.seqno, sizeof(buffer_drop.seqno));\n \n             // skip all dropped packets\n@@ -9885,133 +9416,43 @@ int srt::CUDT::extractCleanRexmitPacket(int32_t seqno, int offset, CPacket& w_pa\n             m_iSndCurrSeqNo = CSeqNo::maxseq(m_iSndCurrSeqNo, buffer_drop.seqno[DropRange::END]);\n             continue;\n         }\n+        else if (payload == CSndBuffer::READ_NONE)\n+            continue;\n \n-        if (payload == CSndBuffer::READ_NONE)\n+        // The packet has been ecrypted, thus the authentication tag is expected to be stored\n+        // in the SND buffer as well right after the payload.\n+        if (m_pCryptoControl && m_pCryptoControl->getCryptoMode() == CSrtConfig::CIPHER_MODE_AES_GCM)\n         {\n-            LOGC(qslog.Error, log << CONID() << \"loss-reported packet %\" << w_packet.seqno() << \" NOT FOUND in the sender buffer\");\n-            return 0;\n+            w_packet.setLength(w_packet.getLength() + HAICRYPT_AUTHTAG_MAX);\n         }\n \n-        return payload;\n-    }\n-\n-}\n-\n-int srt::CUDT::packLostData(CPacket& w_packet)\n-{\n-#if ENABLE_MAXREXMITBW\n-\n-#ifdef ENABLE_RATE_MEASUREMENT\n-#define IF_RATE_MEA(expr) expr\n-#else\n-#define IF_RATE_MEA(expr)\n-#endif\n+        // At this point we no longer need the ACK lock,\n+        // because we are going to return from the function.\n+        // Therefore unlocking in order not to block other threads.\n+        ackguard.unlock();\n \n-    // XXX NOTE: If you refactor the sender buffer so that the random access\n-    // is possible, you might be able to extract the exact packet size to\n-    // check for enough tokens and consume them in one step.\n-\n-    bool maxrexmitbw_enabled = m_config.llMaxRexmitBW >= 0;\n-    if (maxrexmitbw_enabled)\n-    {\n-        IF_RATE_MEA( IF_HEAVY_LOGGING(const int64_t iRexmitRateMeasured = m_SndRexmitMeasurement.rateBytes()); )\n-        size_t granted_size = m_zSndAveragePacketSize;\n-        size_t len = granted_size + CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE;\n+        enterCS(m_StatsLock);\n+        m_stats.sndr.sentRetrans.count(payload);\n+        leaveCS(m_StatsLock);\n \n-        if (!m_SndRexmitShaper.enoughTokens(len))\n+        // Despite the contextual interpretation of packet.m_iMsgNo around\n+        // CSndBuffer::readData version 2 (version 1 doesn't return -1), in this particular\n+        // case we can be sure that this is exactly the value of PH_MSGNO as a bitset.\n+        // So, set here the rexmit flag if the peer understands it.\n+        if (m_bPeerRexmitFlag)\n         {\n-            HLOGC(qslog.Debug, log << \"REXMIT-SH: BLOCKED pkt est/len=\" << len << \" exceeds \" << m_SndRexmitShaper.ntokens()\n-                    << \" tokens, rate/Bps:used=\" << m_SndRexmitShaper.usedRate_Bps() << \",avail=\" << m_SndRexmitShaper.availRate_Bps()\n-                    IF_RATE_MEA( << \" (measured: \" << FormatValue(iRexmitRateMeasured, 1024, \"kBps\") << \")\" )\n-                 );\n-            return 0;\n+            w_packet.set_msgflags(w_packet.msgflags() | PACKET_SND_REXMIT);\n         }\n-\n-        HLOGC(qslog.Debug, log << \"REXMIT-SH: ALLOWED pkt est/len=\" << len << \" allowed, budget \" << m_SndRexmitShaper.ntokens()\n-                << \" tokens, rate/Bps:used=\" << m_SndRexmitShaper.usedRate_Bps() << \",avail=\" << m_SndRexmitShaper.availRate_Bps()\n-                IF_RATE_MEA( << \" (measured: \" << FormatValue(iRexmitRateMeasured, 1024, \"kBps\") << \")\" )\n-             );\n-    }\n-\n-#undef IF_RATE_MEA\n-#endif\n-\n-    // Original sending time of the packet, to be stamped after filling.\n-    steady_clock::time_point tsOrigin;\n-\n-    {\n-        // protect m_iSndLastDataAck from updating by ACK processing\n-        ScopedLock ackguard(m_RecvAckLock);\n-        int32_t seqno;\n-        int offset;\n-\n-        // Get the first sequence for retransmission, bypassing and taking care of\n-        // those that are in the forgotten region, as well as required to be rejected.\n-        Tie2(seqno, offset) = getCleanRexmitOffset();\n-\n-        if (seqno == SRT_SEQNO_NONE)\n-            return 0;\n-\n-        // Extract the packet from the sender buffer that is mapped to the expected sequence\n-        // number, bypassing and taking care of those that are decided to be dropped.\n-        const int payload = extractCleanRexmitPacket(seqno, offset, (w_packet), (tsOrigin));\n-        if (payload <= 0)\n-            return 0;\n-    }\n-\n-    HLOGC(qslog.Debug, log << CONID() << \"packed REXMIT packet %\" << w_packet.seqno() << \" size=\" << w_packet.getLength()\n-            << \" - still \" << m_pSndLossList->getLossLength() << \" LOSS ENTRIES left\");\n-\n-    // POST-EXTRACTION length fixes.\n-\n-    // The packet has been ecrypted, thus the authentication tag is expected to be stored\n-    // in the SND buffer as well right after the payload.\n-    if (m_pCryptoControl && m_pCryptoControl->getCryptoMode() == CSrtConfig::CIPHER_MODE_AES_GCM)\n-    {\n-        w_packet.setLength(w_packet.getLength() + HAICRYPT_AUTHTAG_MAX);\n-    }\n-\n-#if ENABLE_MAXREXMITBW\n-    if (maxrexmitbw_enabled)\n-    {\n-        // Token consumption will only happen when the retransmission\n-        // effectively happens.\n-        // XXX NOTE: In version 1.6.0 use the IP-version dependent value for UDP_HDR_SIZE\n-        size_t network_size = w_packet.getLength() + CPacket::HDR_SIZE + CPacket::UDP_HDR_SIZE;\n-        m_SndRexmitShaper.consumeTokens(network_size);\n-        HLOGC(qslog.Debug, log << \"REXMIT-SH: consumed \" << network_size << \" tokens, remain \" << m_SndRexmitShaper.ntokens());\n-    }\n-#endif\n-\n-    enterCS(m_StatsLock);\n-    m_stats.sndr.sentRetrans.count(w_packet.getLength());\n-    leaveCS(m_StatsLock);\n-\n-    // Despite the contextual interpretation of packet.m_iMsgNo around\n-    // CSndBuffer::readData version 2 (version 1 doesn't return -1), in this particular\n-    // case we can be sure that this is exactly the value of PH_MSGNO as a bitset.\n-    // So, set here the rexmit flag if the peer understands it.\n-    if (m_bPeerRexmitFlag)\n-    {\n-        w_packet.set_msgflags(w_packet.msgflags() | PACKET_SND_REXMIT);\n-    }\n-    setDataPacketTS(w_packet, tsOrigin);\n+        setDataPacketTS(w_packet, tsOrigin);\n \n #ifdef ENABLE_MAXREXMITBW\n-    // XXX OLD rexmit measurement\n-    // m_SndRexmitRate.addSample(time_now, 1, w_packet.getLength());\n+        m_SndRexmitRate.addSample(time_now, 1, w_packet.getLength());\n #endif\n \n-    // XXX Consider calculating the total packet length once you have a possibility\n-    // to get the in-connection used IP version.\n-#ifdef ENABLE_RATE_MEASUREMENT\n-    m_SndRexmitMeasurement.dataUpdate(1, w_packet.getLength());\n-    HLOGC(bslog.Debug, log << \"RateMeasurement: REXMIT, pkt-size=\" << w_packet.getLength()\n-            << \" - COLLECTED pkts=\" << m_SndRexmitMeasurement.m_nInstaPackets\n-            << \" bytes=\" << m_SndRexmitMeasurement.m_nInstaBytes);\n-#endif\n+        return payload;\n+    }\n \n-    return w_packet.getLength();\n+    return 0;\n }\n \n #if SRT_DEBUG_TRACE_SND\n@@ -10136,68 +9577,14 @@ void srt::CUDT::setDataPacketTS(CPacket& p, const time_point& ts)\n     p.set_timestamp(makeTS(ts, tsStart));\n }\n \n-bool srt::CUDT::isRegularSendingPriority()\n+bool srt::CUDT::isRetransmissionAllowed(const time_point& tnow SRT_ATR_UNUSED)\n {\n-    // In order to have regular packets take precedence over retransmitted:\n-    // - SRTO_TLPKTDROP = true\n-    // - SRTO_MESSAGEAPI = true\n-    // NOTE:\n-    // - tlpktdrop is ignored in stream mode\n-    // - messageapi without tlpktdrop is possible in non-live message mode\n-    // - Live mode without tlpktdrop is possible and in this mode also the\n-    //   retransmitted packets should have priority.\n+    // Prioritization of original packets only applies to Live CC.\n     if (!m_bPeerTLPktDrop || !m_config.bMessageAPI)\n-        return false;\n-\n-    // XXX NOTE: the current solution is simple - the regular packet takes precedence\n-    // over a retransmitted packet, if there is at least one such packet already\n-    // scheduled.\n-    //\n-    // This probably isn't the most wanted solution, some more elaborate condition\n-    // might be better in some situations. For example, it should be acceptable\n-    // that a packet that has very little time to be recovered is sent before a\n-    // regular packet that has still STT + Latency time to deliver. The regular\n-    // packets should still be favored, but not necessarily at the expense of\n-    // dismissing a recovery chance that wouldn't endanger the delivery of a regular\n-    // packet. Criteria might be various, for example, the number of scheduled\n-    // packets and their late delivery time might be taken into account.\n-    const time_point tsNextPacket = m_pSndBuffer->peekNextOriginal();\n-\n-    if (tsNextPacket != time_point())\n-    {\n-        // Have regular packet and we decided they have a priority.\n-        HLOGC(qslog.Debug, log << \"REXMIT-SH: BLOCKED because regular packets have priority\");\n         return true;\n-    }\n-    return false;\n-}\n-\n-namespace srt {\n-#ifdef ENABLE_MAXREXMITBW\n-static sync::steady_clock::duration optimisticSingleTripDuration(int rttval, int rttvar)\n-{\n-    int lowrtt = rttval - rttvar;\n-    if (lowrtt < 0) // bullshit?\n-        lowrtt = rttval;\n-\n-    int stt = lowrtt/2;\n-\n-    // Make sure that burst period has at least this value\n-    sync::steady_clock::duration stt_td = sync::microseconds_from(stt);\n-\n-    // Still, prevent from setting enormous STT values\n-    if (stt_td < sync::seconds_from(4))\n-    {\n-        return stt_td;\n-    }\n-    return sync::steady_clock::duration();\n-}\n-#endif\n-}\n \n-void srt::CUDT::updateSenderMeasurements(bool can_rexmit SRT_ATR_UNUSED)\n-{\n-    const time_point tnow SRT_ATR_UNUSED = steady_clock::now();\n+    // TODO: lock sender buffer?\n+    const time_point tsNextPacket = m_pSndBuffer->peekNextOriginal();\n \n #if SRT_DEBUG_TRACE_SND\n     const int buffdelay_ms = count_milliseconds(m_pSndBuffer->getBufferingDelay(tnow));\n@@ -10214,37 +9601,31 @@ void srt::CUDT::updateSenderMeasurements(bool can_rexmit SRT_ATR_UNUSED)\n     g_snd_logger.state.msTimespanTh = threshold_ms_min;\n     g_snd_logger.state.msNextUniqueToSend = msNextUniqueToSend;\n     g_snd_logger.state.usElapsedLastDrop = count_microseconds(tnow - m_tsLastTLDrop);\n-    g_snd_logger.state.canRexmit = can_rexmit;\n+    g_snd_logger.state.canRexmit = false;\n #endif\n \n+    if (tsNextPacket != time_point())\n+    {\n+        // Can send original packet, so just send it\n+        return false;\n+    }\n+\n #ifdef ENABLE_MAXREXMITBW\n-    /* OLD rate estimator; CODE for packLostData()! \n     m_SndRexmitRate.addSample(tnow, 0, 0); // Update the estimation.\n     const int64_t iRexmitRateBps = m_SndRexmitRate.getRate();\n+    const int64_t iRexmitRateLimitBps = m_config.llMaxRexmitBW;\n     if (iRexmitRateLimitBps >= 0 && iRexmitRateBps > iRexmitRateLimitBps)\n     {\n         // Too many retransmissions, so don't send anything.\n         // TODO: When to wake up next time?\n         return false;\n     }\n-    */\n-    const int64_t iRexmitRateLimitBps = m_config.llMaxRexmitBW;\n-    if (iRexmitRateLimitBps >= 0)\n-    {\n-        int b4_tokens SRT_ATR_UNUSED = m_SndRexmitShaper.ntokens();\n-        m_SndRexmitShaper.setBitrate(iRexmitRateLimitBps);\n-        duration stt_td = optimisticSingleTripDuration(m_iSRTT, m_iRTTVar);\n-        if (stt_td != duration())\n-            m_SndRexmitShaper.setMinimumBurstPeriod(stt_td);\n-        m_SndRexmitShaper.tick(tnow);\n-        int a4_tokens SRT_ATR_UNUSED = m_SndRexmitShaper.ntokens();\n-\n-        HLOGC(qslog.Debug, log << \"REXMIT-SW: tick tokens updated: \" << b4_tokens << \" -> \" << a4_tokens\n-                << \"/\" << m_SndRexmitShaper.maxTokens() << \" period=\"\n-                << FormatDuration<DUNIT_MS>(m_SndRexmitShaper.burstPeriod()));\n-    }\n #endif\n \n+#if SRT_DEBUG_TRACE_SND\n+    g_snd_logger.state.canRexmit = true;\n+#endif\n+    return true;\n }\n \n bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime, sockaddr_any& w_src_addr)\n@@ -10273,25 +9654,9 @@ bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime\n     if (!m_bOpened)\n         return false;\n \n-    // This function returns true if there is a regular packet candidate waiting\n-    // for being sent and sending this packet has a prioriry over retransmission candidate.\n-    if (!isRegularSendingPriority())\n-    {\n-        payload = packLostData((w_packet));\n-#if ENABLE_MAXREXMITBW\n-        if (payload == 0)\n-        {\n-            HLOGC(qslog.Debug, log << \"REXMIT-SH: no rexmit required, remain \" << m_SndRexmitShaper.ntokens() << \" tokens\");\n-        }\n-#endif\n-    }\n-    else\n-    {\n-        HLOGC(qslog.Debug, log << \"REXMIT: retransmission SUPERSEDED, proceed with regular candidate\");\n-    }\n-\n-    // Updates the data that will be next used in packLostData() in next calls.\n-    updateSenderMeasurements(payload != 0);\n+    payload = isRetransmissionAllowed(enter_time)\n+        ? packLostData((w_packet))\n+        : 0;\n \n     IF_HEAVY_LOGGING(const char* reason); // The source of the data packet (normal/rexmit/filter)\n     if (payload > 0)\n@@ -10317,18 +9682,6 @@ bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime\n             m_tdSendTimeDiff = steady_clock::duration();\n             return false;\n         }\n-\n-#if ENABLE_MAXREXMITBW\n-        if (m_zSndAveragePacketSize > 0)\n-        {\n-            m_zSndAveragePacketSize = avg_iir<16>(m_zSndAveragePacketSize, w_packet.getLength());\n-        }\n-        else\n-        {\n-            m_zSndAveragePacketSize = w_packet.getLength();\n-        }\n-        m_zSndMaxPacketSize = std::max(m_zSndMaxPacketSize, w_packet.getLength());\n-#endif\n         new_packet_packed = true;\n \n         // every 16 (0xF) packets, a packet pair is sent\n@@ -10565,11 +9918,6 @@ bool srt::CUDT::packUniqueData(CPacket& w_packet)\n     g_snd_logger.trace();\n #endif\n \n-#ifdef ENABLE_RATE_MEASUREMENT\n-    HLOGC(bslog.Debug, log << \"RATE-MEASUREMENT: REGULAR, pkt-size=\" << w_packet.getLength());\n-    m_SndRegularMeasurement.dataUpdate(1, w_packet.getLength());\n-#endif\n-\n     return true;\n }\n \n@@ -10583,7 +9931,7 @@ void srt::CUDT::processClose()\n     m_bBroken        = true;\n     m_iBrokenCounter = 60;\n \n-    HLOGP(smlog.Debug, \"processClose: (closing=true) sent message and set flags\");\n+    HLOGP(smlog.Debug, \"processClose: sent message and set flags\");\n \n     if (m_bTsbPd)\n     {\n@@ -10630,7 +9978,7 @@ void srt::CUDT::sendLossReport(const std::vector<std::pair<int32_t, int32_t> > &\n bool srt::CUDT::overrideSndSeqNo(int32_t seq)\n {\n     // This function is intended to be called from the socket\n-    // group management functions to synchronize the sequence in\n+    // group management functions to synchronize the sequnece in\n     // all sockes in the bonding group. THIS sequence given\n     // here is the sequence TO BE STAMPED AT THE EXACTLY NEXT\n     // sent payload. Therefore, screw up the ISN to exactly this\n@@ -10815,7 +10163,6 @@ int srt::CUDT::handleSocketPacketReception(const vector<CUnit*>& incoming, bool&\n             }\n         }\n \n-        bool decrypt_successful = false;\n         const int buffer_add_result = m_pRcvBuffer->insert(u);\n         if (buffer_add_result < 0)\n         {\n@@ -10876,12 +10223,8 @@ int srt::CUDT::handleSocketPacketReception(const vector<CUnit*>& incoming, bool&\n                     }\n #endif\n                 }\n-                else\n-                {\n-                    decrypt_successful = true;\n-                }\n             }\n-            else if (m_pCryptoControl && m_pCryptoControl->m_RcvKmState != SRT_KM_S_UNSECURED)\n+            else if (m_pCryptoControl && m_pCryptoControl->m_RcvKmState == SRT_KM_S_SECURED)\n             {\n                 // Unencrypted packets are not allowed.\n                 const int iDropCnt = m_pRcvBuffer->dropMessage(u->m_Packet.getSeqNo(), u->m_Packet.getSeqNo(), SRT_MSGNO_NONE, CRcvBuffer::DROP_EXISTING);\n@@ -10960,10 +10303,6 @@ int srt::CUDT::handleSocketPacketReception(const vector<CUnit*>& incoming, bool&\n         if (CSeqNo::seqcmp(rpkt.seqno(), m_iRcvCurrSeqNo) > 0)\n         {\n             m_iRcvCurrSeqNo = rpkt.seqno(); // Latest possible received\n-            if (decrypt_successful && m_pCryptoControl)\n-            {\n-                m_pCryptoControl->m_CurrentKey = rpkt.getMsgCryptoFlags();\n-            }\n         }\n         else\n         {\n@@ -11119,7 +10458,7 @@ int srt::CUDT::processData(CUnit* in_unit)\n     // reception sequence pointer stating that this link is not receiving.\n     if (m_parent->m_GroupOf)\n     {\n-        ExclusiveLock protect_group_existence (uglobal().m_GlobControlLock);\n+        ScopedLock protect_group_existence (uglobal().m_GlobControlLock);\n         groups::SocketData* gi = m_parent->m_GroupMemberData;\n \n         // This check is needed as after getting the lock the socket\n@@ -11128,7 +10467,7 @@ int srt::CUDT::processData(CUnit* in_unit)\n         // this socket as member (that is, 'gi' cannot be a dangling pointer).\n         if (gi != NULL)\n         {\n-            if (gi->rcvstate < SRT_GST_RUNNING) // PENDING or IDLE, though PENDING is unlikely\n+            if (gi->rcvstate < SRT_GST_RUNNING) // PENDING or IDLE, tho PENDING is unlikely\n             {\n                 HLOGC(qrlog.Debug,\n                       log << CONID() << \"processData: IN-GROUP rcv state transition \" << srt_log_grp_state[gi->rcvstate]\n@@ -11306,7 +10645,7 @@ int srt::CUDT::processData(CUnit* in_unit)\n     //    If so, send the loss report and remove this element.\n     //  - Since the first element that has TTL>0, iterate until the end of container and decrease TTL.\n     //\n-    // This will be efficient because the loop to increment one field (without any condition check)\n+    // This will be efficient becase the loop to increment one field (without any condition check)\n     // can be quite well optimized.\n \n     vector<int32_t> lossdata;\n@@ -11729,7 +11068,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet)\n         return m_RejectReason;\n     }\n \n-    // Don't know why the original UDT4 code only MUCH LATER was checking if the packet was UMSG_HANDSHAKE.\n+    // Dunno why the original UDT4 code only MUCH LATER was checking if the packet was UMSG_HANDSHAKE.\n     // It doesn't seem to make sense to deserialize it into the handshake structure if we are not\n     // sure that the packet contains the handshake at all!\n     if (!packet.isControl(UMSG_HANDSHAKE))\n@@ -11959,7 +11298,7 @@ int srt::CUDT::processConnectRequest(const sockaddr_any& addr, CPacket& packet)\n             if (conn != CONN_ACCEPT)\n                 return conn;\n \n-            packet.setLength(controlPayloadSize(addr.family()));\n+            packet.setLength(m_iMaxSRTPayloadSize);\n             if (!acpu->createSrtHandshake(SRT_CMD_HSRSP, SRT_CMD_KMRSP,\n                         kmdata, kmdatasize,\n                         (packet), (hs)))\n@@ -12308,11 +11647,6 @@ void srt::CUDT::checkTimers()\n         << \" pkt-count=\" << m_iPktCount << \" liteack-count=\" << m_iLightACKCount);\n #endif\n \n-#ifdef ENABLE_RATE_MEASUREMENT\n-    m_SndRegularMeasurement.pickup(currtime);\n-    m_SndRexmitMeasurement.pickup(currtime);\n-#endif\n-\n     // Check if it is time to send ACK\n     int debug_decision = checkACKTimer(currtime);\n \n@@ -12332,7 +11666,7 @@ void srt::CUDT::checkTimers()\n #if ENABLE_BONDING\n         if (m_parent->m_GroupOf)\n         {\n-            SharedLock glock (uglobal().m_GlobControlLock);\n+            ScopedLock glock (uglobal().m_GlobControlLock);\n             if (m_parent->m_GroupOf)\n             {\n                 // Pass socket ID because it's about changing group socket data\n@@ -12349,7 +11683,6 @@ void srt::CUDT::checkTimers()\n \n void srt::CUDT::updateBrokenConnection()\n {\n-    HLOGC(smlog.Debug, log << \"updateBrokenConnection: setting closing=true and taking out epoll events\");\n     m_bClosing = true;\n     releaseSynch();\n     // app can call any UDT API to learn the connection_broken error\n@@ -12364,7 +11697,7 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode)\n #if ENABLE_BONDING\n     bool pending_broken = false;\n     {\n-        SharedLock guard_group_existence (uglobal().m_GlobControlLock);\n+        ScopedLock guard_group_existence (uglobal().m_GlobControlLock);\n         if (m_parent->m_GroupOf)\n         {\n             token = m_parent->m_GroupMemberData->token;\n@@ -12399,7 +11732,7 @@ void srt::CUDT::completeBrokenConnectionDependencies(int errorcode)\n         // existence of the group will not be changed during\n         // the operation. The attempt of group deletion will\n         // have to wait until this operation completes.\n-        ExclusiveLock lock(uglobal().m_GlobControlLock);\n+        ScopedLock lock(uglobal().m_GlobControlLock);\n         CUDTGroup* pg = m_parent->m_GroupOf;\n         if (pg)\n         {\n@@ -12536,7 +11869,7 @@ int64_t srt::CUDT::socketStartTime(SRTSOCKET u)\n     if (!s)\n         return APIError(MJ_NOTSUP, MN_SIDINVAL);\n \n-    return count_microseconds(s->core().socketStartTime().time_since_epoch());\n+    return count_microseconds(s->core().m_stats.tsStartTime.time_since_epoch());\n }\n \n bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShake& hs, const CPacket& hspkt)\n@@ -12579,7 +11912,7 @@ bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShak\n                 if (!bytelen || bytelen > CSrtConfig::MAX_SID_LENGTH)\n                 {\n                     LOGC(cnlog.Error,\n-                         log << CONID() << FUNID() << \": STREAMID length \" << bytelen << \" is 0 or > \"\n+                         log << CONID() << \"interpretSrtHandshake: STREAMID length \" << bytelen << \" is 0 or > \"\n                              << +CSrtConfig::MAX_SID_LENGTH << \" - PROTOCOL ERROR, REJECTING\");\n                     return false;\n                 }\n@@ -12644,7 +11977,7 @@ bool srt::CUDT::runAcceptHook(CUDT *acore, const sockaddr* peer, const CHandShak\n     return true;\n }\n \n-bool srt::CUDT::processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival)\n+void srt::CUDT::processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival)\n {\n     // Here can be handled some protocol definition\n     // for extra data sent through keepalive.\n@@ -12657,7 +11990,7 @@ bool srt::CUDT::processKeepalive(const CPacket& ctrlpkt, const time_point& tsArr\n         // existence of the group will not be changed during\n         // the operation. The attempt of group deletion will\n         // have to wait until this operation completes.\n-        ExclusiveLock lock(uglobal().m_GlobControlLock);\n+        ScopedLock lock(uglobal().m_GlobControlLock);\n         CUDTGroup* pg = m_parent->m_GroupOf;\n         if (pg)\n         {\n@@ -12673,21 +12006,4 @@ bool srt::CUDT::processKeepalive(const CPacket& ctrlpkt, const time_point& tsArr\n     m_pRcvBuffer->updateTsbPdTimeBase(ctrlpkt.getMsgTimeStamp());\n     if (m_config.bDriftTracer)\n         m_pRcvBuffer->addRcvTsbPdDriftSample(ctrlpkt.getMsgTimeStamp(), tsArrival, -1);\n-\n-    return true;\n-}\n-\n-namespace srt {\n-HandshakeSide getHandshakeSide(SRTSOCKET u)\n-{\n-    return CUDT::handshakeSide(u);\n }\n-\n-HandshakeSide CUDT::handshakeSide(SRTSOCKET u)\n-{\n-    CUDTSocket *s = uglobal().locateSocket(u);\n-    return s ? s->core().handshakeSide() : HSD_DRAW;\n-}\n-}\n-\n-\ndiff --git a/srtcore/core.h b/srtcore/core.h\nindex fb9f733..ed250c6 100644\n--- a/srtcore/core.h\n+++ b/srtcore/core.h\n@@ -149,142 +149,16 @@ enum SeqPairItems\n };\n \n \n+// Extended SRT Congestion control class - only an incomplete definition required\n+class CCryptoControl;\n \n namespace srt {\n-class CCryptoControl;\n class CUDTUnited;\n class CUDTSocket;\n #if ENABLE_BONDING\n class CUDTGroup;\n #endif\n \n-#ifdef ENABLE_RATE_MEASUREMENT\n-struct RateMeasurement\n-{\n-    typedef sync::steady_clock clock_type;\n-    typedef clock_type::time_point clock_time;\n-    typedef clock_type::duration clock_interval;\n-\n-    static const int SLICE_INTERVAL_MS = 20;\n-    static const size_t MIN_SLICES = 5; // min \n-    static const size_t MAX_SLICES = 10;\n-\n-    sync::Mutex m_lock;\n-\n-    size_t m_SysHeaderSize;\n-\n-    // Instantaneous data updated by sending packets\n-    // AFFINITY: Snd:worker thread\n-    // MODE: write\n-    sync::atomic<int> m_nInstaPackets;\n-    sync::atomic<int> m_nInstaBytes;\n-\n-    void dataUpdate(int packets, int bytes)\n-    {\n-        sync::ScopedLock lk (m_lock);\n-        m_nInstaPackets = m_nInstaPackets + packets;\n-        m_nInstaBytes = m_nInstaBytes + bytes;\n-    }\n-\n-    // Cached last measurement\n-    // AFFINITY: Snd:worker thread MODE: read\n-    // AFFINITY: Rcv:worker thread MODE: write\n-    // (not locking because one data is updated at a time).\n-    sync::atomic<int64_t> m_currentPktRate;\n-    sync::atomic<int64_t> m_currentByteRate;\n-    int64_t rateBytes() const\n-    {\n-        return m_currentByteRate;\n-    }\n-    int64_t ratePackets() const\n-    {\n-        return m_currentPktRate;\n-    }\n-\n-    // Time of the last checkpoint or initialization\n-    clock_time m_beginTime;\n-\n-    struct Slice\n-    {\n-        int packets;\n-        int bytes;\n-        clock_time begin_time;\n-\n-        Slice(): packets(0), bytes(0) {} // clock_time is non-POD\n-        Slice(const clock_time& t): packets(0), bytes(0), begin_time(t) {}\n-\n-    };\n-\n-    struct Summary: Slice\n-    {\n-        Summary(const clock_time& earliest_time): Slice(earliest_time), nsamples(0) {}\n-\n-        unsigned char nsamples;\n-\n-        void consume(const Slice& another)\n-        {\n-            if (is_zero(begin_time))\n-                begin_time = another.begin_time;\n-            packets += another.packets;\n-            bytes += another.bytes;\n-            nsamples++;\n-        }\n-\n-        int64_t ratePackets(const clock_time& end_time) const\n-        {\n-            double packets_per_micro = double(packets) * 1000 * 1000;\n-            double rate = packets_per_micro / count_microseconds(end_time - begin_time);\n-            return rate;\n-        }\n-\n-        int64_t rateBytes(const clock_time& end_time, size_t hdr_size) const\n-        {\n-            double data_bytes = bytes + (packets * hdr_size);\n-            double bytes_per_micro = data_bytes * 1000 * 1000;\n-            double rate = bytes_per_micro / count_microseconds(end_time - begin_time);\n-            return rate;\n-        }\n-    };\n-\n-    std::deque<Slice> m_slices;\n-\n-    RateMeasurement():\n-        m_SysHeaderSize(CPacket::UDP_HDR_SIZE), // XXX NOTE: IPv4 !\n-        m_nInstaPackets(0),\n-        m_nInstaBytes(0),\n-        m_currentPktRate(0),\n-        m_currentByteRate(0)\n-    {\n-    }\n-\n-    bool passedInterval(const clock_time& this_time, clock_interval& w_interval)\n-    {\n-        if (is_zero(m_beginTime))\n-        {\n-            sync::ScopedLock lk (m_lock);\n-            m_beginTime = this_time;\n-            w_interval = clock_interval(0);\n-            return false;\n-        }\n-        w_interval = this_time - m_beginTime;\n-        return (sync::count_milliseconds(w_interval) > SLICE_INTERVAL_MS);\n-    }\n-\n-    // This is to be called in constructor, only once.\n-    void init(const clock_time& time, size_t sys_hdr_size)\n-    {\n-        // Just formally.\n-        sync::ScopedLock lk (m_lock);\n-        m_beginTime = time;\n-        m_SysHeaderSize = sys_hdr_size;\n-    }\n-\n-    // AFFINITY: Rcv:worker thread (update thread)\n-    // This function should be called in regular time periods.\n-    void pickup(const clock_time& time);\n-};\n-#endif\n-\n // XXX REFACTOR: The 'CUDT' class is to be merged with 'CUDTSocket'.\n // There's no reason for separating them, there's no case of having them\n // anyhow managed separately. After this is done, with a small help with\n@@ -306,14 +180,13 @@ class CUDT\n     friend class PacketFilter;\n     friend class CUDTGroup;\n     friend class TestMockCUDT; // unit tests\n-    friend class TestMockControlPackets; // unit tests\n \n     typedef sync::steady_clock::time_point time_point;\n     typedef sync::steady_clock::duration duration;\n     typedef sync::AtomicClock<sync::steady_clock> atomic_time_point;\n     typedef sync::AtomicDuration<sync::steady_clock> atomic_duration;\n \n-private: // constructor and destructor\n+private: // constructor and desctructor\n     void construct();\n     void clearData();\n     CUDT(CUDTSocket* parent);\n@@ -324,7 +197,6 @@ private: // constructor and destructor\n public: //API\n     static int startup();\n     static int cleanup();\n-    static int cleanupAtFork();\n     static SRTSOCKET socket();\n #if ENABLE_BONDING\n     static SRTSOCKET createGroup(SRT_GROUP_TYPE);\n@@ -421,17 +293,6 @@ public: // internal API\n         return m_ConnRes.m_iVersion;\n     }\n \n-    int32_t handshakeCookie()\n-    {\n-        return m_ConnReq.m_iCookie;\n-    }\n-\n-    static HandshakeSide handshakeSide(SRTSOCKET u);\n-    HandshakeSide handshakeSide()\n-    {\n-        return m_SrtHsSide;\n-    }\n-\n     std::string CONID() const\n     {\n #if ENABLE_LOGGING\n@@ -475,7 +336,7 @@ public: // internal API\n \n     uint32_t        peerLatency_us()        const { return m_iPeerTsbPdDelay_ms * 1000; }\n     int             peerIdleTimeout_ms()    const { return m_config.iPeerIdleTimeout_ms; }\n-    size_t          maxDataPayloadSize()    const { return m_iMaxDataPayloadSize; }\n+    size_t          maxPayloadSize()        const { return m_iMaxSRTPayloadSize; }\n     size_t          OPT_PayloadSize()       const { return m_config.zExpPayloadSize; }\n     size_t          payloadSize()           const\n     {\n@@ -488,7 +349,7 @@ public: // internal API\n \n         // If SRTO_PAYLOADSIZE was remaining with 0 (default for FILE mode)\n         // then return the maximum payload size per packet.\n-        return m_iMaxDataPayloadSize;\n+        return m_iMaxSRTPayloadSize;\n     }\n \n     int             sndLossLength()               { return m_pSndLossList->getLossLength(); }\n@@ -536,21 +397,12 @@ public: // internal API\n \n     int minSndSize(int len = 0) const\n     {\n-        const int ps = (int) maxDataPayloadSize();\n+        const int ps = (int) maxPayloadSize();\n         if (len == 0) // weird, can't use non-static data member as default argument!\n             len = ps;\n         return m_config.bMessageAPI ? (len+ps-1)/ps : 1;\n     }\n \n-    // This returns the biggest possible size for an SRT payload with\n-    // the default 1500 MTU size. When in doubt, use AF_INET, which returns\n-    // bigger size, if needed for a safe allocation.\n-    static int controlPayloadSize(int family = AF_INET)\n-    {\n-        int header = family == AF_INET6 ? CPacket::UDP_HDR_SIZE_IPv6 : CPacket::UDP_HDR_SIZE;\n-        return CPacket::ETH_MAX_MTU_SIZE - header;\n-    }\n-\n     static int32_t makeTS(const time_point& from_time, const time_point& tsStartTime)\n     {\n         // NOTE:\n@@ -584,6 +436,7 @@ public: // internal API\n     // immediately to free the socket\n     void notListening()\n     {\n+        sync::ScopedLock cg(m_ConnectionLock);\n         m_bListening = false;\n         m_pRcvQueue->removeListener(this);\n     }\n@@ -729,14 +582,11 @@ private:\n     SRT_ATTR_REQUIRES2(m_RecvAckLock, m_StatsLock)\n     int sndDropTooLate();\n \n-    // Returns true if there is a regular packet waiting for sending\n-    // and sending regular packets has priority over retransmitted ones.\n-    bool isRegularSendingPriority();\n-\n-    // Performs updates in the measurement variables after possible\n-    // extraction of a retransmission packet. Some are for debug purposes,\n-    // others for retransmission rate measurement.\n-    void updateSenderMeasurements(bool can_rexmit);\n+    /// @bried Allow packet retransmission.\n+    /// Depending on the configuration mode (live / file), retransmission\n+    /// can be blocked if e.g. there are original packets pending to be sent.\n+    /// @return true if retransmission is allowed; false otherwise.\n+    bool isRetransmissionAllowed(const time_point& tnow);\n \n     /// Connect to a UDT entity as per hs request. This will update\n     /// required data in the entity, then update them also in the hs structure,\n@@ -755,7 +605,6 @@ private:\n     /// Close the opened UDT entity.\n \n     bool closeInternal() ATR_NOEXCEPT;\n-    bool closeAtFork() ATR_NOEXCEPT;\n     void updateBrokenConnection();\n     void completeBrokenConnectionDependencies(int errorcode);\n \n@@ -888,7 +737,7 @@ private:\n \n     int sndSpaceLeft()\n     {\n-        return static_cast<int>(sndBuffersLeft() * maxDataPayloadSize());\n+        return static_cast<int>(sndBuffersLeft() * maxPayloadSize());\n     }\n \n     int sndBuffersLeft()\n@@ -898,7 +747,6 @@ private:\n \n     time_point socketStartTime()\n     {\n-        sync::ScopedLock lk (m_StatsLock);\n         return m_stats.tsStartTime;\n     }\n \n@@ -955,7 +803,7 @@ private: // Identification\n #endif\n \n private:\n-    int                       m_iMaxDataPayloadSize;    // Maximum data payload size, in bytes\n+    int                       m_iMaxSRTPayloadSize;     // Maximum/regular payload size, in bytes\n     int                       m_iTsbPdDelay_ms;         // Rx delay to absorb burst, in milliseconds\n     int                       m_iPeerTsbPdDelay_ms;     // Tx delay that the peer uses to absorb burst, in milliseconds\n     bool                      m_bTLPktDrop;             // Enable Too-late Packet Drop\n@@ -981,7 +829,6 @@ private:\n     sync::atomic<bool> m_bConnected;             // Whether the connection is on or off\n     sync::atomic<bool> m_bClosing;               // If the UDT entity is closing\n     sync::atomic<bool> m_bShutdown;              // If the peer side has shutdown the connection\n-    sync::atomic<bool> m_bBreaking;              // The flag that declares interrupt of the connecting process\n     sync::atomic<bool> m_bBroken;                // If the connection has been broken\n     sync::atomic<bool> m_bBreakAsUnstable;       // A flag indicating that the socket should become broken because it has been unstable for too long.\n     sync::atomic<bool> m_bPeerHealth;            // If the peer status is normal\n@@ -1013,16 +860,7 @@ private: // Sending related data\n     CSndLossList* m_pSndLossList;                // Sender loss list\n     CPktTimeWindow<16, 16> m_SndTimeWindow;      // Packet sending time window\n #ifdef ENABLE_MAXREXMITBW\n-    size_t m_zSndAveragePacketSize;\n-    size_t m_zSndMaxPacketSize;\n-    // XXX Old rate estimator for rexmit\n-    // CSndRateEstimator m_SndRexmitRate;      // Retransmission rate estimation.\n-    CShaper m_SndRexmitShaper;\n-\n-#ifdef ENABLE_RATE_MEASUREMENT\n-    RateMeasurement   m_SndRegularMeasurement;   // Regular rate measurement\n-    RateMeasurement   m_SndRexmitMeasurement;    // Retransmission rate measurement\n-#endif\n+    CSndRateEstimator      m_SndRexmitRate;      // Retransmission rate estimation.\n #endif\n \n     atomic_duration m_tdSendInterval;            // Inter-packet time, in CPU clock cycles\n@@ -1170,8 +1008,6 @@ private: // Receiving related data\n public:\n     static int installAcceptHook(SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq);\n     static int installConnectHook(SRTSOCKET lsn, srt_connect_callback_fn* hook, void* opaq);\n-    static enum HandshakeSide compareCookies(int32_t req, int32_t res);\n-    static enum HandshakeSide backwardCompatibleCookieContest(int32_t req, int32_t res);\n private:\n     void installAcceptHook(srt_listen_callback_fn* hook, void* opaq)\n     {\n@@ -1209,7 +1045,6 @@ private: // synchronization: mutexes and conditions\n \n     void initSynch();\n     void destroySynch();\n-    void resetAtFork();\n     void releaseSynch();\n \n private: // Common connection Congestion Control setup\n@@ -1234,42 +1069,42 @@ private: // Generation and processing of packets\n     /// Forms and sends ACK packet\n     /// @note Assumes @ctrlpkt already has a timestamp.\n     ///\n-    /// @param ctrlpkt  A control packet structure to fill. It must have a timestamp already set.\n+    /// @param ctrlpkt  A control packet structure to fill. It must have a timestemp already set.\n     /// @param size     Sends lite ACK if size is SEND_LITE_ACK, Full ACK otherwise\n     ///\n-    /// @returns the number of packets sent.\n+    /// @returns the nmber of packets sent.\n     int  sendCtrlAck(CPacket& ctrlpkt, int size);\n     void sendLossReport(const std::vector< std::pair<int32_t, int32_t> >& losslist);\n \n-    bool processCtrl(const CPacket& ctrlpkt);\n-\n+    void processCtrl(const CPacket& ctrlpkt);\n+    \n     /// @brief Process incoming control ACK packet.\n     /// @param ctrlpkt incoming ACK packet\n     /// @param currtime current clock time\n-    bool processCtrlAck(const CPacket& ctrlpkt, const time_point& currtime);\n+    void processCtrlAck(const CPacket& ctrlpkt, const time_point& currtime);\n \n     /// @brief Process incoming control ACKACK packet.\n     /// @param ctrlpkt incoming ACKACK packet\n     /// @param tsArrival time when packet has arrived (used to calculate RTT)\n-    bool processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival);\n+    void processCtrlAckAck(const CPacket& ctrlpkt, const time_point& tsArrival);\n \n     /// @brief Process incoming loss report (NAK) packet.\n     /// @param ctrlpkt incoming NAK packet\n-    bool processCtrlLossReport(const CPacket& ctrlpkt);\n+    void processCtrlLossReport(const CPacket& ctrlpkt);\n \n     /// @brief Process incoming handshake control packet\n     /// @param ctrlpkt incoming HS packet\n-    bool processCtrlHS(const CPacket& ctrlpkt);\n+    void processCtrlHS(const CPacket& ctrlpkt);\n \n     /// @brief Process incoming drop request control packet\n     /// @param ctrlpkt incoming drop request packet\n-    bool processCtrlDropReq(const CPacket& ctrlpkt);\n+    void processCtrlDropReq(const CPacket& ctrlpkt);\n \n     /// @brief Process incoming shutdown control packet\n-    bool processCtrlShutdown();\n+    void processCtrlShutdown();\n     /// @brief Process incoming user defined control packet\n     /// @param ctrlpkt incoming user defined packet\n-    bool processCtrlUserDefined(const CPacket& ctrlpkt);\n+    void processCtrlUserDefined(const CPacket& ctrlpkt);\n \n     /// @brief Update sender's loss list on an incoming acknowledgement.\n     /// @param ackdata_seqno    sequence number of a data packet being acknowledged\n@@ -1280,11 +1115,6 @@ private: // Generation and processing of packets\n     /// @return payload size on success, <=0 on failure\n     int packLostData(CPacket &packet);\n \n-    std::pair<int32_t, int> getCleanRexmitOffset();\n-    bool checkRexmitRightTime(int offset, const srt::sync::steady_clock::time_point& current_time);\n-    int extractCleanRexmitPacket(int32_t seqno, int offset, CPacket& w_packet,\n-        srt::sync::steady_clock::time_point& w_tsOrigin);\n-\n     /// Pack a unique data packet (never sent so far) in CPacket for sending.\n     /// @param packet [in, out] a CPacket structure to fill.\n     ///\n@@ -1343,7 +1173,7 @@ private: // Generation and processing of packets\n     static void addLossRecord(std::vector<int32_t>& lossrecord, int32_t lo, int32_t hi);\n     int32_t bake(const sockaddr_any& addr, int32_t previous_cookie = 0, int correction = 0);\n \n-    bool processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival);\n+    void processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival);\n \n \n     SRT_ATTR_REQUIRES(m_RcvBufferLock)\n@@ -1415,9 +1245,6 @@ private: // for epoll\n     void removeEPollID(const int eid);\n };\n \n-// DEBUG SUPPORT\n-HandshakeSide getHandshakeSide(SRTSOCKET s);\n-\n } // namespace srt\n \n #endif\ndiff --git a/srtcore/crypto.cpp b/srtcore/crypto.cpp\nindex c6b1891..e7fe0be 100644\n--- a/srtcore/crypto.cpp\n+++ b/srtcore/crypto.cpp\n@@ -81,7 +81,7 @@ void srt::CCryptoControl::globalInit()\n {\n #ifdef SRT_ENABLE_ENCRYPTION\n     // We need to force the Cryspr to be initialized during startup to avoid the\n-    // possibility of multiple threads initializing the same static data later on.\n+    // possibility of multiple threads initialzing the same static data later on.\n     HaiCryptCryspr_Get_Instance();\n #endif\n }\n@@ -135,302 +135,250 @@ void srt::CCryptoControl::createFakeSndContext()\n     }\n }\n \n-#ifdef SRT_ENABLE_ENCRYPTION\n-\n int srt::CCryptoControl::processSrtMsg_KMREQ(\n-        const uint32_t* srtdata, size_t bytelen, int hsv, unsigned srtv,\n+        const uint32_t* srtdata SRT_ATR_UNUSED,\n+        size_t bytelen SRT_ATR_UNUSED,\n+        int hsv SRT_ATR_UNUSED, unsigned srtv SRT_ATR_UNUSED,\n         uint32_t pw_srtdata_out[], size_t& w_srtlen)\n {\n+    //Receiver\n+    /* All 32-bit msg fields swapped on reception\n+     * But HaiCrypt expect network order message\n+     * Re-swap to cancel it.\n+     */\n+#ifdef SRT_ENABLE_ENCRYPTION\n+    w_srtlen = bytelen/sizeof(srtdata[SRT_KMR_KMSTATE]);\n+    HtoNLA((pw_srtdata_out), srtdata, w_srtlen);\n     unsigned char* kmdata = reinterpret_cast<unsigned char*>(pw_srtdata_out);\n \n     // The side that has received KMREQ is always an HSD_RESPONDER, regardless of\n     // what has called this function. The HSv5 handshake only enforces bidirectional\n     // connection.\n \n-    // They actually mean the same thing in HSv5, but removal of bidirectional can be\n-    // only done when the compat with <1.3.0 is allowed to be broken.\n     const bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;\n-    const bool kmx_update = m_hRcvCrypto;\n-    SRT_KM_STATE failure_state = m_KmSecret.len == 0 ? SRT_KM_S_NOSECRET : SRT_KM_S_BADSECRET;\n-    bool bUseGCM = false;\n \n-    // TRY-BLOCK, with THROW done by \"goto Error\".\n+    // Local macro to return rejection appropriately.\n+    // CHANGED. The first version made HSv5 reject the connection.\n+    // This isn't well handled by applications, so the connection is\n+    // still established, but unable to handle any transport.\n+//#define KMREQ_RESULT_REJECTION() if (bidirectional) { return SRT_CMD_NONE; } else { w_srtlen = 1; goto HSv4_ErrorReport; }\n+#define KMREQ_RESULT_REJECTION() { w_srtlen = 1; goto HSv4_ErrorReport; }\n+\n+    int rc = HAICRYPT_OK; // needed before 'goto' run from KMREQ_RESULT_REJECTION macro\n+    bool wasb4 SRT_ATR_UNUSED = false;\n+    size_t sek_len = 0;\n+\n+    const bool bUseGCM =\n+        (m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO && kmdata[HCRYPT_MSG_KM_OFS_CIPHER] == HCRYPT_CIPHER_AES_GCM) ||\n+        (m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM);\n+\n+    m_bUseGcm153 = srtv <= SrtVersion(1, 5, 3);\n+\n+    // What we have to do:\n+    // If encryption is on (we know that by having m_KmSecret nonempty), create\n+    // the crypto context (if bidirectional, create for both sending and receiving).\n+    // Both crypto contexts should be set with the same length of the key.\n+    // The problem with interpretinting this should be reported as SRT_CMD_NONE,\n+    // should be appropriately handled by the caller, as it expects that this\n+    // function normally return SRT_CMD_KMRSP.\n+    if ( bytelen <= HCRYPT_MSG_KM_OFS_SALT )  //Sanity on message\n     {\n-        if (bytelen % sizeof(uint32_t) != 0 || bytelen > HCRYPT_MSG_KM_MAX_SZ)\n-        {\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: size of the KM (\" << bytelen << \") is too high, must be < \" << HCRYPT_MSG_KM_MAX_SZ);\n-            goto Error;\n-        }\n-\n-        // Default successful settings: original length and contents\n-        w_srtlen = bytelen/sizeof(srtdata[SRT_KMR_KMSTATE]);\n-\n-        /* All 32-bit msg fields swapped on reception\n-         * But HaiCrypt expect network order message\n-         * Re-swap to cancel it.\n-         */\n-        HtoNLA((pw_srtdata_out), srtdata, w_srtlen);\n-\n-        if (!kmx_update) // Only in initial/handshake\n-        {\n-            // If this is NOT changed anywhere later, failure_state value will be used\n-            m_RcvKmState = SRT_KM_S_SECURING;\n-        }\n-\n-        if ((m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO && kmdata[HCRYPT_MSG_KM_OFS_CIPHER] == HCRYPT_CIPHER_AES_GCM)\n-                || (m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM))\n-            bUseGCM = true;\n-\n-        m_bUseGcm153 = srtv <= SrtVersion(1, 5, 3);\n-\n-        // INITIAL ACTIONS (first time KMREQ received):\n-        // If encryption is on (we know that by having m_KmSecret nonempty), create\n-        // the crypto context (if bidirectional, create for both sending and receiving).\n-        // Both crypto contexts should be set with the same length of the key.\n-        // Report SRT_CMD_NONE if no response is to be sent or SRT_CMD_KMRSP if the\n-        // response is filled and ready (including erroneous).\n-        if (bytelen <= HCRYPT_MSG_KM_OFS_SALT)  //Sanity on message\n-        {\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: size of the KM (\" << bytelen << \") is too small, must be >\" << HCRYPT_MSG_KM_OFS_SALT);\n-            goto Error;\n-        }\n-\n-        size_t sek_len = hcryptMsg_KM_GetSekLen(kmdata);\n-        if (sek_len == 0)\n-        {\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Received SEK is empty - REJECTING!\");\n-            goto Error;\n-        }\n-\n-        bool new_keylen = m_iSndKmKeyLen != sek_len;\n-\n-        if (kmx_update && new_keylen)\n-        {\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: KMX refresh came in with a DIFFERENT KEY LEN: \" << sek_len);\n-            goto Error;\n-        }\n-\n-        HLOGC(cnlog.Debug, log << \"KMREQ: getting SEK and creating receiver crypto sek_len=\" << sek_len\n-                << \" local=\" << m_iSndKmKeyLen\n-                << (new_keylen ? \" - OVERRIDE with received SEK len\" : \"\"));\n-\n-        // Write the key length.\n-        // Overwrite the key length anyway - it doesn't make sense to somehow\n-        // keep the original setting because it will only make KMX impossible.\n-        m_iSndKmKeyLen = m_iRcvKmKeyLen = sek_len;\n+        LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: size of the KM (\" << bytelen << \") is too small, must be >\" << HCRYPT_MSG_KM_OFS_SALT);\n+        m_RcvKmState = SRT_KM_S_BADSECRET;\n+        KMREQ_RESULT_REJECTION();\n+    }\n \n-        // This is checked only now so that the SRTO_PBKEYLEN return always the correct value,\n-        // even if encryption is not possible because Agent didn't set a password, or supplied\n-        // a wrong password.\n-        if (!hasPassphrase())  //We have a shared secret <==> encryption is on\n-        {\n-            LOGC(cnlog.Warn, log << \"processSrtMsg_KMREQ: Agent does not declare encryption - won't decrypt incoming packets!\");\n-            goto Error;\n-        }\n+    HLOGC(cnlog.Debug, log << \"KMREQ: getting SEK and creating receiver crypto\");\n+    sek_len = hcryptMsg_KM_GetSekLen(kmdata);\n+    if ( sek_len == 0 )\n+    {\n+        LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Received SEK is empty - REJECTING!\");\n+        m_RcvKmState = SRT_KM_S_BADSECRET;\n+        KMREQ_RESULT_REJECTION();\n+    }\n \n-        if (!createCryptoCtx((m_hRcvCrypto), m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, bUseGCM))\n-        {\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...\");\n-            failure_state = SRT_KM_S_NOSECRET;\n-            goto Error;\n-        }\n+    // Write the key length\n+    m_iRcvKmKeyLen = sek_len;\n+    // Overwrite the key length anyway - it doesn't make sense to somehow\n+    // keep the original setting because it will only make KMX impossible.\n+#if ENABLE_HEAVY_LOGGING\n+    if (m_iSndKmKeyLen != m_iRcvKmKeyLen)\n+    {\n+        LOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: Agent's PBKEYLEN=\" << m_iSndKmKeyLen\n+                << \" overwritten by Peer's PBKEYLEN=\" << m_iRcvKmKeyLen);\n+    }\n+#endif\n+    m_iSndKmKeyLen = m_iRcvKmKeyLen;\n \n-        if (!kmx_update)\n-        {\n-            // Deduce resulting mode.\n-            m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;\n-            HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: created RX ENC with KeyLen=\" << m_iRcvKmKeyLen);\n-        }\n+    // This is checked only now so that the SRTO_PBKEYLEN return always the correct value,\n+    // even if encryption is not possible because Agent didn't set a password, or supplied\n+    // a wrong password.\n+    if (m_KmSecret.len == 0)  //We have a shared secret <==> encryption is on\n+    {\n+        LOGC(cnlog.Warn, log << \"processSrtMsg_KMREQ: Agent does not declare encryption - won't decrypt incoming packets!\");\n+        m_RcvKmState = SRT_KM_S_NOSECRET;\n+        KMREQ_RESULT_REJECTION();\n+    }\n+    wasb4 = m_hRcvCrypto;\n \n-        // We have both sides set with password, so both are pending for security\n-        int rc = HaiCrypt_Rx_Process(m_hRcvCrypto, kmdata, bytelen, NULL, NULL, 0);\n-        LOGC(cnlog.Note, log << FormatKmMessage(\"processSrtMsg_KMREQ\", SRT_CMD_KMREQ, bytelen) << \" result: \" << rc);\n+    if (!createCryptoCtx((m_hRcvCrypto), m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, bUseGCM))\n+    {\n+        LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...\");\n+        m_RcvKmState = SRT_KM_S_NOSECRET;\n+        KMREQ_RESULT_REJECTION();\n+    }\n \n-        // Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,\n-        // until the next KMREQ is received as a key regeneration.\n-        m_bErrorReported = false;\n+    // Deduce resulting mode.\n+    m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;\n \n-        if (rc >= HAICRYPT_OK)\n-        {\n-            m_RcvKmState = SRT_KM_S_SECURED;\n-            HLOGC(cnlog.Debug, log << \"KMREQ/rcv: (snd) Rx process successful - SECURED.\");\n-        }\n-        else\n-        {\n-            switch(rc)\n-            {\n-            case HAICRYPT_ERROR_WRONG_SECRET: //Unmatched shared secret to decrypt wrapped key\n-                failure_state = SRT_KM_S_BADSECRET;\n-                //Send status KMRSP message to tel error\n-                LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure - BADSECRET\");\n-                break;\n-            case HAICRYPT_ERROR_CIPHER:\n+    if (!wasb4)\n+    {\n+        HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: created RX ENC with KeyLen=\" << m_iRcvKmKeyLen);\n+    }\n+    // We have both sides set with password, so both are pending for security\n+    m_RcvKmState = SRT_KM_S_SECURING;\n+    // m_SndKmState is set to SECURING or UNSECURED in init(),\n+    // or it might have been set to SECURED, NOSECRET or BADSECRET in the previous\n+    // handshake iteration (handshakes may be sent multiple times for the same connection).\n+\n+    rc = HaiCrypt_Rx_Process(m_hRcvCrypto, kmdata, bytelen, NULL, NULL, 0);\n+    switch(rc >= 0 ? HAICRYPT_OK : rc)\n+    {\n+    case HAICRYPT_OK:\n+        m_RcvKmState = SRT_KM_S_SECURED;\n+        HLOGC(cnlog.Debug, log << \"KMREQ/rcv: (snd) Rx process successful - SECURED.\");\n+        //Send back the whole message to confirm\n+        break;\n+    case HAICRYPT_ERROR_WRONG_SECRET: //Unmatched shared secret to decrypt wrapped key\n+        m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET;\n+        //Send status KMRSP message to tel error\n+        w_srtlen = 1;\n+        LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure - BADSECRET\");\n+        break;\n+    case HAICRYPT_ERROR_CIPHER:\n #ifdef ENABLE_AEAD_API_PREVIEW\n-                failure_state = SRT_KM_S_BADCRYPTOMODE;\n+        m_RcvKmState = m_SndKmState = SRT_KM_S_BADCRYPTOMODE;\n #else\n-                failure_state = SRT_KM_S_BADSECRET; // Use \"bad secret\" as a fallback.\n+        m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET; // Use \"bad secret\" as a fallback.\n #endif\n-                LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure - BADCRYPTOMODE\");\n-                break;\n-            case HAICRYPT_ERROR: //Other errors\n-            default:\n-                failure_state = SRT_KM_S_NOSECRET;\n-                LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure (IPE) - NOSECRET\");\n-                break;\n-            }\n+        w_srtlen = 1;\n+        LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure - BADCRYPTOMODE\");\n+        break;\n+    case HAICRYPT_ERROR: //Other errors\n+    default:\n+        m_RcvKmState = m_SndKmState = SRT_KM_S_NOSECRET;\n+        w_srtlen = 1;\n+        LOGC(cnlog.Warn, log << \"KMREQ/rcv: (snd) Rx process failure (IPE) - NOSECRET\");\n+        break;\n+    }\n \n-            if (!kmx_update)\n-            {\n-                // Only initially, set this also to SND state.\n-                m_SndKmState = failure_state;\n-            }\n-            goto Error;\n-        }\n+    LOGP(cnlog.Note, FormatKmMessage(\"processSrtMsg_KMREQ\", SRT_CMD_KMREQ, bytelen));\n+\n+    // Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,\n+    // until the next KMREQ is received as a key regeneration.\n+    m_bErrorReported = false;\n+\n+    if (w_srtlen == 1)\n+        goto HSv4_ErrorReport;\n \n-        // Configure the sender context also, if it succeeded to configure the\n-        // receiver context and we are using bidirectional mode.\n-        if (bidirectional)\n+    // Configure the sender context also, if it succeeded to configure the\n+    // receiver context and we are using bidirectional mode.\n+    if (bidirectional)\n+    {\n+        // Note: 'bidirectional' means that we want a bidirectional key update,\n+        // which happens only and exclusively with HSv5 handshake - not when the\n+        // usual key update through UMSG_EXT+SRT_CMD_KMREQ was done (which is used\n+        // in HSv4 versions also to initialize the first key, unlike HSv5).\n+        if (m_RcvKmState == SRT_KM_S_SECURED)\n         {\n-            // Note: 'bidirectional' means that we want a bidirectional key update,\n-            // which happens only and exclusively with HSv5 handshake - not when the\n-            // usual key update through UMSG_EXT+SRT_CMD_KMREQ was done (which is used\n-            // in HSv4 versions also to initialize the first key, unlike HSv5).\n-            if (m_RcvKmState == SRT_KM_S_SECURED)\n+            if (m_SndKmState == SRT_KM_S_SECURING && !m_hSndCrypto)\n             {\n-                if (m_SndKmState == SRT_KM_S_SECURING && !m_hSndCrypto)\n+                m_iSndKmKeyLen = m_iRcvKmKeyLen;\n+                if (HaiCrypt_Clone(m_hRcvCrypto, HAICRYPT_CRYPTO_DIR_TX, &m_hSndCrypto) != HAICRYPT_OK)\n                 {\n-                    m_iSndKmKeyLen = m_iRcvKmKeyLen;\n-                    if (HaiCrypt_Clone(m_hRcvCrypto, HAICRYPT_CRYPTO_DIR_TX, &m_hSndCrypto) != HAICRYPT_OK)\n-                    {\n-                        LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Can't create SND CRYPTO CTX - WILL NOT SEND-ENCRYPT correctly!\");\n-                        m_SndKmState = failure_state;\n-                    }\n+                    LOGC(cnlog.Error, log << \"processSrtMsg_KMREQ: Can't create SND CRYPTO CTX - WILL NOT SEND-ENCRYPT correctly!\");\n+                    if (hasPassphrase())\n+                        m_SndKmState = SRT_KM_S_BADSECRET;\n                     else\n-                    {\n-                        m_SndKmState = SRT_KM_S_SECURED;\n-                    }\n-\n-                    LOGC(cnlog.Note, log << FormatKmMessage(\"processSrtMsg_KMREQ\", SRT_CMD_KMREQ, bytelen)\n-                            << \" SndKeyLen=\" << m_iSndKmKeyLen\n-                            << \" TX CRYPTO CTX CLONED FROM RX\"\n-                        );\n-\n-                    // Write the KM message into the field from which it will be next sent.\n-                    memcpy((m_SndKmMsg[0].Msg), kmdata, bytelen);\n-                    m_SndKmMsg[0].MsgLen = bytelen;\n-                    m_SndKmMsg[0].iPeerRetry = 0; // Don't start sending them upon connection :)\n+                        m_SndKmState = SRT_KM_S_NOSECRET;\n                 }\n                 else\n                 {\n-                    HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: NOT cloning RX to TX crypto: already in \"\n-                            << KmStateStr(m_SndKmState) << \" state\");\n+                    m_SndKmState = SRT_KM_S_SECURED;\n                 }\n+\n+                LOGC(cnlog.Note, log << FormatKmMessage(\"processSrtMsg_KMREQ\", SRT_CMD_KMREQ, bytelen)\n+                        << \" SndKeyLen=\" << m_iSndKmKeyLen\n+                        << \" TX CRYPTO CTX CLONED FROM RX\"\n+                    );\n+\n+                // Write the KM message into the field from which it will be next sent.\n+                memcpy((m_SndKmMsg[0].Msg), kmdata, bytelen);\n+                m_SndKmMsg[0].MsgLen = bytelen;\n+                m_SndKmMsg[0].iPeerRetry = 0; // Don't start sending them upon connection :)\n             }\n             else\n             {\n-                HLOGP(cnlog.Debug, \"processSrtMsg_KMREQ: NOT SECURED - not replaying failed security association to TX CRYPTO CTX\");\n+                HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: NOT cloning RX to TX crypto: already in \"\n+                        << KmStateStr(m_SndKmState) << \" state\");\n             }\n         }\n         else\n         {\n-            HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.\");\n+            HLOGP(cnlog.Debug, \"processSrtMsg_KMREQ: NOT SECURED - not replaying failed security association to TX CRYPTO CTX\");\n         }\n-\n-        if (m_hRcvCrypto != NULL)\n-            HaiCrypt_UpdateGcm153(m_hRcvCrypto, m_bUseGcm153);\n-        if (m_hSndCrypto != NULL)\n-            HaiCrypt_UpdateGcm153(m_hSndCrypto, m_bUseGcm153);\n-\n-        // NOTE: The \"loop\" gets exit with return HERE.\n-        return SRT_CMD_KMRSP;\n     }\n-Error: // CATCH POINT\n+    else\n+    {\n+        HLOGC(cnlog.Debug, log << \"processSrtMsg_KMREQ: NOT REPLAYING the key update to TX CRYPTO CTX.\");\n+    }\n \n-    // NOTE: This is set, but if we return NONE, this will not be\n-    // taken into account anyhow. The state is returned this way only for\n-    // unit tests so that they recognize the result of the call.\n-    w_srtlen = 1;\n-    pw_srtdata_out[SRT_KMR_KMSTATE] = failure_state;\n+#ifdef SRT_ENABLE_ENCRYPTION\n+    if (m_hRcvCrypto != NULL)\n+        HaiCrypt_UpdateGcm153(m_hRcvCrypto, m_bUseGcm153);\n+    if (m_hSndCrypto != NULL)\n+        HaiCrypt_UpdateGcm153(m_hSndCrypto, m_bUseGcm153);\n+#endif\n \n-    if (!kmx_update)\n-    {\n-        // Set the appropriate error, if it wasn't already set before \n-        m_RcvKmState = failure_state;\n-        if (bidirectional && hasPassphrase())\n-        {\n-            // If the Forward KMX process has failed, the reverse-KMX process was not done at all.\n-            // This will lead to incorrect object configuration and will fail to properly declare\n-            // the transmission state.\n-            // Create the \"fake crypto\" with the passphrsae you currently have.\n-            createFakeSndContext();\n-        }\n+    return SRT_CMD_KMRSP;\n \n-        return SRT_CMD_KMRSP;\n-    }\n-    return SRT_CMD_NONE;\n-}\n+HSv4_ErrorReport:\n \n-// RETURNS:\n-//   first: the converted state_value, or fallback if it was wrong\n-//  second: the value to be set in the opposite direction, if different\n-inline std::pair<SRT_KM_STATE, SRT_KM_STATE> ErraticKMState(uint32_t state_value)\n-{\n-    if (state_value >= uint32_t(SRT_KM_S_E_SIZE))\n+    if (bidirectional && hasPassphrase())\n     {\n-        LOGC(cnlog.Fatal, log << \"processSrtMsg_KMRSP: IPE: unknown peer state value: \" << state_value);\n-        return std::make_pair(SRT_KM_S_BADSECRET, SRT_KM_S_BADSECRET);\n+        // If the Forward KMX process has failed, the reverse-KMX process was not done at all.\n+        // This will lead to incorrect object configuration and will fail to properly declare\n+        // the transmission state.\n+        // Create the \"fake crypto\" with the passphrsae you currently have.\n+        createFakeSndContext();\n     }\n+#undef KMREQ_RESULT_REJECTION\n \n-    SRT_KM_STATE state = SRT_KM_STATE(state_value);\n-    switch (state)\n-    {\n-    case SRT_KM_S_NOSECRET:\n-        return std::make_pair(state, SRT_KM_S_UNSECURED);\n+#else\n+    // It's ok that this is reported as error because this happens in a scenario,\n+    // when non-encryption-enabled SRT application is contacted by encryption-enabled SRT\n+    // application which tries to make a security association.\n+    LOGC(cnlog.Warn, log << \"processSrtMsg_KMREQ: Encryption not enabled at compile time - must reject...\");\n+    m_RcvKmState = SRT_KM_S_NOSECRET;\n+#endif\n \n-    case SRT_KM_S_UNSECURED:\n-        return std::make_pair(state, SRT_KM_S_NOSECRET);\n+    w_srtlen = 1;\n \n-    default: ; // do nothing\n-    }\n-    return std::make_pair(state, state);\n+    pw_srtdata_out[SRT_KMR_KMSTATE] = m_RcvKmState;\n+    return SRT_CMD_KMRSP;\n }\n \n-int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, unsigned srtv, bool is_handshake)\n+int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, unsigned srtv)\n {\n-    uint32_t srtd[SRTDATA_MAXSIZE];\n-    size_t srtlen = len/sizeof(uint32_t);\n-    // Validate the wire-supplied length before using it:\n-    //  - oversize would overflow the fixed-size stack buffer below;\n-    //  - non-word-aligned or too-small payloads are malformed by protocol and would\n-    //    feed uninitialised stack into downstream key-matching logic.\n-    if (srtlen > SRTDATA_MAXSIZE)\n-    {\n-        LOGC(cnlog.Error, log << \"processSrtMsg_KMRSP: malformed len \" << len\n-                              << \" (must be up to \" << SRT_CMD_MAXSZ << \") - rejecting\");\n-        return SRT_CMD_NONE;\n-    }\n-\n-    // Still handle HSv4 post-handshake-handshake. XXX: DEPRECATED. Remove in next major version.\n-    if (!is_handshake)\n-    {\n-        // HSv4 version is unidirectional and encryption is only set in one direction.\n-        // So, as KMRSP handler, the agent should be expected to be a sender, hence m_hSndCrypto\n-        // should be created, but m_hRcvCrypto not. In case of HSv5, both should be simultaneously\n-        // either NULL or valid pointers.\n-        if (!m_hRcvCrypto && m_SndKmState != SRT_KM_S_SECURED)\n-            is_handshake = true;\n-\n-        if (!m_hSndCrypto)\n-            return SRT_CMD_NONE;\n-    }\n-\n     /* All 32-bit msg fields (if present) swapped on reception\n      * But HaiCrypt expect network order message\n      * Re-swap to cancel it.\n      */\n+    uint32_t srtd[SRTDATA_MAXSIZE];\n+    size_t srtlen = len/sizeof(uint32_t);\n     HtoNLA(srtd, srtdata, srtlen);\n \n-    int retstatus = -1; // Error by default, unless all is confirmed\n+    int retstatus = -1;\n \n     // Since now, when CCryptoControl::decrypt() encounters an error, it will print it, ONCE,\n     // until the next KMREQ is received as a key regeneration.\n@@ -438,30 +386,55 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len\n \n     if (srtlen == 1) // Error report. Set accordingly.\n     {\n-        SRT_KM_STATE peerstate, revstate;\n-        Tie2(peerstate, revstate) = ErraticKMState(srtd[SRT_KMR_KMSTATE]);\n-        if (peerstate == SRT_KM_S_UNSECURED)\n-            retstatus = 0;\n+        SRT_KM_STATE peerstate = SRT_KM_STATE(srtd[SRT_KMR_KMSTATE]); /* Bad or no passphrase */\n+        m_SndKmMsg[0].iPeerRetry = 0;\n+        m_SndKmMsg[1].iPeerRetry = 0;\n \n-        // If the erroneous KMRSP was received while the connection is established, we state\n-        // the connection should be SECURED already, so no change of the state is done.\n-        if (!is_handshake)\n-        {\n-            LOGC(cnlog.Warn, log << \"processSrtMsg_KMRSP: rogue KMRSP received as KMX update - ignoring\");\n-            // Still proceed with the summary logging.\n-        }\n-        else\n+        switch (peerstate)\n         {\n-            m_SndKmMsg[0].iPeerRetry = 0;\n-            m_SndKmMsg[1].iPeerRetry = 0;\n-            m_SndKmState = peerstate;\n-            m_RcvKmState = revstate;\n-            LOGC(cnlog.Warn, log << \"processSrtMsg_KMRSP: received failure report. STATE: \" << KmStateStr(m_RcvKmState));\n+        case SRT_KM_S_BADSECRET:\n+            m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;\n+            retstatus = -1;\n+            break;\n+\n+            // Default embraces two cases:\n+            // NOSECRET: this KMRSP was sent by secured Peer, but Agent supplied no password.\n+            // UNSECURED: this KMRSP was sent by unsecure Peer because Agent sent KMREQ.\n+\n+        case SRT_KM_S_NOSECRET:\n+            // This means that the peer did not set the password, while Agent did.\n+            m_RcvKmState = SRT_KM_S_UNSECURED;\n+            m_SndKmState = SRT_KM_S_NOSECRET;\n+            retstatus = -1;\n+            break;\n+\n+        case SRT_KM_S_UNSECURED:\n+            // This means that KMRSP was sent without KMREQ, to inform the Agent,\n+            // that the Peer, unlike Agent, does use password. Agent can send then,\n+            // but can't decrypt what Peer would send.\n+            m_RcvKmState = SRT_KM_S_NOSECRET;\n+            m_SndKmState = SRT_KM_S_UNSECURED;\n+            retstatus = 0;\n+            break;\n+#ifdef ENABLE_AEAD_API_PREVIEW\n+        case SRT_KM_S_BADCRYPTOMODE:\n+            // The peer expects to use a different cryptographic mode (e.g. AES-GCM, not AES-CTR).\n+            m_RcvKmState = SRT_KM_S_BADCRYPTOMODE;\n+            m_SndKmState = SRT_KM_S_BADCRYPTOMODE;\n+            retstatus = -1;\n+            break;\n+#endif\n+\n+        default:\n+            LOGC(cnlog.Fatal, log << \"processSrtMsg_KMRSP: IPE: unknown peer error state: \"\n+                    << KmStateStr(peerstate) << \" (\" << int(peerstate) << \")\");\n+            m_RcvKmState = SRT_KM_S_NOSECRET;\n+            m_SndKmState = SRT_KM_S_NOSECRET;\n+            retstatus = -1; //This is IPE\n+            break;\n         }\n-    }\n-    else if (srtlen == 0) // 0-size is a special value for MsgLen, so avoid checks!\n-    {\n-        LOGC(cnlog.Warn, log << \"processSrtMsg_KMRSP: IPE/EPE KM response key is empty - ignoring\");\n+\n+        LOGC(cnlog.Warn, log << \"processSrtMsg_KMRSP: received failure report. STATE: \" << KmStateStr(m_RcvKmState));\n     }\n     else\n     {\n@@ -481,27 +454,25 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len\n         else\n         {\n             retstatus = -1;\n-            LOGC(cnlog.Error, log << \"processSrtMsg_KMRSP: IPE/EPE KM response key matches no key\");\n+            LOGC(cnlog.Error, log << \"processSrtMsg_KMRSP: IPE??? KM response key matches no key\");\n             /* XXX INSECURE\n             LOGC(cnlog.Error, log << \"processSrtMsg_KMRSP: KM response: [\" << FormatBinaryString((uint8_t*)srtd, len)\n                 << \"] matches no key 0=[\" << FormatBinaryString((uint8_t*)m_SndKmMsg[0].Msg, m_SndKmMsg[0].MsgLen)\n                 << \"] 1=[\" << FormatBinaryString((uint8_t*)m_SndKmMsg[1].Msg, m_SndKmMsg[1].MsgLen) << \"]\");\n                 */\n \n-            // DO NOT change the state in case of KMX update with secured sender.\n-            if (is_handshake)\n-            {\n-                m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;\n-            }\n+            m_SndKmState = m_RcvKmState = SRT_KM_S_BADSECRET;\n         }\n         HLOGC(cnlog.Debug, log << \"processSrtMsg_KMRSP: key[0]: len=\" << m_SndKmMsg[0].MsgLen << \" retry=\" << m_SndKmMsg[0].iPeerRetry\n             << \"; key[1]: len=\" << m_SndKmMsg[1].MsgLen << \" retry=\" << m_SndKmMsg[1].iPeerRetry);\n \n         m_bUseGcm153 = srtv <= SrtVersion(1, 5, 3);\n+#ifdef SRT_ENABLE_ENCRYPTION\n         if (m_hRcvCrypto != NULL)\n             HaiCrypt_UpdateGcm153(m_hRcvCrypto, m_bUseGcm153);\n         if (m_hSndCrypto != NULL)\n             HaiCrypt_UpdateGcm153(m_hSndCrypto, m_bUseGcm153);\n+#endif\n     }\n \n     LOGP(cnlog.Note, FormatKmMessage(\"processSrtMsg_KMRSP\", SRT_CMD_KMRSP, len));\n@@ -509,30 +480,6 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len\n     return retstatus;\n }\n \n-#else\n-\n-int srt::CCryptoControl::processSrtMsg_KMREQ(\n-        const uint32_t*, size_t, int, unsigned, // ignore input\n-        uint32_t pw_srtdata_out[], size_t& w_srtlen)\n-{\n-    // It's ok that this is reported as error because this happens in a scenario,\n-    // when non-encryption-enabled SRT application is contacted by encryption-enabled SRT\n-    // application which tries to make a security association.\n-    LOGC(cnlog.Warn, log << \"processSrtMsg_KMREQ: Encryption not enabled at compile time - must reject...\");\n-    m_RcvKmState = SRT_KM_S_NOSECRET;\n-    pw_srtdata_out[SRT_KMR_KMSTATE] = m_RcvKmState;\n-    w_srtlen = 1;\n-\n-    return SRT_CMD_KMRSP;\n-}\n-\n-int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t*, size_t, unsigned, bool)\n-{\n-    LOGP(cnlog.Error, \"processSrtMsg_KMRSP: Encryption not enabled at compile time; not expected to receive SRT_CMD_KMRSP\");\n-    return SRT_CMD_NONE;\n-}\n-#endif\n-\n void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SRT_ATR_UNUSED)\n {\n     sync::ScopedLock lck(m_mtxLock);\n@@ -657,7 +604,6 @@ srt::CCryptoControl::CCryptoControl(SRTSOCKET id)\n     , m_iRcvKmKeyLen(0)\n     , m_SndKmState(SRT_KM_S_UNSECURED)\n     , m_RcvKmState(SRT_KM_S_UNSECURED)\n-    , m_CurrentKey(EK_NOENC)\n     , m_KmRefreshRatePkt(0)\n     , m_KmPreAnnouncePkt(0)\n     , m_iCryptoMode(CSrtConfig::CIPHER_MODE_AUTO)\n@@ -924,9 +870,9 @@ srt::EncryptionStatus srt::CCryptoControl::decrypt(CPacket& w_packet SRT_ATR_UNU\n     if (m_RcvKmState != SRT_KM_S_SECURED)\n     {\n         // If not \"secured\", it means that it won't be able to decrypt packets,\n-        // so there's no point in even trying to send them to HaiCrypt_Rx_Data.\n+        // so there's no point to even try to send them to HaiCrypt_Rx_Data.\n         // Actually the current conditions concerning m_hRcvCrypto are such that this object\n-        // is created in case of SRT_KM_S_BADSECRET, so it will simply fail to decrypt,\n+        // is cretaed in case of SRT_KM_S_BADSECRET, so it will simply fail to decrypt,\n         // but with SRT_KM_S_NOSECRET m_hRcvCrypto is not even created (is NULL), which\n         // will then cause an error to be reported, misleadingly. Simply don't try to\n         // decrypt anything as long as you are not sure that the connection is secured.\n@@ -961,7 +907,6 @@ srt::EncryptionStatus srt::CCryptoControl::decrypt(CPacket& w_packet SRT_ATR_UNU\n     HLOGC(cnlog.Debug, log << \"decrypt: successfully decrypted, resulting length=\" << rc);\n     return ENCS_CLEAR;\n #else\n-    (void)m_bErrorReported; // otherwise warning!\n     return ENCS_NOTSUP;\n #endif\n }\ndiff --git a/srtcore/crypto.h b/srtcore/crypto.h\nindex 4a0d6aa..613ded8 100644\n--- a/srtcore/crypto.h\n+++ b/srtcore/crypto.h\n@@ -22,7 +22,6 @@ written by\n // UDT\n #include \"udt.h\"\n #include \"packet.h\"\n-#include \"common.h\"\n #include \"utilities.h\"\n #include \"logging.h\"\n \n@@ -62,7 +61,6 @@ class CCryptoControl\n public:\n     SRT_KM_STATE m_SndKmState;         //Sender Km State (imposed by agent)\n     SRT_KM_STATE m_RcvKmState;         //Receiver Km State (informed by peer)\n-    EncryptionKeySpec m_CurrentKey;\n \n private:\n     // Partial haicrypt configuration, consider\n@@ -141,7 +139,7 @@ public:\n     /// 1 - the given payload is the same as the currently used key\n     /// 0 - there's no key in agent or the payload is error message with agent NOSECRET.\n     /// -1 - the payload is error message with other state or it doesn't match the key\n-    int processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, unsigned srtv, bool is_handshake);\n+    int processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len, unsigned srtv);\n     void createFakeSndContext();\n \n     const unsigned char* getKmMsg_data(size_t ki) const { return m_SndKmMsg[ki].Msg; }\ndiff --git a/srtcore/epoll.cpp b/srtcore/epoll.cpp\nindex e3545b7..8cd8440 100644\n--- a/srtcore/epoll.cpp\n+++ b/srtcore/epoll.cpp\n@@ -486,7 +486,7 @@ int srt::CEPoll::setflags(const int eid, int32_t flags)\n \n int srt::CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut)\n {\n-    // It is allowed to call this function with fdsSize == 0\n+    // It is allowed to call this function witn fdsSize == 0\n     // and therefore also NULL fdsSet. This will then only report\n     // the number of ready sockets, just without information which.\n     if (fdsSize < 0 || (fdsSize > 0 && !fdsSet))\n@@ -522,17 +522,22 @@ int srt::CEPoll::uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int6\n                 throw CUDTException(MJ_NOTSUP, MN_INVAL);\n             }\n \n-            CEPollDesc::enotice_t::iterator i = ed.enotice_begin(), inext;\n-            int pos = 0; // This is a list, so count it during iteration\n-            for (inext = i ; i != ed.enotice_end() && pos < fdsSize ; ++pos, i = inext)\n+            int total = 0; // This is a list, so count it during iteration\n+            CEPollDesc::enotice_t::iterator i = ed.enotice_begin();\n+            while (i != ed.enotice_end())\n             {\n-                ++inext; // deletion-safe list loop\n+                int pos = total; // previous past-the-end position\n+                ++total;\n+\n+                if (total > fdsSize)\n+                    break;\n \n                 fdsSet[pos] = *i;\n-                ed.checkEdge(i); // NOTE: potentially deletes `i`\n+\n+                ed.checkEdge(i++); // NOTE: potentially deletes `i`\n             }\n-            if (pos) // pos is increased by 1 towards the last used position\n-                return pos;\n+            if (total)\n+                return total;\n         }\n \n         if ((msTimeOut >= 0) && (count_microseconds(srt::sync::steady_clock::now() - entertime) >= msTimeOut * int64_t(1000)))\ndiff --git a/srtcore/epoll.h b/srtcore/epoll.h\nindex 09e0f0e..00d46ce 100644\n--- a/srtcore/epoll.h\n+++ b/srtcore/epoll.h\n@@ -157,7 +157,7 @@ std::string DisplayEpollWatch();\n    ewatch_t m_USockWatchState;\n \n    /// Objects representing changes in SRT sockets.\n-   /// Objects are removed from here when an event is registered as edge-triggered.\n+   /// Objects are removed from here when an event is registerred as edge-triggered.\n    /// Otherwise it is removed only when all events as per subscription\n    /// are no longer on.\n    enotice_t m_USockEventNotice;\n@@ -429,7 +429,7 @@ public: // for CUDTUnited API\n    /// @param d the internal structure of the epoll container\n    /// @param st output container for the results: { socket_type, event }\n    /// @param msTimeOut timeout after which return with empty output is allowed\n-   /// @param report_by_exception if true, errors will result in exception instead of returning -1\n+   /// @param report_by_exception if true, errors will result in exception intead of returning -1\n    /// @retval -1 error occurred\n    /// @retval >=0 number of ready sockets (actually size of `st`)\n    int swait(CEPollDesc& d, fmap_t& st, int64_t msTimeOut, bool report_by_exception = true);\n@@ -438,7 +438,7 @@ public: // for CUDTUnited API\n    bool empty(const CEPollDesc& d) const;\n \n    /// Reports which events are ready on the given socket.\n-   /// @param mp socket event map returned by `swait`\n+   /// @param mp socket event map retirned by `swait`\n    /// @param sock which socket to ask\n    /// @return event flags for given socket, or 0 if none\n    static int ready(const fmap_t& mp, SRTSOCKET sock)\n@@ -450,7 +450,7 @@ public: // for CUDTUnited API\n    }\n \n    /// Reports whether socket is ready for given event.\n-   /// @param mp socket event map returned by `swait`\n+   /// @param mp socket event map retirned by `swait`\n    /// @param sock which socket to ask\n    /// @param event which events it should be ready for\n    /// @return true if the given socket is ready for given event\ndiff --git a/srtcore/fec.cpp b/srtcore/fec.cpp\nindex 498c521..fd762b8 100644\n--- a/srtcore/fec.cpp\n+++ b/srtcore/fec.cpp\n@@ -59,11 +59,11 @@ bool FECFilterBuiltin::verifyConfig(const SrtFilterConfig& cfg, string& w_error)\n \n     string colspec = map_get(cfg.parameters, \"cols\"), rowspec = map_get(cfg.parameters, \"rows\");\n \n-    int out_rows = 1, out_cols = 2;\n+    int out_rows = 1;\n \n     if (colspec != \"\")\n     {\n-        out_cols = atoi(colspec.c_str());\n+        int out_cols = atoi(colspec.c_str());\n         if (out_cols < 2)\n         {\n             w_error = \"at least 'cols' must be specified and > 1\";\n@@ -81,12 +81,6 @@ bool FECFilterBuiltin::verifyConfig(const SrtFilterConfig& cfg, string& w_error)\n         }\n     }\n \n-    if (out_cols > MAX_GROUP_SIZE || out_rows > MAX_GROUP_SIZE || out_rows < -MAX_GROUP_SIZE)\n-    {\n-        w_error = \"rows/cols size must not exceed 16-bit max value\";\n-        return false;\n-    }\n-\n     // Extra interpret level, if found, default never.\n     // Check only those that are managed.\n     string level = map_get(cfg.parameters, \"arq\");\n@@ -219,85 +213,74 @@ FECFilterBuiltin::FECFilterBuiltin(const SrtFilterInitializer &init, std::vector\n     // Required to store in the header when rebuilding\n     rcv.id = socketID();\n \n-    // This will catch any memory allocation error and translate\n-    // to MJ_SETUP / MN_NORES.\n-    try\n-    {\n-        // Setup the bit matrix, initialize everything with false.\n-\n-        // Vertical size (y)\n-        rcv.cells.resize(sizeCol() * sizeRow(), false);\n-\n-        // These sequence numbers are both the value of ISN-1 at the moment\n-        // when the handshake is done. The sender ISN is generated here, the\n-        // receiver ISN by the peer. Both should be known after the handshake.\n-        // Later they will be updated as packets are transmitted.\n-\n-        int32_t snd_isn = CSeqNo::incseq(sndISN());\n-        int32_t rcv_isn = CSeqNo::incseq(rcvISN());\n-\n-        // Alright, now we need to get the ISN from m_parent\n-        // to extract the sequence number allowing qualification to the group.\n-        // The base values must be prepared so that feedSource can qualify them.\n-\n-        // SEPARATE FOR SENDING AND RECEIVING!\n-\n-        // Now, assignment of the groups requires:\n-        // For row groups, simply the size of the group suffices.\n-        // For column groups, you need a whole matrix of all sequence\n-        // numbers that are base sequence numbers for the group.\n-        // Sequences that belong to this group are:\n-        // 1. First packet has seq+1 towards the base.\n-        // 2. Every next packet has this value + the size of the row group.\n-        // So: group dispatching is:\n-        //  - get the column number\n-        //  - extract the group data for that column\n-        //  - check if the sequence is later than the group base sequence, if not, report no group for the packet\n-        //  - sanity check, if the seqdiff divided by row size gets 0 remainder\n-        //  - The result from the above division can't exceed the column size, otherwise\n-        //    it's another group. The number of currently collected data should be in 'collected'.\n-\n-        // Now set up the group starting sequences.\n-        // The very first group in both dimensions will have the value of ISN in particular direction.\n-\n-        // Set up sender part.\n-        //\n-        // Size: rows\n-        // Step: 1 (next packet in group is 1 past the previous one)\n-        // Slip: rows (first packet in the next group is distant to first packet in the previous group by 'rows')\n-        HLOGC(pflog.Debug, log << \"FEC: INIT: ISN { snd=\" << snd_isn << \" rcv=\" << rcv_isn << \" }; sender single row\");\n-        ConfigureGroup(snd.row, snd_isn, 1, sizeRow());\n-\n-        // In the beginning we need just one reception group. New reception\n-        // groups will be created in tact with receiving packets outside this one.\n-        // The value of rcv.row[0].base will be used as an absolute base for calculating\n-        // the index of the group for a given received packet.\n-        rcv.rowq.resize(1);\n-        HLOGP(pflog.Debug, \"FEC: INIT: receiver first row\");\n-        ConfigureGroup(rcv.rowq[0], rcv_isn, 1, sizeRow());\n+    // Setup the bit matrix, initialize everything with false.\n \n-        if (sizeCol() > 1)\n-        {\n-            // Size: cols\n-            // Step: rows (the next packet in the group is one row later)\n-            // Slip: rows+1 (the first packet in the next group is later by 1 column + one whole row down)\n-\n-            HLOGP(pflog.Debug, \"FEC: INIT: sender first N columns\");\n-            ConfigureColumns(snd.cols, snd_isn);\n-            HLOGP(pflog.Debug, \"FEC: INIT: receiver first N columns\");\n-            ConfigureColumns(rcv.colq, rcv_isn);\n-        }\n+    // Vertical size (y)\n+    rcv.cells.resize(sizeCol() * sizeRow(), false);\n \n-        // The bit markers that mark the received/lost packets will be expanded\n-        // as packets come in.\n-        rcv.cell_base = rcv_isn;\n-    }\n-    catch (std::bad_alloc& be)\n+    // These sequence numbers are both the value of ISN-1 at the moment\n+    // when the handshake is done. The sender ISN is generated here, the\n+    // receiver ISN by the peer. Both should be known after the handshake.\n+    // Later they will be updated as packets are transmitted.\n+\n+    int32_t snd_isn = CSeqNo::incseq(sndISN());\n+    int32_t rcv_isn = CSeqNo::incseq(rcvISN());\n+\n+    // Alright, now we need to get the ISN from m_parent\n+    // to extract the sequence number allowing qualification to the group.\n+    // The base values must be prepared so that feedSource can qualify them.\n+\n+    // SEPARATE FOR SENDING AND RECEIVING!\n+\n+    // Now, assignment of the groups requires:\n+    // For row groups, simply the size of the group suffices.\n+    // For column groups, you need a whole matrix of all sequence\n+    // numbers that are base sequence numbers for the group.\n+    // Sequences that belong to this group are:\n+    // 1. First packet has seq+1 towards the base.\n+    // 2. Every next packet has this value + the size of the row group.\n+    // So: group dispatching is:\n+    //  - get the column number\n+    //  - extract the group data for that column\n+    //  - check if the sequence is later than the group base sequence, if not, report no group for the packet\n+    //  - sanity check, if the seqdiff divided by row size gets 0 remainder\n+    //  - The result from the above division can't exceed the column size, otherwise\n+    //    it's another group. The number of currently collected data should be in 'collected'.\n+\n+    // Now set up the group starting sequences.\n+    // The very first group in both dimensions will have the value of ISN in particular direction.\n+\n+    // Set up sender part.\n+    //\n+    // Size: rows\n+    // Step: 1 (next packet in group is 1 past the previous one)\n+    // Slip: rows (first packet in the next group is distant to first packet in the previous group by 'rows')\n+    HLOGC(pflog.Debug, log << \"FEC: INIT: ISN { snd=\" << snd_isn << \" rcv=\" << rcv_isn << \" }; sender single row\");\n+    ConfigureGroup(snd.row, snd_isn, 1, sizeRow());\n+\n+    // In the beginning we need just one reception group. New reception\n+    // groups will be created in tact with receiving packets outside this one.\n+    // The value of rcv.row[0].base will be used as an absolute base for calculating\n+    // the index of the group for a given received packet.\n+    rcv.rowq.resize(1);\n+    HLOGP(pflog.Debug, \"FEC: INIT: receiver first row\");\n+    ConfigureGroup(rcv.rowq[0], rcv_isn, 1, sizeRow());\n+\n+    if (sizeCol() > 1)\n     {\n-        LOGC(pflog.Error, log << \"FEC: INIT: Memory allocation error with cols=\"\n-                << numberCols() << \" rows=\" << numberRows());\n-        throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);\n+        // Size: cols\n+        // Step: rows (the next packet in the group is one row later)\n+        // Slip: rows+1 (the first packet in the next group is later by 1 column + one whole row down)\n+\n+        HLOGP(pflog.Debug, \"FEC: INIT: sender first N columns\");\n+        ConfigureColumns(snd.cols, snd_isn);\n+        HLOGP(pflog.Debug, \"FEC: INIT: receiver first N columns\");\n+        ConfigureColumns(rcv.colq, rcv_isn);\n     }\n+\n+    // The bit markers that mark the received/lost packets will be expanded\n+    // as packets come in.\n+    rcv.cell_base = rcv_isn;\n }\n \n template <class Container>\n@@ -314,7 +297,7 @@ void FECFilterBuiltin::ConfigureColumns(Container& which, int32_t isn)\n     size_t zero = which.size();\n \n     // The first series of initialization should embrace:\n-    // - if multiplayer == 1, EVERYTHING (also the case of SOLID matrix)\n+    // - if multiplyer == 1, EVERYTHING (also the case of SOLID matrix)\n     // - if more, ONLY THE FIRST SQUARE.\n     which.resize(zero + numberCols());\n \n@@ -561,16 +544,11 @@ void FECFilterBuiltin::ClipPacket(Group& g, const CPacket& pkt)\n \n // Clipping a control packet does merely the same, just the packet has\n // different contents, so it must be differetly interpreted.\n-bool FECFilterBuiltin::ClipControlPacket(Group& g, const CPacket& pkt)\n+void FECFilterBuiltin::ClipControlPacket(Group& g, const CPacket& pkt)\n {\n     // Both length and timestamp must be taken as NETWORK ORDER\n     // before applying the clip.\n \n-    if (pkt.size() < 4) // paranoid check\n-    {\n-        return false;\n-    }\n-\n     const char* fec_header = pkt.data();\n     const char* payload = fec_header + 4;\n     size_t payload_clip_len = pkt.size() - 4;\n@@ -589,8 +567,6 @@ bool FECFilterBuiltin::ClipControlPacket(Group& g, const CPacket& pkt)\n             << \" LENGTH[ne]=\" << g.length_clip\n             << \" TS[he]=\" << g.timestamp_clip\n             << \" PL4=\" << (*(uint32_t*)&g.payload_clip[0]));\n-\n-    return true;\n }\n \n void FECFilterBuiltin::ClipRebuiltPacket(Group& g, Receive::PrivPacket& pkt)\n@@ -625,10 +601,6 @@ void FECFilterBuiltin::ClipData(Group& g, uint16_t length_net, uint8_t kflg,\n     HLOGC(pflog.Debug, log << \"FEC CLIP: data pkt.size=\" << payload_size\n             << \" to a clip buffer size=\" << payloadSize());\n \n-    // Paranoid check\n-    if (payload_size > payloadSize())\n-        payload_size = payloadSize();\n-\n     // Payload goes \"as is\".\n     for (size_t i = 0; i < payload_size; ++i)\n     {\n@@ -915,11 +887,11 @@ bool FECFilterBuiltin::receive(const CPacket& rpkt, loss_seqs_t& loss_seqs)\n         // - Both HangVertical and HangHorizontal\n \n         okv = HangVertical(rpkt, isfec.colx, irrecover_col);\n-        IF_HEAVY_LOGGING(bool discrep = (okv == HANG_CRAZY) ? okh < HANG_CRAZY : false);\n+        IF_HEAVY_LOGGING(bool discrep = (okv == HANG_CRAZY) ? int(okh) < HANG_CRAZY : false);\n         HLOGC(pflog.Debug, log << \"FEC: HangVertical %\" << rpkt.getSeqNo()\n                 << \" msgno=\" << rpkt.getMsgSeq()\n                 << \" RESULT=\" << hangname[okh]\n-                << (discrep ? \" IPE: H successful and V failed!\" : \"\")\n+                << (discrep ? \" IPE: H successul and V failed!\" : \"\")\n                 << \" IRRECOVERABLE: \" << Printable(irrecover_col));\n     }\n \n@@ -1190,11 +1162,7 @@ FECFilterBuiltin::EHangStatus FECFilterBuiltin::HangHorizontal(const CPacket& rp\n     {\n         if (!rowg.fec)\n         {\n-            if (!ClipControlPacket(rowg, rpkt))\n-            {\n-                LOGC(pflog.Error, log << \"FEC/H: Rogue control packet received\");\n-                return HANG_CRAZY; // That's the only \"complete failure\" statement\n-            }\n+            ClipControlPacket(rowg, rpkt);\n             rowg.fec = true;\n             HLOGC(pflog.Debug, log << \"FEC/H: FEC/CTL packet clipped, %\" << seq << \" base=%\" << rowg.base);\n         }\n@@ -1895,11 +1863,7 @@ FECFilterBuiltin::EHangStatus FECFilterBuiltin::HangVertical(const CPacket& rpkt\n     {\n         if (!colg.fec)\n         {\n-            if (!ClipControlPacket(colg, rpkt))\n-            {\n-                LOGC(pflog.Error, log << \"FEC/H: Rogue control packet received\");\n-                return HANG_CRAZY; // That's the only \"complete failure\" statement\n-            }\n+            ClipControlPacket(colg, rpkt);\n             colg.fec = true;\n             HLOGC(pflog.Debug, log << \"FEC/V: FEC/CTL packet clipped, %\" << seq << \" FOR COLUMN \" << int(fec_col)\n                     << \" base=%\" << colg.base);\ndiff --git a/srtcore/fec.h b/srtcore/fec.h\nindex c571578..0297094 100644\n--- a/srtcore/fec.h\n+++ b/srtcore/fec.h\n@@ -34,12 +34,6 @@ class FECFilterBuiltin: public SrtPacketFilterBase\n \n public:\n \n-    // rows/cols size can have this size at maximum, otherwise\n-    // there's a risk to have an overflow memory size value on\n-    // 32-bit systems, which may result in a false success followed\n-    // by a crash.\n-    static const int MAX_GROUP_SIZE = 0xFFFF;\n-\n     size_t numberCols() const { return m_number_cols; }\n     size_t numberRows() const { return m_number_rows; }\n \n@@ -138,10 +132,10 @@ private:\n \n         // Base index at the oldest column platform determines\n         // the base index of the queue. Meaning, first you need\n-        // to determine the column index, where the index 0 is\n+        // to determnine the column index, where the index 0 is\n         // the fistmost element of this queue. After determining\n         // the column index, there must be also a second factor\n-        // determined - which column series it is. So, this can\n+        // deteremined - which column series it is. So, this can\n         // start by extracting the base sequence of the element\n         // at the index column. This is the series 0. Now, the\n         // distance between these two sequences, divided by\n@@ -223,7 +217,7 @@ private:\n \n     EHangStatus HangHorizontal(const CPacket& pkt, bool fec_ctl, loss_seqs_t& irrecover);\n     EHangStatus HangVertical(const CPacket& pkt, signed char fec_colx, loss_seqs_t& irrecover);\n-    SRT_ATR_NODISCARD bool ClipControlPacket(Group& g, const CPacket& pkt);\n+    void ClipControlPacket(Group& g, const CPacket& pkt);\n     void ClipRebuiltPacket(Group& g, Receive::PrivPacket& pkt);\n     void RcvRebuild(Group& g, int32_t seqno, Group::Type tp);\n     int32_t RcvGetLossSeqHoriz(Group& g);\ndiff --git a/srtcore/group.cpp b/srtcore/group.cpp\nindex bd034a5..6b0b164 100644\n--- a/srtcore/group.cpp\n+++ b/srtcore/group.cpp\n@@ -90,7 +90,7 @@ bool CUDTGroup::applyGroupSequences(SRTSOCKET target, int32_t& w_snd_isn, int32_\n \n             // NOTE: the groupwise scheduling sequence might have been set\n             // already. If so, it means that it was set by either:\n-            // - the call of this function on the very first connected socket (see below)\n+            // - the call of this function on the very first conencted socket (see below)\n             // - the call to `sendBroadcast` or `sendBackup`\n             // In both cases, we want THIS EXACTLY value to be reported\n             if (m_iLastSchedSeqNo != -1)\n@@ -205,7 +205,7 @@ void CUDTGroup::debugMasterData(SRTSOCKET slave)\n     else\n     {\n         // The returned master_st is the master's start time. Calculate the\n-        // difference time.\n+        // differene time.\n         IF_LOGGING(steady_clock::duration master_tdiff = m_tsStartTime - start_time);\n         LOGC(cnlog.Debug, log << CONID() << \"FOUND GROUP MASTER LINK: peer=$\" << mpeer\n                 << \" - start time diff: \" << FormatDuration<DUNIT_S>(master_tdiff));\n@@ -347,36 +347,6 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)\n \n     switch (optName)\n     {\n-        // First go options that are NOT ALLOWED to be modified on the group.\n-        // (socket-only), or are read-only.\n-\n-    case SRTO_ISN: // read-only\n-    case SRTO_STATE: // read-only\n-    case SRTO_EVENT: // read-only\n-    case SRTO_SNDDATA: // read-only\n-    case SRTO_RCVDATA: // read-only\n-    case SRTO_KMSTATE: // read-only\n-    case SRTO_VERSION: // read-only\n-    case SRTO_PEERVERSION: // read-only\n-    case SRTO_SNDKMSTATE: // read-only\n-    case SRTO_RCVKMSTATE: // read-only\n-    case SRTO_GROUPTYPE: // read-only\n-        LOGC(gmlog.Error, log << \"group option setter: this option (\"<< int(optName) << \") is read-only\");\n-        throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n-\n-    case SRTO_SENDER: // deprecated (1.2.0 version legacy)\n-    case SRTO_IPV6ONLY: // link-type specific\n-    case SRTO_RENDEZVOUS: // socket-only\n-    case SRTO_BINDTODEVICE: // socket-specific\n-    case SRTO_GROUPCONNECT: // listener-specific\n-        LOGC(gmlog.Error, log << \"group option setter: this option (\"<< int(optName) << \") is socket- or link-specific\");\n-        throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n-\n-    case SRTO_TRANSTYPE:\n-    case SRTO_TSBPDMODE:\n-    case SRTO_CONGESTION:\n-        LOGC(gmlog.Error, log << \"group option setter: this option (\" << int(optName) << \") removes live mode, which is the only supported for groups\");\n-        throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n     case SRTO_RCVSYN:\n         m_bSynRecving = cast_optval<bool>(optval, optlen);\n         return;\n@@ -399,7 +369,7 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)\n         const int min_timeo_ms = (int) CSrtConfig::COMM_DEF_MIN_STABILITY_TIMEOUT_MS;\n         if (val_ms < min_timeo_ms)\n         {\n-            LOGC(gmlog.Error,\n+            LOGC(qmlog.Error,\n                  log << \"group option: SRTO_GROUPMINSTABLETIMEO min allowed value is \" << min_timeo_ms << \" ms.\");\n             throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n         }\n@@ -415,7 +385,7 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)\n \n         if (val_ms > idletmo)\n         {\n-            LOGC(gmlog.Error,\n+            LOGC(qmlog.Error,\n                  log << \"group option: SRTO_GROUPMINSTABLETIMEO=\" << val_ms << \" exceeds SRTO_PEERIDLETIMEO=\" << idletmo);\n             throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n         }\n@@ -461,14 +431,6 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)\n         }\n     }\n \n-    // Before possibly storing the option, check if it is settable on a socket.\n-    CSrtConfig testconfig;\n-\n-    // Note: this call throws CUDTException by itself.\n-    int result = testconfig.set(optName, optval, optlen);\n-    if (result == -1) // returned in case of unknown option\n-        throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n-\n     // Store the option regardless if pre or post. This will apply\n     m_config.push_back(ConfigItem(optName, optval, optlen));\n }\n@@ -482,45 +444,23 @@ static bool operator!=(const struct linger& l1, const struct linger& l2)\n     return l1.l_onoff != l2.l_onoff || l1.l_linger != l2.l_linger;\n }\n \n-/// A function template to import socket option of a trivial type.\n-/// This includes linger, bool, int8_t, int32_t, int64_t, double, etc.\n-/// Potentially can be extended to trivially_copyable if needed.\n template <class ValueType>\n-static void importTrivialOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const ValueType& optval, const int optsize = sizeof(ValueType))\n+static void importOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const ValueType& field)\n {\n-    SRT_STATIC_ASSERT(std::is_trivial<ValueType>::value, \"ValueType must be a trivial type.\");\n-    ValueType optval_dflt = ValueType();\n-    int optsize_dflt      = sizeof(ValueType);\n-    if (!getOptDefault(optname, (&optval_dflt), (optsize_dflt)) || optval_dflt != optval)\n+    ValueType default_opt             = ValueType();\n+    static const int default_opt_size = sizeof(ValueType);\n+    ValueType opt                     = field;\n+    int opt_size                      = default_opt_size;\n+    if (!getOptDefault(optname, (&default_opt), (opt_size)) || default_opt != opt)\n     {\n-        SRT_ASSERT(optsize == sizeof(ValueType));\n+        SRT_ASSERT(opt_size == default_opt_size);\n         // Store the option when:\n         // - no default for this option is found\n-        // - the option value retrieved from the field is different from the default one\n-#if HAVE_FULL_CXX11\n-\t\tstorage.emplace_back(optname, &optval, optsize);\n-#else\n-        storage.push_back(CUDTGroup::ConfigItem(optname, &optval, optsize));\n-#endif\n+        // - the option value retrieved from the field is different than default\n+        storage.push_back(CUDTGroup::ConfigItem(optname, &opt, default_opt_size));\n     }\n }\n \n-/// A function template to import a StringStorage option.\n-template <size_t N>\n-static void importStringOption(vector<CUDTGroup::ConfigItem>& storage, SRT_SOCKOPT optname, const StringStorage<N>& optval)\n-{\n-    if (optval.empty())\n-        return;\n-\n-    // Store the option when:\n-    // - option has a value (default is empty).\n-#if HAVE_FULL_CXX11\n-    storage.emplace_back(optname, optval.c_str(),(int) optval.size());\n-#else\n-    storage.push_back(CUDTGroup::ConfigItem(optname, optval.c_str(), (int) optval.size()));\n-#endif\n-}\n-\n // This function is called by the same premises as the CUDT::CUDT(const CUDT&) (copy constructor).\n // The intention is to rewrite the part that comprises settings from the socket\n // into the group. Note that some of the settings concern group, some others concern\n@@ -562,18 +502,17 @@ void CUDTGroup::deriveSettings(CUDT* u)\n     // to be potentially replicated on the socket. So both pre\n     // and post options apply.\n \n-#define IM(option, field) importTrivialOption(m_config, option, u->m_config.field)\n-#define IMF(option, field) importTrivialOption(m_config, option, u->field)\n+#define IM(option, field) importOption(m_config, option, u->m_config.field)\n+#define IMF(option, field) importOption(m_config, option, u->field)\n \n     IM(SRTO_MSS, iMSS);\n     IM(SRTO_FC, iFlightFlagSize);\n \n     // Nonstandard\n-    importTrivialOption(m_config, SRTO_SNDBUF, u->m_config.iSndBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));\n-    importTrivialOption(m_config, SRTO_RCVBUF, u->m_config.iRcvBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));\n+    importOption(m_config, SRTO_SNDBUF, u->m_config.iSndBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));\n+    importOption(m_config, SRTO_RCVBUF, u->m_config.iRcvBufSize * (u->m_config.iMSS - CPacket::UDP_HDR_SIZE));\n \n     IM(SRTO_LINGER, Linger);\n-\n     IM(SRTO_UDP_SNDBUF, iUDPSndBufSize);\n     IM(SRTO_UDP_RCVBUF, iUDPRcvBufSize);\n     // SRTO_RENDEZVOUS: impossible to have it set on a listener socket.\n@@ -581,7 +520,7 @@ void CUDTGroup::deriveSettings(CUDT* u)\n \n     // SRTO_CONNTIMEO requires a special handling, because API stores the value in integer milliseconds,\n     // but the type of the variable is srt::sync::duration.\n-    importTrivialOption(m_config, SRTO_CONNTIMEO, (int) count_milliseconds(u->m_config.tdConnTimeOut));\n+    importOption(m_config, SRTO_CONNTIMEO, (int) count_milliseconds(u->m_config.tdConnTimeOut));\n \n     IM(SRTO_DRIFTTRACER, bDriftTracer);\n     // Reuseaddr: true by default and should only be true.\n@@ -595,12 +534,12 @@ void CUDTGroup::deriveSettings(CUDT* u)\n     IM(SRTO_RCVLATENCY, iRcvLatency);\n     IM(SRTO_PEERLATENCY, iPeerLatency);\n     IM(SRTO_SNDDROPDELAY, iSndDropDelay);\n-    // Special handling of SRTO_PAYLOADSIZE because API stores the value as int32_t,\n+    // Special handling of SRTO_PAYLOADSIZE becuase API stores the value as int32_t,\n     // while the config structure stores it as size_t.\n-    importTrivialOption(m_config, SRTO_PAYLOADSIZE, (int)u->m_config.zExpPayloadSize);\n+    importOption(m_config, SRTO_PAYLOADSIZE, (int)u->m_config.zExpPayloadSize);\n     IMF(SRTO_TLPKTDROP, m_bTLPktDrop);\n \n-    importStringOption(m_config, SRTO_STREAMID, u->m_config.sStreamName);\n+    importOption(m_config, SRTO_STREAMID, u->m_config.sStreamName.str());\n \n     IM(SRTO_MESSAGEAPI, bMessageAPI);\n     IM(SRTO_NAKREPORT, bRcvNakReport);\n@@ -609,22 +548,22 @@ void CUDTGroup::deriveSettings(CUDT* u)\n     IM(SRTO_IPV6ONLY, iIpV6Only);\n     IM(SRTO_PEERIDLETIMEO, iPeerIdleTimeout_ms);\n \n-    importStringOption(m_config, SRTO_PACKETFILTER, u->m_config.sPacketFilterConfig);\n+    importOption(m_config, SRTO_PACKETFILTER, u->m_config.sPacketFilterConfig.str());\n \n-    importTrivialOption(m_config, SRTO_PBKEYLEN, (int) u->m_pCryptoControl->KeyLen());\n+    importOption(m_config, SRTO_PBKEYLEN, (int) u->m_pCryptoControl->KeyLen());\n \n     // Passphrase is empty by default. Decipher the passphrase and\n     // store as passphrase option\n     if (u->m_config.CryptoSecret.len)\n     {\n-        const StringStorage<HAICRYPT_SECRET_MAX_SZ> password((const char*)u->m_config.CryptoSecret.str, u->m_config.CryptoSecret.len);\n-        importStringOption(m_config, SRTO_PASSPHRASE, password);\n+        string password((const char*)u->m_config.CryptoSecret.str, u->m_config.CryptoSecret.len);\n+        m_config.push_back(ConfigItem(SRTO_PASSPHRASE, password.c_str(), (int)password.size()));\n     }\n \n     IM(SRTO_KMREFRESHRATE, uKmRefreshRatePkt);\n     IM(SRTO_KMPREANNOUNCE, uKmPreAnnouncePkt);\n \n-    const string cc = u->m_CongCtl.selected_name();\n+    string cc = u->m_CongCtl.selected_name();\n     if (cc != \"live\")\n     {\n         m_config.push_back(ConfigItem(SRTO_CONGESTION, cc.c_str(), (int)cc.size()));\n@@ -638,7 +577,6 @@ void CUDTGroup::deriveSettings(CUDT* u)\n #undef IMF\n }\n \n-// XXX This function is likely of no use now.\n bool CUDTGroup::applyFlags(uint32_t flags, HandshakeSide)\n {\n     const bool synconmsg = IsSet(flags, SRT_GFLAG_SYNCONMSG);\n@@ -654,18 +592,16 @@ bool CUDTGroup::applyFlags(uint32_t flags, HandshakeSide)\n template <class Type>\n struct Value\n {\n-    static int fill(void* optval, int len, const Type& value)\n+    static int fill(void* optval, int, Type value)\n     {\n-        if (size_t(len) < sizeof(Type))\n-            return 0;\n-\n+        // XXX assert size >= sizeof(Type) ?\n         *(Type*)optval = value;\n         return sizeof(Type);\n     }\n };\n \n template <>\n-inline int Value<std::string>::fill(void* optval, int len, const std::string& value)\n+inline int Value<std::string>::fill(void* optval, int len, std::string value)\n {\n     if (size_t(len) < value.size())\n         return 0;\n@@ -712,7 +648,7 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n \n     case SRTO_SNDBUF:\n     case SRTO_RCVBUF:\n-        w_optlen = fillValue<int>((pw_optval), w_optlen, CSrtConfig::DEF_BUFFER_SIZE * (CSrtConfig::DEF_MSS - CPacket::UDP_HDR_SIZE));\n+        w_optlen = fillValue((pw_optval), w_optlen, CSrtConfig::DEF_BUFFER_SIZE * (CSrtConfig::DEF_MSS - CPacket::UDP_HDR_SIZE));\n         break;\n \n     case SRTO_LINGER:\n@@ -730,16 +666,10 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n         RD(true);\n     case SRTO_MAXBW:\n         RD(int64_t(-1));\n-#ifdef ENABLE_MAXREXMITBW\n-    case SRTO_MAXREXMITBW:\n-        RD(int64_t(-1));\n-#endif\n     case SRTO_INPUTBW:\n         RD(int64_t(-1));\n-    case SRTO_MININPUTBW:\n-        RD(int64_t(0));\n     case SRTO_OHEADBW:\n-        RD(SRT_OHEAD_DEFAULT_P100);\n+        RD(0);\n     case SRTO_STATE:\n         RD(SRTS_INIT);\n     case SRTO_EVENT:\n@@ -760,9 +690,8 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n         RD(false);\n     case SRTO_LATENCY:\n     case SRTO_RCVLATENCY:\n-        RD(SRT_LIVE_DEF_LATENCY_MS);\n     case SRTO_PEERLATENCY:\n-        RD(0);\n+        RD(SRT_LIVE_DEF_LATENCY_MS);\n     case SRTO_TLPKTDROP:\n         RD(true);\n     case SRTO_SNDDROPDELAY:\n@@ -773,15 +702,14 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n         RD(SRT_DEF_VERSION);\n     case SRTO_PEERVERSION:\n         RD(0);\n-    case SRTO_PEERIDLETIMEO:\n-        RD(CSrtConfig::COMM_RESPONSE_TIMEOUT_MS);\n+\n     case SRTO_CONNTIMEO:\n-        RD(CSrtConfig::DEF_CONNTIMEO_S * 1000); // required milliseconds\n+        RD(-1);\n     case SRTO_DRIFTTRACER:\n         RD(true);\n \n     case SRTO_MINVERSION:\n-        RD(SRT_VERSION_MAJ1);\n+        RD(0);\n     case SRTO_STREAMID:\n         RD(std::string());\n     case SRTO_CONGESTION:\n@@ -792,10 +720,6 @@ static bool getOptDefault(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n         RD(0);\n     case SRTO_GROUPMINSTABLETIMEO:\n         RD(CSrtConfig::COMM_DEF_MIN_STABILITY_TIMEOUT_MS);\n-    case SRTO_LOSSMAXTTL:\n-        RD(0);\n-    case SRTO_RETRANSMITALGO:\n-        RD(1);\n     }\n \n #undef RD\n@@ -866,33 +790,27 @@ void CUDTGroup::getOpt(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n     {\n         // Can't have m_GroupLock locked while calling getOpt on a member socket\n         // because the call will acquire m_ControlLock leading to a lock-order-inversion.\n-        SRTSOCKET firstsocket = SRT_INVALID_SOCK;\n         enterCS(m_GroupLock);\n         gli_t gi = m_Group.begin();\n-        if (gi != m_Group.end())\n-            firstsocket = gi->ps->core().id();\n+        CUDTSocket* const ps = (gi != m_Group.end()) ? gi->ps : NULL;\n+        CUDTUnited::SocketKeeper sk(CUDT::uglobal(), ps);\n         leaveCS(m_GroupLock);\n-        // CUDTUnited::m_GlobControlLock can't be acquired with m_GroupLock either.\n-        // We have also no guarantee that after leaving m_GroupLock the socket isn't\n-        // going to be deleted. Hence use the safest method by extracting through the id.\n-        if (firstsocket != SRT_INVALID_SOCK)\n+        if (sk.socket)\n         {\n-            CUDTUnited::SocketKeeper sk(CUDT::uglobal(), firstsocket);\n-            if (sk.socket)\n-            {\n-                // Return the value from the first member socket, if any is present\n-                // Note: Will throw exception if the request is wrong.\n-                sk.socket->core().getOpt(optname, (pw_optval), (w_optlen));\n-                is_set_on_socket = true;\n-            }\n+            // Return the value from the first member socket, if any is present\n+            // Note: Will throw exception if the request is wrong.\n+            sk.socket->core().getOpt(optname, (pw_optval), (w_optlen));\n+            is_set_on_socket = true;\n         }\n     }\n \n     // Check if the option is in the storage, which means that\n     // it was modified on the group.\n-    vector<ConfigItem>::const_iterator i = find_if(m_config.begin(), m_config.end(), FOptionValue(optname));\n \n-    if (i == m_config.end() || i->value.empty())\n+    vector<ConfigItem>::const_iterator i = find_if(m_config.begin(), m_config.end(),\n+            FOptionValue(optname));\n+\n+    if (i == m_config.end())\n     {\n         // Already written to the target variable.\n         if (is_set_on_socket)\n@@ -904,14 +822,15 @@ void CUDTGroup::getOpt(SRT_SOCKOPT optname, void* pw_optval, int& w_optlen)\n \n         return;\n     }\n+    // NOTE: even if is_set_on_socket, if it was also found in the group\n+    // settings, overwrite with the value from the group.\n \n-    // Found a value set on or derived by a group. Prefer returning it over the one taken from a member socket.\n+    // Found, return the value from the storage.\n     // Check the size first.\n     if (w_optlen < int(i->value.size()))\n         throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);\n \n-    SRT_ASSERT(!i->value.empty());\n-    w_optlen = (int)i->value.size();\n+    w_optlen = (int) i->value.size();\n     memcpy((pw_optval), &i->value[0], i->value.size());\n }\n \n@@ -935,7 +854,7 @@ SRT_KM_STATE CUDTGroup::getGroupEncryptionState()\n             // no password, but peer did, and ENFORCEDENCRYPTION=false allowed\n             // this connection to be established. UNSECURED can't be taken in this\n             // case because this would suggest that BOTH are unsecured, that is,\n-            // we have established an unsecured connection (which is not true).\n+            // we have established an unsecured connection (which ain't true).\n             if (gst == SRT_KM_S_UNSECURED && cc->m_SndKmState == SRT_KM_S_NOSECRET)\n                 gst = SRT_KM_S_NOSECRET;\n             kmstates.insert(gst);\n@@ -1048,7 +967,7 @@ void CUDTGroup::close()\n     vector<SRTSOCKET> ids;\n \n     {\n-        ExclusiveLock glob(CUDT::uglobal().m_GlobControlLock);\n+        ScopedLock glob(CUDT::uglobal().m_GlobControlLock);\n         ScopedLock g(m_GroupLock);\n \n         m_bClosing = true;\n@@ -1150,7 +1069,7 @@ void CUDTGroup::close()\n     // Release blocked clients\n     // XXX This looks like a dead code. Group receiver functions\n     // do not use any lock on m_RcvDataLock, it is likely a remainder\n-    // of the old, internal implementation.\n+    // of the old, internal impementation. \n     // CSync::lock_notify_one(m_RcvDataCond, m_RcvDataLock);\n }\n \n@@ -1477,28 +1396,9 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n \n     // { send_CheckBrokenSockets()\n \n-    // Make an extra loop check to see if we could be\n-    // in a condition of \"all sockets either blocked or pending\"\n-\n-    int nsuccessful = 0; // number of successfully connected sockets\n-    int nblocked    = 0; // number of sockets blocked in connection\n-    bool is_pending_blocked = false;\n-    for (vector<Sendstate>::iterator is = sendstates.begin(); is != sendstates.end(); ++is)\n+    if (!pendingSockets.empty())\n     {\n-        if (is->stat != -1)\n-        {\n-            nsuccessful++;\n-        }\n-        // is->stat == -1\n-        else if (is->code == SRT_EASYNCSND)\n-        {\n-            ++nblocked;\n-        }\n-    }\n-\n-    if (!pendingSockets.empty() || nblocked)\n-    {\n-        HLOGC(gslog.Debug, log << \"grp/sendBroadcast: found pending sockets (blocked: \" << nblocked << \"), polling them.\");\n+        HLOGC(gslog.Debug, log << \"grp/sendBroadcast: found pending sockets, polling them.\");\n \n         // These sockets if they are in pending state, they should be added to m_SndEID\n         // at the connecting stage.\n@@ -1513,24 +1413,12 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n         }\n         else\n         {\n-            int swait_timeout = 0;\n-\n-            // There's also a hidden condition here that is the upper if condition.\n-            is_pending_blocked = (nsuccessful == 0);\n-\n-            // If this is the case when \n-            if (m_bSynSending && is_pending_blocked)\n-            {\n-                HLOGC(gslog.Debug, log << \"grp/sendBroadcast: will block for \" << m_iSndTimeOut << \" - waiting for any writable in blocking mode\");\n-                swait_timeout = m_iSndTimeOut;\n-            }\n-\n             {\n                 InvertedLock ug(m_GroupLock);\n \n                 THREAD_PAUSED();\n                 m_Global.m_EPoll.swait(\n-                    *m_SndEpolld, (sready), swait_timeout, false /*report by retval*/); // Just check if anything happened\n+                    *m_SndEpolld, sready, 0, false /*report by retval*/); // Just check if anything happened\n                 THREAD_RESUMED();\n             }\n \n@@ -1543,10 +1431,6 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n             HLOGC(gslog.Debug, log << \"grp/sendBroadcast: RDY: \" << DisplayEpollResults(sready));\n \n             // sockets in EX: should be moved to wipeme.\n-            // IMPORTANT: we check only PENDING sockets (not blocked) because only\n-            // pending sockets might report ERR epoll without being explicitly broken.\n-            // Sockets that did connect and just have buffer full will be always broken,\n-            // if they're going to report ERR in epoll.\n             for (vector<SRTSOCKET>::iterator i = pendingSockets.begin(); i != pendingSockets.end(); ++i)\n             {\n                 if (CEPoll::isready(sready, *i, SRT_EPOLL_ERR))\n@@ -1558,9 +1442,6 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n                     int no_events = 0;\n                     m_Global.m_EPoll.update_usock(m_SndEID, *i, &no_events);\n                 }\n-\n-                if (CEPoll::isready(sready, *i, SRT_EPOLL_OUT))\n-                    is_pending_blocked = false;\n             }\n \n             // After that, all sockets that have been reported\n@@ -1577,10 +1458,7 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n     if (m_bClosing)\n         throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);\n \n-    // Just for a case, when a socket that was blocked or pending\n-    // had switched to write-enabled, \n-\n-    send_CloseBrokenSockets((wipeme)); // wipeme will be cleared by this function\n+    send_CloseBrokenSockets(wipeme);\n \n     // Re-check after the waiting lock has been reacquired\n     if (m_bClosing)\n@@ -1842,18 +1720,9 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)\n \n     if (none_succeeded)\n     {\n+        HLOGC(gslog.Debug, log << \"grp/sendBroadcast: all links broken (none succeeded to send a payload)\");\n         m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_OUT, false);\n-        if (!m_bSynSending && (is_pending_blocked || was_blocked))\n-        {\n-            HLOGC(gslog.Debug, log << \"grp/sendBroadcast: no links are ready for sending\");\n-            ercode = SRT_EASYNCSND;\n-        }\n-        else\n-        {\n-            HLOGC(gslog.Debug, log << \"grp/sendBroadcast: all links broken (none succeeded to send a payload)\");\n-            m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true);\n-        }\n-\n+        m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true);\n         // Reparse error code, if set.\n         // It might be set, if the last operation was failed.\n         // If any operation succeeded, this will not be executed anyway.\n@@ -2976,7 +2845,7 @@ CUDTGroup::BackupMemberState CUDTGroup::sendBackup_QualifyActiveState(const gli_\n     const int64_t probing_period_us = initial_stabtout_us + 5 * CUDT::COMM_SYN_INTERVAL_US;\n \n     // RTT and RTTVar values are still being refined during the probing period,\n-    // therefore the dynamic timeout should not be used during the probing period.\n+    // therefore the dymanic timeout should not be used during the probing period.\n     const bool is_activation_phase = !is_zero(u.freshActivationStart())\n         && (count_microseconds(currtime - u.freshActivationStart()) <= probing_period_us);\n \n@@ -3413,7 +3282,7 @@ void CUDTGroup::send_CloseBrokenSockets(vector<SRTSOCKET>& w_wipeme)\n         // With unlocked GroupLock, we can now lock GlobControlLock.\n         // This is needed to prevent any of them deleted from the container\n         // at the same time.\n-        SharedLock globlock(CUDT::uglobal().m_GlobControlLock);\n+        ScopedLock globlock(CUDT::uglobal().m_GlobControlLock);\n \n         for (vector<SRTSOCKET>::iterator p = w_wipeme.begin(); p != w_wipeme.end(); ++p)\n         {\n@@ -3450,7 +3319,7 @@ void CUDTGroup::sendBackup_CloseBrokenSockets(SendBackupCtx& w_sendBackupCtx)\n     // With unlocked GroupLock, we can now lock GlobControlLock.\n     // This is needed prevent any of them be deleted from the container\n     // at the same time.\n-    SharedLock globlock(CUDT::uglobal().m_GlobControlLock);\n+    ScopedLock globlock(CUDT::uglobal().m_GlobControlLock);\n \n     typedef vector<BackupMemberStateEntry>::const_iterator const_iter_t;\n     for (const_iter_t member = w_sendBackupCtx.memberStates().begin(); member != w_sendBackupCtx.memberStates().end(); ++member)\n@@ -3507,13 +3376,11 @@ void CUDTGroup::sendBackup_RetryWaitBlocked(SendBackupCtx&       w_sendBackupCtx\n     // Note: A link is added in unstableLinks if sending has failed with SRT_ESYNCSND.\n     const unsigned num_unstable = w_sendBackupCtx.countMembersByState(BKUPST_ACTIVE_UNSTABLE);\n     const unsigned num_wary     = w_sendBackupCtx.countMembersByState(BKUPST_ACTIVE_UNSTABLE_WARY);\n-    const unsigned num_pending  = w_sendBackupCtx.countMembersByState(BKUPST_PENDING);\n-    if ((num_unstable + num_wary + num_pending == 0) || !w_none_succeeded)\n+    if ((num_unstable + num_wary == 0) || !w_none_succeeded)\n         return;\n \n-    HLOGC(gslog.Debug, log << \"grp/sendBackup: no successful sending: \"\n-        << (num_unstable + num_wary) << \" unstable links, \"\n-        << num_pending << \" pending - waiting to retry sending...\");\n+    HLOGC(gslog.Debug, log << \"grp/sendBackup: no successfull sending: \"\n+        << (num_unstable + num_wary) << \" unstable links - waiting to retry sending...\");\n \n     // Note: GroupLock is set already, skip locks and checks\n     getGroupData_LOCKED((w_mc.grpdata), (&w_mc.grpdata_size));\n@@ -3587,8 +3454,9 @@ RetryWaitBlocked:\n                 CUDTSocket* s = m_Global.locateSocket(id, CUDTUnited::ERH_RETURN); // << LOCKS m_GlobControlLock!\n                 if (s)\n                 {\n-                    HLOGC(gslog.Debug, log << \"grp/sendBackup: swait/ex on @\" << id\n-                            << \" while waiting for any writable socket - CLOSING\");\n+                    HLOGC(gslog.Debug,\n+                        log << \"grp/sendBackup: swait/ex on @\" << (id)\n+                        << \" while waiting for any writable socket - CLOSING\");\n                     CUDT::uglobal().close(s); // << LOCKS m_GlobControlLock, then GroupLock!\n                 }\n                 else\n@@ -3620,32 +3488,6 @@ RetryWaitBlocked:\n         throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);\n     }\n \n-    // IMPORTANT!\n-    // There was a socket deletion possibly done above, and as well there\n-    // was the m_GroupLock lifted for that check activity, so potentially any socket\n-    // from m_Group container could be deleted; review them and remove any dangling\n-    // objects from w_sendBackupCtx.\n-    //\n-    // Due to the nature of the m_Group container, use mark-and-sweep method.\n-\n-    set<SRTSOCKET> remain;\n-    w_sendBackupCtx.getSocketIds( (remain) );\n-\n-    // MARK\n-    for (gli_t d = m_Group.begin(); d != m_Group.end(); ++d)\n-    {\n-        remain.erase(d->id);\n-    }\n-\n-    HLOGC(gslog.Debug, log << \"grp/sendBackup: RE-LOCK, checking members deleted in the meantime: \"\n-            << Printable(remain));\n-\n-    // SWEEP\n-    for (set<SRTSOCKET>::iterator i = remain.begin(); i != remain.end(); ++i)\n-    {\n-        w_sendBackupCtx.deleteById(*i);\n-    }\n-\n     // Ok, now check if we have at least one write-ready.\n     // Note that the procedure of activation of a new link in case of\n     // no stable links found embraces also rexmit-sending and status\n@@ -3724,7 +3566,7 @@ void CUDTGroup::sendBackup_SilenceRedundantLinks(SendBackupCtx& w_sendBackupCtx,\n {\n     // The most important principle is to keep the data being sent constantly,\n     // even if it means temporarily full redundancy.\n-    // A member can be silenced only if there is at least one stable member.\n+    // A member can be silenced only if there is at least one stable memebr.\n     const unsigned num_stable = w_sendBackupCtx.countMembersByState(BKUPST_ACTIVE_STABLE);\n     if (num_stable == 0)\n         return;\n@@ -3794,7 +3636,6 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc)\n {\n     if (len <= 0)\n     {\n-        LOGC(gslog.Error, log << \"grp/send(backup): negative length: \" << len);\n         throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);\n     }\n \n@@ -3814,7 +3655,6 @@ int CUDTGroup::sendBackup(const char* buf, int len, SRT_MSGCTRL& w_mc)\n     if (m_bClosing)\n     {\n         leaveCS(m_Global.m_GlobControlLock);\n-        LOGC(gslog.Error, log << \"grp/send(backup): Cannot send, connection lost!\");\n         throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);\n     }\n \n@@ -4208,7 +4048,7 @@ void CUDTGroup::processKeepalive(CUDTGroup::SocketData* gli)\n         // the sequence per being IDLE and empty buffer), so a large portion of initial\n         // series of packets may come with past sequence, delaying this way with ACK,\n         // which may result not only with exceeded stability timeout (which fortunately\n-        // isn't being measured in this case), but also with receiving keepalive\n+        // isn't being measured in this case), but also with receiveing keepalive\n         // (therefore we also don't reset the link to IDLE in the temporary activation period).\n         if (gli->sndstate == SRT_GST_RUNNING && is_zero(gli->ps->core().m_tsFreshActivation))\n         {\ndiff --git a/srtcore/group.h b/srtcore/group.h\nindex e47f124..56f1456 100644\n--- a/srtcore/group.h\n+++ b/srtcore/group.h\n@@ -223,7 +223,7 @@ private:\n     bool send_CheckIdle(const gli_t d, std::vector<SRTSOCKET>& w_wipeme, std::vector<SRTSOCKET>& w_pendingLinks);\n \n \n-    /// This function checks if the member has just become idle (check if sender buffer is empty) to send a KEEPALIVE immediately.\n+    /// This function checks if the member has just become idle (check if sender buffer is empty) to send a KEEPALIVE immidiatelly.\n     /// @todo Check it is some abandoned logic.\n     void sendBackup_CheckIdleTime(gli_t w_d);\n     \n@@ -247,11 +247,11 @@ private:\n     /// @param[in,out] w_mc message control\n     /// @param[in] currtime current time\n     /// @param[in] currseq current packet sequence number\n-    /// @param[out] w_nsuccessful number of members with successful sending.\n+    /// @param[out] w_nsuccessful number of members with successfull sending.\n     /// @param[in,out] maxActiveWeight\n     /// @param[in,out] sendBackupCtx context\n     /// @param[in,out] w_cx error\n-    /// @return group send result: -1 if sending over all members has failed; number of bytes sent otherwise.\n+    /// @return group send result: -1 if sending over all members has failed; number of bytes sent overwise.\n     int sendBackup_SendOverActive(const char* buf, int len, SRT_MSGCTRL& w_mc, const steady_clock::time_point& currtime, int32_t& w_curseq,\n         size_t& w_nsuccessful, uint16_t& w_maxActiveWeight, SendBackupCtx& w_sendBackupCtx, CUDTException& w_cx);\n     \ndiff --git a/srtcore/group_backup.cpp b/srtcore/group_backup.cpp\nindex 825791d..9adb196 100644\n--- a/srtcore/group_backup.cpp\n+++ b/srtcore/group_backup.cpp\n@@ -144,30 +144,6 @@ unsigned SendBackupCtx::countMembersByState(BackupMemberState st) const\n     return m_stateCounter[st];\n }\n \n-void SendBackupCtx::getSocketIds(std::set<SRTSOCKET>& ids) const\n-{\n-    typedef vector<BackupMemberStateEntry>::const_iterator const_iter_t;\n-    for (const_iter_t i = m_memberStates.begin(); i != m_memberStates.end(); ++i)\n-    {\n-        ids.insert(i->socketID);\n-    }\n-}\n-\n-bool SendBackupCtx::deleteById(SRTSOCKET id)\n-{\n-    typedef vector<BackupMemberStateEntry>::iterator iter_t;\n-    for (iter_t i = m_memberStates.begin(); i != m_memberStates.end(); ++i)\n-    {\n-        if (i->socketID == id)\n-        {\n-            m_memberStates.erase(i);\n-            return true;\n-        }\n-    }\n-\n-    return false;\n-}\n-\n std::string SendBackupCtx::printMembers() const\n {\n     stringstream ss;\ndiff --git a/srtcore/group_backup.h b/srtcore/group_backup.h\nindex 4705cc3..ed2fb29 100644\n--- a/srtcore/group_backup.h\n+++ b/srtcore/group_backup.h\n@@ -92,13 +92,13 @@ namespace groups\n \n         /// @brief  Adds or updates a record of the member socket state.\n         /// @param pSocketDataIt Iterator to a socket\n-        /// @param st State of the member socket\n+        /// @param st State of the memmber socket\n         /// @todo Implement updating member state\n         void recordMemberState(SocketData* pSocketDataIt, BackupMemberState st);\n \n         /// @brief  Updates a record of the member socket state.\n         /// @param pSocketDataIt Iterator to a socket\n-        /// @param st State of the member socket\n+        /// @param st State of the memmber socket\n         /// @todo To be replaced by recordMemberState\n         /// @todo Update max weights?\n         void updateMemberState(const SocketData* pSocketDataIt, BackupMemberState st);\n@@ -107,8 +107,6 @@ namespace groups\n         /// Higher weight comes first, same weight: stable first, then fresh active.\n         void sortByWeightAndState();\n \n-        bool deleteById(SRTSOCKET id);\n-\n         BackupMemberState getMemberState(const SocketData* pSocketDataIt) const;\n \n         unsigned countMembersByState(BackupMemberState st) const;\n@@ -124,8 +122,6 @@ namespace groups\n \n         const CRateEstimator& getRateEstimate() const { return m_rateEstimate; }\n \n-        void getSocketIds(std::set<SRTSOCKET>& out) const;\n-\n     private:\n         std::vector<BackupMemberStateEntry> m_memberStates; // TODO: consider std::map here?\n         unsigned m_stateCounter[BKUPST_E_SIZE];\ndiff --git a/srtcore/handshake.cpp b/srtcore/handshake.cpp\nindex 878b904..c97b4e2 100644\n--- a/srtcore/handshake.cpp\n+++ b/srtcore/handshake.cpp\n@@ -51,11 +51,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n #include <iterator>\n #include <algorithm>\n \n-#include \"handshake.h\"\n-#include \"packet.h\"\n #include \"udt.h\"\n #include \"api.h\"\n #include \"core.h\"\n+#include \"handshake.h\"\n #include \"utilities.h\"\n \n using namespace std;\n@@ -199,7 +198,7 @@ bool srt::CHandShake::valid()\n {\n     if (m_iVersion < CUDT::HS_VERSION_UDT4\n             || m_iISN < 0 || m_iISN >= CSeqNo::m_iMaxSeqNo\n-            || m_iMSS < int(CPacket::UDP_HDR_SIZE_IPv6 + CPacket::HDR_SIZE)\n+            || m_iMSS < 32\n             || m_iFlightFlagSize < 2)\n         return false;\n \ndiff --git a/srtcore/list.cpp b/srtcore/list.cpp\nindex 8573ee2..0fe7d2b 100644\n--- a/srtcore/list.cpp\n+++ b/srtcore/list.cpp\n@@ -740,7 +740,7 @@ int32_t srt::CRcvLossList::removeUpTo(int32_t seqno_last)\n \n     if (CSeqNo::seqcmp(seqno_last, first) < 0)\n     {\n-        //HLOGC(tslog.Debug, log << \"rcv-loss: DROP to %\" << seqno_last << \" - first %\" << first << \" is newer, exiting\");\n+        //HLOGC(tslog.Debug, log << \"rcv-loss: DROP to %\" << seqno_last << \" - first %\" << first << \" is newer, exitting\");\n         return first; // seqno_last older than first - nothing to remove\n     }\n \n@@ -791,12 +791,13 @@ int32_t srt::CRcvLossList::getFirstLostSeq() const\n     return m_caSeq[m_iHead].seqstart;\n }\n \n-int srt::CRcvLossList::getLossArray(FixedArray<int32_t>& array)\n+void srt::CRcvLossList::getLossArray(int32_t* array, int& len, int limit)\n {\n-    int len = 0;\n+    len = 0;\n+\n     int i = m_iHead;\n \n-    while ((len < int(array.size()) - 1) && (i != -1))\n+    while ((len < limit - 1) && (-1 != i))\n     {\n         array[len] = m_caSeq[i].seqstart;\n         if (SRT_SEQNO_NONE != m_caSeq[i].seqend)\n@@ -811,7 +812,6 @@ int srt::CRcvLossList::getLossArray(FixedArray<int32_t>& array)\n \n         i = m_caSeq[i].inext;\n     }\n-    return len;\n }\n \n srt::CRcvFreshLoss::CRcvFreshLoss(int32_t seqlo, int32_t seqhi, int initial_age)\ndiff --git a/srtcore/list.h b/srtcore/list.h\nindex 539c184..40b8ee0 100644\n--- a/srtcore/list.h\n+++ b/srtcore/list.h\n@@ -57,7 +57,6 @@ modified by\n \n #include \"udt.h\"\n #include \"common.h\"\n-#include \"utilities.h\"\n \n namespace srt {\n \n@@ -163,7 +162,7 @@ public:\n \n     /// Insert a series of loss seq. no. between \"seqno1\" and \"seqno2\" into the receiver's loss list.\n     /// @param [in] seqno1 sequence number starts.\n-    /// @param [in] seqno2 sequence number ends.\n+    /// @param [in] seqno2 seqeunce number ends.\n     /// @return length of the loss record inserted (seqlen(seqno1, seqno2)), -1 on error.\n     int insert(int32_t seqno1, int32_t seqno2);\n \n@@ -204,9 +203,11 @@ public:\n     int32_t getFirstLostSeq() const;\n \n     /// Get a encoded loss array for NAK report.\n-    /// @param [inout] array the result list of seq. no. to be included in NAK.\n-    /// @return physical length of the result array.\n-    int getLossArray(FixedArray<int32_t>& array);\n+    /// @param [out] array the result list of seq. no. to be included in NAK.\n+    /// @param [out] len physical length of the result array.\n+    /// @param [in] limit maximum length of the array.\n+\n+    void getLossArray(int32_t* array, int& len, int limit);\n \n private:\n     struct Seq\ndiff --git a/srtcore/logging.h b/srtcore/logging.h\nindex dd9be95..7782245 100644\n--- a/srtcore/logging.h\n+++ b/srtcore/logging.h\n@@ -189,7 +189,6 @@ public:\n \n     ~LogDispatcher()\n     {\n-        src_config = NULL; // Allow to call CheckEnabled after destruction\n     }\n \n     bool CheckEnabled();\n@@ -391,12 +390,6 @@ struct LogDispatcher::Proxy\n \n #endif\n \n-\n-// IMPORTANT:\n-// 1. Logger objects are only allowed to be global. The CheckEnabled\n-//    method RELIES ON THAT it may run before the Logger() constructor is run.\n-// 2. Destructor resets src_config to NULL to prevent any logging instruction\n-//    to access the facility after destruction.\n class Logger\n {\n     int m_fa;\n@@ -432,16 +425,12 @@ inline bool LogDispatcher::CheckEnabled()\n     // when the enabler check is tested here. Worst case, the log\n     // will be printed just a moment after it was turned off.\n     const LogConfig* config = src_config; // to enforce using const operator[]\n-    if (config)\n-    {\n-        config->lock();\n-        int configured_enabled_fa = config->enabled_fa[fa];\n-        int configured_maxlevel = config->max_level;\n-        config->unlock();\n+    config->lock();\n+    int configured_enabled_fa = config->enabled_fa[fa];\n+    int configured_maxlevel = config->max_level;\n+    config->unlock();\n \n-        return configured_enabled_fa && level <= configured_maxlevel;\n-    }\n-    return false;\n+    return configured_enabled_fa && level <= configured_maxlevel;\n }\n \n \ndiff --git a/srtcore/packet.cpp b/srtcore/packet.cpp\nindex e0b1edf..1806230 100644\n--- a/srtcore/packet.cpp\n+++ b/srtcore/packet.cpp\n@@ -110,7 +110,7 @@ modified by\n //              Control Info: None\n //      2: Acknowledgement (UMSG_ACK)\n //              Add. Info:    The ACK sequence number\n-//              Control Info: The sequence number to which (but not include) all the previous packets have been received\n+//              Control Info: The sequence number to which (but not include) all the previous packets have beed received\n //              Optional:     RTT\n //                            RTT Variance\n //                            available receiver buffer size (in bytes)\n@@ -131,7 +131,7 @@ modified by\n //      7: Message Drop Request (UMSG_DROPREQ)\n //              Add. Info:    Message ID\n //              Control Info: first sequence number of the message\n-//                            last sequence number of the message\n+//                            last seqeunce number of the message\n //      8: Error Signal from the Peer Side (UMSG_PEERERROR)\n //              Add. Info:    Error code\n //              Control Info: None\n@@ -151,7 +151,7 @@ modified by\n //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n //\n //   Loss List Field Coding:\n-//      For any consecutive lost sequence numbers that the difference between\n+//      For any consecutive lost seqeunce numbers that the differnece between\n //      the last and first is more than 1, only record the first (a) and the\n //      the last (b) sequence numbers in the loss list field, and modify the\n //      the first bit of a to 1.\n@@ -174,7 +174,7 @@ using namespace srt_logging;\n \n namespace srt {\n \n-// Set up the aliases in the constructor\n+// Set up the aliases in the constructure\n CPacket::CPacket()\n     : m_nHeader() // Silences GCC 12 warning \"used uninitialized\".\n     , m_extra_pad()\ndiff --git a/srtcore/packet.h b/srtcore/packet.h\nindex a735c4c..5a6d6eb 100644\n--- a/srtcore/packet.h\n+++ b/srtcore/packet.h\n@@ -64,7 +64,7 @@ namespace srt\n \n //////////////////////////////////////////////////////////////////////////////\n // The purpose of the IOVector class is to proide a platform-independet interface\n-// to the WSABUF on Windows and iovec on Linux, that can be easily converted\n+// to the WSABUF on Windows and iovec on Linux, that can be easilly converted\n // to the native structure for use in WSARecvFrom() and recvmsg(...) functions\n class IOVector\n #ifdef _WIN32\n@@ -372,12 +372,7 @@ public:\n     static const size_t HDR_SIZE = sizeof(HEADER_TYPE); // packet header size = SRT_PH_E_SIZE * sizeof(uint32_t)\n \n     // Can also be calculated as: sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr).\n-    static const size_t BARE_UDP_HDR_SIZE = 8; // 8 bytes of UDP { u16 sport, dport, len, csum }.\n-    static const size_t IPv4_HDR_SIZE = 20; // 20 bytes IPv4\n-    static const size_t IPv6_HDR_SIZE = 40; // 40 bytes IPv6\n-\n-    static const size_t UDP_HDR_SIZE = BARE_UDP_HDR_SIZE + IPv4_HDR_SIZE;\n-    static const size_t UDP_HDR_SIZE_IPv6 = BARE_UDP_HDR_SIZE + IPv6_HDR_SIZE;\n+    static const size_t UDP_HDR_SIZE = 28; // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }.\n \n     static const size_t SRT_DATA_HDR_SIZE = UDP_HDR_SIZE + HDR_SIZE;\n \ndiff --git a/srtcore/packetfilter.cpp b/srtcore/packetfilter.cpp\nindex e8b2a61..dc7e5b4 100644\n--- a/srtcore/packetfilter.cpp\n+++ b/srtcore/packetfilter.cpp\n@@ -26,13 +26,12 @@ using namespace std;\n using namespace srt_logging;\n using namespace srt::sync;\n \n-namespace srt {\n-bool PacketFilter::Internal::ParseConfig(const string& s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf)\n+bool srt::ParseFilterConfig(const string& s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf)\n {\n     if (!SrtParseConfig(s, (w_config)))\n         return false;\n \n-    PacketFilter::Factory* fac = find(w_config.type);\n+    PacketFilter::Factory* fac = PacketFilter::find(w_config.type);\n     if (!fac)\n         return false;\n \n@@ -44,26 +43,24 @@ bool PacketFilter::Internal::ParseConfig(const string& s, SrtFilterConfig& w_con\n     return true;\n }\n \n-bool ParseFilterConfig(const std::string& s, SrtFilterConfig& w_config)\n+bool srt::ParseFilterConfig(const string& s, SrtFilterConfig& w_config)\n {\n-    return PacketFilter::internal().ParseConfig(s, (w_config), NULL);\n+    return ParseFilterConfig(s, (w_config), NULL);\n }\n \n // Parameters are passed by value because they need to be potentially modicied inside.\n-bool PacketFilter::Internal::CheckFilterCompat(SrtFilterConfig& w_agent, const SrtFilterConfig& peer_in)\n+bool srt::CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer)\n {\n-    PacketFilter::Factory* fac = find(w_agent.type);\n+    PacketFilter::Factory* fac = PacketFilter::find(w_agent.type);\n     if (!fac)\n         return false;\n \n     SrtFilterConfig defaults;\n-    if (!ParseConfig(fac->defaultConfig(), (defaults)))\n+    if (!ParseFilterConfig(fac->defaultConfig(), (defaults)))\n     {\n         return false;\n     }\n \n-    // Make a copy so that modifications can be done. This is only required for internal checks.\n-    SrtFilterConfig peer = peer_in;\n     set<string> keys;\n     // Extract all keys to identify also unspecified parameters on both sides\n     // Note that theoretically for FEC it could simply check for the \"cols\" parameter\n@@ -112,18 +109,20 @@ bool PacketFilter::Internal::CheckFilterCompat(SrtFilterConfig& w_agent, const S\n     return true;\n }\n \n-struct SortBySequence\n-{\n-    bool operator()(const CUnit* u1, const CUnit* u2)\n+namespace srt {\n+    struct SortBySequence\n     {\n-        int32_t s1 = u1->m_Packet.getSeqNo();\n-        int32_t s2 = u2->m_Packet.getSeqNo();\n+        bool operator()(const CUnit* u1, const CUnit* u2)\n+        {\n+            int32_t s1 = u1->m_Packet.getSeqNo();\n+            int32_t s2 = u2->m_Packet.getSeqNo();\n \n-        return CSeqNo::seqcmp(s1, s2) < 0;\n-    }\n-};\n+            return CSeqNo::seqcmp(s1, s2) < 0;\n+        }\n+    };\n+} // namespace srt\n \n-void PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_seqs_t& w_loss_seqs)\n+void srt::PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_seqs_t& w_loss_seqs)\n {\n     const CPacket& rpkt = unit->m_Packet;\n \n@@ -206,7 +205,7 @@ void PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_se\n \n }\n \n-bool PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet)\n+bool srt::PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet)\n {\n     bool have = m_filter->packControlPacket(m_sndctlpkt, seq);\n     if (!have)\n@@ -238,7 +237,7 @@ bool PacketFilter::packControlPacket(int32_t seq, int kflg, CPacket& w_packet)\n }\n \n \n-void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)\n+void srt::PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)\n {\n     if (m_provided.empty())\n         return;\n@@ -273,61 +272,42 @@ void PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)\n     m_provided.clear();\n }\n \n-// Placement here is necessary in order to mark the location to\n-// store the PacketFilter::Factory class characteristic object.\n-PacketFilter::Factory::~Factory()\n+bool srt::PacketFilter::IsBuiltin(const string& s)\n {\n+    return builtin_filters.count(s);\n }\n \n-#if HAVE_CXX11\n-\n-PacketFilter::Internal& PacketFilter::internal()\n-{\n-    static PacketFilter::Internal instance;\n-    return instance;\n-}\n-\n-#else // !HAVE_CXX11\n-\n-static pthread_once_t s_PacketFactoryOnce = PTHREAD_ONCE_INIT;\n-\n-static PacketFilter::Internal *getInstance()\n-{\n-    static PacketFilter::Internal instance;\n-    return &instance;\n+namespace srt {\n+std::set<std::string> PacketFilter::builtin_filters;\n+PacketFilter::filters_map_t PacketFilter::filters;\n }\n \n-PacketFilter::Internal& PacketFilter::internal()\n+srt::PacketFilter::Factory::~Factory()\n {\n-    // We don't want lock each time, pthread_once can be faster than mutex.\n-    pthread_once(&s_PacketFactoryOnce, reinterpret_cast<void (*)()>(getInstance));\n-    return *getInstance();\n }\n \n-#endif\n-\n-PacketFilter::Internal::Internal()\n+void srt::PacketFilter::globalInit()\n {\n     // Add here builtin packet filters and mark them\n     // as builtin. This will disallow users to register\n     // external filters with the same name.\n \n-    m_filters[\"fec\"] = new PacketFilter::Creator<FECFilterBuiltin>;\n-    m_builtin_filters.insert(\"fec\");\n+    filters[\"fec\"] = new Creator<FECFilterBuiltin>;\n+    builtin_filters.insert(\"fec\");\n }\n \n-bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr)\n+bool srt::PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& confstr)\n {\n     m_parent = parent;\n \n     SrtFilterConfig cfg;\n-    if (!internal().ParseConfig(confstr, (cfg)))\n+    if (!ParseFilterConfig(confstr, (cfg)))\n         return false;\n \n     // Extract the \"type\" key from parameters, or use\n     // builtin if lacking.\n-    PacketFilter::Factory *factory = internal().find(cfg.type);\n-    if (factory == NULL)\n+    filters_map_t::iterator selector = filters.find(cfg.type);\n+    if (selector == filters.end())\n         return false;\n \n     SrtFilterInitializer init;\n@@ -344,7 +324,7 @@ bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& co\n             << init.payload_size << \" rcvbuf size=\" << init.rcvbuf_size);\n \n     // Found a filter, so call the creation function\n-    m_filter = factory->Create(init, m_provided, confstr);\n+    m_filter = selector->second->Create(init, m_provided, confstr);\n     if (!m_filter)\n         return false;\n \n@@ -356,7 +336,7 @@ bool PacketFilter::configure(CUDT* parent, CUnitQueue* uq, const std::string& co\n     return true;\n }\n \n-bool PacketFilter::correctConfig(const SrtFilterConfig& conf)\n+bool srt::PacketFilter::correctConfig(const SrtFilterConfig& conf)\n {\n     const string* pname = map_getp(conf.parameters, \"type\");\n \n@@ -366,16 +346,15 @@ bool PacketFilter::correctConfig(const SrtFilterConfig& conf)\n     if (*pname == \"adaptive\")\n         return true;\n \n-    PacketFilter::Factory *factory = internal().find(*pname);\n-    if (factory == NULL)\n+    filters_map_t::iterator x = filters.find(*pname);\n+    if (x == filters.end())\n         return false;\n \n     return true;\n }\n \n-PacketFilter::~PacketFilter()\n+srt::PacketFilter::~PacketFilter()\n {\n     delete m_filter;\n }\n \n-} // namespace srt\ndiff --git a/srtcore/packetfilter.h b/srtcore/packetfilter.h\nindex 8d4dc63..429e81e 100644\n--- a/srtcore/packetfilter.h\n+++ b/srtcore/packetfilter.h\n@@ -51,6 +51,7 @@ public:\n         virtual ~Factory();\n     };\n private:\n+    friend bool ParseFilterConfig(const std::string& s, SrtFilterConfig& out, PacketFilter::Factory** ppf);\n \n     template <class Target>\n     class Creator: public Factory\n@@ -73,6 +74,7 @@ private:\n         virtual ~Creator() {}\n     };\n \n+\n     // We need a private wrapper for the auto-pointer, can't use\n     // std::unique_ptr here due to no C++11.\n     struct ManagedPtr\n@@ -112,6 +114,14 @@ private:\n         Factory* get() { return f; }\n     };\n \n+    // The list of builtin names that are reserved.\n+    static std::set<std::string> builtin_filters;\n+\n+    // Temporarily changed to linear searching, until this is exposed\n+    // for a user-defined filter.\n+    typedef std::map<std::string, ManagedPtr> filters_map_t;\n+    static filters_map_t filters;\n+\n     // This is a filter container.\n     SrtPacketFilterBase* m_filter;\n     void Check()\n@@ -123,52 +133,29 @@ private:\n         // Don't do any check for now.\n     }\n \n-    friend class Internal;\n-\n public:\n-    class Internal\n-    {\n-    public:\n-\n-        // The list of builtin names that are reserved.\n-        std::set<std::string> m_builtin_filters;\n \n-        // Temporarily changed to linear searching, until this is exposed\n-        // for a user-defined filter.\n-        typedef std::map<std::string, ManagedPtr> filters_map_t;\n-        filters_map_t m_filters;\n+    static void globalInit();\n \n+    static bool IsBuiltin(const std::string&);\n \n-    public:\n-\n-        bool IsBuiltin(const std::string& s)\n-        {\n-            return m_builtin_filters.count(s);\n-        }\n-\n-        template <class NewFilter>\n-        bool add(const std::string& name)\n-        {\n-            if (IsBuiltin(name))\n-                return false;\n+    template <class NewFilter>\n+    static bool add(const std::string& name)\n+    {\n+        if (IsBuiltin(name))\n+            return false;\n \n-            m_filters[name] = new Creator<NewFilter>;\n-            return true;\n-        }\n+        filters[name] = new Creator<NewFilter>;\n+        return true;\n+    }\n \n-        Factory* find(const std::string& type)\n-        {\n-            filters_map_t::iterator i = m_filters.find(type);\n-            if (i == m_filters.end())\n-                return NULL; // No matter what to return - this is \"undefined behavior\" to be prevented\n-            return i->second.get();\n-        }\n-        bool ParseConfig(const std::string& s, SrtFilterConfig& out, PacketFilter::Factory** ppf = NULL);\n-        bool CheckFilterCompat(srt::SrtFilterConfig& w_agent, const srt::SrtFilterConfig& peer);\n-    public:\n-        Internal();\n-    };\n-    static Internal& internal(); // Singleton accessor\n+    static Factory* find(const std::string& type)\n+    {\n+        filters_map_t::iterator i = filters.find(type);\n+        if (i == filters.end())\n+            return NULL; // No matter what to return - this is \"undefined behavior\" to be prevented\n+        return i->second.get();\n+    }\n \n     // Filter is optional, so this check should be done always\n     // manually.\n@@ -184,7 +171,7 @@ public:\n     // Copy constructor - important when listener-spawning\n     // Things being done:\n     // 1. The filter is individual, so don't copy it. Set NULL.\n-    // 2. This will be configured anyway basing on possibly a new rule set.\n+    // 2. This will be configued anyway basing on possibly a new rule set.\n     PacketFilter(const PacketFilter& source SRT_ATR_UNUSED): m_filter(), m_parent(), m_sndctlpkt(0), m_unitq() {}\n \n     // This function will be called by the parent CUDT\n@@ -201,8 +188,8 @@ public:\n     ~PacketFilter();\n \n     // Simple wrappers\n-    void feedSource(CPacket& w_packet) { SRT_ASSERT(m_filter); return m_filter->feedSource((w_packet)); }\n-    SRT_ARQLevel arqLevel() { SRT_ASSERT(m_filter); return m_filter->arqLevel(); }\n+    void feedSource(CPacket& w_packet);\n+    SRT_ARQLevel arqLevel();\n     bool packControlPacket(int32_t seq, int kflg, CPacket& w_packet);\n     void receive(CUnit* unit, std::vector<CUnit*>& w_incoming, loss_seqs_t& w_loss_seqs);\n \n@@ -220,10 +207,12 @@ protected:\n     std::vector<SrtPacket> m_provided;\n };\n \n-inline bool CheckFilterCompat(SrtFilterConfig& w_agent, const SrtFilterConfig& peer)\n-{\n-    return PacketFilter::internal().CheckFilterCompat((w_agent), peer);\n-}\n+bool CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer);\n+\n+inline void PacketFilter::feedSource(CPacket& w_packet) { SRT_ASSERT(m_filter); return m_filter->feedSource((w_packet)); }\n+inline SRT_ARQLevel PacketFilter::arqLevel() { SRT_ASSERT(m_filter); return m_filter->arqLevel(); }\n+\n+bool ParseFilterConfig(const std::string& s, SrtFilterConfig& out, PacketFilter::Factory** ppf);\n \n } // namespace srt\n \ndiff --git a/srtcore/platform_sys.h b/srtcore/platform_sys.h\nindex 5dd2b92..83763e5 100644\n--- a/srtcore/platform_sys.h\n+++ b/srtcore/platform_sys.h\n@@ -68,9 +68,7 @@\n // also other macros, like TARGET_OS_IOS etc.\n \n #include \"TargetConditionals.h\"\n-#ifndef __APPLE_USE_RFC_3542\n #define __APPLE_USE_RFC_3542 /* IPV6_PKTINFO */\n-#endif\n \n #ifdef SRT_IMPORT_TIME\n       #include <mach/mach_time.h>\ndiff --git a/srtcore/queue.cpp b/srtcore/queue.cpp\nindex 278d802..6cb4fae 100644\n--- a/srtcore/queue.cpp\n+++ b/srtcore/queue.cpp\n@@ -220,11 +220,6 @@ srt::CSndUList::~CSndUList()\n     delete[] m_pHeap;\n }\n \n-void srt::CSndUList::resetAtFork()\n-{\n-    resetCond(m_ListCond);\n-}\n-\n void srt::CSndUList::update(const CUDT* u, EReschedule reschedule, sync::steady_clock::time_point ts)\n {\n     ScopedLock listguard(m_ListLock);\n@@ -419,17 +414,6 @@ srt::CSndQueue::CSndQueue()\n }\n \n srt::CSndQueue::~CSndQueue()\n-{\n-    delete m_pSndUList;\n-}\n-\n-void srt::CSndQueue::resetAtFork()\n-{\n-    resetThread(&m_WorkerThread);\n-    m_pSndUList->resetAtFork();\n-}\n-\n-void srt::CSndQueue::stop()\n {\n     m_bClosing = true;\n \n@@ -446,6 +430,8 @@ void srt::CSndQueue::stop()\n         HLOGC(rslog.Debug, log << \"SndQueue: EXIT\");\n         m_WorkerThread.join();\n     }\n+\n+    delete m_pSndUList;\n }\n \n int srt::CSndQueue::ioctlQuery(int type) const\n@@ -927,7 +913,7 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst\n         return;\n \n     HLOGC(cnlog.Debug,\n-          log << FUNID() << \": collected \" << toProcess.size() << \" for processing, \" << toRemove.size()\n+          log << \"updateConnStatus: collected \" << toProcess.size() << \" for processing, \" << toRemove.size()\n               << \" to close\");\n \n     // Repeat (resend) connection request.\n@@ -947,45 +933,43 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst\n         // to interpret these data (for caller-listener this was already done by `processConnectRequest`\n         // before calling this function), and it checks for the data presence.\n \n+        EReadStatus    read_st = rst;\n+        EConnectStatus conn_st = cst;\n+\n         CUDTUnited::SocketKeeper sk (CUDT::uglobal(), i->id);\n         if (!sk.socket)\n         {\n             // Socket deleted already, so stop this and proceed to the next loop.\n-            LOGC(cnlog.Error, log << FUNID() << \": IPE: socket @\" << i->id << \" already closed, proceed to only removal from lists\");\n+            LOGC(cnlog.Error, log << \"updateConnStatus: IPE: socket @\" << i->id << \" already closed, proceed to only removal from lists\");\n             toRemove.push_back(*i);\n             continue;\n         }\n \n-        EReadStatus    read_st = rst;\n-        EConnectStatus conn_st = cst;\n-\n-        // Ok, we should have 3 cases here:\n-        // 1. id == 0  ==> conn_st cannot be == CONN_RENDEZVOUS; reset to AGAIN always\n-        // 2. conn_st == CONN_RENDEZVOUS -> id > 0 and no \"alien\" sockets are expected to be in the loop -> never reset to AGAIN\n-        // 3. id > 0 and no rendezvous -> reset to AGAIN, unless id == dest_id.\n \n-        // Condition:\n-        // IF CONN_RENDEZVOUS -> never reset to AGAIN.\n-        // ELSE IF dest_id == id -> don't reset to AGAIN\n-        // ELSE: reset to again.\n-\n-        if (cst == CONN_RENDEZVOUS || i->id == dest_id)\n+        if (cst != CONN_RENDEZVOUS && dest_id != 0)\n         {\n-            HLOGC(cnlog.Debug, log << FUNID() << \": applied to @\" << i->id\n-                    << (cst == CONN_RENDEZVOUS ? \"[RDV] \" : \"\")\n-                    << \" with target @\" << dest_id << \" -- remains: cst=\" << ConnectStatusStr(cst));\n+            if (i->id != dest_id)\n+            {\n+                HLOGC(cnlog.Debug, log << \"updateConnStatus: cst=\" << ConnectStatusStr(cst) << \" but for RID @\" << i->id\n+                        << \" dest_id=@\" << dest_id << \" - resetting to AGAIN\");\n+\n+                read_st = RST_AGAIN;\n+                conn_st = CONN_AGAIN;\n+            }\n+            else\n+            {\n+                HLOGC(cnlog.Debug, log << \"updateConnStatus: cst=\" << ConnectStatusStr(cst) << \" for @\"\n+                        << i->id);\n+            }\n         }\n         else\n         {\n-            HLOGC(cnlog.Debug, log << FUNID() << \": applied to @\" << i->id\n-                    << \" with target @\" << dest_id << \" -- resetting to AGAIN\");\n-\n-            read_st = RST_AGAIN;\n-            conn_st = CONN_AGAIN;\n+            HLOGC(cnlog.Debug, log << \"updateConnStatus: cst=\" << ConnectStatusStr(cst) << \" and dest_id=@\" << dest_id\n+                    << \" - NOT checking against RID @\" << i->id);\n         }\n \n         HLOGC(cnlog.Debug,\n-              log << FUNID() << \": processing async conn for @\" << i->id << \" FROM \" << i->peeraddr.str());\n+              log << \"updateConnStatus: processing async conn for @\" << i->id << \" FROM \" << i->peeraddr.str());\n \n         if (!i->u->processAsyncConnectRequest(read_st, conn_st, pkt, i->peeraddr))\n         {\n@@ -1006,14 +990,14 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst\n \n     for (vector<LinkStatusInfo>::iterator i = toRemove.begin(); i != toRemove.end(); ++i)\n     {\n-        HLOGC(cnlog.Debug, log << FUNID() << \": COMPLETING dep objects update on failed @\" << i->id);\n+        HLOGC(cnlog.Debug, log << \"updateConnStatus: COMPLETING dep objects update on failed @\" << i->id);\n         remove(i->id);\n \n         CUDTUnited::SocketKeeper sk (CUDT::uglobal(), i->id);\n         if (!sk.socket)\n         {\n             // This actually shall never happen, so it's a kind of paranoid check.\n-            LOGC(cnlog.Error, log << FUNID() << \": IPE: socket @\" << i->id << \" already closed, NOT ACCESSING its contents\");\n+            LOGC(cnlog.Error, log << \"updateConnStatus: IPE: socket @\" << i->id << \" already closed, NOT ACCESSING its contents\");\n             continue;\n         }\n \n@@ -1050,7 +1034,7 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst\n             if (find_if(toRemove.begin(), toRemove.end(), LinkStatusInfo::HasID(i->m_iID)) != toRemove.end())\n             {\n                 LOGC(cnlog.Error,\n-                     log << FUNID() << \": processAsyncConnectRequest FAILED on @\" << i->m_iID\n+                     log << \"updateConnStatus: processAsyncConnectRequest FAILED on @\" << i->m_iID\n                          << \". Setting TTL as EXPIRED.\");\n                 i->m_tsTTL =\n                     steady_clock::time_point(); // Make it expire right now, will be picked up at the next iteration\n@@ -1071,7 +1055,7 @@ bool srt::CRendezvousQueue::qualifyToHandle(EReadStatus    rst,\n         return false; // nothing to process.\n \n     HLOGC(cnlog.Debug,\n-          log << FUNID() << \": updating after getting pkt with DST socket ID @\" << iDstSockID\n+          log << \"updateConnStatus: updating after getting pkt with DST socket ID @\" << iDstSockID\n               << \" status: \" << ConnectStatusStr(cst));\n \n     for (list<CRL>::iterator i = m_lRendezvousID.begin(), i_next = i; i != m_lRendezvousID.end(); i = i_next)\n@@ -1184,6 +1168,15 @@ srt::CRcvQueue::CRcvQueue()\n \n srt::CRcvQueue::~CRcvQueue()\n {\n+    m_bClosing = true;\n+\n+    if (m_WorkerThread.joinable())\n+    {\n+        HLOGC(rslog.Debug, log << \"RcvQueue: EXIT\");\n+        m_WorkerThread.join();\n+    }\n+    releaseCond(m_BufferCond);\n+\n     delete m_pUnitQueue;\n     delete m_pRcvUList;\n     delete m_pHash;\n@@ -1201,24 +1194,6 @@ srt::CRcvQueue::~CRcvQueue()\n     }\n }\n \n-void srt::CRcvQueue::resetAtFork()\n-{\n-    resetThread(&m_WorkerThread);\n-}\n-\n-void srt::CRcvQueue::stop()\n-{\n-    m_bClosing = true;\n-\n-    if (m_WorkerThread.joinable())\n-    {\n-        HLOGC(rslog.Debug, log << \"RcvQueue: EXIT\");\n-        m_WorkerThread.join();\n-    }\n-    releaseCond(m_BufferCond);\n-}\n-\n-\n #if ENABLE_LOGGING\n srt::sync::atomic<int> srt::CRcvQueue::m_counter(0);\n #endif\n@@ -1253,7 +1228,7 @@ void srt::CRcvQueue::init(int qsize, size_t payload, int version, int hsize, CCh\n     }\n }\n \n-void* srt::CRcvQueue::worker(void* param) ATR_NOEXCEPT\n+void* srt::CRcvQueue::worker(void* param)\n {\n     CRcvQueue*   self = (CRcvQueue*)param;\n     sockaddr_any sa(self->getIPversion());\n@@ -1330,11 +1305,7 @@ void* srt::CRcvQueue::worker(void* param) ATR_NOEXCEPT\n                          << \"CChannel reported ERROR DURING TRANSMISSION - IPE. INTERRUPTING worker anyway.\");\n             }\n             cst = CONN_REJECT;\n-\n-            // DO NOT interrupt though - the worker thread must run until all\n-            // sockets are removed from the multiplexer. Alternatively you can forcefully\n-            // remove all sockets from the receive U list.\n-            continue;\n+            break;\n         }\n         // OTHERWISE: this is an \"AGAIN\" situation. No data was read, but the process should continue.\n \n@@ -1356,7 +1327,10 @@ void* srt::CRcvQueue::worker(void* param) ATR_NOEXCEPT\n             {\n                 HLOGC(qrlog.Debug,\n                       log << CUDTUnited::CONID(u->m_SocketID) << \" SOCKET broken, REMOVING FROM RCV QUEUE/MAP.\");\n-                self->removeFromLists(u);\n+                // the socket must be removed from Hash table first, then RcvUList\n+                self->m_pHash->remove(u->m_SocketID);\n+                self->m_pRcvUList->remove(u);\n+                u->m_pRNode->m_bOnList = false;\n             }\n \n             ul = self->m_pRcvUList->m_pUList;\n@@ -1455,7 +1429,7 @@ srt::EConnectStatus srt::CRcvQueue::worker_ProcessConnectionRequest(CUnit* unit,\n     bool have_listener = false;\n     {\n         SharedLock shl(m_pListener);\n-        CUDT*      pListener = m_pListener.get_locked(shl);\n+        CUDT*      pListener = m_pListener.getPtrNoLock();\n \n         if (pListener)\n         {\n@@ -1562,7 +1536,7 @@ srt::EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUni\n         // side just started sending its handshake packets, the local side has already\n         // run the CRcvQueue::worker thread, and this worker thread is trying to dispatch\n         // the handshake packet too early, before the dispatcher has a chance to see\n-        // this socket registered in the RendezvousQueue, which causes the packet unable\n+        // this socket registerred in the RendezvousQueue, which causes the packet unable\n         // to be dispatched. Therefore simply treat every \"out of band\" packet (with socket\n         // not belonging to the connection and not registered as rendezvous) as \"possible\n         // attack\" and ignore it. This also should better protect the rendezvous socket\n@@ -1623,7 +1597,7 @@ srt::EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUni\n             // that we KNOW (by the cst == CONN_ACCEPT result) that the socket should be inserted\n             // into the pending anteroom.\n \n-            CUDT* ne = getNewEntry(); // This function actually removes the entry and returns it.\n+            CUDT* ne = getNewEntry(); // This function actuall removes the entry and returns it.\n             // This **should** now always return a non-null value, but check it first\n             // because if this accidentally isn't true, the call to worker_ProcessAddressedPacket will\n             // result in redirecting it to here and so on until the call stack overflow. In case of\n@@ -1746,25 +1720,17 @@ int srt::CRcvQueue::recvfrom(int32_t id, CPacket& w_packet)\n     return (int)w_packet.getLength();\n }\n \n-bool srt::CRcvQueue::setListener(CUDT* u)\n+int srt::CRcvQueue::setListener(CUDT* u)\n {\n-    return m_pListener.compare_exchange(NULL, u);\n-}\n+    if (!m_pListener.set(u))\n+        return -1;\n \n-srt::CUDT* srt::CRcvQueue::getListener()\n-{\n-    SharedLock lkl (m_pListener);\n-    return m_pListener.get_locked(lkl);\n+    return 0;\n }\n \n-// XXX NOTE: TSan reports here false positive against the call\n-// to locateSocket in CUDTUnited::newConnection. This here will apply\n-// exclusive lock on m_pListener, while keeping shared lock on\n-// CUDTUnited::m_GlobControlLock in CUDTUnited::closeAllSockets.\n-// As the other thread locks both as shared, this is no deadlock risk.\n-bool srt::CRcvQueue::removeListener(CUDT* u)\n+void srt::CRcvQueue::removeListener(const CUDT* u)\n {\n-    return m_pListener.compare_exchange(u, NULL);\n+    m_pListener.clearIf(u);\n }\n \n void srt::CRcvQueue::registerConnector(const SRTSOCKET&                id,\n@@ -1845,43 +1811,16 @@ void srt::CRcvQueue::storePktClone(int32_t id, const CPacket& pkt)\n     }\n }\n \n-void srt::CRcvQueue::removeFromLists(CUDT* u)\n-{\n-    // the socket must be removed from Hash table first, then RcvUList\n-    m_pHash->remove(u->m_SocketID);\n-    m_pRcvUList->remove(u);\n-    u->m_pRNode->m_bOnList = false;\n-}\n-\n-void srt::CMultiplexer::resetAtFork()\n+void srt::CMultiplexer::destroy()\n {\n-    if (m_pRcvQueue != NULL)\n-        m_pRcvQueue->resetAtFork();\n-    if (m_pSndQueue != NULL)\n-        m_pSndQueue->resetAtFork();\n-}\n+    // Reverse order of the assigned.\n+    delete m_pRcvQueue;\n+    delete m_pSndQueue;\n+    delete m_pTimer;\n \n-void srt::CMultiplexer::close()\n-{\n     if (m_pChannel)\n     {\n         m_pChannel->close();\n         delete m_pChannel;\n-        m_pChannel = NULL;\n     }\n }\n-\n-void srt::CMultiplexer::stop()\n-{\n-    if (m_pRcvQueue != NULL)\n-        m_pRcvQueue->stop();\n-    if (m_pSndQueue != NULL)\n-        m_pSndQueue->stop();\n-}\n-\n-void srt::CMultiplexer::destroy()\n-{\n-    // Reverse order of the assigned.\n-    stop();\n-    close();\n-}\ndiff --git a/srtcore/queue.h b/srtcore/queue.h\nindex 2b537a5..48bedd9 100644\n--- a/srtcore/queue.h\n+++ b/srtcore/queue.h\n@@ -157,7 +157,6 @@ public:\n     };\n \n     static EReschedule rescheduleIf(bool cond) { return cond ? DO_RESCHEDULE : DONT_RESCHEDULE; }\n-    void resetAtFork();\n \n     /// Update the timestamp of the UDT instance on the list.\n     /// @param [in] u pointer to the UDT instance\n@@ -339,7 +338,7 @@ public:\n \n     /// @brief Update status of connections in the pending queue.\n     /// Stop connecting if TTL expires. Resend handshake request every 250 ms if no response from the peer.\n-    /// @param rst result of reading from a UDP socket: received packet / nothing read / read error.\n+    /// @param rst result of reading from a UDP socket: received packet / nothin read / read error.\n     /// @param cst target status for pending connection: reject or proceed.\n     /// @param pktIn packet received from the UDP socket.\n     void updateConnStatus(EReadStatus rst, EConnectStatus cst, CUnit* unit);\n@@ -368,7 +367,7 @@ private:\n     /// - Sockets with expired TTL go to the 'to_remove' list and removed from the queue straight away.\n     /// - If HS request is to be resent (resend 250 ms if no response from the peer) go to the 'to_process' list.\n     ///\n-    /// @param rst result of reading from a UDP socket: received packet / nothing read / read error.\n+    /// @param rst result of reading from a UDP socket: received packet / nothin read / read error.\n     /// @param cst target status for pending connection: reject or proceed.\n     /// @param iDstSockID destination socket ID of the received packet.\n     /// @param[in,out] toRemove stores sockets with expired TTL.\n@@ -402,7 +401,6 @@ public:\n     ~CSndQueue();\n \n public:\n-    void resetAtFork();\n     // XXX There's currently no way to access the socket ID set for\n     // whatever the queue is currently working for. Required to find\n     // some way to do this, possibly by having a \"reverse pointer\".\n@@ -441,7 +439,6 @@ public:\n     int sockoptQuery(int level, int type) const;\n \n     void setClosing() { m_bClosing = true; }\n-    void stop();\n \n private:\n     static void*  worker(void* param);\n@@ -489,7 +486,6 @@ public:\n     ~CRcvQueue();\n \n public:\n-    void resetAtFork();\n     // XXX There's currently no way to access the socket ID set for\n     // whatever the queue is currently working. Required to find\n     // some way to do this, possibly by having a \"reverse pointer\".\n@@ -517,11 +513,8 @@ public:\n \n     int getIPversion() { return m_iIPversion; }\n \n-    void removeFromLists(CUDT* u);\n-\n-    void stop();\n private:\n-    static void*  worker(void* param) ATR_NOEXCEPT;\n+    static void*  worker(void* param);\n     sync::CThread m_WorkerThread;\n     // Subroutines of worker\n     EReadStatus    worker_RetrieveUnit(int32_t& id, CUnit*& unit, sockaddr_any& sa);\n@@ -545,9 +538,8 @@ private:\n #endif\n \n private:\n-    bool setListener(CUDT* u);\n-    CUDT* getListener();\n-    bool removeListener(CUDT* u);\n+    int  setListener(CUDT* u);\n+    void removeListener(const CUDT* u);\n \n     void registerConnector(const SRTSOCKET&                      id,\n                            CUDT*                                 u,\n@@ -606,19 +598,6 @@ struct CMultiplexer\n     {\n     }\n \n-    ~CMultiplexer()\n-    {\n-        if (m_pRcvQueue != NULL)\n-            delete m_pRcvQueue;\n-        if (m_pSndQueue != NULL)\n-            delete m_pSndQueue;\n-        if (m_pTimer != NULL)\n-            delete m_pTimer;\n-        close();\n-    }\n-    void resetAtFork();\n-    void close();\n-    void stop();\n     void destroy();\n };\n \ndiff --git a/srtcore/socketconfig.cpp b/srtcore/socketconfig.cpp\nindex e3ad5cd..1c067d0 100644\n--- a/srtcore/socketconfig.cpp\n+++ b/srtcore/socketconfig.cpp\n@@ -56,7 +56,7 @@ namespace srt\n {\n int RcvBufferSizeOptionToValue(int val, int flightflag, int mss)\n {\n-    // Minimum recv buffer size is 32 packets\n+    // Mimimum recv buffer size is 32 packets\n     const int mssin_size = mss - CPacket::UDP_HDR_SIZE;\n \n     int bufsize;\n@@ -811,7 +811,7 @@ struct CSrtConfigSetter<SRTO_PACKETFILTER>\n         // Parse the configuration string prematurely\n         SrtFilterConfig fc;\n         PacketFilter::Factory* fax = 0;\n-        if (!PacketFilter::internal().ParseConfig(arg, (fc), (&fax)))\n+        if (!ParseFilterConfig(arg, (fc), (&fax)))\n         {\n             LOGC(aclog.Error,\n                  log << \"SRTO_PACKETFILTER: Incorrect syntax. Use: FILTERTYPE[,KEY:VALUE...]. \"\n@@ -1025,7 +1025,7 @@ bool CSrtConfig::payloadSizeFits(size_t val, int /*ip_family*/, std::string& w_e\n         }\n     }\n \n-    // Not checking AUTO to allow default 1456 bytes.\n+    // Not checking AUTO to allow defaul 1456 bytes.\n     if ((this->iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM)\n             && (val > (SRT_LIVE_MAX_PLSIZE - HAICRYPT_AUTHTAG_MAX)))\n     {\n@@ -1089,10 +1089,10 @@ bool SRT_SocketOptionObject::add(SRT_SOCKOPT optname, const void* optval, size_t\n \n     // Header size will get the size likely aligned, but it won't\n     // hurt if the memory size will be up to 4 bytes more than\n-    // needed - and it's better to not risk that alignment rules\n+    // needed - and it's better to not risk that alighment rules\n     // will make these calculations result in less space than needed.\n     const size_t headersize = sizeof(SingleOption);\n-    const size_t payload = std::max(sizeof(uint32_t), optlen);\n+    const size_t payload = std::min(sizeof(uint32_t), optlen);\n     unsigned char* mem = new unsigned char[headersize + payload];\n     SingleOption* option = reinterpret_cast<SingleOption*>(mem);\n     option->option = optname;\ndiff --git a/srtcore/socketconfig.h b/srtcore/socketconfig.h\nindex f44e3c2..8a78ea2 100644\n--- a/srtcore/socketconfig.h\n+++ b/srtcore/socketconfig.h\n@@ -70,8 +70,6 @@ written by\n #define SRT_VERSION_MIN(v) (0x00FF00 & (v))\n #define SRT_VERSION_PCH(v) (0x0000FF & (v))\n \n-static const int SRT_OHEAD_DEFAULT_P100 = 25;\n-\n // NOTE: SRT_VERSION is primarily defined in the build file.\n extern const int32_t SRT_DEF_VERSION;\n \n@@ -93,7 +91,7 @@ struct CSrtMuxerConfig\n     int iUDPSndBufSize; // UDP sending buffer size\n     int iUDPRcvBufSize; // UDP receiving buffer size\n \n-    // NOTE: this operator is not reversible. The syntax must use:\n+    // NOTE: this operator is not reversable. The syntax must use:\n     //  muxer_entry == socket_entry\n     bool isCompatWith(const CSrtMuxerConfig& other) const\n     {\n@@ -144,12 +142,6 @@ public:\n         memset(stor, 0, sizeof stor);\n     }\n \n-    StringStorage(const char* s, size_t length)\n-        : len(0)\n-    {\n-        set(s, length);\n-\t}\n-\n     bool set(const char* s, size_t length)\n     {\n         if (length > SIZE)\n@@ -212,7 +204,7 @@ struct CSrtConfig: CSrtMuxerConfig\n     static const int      COMM_RESPONSE_TIMEOUT_MS      = 5 * 1000; // 5 seconds\n     static const uint32_t COMM_DEF_MIN_STABILITY_TIMEOUT_MS = 60;   // 60 ms\n \n-    // Minimum recv flight flag size is 32 packets\n+    // Mimimum recv flight flag size is 32 packets\n     static const int    DEF_MIN_FLIGHT_PKT = 32;\n     static const size_t MAX_SID_LENGTH     = 512;\n     static const size_t MAX_PFILTER_LENGTH = 64;\n@@ -318,7 +310,7 @@ struct CSrtConfig: CSrtMuxerConfig\n         , iCryptoMode(CIPHER_MODE_AUTO)\n         , llInputBW(0)\n         , llMinInputBW(0)\n-        , iOverheadBW(SRT_OHEAD_DEFAULT_P100)\n+        , iOverheadBW(25)\n         , bRcvNakReport(true)\n         , iMaxReorderTolerance(0) // Sensible optimal value is 10, 0 preserves old behavior\n         , uKmRefreshRatePkt(0)\n@@ -339,7 +331,7 @@ struct CSrtConfig: CSrtMuxerConfig\n \n         // Default congestion is \"live\".\n         // Available builtin congestions: \"file\".\n-        // Others can be registered.\n+        // Others can be registerred.\n         sCongestion.set(\"live\", 4);\n     }\n \ndiff --git a/srtcore/srt.h b/srtcore/srt.h\nindex 43c6593..614a85a 100644\n--- a/srtcore/srt.h\n+++ b/srtcore/srt.h\n@@ -109,21 +109,17 @@ written by\n \n #define SRT_ATR_DEPRECATED\n #define SRT_ATR_DEPRECATED_PX [[deprecated]]\n-#define SRT_ATR_NODISCARD [[nodiscard]]\n \n // GNUG is GNU C/C++; this syntax is also supported by Clang\n #elif defined(__GNUC__)\n #define SRT_ATR_DEPRECATED_PX\n #define SRT_ATR_DEPRECATED __attribute__((deprecated))\n-#define SRT_ATR_NODISCARD __attribute__((warn_unused_result))\n #elif defined(_MSC_VER)\n #define SRT_ATR_DEPRECATED_PX __declspec(deprecated)\n #define SRT_ATR_DEPRECATED // no postfix-type modifier\n-#define SRT_ATR_NODISCARD _Check_return_\n #else\n #define SRT_ATR_DEPRECATED_PX\n #define SRT_ATR_DEPRECATED\n-#define SRT_ATR_NODISCARD\n #endif\n \n #ifdef __cplusplus\n@@ -142,10 +138,8 @@ static const int32_t SRTGROUP_MASK = (1 << 30);\n \n #ifdef _WIN32\n    typedef SOCKET SYSSOCKET;\n-   static const SYSSOCKET SYSSOCKET_INVALID = INVALID_SOCKET;\n #else\n    typedef int SYSSOCKET;\n-   static const int SYSSOCKET_INVALID = -1;\n #endif\n \n #ifndef ENABLE_BONDING\n@@ -188,7 +182,7 @@ typedef enum SRT_SOCKOPT {\n    SRTO_RCVTIMEO = 14,       // recv() timeout\n    SRTO_REUSEADDR = 15,      // reuse an existing port or create a new one\n    SRTO_MAXBW = 16,          // maximum bandwidth (bytes per second) that the connection can use\n-   SRTO_STATE = 17,          // current socket state, see SRT_SOCKSTATUS, read only\n+   SRTO_STATE = 17,          // current socket state, see UDTSTATUS, read only\n    SRTO_EVENT = 18,          // current available events associated with the socket\n    SRTO_SNDDATA = 19,        // size of data in the sending buffer\n    SRTO_RCVDATA = 20,        // size of data available for recv\n@@ -223,7 +217,7 @@ typedef enum SRT_SOCKOPT {\n    SRTO_PAYLOADSIZE,         // Maximum payload size sent in one UDP packet (0 if unlimited)\n    SRTO_TRANSTYPE = 50,      // Transmission type (set of options required for given transmission type)\n    SRTO_KMREFRESHRATE,       // After sending how many packets the encryption key should be flipped to the new key\n-   SRTO_KMPREANNOUNCE,       // How many packets before key flip the new key is announced and after key flip the old one decommissioned\n+   SRTO_KMPREANNOUNCE,       // How many packets before key flip the new key is annnounced and after key flip the old one decommissioned\n    SRTO_ENFORCEDENCRYPTION,  // Connection to be rejected or quickly broken when one side encryption set or bad password\n    SRTO_IPV6ONLY,            // IPV6_V6ONLY mode\n    SRTO_PEERIDLETIMEO,       // Peer-idle timeout (max time of silence heard from peer) in [ms]\n@@ -601,7 +595,7 @@ enum SRT_REJECT_REASON\n #define SRT_LOGFA_CONGEST    7   // cclog: Congestion control module\n #define SRT_LOGFA_PFILTER    8   // pflog: Packet filter module\n \n-#define SRT_LOGFA_API_CTRL   11  // aclog: API part for socket and library management\n+#define SRT_LOGFA_API_CTRL   11  // aclog: API part for socket and library managmenet\n \n #define SRT_LOGFA_QUE_CTRL   13  // qclog: Queue control activities\n \n@@ -641,9 +635,10 @@ enum SRT_KM_STATE\n     SRT_KM_S_SECURING      = 1, // Stream encrypted, exchanging Keying Material\n     SRT_KM_S_SECURED       = 2, // Stream encrypted, keying Material exchanged, decrypting ok.\n     SRT_KM_S_NOSECRET      = 3, // Stream encrypted and no secret to decrypt Keying Material\n-    SRT_KM_S_BADSECRET     = 4, // Stream encrypted and wrong secret is used, cannot decrypt Keying Material\n-    SRT_KM_S_BADCRYPTOMODE = 5,  // Stream encrypted but wrong cryptographic mode is used, cannot decrypt. Since v1.5.2.\n-    SRT_KM_S_E_SIZE\n+    SRT_KM_S_BADSECRET     = 4 // Stream encrypted and wrong secret is used, cannot decrypt Keying Material\n+#ifdef ENABLE_AEAD_API_PREVIEW\n+    ,SRT_KM_S_BADCRYPTOMODE = 5  // Stream encrypted but wrong cryptographic mode is used, cannot decrypt. Since v1.5.2.\n+#endif\n };\n \n enum SRT_EPOLL_OPT\ndiff --git a/srtcore/srt_attr_defs.h b/srtcore/srt_attr_defs.h\nindex 1c48965..726c4a0 100644\n--- a/srtcore/srt_attr_defs.h\n+++ b/srtcore/srt_attr_defs.h\n@@ -17,17 +17,26 @@ used by SRT library internally.\n \n // ATTRIBUTES:\n //\n+// SRT_ATR_UNUSED: declare an entity ALLOWED to be unused (prevents warnings)\n+// ATR_DEPRECATED: declare an entity deprecated (compiler should warn when used)\n // ATR_NOEXCEPT: The true `noexcept` from C++11, or nothing if compiling in pre-C++11 mode\n // ATR_NOTHROW: In C++11: `noexcept`. In pre-C++11: `throw()`. Required for GNU libstdc++.\n // ATR_CONSTEXPR: In C++11: `constexpr`. Otherwise empty.\n // ATR_OVERRIDE: In C++11: `override`. Otherwise empty.\n // ATR_FINAL: In C++11: `final`. Otherwise empty.\n \n-\n #ifdef __GNUG__\n-#define HAVE_GCC 1\n+#define ATR_DEPRECATED __attribute__((deprecated))\n+#else\n+#define ATR_DEPRECATED\n+#endif\n+\n+#if HAVE_CXX11\n+#define SRT_ATR_ALIGNAS(n) alignas(n)\n+#elif HAVE_GCC\n+#define SRT_ATR_ALIGNAS(n) __attribute__((aligned(n)))\n #else\n-#define HAVE_GCC 0\n+#define SRT_ATR_ALIGNAS(n)\n #endif\n \n #if defined(__cplusplus) && __cplusplus > 199711L\n@@ -35,15 +44,18 @@ used by SRT library internally.\n // For gcc 4.7, claim C++11 is supported, as long as experimental C++0x is on,\n // however it's only the \"most required C++11 support\".\n #if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 7 // 4.7 only!\n+#define ATR_NOEXCEPT\n+#define ATR_NOTHROW throw()\n+#define ATR_CONSTEXPR\n+#define ATR_OVERRIDE\n+#define ATR_FINAL\n #else\n #define HAVE_FULL_CXX11 1\n-\n-#if __cplusplus >= 201703L\n-#define HAVE_CXX17 1\n-#else\n-#define HAVE_CXX17 0\n-#endif\n-\n+#define ATR_NOEXCEPT noexcept\n+#define ATR_NOTHROW noexcept\n+#define ATR_CONSTEXPR constexpr\n+#define ATR_OVERRIDE override\n+#define ATR_FINAL final\n #endif\n #elif defined(_MSC_VER) && _MSC_VER >= 1800\n // Microsoft Visual Studio supports C++11, but not fully,\n@@ -53,41 +65,26 @@ used by SRT library internally.\n #define HAVE_CXX11 1\n #if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026\n #define HAVE_FULL_CXX11 1\n-\n-#if __cplusplus >= 201703L\n-#define HAVE_CXX17 1\n-#else\n-#define HAVE_CXX17 0\n-#endif\n-\n-#endif\n-#else\n-#define HAVE_CXX11 0\n-#define HAVE_CXX17 0\n-#endif // __cplusplus\n-\n-#if HAVE_FULL_CXX11\n #define ATR_NOEXCEPT noexcept\n #define ATR_NOTHROW noexcept\n #define ATR_CONSTEXPR constexpr\n #define ATR_OVERRIDE override\n #define ATR_FINAL final\n #else\n-// These are both for HAVE_CXX11 == 1 and 0.\n #define ATR_NOEXCEPT\n #define ATR_NOTHROW throw()\n #define ATR_CONSTEXPR\n #define ATR_OVERRIDE\n #define ATR_FINAL\n #endif\n-\n-#if HAVE_CXX11\n-#define SRT_ATR_ALIGNAS(n) alignas(n)\n-#elif HAVE_GCC\n-#define SRT_ATR_ALIGNAS(n) __attribute__((aligned(n)))\n #else\n-#define SRT_ATR_ALIGNAS(n)\n-#endif\n+#define HAVE_CXX11 0\n+#define ATR_NOEXCEPT\n+#define ATR_NOTHROW throw()\n+#define ATR_CONSTEXPR\n+#define ATR_OVERRIDE\n+#define ATR_FINAL\n+#endif // __cplusplus\n \n #if !HAVE_CXX11 && defined(REQUIRE_CXX11) && REQUIRE_CXX11 == 1\n #error \"The currently compiled application required C++11, but your compiler doesn't support it.\"\ndiff --git a/srtcore/srt_c_api.cpp b/srtcore/srt_c_api.cpp\nindex cf82467..031030c 100644\n--- a/srtcore/srt_c_api.cpp\n+++ b/srtcore/srt_c_api.cpp\n@@ -26,14 +26,6 @@ written by\n using namespace std;\n using namespace srt;\n \n-namespace srt\n-{\n-// This is provided in strerror_defs.cpp, which doesn't have\n-// its header file.\n-// XXX Consider adding some static function to CUDTException.\n-const char* strerror_get_message(size_t major, size_t minor);\n-}\n-\n \n extern \"C\" {\n \n@@ -256,9 +248,11 @@ int srt_getlasterror(int* loc_errno)\n     return CUDT::getlasterror().getErrorCode();\n }\n \n-const char* srt_strerror(int code, int /*err ignored*/)\n+const char* srt_strerror(int code, int err)\n {\n-    return strerror_get_message(CodeMajor(code/1000), CodeMinor(code%1000));\n+    static srt::CUDTException e;\n+    e = srt::CUDTException(CodeMajor(code/1000), CodeMinor(code%1000), err);\n+    return(e.getErrorMessage());\n }\n \n \ndiff --git a/srtcore/srt_compat.c b/srtcore/srt_compat.c\nindex 819fe41..bbdf7f7 100644\n--- a/srtcore/srt_compat.c\n+++ b/srtcore/srt_compat.c\n@@ -108,7 +108,7 @@ extern const char * SysStrError(int errnum, char * buf, size_t buflen)\n     // 0 for success, otherwise it's:\n     // - possibly -1 and the error code is in ::errno\n     // - possibly the error code itself\n-    // The details of the error are not interesting; simply\n+    // The details of the errror are not interesting; simply\n     // craft a fallback message in this case.\n     if (strerror_r(errnum, buf, buflen) != 0)\n     {\ndiff --git a/srtcore/srt_compat.h b/srtcore/srt_compat.h\nindex 46fe6aa..d4fd236 100644\n--- a/srtcore/srt_compat.h\n+++ b/srtcore/srt_compat.h\n@@ -24,7 +24,7 @@ written by\n extern \"C\" {\n #endif\n \n-/* Ensures that we store the error in the buffer and return the buffer. */\n+/* Ensures that we store the error in the buffer and return the bufer. */\n const char * SysStrError(int errnum, char * buf, size_t buflen);\n \n #ifdef __cplusplus\ndiff --git a/srtcore/srt_shared.rc b/srtcore/srt_shared.rc\nindex 5639a02..4481928 100644\n--- a/srtcore/srt_shared.rc\n+++ b/srtcore/srt_shared.rc\n@@ -1,45 +1,45 @@\n-// Microsoft Visual C++ generated resource script.\r\n-//\r\n-#include \"version.h\"\r\n-#include \"winres.h\"\r\n-\r\n-/////////////////////////////////////////////////////////////////////////////\r\n-//\r\n-// Version\r\n-//\r\n-\r\n-VS_VERSION_INFO VERSIONINFO\r\n-#ifdef SRT_VERSION_BUILD\r\n- FILEVERSION SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH, SRT_VERSION_BUILD\r\n-#else\r\n- FILEVERSION SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH\r\n-#endif\r\n- FILEFLAGSMASK 0x3fL\r\n-#ifdef _DEBUG\r\n- FILEFLAGS 0x1L\r\n-#else\r\n- FILEFLAGS 0x0L\r\n-#endif\r\n- FILEOS 0x40004L\r\n- FILETYPE 0x2L\r\n- FILESUBTYPE 0x0L\r\n-BEGIN\r\n-    BLOCK \"StringFileInfo\"\r\n-    BEGIN\r\n-        BLOCK \"080904b0\"\r\n-        BEGIN\r\n-            VALUE \"CompanyName\", \"SRT Alliance\"\r\n-            VALUE \"FileDescription\", \"SRT Local Build\"\r\n-            VALUE \"InternalName\", \"srt.dll\"\r\n-            VALUE \"LegalCopyright\", \"\"\r\n-            VALUE \"OriginalFilename\", \"srt.dll\"\r\n-            VALUE \"ProductName\", \"SRT\"\r\n-            VALUE \"ProductVersion\", SRT_VERSION_STRING\r\n-        END\r\n-    END\r\n-    BLOCK \"VarFileInfo\"\r\n-    BEGIN\r\n-        VALUE \"Translation\", 0x809, 1200\r\n-    END\r\n-END\r\n-\r\n+// Microsoft Visual C++ generated resource script.\n+//\n+#include \"version.h\"\n+#include \"winres.h\"\n+\n+/////////////////////////////////////////////////////////////////////////////\n+//\n+// Version\n+//\n+\n+VS_VERSION_INFO VERSIONINFO\n+#ifdef SRT_VERSION_BUILD\n+ FILEVERSION SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH, SRT_VERSION_BUILD\n+#else\n+ FILEVERSION SRT_VERSION_MAJOR, SRT_VERSION_MINOR, SRT_VERSION_PATCH\n+#endif\n+ FILEFLAGSMASK 0x3fL\n+#ifdef _DEBUG\n+ FILEFLAGS 0x1L\n+#else\n+ FILEFLAGS 0x0L\n+#endif\n+ FILEOS 0x40004L\n+ FILETYPE 0x2L\n+ FILESUBTYPE 0x0L\n+BEGIN\n+    BLOCK \"StringFileInfo\"\n+    BEGIN\n+        BLOCK \"080904b0\"\n+        BEGIN\n+            VALUE \"CompanyName\", \"SRT Alliance\"\n+            VALUE \"FileDescription\", \"SRT Local Build\"\n+            VALUE \"InternalName\", \"srt.dll\"\n+            VALUE \"LegalCopyright\", \"\"\n+            VALUE \"OriginalFilename\", \"srt.dll\"\n+            VALUE \"ProductName\", \"SRT\"\n+            VALUE \"ProductVersion\", SRT_VERSION_STRING\n+        END\n+    END\n+    BLOCK \"VarFileInfo\"\n+    BEGIN\n+        VALUE \"Translation\", 0x809, 1200\n+    END\n+END\n+\ndiff --git a/srtcore/strerror_defs.cpp b/srtcore/strerror_defs.cpp\nindex 4a93d6a..e99c8e2 100644\n--- a/srtcore/strerror_defs.cpp\n+++ b/srtcore/strerror_defs.cpp\n@@ -66,7 +66,7 @@ const char* strerror_msgs_filesystem [] = {\n const char* strerror_msgs_notsup [] = {\n     \"Operation not supported\", // MN_NONE = 0\n     \"Operation not supported: Cannot do this operation on a BOUND socket\", // MN_ISBOUND = 1\n-    \"Operation not supported: Cannot do this operation on a CONNECTED or LISTENING socket\", // MN_ISCONNECTED = 2\n+    \"Operation not supported: Cannot do this operation on a CONNECTED socket\", // MN_ISCONNECTED = 2\n     \"Operation not supported: Bad parameters\", // MN_INVAL = 3\n     \"Operation not supported: Invalid socket ID\", // MN_SIDINVAL = 4\n     \"Operation not supported: Cannot do this operation on an UNBOUND socket\", // MN_ISUNBOUND = 5\n@@ -76,7 +76,7 @@ const char* strerror_msgs_notsup [] = {\n     \"Operation not supported: Incorrect use of Message API (sendmsg/recvmsg)\", // MN_INVALMSGAPI = 9\n     \"Operation not supported: Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile)\", // MN_INVALBUFFERAPI = 10\n     \"Operation not supported: Another socket is already listening on the same port\", // MN_BUSY = 11\n-    \"Operation not supported: Message too large to send (exceeds send buffer size)\", // MN_XSIZE = 12\n+    \"Operation not supported: Message is too large to send\", // MN_XSIZE = 12\n     \"Operation not supported: Invalid epoll ID\", // MN_EIDINVAL = 13\n     \"Operation not supported: All sockets removed from epoll, waiting would deadlock\", // MN_EEMPTY = 14\n     \"Operation not supported: Another socket is bound to that port and is not reusable for requested settings\", // MN_BUSYPORT = 15\ndiff --git a/srtcore/sync.cpp b/srtcore/sync.cpp\nindex ff16a71..bfe1536 100644\n--- a/srtcore/sync.cpp\n+++ b/srtcore/sync.cpp\n@@ -347,7 +347,7 @@ int srt::sync::genRandomInt(int minVal, int maxVal)\n #endif\n \n     // Map onto [minVal, maxVal].\n-    // Note. There is a minuscule probability to get maxVal+1 as the result.\n+    // Note. There is a minuscule probablity to get maxVal+1 as the result.\n     // So we have to use long long to handle cases when maxVal = INT32_MAX.\n     // Also we must check 'res' does not exceed maxVal,\n     // which may happen if rand_0_1 = 1, even though the chances are low.\n@@ -357,11 +357,6 @@ int srt::sync::genRandomInt(int minVal, int maxVal)\n #endif // HAVE_CXX11\n }\n \n-#if defined(ENABLE_STDCXX_SYNC) && HAVE_CXX17\n-\n-// Shared mutex imp not required - aliased from C++17\n-\n-#else\n \n ////////////////////////////////////////////////////////////////////////////////\n //\n@@ -456,6 +451,4 @@ int srt::sync::SharedMutex::getReaderCount() const\n {\n     ScopedLock lk(m_Mutex);\n     return m_iCountRead;\n-}\n-#endif // C++17 for shared_mutex\n-\n+}\n\\ No newline at end of file\ndiff --git a/srtcore/sync.h b/srtcore/sync.h\nindex a5ac6d6..4528582 100644\n--- a/srtcore/sync.h\n+++ b/srtcore/sync.h\n@@ -12,7 +12,6 @@\n #define INC_SRT_SYNC_H\n \n #include \"platform_sys.h\"\n-#include \"srt_attr_defs.h\"\n \n #include <cstdlib>\n #include <limits>\n@@ -22,9 +21,6 @@\n #include <mutex>\n #include <condition_variable>\n #include <atomic>\n-#if HAVE_CXX17\n-#include <shared_mutex>\n-#endif\n #define SRT_SYNC_CLOCK SRT_SYNC_CLOCK_STDCXX_STEADY\n #define SRT_SYNC_CLOCK_STR \"STDCXX_STEADY\"\n #else\n@@ -58,6 +54,7 @@\n \n #include \"srt.h\"\n #include \"utilities.h\"\n+#include \"srt_attr_defs.h\"\n \n \n namespace srt\n@@ -429,11 +426,11 @@ class Condition\n public:\n     Condition();\n     ~Condition();\n+\n public:\n     /// These functions do not align with C++11 version. They are here hopefully as a temporal solution\n-    /// to avoid issues with static initialization of CV on windows.\n+    /// to avoud issues with static initialization of CV on windows.\n     void init();\n-    void reset();\n     void destroy();\n \n public:\n@@ -486,7 +483,6 @@ private:\n };\n \n inline void setupCond(Condition& cv, const char*) { cv.init(); }\n-inline void resetCond(Condition& cv) { cv.reset(); }\n inline void releaseCond(Condition& cv) { cv.destroy(); }\n \n ///////////////////////////////////////////////////////////////////////////////\n@@ -495,15 +491,11 @@ inline void releaseCond(Condition& cv) { cv.destroy(); }\n //\n ///////////////////////////////////////////////////////////////////////////////\n \n-#if defined(ENABLE_STDCXX_SYNC) && HAVE_CXX17\n-using SharedMutex = std::shared_mutex;\n-#else\n-\n /// Implementation of a read-write mutex. \n /// This allows multiple readers at a time, or a single writer.\n /// TODO: The class can be improved if needed to give writer a preference\n /// by adding additional m_iWritersWaiting member variable (counter).\n-/// TODO: The m_iCountRead could be made atomic to make unlock_shared() faster and lock-free.\n+/// TODO: The m_iCountRead could be made atomic to make unlok_shared() faster and lock-free.\n class SharedMutex\n {\n public:\n@@ -511,13 +503,13 @@ public:\n     ~SharedMutex();\n \n public:\n-    /// Acquire the lock for writing purposes. Only one thread can acquire this lock at a time\n+    /// Acquire the lock for writting purposes. Only one thread can acquire this lock at a time\n     /// Once it is locked, no reader can acquire it\n     void lock();\n     bool try_lock();\n     void unlock();\n \n-    /// Acquire the lock if no writer already has it. For read purpose only\n+    /// Acquire the lock if no writter already has it. For read purpose only\n     /// Several readers can lock this at the same time.\n     void lock_shared();\n     bool try_lock_shared();\n@@ -534,20 +526,10 @@ protected:\n     int  m_iCountRead;\n     bool m_bWriterLocked;\n };\n-#endif\n-\n-inline void enterCS(SharedMutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m) { m.lock(); }\n-\n-inline bool tryEnterCS(SharedMutex& m) SRT_ATTR_EXCLUDES(m) SRT_ATTR_TRY_ACQUIRE(true, m) { return m.try_lock(); }\n-\n-inline void leaveCS(SharedMutex& m) SRT_ATTR_REQUIRES(m) SRT_ATTR_RELEASE(m) { m.unlock(); }\n-\n-inline void setupMutex(SharedMutex&, const char*) {}\n-inline void releaseMutex(SharedMutex&) {}\n \n /// A version of std::scoped_lock<std::shared_mutex> (or lock_guard for C++11).\n /// We could have used the srt::sync::ScopedLock making it a template-based class.\n-/// But in that case all usages would have to be specified like ScopedLock<Mutex> in C++03.\n+/// But in that case all usages would have to be specificed like ScopedLock<Mutex> in C++03.\n class SRT_ATTR_SCOPED_CAPABILITY ExclusiveLock\n {\n public:\n@@ -595,21 +577,26 @@ public:\n     {\n     }\n \n-    bool compare_exchange(T* expected, T* newobj)\n+    bool set(T* pObj)\n     {\n         ExclusiveLock lock(*this);\n-        if (m_pObj != expected)\n+        if (m_pObj)\n             return false;\n-        m_pObj = newobj;\n+        m_pObj = pObj;\n         return true;\n     }\n \n-    T* get_locked(SharedLock& /*wholocked*/)\n+    bool clearIf(const T* pObj)\n     {\n-        // XXX Here you can assert that `wholocked` locked *this.\n-        return m_pObj;\n+        ExclusiveLock lock(*this);\n+        if (m_pObj != pObj)\n+            return false;\n+        m_pObj = NULL;\n+        return true;\n     }\n \n+    T* getPtrNoLock() const { return m_pObj; }\n+\n private:\n     T* m_pObj;\n };\n@@ -856,7 +843,7 @@ public:\n \n     /// Wakes up waiting thread (sleep_until(..)) without\n     /// changing the target waiting time to force a recheck\n-    /// of the current time in comparison to the target time.\n+    /// of the current time in comparisson to the target time.\n     void tick();\n \n private:\n@@ -1003,7 +990,6 @@ public: // Internal\n \n private:\n     pthread_t m_thread;\n-    pid_t     m_pid;\n };\n \n template <class Stream>\n@@ -1035,8 +1021,6 @@ namespace this_thread\n \n #endif\n \n-inline void resetThread(CThread* th) { (void)new (th) CThread; }\n-\n /// StartThread function should be used to do CThread assignments:\n /// @code\n /// CThread a();\ndiff --git a/srtcore/sync_cxx11.cpp b/srtcore/sync_cxx11.cpp\nindex c376b0a..bdfbf9a 100644\n--- a/srtcore/sync_cxx11.cpp\n+++ b/srtcore/sync_cxx11.cpp\n@@ -58,24 +58,6 @@ srt::sync::Condition::~Condition() {}\n \n void srt::sync::Condition::init() {}\n \n-void srt::sync::Condition::reset()\n-{\n-    // SRT attempts to safely handle `fork()` in multithreaded environments,\n-    // even though using `fork()` in such contexts is strongly discouraged.\n-    // This is because `fork()` only duplicates the calling thread, leaving\n-    // synchronization primitives (like condition variables) in an\n-    // undefined or inconsistent state in the child process.\n-    //\n-    // To mitigate this, SRT forcefully reinitializes these synchronization\n-    // primitives post-fork. In POSIX, this is done by overwriting the object\n-    // with its default-initialized state. In C++11, we achieve the same effect\n-    // using *placement new* to reconstruct the object in place. This ensures\n-    // the condition variable is returned to a fresh, \"neutral\" state,\n-    // as if it was just created.\n-\n-    new (&m_cv) std::condition_variable;\n-}\n-\n void srt::sync::Condition::destroy() {}\n \n void srt::sync::Condition::wait(UniqueLock& lock)\ndiff --git a/srtcore/sync_posix.cpp b/srtcore/sync_posix.cpp\nindex cfbd2ab..8d7561a 100644\n--- a/srtcore/sync_posix.cpp\n+++ b/srtcore/sync_posix.cpp\n@@ -288,35 +288,17 @@ Condition::~Condition() {}\n void Condition::init()\n {\n     pthread_condattr_t* attr = NULL;\n-#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK\n+#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC\n     pthread_condattr_t  CondAttribs;\n     pthread_condattr_init(&CondAttribs);\n-    if (pthread_condattr_setclock(&CondAttribs, CLOCK_MONOTONIC) != 0)\n-    {\n-        pthread_condattr_destroy(&CondAttribs);\n-        LOGC(inlog.Fatal, log << \"IPE: pthread_condattr_setclock failed to set up a monotonic clock for a CV\");\n-    }\n+    pthread_condattr_setclock(&CondAttribs, CLOCK_MONOTONIC);\n     attr = &CondAttribs;\n #endif\n     const int res = pthread_cond_init(&m_cv, attr);\n-#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK\n-    if (attr != NULL)\n-    {\n-        pthread_condattr_destroy(attr);\n-    }\n-#endif\n     if (res != 0)\n         throw std::runtime_error(\"pthread_cond_init monotonic failed\");\n }\n \n-void Condition::reset()\n-{\n-\n-    pthread_cond_t  temp = PTHREAD_COND_INITIALIZER;\n-    memcpy(&m_cv, (void *) &temp, sizeof(m_cv));\n-    init();\n-}\n-\n void Condition::destroy()\n {\n     pthread_cond_destroy(&m_cv);\n@@ -330,7 +312,7 @@ void Condition::wait(UniqueLock& lock)\n bool Condition::wait_for(UniqueLock& lock, const steady_clock::duration& rel_time)\n {\n     timespec timeout;\n-#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC && HAVE_PTHREAD_CONDATTR_SETCLOCK\n+#if SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_GETTIME_MONOTONIC\n     clock_gettime(CLOCK_MONOTONIC, &timeout);\n     const uint64_t now_us = timeout.tv_sec * uint64_t(1000000) + (timeout.tv_nsec / 1000);\n #else\n@@ -378,7 +360,6 @@ void Condition::notify_all()\n srt::sync::CThread::CThread()\n {\n     m_thread = pthread_t();\n-    m_pid = getpid();\n }\n \n srt::sync::CThread::CThread(void *(*start_routine) (void *), void *arg)\n@@ -400,20 +381,20 @@ srt::sync::CThread& srt::sync::CThread::operator=(CThread& other)\n         LOGC(inlog.Error, log << \"IPE: Assigning to a thread that is not terminated!\");\n \n #ifndef DEBUG\n-#if !defined(__ANDROID__) && !defined(__OHOS__)\n+#ifndef __ANDROID__\n         // In case of production build the hanging thread should be terminated\n         // to avoid hang ups and align with C++11 implementation.\n         // There is no pthread_cancel on Android. See #1476. This error should not normally\n         // happen, but if it happen, then detaching the thread.\n         pthread_cancel(m_thread);\n-#endif // __ANDROID__ __OHOS__\n+#endif // __ANDROID__\n #else\n         join();\n #endif\n     }\n+\n     // Move thread handler from other\n     m_thread = other.m_thread;\n-    m_pid = other.m_pid;\n     other.m_thread = pthread_t();\n     return *this;\n }\n@@ -428,27 +409,24 @@ void srt::sync::CThread::create_thread(void *(*start_routine) (void *), void *ar\n \n bool srt::sync::CThread::joinable() const\n {\n-    return m_pid == getpid() && !pthread_equal(m_thread, pthread_t());\n+    return !pthread_equal(m_thread, pthread_t());\n }\n \n void srt::sync::CThread::join()\n {\n-\tif (joinable())\n-\t{\n-        void *retval;\n-        const int ret SRT_ATR_UNUSED = pthread_join(m_thread, &retval);\n-        if (ret != 0)\n-        {\n-            LOGC(inlog.Error, log << \"pthread_join failed with \" << ret << \" (\" << m_thread << \")\");\n-        }\n+    void *retval;\n+    const int ret SRT_ATR_UNUSED = pthread_join(m_thread, &retval);\n+    if (ret != 0)\n+    {\n+        LOGC(inlog.Error, log << \"pthread_join failed with \" << ret);\n+    }\n #ifdef HEAVY_LOGGING\n-        else\n-        {\n-            HLOGC(inlog.Debug, log << \"pthread_join SUCCEEDED\");\n-        }\n+    else\n+    {\n+        HLOGC(inlog.Debug, log << \"pthread_join SUCCEEDED\");\n+    }\n #endif\n-        // After joining, joinable should be false\n-\t}\n+    // After joining, joinable should be false\n     m_thread = pthread_t();\n     return;\n }\n@@ -461,7 +439,6 @@ void srt::sync::CThread::create(void *(*start_routine) (void *), void *arg)\n         LOGC(inlog.Error, log << \"pthread_create failed with \" << st);\n         throw CThreadException(MJ_SYSTEMRES, MN_THREAD, 0);\n     }\n-    m_pid = getpid();\n }\n \n \n@@ -567,7 +544,7 @@ CUDTException& GetThreadLocalError()\n {\n     // In POSIX version we take into account the possibility\n     // of having an allocation error here. Therefore we need to\n-    // allow this value to return NULL and have some fallback\n+    // allow thie value to return NULL and have some fallback\n     // for that case. The dynamic memory allocation failure should\n     // be the only case as to why it is unable to get the pointer\n     // to the error description.\ndiff --git a/srtcore/tsbpd_time.cpp b/srtcore/tsbpd_time.cpp\nindex b85aa50..d45215a 100644\n--- a/srtcore/tsbpd_time.cpp\n+++ b/srtcore/tsbpd_time.cpp\n@@ -266,7 +266,7 @@ void CTsbpdTime::updateBaseTime(uint32_t usPktTimestamp)\n     // Check if timestamp is within the TSBPD_WRAP_PERIOD before reaching the MAX_TIMESTAMP.\n     if (usPktTimestamp > (CPacket::MAX_TIMESTAMP - TSBPD_WRAP_PERIOD))\n     {\n-        // Approaching wrap around point, start wrap check period (if for packet delivery head)\n+        // Approching wrap around point, start wrap check period (if for packet delivery head)\n         m_bTsbPdWrapCheck = true;\n         LOGC(tslog.Debug,\n              log << \"tsbpd wrap period begins with ts=\" << usPktTimestamp\ndiff --git a/srtcore/utilities.h b/srtcore/utilities.h\nindex 9f0ab78..ca8c365 100644\n--- a/srtcore/utilities.h\n+++ b/srtcore/utilities.h\n@@ -285,7 +285,7 @@ inline void ItoHLA(uint32_t* dst, const uint32_t* src, size_t size)\n // Usage: typedef Bits<leftmost, rightmost> MASKTYPE;  // MASKTYPE is a name of your choice.\n //\n // With this defined, you can use the following members:\n-// - MASKTYPE::mask - to get the int32_t value with bitmask (used bits set to 1, others to 0)\n+// - MASKTYPE::mask - to get the int32_t value with bimask (used bits set to 1, others to 0)\n // - MASKTYPE::offset - to get the lowermost bit number, or number of bits to shift\n // - MASKTYPE::wrap(int value) - to create a bitset where given value is encoded in given bits\n // - MASKTYPE::unwrap(int bitset) - to extract an integer value from the bitset basing on mask definition\n@@ -789,6 +789,12 @@ inline void insert_uniq(std::vector<Value>& v, const ArgValue& val)\n     v.push_back(val);\n }\n \n+template <class Type1, class Type2>\n+inline std::pair<Type1&, Type2&> Tie(Type1& var1, Type2& var2)\n+{\n+    return std::pair<Type1&, Type2&>(var1, var2);\n+}\n+\n // This can be used in conjunction with Tie to simplify the code\n // in loops around a whole container:\n // list<string>::const_iterator it, end;\n@@ -822,14 +828,17 @@ struct CallbackHolder\n         // Test if the pointer is a pointer to function. Don't let\n         // other type of pointers here.\n #if HAVE_CXX11\n-        // NOTE: No poor-man's replacement can be done for C++03 because it's\n-        // not possible to fake calling a function without calling it and no\n-        // other operation can be done without extensive transformations on\n-        // the Signature type, still in C++03 possible only on functions up to\n-        // 2 arguments (callbacks in SRT usually have more).\n         static_assert(std::is_function<Signature>::value, \"CallbackHolder is for functions only!\");\n+#else\n+        // This is a poor-man's replacement, which should in most compilers\n+        // generate a warning, if `Signature` resolves to a value type.\n+        // This would make an illegal pointer cast from a value to a function type.\n+        // Casting function-to-function, however, should not. Unfortunately\n+        // newer compilers disallow that, too (when a signature differs), but\n+        // then they should better use the C++11 way, much more reliable and safer.\n+        void* (*testfn)(void*) = (void*(*)(void*))f;\n+        (void)(testfn);\n #endif\n-\n         opaque = o;\n         fn = f;\n     }\n@@ -966,16 +975,6 @@ inline void AccumulatePassFilterParallel(const int* p, size_t size, PassFilter<i\n     w_paracount = parasum;\n }\n \n-template<class Type>\n-inline Type Bounds(Type lower, Type value, Type upper)\n-{\n-    if (value < lower)\n-        return lower;\n-    if (value > upper)\n-        return upper;\n-    return value;\n-}\n-\n \n inline std::string FormatBinaryString(const uint8_t* bytes, size_t size)\n {\n@@ -1072,7 +1071,7 @@ public:\n     // overdrift() should be read only immediately after update() returned\n     // true. It will stay available with this value until the next time when\n     // update() returns true, in which case the value will be cleared.\n-    // Therefore, after calling update() if it returns true, you should read\n+    // Therefore, after calling update() if it retuns true, you should read\n     // overdrift() immediately an make some use of it. Next valid overdrift\n     // will be then relative to every previous overdrift.\n     //\n@@ -1112,7 +1111,7 @@ struct MapProxy\n     {\n         typename std::map<KeyType, ValueType>::const_iterator p = find();\n         if (p == mp.end())\n-            return ValueType();\n+            return \"\";\n         return p->second;\n     }\n \n@@ -1215,7 +1214,7 @@ inline size_t safe_advance(It& it, size_t num, It end)\n     return num; // will be effectively 0, if reached the required point, or >0, if end was by that number earlier\n }\n \n-// This is available only in C++17, don't know why not C++11 as it's pretty useful.\n+// This is available only in C++17, dunno why not C++11 as it's pretty useful.\n template <class V, size_t N> inline\n ATR_CONSTEXPR size_t Size(const V (&)[N]) ATR_NOEXCEPT { return N; }\n \ndiff --git a/srtcore/window.cpp b/srtcore/window.cpp\nindex 5a926c7..1950f7e 100644\n--- a/srtcore/window.cpp\n+++ b/srtcore/window.cpp\n@@ -154,13 +154,13 @@ void srt::CPktTimeWindowTools::initializeWindowArrays(int* r_pktWindow, int* r_p\n       r_probeWindow[k] = 1000;    //1 msec -> 1000 pkts/sec\n \n    for (size_t i = 0; i < asize; ++ i)\n-      r_bytesWindow[i] = int(max_payload_size); //based on 1 pkt/sec set in r_pktWindow[i]\n+      r_bytesWindow[i] = max_payload_size; //based on 1 pkt/sec set in r_pktWindow[i]\n }\n \n int srt::CPktTimeWindowTools::ceilPerMega(double value, double count)\n {\n     static const double MEGA = 1000.0 * 1000.0;\n-    return int(::ceil(MEGA / (value / count)));\n+    return ::ceil(MEGA / (value / count));\n }\n \n int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica, const int* abytes, size_t asize, size_t hdr_size, int& w_bytesps)\n@@ -176,14 +176,14 @@ int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica,\n     AccumulatePassFilterParallel<unsigned, unsigned long>(window, asize, filter, abytes,\n             (sum), (count), (bytes));\n \n-    // calculate speed, or return 0 if not enough valid value\n+    // claculate speed, or return 0 if not enough valid value\n     if (count <= (asize/2))\n     {\n         w_bytesps = 0;\n         return 0;\n     }\n \n-    bytes += (unsigned long)(hdr_size * count); //Add protocol headers to bytes received\n+    bytes += (hdr_size * count); //Add protocol headers to bytes received\n     w_bytesps = ceilPerMega(sum, bytes);\n     return ceilPerMega(sum, count);\n }\ndiff --git a/srtcore/window.h b/srtcore/window.h\nindex 4e548d3..dbe4b71 100644\n--- a/srtcore/window.h\n+++ b/srtcore/window.h\n@@ -322,7 +322,7 @@ public:\n        // Meaning: if the packet is fully packed, probe_case = timediff.\n        // Otherwise the timediff will be \"converted\" to a time that a fully packed packet \"would take\",\n        // provided the arrival time is proportional to the payload size and skipping\n-       // the ETH+IP+UDP+SRT header part eliminates the constant packet delivery time influence.\n+       // the ETH+IP+UDP+SRT header part elliminates the constant packet delivery time influence.\n        //\n        const size_t pktsz = pkt.getLength();\n        m_aProbeWindow[m_iProbeWindowPtr] = pktsz ? int(timediff_times_pl_size / pktsz) : int(timediff);\ndiff --git a/test/any.hpp b/test/any.hpp\nindex afe3fc7..9ecb96c 100644\n--- a/test/any.hpp\n+++ b/test/any.hpp\n@@ -209,11 +209,11 @@ private: // Storage and Virtual Method Table\n         /// The state of the union after this call is unspecified, caller must ensure not to use src anymore.\n         void(*destroy)(storage_union&) noexcept;\n \n-        /// Copies the **inner** content of the src union into the yet uninitialized dest union.\n+        /// Copies the **inner** content of the src union into the yet unitialized dest union.\n         /// As such, both inner objects will have the same state, but on separate memory locations.\n         void(*copy)(const storage_union& src, storage_union& dest);\n \n-        /// Moves the storage from src to the yet uninitialized dest union.\n+        /// Moves the storage from src to the yet unitialized dest union.\n         /// The state of src after this call is unspecified, caller must ensure not to use src anymore.\n         void(*move)(storage_union& src, storage_union& dest) noexcept;\n \n@@ -251,7 +251,7 @@ private: // Storage and Virtual Method Table\n \n         static void swap(storage_union& lhs, storage_union& rhs) noexcept\n         {\n-            // just exchange the storage pointers.\n+            // just exchage the storage pointers.\n             std::swap(lhs.dynamic, rhs.dynamic);\n         }\n     };\ndiff --git a/test/filelist.maf b/test/filelist.maf\nindex e39d6ac..7ae5693 100644\n--- a/test/filelist.maf\n+++ b/test/filelist.maf\n@@ -7,7 +7,6 @@ test_main.cpp\n test_buffer_rcv.cpp\n test_common.cpp\n test_connection_timeout.cpp\n-test_control_packets.cpp\n test_crypto.cpp\n test_cryspr.cpp\n test_enforced_encryption.cpp\ndiff --git a/test/test_bonding.cpp b/test/test_bonding.cpp\nindex bc870ce..0e48c8a 100644\n--- a/test/test_bonding.cpp\n+++ b/test/test_bonding.cpp\n@@ -1,18 +1,14 @@\n-#include <array>\n #include <future>\n #include <thread>\n #include <chrono>\n #include <vector>\n+#include <functional>\n+\n #include \"gtest/gtest.h\"\n #include \"test_env.h\"\n \n #include \"srt.h\"\n-#include \"udt.h\"\n-#include \"common.h\"\n #include \"netinet_any.h\"\n-#include \"socketconfig.h\"\n-\n-#include \"apputil.hpp\"\n \n TEST(Bonding, SRTConnectGroup)\n {\n@@ -27,7 +23,7 @@ TEST(Bonding, SRTConnectGroup)\n     {\n         sa.sin_family = AF_INET;\n         sa.sin_port = htons(4200 + i);\n-        EXPECT_EQ(inet_pton(AF_INET, \"192.168.1.237\", &sa.sin_addr), 1);\n+        ASSERT_EQ(inet_pton(AF_INET, \"192.168.1.237\", &sa.sin_addr), 1);\n \n         const SRT_SOCKGROUPCONFIG gd = srt_prepare_endpoint(NULL, (struct sockaddr*)&sa, sizeof sa);\n         targets.push_back(gd);\n@@ -60,7 +56,7 @@ TEST(Bonding, SRTConnectGroup)\n     }\n }\n \n-#define EXPECT_SRT_SUCCESS(callform) EXPECT_NE(callform, -1) << \"SRT ERROR: \" << srt_getlasterror_str()\n+#define ASSERT_SRT_SUCCESS(callform) ASSERT_NE(callform, -1) << \"SRT ERROR: \" << srt_getlasterror_str()\n \n void listening_thread(bool should_read)\n {\n@@ -68,37 +64,37 @@ void listening_thread(bool should_read)\n     sockaddr_in bind_sa;\n     memset(&bind_sa, 0, sizeof bind_sa);\n     bind_sa.sin_family = AF_INET;\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &bind_sa.sin_addr), 1);\n+    ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &bind_sa.sin_addr), 1);\n     bind_sa.sin_port = htons(4200);\n \n-    EXPECT_SRT_SUCCESS(srt_bind(server_sock, (sockaddr*)&bind_sa, sizeof bind_sa));\n+    ASSERT_SRT_SUCCESS(srt_bind(server_sock, (sockaddr*)&bind_sa, sizeof bind_sa));\n     const int yes = 1;\n-    EXPECT_SRT_SUCCESS(srt_setsockflag(server_sock, SRTO_GROUPCONNECT, &yes, sizeof yes));\n+    ASSERT_SRT_SUCCESS(srt_setsockflag(server_sock, SRTO_GROUPCONNECT, &yes, sizeof yes));\n \n     const int no = 1;\n-    EXPECT_SRT_SUCCESS(srt_setsockflag(server_sock, SRTO_RCVSYN, &no, sizeof no));\n+    ASSERT_SRT_SUCCESS(srt_setsockflag(server_sock, SRTO_RCVSYN, &no, sizeof no));\n \n     const int eid = srt_epoll_create();\n     const int listen_event = SRT_EPOLL_IN | SRT_EPOLL_ERR;\n-    EXPECT_SRT_SUCCESS(srt_epoll_add_usock(eid, server_sock, &listen_event));\n+    ASSERT_SRT_SUCCESS(srt_epoll_add_usock(eid, server_sock, &listen_event));\n \n-    EXPECT_SRT_SUCCESS(srt_listen(server_sock, 5));\n+    ASSERT_SRT_SUCCESS(srt_listen(server_sock, 5));\n     std::cout << \"Listen: wait for acceptability\\n\";\n     int fds[2];\n     int fds_len = 2;\n     int ers[2];\n     int ers_len = 2;\n-    EXPECT_SRT_SUCCESS(srt_epoll_wait(eid, fds, &fds_len, ers, &ers_len, 5000,\n+    ASSERT_SRT_SUCCESS(srt_epoll_wait(eid, fds, &fds_len, ers, &ers_len, 5000,\n             0, 0, 0, 0));\n \n     std::cout << \"Listen: reported \" << fds_len << \" acceptable and \" << ers_len << \" errors\\n\";\n-    EXPECT_GT(fds_len, 0);\n-    EXPECT_EQ(fds[0], server_sock);\n+    ASSERT_GT(fds_len, 0);\n+    ASSERT_EQ(fds[0], server_sock);\n \n     srt::sockaddr_any scl;\n     int acp = srt_accept(server_sock, (scl.get()), (&scl.len));\n-    EXPECT_SRT_SUCCESS(acp);\n-    EXPECT_NE(acp & SRTGROUP_MASK, 0);\n+    ASSERT_SRT_SUCCESS(acp);\n+    ASSERT_NE(acp & SRTGROUP_MASK, 0);\n \n     if (should_read)\n     {\n@@ -126,22 +122,11 @@ void listening_thread(bool should_read)\n     // srt_accept..\n }\n \n-SRTSOCKET g_listen_socket = -1;\n-int g_nconnected = 0;\n-int g_nfailed = 0;\n-\n-// This ConnectCallback is mainly informative, but it also collects the\n-// number of succeeded and failed links.\n-void ConnectCallback(void* , SRTSOCKET sock, int error, const sockaddr* /*peer*/, int token)\n+void ConnectCallback(void* /*opaq*/, SRTSOCKET sock, int error, const sockaddr* /*peer*/, int token)\n {\n     std::cout << \"Connect callback. Socket: \" << sock\n         << \", error: \" << error\n         << \", token: \" << token << '\\n';\n-\n-    if (error == SRT_SUCCESS)\n-        ++g_nconnected;\n-    else\n-        ++g_nfailed;\n }\n \n TEST(Bonding, NonBlockingGroupConnect)\n@@ -153,20 +138,20 @@ TEST(Bonding, NonBlockingGroupConnect)\n     std::cout << \"Created group socket: \" << ss << '\\n';\n \n     int no = 0;\n-    EXPECT_NE(srt_setsockopt(ss, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n-    EXPECT_NE(srt_setsockopt(ss, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n+    ASSERT_NE(srt_setsockopt(ss, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n+    ASSERT_NE(srt_setsockopt(ss, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n \n     const int poll_id = srt_epoll_create();\n     // Will use this epoll to wait for srt_accept(...)\n     const int epoll_out = SRT_EPOLL_OUT | SRT_EPOLL_ERR;\n-    EXPECT_NE(srt_epoll_add_usock(poll_id, ss, &epoll_out), SRT_ERROR);\n+    ASSERT_NE(srt_epoll_add_usock(poll_id, ss, &epoll_out), SRT_ERROR);\n \n     srt_connect_callback(ss, &ConnectCallback, this);\n \n     sockaddr_in sa;\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(4200);\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n+    ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n     sockaddr_in safail = sa;\n     safail.sin_port = htons(4201); // port where we have no listener\n@@ -179,14 +164,14 @@ TEST(Bonding, NonBlockingGroupConnect)\n         EXPECT_GT(sockid, 0) << \"Socket \" << 1;\n         sa.sin_port = htons(4201); // Changing port so that second connect fails\n         std::cout << \"Socket created: \" << sockid << '\\n';\n-        EXPECT_NE(srt_epoll_add_usock(poll_id, sockid, &epoll_out), SRT_ERROR);\n+        ASSERT_NE(srt_epoll_add_usock(poll_id, sockid, &epoll_out), SRT_ERROR);\n     }\n     {\n         const int sockid = srt_connect(ss, (sockaddr*) &safail, sizeof safail);\n         EXPECT_GT(sockid, 0) << \"Socket \" << 2;\n         safail.sin_port = htons(4201); // Changing port so that second connect fails\n         std::cout << \"Socket created: \" << sockid << '\\n';\n-        EXPECT_NE(srt_epoll_add_usock(poll_id, sockid, &epoll_out), SRT_ERROR);\n+        ASSERT_NE(srt_epoll_add_usock(poll_id, sockid, &epoll_out), SRT_ERROR);\n     }\n     std::cout << \"Returned from connecting two sockets \" << std::endl;\n \n@@ -239,8 +224,8 @@ TEST(Bonding, CloseGroupAndSocket)\n {\n     srt::TestInit srtinit;\n \n-    MAKE_UNIQUE_SOCK(ss, \"broadcast group\", srt_create_group(SRT_GTYPE_BROADCAST));\n-\n+    const int ss = srt_create_group(SRT_GTYPE_BROADCAST);\n+    ASSERT_NE(ss, SRT_ERROR);\n     std::cout << \"Created group socket: \" << ss << '\\n';\n \n     int no = 0;\n@@ -326,7 +311,7 @@ TEST(Bonding, CloseGroupAndSocket)\n             std::this_thread::sleep_for(std::chrono::milliseconds(10));\n             if (srt_send(ss, buf, 1316) == -1)\n             {\n-                std::cout << \"[Sender] sending failure, exiting after sending \" << n << \" packets\\n\";\n+                std::cout << \"[Sender] sending failure, exitting after sending \" << n << \" packets\\n\";\n                 break;\n             }\n \n@@ -338,25 +323,13 @@ TEST(Bonding, CloseGroupAndSocket)\n \n     std::this_thread::sleep_for(std::chrono::milliseconds(300));\n \n-    ss.close();\n+    EXPECT_EQ(srt_close(ss), 0) << \"srt_close: %s\\n\" << srt_getlasterror_str();\n \n     std::cout << \"CLOSED GROUP. Now waiting for sender to exit...\\n\";\n     sender.join();\n     listen_promise.wait();\n }\n \n-// (void* opaq, SRTSOCKET ns, int hsversion, const struct sockaddr* peeraddr, const char* streamid);\n-int ListenCallbackFn(void* expected_sid, SRTSOCKET, int /*hsversion*/, const sockaddr* /*peer*/, const char* streamid)\n-{\n-    const auto* p = (std::pair<const char*, int>*) expected_sid;\n-    // Note: It is not safe to access the streamid pointer by the expected size,\n-    // but there is no way to know the real size apart from finding the first null terminator.\n-    // See FR #3073.\n-    EXPECT_EQ(std::memcmp(streamid, p->first, p->second), 0);\n-    \n-    return 0;\n-}\n-\n TEST(Bonding, Options)\n {\n     using namespace std;\n@@ -365,7 +338,7 @@ TEST(Bonding, Options)\n     TestInit srtinit;\n \n     // Create a group\n-    MAKE_UNIQUE_SOCK(grp, \"broadcast group\", srt_create_group(SRT_GTYPE_BROADCAST));\n+    const SRTSOCKET grp = srt_create_group(SRT_GTYPE_BROADCAST);\n \n     // rendezvous shall not be allowed to be set on the group\n     // XXX actually it is possible, but no one tested it. POSTPONE.\n@@ -373,15 +346,12 @@ TEST(Bonding, Options)\n     //EXPECT_EQ(srt_setsockflag(grp, SRTO_RENDEZVOUS, &yes, sizeof yes), SRT_ERROR);\n \n #ifdef SRT_ENABLE_ENCRYPTION\n-    const string pass = \"longenoughpassword\";\n+    string pass = \"longenoughpassword\";\n     // passphrase should be ok.\n-    EXPECT_NE(srt_setsockflag(grp, SRTO_PASSPHRASE, pass.c_str(), (int) pass.size()), SRT_ERROR);\n+    EXPECT_NE(srt_setsockflag(grp, SRTO_PASSPHRASE, pass.c_str(), pass.size()), SRT_ERROR);\n \n     uint32_t val = 16;\n-    EXPECT_NE(srt_setsockflag(grp, SRTO_PBKEYLEN, &val, (int) sizeof val), SRT_ERROR);\n-\n-    const bool bfalse = true;\n-    EXPECT_EQ(srt_setsockflag(grp, SRTO_RENDEZVOUS, &bfalse, (int)sizeof bfalse), SRT_ERROR);\n+    EXPECT_NE(srt_setsockflag(grp, SRTO_PBKEYLEN, &val, sizeof val), SRT_ERROR);\n \n #ifdef ENABLE_AEAD_API_PREVIEW\n     val = 1;\n@@ -389,38 +359,6 @@ TEST(Bonding, Options)\n #endif\n #endif\n \n-    const string packet_filter = \"fec,cols:10,rows:5\";\n-    EXPECT_NE(srt_setsockflag(grp, SRTO_PACKETFILTER, packet_filter.c_str(), (int)packet_filter.size()), SRT_ERROR);\n-\n-    // ================\n-    // Linger is an option of a trivial type, but differs from other integer-typed options.\n-    // Therefore checking it specifically.\n-    const linger l = {1, 10};\n-    srt_setsockflag(grp, SRTO_LINGER, &l, sizeof l);\n-\n-    {\n-        linger l2;\n-        int optsize = sizeof l2;\n-        EXPECT_NE(srt_getsockflag(grp, SRTO_LINGER, &l2, &optsize), SRT_ERROR);\n-        EXPECT_EQ(optsize, (int)sizeof l2);\n-        EXPECT_EQ(l2.l_onoff, l.l_onoff);\n-        EXPECT_EQ(l2.l_linger, l.l_linger);\n-    }\n-    // ================\n-\n-    const std::array<char, 10> streamid = { 's', 't', 'r', 'e', 0, 'm', 'i', 'd', '%', '&'};\n-    EXPECT_NE(srt_setsockflag(grp, SRTO_STREAMID, &streamid, streamid.size()), SRT_ERROR);\n-\n-    auto check_streamid = [&streamid](SRTSOCKET sock) {\n-        std::array<char, srt::CSrtConfig::MAX_SID_LENGTH> tmpbuf;\n-        auto opt_len = (int)tmpbuf.size();\n-        EXPECT_EQ(srt_getsockflag(sock, SRTO_STREAMID, tmpbuf.data(), &opt_len), SRT_SUCCESS);\n-        EXPECT_EQ(size_t(opt_len), streamid.size());\n-        EXPECT_EQ(std::memcmp(tmpbuf.data(), streamid.data(), opt_len), 0);\n-    };\n-\n-    check_streamid(grp);\n-\n     int lat = 500;\n     EXPECT_NE(srt_setsockflag(grp, SRTO_RCVLATENCY, &lat, sizeof lat), SRT_ERROR);\n \n@@ -433,34 +371,22 @@ TEST(Bonding, Options)\n         unique_lock<mutex> ux(mx);\n \n         SRTSOCKET lsn = srt_create_socket();\n-\n-        auto expected_sid = std::make_pair<const char*, int>(streamid.data(), streamid.size());\n-        srt_listen_callback(lsn, &ListenCallbackFn, (void*) &expected_sid);\n-\n #ifdef SRT_ENABLE_ENCRYPTION\n         EXPECT_NE(srt_setsockflag(lsn, SRTO_PASSPHRASE, pass.c_str(), pass.size()), SRT_ERROR);\n #endif\n         int allow = 1;\n-        EXPECT_NE(srt_setsockflag(lsn, SRTO_GROUPCONNECT, &allow, sizeof allow), SRT_ERROR);\n-        sockaddr_any sa = srt::CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n-        EXPECT_NE(srt_bind(lsn, sa.get(), sa.size()), SRT_ERROR);\n-        EXPECT_NE(srt_listen(lsn, 1), SRT_ERROR);\n+        ASSERT_NE(srt_setsockflag(lsn, SRTO_GROUPCONNECT, &allow, sizeof allow), SRT_ERROR);\n+        sockaddr_any sa = CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n+        ASSERT_NE(srt_bind(lsn, sa.get(), sa.size()), SRT_ERROR);\n+        ASSERT_NE(srt_listen(lsn, 1), SRT_ERROR);\n         started = true;\n \n         // First wait - until it's let go with accepting\n         latch.wait(ux);\n \n-        //sockaddr_any revsa;\n-        SRTSOCKET lsna [1] = { lsn };\n-        SRTSOCKET gs = srt_accept_bond(lsna, 1, 1000);\n-        ASSERT_NE(gs, SRT_INVALID_SOCK);\n-\n-        check_streamid(gs);\n-\n-        std::array<char, 800> tmpbuf;\n-        auto opt_len = (int)tmpbuf.size();\n-        EXPECT_EQ(srt_getsockflag(gs, SRTO_PACKETFILTER, tmpbuf.data(), &opt_len), SRT_SUCCESS);\n-        std::cout << \"Packet filter: \" << std::string(tmpbuf.data(), opt_len) << '\\n';\n+        sockaddr_any revsa;\n+        SRTSOCKET gs = srt_accept(lsn, revsa.get(), &revsa.len);\n+        ASSERT_NE(gs, SRT_ERROR);\n \n         // Connected, wait to close\n         latch.wait(ux);\n@@ -487,7 +413,7 @@ TEST(Bonding, Options)\n     }\n \n     // Now the thread is accepting, so we call the connect.\n-    sockaddr_any sa = srt::CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n+    sockaddr_any sa = CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n     SRTSOCKET member = srt_connect(grp, sa.get(), sa.size());\n \n     // We've released the mutex and signaled the CV, so accept should proceed now.\n@@ -530,20 +456,20 @@ TEST(Bonding, Options)\n \n #if SRT_ENABLE_ENCRYPTION\n \n-    int32_t kms = -1;\n+    uint32_t kms = -1;\n \n     EXPECT_NE(srt_getsockflag(grp, SRTO_KMSTATE, &kms, &optsize), SRT_ERROR);\n     EXPECT_EQ(optsize, (int) sizeof kms);\n-    EXPECT_EQ(kms, uint32_t(SRT_KM_S_SECURED));\n+    EXPECT_EQ(kms, int(SRT_KM_S_SECURED));\n \n     EXPECT_NE(srt_getsockflag(grp, SRTO_PBKEYLEN, &kms, &optsize), SRT_ERROR);\n     EXPECT_EQ(optsize, (int) sizeof kms);\n-    EXPECT_EQ(kms, uint32_t(16));\n+    EXPECT_EQ(kms, 16);\n \n #ifdef ENABLE_AEAD_API_PREVIEW\n     EXPECT_NE(srt_getsockflag(grp, SRTO_CRYPTOMODE, &kms, &optsize), SRT_ERROR);\n-    EXPECT_EQ(optsize, (int) sizeof kms);\n-    EXPECT_EQ(kms, uint32_t(SRT_KM_S_SECURING));\n+    EXPECT_EQ(optsize, sizeof kms);\n+    EXPECT_EQ(kms, 1);\n #endif\n #endif\n \n@@ -555,6 +481,7 @@ TEST(Bonding, Options)\n     }\n \n     accept_and_close.join();\n+    srt_close(grp);\n }\n \n inline SRT_SOCKGROUPCONFIG PrepareEndpoint(const std::string& host, int port)\n@@ -580,7 +507,7 @@ TEST(Bonding, InitialFailure)\n     int allow = 1;\n     ASSERT_NE(srt_setsockflag(lsn, SRTO_GROUPCONNECT, &allow, sizeof allow), SRT_ERROR);\n \n-    sockaddr_any sa = srt::CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n+    sockaddr_any sa = CreateAddr(\"127.0.0.1\", 5555, AF_INET);\n     ASSERT_NE(srt_bind(lsn, sa.get(), sa.size()), SRT_ERROR);\n     ASSERT_NE(srt_listen(lsn, 5), SRT_ERROR);\n \n@@ -637,976 +564,3 @@ TEST(Bonding, InitialFailure)\n     srt_close(lsn);\n }\n \n-\n-\n-// General idea:\n-// This should try to connect to two nonexistent links,\n-// the connecting function (working in blocking mode)\n-// should exit with error, after the group has been closed\n-// in a separate thread.\n-//\n-// Steps:\n-// 1. Create group\n-// 2. Use a nonexistent endpoints 192.168.1.237:4200 and *:4201\n-// 3. Close the group in a thread\n-// 4. Wait for error\n-TEST(Bonding, ConnectBlind)\n-{\n-    using namespace srt;\n-\n-    TestInit srtinit;\n-    MAKE_UNIQUE_SOCK(ss, \"GrpCaller\", srt_create_group(SRT_GTYPE_BROADCAST));\n-\n-    std::vector<SRT_SOCKGROUPCONFIG> targets;\n-    for (int i = 0; i < 2; ++i)\n-    {\n-        sockaddr_any sa = srt::CreateAddr(\"192.168.1.237\", 4200 + i, AF_INET);\n-        const SRT_SOCKGROUPCONFIG gd = srt_prepare_endpoint(NULL, sa.get(), sa.size());\n-        targets.push_back(gd);\n-    }\n-\n-    std::future<void> closing_promise = std::async(std::launch::async, [](int s) {\n-        std::this_thread::sleep_for(std::chrono::seconds(2));\n-        std::cerr << \"Closing group\" << std::endl;\n-        srt_close(s);\n-    }, ss);\n-\n-    std::cout << \"srt_connect_group calling \" << std::endl;\n-    const int st = srt_connect_group(ss, targets.data(), targets.size());\n-    std::cout << \"srt_connect_group returned \" << st << std::endl;\n-\n-    closing_promise.wait();\n-    EXPECT_EQ(st, -1);\n-\n-    // Delete config objects before prospective exception\n-    for (auto& gd: targets)\n-        srt_delete_config(gd.config);\n-\n-    int res = srt_close(ss);\n-    if (res == SRT_ERROR)\n-    {\n-        std::cerr << \"srt_close: \" << srt_getlasterror_str() << std::endl;\n-    }\n-}\n-\n-// TEST IDEA:\n-// This uses srt_connect_group in non-blocking mode. The listener\n-// is also created to respond to the connection. Expected is to\n-// continue the connecting in background and report a success,\n-// and report the epoll IN on listener for the first connection,\n-// and UPDATE For the second one.\n-//\n-// TEST STEPS:\n-// 1. Create a listener socket and a group.\n-// 2. Set the group and the listener socket non-blocking mode\n-// 3. Start the accepting thread\n-//    - wait for IN event ready on the listener socket\n-//    - accept a connection\n-//    - wait for UPDATE event ready on the listener socket\n-//    - wait for any event up to 5s (possibly ERR)\n-//    - close the listener socket\n-// 4. Prepare two connections and start connecting\n-// 5. Wait for the OUT readiness event on the group\n-// 6. Close the group.\n-// 7. Join the thread\n-TEST(Bonding, ConnectNonBlocking)\n-{\n-    using namespace std;\n-    using namespace std::chrono;\n-    using namespace srt;\n-\n-    TestInit srtinit;\n-\n-    const string ADDR = \"127.0.0.1\";\n-    const int PORT = 4209;\n-\n-    // NOTE: Add more group types, if implemented!\n-    vector<SRT_GROUP_TYPE> types { SRT_GTYPE_BROADCAST, SRT_GTYPE_BACKUP };\n-\n-    for (const auto GTYPE: types)\n-    {\n-        g_listen_socket = srt_create_socket();\n-\n-        sockaddr_any sa = srt::CreateAddr(ADDR, PORT, AF_INET);\n-\n-        EXPECT_NE(srt_bind(g_listen_socket, sa.get(), sa.size()), -1);\n-        const int yes = 1;\n-        srt_setsockflag(g_listen_socket, SRTO_GROUPCONNECT, &yes, sizeof yes);\n-\n-        int lsn_eid = srt_epoll_create();\n-        int lsn_events = SRT_EPOLL_IN | SRT_EPOLL_ERR | SRT_EPOLL_UPDATE;\n-        srt_epoll_add_usock(lsn_eid, g_listen_socket, &lsn_events);\n-\n-        // Caller part\n-\n-        const int ss = srt_create_group(GTYPE);\n-        EXPECT_NE(ss, SRT_ERROR);\n-        std::cout << \"Created group socket: \" << ss << '\\n';\n-\n-        int no = 0;\n-        EXPECT_NE(srt_setsockopt(ss, 0, SRTO_RCVSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n-        EXPECT_NE(srt_setsockopt(ss, 0, SRTO_SNDSYN, &no, sizeof no), SRT_ERROR); // non-blocking mode\n-\n-        const int poll_id = srt_epoll_create();\n-        // Will use this epoll to wait for srt_accept(...)\n-        const int epoll_out = SRT_EPOLL_OUT | SRT_EPOLL_ERR;\n-        EXPECT_NE(srt_epoll_add_usock(poll_id, ss, &epoll_out), SRT_ERROR);\n-\n-        srt_connect_callback(ss, &ConnectCallback, this);\n-\n-        cout << \"TEST: Group type: \" << GTYPE << endl;\n-\n-        // synchronizers\n-        std::promise<void>\n-            connect_passed,\n-            accept_passed,\n-            checks_done;\n-\n-        //srt_setloglevel(LOG_DEBUG);\n-\n-        auto acthr = std::thread([&lsn_eid, &connect_passed, &accept_passed, &checks_done]() {\n-                SRT_EPOLL_EVENT ev[3];\n-\n-                ThreadName::set(\"TEST_A\");\n-\n-                cout << \"[A] Waiting for main thread to pass connect()\\n\";\n-\n-                // Delay with executing accept to keep the peer in \"in progress\"\n-                // connection state.\n-                connect_passed.get_future().get();\n-                EXPECT_NE(srt_listen(g_listen_socket, 5), SRT_ERROR);\n-\n-                cout << \"[A] Waiting for accept\\n\";\n-                // This can wait in infinity; worst case it will be killed in process.\n-                int uwait_res = srt_epoll_uwait(lsn_eid, ev, 3, -1);\n-                EXPECT_EQ(uwait_res, 1);\n-                EXPECT_EQ(ev[0].fd, g_listen_socket);\n-\n-                // Check if the IN event is set, even if it's not the only event\n-                const int ev_in_bit = SRT_EPOLL_IN;\n-                EXPECT_NE(ev[0].events & ev_in_bit, 0);\n-                bool have_also_update = ev[0].events & SRT_EPOLL_UPDATE;\n-\n-                cout << \"[A] Accept delay until connect done...\\n\";\n-\n-                cout << \"[A] Accept: go on\\n\";\n-\n-                sockaddr_any adr;\n-                SRTSOCKET accept_id = srt_accept(g_listen_socket, adr.get(), &adr.len);\n-\n-                // Expected: group reporting\n-                EXPECT_NE(accept_id & SRTGROUP_MASK, 0);\n-\n-                if (have_also_update)\n-                {\n-                    cout << \"[A] NOT waiting for update - already reported previously\\n\";\n-                }\n-                else\n-                {\n-                    cout << \"[A] Waiting for update\\n\";\n-                    // Now another waiting is required and expected the update event\n-                    // Wait up to 5s to avoid hangup in case of error\n-                    uwait_res = srt_epoll_uwait(lsn_eid, ev, 3, 5000);\n-                    EXPECT_EQ(uwait_res, 1);\n-                    EXPECT_EQ(ev[0].fd, g_listen_socket);\n-                    EXPECT_EQ(ev[0].events, (int)SRT_EPOLL_UPDATE);\n-                }\n-\n-                // As accept is expected to be finished and two connections were\n-                // established, make sure that both connections are established.\n-                // Wait until you have at least two members\n-                SRT_SOCKGROUPDATA members[3];\n-                size_t grouplen = 3;\n-                cout << \"[A] Waiting until having 2 members in the group\\n\";\n-                while (srt_group_data(accept_id, members, &grouplen) != SRT_ERROR\n-                        && grouplen < 2)\n-                {\n-                    grouplen = 3;\n-                    this_thread::sleep_for(milliseconds(250));\n-                }\n-                accept_passed.set_value();\n-\n-\n-                cout << \"[A] Waitig on epoll for close (up to 5s)\\n\";\n-                // Wait up to 5s for an error\n-                srt_epoll_uwait(lsn_eid, ev, 3, 5000);\n-                srt_close(accept_id);\n-                checks_done.set_value();\n-\n-                cout << \"[A] thread finished\\n\";\n-        });\n-\n-        cout << \"Connecting two sockets\\n\";\n-\n-        SRT_SOCKGROUPCONFIG cc[2];\n-        cc[0] = srt_prepare_endpoint(NULL, sa.get(), sa.size());\n-        cc[1] = srt_prepare_endpoint(NULL, sa.get(), sa.size());\n-\n-        EXPECT_NE(srt_epoll_add_usock(poll_id, ss, &epoll_out), SRT_ERROR);\n-\n-        int result = srt_connect_group(ss, cc, 2);\n-        EXPECT_NE(result, -1);\n-        char data[4] = { 1, 2, 3, 4};\n-        cout << \"Sending...\\n\";\n-        int wrong_send = srt_send(ss, data, sizeof data);\n-\n-        // Only now we allow the other thread to go on with accept\n-        connect_passed.set_value();\n-        cout << \"Getting error...\\n\";\n-        int errorcode = srt_getlasterror(NULL);\n-        EXPECT_EQ(wrong_send, -1);\n-        EXPECT_EQ(errorcode, SRT_EASYNCSND) << \"REAL ERROR: \" << srt_getlasterror_str();\n-\n-        // Wait to make sure that both links are connected.\n-        accept_passed.get_future().get();\n-\n-        // Wait up to 2s\n-        SRT_EPOLL_EVENT ev[3];\n-        const int uwait_result = srt_epoll_uwait(poll_id, ev, 3, 2000);\n-        std::cout << \"Returned from connecting two sockets, waiting for all checks from [A]\" << std::endl;\n-\n-        checks_done.get_future().get();\n-\n-        EXPECT_EQ(uwait_result, 1);  // Expect the group reported\n-        EXPECT_EQ(ev[0].fd, ss);\n-\n-        std::cout << \"Closing group and releasing resources\\n\";\n-\n-        EXPECT_EQ(srt_close(ss), 0);\n-        acthr.join();\n-\n-        srt_epoll_release(lsn_eid);\n-        srt_epoll_release(poll_id);\n-\n-        srt_close(g_listen_socket);\n-    }\n-\n-}\n-\n-// TEST IDEA:\n-// In this test there is created a working listener socket to\n-// accept the connection, and we use a Backup-type group with\n-// two links, but different weights. We connect them both and\n-// make sure that both are ready for use. Then we send a packet\n-// over the group and see, which link got activated and which\n-// remained idle. Expected is to have the link with higher\n-// priority (greater weight) to be activated.\n-//\n-// TEST STEPS:\n-// 1. Create a listener socket and a group.\n-// 3. Start the accepting thread\n-//    - accept a connection\n-//    - read one packet from the accepted entity\n-//    - close the listener socket\n-// 4. Prepare two connections (one with weight=1) and connect the group\n-// 5. Wait for having all links connected\n-// 6. Send one packet and check which link was activated\n-// 6. Close the group.\n-// 7. Join the thread\n-TEST(Bonding, BackupPriorityBegin)\n-{\n-    using namespace std;\n-    using namespace std::chrono;\n-    using namespace srt;\n-\n-    TestInit srtinit;\n-\n-    g_nconnected = 0;\n-    g_nfailed = 0;\n-\n-    g_listen_socket = srt_create_socket();\n-    ASSERT_NE(g_listen_socket, SRT_INVALID_SOCK);\n-    sockaddr_in bind_sa;\n-    memset(&bind_sa, 0, sizeof bind_sa);\n-    bind_sa.sin_family = AF_INET;\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &bind_sa.sin_addr), 1);\n-    bind_sa.sin_port = htons(4200);\n-\n-    EXPECT_NE(srt_bind(g_listen_socket, (sockaddr*)&bind_sa, sizeof bind_sa), -1);\n-    const int yes = 1;\n-    srt_setsockflag(g_listen_socket, SRTO_GROUPCONNECT, &yes, sizeof yes);\n-    EXPECT_NE(srt_listen(g_listen_socket, 5), -1);\n-\n-    // Caller part\n-\n-    const int ss = srt_create_group(SRT_GTYPE_BACKUP);\n-    EXPECT_NE(ss, SRT_ERROR);\n-\n-    srt_connect_callback(ss, &ConnectCallback, this);\n-\n-    sockaddr_in sa;\n-    sa.sin_family = AF_INET;\n-    sa.sin_port = htons(4200);\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n-\n-    auto acthr = std::thread([]() {\n-            sockaddr_any adr;\n-            cout << \"[A] Accepting a connection...\\n\";\n-            int accept_id = srt_accept(g_listen_socket, adr.get(), &adr.len);\n-\n-            // Expected: group reporting\n-            EXPECT_NE(accept_id & SRTGROUP_MASK, 0);\n-\n-            SRT_SOCKGROUPDATA gdata[2];\n-            SRT_MSGCTRL mc = srt_msgctrl_default;\n-            mc.grpdata = gdata;\n-            mc.grpdata_size = 2;\n-            long long data[1320/8];\n-\n-            cout << \"[A] Receiving...\\n\";\n-            int ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            EXPECT_EQ(ds, 8);\n-\n-            cout << \"[A] Closing\\n\";\n-            srt_close(accept_id);\n-            cout << \"[A] thread finished\\n\";\n-    });\n-\n-    cout << \"Connecting two sockets\\n\";\n-\n-    SRT_SOCKGROUPCONFIG cc[2];\n-    cc[0] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[0].token = 0;\n-    cc[1] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[1].token = 1;\n-    cc[1].weight = 1; // higher than the default 0\n-\n-    int result = srt_connect_group(ss, cc, 2);\n-    EXPECT_GT(result, 0); // blocking mode, first connection = returns Socket ID\n-\n-    // Make sure both links are connected\n-    SRT_SOCKGROUPDATA gdata[2];\n-    size_t psize = 2;\n-    size_t nwait = 10;\n-    cout << \"Waiting for getting 2 links:\\n\";\n-    while (--nwait)\n-    {\n-        srt_group_data(ss, gdata, &psize);\n-        if (psize == 2)\n-        {\n-            int l1, l2;\n-            l1 = gdata[0].memberstate;\n-            l2 = gdata[1].memberstate;\n-\n-            if (l1 > SRT_GST_PENDING && l2 > SRT_GST_PENDING)\n-            {\n-                cout << \"Both up: [0]=\" << l1 << \" [1]=\" << l2 << \"\\n\";\n-                break;\n-            }\n-            else\n-            {\n-                cout << \"Still link states [0]=\" << l1 << \" [1]=\" << l2 << \"\\n\";\n-            }\n-        }\n-        else\n-        {\n-            cout << \"Still \" << psize << endl;\n-        }\n-        this_thread::sleep_for(milliseconds(500));\n-    }\n-    EXPECT_NE(nwait, size_t());\n-\n-    // Now send one packet\n-    long long data = 0x1234123412341234;\n-\n-    SRT_MSGCTRL mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 2;\n-\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    int sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    EXPECT_EQ(sendret, int(sizeof data));\n-\n-    // So, let's check which link is in RUNNING state\n-    // TOKEN value is the index in cc array, and we should\n-    // also have the weight value there.\n-\n-    SRT_SOCKGROUPDATA* mane, * backup;\n-    if (gdata[0].weight == 0)\n-    {\n-        backup = &gdata[0];\n-        mane = &gdata[1];\n-    }\n-    else\n-    {\n-        mane = &gdata[0];\n-        backup = &gdata[1];\n-    }\n-\n-    cout << \"MAIN:[\" << mane->token << \"] weight=\" << mane->weight << endl;\n-    cout << \"BACKUP:[\" << backup->token << \"] weight=\" << backup->weight << endl;\n-\n-    // Ok, now mane link should be active, backup idle\n-    EXPECT_EQ(mane->memberstate, SRT_GST_RUNNING);\n-    EXPECT_EQ(backup->memberstate, SRT_GST_IDLE);\n-\n-    acthr.join();\n-\n-    srt_close(g_listen_socket);\n-    srt_close(ss);\n-}\n-\n-\n-// TEST IDEA:\n-// In this test there is created a working listener socket to\n-// accept the connection, and we use a Backup-type group with\n-// two links, but different weights. We connect the first link\n-// with less weight and send one packet to make sure this only\n-// link was activated. Then we connect a second link with weight=1.\n-// Then we send the packet again and see if the new link was\n-// immediately activated. The first link should be silenced after\n-// time, but there's no possibility to check this in such a\n-// simple test.\n-//\n-// TEST STEPS:\n-// 1. Create a listener socket and a group.\n-// 3. Start the accepting thread\n-//    - accept a connection\n-//    - read one packet from the accepted entity\n-//    - read the second packet from the accepted entity\n-//    - close the listener socket\n-// 4. Prepare one connection with weight=0 and connect the group\n-// 5. Send a packet to enforce activation of one link\n-// 6. Prepare another connection with weight=1 and connect the group\n-// 7. Send a packet\n-// 8. Check member status - both links should be running.\n-// 9. Close the group.\n-// 10. Join the thread\n-TEST(Bonding, BackupPriorityTakeover)\n-{\n-    using namespace std;\n-    using namespace std::chrono;\n-    using namespace srt;\n-\n-    TestInit srtinit;\n-\n-    g_nconnected = 0;\n-    g_nfailed = 0;\n-\n-    g_listen_socket = srt_create_socket();\n-    ASSERT_NE(g_listen_socket, SRT_INVALID_SOCK);\n-    sockaddr_in bind_sa;\n-    memset(&bind_sa, 0, sizeof bind_sa);\n-    bind_sa.sin_family = AF_INET;\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &bind_sa.sin_addr), 1);\n-    bind_sa.sin_port = htons(4200);\n-\n-    EXPECT_NE(srt_bind(g_listen_socket, (sockaddr*)&bind_sa, sizeof bind_sa), -1);\n-    const int yes = 1;\n-    srt_setsockflag(g_listen_socket, SRTO_GROUPCONNECT, &yes, sizeof yes);\n-    EXPECT_NE(srt_listen(g_listen_socket, 5), -1);\n-\n-    // Caller part\n-\n-    const int ss = srt_create_group(SRT_GTYPE_BACKUP);\n-    EXPECT_NE(ss, SRT_ERROR);\n-\n-    srt_connect_callback(ss, &ConnectCallback, this);\n-\n-    sockaddr_in sa;\n-    sa.sin_family = AF_INET;\n-    sa.sin_port = htons(4200);\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n-\n-    auto acthr = std::thread([]() {\n-            sockaddr_any adr;\n-            cout << \"[A] Accepting a connection...\\n\";\n-            int accept_id = srt_accept(g_listen_socket, adr.get(), &adr.len);\n-\n-            // Expected: group reporting\n-            EXPECT_NE(accept_id & SRTGROUP_MASK, 0);\n-\n-            SRT_SOCKGROUPDATA gdata[2];\n-            SRT_MSGCTRL mc = srt_msgctrl_default;\n-            mc.grpdata = gdata;\n-            mc.grpdata_size = 2;\n-            long long data[1320/8];\n-\n-            cout << \"[A] Receiving 1...\\n\";\n-            int ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            EXPECT_EQ(ds, 8);\n-\n-            cout << \"[A] Receiving 2...\\n\";\n-            ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            EXPECT_EQ(ds, 8);\n-\n-            // To make it possible that the state is checked before it is closed.\n-            this_thread::sleep_for(seconds(1));\n-\n-            cout << \"[A] Closing\\n\";\n-            srt_close(accept_id);\n-            cout << \"[A] thread finished\\n\";\n-    });\n-\n-    cout << \"Connecting first link weight=0:\\n\";\n-\n-    SRT_SOCKGROUPCONFIG cc[2];\n-    cc[0] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[0].token = 0;\n-\n-    int result = srt_connect_group(ss, cc, 1);\n-    EXPECT_GT(result, 0); // connect with only one element returns socket ID\n-\n-    // As we have one link, after `srt_connect_group` returns, we have\n-    // this link now connected. Send one data portion.\n-\n-    SRT_SOCKGROUPDATA gdata[2];\n-\n-    long long data = 0x1234123412341234;\n-    SRT_MSGCTRL mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 2;\n-\n-    cout << \"Sending (1)\\n\";\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    int sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    EXPECT_EQ(sendret, int(sizeof data));\n-    EXPECT_EQ(mc.grpdata_size, size_t(1));\n-    EXPECT_EQ(gdata[0].memberstate, SRT_GST_RUNNING);\n-\n-    cout << \"Connecting second link weight=1:\\n\";\n-    // Now prepare the second connection\n-    cc[0].token = 1;\n-    cc[0].weight = 1; // higher than the default 0\n-    result = srt_connect_group(ss, cc, 1);\n-    EXPECT_GT(result, 0); // connect with only one element returns socket ID\n-\n-    // Make sure both links are connected\n-    size_t psize = 2;\n-    size_t nwait = 10;\n-    cout << \"Waiting for getting 2 links:\\n\";\n-    while (--nwait)\n-    {\n-        srt_group_data(ss, gdata, &psize);\n-        if (psize == 2)\n-        {\n-            int l1, l2;\n-            l1 = gdata[0].memberstate;\n-            l2 = gdata[1].memberstate;\n-\n-            if (l1 > SRT_GST_PENDING && l2 > SRT_GST_PENDING)\n-            {\n-                cout << \"Both up: [0]=\" << l1 << \" [1]=\" << l2 << \"\\n\";\n-                break;\n-            }\n-            else\n-            {\n-                cout << \"Still link states [0]=\" << l1 << \" [1]=\" << l2 << \"\\n\";\n-            }\n-        }\n-        else\n-        {\n-            cout << \"Still \" << psize << endl;\n-        }\n-        this_thread::sleep_for(milliseconds(500));\n-    }\n-    EXPECT_NE(nwait, size_t(0));\n-\n-    // Now send one packet (again)\n-    mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 2;\n-\n-    cout << \"Sending (2)\\n\";\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    EXPECT_EQ(sendret, int(sizeof data));\n-\n-    // So, let's check which link is in RUNNING state\n-    // TOKEN value is the index in cc array, and we should\n-    // also have the weight value there.\n-\n-    SRT_SOCKGROUPDATA* mane, * backup;\n-    if (gdata[0].weight == 0)\n-    {\n-        backup = &gdata[0];\n-        mane = &gdata[1];\n-    }\n-    else\n-    {\n-        mane = &gdata[0];\n-        backup = &gdata[1];\n-    }\n-\n-    cout << \"MAIN:[\" << mane->token << \"] weight=\" << mane->weight << endl;\n-    cout << \"BACKUP:[\" << backup->token << \"] weight=\" << backup->weight << endl;\n-\n-    // Ok, now both links should be running (this state lasts\n-    // for the \"temporary activation\" period.\n-    EXPECT_EQ(mane->memberstate, SRT_GST_RUNNING);\n-    EXPECT_EQ(backup->memberstate, SRT_GST_RUNNING);\n-\n-    acthr.join();\n-\n-    srt_close(g_listen_socket);\n-    srt_close(ss);\n-}\n-\n-\n-// TEST IDEA:\n-// In this test there is created a working listener socket to\n-// accept the connection, and we use a Backup-type group with\n-// two links, but different weights. We connect then two links\n-// both with weight=1. Then we send a packet to make sure that\n-// exactly one of them got activated. Then we connect another\n-// link with weight=0. Then we send a packet again, which should\n-// not change the link usage. Then we check which link was\n-// active so far, and we close the socket for that link to make\n-// it broken, then we wait for having only two links connected.\n-// Then a packet is sent to activate a link. We expect the link\n-// with higher weight is activated.\n-//\n-// TEST STEPS:\n-// 1. Create a listener socket.\n-// 2. Create and setup a group.\n-// 3. Start the accepting thread\n-//    A1. accept a connection\n-//    A2. read one packet from the accepted entity\n-//    A3. read the second packet from the accepted entity\n-//    A4. read the third packet from the accepted entity\n-//    A5. close the listener socket\n-// 4. Prepare two connections with weight=1 and connect the group\n-// 5. Send a packet to enforce activation of one link\n-// 6. Prepare another connection with weight=0 and connect the group\n-// 7. Wait for having all 3 links connected.\n-// 8. Send a packet\n-// 9. Find which link is currently active and close it\n-// 10. Wait for having only two links.\n-// 11. Send a packet.\n-// 12. Find one link active and one idle\n-// 13. Check if the link with weight=1 is active and the one with weight=0 is idle.\n-// 14. Close the group.\n-// 15. Join the thread\n-TEST(Bonding, BackupPrioritySelection)\n-{\n-    using namespace std;\n-    using namespace std::chrono;\n-    using namespace srt;\n-\n-    TestInit srtinit;\n-\n-    g_nconnected = 0;\n-    g_nfailed = 0;\n-    sync::atomic<bool> recvd { false };\n-\n-    // 1.\n-    sockaddr_in bind_sa;\n-    memset(&bind_sa, 0, sizeof bind_sa);\n-    bind_sa.sin_family = AF_INET;\n-    ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &bind_sa.sin_addr), 1);\n-    bind_sa.sin_port = htons(4200);\n-\n-    g_listen_socket = srt_create_socket();\n-    ASSERT_NE(g_listen_socket, SRT_INVALID_SOCK);\n-    EXPECT_NE(srt_bind(g_listen_socket, (sockaddr*)&bind_sa, sizeof bind_sa), -1);\n-    const int yes = 1;\n-    srt_setsockflag(g_listen_socket, SRTO_GROUPCONNECT, &yes, sizeof yes);\n-    EXPECT_NE(srt_listen(g_listen_socket, 5), -1);\n-\n-    // Caller part\n-    // 2.\n-    const int ss = srt_create_group(SRT_GTYPE_BACKUP);\n-    EXPECT_NE(ss, SRT_ERROR);\n-\n-    srt_connect_callback(ss, &ConnectCallback, this);\n-\n-    // Set the group's stability timeout to 1s, otherwise it will\n-    // declare the links unstable by not receiving ACKs.\n-    int stabtimeo = 1000;\n-    srt_setsockflag(ss, SRTO_GROUPMINSTABLETIMEO, &stabtimeo, sizeof stabtimeo);\n-\n-    //srt_setloglevel(LOG_DEBUG);\n-    srt::resetlogfa( std::set<srt_logging::LogFA> {\n-            SRT_LOGFA_GRP_SEND,\n-            SRT_LOGFA_GRP_MGMT,\n-            SRT_LOGFA_CONN\n-            });\n-\n-    sockaddr_in sa;\n-    sa.sin_family = AF_INET;\n-    sa.sin_port = htons(4200);\n-    EXPECT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n-\n-    // 3.\n-    auto acthr = std::thread([&recvd]() {\n-            sockaddr_any adr;\n-            cout << \"[A1] Accepting a connection...\\n\";\n-\n-            // A1\n-            int accept_id = srt_accept(g_listen_socket, adr.get(), &adr.len);\n-\n-            // Expected: group reporting\n-            EXPECT_NE(accept_id & SRTGROUP_MASK, 0);\n-\n-            SRT_SOCKGROUPDATA gdata[2];\n-            SRT_MSGCTRL mc = srt_msgctrl_default;\n-            mc.grpdata = gdata;\n-            mc.grpdata_size = 2;\n-            long long data[1320/8];\n-\n-            // A2\n-            cout << \"[A2] Receiving 1...\\n\";\n-            int ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            if (ds == -1) { cout << \"[A2] ERROR: \" << srt_getlasterror(NULL) << \" \" << srt_getlasterror_str() << endl; }\n-            EXPECT_EQ(ds, 8);\n-\n-            // A3\n-            cout << \"[A3] Receiving 2...\\n\";\n-            ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            if (ds == -1) { cout << \"[A3] ERROR: \" << srt_getlasterror(NULL) << \" \" << srt_getlasterror_str() << endl; }\n-            EXPECT_EQ(ds, 8);\n-            recvd = true;\n-\n-            // A4\n-            cout << \"[A4] Receiving 3...\\n\";\n-            ds = srt_recvmsg2(accept_id, (char*)data, sizeof data, (&mc));\n-            if (ds == -1) { cout << \"[A4] ERROR: \" << srt_getlasterror(NULL) << \" \" << srt_getlasterror_str() << endl; }\n-            EXPECT_EQ(ds, 8);\n-\n-            cout << \"[A] Waiting 5s...\\n\";\n-            // To make it possible that the state is checked before it is closed.\n-            this_thread::sleep_for(seconds(5));\n-\n-            // A5\n-            cout << \"[A5] Closing\\n\";\n-            srt_close(accept_id);\n-            cout << \"[A] thread finished\\n\";\n-    });\n-\n-\n-    cout << \"(4) Connecting first 2 links weight=1:\\n\";\n-\n-    SRT_SOCKGROUPCONFIG cc[2];\n-    cc[0] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[0].token = 0;\n-    cc[0].weight = 1;\n-    cc[1] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[1].token = 1;\n-    cc[1].weight = 1;\n-\n-    // 4.\n-    int result = srt_connect_group(ss, cc, 2);\n-    EXPECT_GT(result, 0); // BLOCKING MODE, always returns the socket value\n-\n-    // As we have one link, after `srt_connect_group` returns, we have\n-    // this link now connected. Send one data portion.\n-\n-    SRT_SOCKGROUPDATA gdata[3];\n-    memset(gdata, 0, sizeof(gdata));\n-\n-    long long data = 0x1234123412341234;\n-    SRT_MSGCTRL mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 3;\n-\n-    // We can send now. We know that we have at least one\n-    // link connected and it already has the same priority\n-    // as the other.\n-\n-    //srt_setloglevel(LOG_DEBUG);\n-    // 5.\n-    cout << \"(5) Sending (1)\\n\";\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    int sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    // In case when this was an error, display the code\n-    if (sendret == -1) { cout << \"[A4] ERROR: \" << srt_getlasterror(NULL) << \" \" << srt_getlasterror_str() << endl; }\n-\n-    EXPECT_EQ(sendret, int(sizeof data));\n-\n-    EXPECT_EQ(mc.grpdata_size, size_t(2));\n-\n-    int state0 = gdata[0].memberstate;\n-    int state1 = gdata[1].memberstate;\n-\n-    cout << \"States: [0]=\" << state0 << \" [1]=\" << state1 << endl;\n-    EXPECT_TRUE(state0 == SRT_GST_RUNNING || state1 == SRT_GST_RUNNING);\n-\n-    // 6.\n-    cout << \"(6) Connecting third link weight=0:\\n\";\n-    // Now prepare the third connection\n-    cc[0] = srt_prepare_endpoint(NULL, (sockaddr*)&sa, sizeof sa);\n-    cc[0].token = 2;\n-    cc[0].weight = 0; // higher than the default 0\n-    result = srt_connect_group(ss, cc, 1);\n-    EXPECT_GE(result, 0); // ONE connection only - will return socket id\n-\n-    // Make sure all 3 links are connected\n-    size_t psize = 3;\n-    size_t nwait = 10;\n-    set<SRT_MEMBERSTATUS> states;\n-\n-    // 7.\n-    cout << \"(7) Waiting for getting 3 links:\\n\";\n-    while (--nwait)\n-    {\n-        srt_group_data(ss, gdata, &psize);\n-        if (psize == 3)\n-        {\n-            states.clear();\n-            for (int i = 0; i < 3; ++i)\n-                states.insert(gdata[i].memberstate);\n-\n-            if (states.count(SRT_GST_PENDING))\n-            {\n-                cout << \"Still not all links...\\n\";\n-            }\n-            else\n-            {\n-                cout << \"All links up\\n\";\n-                break;\n-            }\n-        }\n-        else\n-        {\n-            cout << \"Still \" << psize << endl;\n-        }\n-        this_thread::sleep_for(milliseconds(500));\n-    }\n-    EXPECT_NE(nwait, size_t(0));\n-\n-    // Now send one packet (again)\n-    mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 3;\n-\n-    // 8.\n-    cout << \"(8) Sending (2)\\n\";\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    EXPECT_EQ(sendret, int(sizeof data));\n-    EXPECT_EQ(mc.grpdata_size, size_t(3));\n-\n-    // So, let's check which link is in RUNNING state\n-    // TOKEN value is the index in cc array, and we should\n-    // also have the weight value there.\n-\n-    SRT_SOCKGROUPDATA* mane = nullptr;\n-\n-    for (size_t i = 0; i < mc.grpdata_size; ++i)\n-    {\n-        if (gdata[i].memberstate == SRT_GST_RUNNING)\n-        {\n-            mane = &gdata[i];\n-            break;\n-        }\n-    }\n-\n-    EXPECT_NE(mane, nullptr);\n-    EXPECT_EQ(mane->weight, 1);\n-\n-    // Spin-wait for making sure the reception succeeded before\n-    // closing. This shouldn't be a problem in general, but\n-    int ntry = 100;\n-    while (!recvd && --ntry)\n-        this_thread::sleep_for(milliseconds(200));\n-    EXPECT_NE(ntry, 0);\n-\n-    cout << \"(9) Found activated link: [\" << mane->token << \"] - closing after 0.5s...\\n\";\n-\n-    // Waiting is to make sure that the listener thread has received packet 3.\n-    this_thread::sleep_for(milliseconds(500));\n-    EXPECT_NE(srt_close(mane->id), -1);\n-\n-    // Now expect to have only 2 links, wait for it if needed.\n-    psize = 2;\n-    nwait = 10;\n-\n-    cout << \"(10) Waiting for ONLY 2 links:\\n\";\n-    while (--nwait)\n-    {\n-        srt_group_data(ss, gdata, &psize);\n-        if (psize == 2)\n-        {\n-            break;\n-        }\n-        else\n-        {\n-            cout << \"Still \" << psize << endl;\n-        }\n-        this_thread::sleep_for(milliseconds(500));\n-    }\n-    EXPECT_NE(nwait, size_t(0));\n-\n-    // Now send one packet (again)\n-    mc = srt_msgctrl_default;\n-    mc.grpdata = gdata;\n-    mc.grpdata_size = 2;\n-\n-    cout << \"(11) Sending (3)\\n\";\n-    // This call should retrieve the group information\n-    // AFTER the transition has happened\n-    sendret = srt_sendmsg2(ss, (char*)&data, sizeof data, (&mc));\n-    EXPECT_EQ(sendret, int(sizeof data));\n-\n-    cout << \"(sleep)\\n\";\n-    this_thread::sleep_for(seconds(1));\n-\n-    mane = nullptr;\n-    SRT_SOCKGROUPDATA* backup = nullptr;\n-    cout << \"(12) Checking main/backup:\";\n-    int repeat_check = 1; // 50;\n-CheckLinksAgain:\n-    for (size_t i = 0; i < mc.grpdata_size; ++i)\n-    {\n-        cout << \"[\" << i << \"]\" << srt_logging::MemberStatusStr(gdata[i].memberstate)\n-            << \" weight=\" << gdata[i].weight;\n-        if (gdata[i].memberstate == SRT_GST_RUNNING)\n-        {\n-            cout << \" (main) \";\n-            mane = &gdata[i];\n-        }\n-        else\n-        {\n-            cout << \" (backup) \";\n-            backup = &gdata[i];\n-        }\n-    }\n-    if (backup == nullptr)\n-    {\n-        if (--repeat_check)\n-        {\n-            cout << \"BACKUP STILL RUNNING. AGAIN\\n\";\n-            this_thread::sleep_for(milliseconds(250));\n-            goto CheckLinksAgain;\n-        }\n-    }\n-    cout << endl;\n-\n-    EXPECT_NE(mane, nullptr);\n-    EXPECT_NE(backup, nullptr);\n-    EXPECT_EQ(mane->weight, 1);\n-    EXPECT_EQ(backup->weight, 0);\n-\n-    cout << \"MAIN (expected active):[\" << mane->token << \"] weight=\" << mane->weight << endl;\n-    cout << \"BACKUP (expected idle):[\" << backup->token << \"] weight=\" << backup->weight << endl;\n-\n-    // Ok, now both links should be running (this state lasts\n-    // for the \"temporary activation\" period.\n-    EXPECT_EQ(mane->memberstate, SRT_GST_RUNNING);\n-    EXPECT_EQ(backup->memberstate, SRT_GST_IDLE);\n-\n-    this_thread::sleep_for(seconds(1));\n-\n-    cout << \"Closing receiver thread [A]\\n\";\n-\n-    acthr.join();\n-\n-    srt_close(g_listen_socket);\n-    srt_close(ss);\n-}\n-\n-\n-TEST(Bonding, ApiConfig)\n-{\n-    using namespace std;\n-    SRT_SOCKOPT_CONFIG config;\n-\n-    string example = \"example_long_excessively\";\n-\n-    EXPECT_EQ(srt_config_add(&config, SRTO_BINDTODEVICE, (void*)example.data(), example.size()), 0);\n-}\ndiff --git a/test/test_buffer_rcv.cpp b/test/test_buffer_rcv.cpp\nindex 5e766de..511c2dc 100644\n--- a/test/test_buffer_rcv.cpp\n+++ b/test/test_buffer_rcv.cpp\n@@ -25,7 +25,7 @@ protected:\n     // SetUp() is run immediately before a test starts.\n     void SetUp() override\n     {\n-        // make_unique is unfortunately C++14\n+        // make_unique is unfortunatelly C++14\n         m_unit_queue.reset(new CUnitQueue(m_buff_size_pkts, 1500));\n         ASSERT_NE(m_unit_queue.get(), nullptr);\n \n@@ -296,34 +296,6 @@ TEST_F(CRcvBufferReadMsg, PacketDropBySeqNo)\n     EXPECT_EQ(m_unit_queue->size(), m_unit_queue->capacity());\n }\n \n-// Drop ranges whose low seqno is already past the buffer end must be a\n-// no-op. Without the offset_a >= m_szSize guard, incPos() wraps modulo\n-// m_szSize and the loop walks legitimate entries -- mirroring the DoS\n-// shape of a reversed range, just triggered from the other side.\n-TEST_F(CRcvBufferReadMsg, PacketDropLoPastBufferEnd)\n-{\n-    EXPECT_EQ(addMessage(1, 1, m_init_seqno), 0);\n-    EXPECT_EQ(addMessage(1, 2, CSeqNo::incseq(m_init_seqno)), 0);\n-\n-    auto& rcv_buffer = *m_rcv_buffer.get();\n-    EXPECT_TRUE(hasAvailablePackets());\n-\n-    // Buffer size is m_buff_size_pkts (16); pick a range that begins\n-    // well past the last valid slot.\n-    const int32_t lo = m_init_seqno + 2 * m_buff_size_pkts;\n-    const int32_t hi = lo + 4;\n-    EXPECT_EQ(rcv_buffer.dropMessage(lo, hi, SRT_MSGNO_NONE, CRcvBuffer::DROP_EXISTING), 0);\n-\n-    // The two packets we inserted must still be present and readable.\n-    EXPECT_TRUE(hasAvailablePackets());\n-    EXPECT_TRUE(rcv_buffer.isRcvDataReady());\n-    array<char, m_payload_sz> buff;\n-    EXPECT_EQ(readMessage(buff.data(), buff.size()), (int) m_payload_sz);\n-    EXPECT_TRUE(verifyPayload(buff.data(), m_payload_sz, m_init_seqno));\n-    EXPECT_EQ(readMessage(buff.data(), buff.size()), (int) m_payload_sz);\n-    EXPECT_TRUE(verifyPayload(buff.data(), m_payload_sz, CSeqNo::incseq(m_init_seqno)));\n-}\n-\n // Test dropping a message by message number and sequence number.\n TEST_F(CRcvBufferReadMsg, PacketDropByMsgNoSeqNo)\n {\ndiff --git a/test/test_common.cpp b/test/test_common.cpp\nindex b4e150f..1a8cca0 100644\n--- a/test/test_common.cpp\n+++ b/test/test_common.cpp\n@@ -5,7 +5,6 @@\n #include \"test_env.h\"\n #include \"utilities.h\"\n #include \"common.h\"\n-#include \"core.h\"\n \n using namespace srt;\n \n@@ -72,47 +71,3 @@ TEST(CIPAddress, IPv4_in_IPv6_pton)\n \n     test_cipaddress_pton(peer_ip, AF_INET6, ip);\n }\n-\n-void testCookieContest(int32_t agent_cookie, int32_t peer_cookie)\n-{\n-    using namespace srt;\n-    using namespace std;\n-\n-    cout << \"TEST: Cookies: agent=\" << hex << agent_cookie\n-        << \" peer=\" << peer_cookie << endl << dec;\n-    HandshakeSide agent_side = CUDT::backwardCompatibleCookieContest(agent_cookie, peer_cookie);\n-    EXPECT_EQ(agent_side, HSD_INITIATOR);\n-    HandshakeSide peer_side =  CUDT::backwardCompatibleCookieContest(peer_cookie, agent_cookie);\n-    EXPECT_EQ(peer_side, HSD_RESPONDER);\n-}\n-\n-TEST(Common, CookieContest)\n-{\n-    srt::TestInit srtinit;\n-    using namespace std;\n-\n-    srt_setloglevel(LOG_NOTICE);\n-\n-    // In this function you should pass cookies always in the order: INITIATOR, RESPONDER.\n-    cout << \"TEST 1: two easy comparable values\\n\";\n-    testCookieContest(100, 50);\n-    testCookieContest(-1, -1000);\n-    testCookieContest(10055, -10000);\n-    testCookieContest(-1480577720, 811599203);\n-    testCookieContest( -2147483648, 2147483647);\n-    testCookieContest(0x00000001, 0x80000001);\n-\n-    /* XXX Blocked temporarily because in 1.5.5 they would fail,\n-       and it's decided to not provide the fix, which is too\n-       dangerous. The real fix will be provided in 1.6.0.\n-\n-    // Values from PR 1517\n-    cout << \"TEST 2: Values from PR 1517\\n\";\n-    testCookieContest(811599203, -1480577720);\n-    testCookieContest(2147483647, -2147483648);\n-\n-    cout << \"TEST 3: wrong post-fix\\n\";\n-    // NOTE: 0x80000001 is a negative number in hex\n-    testCookieContest(0x00000001, 0x80000001);\n-    */\n-}\ndiff --git a/test/test_connection_timeout.cpp b/test/test_connection_timeout.cpp\nindex 2c44baa..ec52d9d 100644\n--- a/test/test_connection_timeout.cpp\n+++ b/test/test_connection_timeout.cpp\n@@ -14,10 +14,9 @@ typedef int SOCKET;\n #include\"platform_sys.h\"\n #include \"srt.h\"\n #include \"netinet_any.h\"\n-#include \"common.h\"\n \n using namespace std;\n-using namespace srt_logging;\n+\n \n class TestConnectionTimeout\n     : public ::srt::Test\n@@ -171,29 +170,20 @@ TEST_F(TestConnectionTimeout, Nonblocking) {\n */\n TEST_F(TestConnectionTimeout, BlockingLoop)\n {\n-    const sockaddr* psa = reinterpret_cast<const sockaddr*>(&m_sa);\n+    const SRTSOCKET client_sock = srt_create_socket();\n+    ASSERT_GT(client_sock, 0);    // socket_id should be > 0\n+\n+    // Set connection timeout to 999 ms to reduce the test execution time.\n+    // Also need to hit a time point between two threads:\n+    // srt_connect will check TTL every second,\n+    // CRcvQueue::worker will wait on a socket for 10 ms.\n+    // Need to have a condition, when srt_connect will process the timeout.\n     const int connection_timeout_ms = 999;\n-    cout << \"[          ]\\r[\" << flush;\n+    EXPECT_EQ(srt_setsockopt(client_sock, 0, SRTO_CONNTIMEO, &connection_timeout_ms, sizeof connection_timeout_ms), SRT_SUCCESS);\n \n+    const sockaddr* psa = reinterpret_cast<const sockaddr*>(&m_sa);\n     for (int i = 0; i < 10; ++i)\n     {\n-        const SRTSOCKET client_sock = srt_create_socket();\n-        EXPECT_GT(client_sock, 0);    // socket_id should be > 0\n-        if (client_sock <= 0)\n-        {\n-            cout << \"!\\n\";\n-            break;\n-        }\n-\n-        cout << \".\" << flush;\n-\n-        // Set connection timeout to 999 ms to reduce the test execution time.\n-        // Also need to hit a time point between two threads:\n-        // srt_connect will check TTL every second,\n-        // CRcvQueue::worker will wait on a socket for 10 ms.\n-        // Need to have a condition, when srt_connect will process the timeout.\n-        EXPECT_EQ(srt_setsockopt(client_sock, 0, SRTO_CONNTIMEO, &connection_timeout_ms, sizeof connection_timeout_ms), SRT_SUCCESS);\n-\n         const chrono::steady_clock::time_point chrono_ts_start = chrono::steady_clock::now();\n         EXPECT_EQ(srt_connect(client_sock, psa, sizeof m_sa), SRT_ERROR);\n \n@@ -206,125 +196,15 @@ TEST_F(TestConnectionTimeout, BlockingLoop)\n         EXPECT_EQ(error_code, SRT_ENOSERVER);\n         if (error_code != SRT_ENOSERVER)\n         {\n-            cout << \"!\\nConnection attempt no. \" << i << \" resulted with: \"\n+            cerr << \"Connection attempt no. \" << i << \" resulted with: \"\n                 << error_code << \" \" << srt_getlasterror_str() << \"\\n\";\n             break;\n         }\n-\n-        EXPECT_EQ(srt_close(client_sock), SRT_SUCCESS);\n     }\n-    cout << endl;\n-}\n-\n-TEST_F(TestConnectionTimeout, BlockingInterrupted)\n-{\n-    const SRTSOCKET client_sock = srt_create_socket();\n-    EXPECT_GT(client_sock, 0);    // socket_id should be > 0\n \n-    const int connection_timeout_ms = 10000;\n-    EXPECT_EQ(srt_setsockopt(client_sock, 0, SRTO_CONNTIMEO, &connection_timeout_ms, sizeof connection_timeout_ms), SRT_SUCCESS);\n-\n-    using namespace std::chrono;\n-\n-    steady_clock::time_point begin = steady_clock::now();\n-\n-    std::thread interrupter ( [client_sock] () {\n-        cout << \"[T] START: Waiting 1s\\n\";\n-        std::this_thread::sleep_for(seconds(1));\n-        steady_clock::time_point b = steady_clock::now();\n-\n-        cout << \"[T] CLOSING @\" << client_sock << \"\\n\";\n-        srt_close(client_sock);\n-        steady_clock::time_point e = steady_clock::now();\n-        auto passed = duration_cast<milliseconds>(e - b);\n-        int close_time_passed_ms = passed.count();\n-        EXPECT_LT(close_time_passed_ms, 2000);\n-\n-        cout << \"[T] Thread exit\\n\";\n-    });\n-\n-    const sockaddr* psa = reinterpret_cast<const sockaddr*>(&m_sa);\n-    cout << \"START: Connect @\" << client_sock << \" blind\\n\";\n-    EXPECT_EQ(srt_connect(client_sock, psa, sizeof m_sa), SRT_ERROR);\n-    cout << \"STOP: Connect\\n\";\n-\n-    steady_clock::time_point end = steady_clock::now();\n-    auto passed = duration_cast<milliseconds>(end - begin);\n-    int time_passed_ms = passed.count();\n-    cout << \"Interrupted after \" << time_passed_ms << \"ms\\n\";\n-\n-    EXPECT_LT(time_passed_ms, 8000);\n-\n-    interrupter.join();\n+    EXPECT_EQ(srt_close(client_sock), SRT_SUCCESS);\n }\n \n-TEST_F(TestConnectionTimeout, NonblockingInterrupted)\n-{\n-    const SRTSOCKET client_sock = srt_create_socket();\n-    // const SRTSOCKET extra_sock = srt_create_socket();\n-    EXPECT_GT(client_sock, 0);    // socket_id should be > 0\n-\n-    const int connection_timeout_ms = 10000;\n-    EXPECT_EQ(srt_setsockopt(client_sock, 0, SRTO_CONNTIMEO, &connection_timeout_ms, sizeof connection_timeout_ms), SRT_SUCCESS);\n-\n-    const bool non_blocking = false;\n-    EXPECT_EQ(srt_setsockflag(client_sock, SRTO_RCVSYN, &non_blocking, sizeof non_blocking), SRT_SUCCESS);\n-    EXPECT_EQ(srt_setsockflag(client_sock, SRTO_SNDSYN, &non_blocking, sizeof non_blocking), SRT_SUCCESS);\n-\n-    using namespace std::chrono;\n-\n-    int eid = srt_epoll_create();\n-\n-    int conn_err = SRT_EPOLL_OUT | SRT_EPOLL_ERR;\n-\n-    srt_epoll_add_usock(eid, client_sock, &conn_err);\n-    // srt_epoll_add_usock(eid, extra_sock, &conn_err);\n-\n-    steady_clock::time_point begin = steady_clock::now();\n-\n-    std::thread interrupter ( [client_sock] () {\n-        cout << \"[T] START: Waiting 1s\\n\";\n-        std::this_thread::sleep_for(seconds(1));\n-        steady_clock::time_point b = steady_clock::now();\n-\n-        cout << \"[T] CLOSING @\" << client_sock << \"\\n\";\n-        srt_close(client_sock);\n-        steady_clock::time_point e = steady_clock::now();\n-        auto passed = duration_cast<milliseconds>(e - b);\n-        int close_time_passed_ms = passed.count();\n-        EXPECT_LT(close_time_passed_ms, 2000);\n-\n-        cout << \"[T] Thread exit\\n\";\n-    });\n-\n-    const sockaddr* psa = reinterpret_cast<const sockaddr*>(&m_sa);\n-    cout << \"START: Connect @\" << client_sock << \" blind\\n\";\n-\n-    // Result should be CONNREQ because this is non-blocking connect\n-    EXPECT_EQ(srt_connect(client_sock, psa, sizeof m_sa), 0);\n-\n-    cout << \"EPOLL - wait for connect\\n\";\n-\n-    // Expect uwait to return -1 because all sockets have been\n-    // removed from EID, so the call would block forever.\n-    SRT_EPOLL_EVENT fdset[2];\n-    EXPECT_EQ(srt_epoll_uwait(eid, fdset, 2, 3000), -1);\n-    SRT_SOCKSTATUS socket_status = srt_getsockstate(client_sock);\n-\n-    steady_clock::time_point end = steady_clock::now();\n-    auto passed = duration_cast<milliseconds>(end - begin);\n-    int time_passed_ms = passed.count();\n-    cout << \"Interrupted after \" << time_passed_ms << \"ms\\n\";\n-\n-    EXPECT_LT(time_passed_ms, 8000);\n-\n-    interrupter.join();\n-\n-    cout << \"SOCKET STATUS: \" << SockStatusStr(socket_status) << endl;\n-    EXPECT_GE(socket_status, SRTS_CLOSED);\n-\n-    // srt_close(extra_sock);\n-}\n \n TEST(TestConnectionAPI, Accept)\n {\n@@ -390,30 +270,4 @@ TEST(TestConnectionAPI, Accept)\n     srt_cleanup();\n }\n \n-TEST(TestConnectionAPI, Listen)\n-{\n-    using namespace std::chrono;\n-    using namespace srt;\n-    srt_startup();\n-\n-    SRTSOCKET s = srt_create_socket();\n-    int listen_stat1, listen_stat2, listen_stat3;\n-\n-    sockaddr_any sa = srt::CreateAddr(\"localhost\", 5555, AF_INET);\n-\n-    ASSERT_NE(srt_bind(s, sa.get(), sa.size()), -1);\n-    listen_stat1 = srt_listen(s, 1);\n-    listen_stat2 = srt_listen(s, 5);\n-    srt_close(s);\n-    listen_stat3 = srt_listen(s, 5);\n-\n-    int err = srt_getlasterror(NULL);\n-    std::cout << \"Listen after close error: \" << srt_strerror(err, 0) << std::endl;\n-\n-    EXPECT_EQ(listen_stat1, 0);\n-    EXPECT_EQ(listen_stat2, 0);\n-    EXPECT_EQ(listen_stat3, -1);\n-\n-    srt_cleanup();\n-}\n \ndiff --git a/test/test_control_packets.cpp b/test/test_control_packets.cpp\ndeleted file mode 100644\nindex c588b8a..0000000\n--- a/test/test_control_packets.cpp\n+++ /dev/null\n@@ -1,149 +0,0 @@\n-#include <thread>\n-\n-#include \"gtest/gtest.h\"\n-#include \"test_env.h\"\n-\n-#include \"srt.h\"\n-#include \"api.h\"\n-#include \"core.h\"\n-#include \"packet.h\"\n-\n-using namespace srt;\n-\n-namespace srt {\n-    // Friend wrapper for unit tests that drive private CUDT control-packet\n-    // entry points. Declared as a friend in core.h.\n-    class TestMockControlPackets\n-    {\n-    public:\n-        CUDT* core;\n-\n-        bool processCtrl(const CPacket& pkt) { return core->processCtrl(pkt); }\n-        void processCtrlLossReport(const CPacket& pkt) { core->processCtrlLossReport(pkt); }\n-        int32_t rcvCurrSeqNo() const { return core->m_iRcvCurrSeqNo; }\n-        void setRcvCurrSeqNo(int32_t v) { core->m_iRcvCurrSeqNo = v; }\n-        bool isBroken() const { return core->m_bBroken; }\n-    };\n-}\n-\n-class ControlPackets: public srt::Test\n-{\n-public:\n-    SRTSOCKET caller = SRT_INVALID_SOCK;\n-    SRTSOCKET listener = SRT_INVALID_SOCK;\n-    SRTSOCKET accepted = SRT_INVALID_SOCK;\n-    CUDTSocket* pcaller = NULL;\n-    TestMockControlPackets cmock;\n-\n-    static void swipe(SRTSOCKET& sockid)\n-    {\n-        if (sockid == SRT_INVALID_SOCK)\n-            return;\n-\n-        EXPECT_NE(srt_close(sockid), SRT_ERROR);\n-        sockid = SRT_INVALID_SOCK;\n-    }\n-\n-    void setup() override\n-    {\n-        caller = CUDT::uglobal().newSocket(&pcaller);\n-        ASSERT_NE(caller, SRT_INVALID_SOCK);\n-        cmock.core = &pcaller->core();\n-\n-        ASSERT_NE(listener = srt_create_socket(), SRT_INVALID_SOCK);\n-\n-        srt::sockaddr_any sa = srt::CreateAddr(\"localhost\", 5555, AF_INET);\n-        ASSERT_NE(srt_bind(listener, sa.get(), sa.size()), SRT_ERROR);\n-        ASSERT_NE(srt_listen(listener, 1), SRT_ERROR);\n-\n-        std::thread spawned_connect( [this, &sa] { EXPECT_NE(srt_connect(caller, sa.get(), sa.size()), SRT_ERROR); });\n-\n-        accepted = srt_accept(listener, NULL, 0);\n-        spawned_connect.join();\n-        ASSERT_NE(accepted, SRT_ERROR);\n-    }\n-\n-    void stop()\n-    {\n-        swipe(caller);\n-    }\n-\n-    void teardown() override\n-    {\n-        swipe(caller);\n-        swipe(accepted);\n-        swipe(listener);\n-    }\n-};\n-\n-// processCtrlDropReq must reject DROPREQs whose payload is smaller than two\n-// seqno words; otherwise dropdata[1] reads past the wire payload.\n-TEST_F(ControlPackets, DropReqRejectsShortPayload)\n-{\n-    const int32_t sentinel = 100;\n-    cmock.setRcvCurrSeqNo(sentinel);\n-\n-    CPacket pkt;\n-    pkt.allocate(1500);\n-    pkt.setControl(UMSG_DROPREQ);\n-\n-    // Each of these is shorter than the 8-byte minimum and must be rejected\n-    // by the guard at the top of processCtrlDropReq.\n-    const size_t short_lens[] = { 0, 1, 4, 7 };\n-    for (size_t i = 0; i < sizeof(short_lens) / sizeof(short_lens[0]); ++i)\n-    {\n-        pkt.setLength(short_lens[i]);\n-        EXPECT_FALSE(cmock.processCtrl(pkt));\n-        EXPECT_EQ(cmock.rcvCurrSeqNo(), sentinel)\n-            << \"DROPREQ with payload \" << short_lens[i] << \" bytes must not be processed\";\n-    }\n-}\n-\n-// processCtrlDropReq must reject DROPREQs whose (lo, hi) seqno range is\n-// reversed. Otherwise CRcvBuffer::dropMessage walks the circular buffer from\n-// offset(lo) past offset(hi)+1 via incPos() and wipes nearly every entry --\n-// a DoS primitive triggerable by a single malicious DROPREQ.\n-TEST_F(ControlPackets, DropReqRejectsReversedRange)\n-{\n-    const int32_t sentinel = 1000;\n-    cmock.setRcvCurrSeqNo(sentinel);\n-\n-    CPacket pkt;\n-    pkt.allocate(8);\n-    int32_t* data = (int32_t*) pkt.m_pcData;\n-    data[0] = 2000;  // lo\n-    data[1] = 1500;  // hi  (seqcmp(lo, hi) > 0)\n-    pkt.setLength(8);\n-    pkt.setControl(UMSG_DROPREQ);\n-\n-    // With the guard, this returns before touching m_pRcvBuffer (NULL on\n-    // an unconnected socket -- would crash if the guard were missing).\n-    EXPECT_FALSE(cmock.processCtrl(pkt));\n-\n-    EXPECT_EQ(cmock.rcvCurrSeqNo(), sentinel);\n-}\n-\n-// processCtrlLossReport must reject a LOSSREPORT whose final cell carries\n-// the LOSSDATA_SEQNO_RANGE_FIRST marker but has no HI cell behind it;\n-// otherwise losslist[i+1] reads past the wire payload (4-byte OOB read of\n-// adjacent heap). The handler should mark the connection broken via the\n-// `secure = false` path.\n-TEST_F(ControlPackets, LossReportRejectsTrailingRangeFirst)\n-{\n-    // Single 4-byte payload, high bit set => LOSSDATA_SEQNO_RANGE_FIRST.\n-    // Without the guard, the handler would dereference losslist[1] (the\n-    // missing HI cell), reading 4 bytes past the packet payload.\n-    CPacket pkt;\n-    pkt.allocate(64);\n-    int32_t* data = (int32_t*) pkt.m_pcData;\n-    data[0] = SEQNO_VALUE::wrap(100) | LOSSDATA_SEQNO_RANGE_FIRST;\n-    pkt.setLength(sizeof(int32_t));\n-    pkt.setControl(UMSG_LOSSREPORT);\n-\n-    EXPECT_FALSE(cmock.processCtrl(pkt));\n-\n-    EXPECT_TRUE(cmock.isBroken())\n-        << \"LOSSREPORT with trailing range-first marker must take the \"\n-           \"secure=false bail path and mark the connection broken\";\n-}\n-\ndiff --git a/test/test_crypto.cpp b/test/test_crypto.cpp\nindex d531303..47b18dd 100644\n--- a/test/test_crypto.cpp\n+++ b/test/test_crypto.cpp\n@@ -1,668 +1,110 @@\n #include <array>\n #include <numeric>\n-#include <vector>\n-#include <thread>\n-#include <mutex>\n \n #include \"gtest/gtest.h\"\n-#include \"test_env.h\"\n-\n-#ifdef SRT_ENABLE_ENCRYPTION\n-\n \n+#if defined(SRT_ENABLE_ENCRYPTION) && defined(ENABLE_AEAD_API_PREVIEW)\n #include \"crypto.h\"\n-#include \"handshake.h\"\n-#include \"hcrypt_msg.h\"\n #include \"hcrypt.h\" // Imports the CRYSPR_HAS_AESGCM definition.\n #include \"socketconfig.h\"\n-#include \"api.h\"\n-\n-// processSrtMsg_KMRSP must reject malformed wire-supplied lengths before they\n-// reach the fixed-size stack buffer / uninitialised-read paths inside the\n-// function. Built into the library unconditionally, so this test runs\n-// regardless of SRT_ENABLE_ENCRYPTION.\n-TEST(CryptoKMRSP, RejectsMalformedLengths)\n-{\n-    srt::CCryptoControl crypt(0);\n-    std::vector<uint32_t> garbage(SRT_CMD_MAXSZ, 0);\n-    const unsigned srtv = srt::SrtVersion(1, 5, 3);\n \n-    // Oversize: would overflow uint32_t srtd[SRTDATA_MAXSIZE].\n-    EXPECT_EQ(crypt.processSrtMsg_KMRSP(garbage.data(), SRT_CMD_MAXSZ + sizeof(uint32_t), srtv, false),\n-              srt::SRT_CMD_NONE);\n-    // Empty / under-a-word: HtoNLA writes nothing and downstream code would read\n-    // uninitialised stack from srtd[].\n-    EXPECT_EQ(crypt.processSrtMsg_KMRSP(garbage.data(), 0, srtv, false), srt::SRT_CMD_NONE);\n-}\n-\n-\n-#ifdef ENABLE_AEAD_API_PREVIEW\n-\n-class Crypto\n-    : public srt::Test\n+namespace srt\n {\n-protected:\n-    Crypto()\n-        : m_crypt(0)\n-    {\n-        // initialization code here\n-    }\n-\n-    virtual ~Crypto()\n-    {\n-        // cleanup any pending stuff, but no exceptions allowed\n-    }\n-\n-protected:\n-    void setup() override\n-    {\n-        using namespace srt;\n-\n-        CSrtConfig cfg;\n-\n-        memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-        cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-        cfg.CryptoSecret.len = (m_pwd.size() <= (int)sizeof(cfg.CryptoSecret.str) ? m_pwd.size() : (int)sizeof(cfg.CryptoSecret.str));\n-        memcpy((cfg.CryptoSecret.str), m_pwd.c_str(), m_pwd.size());\n \n-        m_crypt.setCryptoSecret(cfg.CryptoSecret);\n-\n-        // 2 = 128, 3 = 192, 4 = 256\n-        cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-        m_crypt.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-\n-        cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_GCM;\n-        EXPECT_TRUE(m_crypt.init(HSD_INITIATOR, cfg, true, HaiCrypt_IsAESGCM_Supported()));\n-\n-        const unsigned char* kmmsg = m_crypt.getKmMsg_data(0);\n-        const size_t km_len = m_crypt.getKmMsg_size(0);\n-        uint32_t kmout[72];\n-        size_t kmout_len = 72;\n-\n-        std::array<uint32_t, 72> km_nworder;\n-        NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-        m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3), kmout, kmout_len);\n-    }\n-\n-    void teardown() override\n+    class Crypto\n+        : public ::testing::Test\n     {\n-    }\n-\n-protected:\n-\n-    srt::CCryptoControl m_crypt;\n-    const std::string m_pwd = \"abcdefghijk\";\n-};\n-\n-\n-// Check that destroying the buffer also frees memory units.\n-TEST_F(Crypto, GCM)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    const size_t mtu_size = 1500;\n-    const size_t pld_size = 1316;\n-    const size_t tag_len  = 16;\n-\n-    CPacket pkt;\n-    pkt.allocate(mtu_size);\n-\n-    const int seqno = 1;\n-    const int msgno = 1;\n-    const int inorder = 1;\n-    const int kflg = m_crypt.getSndCryptoFlags();\n-\n-    pkt.set_seqno(seqno);\n-    pkt.set_msgflags(msgno | inorder | PacketBoundaryBits(PB_SOLO) | MSGNO_ENCKEYSPEC::wrap(kflg));\n-    pkt.set_timestamp(356);\n-\n-    std::iota(pkt.data(), pkt.data() + pld_size, '0');\n-    pkt.setLength(pld_size);\n-\n-    EXPECT_EQ(m_crypt.encrypt(pkt), ENCS_CLEAR);\n-    EXPECT_EQ(pkt.getLength(), pld_size + tag_len);\n-\n-    auto pkt_enc = std::unique_ptr<CPacket>(pkt.clone());\n-\n-    EXPECT_EQ(m_crypt.decrypt(pkt), ENCS_CLEAR);\n-    EXPECT_EQ(pkt.getLength(), pld_size);\n-\n-    // Modify the payload and expect auth to fail.\n-    pkt_enc->data()[10] = '5';\n-    EXPECT_EQ(m_crypt.decrypt(*pkt_enc.get()), ENCS_FAILED);\n-}\n-\n-// KMREQ that fails AES-KW unwrap must not downgrade a SECURED session.\n-TEST_F(Crypto, KMREQ_Unwrap_Failure_Does_Not_Downgrade_Secured)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    ASSERT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    // KMREQ wrapped with a different passphrase -> HAICRYPT_ERROR_WRONG_SECRET.\n-    CCryptoControl other(/*socket id*/1);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    const std::string other_pwd = \"completely_different_xy\";\n-    cfg.CryptoSecret.len = (int)other_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, other_pwd.c_str(), other_pwd.size());\n-    other.setCryptoSecret(cfg.CryptoSecret);\n-\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    other.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_GCM;\n-    ASSERT_TRUE(other.init(HSD_INITIATOR, cfg, true, HaiCrypt_IsAESGCM_Supported()));\n-\n-    const unsigned char* kmmsg = other.getKmMsg_data(0);\n-    const size_t km_len = other.getKmMsg_size(0);\n-    ASSERT_GT(km_len, 0u);\n-\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3),\n-                                kmout, kmout_len);\n-\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-}\n-\n-// Malformed KMREQ (too-small payload) on a SECURED session must not\n-// downgrade state.\n-TEST_F(Crypto, KMREQ_MalformedSize_Does_Not_Downgrade_Secured)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    ASSERT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    // Payload <= HCRYPT_MSG_KM_OFS_SALT trips the size sanity check.\n-    uint32_t tiny[2] = {0, 0};\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    EXPECT_EQ(m_crypt.processSrtMsg_KMREQ(tiny, sizeof(tiny),\n-                5, SrtVersion(1, 5, 3), kmout, kmout_len),\n-            SRT_CMD_NONE);\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-    EXPECT_EQ(kmout[SRT_KMR_KMSTATE], (uint32_t)SRT_KM_S_BADSECRET);\n-    EXPECT_EQ(kmout_len, 1u);\n-}\n-\n-// KMREQ with KLEN byte zeroed -> hcryptMsg_KM_GetSekLen returns 0,\n-// tripping the empty-SEK rejection. Must not downgrade SECURED state.\n-TEST_F(Crypto, KMREQ_EmptySEK_Does_Not_Downgrade_Secured)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    ASSERT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    // Take a structurally-valid KMREQ and zero the KLEN field.\n-    const unsigned char* kmmsg = m_crypt.getKmMsg_data(0);\n-    const size_t km_len = m_crypt.getKmMsg_size(0);\n-    std::array<unsigned char, HCRYPT_MSG_KM_MAX_SZ> patched;\n-    memcpy(patched.data(), kmmsg, km_len);\n-    patched[HCRYPT_MSG_KM_OFS_KLEN] = 0;\n-\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(patched.data()), km_len);\n-\n-    uint32_t kmout[72] = {0};\n-    size_t kmout_len = 72;\n-    EXPECT_EQ(m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len,\n-                5, SrtVersion(1, 5, 3), kmout, kmout_len),\n-            SRT_CMD_NONE);\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-    EXPECT_EQ(kmout[SRT_KMR_KMSTATE], (uint32_t)SRT_KM_S_BADSECRET);\n-    EXPECT_EQ(kmout_len, 1u);\n-}\n-\n-// Forged KMRSP claiming any peer-failure state must not downgrade a\n-// SECURED session. The dispatcher accepts KMRSPs unconditionally so each\n-// peerstate branch in processSrtMsg_KMRSP is reachable off-path.\n-TEST_F(Crypto, KMRSP_PeerFailure_Does_Not_Downgrade_Secured)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    const SRT_KM_STATE wire_peerstates[] = {\n-        SRT_KM_S_BADSECRET,\n-        SRT_KM_S_NOSECRET,\n-        SRT_KM_S_UNSECURED,\n-#ifdef ENABLE_AEAD_API_PREVIEW\n-        SRT_KM_S_BADCRYPTOMODE,\n-#endif\n-        // An out-of-enum value drives the default (\"IPE: unknown peer\n-        // error state\") branch in the switch.\n-        (SRT_KM_STATE)99,\n+    protected:\n+        Crypto()\n+            : m_crypt(0)\n+        {\n+            // initialization code here\n+        }\n+\n+        virtual ~Crypto()\n+        {\n+            // cleanup any pending stuff, but no exceptions allowed\n+        }\n+\n+    protected:\n+        // SetUp() is run immediately before a test starts.\n+        void SetUp() override\n+        {\n+            CSrtConfig cfg;\n+\n+            memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n+            cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n+            cfg.CryptoSecret.len = (m_pwd.size() <= (int)sizeof(cfg.CryptoSecret.str) ? m_pwd.size() : (int)sizeof(cfg.CryptoSecret.str));\n+            memcpy((cfg.CryptoSecret.str), m_pwd.c_str(), m_pwd.size());\n+\n+            m_crypt.setCryptoSecret(cfg.CryptoSecret);\n+\n+            // 2 = 128, 3 = 192, 4 = 256\n+            cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n+            m_crypt.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n+\n+            cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_GCM;\n+            EXPECT_TRUE(m_crypt.init(HSD_INITIATOR, cfg, true, HaiCrypt_IsAESGCM_Supported()));\n+\n+            const unsigned char* kmmsg = m_crypt.getKmMsg_data(0);\n+            const size_t km_len = m_crypt.getKmMsg_size(0);\n+            uint32_t kmout[72];\n+            size_t kmout_len = 72;\n+\n+            std::array<uint32_t, 72> km_nworder;\n+            NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n+            m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3), kmout, kmout_len);\n+        }\n+\n+        void TearDown() override\n+        {\n+        }\n+\n+    protected:\n+\n+        srt::CCryptoControl m_crypt;\n+        const std::string m_pwd = \"abcdefghijk\";\n     };\n \n-    for (size_t i = 0; i < sizeof(wire_peerstates)/sizeof(wire_peerstates[0]); ++i)\n-    {\n-        // Reset the agent into a fully-SECURED state for each iteration.\n-        m_crypt.m_RcvKmState = SRT_KM_S_SECURED;\n-        m_crypt.m_SndKmState = SRT_KM_S_SECURED;\n-\n-        // Wire format is network byte order; the function will HtoNLA it\n-        // back. Pre-NtoHLA so srtd[SRT_KMR_KMSTATE] inside the function\n-        // reads the intended peerstate.\n-        uint32_t wire = (uint32_t)wire_peerstates[i];\n-        uint32_t input = 0;\n-        NtoHLA(&input, &wire, 1);\n-\n-        // NOTE: We do not check the result here; success is only expected with\n-        // successful report.\n-        m_crypt.processSrtMsg_KMRSP(&input, sizeof(input), SrtVersion(1, 5, 3), false);\n-\n-        EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED)\n-            << \"peerstate=\" << (int)wire_peerstates[i] << \" downgraded m_RcvKmState\";\n-        EXPECT_EQ(m_crypt.m_SndKmState, SRT_KM_S_SECURED)\n-            << \"peerstate=\" << (int)wire_peerstates[i] << \" downgraded m_SndKmState\";\n-    }\n-}\n-\n-// After a forged KMREQ unwrap failure on a SECURED session, m_SndKmState\n-// must also stay SECURED so sendingAllowed() keeps returning true.\n-TEST_F(Crypto, KMREQ_Unwrap_Failure_Preserves_SndKmState_Secured)\n-{\n-    using namespace srt;\n-\n-    if (HaiCrypt_IsAESGCM_Supported() == 0)\n-        GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n-\n-    // setup() leaves m_SndKmState=SECURING. Simulate a fully-handshaken\n-    // session where the peer's KMRSP would have moved it to SECURED.\n-    m_crypt.m_SndKmState = SRT_KM_S_SECURED;\n-    ASSERT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-    ASSERT_EQ(m_crypt.m_SndKmState, SRT_KM_S_SECURED);\n-\n-    // Forge a KMREQ via a second CCryptoControl with a different passphrase.\n-    CCryptoControl other(/*socket id*/1);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    const std::string other_pwd = \"different_passphrase_xy\";\n-    cfg.CryptoSecret.len = (int)other_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, other_pwd.c_str(), other_pwd.size());\n-    other.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    other.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_GCM;\n-    ASSERT_TRUE(other.init(HSD_INITIATOR, cfg, true, HaiCrypt_IsAESGCM_Supported()));\n-\n-    const unsigned char* kmmsg = other.getKmMsg_data(0);\n-    const size_t km_len = other.getKmMsg_size(0);\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3),\n-                                kmout, kmout_len);\n-\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-    EXPECT_EQ(m_crypt.m_SndKmState, SRT_KM_S_SECURED);\n-}\n-\n-// Regression-test fixture that runs in default builds (CTR mode, no AEAD\n-// preview required). Mirrors the setup of the Crypto fixture above.\n-class CryptoCtr\n-: public srt::Test\n-{\n-protected:\n-    CryptoCtr() : m_crypt(0) {}\n-\n-    void setup() override\n-    {\n-        using namespace srt;\n-        CSrtConfig cfg;\n-        memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-        cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-        cfg.CryptoSecret.len = (m_pwd.size() <= (int)sizeof(cfg.CryptoSecret.str) ? m_pwd.size() : (int)sizeof(cfg.CryptoSecret.str));\n-        memcpy((cfg.CryptoSecret.str), m_pwd.c_str(), m_pwd.size());\n-\n-        m_crypt.setCryptoSecret(cfg.CryptoSecret);\n-        cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-        m_crypt.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-        cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-        EXPECT_TRUE(m_crypt.init(HSD_INITIATOR, cfg, true, false));\n-\n-        const unsigned char* kmmsg = m_crypt.getKmMsg_data(0);\n-        const size_t km_len = m_crypt.getKmMsg_size(0);\n-        uint32_t kmout[72];\n-        size_t kmout_len = 72;\n-\n-        std::array<uint32_t, 72> km_nworder;\n-        NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-        m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3), kmout, kmout_len);\n-    }\n \n-    void teardown() override\n+    // Check that destroying the buffer also frees memory units.\n+    TEST_F(Crypto, GCM)\n     {\n-    }\n-\n-protected:\n-    srt::CCryptoControl m_crypt;\n-    const std::string m_pwd = \"abcdefghijk\";\n-};\n-\n-// Regression test: validates that the legitimate SECURING -> SECURED\n-// transition still happens on a valid KMREQ. Catches a future over-\n-// applied SECURED-preserving guard that would block this path.\n-TEST_F(CryptoCtr, InitialHandshakeReachesSecured)\n-{\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n-}\n-\n-// Regression test: from the SECURING initial state, a KMREQ wrapped with\n-// the wrong passphrase must still drive m_RcvKmState to BADSECRET. The\n-// SECURED-preserving guard must not block the initial transition.\n-TEST_F(CryptoCtr, WrongPassphraseAtInitialReachesBadSecret)\n-{\n-    using namespace srt;\n-\n-    // Build a fresh crypter that has NOT been driven through setup's\n-    // bootstrap KMREQ, so m_RcvKmState is still SECURING.\n-    CCryptoControl fresh(/*socket id*/2);\n-    CSrtConfig fresh_cfg;\n-    memset(&fresh_cfg.CryptoSecret, 0, sizeof(fresh_cfg.CryptoSecret));\n-    fresh_cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    fresh_cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(fresh_cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    fresh.setCryptoSecret(fresh_cfg.CryptoSecret);\n-    fresh_cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    fresh.setCryptoKeylen(fresh_cfg.iSndCryptoKeyLen);\n-    fresh_cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(fresh.init(HSD_INITIATOR, fresh_cfg, true, false));\n-    ASSERT_NE(fresh.m_RcvKmState, SRT_KM_S_SECURED);\n+        if (HaiCrypt_IsAESGCM_Supported() == 0)\n+            GTEST_SKIP() << \"The crypto service provider does not support AES GCM.\";\n \n-    // Forge a KMREQ from a peer using a different passphrase.\n-    CCryptoControl other(/*socket id*/3);\n-    CSrtConfig other_cfg;\n-    memset(&other_cfg.CryptoSecret, 0, sizeof(other_cfg.CryptoSecret));\n-    other_cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    const std::string other_pwd = \"wrong_passphrase_xy\";\n-    other_cfg.CryptoSecret.len = (int)other_pwd.size();\n-    memcpy(other_cfg.CryptoSecret.str, other_pwd.c_str(), other_pwd.size());\n-    other.setCryptoSecret(other_cfg.CryptoSecret);\n-    other_cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    other.setCryptoKeylen(other_cfg.iSndCryptoKeyLen);\n-    other_cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(other.init(HSD_INITIATOR, other_cfg, true, false));\n+        const size_t mtu_size = 1500;\n+        const size_t pld_size = 1316;\n+        const size_t tag_len  = 16;\n \n-    const unsigned char* kmmsg = other.getKmMsg_data(0);\n-    const size_t km_len = other.getKmMsg_size(0);\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n+        CPacket pkt;\n+        pkt.allocate(mtu_size);\n \n-    const SRT_KM_STATE prev_state = fresh.m_RcvKmState;\n-\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    int cmd = fresh.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3),\n-            kmout, kmout_len);\n-\n-    // The guard must NOT block this transition: from SECURING the state\n-    // must reach BADSECRET so the connection can be rejected.\n-    // XXX NOTE: The behavior has been changed and now KMREQ failure is\n-    // simply ignored, if it was done as update. And as we create the\n-    // crypto with init, this is initialized just like through handshake,\n-    // so this KMREQ is considered a KMX update. We have then the right\n-    // state in the output array, but the state remains secure.\n-    EXPECT_EQ(fresh.m_RcvKmState, prev_state);\n-    EXPECT_EQ(cmd, SRT_CMD_NONE);\n-    EXPECT_EQ(kmout[0], SRT_KM_S_BADSECRET);\n-}\n-\n-// Regression test: a fresh KMREQ wrapped with the SAME passphrase\n-// (i.e. legitimate key rotation) on an already-SECURED session must\n-// succeed. State stays SECURED and the KMRSP returned is a full success\n-// response, not a 1-word error.\n-//\n-// This is the highest-risk regression vector for the SECURED-preserving\n-// guards: if they accidentally over-applied to the success path, key\n-// rotation would silently fail and streams would eventually drop.\n-TEST_F(CryptoCtr, KmRefreshOnSecuredSucceeds)\n-{\n-    using namespace srt;\n+        const int seqno = 1;\n+        const int msgno = 1;\n+        const int inorder = 1;\n+        const int kflg = m_crypt.getSndCryptoFlags();\n \n-    ASSERT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n+        pkt.set_seqno(seqno);\n+        pkt.set_msgflags(msgno | inorder | PacketBoundaryBits(PB_SOLO) | MSGNO_ENCKEYSPEC::wrap(kflg));\n+        pkt.set_timestamp(356);\n \n-    // Build a fresh sender with the SAME passphrase. Its generated KM\n-    // message will carry a different SEK but the same KEK as m_crypt,\n-    // so the unwrap will succeed on m_crypt's side. This mirrors what\n-    // happens when the live sender's regenCryptoKm rolls a new key.\n-    CCryptoControl rotator(/*socket id*/4);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    rotator.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    rotator.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(rotator.init(HSD_INITIATOR, cfg, true, false));\n+        std::iota(pkt.data(), pkt.data() + pld_size, '0');\n+        pkt.setLength(pld_size);\n \n-    const unsigned char* kmmsg = rotator.getKmMsg_data(0);\n-    const size_t km_len = rotator.getKmMsg_size(0);\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n+        EXPECT_EQ(m_crypt.encrypt(pkt), ENCS_CLEAR);\n+        EXPECT_EQ(pkt.getLength(), pld_size + tag_len);\n \n-    uint32_t kmout[72] = {0};\n-    size_t kmout_len = 72;\n-    m_crypt.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5, SrtVersion(1, 5, 3),\n-            kmout, kmout_len);\n+        auto pkt_enc = std::unique_ptr<CPacket>(pkt.clone());\n \n-    // State remains SECURED across the rotation.\n-    EXPECT_EQ(m_crypt.m_RcvKmState, SRT_KM_S_SECURED);\n+        EXPECT_EQ(m_crypt.decrypt(pkt), ENCS_CLEAR);\n+        EXPECT_EQ(pkt.getLength(), pld_size);\n \n-    // The success KMRSP echoes the input KM message (multi-word). A\n-    // rejection path would have set kmout_len == 1 and written a single\n-    // SRT_KMR_KMSTATE word.\n-    EXPECT_GT(kmout_len, 1u);\n-}\n-\n-// Regression test: a RESPONDER-side bidirectional handshake must reach\n-// SECURED on BOTH directions via the RX -> TX context clone path in\n-// processSrtMsg_KMREQ. This is the most complex success transition in\n-// the handler and is unguarded by design (gated by m_SndKmState ==\n-// SECURING && !m_hSndCrypto).\n-TEST_F(CryptoCtr, ResponderHandshakeReachesSecuredViaClone)\n-{\n-    using namespace srt;\n-\n-    // RESPONDER doesn't create m_hSndCrypto in init(), so the\n-    // SECURING + !m_hSndCrypto precondition for the clone block holds.\n-    CCryptoControl responder(/*socket id*/8);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    responder.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    responder.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(responder.init(HSD_RESPONDER, cfg, true, false));\n-\n-    // Use the fixture's own (INITIATOR-side) KM message as the KMREQ\n-    // payload for the responder. Same passphrase, so unwrap succeeds.\n-    const unsigned char* kmmsg = m_crypt.getKmMsg_data(0);\n-    const size_t km_len = m_crypt.getKmMsg_size(0);\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    responder.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5,\n-            SrtVersion(1, 5, 3), kmout, kmout_len);\n-\n-    EXPECT_EQ(responder.m_RcvKmState, SRT_KM_S_SECURED);\n-    EXPECT_EQ(responder.m_SndKmState, SRT_KM_S_SECURED);\n-}\n-\n-// Regression test: when the agent has no passphrase but the peer sends\n-// a valid KMREQ, m_RcvKmState must transition UNSECURED -> NOSECRET. The\n-// SECURED-preserving guard must not block this legitimate non-SECURED\n-// transition.\n-TEST_F(CryptoCtr, AgentWithoutPasswordGetsNoSecret)\n-{\n-    using namespace srt;\n-\n-    // Agent with no passphrase. init() leaves both states at UNSECURED.\n-    CCryptoControl no_pw_agent(/*socket id*/5);\n-    CSrtConfig agent_cfg;\n-    memset(&agent_cfg.CryptoSecret, 0, sizeof(agent_cfg.CryptoSecret));\n-    // typ left as 0 / len 0 -> hasPassphrase() returns false.\n-    no_pw_agent.setCryptoSecret(agent_cfg.CryptoSecret);\n-    agent_cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    no_pw_agent.setCryptoKeylen(agent_cfg.iSndCryptoKeyLen);\n-    agent_cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(no_pw_agent.init(HSD_INITIATOR, agent_cfg, true, false));\n-    ASSERT_NE(no_pw_agent.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    // Peer with a valid passphrase sends KMREQ.\n-    CCryptoControl peer(/*socket id*/6);\n-    CSrtConfig peer_cfg;\n-    memset(&peer_cfg.CryptoSecret, 0, sizeof(peer_cfg.CryptoSecret));\n-    peer_cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    peer_cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(peer_cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    peer.setCryptoSecret(peer_cfg.CryptoSecret);\n-    peer_cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    peer.setCryptoKeylen(peer_cfg.iSndCryptoKeyLen);\n-    peer_cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(peer.init(HSD_INITIATOR, peer_cfg, true, false));\n-\n-    const unsigned char* kmmsg = peer.getKmMsg_data(0);\n-    const size_t km_len = peer.getKmMsg_size(0);\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-\n-    uint32_t kmout[72];\n-    size_t kmout_len = 72;\n-    no_pw_agent.processSrtMsg_KMREQ(km_nworder.data(), km_len, 5,\n-            SrtVersion(1, 5, 3), kmout, kmout_len);\n-\n-    EXPECT_EQ(no_pw_agent.m_RcvKmState, SRT_KM_S_NOSECRET);\n-}\n-\n-// Regression test: receiving a KMRSP error report on a non-SECURED\n-// session must still update state per the peer's report. The SECURED-\n-// preserving guard must not block this.\n-TEST_F(CryptoCtr, KmrspPeerNoSecretOnNonSecured)\n-{\n-    using namespace srt;\n-\n-    // Fresh crypter with passphrase but no bootstrap KMREQ processed.\n-    CCryptoControl fresh(/*socket id*/7);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    fresh.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    fresh.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(fresh.init(HSD_INITIATOR, cfg, true, false));\n-    ASSERT_NE(fresh.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    // KMRSP carrying a single peerstate word = NOSECRET (peer has no PW).\n-    uint32_t wire = (uint32_t)SRT_KM_S_NOSECRET;\n-    uint32_t input = 0;\n-    NtoHLA(&input, &wire, 1);\n-    fresh.processSrtMsg_KMRSP(&input, sizeof(input), SrtVersion(1, 5, 3), true);\n-\n-    // Per crypto.cpp KMRSP NOSECRET branch: RX -> UNSECURED, SND -> NOSECRET.\n-    EXPECT_EQ(fresh.m_RcvKmState, SRT_KM_S_UNSECURED);\n-    EXPECT_EQ(fresh.m_SndKmState, SRT_KM_S_NOSECRET);\n-}\n-\n-// Regression test: a successful KMRSP (a KMRSP whose multi-word body\n-// matches a stored sender KM message) must transition both m_RcvKmState\n-// and m_SndKmState to SECURED via the success branch in\n-// processSrtMsg_KMRSP. Mirror of the KMREQ success path.\n-TEST_F(CryptoCtr, KmrspSuccessTransitionsToSecured)\n-{\n-    using namespace srt;\n-\n-    // Fresh initiator with a passphrase and the standard SND KM message\n-    // built by init(), but without the bootstrap KMREQ that setup ran on\n-    // m_crypt. m_SndKmState should be SECURING here.\n-    CCryptoControl fresh(/*socket id*/9);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    fresh.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    fresh.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(fresh.init(HSD_INITIATOR, cfg, true, false));\n-    ASSERT_NE(fresh.m_SndKmState, SRT_KM_S_SECURED);\n-\n-    // A successful KMRSP carries back the same KM payload the agent had\n-    // sent. Feed the agent's own stored KM message back as the KMRSP body.\n-    const unsigned char* kmmsg = fresh.getKmMsg_data(0);\n-    const size_t km_len = fresh.getKmMsg_size(0);\n-    ASSERT_GT(km_len, 0u);\n-\n-    std::array<uint32_t, 72> km_nworder;\n-    NtoHLA(km_nworder.data(), reinterpret_cast<const uint32_t*>(kmmsg), km_len);\n-\n-    fresh.processSrtMsg_KMRSP(km_nworder.data(), km_len, SrtVersion(1, 5, 3), true);\n-\n-    EXPECT_EQ(fresh.m_RcvKmState, SRT_KM_S_SECURED);\n-    EXPECT_EQ(fresh.m_SndKmState, SRT_KM_S_SECURED);\n-}\n-\n-// Regression test: KMRSP carrying the UNSECURED peer-error code on a\n-// non-SECURED session must transition RX -> NOSECRET, SND -> UNSECURED.\n-// Mirror of the NOSECRET branch but with the opposite target mapping.\n-TEST_F(CryptoCtr, KmrspPeerUnsecuredOnNonSecured)\n-{\n-    using namespace srt;\n-\n-    CCryptoControl fresh(/*socket id*/10);\n-    CSrtConfig cfg;\n-    memset(&cfg.CryptoSecret, 0, sizeof(cfg.CryptoSecret));\n-    cfg.CryptoSecret.typ = HAICRYPT_SECTYP_PASSPHRASE;\n-    cfg.CryptoSecret.len = (int)m_pwd.size();\n-    memcpy(cfg.CryptoSecret.str, m_pwd.c_str(), m_pwd.size());\n-    fresh.setCryptoSecret(cfg.CryptoSecret);\n-    cfg.iSndCryptoKeyLen = SrtHSRequest::SRT_PBKEYLEN_BITS::wrap(4);\n-    fresh.setCryptoKeylen(cfg.iSndCryptoKeyLen);\n-    cfg.iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;\n-    ASSERT_TRUE(fresh.init(HSD_INITIATOR, cfg, true, false));\n-    ASSERT_NE(fresh.m_RcvKmState, SRT_KM_S_SECURED);\n-\n-    uint32_t wire = (uint32_t)SRT_KM_S_UNSECURED;\n-    uint32_t input = 0;\n-    NtoHLA(&input, &wire, 1);\n-    fresh.processSrtMsg_KMRSP(&input, sizeof(input), SrtVersion(1, 5, 3), true);\n-\n-    // Per crypto.cpp KMRSP UNSECURED branch: RX -> NOSECRET, SND -> UNSECURED.\n-    EXPECT_EQ(fresh.m_RcvKmState, SRT_KM_S_NOSECRET);\n-    EXPECT_EQ(fresh.m_SndKmState, SRT_KM_S_UNSECURED);\n-}\n+        // Modify the payload and expect auth to fail.\n+        pkt_enc->data()[10] = '5';\n+        EXPECT_EQ(m_crypt.decrypt(*pkt_enc.get()), ENCS_FAILED);\n+    }\n \n-#endif // AEAD\n+} // namespace srt\n \n-#endif //SRT_ENABLE_ENCRYPTION\n+#endif //SRT_ENABLE_ENCRYPTION && ENABLE_AEAD_API_PREVIEW\ndiff --git a/test/test_enforced_encryption.cpp b/test/test_enforced_encryption.cpp\nindex b3807ff..717b454 100644\n--- a/test/test_enforced_encryption.cpp\n+++ b/test/test_enforced_encryption.cpp\n@@ -59,10 +59,10 @@ enum TEST_CASE\n     TEST_CASE_D_3,\n     TEST_CASE_D_4,\n     TEST_CASE_D_5,\n-    TEST_CASE_COUNT\n };\n \n-struct Expect\n+\n+struct TestResultNonBlocking\n {\n     int     connect_ret;\n     int     accept_ret;\n@@ -72,18 +72,26 @@ struct Expect\n     int     km_state    [CHECK_SOCKET_COUNT];\n };\n \n-template<bool BLOCKING>\n-struct TestCase\n+\n+struct TestResultBlocking\n {\n-    static const bool blocking = BLOCKING;\n+    int     connect_ret;\n+    int     accept_ret;\n+    int     socket_state[CHECK_SOCKET_COUNT];\n+    int     km_state[CHECK_SOCKET_COUNT];\n+};\n+\n \n+template<typename TResult>\n+struct TestCase\n+{\n     bool                enforcedenc [PEER_COUNT];\n     const std::string  (&password)[PEER_COUNT];\n-    Expect expected_result;\n+    TResult             expected_result;\n };\n \n-typedef TestCase<false> TestCaseNonBlocking;\n-typedef TestCase<true> TestCaseBlocking;\n+typedef TestCase<TestResultNonBlocking>  TestCaseNonBlocking;\n+typedef TestCase<TestResultBlocking>     TestCaseBlocking;\n \n \n \n@@ -131,10 +139,10 @@ static const std::string s_pwd_no(\"\");\n const int IGNORE_EPOLL = -2;\n const int IGNORE_SRTS = -1;\n \n-const TestCaseNonBlocking g_test_matrix_non_blocking[TEST_CASE_COUNT] =\n+const TestCaseNonBlocking g_test_matrix_non_blocking[] =\n {\n-        // ENFORCEDENC       |  Password            |                              | EPoll wait                       | socket_state                            |  KM State\n-        // caller | listener |  caller  | listener  |  connect_ret   accept_ret    |  ret         | event             | caller              accepted |  caller              listener\n+        // ENFORCEDENC       |  Password           |                                | EPoll wait                       | socket_state                            |  KM State\n+        // caller | listener |  caller  | listener |  connect_ret   accept_ret      |  ret         | event             | caller              accepted |  caller              listener\n /*A.1 */ { {true,     true  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                0,             1,  SRT_EPOLL_IN,  {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n /*A.2 */ { {true,     true  }, {s_pwd_a,   s_pwd_b}, { SRT_SUCCESS, SRT_INVALID_SOCK,             0,  0,             {SRTS_BROKEN,       IGNORE_SRTS}, {SRT_KM_S_UNSECURED,        IGNORE_SRTS}}},\n /*A.3 */ { {true,     true  }, {s_pwd_a,  s_pwd_no}, { SRT_SUCCESS, SRT_INVALID_SOCK,             0,  0,             {SRTS_BROKEN,       IGNORE_SRTS}, {SRT_KM_S_UNSECURED,        IGNORE_SRTS}}},\n@@ -175,33 +183,33 @@ const TestCaseNonBlocking g_test_matrix_non_blocking[TEST_CASE_COUNT] =\n  *\n  * In the cases C.2-C.4 it is the listener who rejects the connection, so we don't have an accepted socket.\n  */\n-const TestCaseBlocking g_test_matrix_blocking[TEST_CASE_COUNT] =\n+const TestCaseBlocking g_test_matrix_blocking[] =\n {\n-        // ENFORCEDENC       |  Password           |                                      | Epoll wait (ignored)       | socket_state                   |  KM State\n-        // caller | listener |  caller  | listener |  connect_ret         accept_ret      |  ret       |   event       | caller                accepted |  caller              listener\n-/*A.1 */ { {true,     true  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n-/*A.2 */ { {true,     true  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*A.3 */ { {true,     true  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*A.4 */ { {true,     true  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*A.5 */ { {true,     true  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n-\n-/*B.1 */ { {true,    false  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n-/*B.2 */ { {true,    false  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK,               -2, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_BADSECRET, SRT_KM_S_BADSECRET}}},\n-/*B.3 */ { {true,    false  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK,               -2, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n-/*B.4 */ { {true,    false  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK,               -2, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_UNSECURED,  SRT_KM_S_NOSECRET}}},\n-/*B.5 */ { {true,    false  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n-\n-/*C.1 */ { {false,    true  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n-/*C.2 */ { {false,    true  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*C.3 */ { {false,    true  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*C.4 */ { {false,    true  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n-/*C.5 */ { {false,    true  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n-\n-/*D.1 */ { {false,   false  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n-/*D.2 */ { {false,   false  }, {s_pwd_a,   s_pwd_b}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_BADSECRET, SRT_KM_S_BADSECRET}}},\n-/*D.3 */ { {false,   false  }, {s_pwd_a,  s_pwd_no}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n-/*D.4 */ { {false,   false  }, {s_pwd_no,  s_pwd_b}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_NOSECRET,   SRT_KM_S_NOSECRET}}},\n-/*D.5 */ { {false,   false  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, IGNORE_EPOLL, SRT_EPOLL_IN, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+        // ENFORCEDENC       |  Password           |                                      | socket_state                   |  KM State\n+        // caller | listener |  caller  | listener |  connect_ret         accept_ret      | caller                accepted |  caller              listener\n+/*A.1 */ { {true,     true  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n+/*A.2 */ { {true,     true  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*A.3 */ { {true,     true  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*A.4 */ { {true,     true  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*A.5 */ { {true,     true  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+\n+/*B.1 */ { {true,    false  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n+/*B.2 */ { {true,    false  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK,               -2, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_BADSECRET, SRT_KM_S_BADSECRET}}},\n+/*B.3 */ { {true,    false  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK,               -2, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+/*B.4 */ { {true,    false  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK,               -2, {SRTS_OPENED,       SRTS_BROKEN}, {SRT_KM_S_UNSECURED,  SRT_KM_S_NOSECRET}}},\n+/*B.5 */ { {true,    false  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+\n+/*C.1 */ { {false,    true  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n+/*C.2 */ { {false,    true  }, {s_pwd_a,   s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*C.3 */ { {false,    true  }, {s_pwd_a,  s_pwd_no}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*C.4 */ { {false,    true  }, {s_pwd_no,  s_pwd_b}, { SRT_INVALID_SOCK, SRT_INVALID_SOCK, {SRTS_OPENED,                -1}, {SRT_KM_S_UNSECURED,                 -1}}},\n+/*C.5 */ { {false,    true  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+\n+/*D.1 */ { {false,   false  }, {s_pwd_a,   s_pwd_a}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_SECURED,     SRT_KM_S_SECURED}}},\n+/*D.2 */ { {false,   false  }, {s_pwd_a,   s_pwd_b}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_BADSECRET, SRT_KM_S_BADSECRET}}},\n+/*D.3 */ { {false,   false  }, {s_pwd_a,  s_pwd_no}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n+/*D.4 */ { {false,   false  }, {s_pwd_no,  s_pwd_b}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_NOSECRET,   SRT_KM_S_NOSECRET}}},\n+/*D.5 */ { {false,   false  }, {s_pwd_no, s_pwd_no}, { SRT_SUCCESS,                     0, {SRTS_CONNECTED, SRTS_CONNECTED}, {SRT_KM_S_UNSECURED, SRT_KM_S_UNSECURED}}},\n };\n \n \n@@ -313,13 +321,14 @@ public:\n     int WaitOnEpoll(const TResult &expect);\n \n \n-    template<typename TCase>\n-    const TCase& GetTestMatrix(TEST_CASE test_case) const;\n+    template<typename TResult>\n+    const TestCase<TResult>& GetTestMatrix(TEST_CASE test_case) const;\n \n-    template<typename TCase>\n+    template<typename TResult>\n     void TestConnect(TEST_CASE test_case/*, bool is_blocking*/)\n     {\n-        if (TCase::blocking)\n+        const bool is_blocking = std::is_same<TResult, TestResultBlocking>::value;\n+        if (is_blocking)\n         {\n             ASSERT_NE(srt_setsockopt(  m_caller_socket, 0, SRTO_RCVSYN, &s_yes, sizeof s_yes), SRT_ERROR);\n             ASSERT_NE(srt_setsockopt(  m_caller_socket, 0, SRTO_SNDSYN, &s_yes, sizeof s_yes), SRT_ERROR);\n@@ -335,7 +344,7 @@ public:\n         }\n \n         // Prepare input state\n-        const auto& test = GetTestMatrix<TCase>(test_case);\n+        const TestCase<TResult> &test = GetTestMatrix<TResult>(test_case);\n         ASSERT_EQ(SetEnforcedEncryption(PEER_CALLER, test.enforcedenc[PEER_CALLER]), SRT_SUCCESS);\n         ASSERT_EQ(SetEnforcedEncryption(PEER_LISTENER, test.enforcedenc[PEER_LISTENER]), SRT_SUCCESS);\n \n@@ -347,7 +356,7 @@ public:\n         const bool case_both_relaxed = !test.enforcedenc[PEER_LISTENER] && !test.enforcedenc[PEER_CALLER];\n         const bool case_sender_enc = test.password[PEER_CALLER] != \"\";\n \n-        const auto& expect = test.expected_result;\n+        const TResult &expect = test.expected_result;\n \n         // Start testing\n         srt::sync::atomic<bool> caller_done;\n@@ -363,7 +372,7 @@ public:\n         SRTSOCKET accepted_socket = -1;\n \n         auto accepting_thread = std::thread([&] {\n-            const int epoll_event = WaitOnEpoll(test);\n+            const int epoll_event = WaitOnEpoll(expect);\n \n             // In a blocking mode we expect a socket returned from srt_accept() if the srt_connect succeeded.\n             // In a non-blocking mode we expect a socket returned from srt_accept() if the srt_connect succeeded,\n@@ -451,7 +460,7 @@ public:\n \n         caller_done = true;\n \n-        if (TCase::blocking == false)\n+        if (is_blocking == false)\n             accepting_thread.join();\n \n         if (m_is_tracing)\n@@ -466,7 +475,7 @@ public:\n \n         // If a blocking call to srt_connect() returned error, then the state is not valid,\n         // but we still check it because we know what it should be. This way we may see potential changes in the core behavior.\n-        if (TCase::blocking)\n+        if (is_blocking)\n         {\n             EXPECT_EQ(srt_getsockstate(m_caller_socket), expect.socket_state[CHECK_SOCKET_CALLER]);\n         }\n@@ -487,7 +496,7 @@ public:\n         EXPECT_EQ(srt_getsockstate(m_listener_socket), SRTS_LISTENING);\n         EXPECT_EQ(GetKMState(m_listener_socket), SRT_KM_S_UNSECURED);\n \n-        if (!TCase::blocking && case_both_relaxed && case_pw_failure && case_sender_enc)\n+        if (!is_blocking && case_both_relaxed && case_pw_failure && case_sender_enc)\n         {\n             // Additionally check decryption failure does not trigger read-readiness (see issue #2503).\n \n@@ -534,7 +543,7 @@ public:\n             srt_epoll_release(epollRead);\n         }\n \n-        if (TCase::blocking)\n+        if (is_blocking)\n         {\n             // srt_accept() has no timeout, so we have to close the socket and wait for the thread to exit.\n             // Just give it some time and close the socket.\n@@ -565,7 +574,7 @@ private:\n \n \n template<>\n-int TestEnforcedEncryption::WaitOnEpoll<TestCaseBlocking>(const TestCaseBlocking &)\n+int TestEnforcedEncryption::WaitOnEpoll<TestResultBlocking>(const TestResultBlocking &)\n {\n     return SRT_EPOLL_IN;\n }\n@@ -598,9 +607,8 @@ static std::ostream& PrintEpollEvent(std::ostream& os, int events, int et_events\n }\n \n template<>\n-int TestEnforcedEncryption::WaitOnEpoll<TestCaseNonBlocking>(const TestCaseNonBlocking &tcase)\n+int TestEnforcedEncryption::WaitOnEpoll<TestResultNonBlocking>(const TestResultNonBlocking &expect)\n {\n-    const auto& expect = tcase.expected_result;\n     const int default_len = 3;\n     SRT_EPOLL_EVENT ready[default_len];\n     const int epoll_res = srt_epoll_uwait(m_pollid, ready, default_len, 500);\n@@ -641,13 +649,13 @@ int TestEnforcedEncryption::WaitOnEpoll<TestCaseNonBlocking>(const TestCaseNonBl\n \n \n template<>\n-const TestCaseBlocking& TestEnforcedEncryption::GetTestMatrix<TestCaseBlocking>(TEST_CASE test_case) const\n+const TestCase<TestResultBlocking>& TestEnforcedEncryption::GetTestMatrix<TestResultBlocking>(TEST_CASE test_case) const\n {\n     return g_test_matrix_blocking[test_case];\n }\n \n template<>\n-const TestCaseNonBlocking& TestEnforcedEncryption::GetTestMatrix<TestCaseNonBlocking>(TEST_CASE test_case) const\n+const TestCase<TestResultNonBlocking>& TestEnforcedEncryption::GetTestMatrix<TestResultNonBlocking>(TEST_CASE test_case) const\n {\n     return g_test_matrix_non_blocking[test_case];\n }\n@@ -732,14 +740,20 @@ TEST_F(TestEnforcedEncryption, SetGetDefault)\n }\n \n \n-#define CREATE_TEST_C(IFBLOCKING, CASE_NUMBER, DESC) TEST_F(TestEnforcedEncryption, CASE_NUMBER##_##IFBLOCKING##_##DESC)\\\n+#define CREATE_TEST_CASE_BLOCKING(CASE_NUMBER, DESC) TEST_F(TestEnforcedEncryption, CASE_NUMBER##_Blocking_##DESC)\\\n {\\\n-    TestConnect<TestCase##IFBLOCKING>(TEST_##CASE_NUMBER);\\\n+    TestConnect<TestResultBlocking>(TEST_##CASE_NUMBER);\\\n }\n \n+#define CREATE_TEST_CASE_NONBLOCKING(CASE_NUMBER, DESC) TEST_F(TestEnforcedEncryption, CASE_NUMBER##_NonBlocking_##DESC)\\\n+{\\\n+    TestConnect<TestResultNonBlocking>(TEST_##CASE_NUMBER);\\\n+}\n+\n+\n #define CREATE_TEST_CASES(CASE_NUMBER, DESC) \\\n-    CREATE_TEST_C(Blocking, CASE_NUMBER, DESC) \\\n-    CREATE_TEST_C(NonBlocking, CASE_NUMBER, DESC)\n+    CREATE_TEST_CASE_NONBLOCKING(CASE_NUMBER, DESC) \\\n+    CREATE_TEST_CASE_BLOCKING(CASE_NUMBER, DESC)\n \n #ifdef SRT_ENABLE_ENCRYPTION\n CREATE_TEST_CASES(CASE_A_1, Enforced_On_On_Pwd_Set_Set_Match)\ndiff --git a/test/test_env.h b/test/test_env.h\nindex 3f90cca..b425fa8 100644\n--- a/test/test_env.h\n+++ b/test/test_env.h\n@@ -7,7 +7,6 @@\n #include <stdexcept>\n #include \"gtest/gtest.h\"\n \n-#include \"sync.h\"\n \n namespace srt\n {\n@@ -41,22 +40,6 @@ public:\n     // All must be static, return bool. Arguments allowed.\n     // The name must start with Allowed_.\n     static bool Allowed_IPv6();\n-\n-    template<typename... Args>\n-    static bool Allowed_Platform(const std::string& first, const Args&... follow)\n-    {\n-        if (first == SRT_TEST_SYSTEM_NAME)\n-            return true;\n-        return Allowed_Platform(follow...);\n-    }\n-\n-    static bool Allowed_Platform() { return false; }\n-\n-#ifdef ENABLE_BONDING\n-    static bool Allowed_Bonding() { return true; }\n-#else\n-    static bool Allowed_Bonding() { return false; }\n-#endif\n };\n \n #define SRTST_REQUIRES(feature,...) if (!srt::TestEnv::Allowed_##feature(__VA_ARGS__)) { return; }\n@@ -146,36 +129,8 @@ public:\n     }\n };\n \n-class CUDT;\n-class CPacket;\n-struct CUnit;\n-class CUDTSocket;\n-\n-class TestMockCUDT\n-{\n-public:\n-    CUDT* core;\n-\n-    TestMockCUDT() : core(NULL) {}\n-\n-    bool setSocket(int32_t socket);\n-\n-    // This is used in TestFEC; leaving with a single forwarder \n-    // to keep the test as is. The class can be as well extended.\n-    bool checkApplyFilterConfig(const std::string& s);\n-\n-    bool processSrtMsg(const srt::CPacket *ctrlpkt);\n-    int rcvKmState();\n-    int processData(CUnit* u);\n-    CUDTSocket* locateSocket(int32_t s);\n-\n-    void processCtrlAck(const CPacket& pkt, const sync::steady_clock::time_point& t);\n-    int flowWindowSize() const;\n-    void setFlowWindowSize(int v);\n-};\n-\n struct sockaddr_any CreateAddr(const std::string& name, unsigned short port, int pref_family);\n \n-} //namespace srt\n+} //namespace\n \n #endif\ndiff --git a/test/test_epoll.cpp b/test/test_epoll.cpp\nindex c2152ce..a8a88aa 100644\n--- a/test/test_epoll.cpp\n+++ b/test/test_epoll.cpp\n@@ -12,7 +12,6 @@\n using namespace std;\n using namespace srt;\n \n-#define TEST_UDP_PORT 9990\n \n TEST(CEPoll, InfiniteWait)\n {\n@@ -572,7 +571,7 @@ protected:\n         sockaddr_in sa;\n         memset(&sa, 0, sizeof sa);\n         sa.sin_family = AF_INET;\n-        sa.sin_port = htons(TEST_UDP_PORT);\n+        sa.sin_port = htons(9999);\n \n         ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n@@ -592,7 +591,7 @@ protected:\n \n             ASSERT_NE(srt_epoll_wait(m_client_pollid, read, &rlen,\n                         write, &wlen,\n-                        -1, // -1 is set for debugging purpose.\n+                        -1, // -1 is set for debuging purpose.\n                         // in case of production we need to set appropriate value\n                         0, 0, 0, 0), SRT_ERROR);\n \n@@ -603,7 +602,7 @@ protected:\n \n         char buffer[1316] = {1, 2, 3, 4};\n         ASSERT_NE(srt_sendmsg(m_client_sock, buffer, sizeof buffer,\n-                    -1, // infinite ttl\n+                    -1, // infinit ttl\n                     true // in order must be set to true\n                     ),\n                 SRT_ERROR);\n@@ -646,7 +645,7 @@ protected:\n         sockaddr_in sa;\n         memset(&sa, 0, sizeof sa);\n         sa.sin_family = AF_INET;\n-        sa.sin_port = htons(TEST_UDP_PORT);\n+        sa.sin_port = htons(9999);\n         sa.sin_addr.s_addr = INADDR_ANY;\n         sockaddr* psa = (sockaddr*)&sa;\n \n@@ -670,7 +669,7 @@ protected:\n             ASSERT_NE(srt_epoll_wait(m_server_pollid,\n                         read,  &rlen,\n                         write, &wlen,\n-                        -1, // -1 is set for debugging purpose.\n+                        -1, // -1 is set for debuging purpose.\n                         // in case of production we need to set appropriate value\n                         0, 0, 0, 0), SRT_ERROR );\n \n@@ -697,7 +696,7 @@ protected:\n             ASSERT_NE(srt_epoll_wait(m_server_pollid,\n                         read,  &rlen,\n                         write, &wlen,\n-                        -1, // -1 is set for debugging purpose.\n+                        -1, // -1 is set for debuging purpose.\n                         // in case of production we need to set appropriate value\n                         0, 0, 0, 0), SRT_ERROR );\n \ndiff --git a/test/test_fec_rebuilding.cpp b/test/test_fec_rebuilding.cpp\nindex f73ee85..7e14992 100644\n--- a/test/test_fec_rebuilding.cpp\n+++ b/test/test_fec_rebuilding.cpp\n@@ -1,7 +1,6 @@\n #include <vector>\n #include <algorithm>\n #include <future>\n-#include <thread>\n \n #include \"gtest/gtest.h\"\n #include \"test_env.h\"\n@@ -30,6 +29,7 @@ protected:\n     TestFECRebuilding()\n     {\n         // Required to make ParseCorrectorConfig work\n+        PacketFilter::globalInit();\n     }\n \n     void setup() override\n@@ -91,25 +91,21 @@ protected:\n     {\n         delete fec;\n     }\n-\n };\n \n-static std::future<int> spawn_connect(SRTSOCKET s, sockaddr_in& sa, int timeout_ms = 1000)\n-{\n-    std::cout << \"[M] SPAWNING srt_connect()\\n\";\n-    return std::async(std::launch::async, [s, &sa, timeout_ms]()\n+namespace srt {\n+    class TestMockCUDT\n+    {\n+    public:\n+        CUDT* core;\n+\n+        bool checkApplyFilterConfig(const string& s)\n         {\n-            // Add a delay for starting connection to give a chance\n-            // for the main thread to establish an EID with the listener\n-            // BEFORE the handshake packet is received, otherwise the\n-            // epoll will miss the signal (a bug fixed in 1.6.0).\n-            std::this_thread::sleep_for(chrono::milliseconds(timeout_ms));\n-            std::cout << \"[T] RUNNING srt_connect()\\n\";\n-            return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n-        });\n+            return core->checkApplyFilterConfig(s);\n+        }\n+    };\n }\n \n-\n // The expected whole procedure of connection using FEC is\n // expected to:\n //\n@@ -247,8 +243,6 @@ TEST(TestFEC, ConfigExchange)\n TEST(TestFEC, ConfigExchangeFaux)\n {\n     srt::TestInit srtinit;\n-    using namespace std;\n-\n \n     CUDTSocket* s1;\n \n@@ -261,15 +255,12 @@ TEST(TestFEC, ConfigExchangeFaux)\n         \"fec,cols:10,rows:-1\", // E3: invalid value for rows\n         \"fec,cols:10,layout:stairwars\", // E4: invalid value for layout\n         \"fec,cols:10,arq:sometimes\", // E5: invalid value for arq\n-        \"fec,cols:10,weight:2\", // F: invalid parameter name\n-        \"fec,cols:80000,rows:70000\", // oversized\n-        \"fec,cols:10,rows:-70000\" // negative oversized rows\n+        \"fec,cols:10,weight:2\" // F: invalid parameter name\n     };\n \n     for (auto badconfig: fec_config_wrong)\n     {\n-        cout << \"CASE: \" << badconfig << endl;\n-        EXPECT_EQ(srt_setsockflag(sid1, SRTO_PACKETFILTER, badconfig, (int)strlen(badconfig)), -1);\n+        ASSERT_EQ(srt_setsockflag(sid1, SRTO_PACKETFILTER, badconfig, (int)strlen(badconfig)), -1);\n     }\n \n     TestMockCUDT m1;\n@@ -290,29 +281,31 @@ TEST(TestFEC, ConfigExchangeFaux)\n \n TEST(TestFEC, Connection)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:10,rows:10\";\n     const char fec_config2 [] = \"fec,cols:10,arq:never\";\n     const char fec_config_final [] = \"fec,cols:10,rows:10,arq:never,layout:staircase\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n-    EXPECT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n \n-    EXPECT_NE(srt_listen(l, 1), -1);\n+    srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa, 1);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n@@ -320,8 +313,8 @@ TEST(TestFEC, Connection)\n     // Given 2s timeout for accepting as it has occasionally happened with Travis\n     // that 1s might not be enough.\n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR);\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR);\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -341,47 +334,45 @@ TEST(TestFEC, Connection)\n     EXPECT_TRUE(filterConfigSame(caller_config, fec_config_final));\n     EXPECT_TRUE(filterConfigSame(accept_config, fec_config_final));\n \n-    // Exceptionally blocked here to test \"forgotten socket cleanup\" additionally\n-    //srt_close(a);\n-    //srt_close(s);\n-    //srt_close(l);\n+    srt_close(a);\n+    srt_close(s);\n+    srt_close(l);\n }\n \n TEST(TestFEC, ConnectionReorder)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:10,rows:10\";\n     const char fec_config2 [] = \"fec,rows:10,cols:10\";\n     const char fec_config_final [] = \"fec,cols:10,rows:10,arq:onreq,layout:staircase\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n-    EXPECT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n-\n-    int conntimeo = 10000;\n-    EXPECT_NE(srt_setsockflag(s, SRTO_CONNTIMEO, &conntimeo, sizeof (conntimeo)), SRT_ERROR);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n \n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR);\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR);\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -408,35 +399,38 @@ TEST(TestFEC, ConnectionReorder)\n \n TEST(TestFEC, ConnectionFull1)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:10,rows:20,arq:never,layout:even\";\n     const char fec_config2 [] = \"fec,layout:even,rows:20,cols:10,arq:never\";\n     const char fec_config_final [] = \"fec,cols:10,rows:20,arq:never,layout:even\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n-    EXPECT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n+\n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n \n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR);\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR);\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -463,36 +457,38 @@ TEST(TestFEC, ConnectionFull1)\n \n TEST(TestFEC, ConnectionFull2)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:10,rows:20,arq:always,layout:even\";\n     const char fec_config2 [] = \"fec,layout:even,rows:20,cols:10,arq:always\";\n     const char fec_config_final [] = \"fec,cols:10,rows:20,arq:always,layout:even\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n-    EXPECT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n \n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR);\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR);\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -519,36 +515,38 @@ TEST(TestFEC, ConnectionFull2)\n \n TEST(TestFEC, ConnectionMess)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:,cols:10\";\n     const char fec_config2 [] = \"fec,cols:,rows:10\";\n     const char fec_config_final [] = \"fec,cols:10,rows:10,arq:onreq,layout:staircase\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n-    EXPECT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(l, SRTO_PACKETFILTER, fec_config2, (sizeof fec_config2)-1), -1);\n \n-    EXPECT_NE(srt_listen(l, 1), -1);\n+    srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n \n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR) << srt_getlasterror_str();\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR) << srt_getlasterror_str();\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -575,34 +573,36 @@ TEST(TestFEC, ConnectionMess)\n \n TEST(TestFEC, ConnectionForced)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,rows:20,cols:20\";\n     const char fec_config_final [] = \"fec,cols:20,rows:20\";\n \n-    EXPECT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n+    ASSERT_NE(srt_setsockflag(s, SRTO_PACKETFILTER, fec_config1, (sizeof fec_config1)-1), -1);\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n \n     SRTSOCKET la[] = { l };\n-    SRTSOCKET a = srt_accept_bond(la, 1, 5000);\n-    EXPECT_NE(a, SRT_ERROR);\n+    SRTSOCKET a = srt_accept_bond(la, 1, 2000);\n+    ASSERT_NE(a, SRT_ERROR);\n     EXPECT_EQ(connect_res.get(), SRT_SUCCESS);\n \n     // Now that the connection is established, check negotiated config\n@@ -625,17 +625,17 @@ TEST(TestFEC, ConnectionForced)\n \n TEST(TestFEC, RejectionConflict)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,cols:10,rows:10\";\n@@ -646,7 +646,9 @@ TEST(TestFEC, RejectionConflict)\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n@@ -670,17 +672,17 @@ TEST(TestFEC, RejectionConflict)\n \n TEST(TestFEC, RejectionIncompleteEmpty)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,rows:10\";\n@@ -688,7 +690,9 @@ TEST(TestFEC, RejectionIncompleteEmpty)\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n@@ -713,17 +717,17 @@ TEST(TestFEC, RejectionIncompleteEmpty)\n \n TEST(TestFEC, RejectionIncomplete)\n {\n+    srt::TestInit srtinit;\n+\n+    SRTSOCKET s = srt_create_socket();\n+    SRTSOCKET l = srt_create_socket();\n+\n     sockaddr_in sa;\n     memset(&sa, 0, sizeof sa);\n     sa.sin_family = AF_INET;\n     sa.sin_port = htons(5555);\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    srt::TestInit srtinit;\n-\n-    SRTSOCKET s = srt_create_socket();\n-    SRTSOCKET l = srt_create_socket();\n-\n     srt_bind(l, (sockaddr*)& sa, sizeof(sa));\n \n     const char fec_config1 [] = \"fec,rows:10\";\n@@ -734,7 +738,9 @@ TEST(TestFEC, RejectionIncomplete)\n \n     srt_listen(l, 1);\n \n-    auto connect_res = spawn_connect(s, sa);\n+    auto connect_res = std::async(std::launch::async, [&s, &sa]() {\n+        return srt_connect(s, (sockaddr*)& sa, sizeof(sa));\n+        });\n \n     // Make sure that the async call to srt_connect() is already kicked.\n     std::this_thread::yield();\n@@ -940,43 +946,3 @@ TEST_F(TestFECRebuilding, Rebuild)\n \n     EXPECT_EQ(memcmp(skipped.data(), rebuilt.data(), rebuilt.size()), 0);\n }\n-\n-// processCtrlAck has two OOB-read sites for intermediate payload sizes:\n-//  - ackdata[ACKD_RCVLASTACK] (index 0) is read up front, OOB for 0-3 byte payloads;\n-//  - ackdata[ACKD_BUFFERLEFT] (index 3) is read in the slow path, OOB for 5-15 byte\n-//    payloads (the lite-ACK fast path matches exactly 4 bytes).\n-// Valid payloads are LITE (4 B) or SMALL+ (>=16 B). The guard at the top of the\n-// handler rejects everything else.\n-TEST(TestCUDT, AckRejectsIntermediatePayload)\n-{\n-    srt::TestInit srtinit;\n-\n-    CUDTSocket* s1 = NULL;\n-    SRTSOCKET sid1 = CUDT::uglobal().newSocket(&s1);\n-\n-    TestMockCUDT m1;\n-    m1.core = &s1->core();\n-\n-    const int sentinel = 0x5A5A5A5A;\n-    m1.setFlowWindowSize(sentinel);\n-\n-    CPacket pkt;\n-    pkt.allocate(1500);\n-\n-    // Fill the payload with bytes that would be plausible ack-seqnos if interpreted\n-    // as int32 (non-negative), so the ackdata_seqno < 0 early return doesn't mask\n-    // the bug for the 0-3 byte cases.\n-    std::memset(pkt.m_pcData, 0x01, 1500);\n-\n-    const size_t bad_lens[] = { 0, 1, 3, 5, 8, 12, 15 };\n-    const sync::steady_clock::time_point now = sync::steady_clock::now();\n-    for (size_t i = 0; i < sizeof(bad_lens) / sizeof(bad_lens[0]); ++i)\n-    {\n-        pkt.setLength(bad_lens[i]);\n-        m1.processCtrlAck(pkt, now);\n-        EXPECT_EQ(m1.flowWindowSize(), sentinel)\n-            << \"ACK with payload \" << bad_lens[i] << \" bytes must not corrupt m_iFlowWindowSize\";\n-    }\n-\n-    srt_close(sid1);\n-}\ndiff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp\nindex e7140bf..bfd668a 100644\n--- a/test/test_file_transmission.cpp\n+++ b/test/test_file_transmission.cpp\n@@ -50,13 +50,9 @@ TEST(Transmission, FileUpload)\n     sa_lsn.sin_addr.s_addr = INADDR_ANY;\n     sa_lsn.sin_port = htons(5555);\n \n-    MAKE_UNIQUE_SOCK(sock_lsn_u, \"listener\", sock_lsn);\n-    MAKE_UNIQUE_SOCK(sock_clr_u, \"listener\", sock_clr);\n-\n     // Find unused a port not used by any other service.    \n     // Otherwise srt_connect may actually connect.\n     int bind_res = -1;\n-    std::cout << \"Looking for a free port... \" << std::flush;\n     for (int port = 5000; port <= 5555; ++port)\n     {\n         sa_lsn.sin_port = htons(port);\n@@ -101,13 +97,10 @@ TEST(Transmission, FileUpload)\n \n     std::atomic<bool> thread_exit { false };\n \n-    std::cout << \"Running accept [A] thread\\n\";\n-\n     auto client = std::thread([&]\n     {\n         sockaddr_in remote;\n         int len = sizeof remote;\n-        std::cout << \"[A] waiting for connection\\n\";\n         const SRTSOCKET accepted_sock = srt_accept(sock_lsn, (sockaddr*)&remote, &len);\n         ASSERT_GT(accepted_sock, 0);\n \n@@ -122,30 +115,27 @@ TEST(Transmission, FileUpload)\n \n         std::vector<char> buf(1456);\n \n-        std::cout << \"[A] Connected, reading data...\\n\";\n         for (;;)\n         {\n             int n = srt_recv(accepted_sock, buf.data(), 1456);\n             EXPECT_NE(n, SRT_ERROR) << srt_getlasterror_str();\n             if (n == 0)\n             {\n-                std::cout << \"Received 0 bytes, breaking.\\n\";\n+                std::cerr << \"Received 0 bytes, breaking.\\n\";\n                 break;\n             }\n             else if (n == -1)\n             {\n-                std::cout << \"READ FAILED, breaking anyway\\n\";\n+                std::cerr << \"READ FAILED, breaking anyway\\n\";\n                 break;\n             }\n \n             // Write to file any amount of data received\n             copyfile.write(buf.data(), n);\n         }\n-        std::cout << \"[A] Closing socket\\n\";\n \n         EXPECT_NE(srt_close(accepted_sock), SRT_ERROR);\n \n-        std::cout << \"[A] Exit\\n\";\n         thread_exit = true;\n     });\n \n@@ -154,7 +144,6 @@ TEST(Transmission, FileUpload)\n     sa.sin_port = sa_lsn.sin_port;\n     ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &sa.sin_addr), 1);\n \n-    std::cout << \"Connecting...\\n\";\n     srt_connect(sock_clr, (sockaddr*)&sa, sizeof(sa));\n \n     std::cout << \"Connection initialized\" << std::endl;\n@@ -162,7 +151,6 @@ TEST(Transmission, FileUpload)\n     std::ifstream ifile(\"file.source\", std::ios::in | std::ios::binary);\n     std::vector<char> buf(1456);\n \n-    std::cout << \"Reading file and sending...\\n\";\n     for (;;)\n     {\n         size_t n = ifile.read(buf.data(), 1456).gcount();\ndiff --git a/test/test_listen_callback.cpp b/test/test_listen_callback.cpp\nindex 7b03437..33753c2 100644\n--- a/test/test_listen_callback.cpp\n+++ b/test/test_listen_callback.cpp\n@@ -94,7 +94,7 @@ public:\n             auto state = srt_getsockstate(server_sock);\n             if (int(state) > int(SRTS_CONNECTED))\n             {\n-                std::cout << \"[T] Listener socket closed, exiting\\n\";\n+                std::cout << \"[T] Listener socket closed, exitting\\n\";\n                 break;\n             }\n \n@@ -107,7 +107,7 @@ public:\n                     SRTSOCKET acp = srt_accept(server_sock, NULL, NULL);\n                     if (acp == SRT_INVALID_SOCK)\n                     {\n-                        std::cout << \"[T] Accept failed, so exiting\\n\";\n+                        std::cout << \"[T] Accept failed, so exitting\\n\";\n                         break;\n                     }\n                     srt_close(acp);\ndiff --git a/test/test_main.cpp b/test/test_main.cpp\nindex 701a867..e2243a3 100644\n--- a/test/test_main.cpp\n+++ b/test/test_main.cpp\n@@ -8,7 +8,6 @@\n \n #include \"srt.h\"\n #include \"netinet_any.h\"\n-#include \"api.h\"\n \n using namespace std;\n \n@@ -213,43 +212,4 @@ void UniqueSocket::close()\n     }\n }\n \n-bool TestMockCUDT::checkApplyFilterConfig(const string& s)\n-{\n-    return core->checkApplyFilterConfig(s);\n-}\n-\n-bool TestMockCUDT::processSrtMsg(const srt::CPacket *ctrlpkt)\n-{\n-    return core->processSrtMsg(ctrlpkt);\n-}\n-\n-int TestMockCUDT::rcvKmState()\n-{\n-    return core->m_pCryptoControl->m_RcvKmState;\n-}\n-\n-int TestMockCUDT::processData(CUnit* u)\n-{\n-    return core->processData(u);\n-}\n-\n-CUDTSocket* TestMockCUDT::locateSocket(int32_t s)\n-{\n-    SRTSOCKET sock (s);\n-    return CUDT::uglobal().locateSocket(sock);\n-}\n-\n-bool TestMockCUDT::setSocket(int32_t sock)\n-{\n-    CUDTSocket* s = locateSocket(sock);\n-    if (!s)\n-        return false;\n-    core = &s->core();\n-    return true;\n-}\n-\n-void TestMockCUDT::processCtrlAck(const CPacket& pkt, const sync::steady_clock::time_point& t) { core->processCtrlAck(pkt, t); }\n-int TestMockCUDT::flowWindowSize() const { return core->m_iFlowWindowSize; }\n-void TestMockCUDT::setFlowWindowSize(int v) { core->m_iFlowWindowSize = v; }\n-\n }\ndiff --git a/test/test_muxer.cpp b/test/test_muxer.cpp\nindex 369cd8c..e85a121 100644\n--- a/test/test_muxer.cpp\n+++ b/test/test_muxer.cpp\n@@ -71,7 +71,7 @@ public:\n \n             ASSERT_NE(srt_epoll_wait(m_client_pollid, read, &rlen,\n                                     write, &wlen,\n-                                    -1, // -1 is set for debugging purpose.\n+                                    -1, // -1 is set for debuging purpose.\n                                         // in case of production we need to set appropriate value\n                                     0, 0, 0, 0), SRT_ERROR);\n \n@@ -82,7 +82,7 @@ public:\n \n         char buffer[1316] = {1, 2, 3, 4};\n         ASSERT_NE(srt_sendmsg(m_caller_sock, buffer, sizeof buffer,\n-                            -1, // infinite ttl\n+                            -1, // infinit ttl\n                             true // in order must be set to true\n                             ), SRT_ERROR);\n     }\n@@ -150,7 +150,7 @@ TEST_F(TestMuxer, IPv4_and_IPv6)\n         ASSERT_NE(srt_epoll_wait(m_server_pollid,\n                                  read,  &rlen,\n                                  write, &wlen,\n-                                 -1, // -1 is set for debugging purpose.\n+                                 -1, // -1 is set for debuging purpose.\n                                      // in case of production we need to set appropriate value\n                                  0, 0, 0, 0), SRT_ERROR );\n \n@@ -177,7 +177,7 @@ TEST_F(TestMuxer, IPv4_and_IPv6)\n         ASSERT_NE(srt_epoll_wait(m_server_pollid,\n                                  read,  &rlen,\n                                  write, &wlen,\n-                                 -1, // -1 is set for debugging purpose.\n+                                 -1, // -1 is set for debuging purpose.\n                                      // in case of production we need to set appropriate value\n                                   0, 0, 0, 0), SRT_ERROR );\n \ndiff --git a/test/test_reuseaddr.cpp b/test/test_reuseaddr.cpp\nindex 64d1c51..df4aec4 100644\n--- a/test/test_reuseaddr.cpp\n+++ b/test/test_reuseaddr.cpp\n@@ -148,6 +148,15 @@ protected:\n         int yes = 1;\n         int no = 0;\n \n+        int family = AF_INET;\n+        string famname = \"IPv4\";\n+        if (ip.substr(0, 2) == \"6.\")\n+        {\n+            family = AF_INET6;\n+            ip = ip.substr(2);\n+            famname = \"IPv6\";\n+        }\n+\n         cout << \"[T/C] Setting up client socket\\n\";\n         ASSERT_NE(client_sock, SRT_INVALID_SOCK);\n         ASSERT_EQ(srt_getsockstate(client_sock), SRTS_INIT);\n@@ -162,8 +171,7 @@ protected:\n         int epoll_out = SRT_EPOLL_OUT;\n         srt_epoll_add_usock(client_pollid, client_sock, &epoll_out);\n \n-        sockaddr_any sa = srt::CreateAddr(ip, port, AF_UNSPEC);\n-        string famname = (sa.family() == AF_INET) ? \"IPv4\" : \"IPv6\";\n+        sockaddr_any sa = srt::CreateAddr(ip, port, family);\n \n         cout << \"[T/C] Connecting to: \" << sa.str() << \" (\" << famname << \")\" << endl;\n \n@@ -194,7 +202,7 @@ protected:\n \n                 EXPECT_NE(srt_epoll_wait(client_pollid, read, &rlen,\n                             write, &wlen,\n-                            -1, // -1 is set for debugging purpose.\n+                            -1, // -1 is set for debuging purpose.\n                             // in case of production we need to set appropriate value\n                             0, 0, 0, 0), SRT_ERROR) << srt_getlasterror_str();\n \n@@ -204,7 +212,7 @@ protected:\n \n                 char buffer[1316] = {1, 2, 3, 4};\n                 EXPECT_NE(srt_sendmsg(client_sock, buffer, sizeof buffer,\n-                            -1, // infinite ttl\n+                            -1, // infinit ttl\n                             true // in order must be set to true\n                             ),\n                         SRT_ERROR);\n@@ -324,7 +332,7 @@ protected:\n             EXPECT_NE(srt_epoll_wait(server_pollid,\n                         read,  &rlen,\n                         write, &wlen,\n-                        10000, // -1 is set for debugging purpose.\n+                        10000, // -1 is set for debuging purpose.\n                         // in case of production we need to set appropriate value\n                         0, 0, 0, 0), SRT_ERROR) << srt_getlasterror_str();\n \n@@ -363,7 +371,7 @@ protected:\n                 EXPECT_NE(srt_epoll_wait(server_pollid,\n                             read,  &rlen,\n                             write, &wlen,\n-                            -1, // -1 is set for debugging purpose.\n+                            -1, // -1 is set for debuging purpose.\n                             // in case of production we need to set appropriate value\n                             0, 0, 0, 0), SRT_ERROR) << srt_getlasterror_str();\n \n@@ -523,29 +531,6 @@ TEST_F(ReuseAddr, DiffAddr)\n     shutdownListener(bindsock_2);\n }\n \n-TEST_F(ReuseAddr, UDPOptions)\n-{\n-    // IP_TOS and IP_TTL don't work on Windows and Mac\n-    SRTST_REQUIRES(Platform, \"Linux\", \"GNU\");\n-\n-    // Travis doesn't work with IPv6\n-    SRTST_REQUIRES(IPv6);\n-\n-    MAKE_UNIQUE_SOCK(bs1, \"general ipv6\", prepareServerSocket());\n-    MAKE_UNIQUE_SOCK(bs2, \"mapped ipv4\", prepareServerSocket());\n-\n-    int val_TOS = 4; // IPTOS_RELIABILITY per <netinet/ip.h>, but not available on Windows\n-    int val_TTL = 10;\n-\n-    EXPECT_NE(srt_setsockflag(bs1, SRTO_IPTOS, &val_TOS, sizeof val_TOS), SRT_ERROR);\n-    EXPECT_NE(srt_setsockflag(bs1, SRTO_IPTTL, &val_TTL, sizeof val_TTL), SRT_ERROR);\n-    EXPECT_NE(srt_setsockflag(bs2, SRTO_IPTOS, &val_TOS, sizeof val_TOS), SRT_ERROR);\n-    EXPECT_NE(srt_setsockflag(bs2, SRTO_IPTTL, &val_TTL, sizeof val_TTL), SRT_ERROR);\n-\n-    bindSocket(bs1, \"::1\", 5000, true);\n-    bindSocket(bs2, \"::FFFF:127.0.0.1\", 5001, true);\n-}\n-\n TEST_F(ReuseAddr, Wildcard)\n {\n #if defined(_WIN32) || defined(CYGWIN)\ndiff --git a/test/test_seqno.cpp b/test/test_seqno.cpp\nindex f129e83..f2e374f 100644\n--- a/test/test_seqno.cpp\n+++ b/test/test_seqno.cpp\n@@ -11,14 +11,14 @@ const int32_t CSeqNo::m_iMaxSeqNo;\n \n TEST(CSeqNo, constants)\n {\n-    // Compare two seq#, considering the wrapping.\n+    // Compare two seq#, considering the wraping.\n     EXPECT_EQ(CSeqNo::m_iMaxSeqNo, 0x7FFFFFFF);\n     EXPECT_EQ(CSeqNo::m_iSeqNoTH,  0x3FFFFFFF);\n }\n \n TEST(CSeqNo, seqcmp)\n {\n-    // Compare two seq#, considering the wrapping.\n+    // Compare two seq#, considering the wraping.\n     EXPECT_EQ(CSeqNo::seqcmp(0x7FFFFFFF, 0x7FFFFFFF), 0);\n \n     // abs(seq1 - seq2) < 0x3FFFFFFF : seq1 - seq2\ndiff --git a/test/test_snd_rate_estimator.cpp b/test/test_snd_rate_estimator.cpp\nindex 5dca5f4..c658c65 100644\n--- a/test/test_snd_rate_estimator.cpp\n+++ b/test/test_snd_rate_estimator.cpp\n@@ -30,7 +30,7 @@ protected:\n     // SetUp() is run immediately before a test starts.\n     void SetUp() override\n     {\n-        // make_unique is unfortunately C++14\n+        // make_unique is unfortunatelly C++14\n \n     }\n \ndiff --git a/test/test_socket_options.cpp b/test/test_socket_options.cpp\nindex 67a3001..84a9303 100644\n--- a/test/test_socket_options.cpp\n+++ b/test/test_socket_options.cpp\n@@ -25,44 +25,39 @@\n using namespace std;\n using namespace srt;\n \n-#define PLEASE_LOG 0\n \n-#if PLEASE_LOG\n-#define LOGD(args) args\n-#else\n-#define LOGD(args) (void)0\n-#endif\n-\n-class TestOptionsCommon: public srt::Test\n+class TestSocketOptions\n+    : public ::srt::Test\n {\n protected:\n-    TestOptionsCommon() = default;\n-    ~TestOptionsCommon() override = default;\n+    TestSocketOptions()\n+    {\n+        // initialization code here\n+    }\n \n-    sockaddr_any m_sa;\n-    SRTSOCKET m_caller_sock = SRT_INVALID_SOCK;\n-    SRTSOCKET m_listen_sock = SRT_INVALID_SOCK;\n+    ~TestSocketOptions()\n+    {\n+        // cleanup any pending stuff, but no exceptions allowed\n+    }\n \n-    int       m_pollid = 0;\n public:\n-\n-    void BindListener() const\n+    void BindListener()\n     {\n         // Specify address of the listener\n-        const auto* psa = (const sockaddr*)&m_sa;\n+        sockaddr* psa = (sockaddr*)&m_sa;\n         ASSERT_NE(srt_bind(m_listen_sock, psa, sizeof m_sa), SRT_ERROR);\n     }\n \n-    void StartListener() const\n+    void StartListener()\n     {\n         BindListener();\n \n         srt_listen(m_listen_sock, 1);\n     }\n \n-    int Connect() const\n+    int Connect()\n     {\n-        const auto* psa = (const sockaddr*)&m_sa;\n+        sockaddr* psa = (sockaddr*)&m_sa;\n         return srt_connect(m_caller_sock, psa, sizeof m_sa);\n     }\n \n@@ -88,104 +83,44 @@ public:\n         return accepted_sock;\n     }\n \n-    void teardown() override\n-    {\n-        // Code here will be called just after the test completes.\n-        // OK to throw exceptions from here if needed.\n-        EXPECT_NE(srt_close(m_caller_sock), SRT_ERROR);\n-        EXPECT_NE(srt_close(m_listen_sock), SRT_ERROR);\n-    }\n-};\n-\n-\n-class TestSocketOptions: public TestOptionsCommon\n-{\n protected:\n-    TestSocketOptions() = default;\n-    ~TestSocketOptions() override = default;\n-\n     // setup() is run immediately before a test starts.\n-    void setup() override\n+    void setup()\n     {\n         const int yes = 1;\n-        m_sa = srt::CreateAddr(\"127.0.0.1\", 5200, AF_INET);\n-        ASSERT_FALSE(m_sa.empty());\n \n-        m_caller_sock = srt_create_socket();\n-        ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK) << srt_getlasterror_str();\n-        m_listen_sock = srt_create_socket();\n-        ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK) << srt_getlasterror_str();\n+        memset(&m_sa, 0, sizeof m_sa);\n+        m_sa.sin_family = AF_INET;\n+        m_sa.sin_port = htons(5200);\n+        ASSERT_EQ(inet_pton(AF_INET, \"127.0.0.1\", &m_sa.sin_addr), 1);\n \n+        m_caller_sock = srt_create_socket();\n+        ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK);\n         ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n         ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n \n-        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n-        ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n-    }\n-};\n-\n-#if ENABLE_BONDING\n-// Test group options\n-class TestGroupOptions: public TestOptionsCommon\n-{\n-protected:\n-    TestGroupOptions() = default;\n-    ~TestGroupOptions() override = default;\n-\n-    // Is run immediately before a test starts.\n-    void setup() override\n-    {\n-        const int yes = 1;\n-\n-        m_sa = srt::CreateAddr(\"127.0.0.1\", 5200, AF_INET);\n-        ASSERT_FALSE(m_sa.empty());\n-\n-        m_caller_sock = srt_create_group(SRT_GTYPE_BROADCAST);\n-        ASSERT_NE(m_caller_sock, SRT_INVALID_SOCK) << srt_getlasterror_str();\n         m_listen_sock = srt_create_socket();\n-        ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK) << srt_getlasterror_str();\n-\n-        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n-        ASSERT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n-\n+        ASSERT_NE(m_listen_sock, SRT_INVALID_SOCK);\n         ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_RCVSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n         ASSERT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_SNDSYN, &yes, sizeof yes), SRT_SUCCESS); // for async connect\n-        ASSERT_EQ(srt_setsockflag(m_listen_sock, SRTO_GROUPCONNECT, &yes, sizeof yes), SRT_SUCCESS);\n     }\n-};\n-#endif\n \n-#if PLEASE_LOG\n-static std::string to_string(const linb::any& val)\n-{\n-    using namespace linb;\n-\n-    if (val.type() == typeid(const char*))\n+    void teardown()\n     {\n-        return any_cast<const char*>(val);\n+        // Code here will be called just after the test completes.\n+        // OK to throw exceptions from here if needed.\n+        EXPECT_NE(srt_close(m_caller_sock), SRT_ERROR);\n+        EXPECT_NE(srt_close(m_listen_sock), SRT_ERROR);\n     }\n \n-    std::ostringstream out;\n-    if (val.type() == typeid(bool))\n-    {\n-        out << any_cast<bool>(val);\n-    }\n-    else if (val.type() == typeid(int))\n-    {\n-        out << any_cast<int>(val);\n-    }\n-    else if (val.type() == typeid(int64_t))\n-    {\n-        out << any_cast<int64_t>(val);\n-    }\n-    else\n-    {\n-        return \"<bad-any-cast>\";\n-    }\n+protected:\n+    sockaddr_in m_sa;\n+    SRTSOCKET m_caller_sock = SRT_INVALID_SOCK;\n+    SRTSOCKET m_listen_sock = SRT_INVALID_SOCK;\n+\n+    int       m_pollid = 0;\n+};\n \n-    return out.str();\n-}\n-#endif\n \n enum class RestrictionType\n {\n@@ -194,76 +129,23 @@ enum class RestrictionType\n     POST    = 2\n };\n \n-// FLAGS\n-// - READABLE (R)\n-//   : You can call srt_getsockflag\n-// - WRITABLE (W)\n-//   : You can call srt_setsockflag\n-// - SOCKETWISE (S)\n-//   : Can be set on a socket\n-// - GROUPWISE (G)\n-//   : Can be set on a group\n-// - DERIVED (D)\n-//   : TRUE: If it's set on the group, it will be derived by members\n-//   : FALSE: It cannot be set on the group to be derived by members\n-// - GROUPUNIQUE (I)\n-//   : TRUE: If set on the group, it's assigned to a group (not members)\n-//   : FALSE: If set on the group, it's derived by members\n-// - MODIFIABLE (M)\n-//   : TRUE: Can be set on individual member socket differently.\n-//   : FALSE: Cannot be altered on the individual member socket.\n-\n-namespace Flags\n-{\n-enum type: char\n-{\n-    O = 0, // Marker for an unset flag\n-\n-    R = 1 << 0,  // readable\n-    W = 1 << 1,  // writable\n-    S = 1 << 2,  // can be set on single socket\n-    G = 1 << 3,  // can be set on group\n-    D = 1 << 4,  // when set on group, derived by the socket\n-    I = 1 << 5,  // when set on group, it concerns group only\n-    M = 1 << 6   // can be modified on individual member\n-};\n-\n-inline type operator|(type f1, type f2)\n-{\n-    char val = char(f1) | char(f2);\n-    return type(val);\n-}\n-\n-inline bool operator&(type ff, type mask)\n-{\n-    char val = char(ff) & char(mask);\n-    return val == mask;\n-}\n-\n-const std::string str(type t)\n-{\n-    static const char names [] = \"RWSGDI+\";\n-    std::string out;\n-\n-    for (int i = 0; i < 7; ++i)\n-        if (int(t) & (1 << i))\n-            out += names[i];\n-\n-    if (out.empty())\n-        return \"O\";\n-    return out;\n-}\n-}\n-\n const char* RestrictionTypeStr(RestrictionType val)\n {\n-    static const std::map<RestrictionType, const char*> type_to_str = {\n-        { RestrictionType::PREBIND, \"PREBIND\" },\n-        { RestrictionType::PRE,     \"PRE\" },\n-        { RestrictionType::POST,    \"POST\" }\n-    };\n-\n-    return type_to_str.find(val) != type_to_str.end() ? type_to_str.at(val) : \"INVALID\";\n+    switch (val)\n+    {\n+    case RestrictionType::PREBIND:\n+        return \"PREBIND\";\n+        break;\n+    case RestrictionType::PRE:\n+        return \"PRE\";\n+        break;\n+    case RestrictionType::POST:\n+        return \"POST\";\n+        break;\n+    default:\n+        break;\n+    }\n+    return \"INVALID\";\n }\n \n struct OptionTestEntry\n@@ -277,51 +159,26 @@ struct OptionTestEntry\n     linb::any dflt_val;\n     linb::any ndflt_val; \n     vector<linb::any> invalid_vals;\n-    Flags::type flags;\n-\n-    bool allof() const { return true; }\n-\n-    template<typename... Args>\n-    bool allof(Flags::type flg, Args... args) const\n-    {\n-        return flags & flg && allof(args...);\n-    }\n-\n-    bool anyof() const { return false; }\n-\n-    template<typename... Args>\n-    bool anyof(Flags::type flg, Args... args) const\n-    {\n-        return flags & flg || anyof(args...);\n-    }\n };\n \n static const size_t UDP_HDR_SIZE = 28;   // 20 bytes IPv4 + 8 bytes of UDP { u16 sport, dport, len, csum }.\n static const size_t DFT_MTU_SIZE = 1500; // Default MTU size\n static const size_t SRT_PKT_SIZE = DFT_MTU_SIZE - UDP_HDR_SIZE; // MTU without UDP header\n \n-namespace Table\n-{\n-    // A trick to localize 1-letter flags without exposing\n-    // them for the rest of the file.\n-using namespace Flags;\n-\n const OptionTestEntry g_test_matrix_options[] =\n {\n-    //                                                                                                                                                                 Place 'O' if not set.\n-    // Option ID,                Option Name |          Restriction |         optlen |             min |       max |  default | nondefault    | invalid vals | flags:  R | W | G | S | D | I | M\n-\n-    //SRTO_BINDTODEVICE                                                                                                                                                R | W | G | S | D | I | M\n-    //{ SRTO_CONGESTION,      \"SRTO_CONGESTION\",  RestrictionType::PRE,               4,           \"live\",     \"file\",   \"live\",       \"file\",   {\"liv\", \"\"},          O | W | O | S | O | O | O },\n-    { SRTO_CONNTIMEO,        \"SRTO_CONNTIMEO\",  RestrictionType::PRE,     sizeof(int),                0,  INT32_MAX,     3000,          250,   {-1},                   O | W | G | S | D | O | M },\n-    { SRTO_DRIFTTRACER,    \"SRTO_DRIFTTRACER\",  RestrictionType::POST,   sizeof(bool),            false,       true,     true,        false,     {},                   R | W | G | S | D | O | O },\n-    { SRTO_ENFORCEDENCRYPTION, \"SRTO_ENFORCEDENCRYPTION\", RestrictionType::PRE, sizeof(bool),     false,       true,     true,        false,     {},                   O | W | G | S | D | O | O },\n-    //SRTO_EVENT                                                                                                                                                       R | O | O | S | O | O | O\n-    { SRTO_FC,                      \"SRTO_FC\",  RestrictionType::PRE,     sizeof(int),               32,  INT32_MAX,    25600,        10000,   {-1, 31},               R | W | G | S | D | O | O },\n-    //SRTO_GROUPCONNECT                                                                                                                                                O | W | O | S | O | O | O \n+    // Option ID,                Option Name |          Restriction |         optlen |             min |       max |  default | nondefault |  invalid vals |\n+    //SRTO_BINDTODEVICE\n+    //{ SRTO_CONGESTION,      \"SRTO_CONGESTION\",  RestrictionType::PRE,               4,           \"live\",     \"file\",   \"live\",       \"file\",   {\"liv\", \"\"} },\n+    { SRTO_CONNTIMEO,        \"SRTO_CONNTIMEO\",  RestrictionType::PRE,     sizeof(int),                0,  INT32_MAX,     3000,          250,   {-1} },\n+    { SRTO_DRIFTTRACER,    \"SRTO_DRIFTTRACER\",  RestrictionType::POST,   sizeof(bool),            false,       true,     true,        false,     {} },\n+    { SRTO_ENFORCEDENCRYPTION, \"SRTO_ENFORCEDENCRYPTION\", RestrictionType::PRE, sizeof(bool),     false,       true,     true,        false,     {} },\n+    //SRTO_EVENT\n+    { SRTO_FC,                      \"SRTO_FC\",  RestrictionType::PRE,     sizeof(int),               32,  INT32_MAX,    25600,        10000,   {-1, 31} },\n+    //SRTO_GROUPCONNECT\n #if ENABLE_BONDING\n     // Max value can't exceed SRTO_PEERIDLETIMEO\n-    { SRTO_GROUPMINSTABLETIMEO, \"SRTO_GROUPMINSTABLETIMEO\", RestrictionType::PRE, sizeof(int),       60,       5000,       60,        70, {0, -1, 50, 5001},           O | W | G | O | D | I | M },\n+    { SRTO_GROUPMINSTABLETIMEO, \"SRTO_GROUPMINSTABLETIMEO\", RestrictionType::PRE, sizeof(int),       60,       5000,       60,           70,     {0, -1, 50, 5001} },\n #endif\n     //SRTO_GROUPTYPE\n     //SRTO_INPUTBW\n@@ -329,66 +186,56 @@ const OptionTestEntry g_test_matrix_options[] =\n     //SRTO_IPTTL\n     //SRTO_IPV6ONLY\n     //SRTO_ISN\n-    { SRTO_KMPREANNOUNCE, \"SRTO_KMPREANNOUNCE\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,        0,         1024,   {-1},                   O | W | G | S | D | O | O },\n-    { SRTO_KMREFRESHRATE, \"SRTO_KMREFRESHRATE\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,        0,         1024,   {-1},                   O | W | G | S | D | O | O },\n+    { SRTO_KMPREANNOUNCE, \"SRTO_KMPREANNOUNCE\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,        0,         1024,   {-1} },\n+    { SRTO_KMREFRESHRATE, \"SRTO_KMREFRESHRATE\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,        0,         1024,   {-1} },\n     //SRTO_KMSTATE\n-    { SRTO_LATENCY,             \"SRTO_LATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,      120,          200,  {-1},                    R | W | G | S | D | O | O },\n+    { SRTO_LATENCY,             \"SRTO_LATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,      120,          200,  {-1} },\n     //SRTO_LINGER\n-    { SRTO_LOSSMAXTTL,       \"SRTO_LOSSMAXTTL\", RestrictionType::POST,    sizeof(int),                 0, INT32_MAX,        0,           10,   {},                     R | W | G | S | D | O | M },\n-    { SRTO_MAXBW,                 \"SRTO_MAXBW\", RestrictionType::POST, sizeof(int64_t),      int64_t(-1),  INT64_MAX, int64_t(-1), int64_t(200000),  {int64_t(-2)},    R | W | G | S | D | O | O },\n+    { SRTO_LOSSMAXTTL,       \"SRTO_LOSSMAXTTL\", RestrictionType::POST,    sizeof(int),                 0, INT32_MAX,        0,           10,   {} },\n+    { SRTO_MAXBW,                 \"SRTO_MAXBW\", RestrictionType::POST, sizeof(int64_t),      int64_t(-1),  INT64_MAX, int64_t(-1), int64_t(200000),  {int64_t(-2)}},\n #ifdef ENABLE_MAXREXMITBW\n-    { SRTO_MAXREXMITBW,      \"SRTO_MAXREXMITBW\", RestrictionType::POST, sizeof(int64_t),     int64_t(-1), INT64_MAX,  int64_t(-1), int64_t(200000),  {int64_t(-2)},    R | W | G | S | D | O | O },\n+    { SRTO_MAXREXMITBW,      \"SRTO_MAXREXMITBW\", RestrictionType::POST, sizeof(int64_t),     int64_t(-1), INT64_MAX,  int64_t(-1), int64_t(200000),  {int64_t(-2)}},\n #endif\n-    { SRTO_MESSAGEAPI,       \"SRTO_MESSAGEAPI\", RestrictionType::PRE,    sizeof(bool),             false,      true,     true,        false,     {},                   O | W | G | S | D | O | O },\n-    { SRTO_MININPUTBW,       \"SRTO_MININPUTBW\", RestrictionType::POST, sizeof(int64_t),       int64_t(0),  INT64_MAX,  int64_t(0), int64_t(200000),  {int64_t(-1)},    R | W | G | S | D | O | O },\n-    { SRTO_MINVERSION,       \"SRTO_MINVERSION\", RestrictionType::PRE,     sizeof(int),                 0,  INT32_MAX, 0x010000,    0x010300,    {},                    R | W | G | S | D | O | O },\n-    { SRTO_MSS,                     \"SRTO_MSS\", RestrictionType::PREBIND, sizeof(int),                76,     65536,     1500,        1400,    {-1, 0, 75},            R | W | G | S | D | O | O },\n-    { SRTO_NAKREPORT,         \"SRTO_NAKREPORT\", RestrictionType::PRE,    sizeof(bool),             false,      true,     true,        false,     {},                   R | W | G | S | D | O | M },\n-    { SRTO_OHEADBW,             \"SRTO_OHEADBW\", RestrictionType::POST,    sizeof(int),                 5,        100,       25,          20, {-1, 0, 4, 101},          R | W | G | S | D | O | O },\n+    { SRTO_MESSAGEAPI,       \"SRTO_MESSAGEAPI\", RestrictionType::PRE,    sizeof(bool),             false,      true,     true,        false,     {} },\n+    { SRTO_MININPUTBW,       \"SRTO_MININPUTBW\", RestrictionType::POST, sizeof(int64_t),       int64_t(0),  INT64_MAX,  int64_t(0), int64_t(200000),  {int64_t(-1)}},\n+    { SRTO_MINVERSION,       \"SRTO_MINVERSION\", RestrictionType::PRE,     sizeof(int),                 0,  INT32_MAX, 0x010000,    0x010300,    {} },\n+    { SRTO_MSS,                     \"SRTO_MSS\", RestrictionType::PREBIND, sizeof(int),                76,     65536,     1500,        1400,    {-1, 0, 75} },\n+    { SRTO_NAKREPORT,         \"SRTO_NAKREPORT\", RestrictionType::PRE,    sizeof(bool),             false,      true,     true,        false,     {} },\n+    { SRTO_OHEADBW,             \"SRTO_OHEADBW\", RestrictionType::POST,    sizeof(int),                 5,        100,       25,          20, {-1, 0, 4, 101} },\n     //SRTO_PACKETFILTER\n     //SRTO_PASSPHRASE\n-    { SRTO_PAYLOADSIZE,     \"SRTO_PAYLOADSIZE\", RestrictionType::PRE,     sizeof(int),                 0,      1456,      1316,        1400,   {-1, 1500},             O | W | G | S | D | O | O },\n+    { SRTO_PAYLOADSIZE,     \"SRTO_PAYLOADSIZE\", RestrictionType::PRE,     sizeof(int),                 0,      1456,      1316,        1400,   {-1, 1500} },\n     //SRTO_PBKEYLEN\n-    { SRTO_PEERIDLETIMEO, \"SRTO_PEERIDLETIMEO\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,      5000,        4500,    {-1},                  R | W | G | S | D | O | M },\n-    { SRTO_PEERLATENCY,     \"SRTO_PEERLATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,         0,        180,    {-1},                   R | W | G | S | D | O | O },\n+    //SRTO_PEERIDLETIMEO\n+    { SRTO_PEERIDLETIMEO, \"SRTO_PEERIDLETIMEO\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,      5000,        4500,    {-1} },\n+    { SRTO_PEERLATENCY,     \"SRTO_PEERLATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX,         0,        180,    {-1} },\n     //SRTO_PEERVERSION\n-    { SRTO_RCVBUF,              \"SRTO_RCVBUF\",  RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1},R | W | G | S | D | O | M },\n+    { SRTO_RCVBUF,              \"SRTO_RCVBUF\",  RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} },\n     //SRTO_RCVDATA\n     //SRTO_RCVKMSTATE\n-    { SRTO_RCVLATENCY,       \"SRTO_RCVLATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX, 120, 1100, {-1},                                  R | W | G | S | D | O | O },\n+    { SRTO_RCVLATENCY,       \"SRTO_RCVLATENCY\", RestrictionType::PRE,     sizeof(int),                 0, INT32_MAX, 120, 1100, {-1} },\n     //SRTO_RCVSYN\n-    { SRTO_RCVTIMEO,           \"SRTO_RCVTIMEO\", RestrictionType::POST,    sizeof(int),                -1, INT32_MAX,  -1, 2000, {-2},                                  R | W | G | S | O | I | O },\n+    { SRTO_RCVTIMEO,           \"SRTO_RCVTIMEO\", RestrictionType::POST,    sizeof(int),                -1, INT32_MAX,  -1, 2000, {-2} },\n     //SRTO_RENDEZVOUS\n-    { SRTO_RETRANSMITALGO, \"SRTO_RETRANSMITALGO\", RestrictionType::PRE,   sizeof(int),                 0,         1,   1,    0, {-1, 2},                               R | W | G | S | D | O | O },\n+    { SRTO_RETRANSMITALGO, \"SRTO_RETRANSMITALGO\", RestrictionType::PRE,   sizeof(int),                 0,         1,   1,    0, {-1, 2} },\n     //SRTO_REUSEADDR\n     //SRTO_SENDER\n-    { SRTO_SNDBUF,              \"SRTO_SNDBUF\",  RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1},R | W | G | S | D | O | M },\n+    { SRTO_SNDBUF,              \"SRTO_SNDBUF\",  RestrictionType::PREBIND, sizeof(int), (int)(32 * SRT_PKT_SIZE), 2147483256, (int)(8192 * SRT_PKT_SIZE), 1000000, {-1} },\n     //SRTO_SNDDATA\n-    { SRTO_SNDDROPDELAY,  \"SRTO_SNDDROPDELAY\", RestrictionType::POST,     sizeof(int),                -1, INT32_MAX, 0, 1500, {-2},                                    O | W | G | S | D | O | M },\n+    { SRTO_SNDDROPDELAY,  \"SRTO_SNDDROPDELAY\", RestrictionType::POST,     sizeof(int),                -1, INT32_MAX, 0, 1500, {-2} },\n     //SRTO_SNDKMSTATE\n     //SRTO_SNDSYN\n-    { SRTO_SNDTIMEO,          \"SRTO_SNDTIMEO\", RestrictionType::POST,     sizeof(int),                -1, INT32_MAX, -1, 1400, {-2},                                   R | W | G | S | O | I | O },\n+    { SRTO_SNDTIMEO,          \"SRTO_SNDTIMEO\", RestrictionType::POST,     sizeof(int),                -1, INT32_MAX, -1, 1400, {-2} },\n     //SRTO_STATE\n     //SRTO_STREAMID\n-    { SRTO_TLPKTDROP,        \"SRTO_TLPKTDROP\",  RestrictionType::PRE,    sizeof(bool),             false,      true,     true, false, {},                              R | W | G | S | D | O | O },\n+    { SRTO_TLPKTDROP,        \"SRTO_TLPKTDROP\",  RestrictionType::PRE,    sizeof(bool),             false,      true,     true, false, {} },\n     //SRTO_TRANSTYPE\n     //SRTO_TSBPDMODE\n     //SRTO_UDP_RCVBUF\n     //SRTO_UDP_SNDBUF\n     //SRTO_VERSION\n };\n-} // end namespace Table\n-\n-using Table::g_test_matrix_options;\n \n-template<class ValueType>\n-void CheckGetSockOptMustFail(const OptionTestEntry& entry, SRTSOCKET sock, const char* desc)\n-{\n-    ValueType opt_val;\n-    int opt_len = (int)entry.opt_len;\n-    EXPECT_NE(srt_getsockopt(sock, 0, entry.optid, &opt_val, &opt_len), SRT_SUCCESS)\n-        << desc << \" Getting \" << entry.optname << \" must fail, but succeeded.\";\n-}\n \n template<class ValueType>\n void CheckGetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueType& value, const char* desc)\n@@ -402,16 +249,16 @@ void CheckGetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueTy\n     EXPECT_EQ(opt_len, (int) entry.opt_len) << desc << \"Wrong \" << entry.optname << \" value length\";\n }\n \n-using strptr = const char *;\n+typedef char const* strptr;\n template<>\n void CheckGetSockOpt<strptr>(const OptionTestEntry& entry, SRTSOCKET sock, const strptr& value, const char* desc)\n {\n-    std::array<char, 16> opt_val;\n+    char opt_val[16];\n     int opt_len = 0;\n-    EXPECT_EQ(srt_getsockopt(sock, 0, entry.optid, opt_val.data(), &opt_len), SRT_SUCCESS)\n+    EXPECT_EQ(srt_getsockopt(sock, 0, entry.optid, &opt_val, &opt_len), SRT_SUCCESS)\n         << \"Getting \" << entry.optname << \" returned error: \" << srt_getlasterror_str();\n \n-    EXPECT_EQ(strncmp(opt_val.data(), value, min(opt_len, (int)entry.opt_len)), 0) << desc << \": Wrong \" << entry.optname << \" value \" << opt_val.data();\n+    EXPECT_EQ(strncmp(opt_val, value, min(opt_len, (int)entry.opt_len)), 0) << desc << \": Wrong \" << entry.optname << \" value \" << opt_val;\n     EXPECT_EQ(opt_len, (int) entry.opt_len) << desc << \"Wrong \" << entry.optname << \" value length\";\n }\n \n@@ -433,7 +280,6 @@ void CheckSetSockOpt(const OptionTestEntry& entry, SRTSOCKET sock, const ValueTy\n template<class ValueType>\n bool CheckDefaultValue(const OptionTestEntry& entry, SRTSOCKET sock, const char* desc)\n {\n-    LOGD(cerr << \"Will check default value: \" << entry.optname << \" = \" << to_string(entry.dflt_val) << \": \" << desc << endl);\n     try {\n         const ValueType dflt_val = linb::any_cast<ValueType>(entry.dflt_val);\n         CheckGetSockOpt<ValueType>(entry, sock, dflt_val, desc);\n@@ -509,7 +355,6 @@ bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char\n {\n     for (const auto& inval : entry.invalid_vals)\n     {\n-        LOGD(cerr << \"Will check INVALID value: \" << entry.optname << \" : \" << to_string(inval) << \": \" << sock_name << endl);\n         try {\n             const ValueType val = linb::any_cast<ValueType>(inval);\n             CheckSetSockOpt<ValueType>(entry, sock, val, SRT_ERROR, sock_name);\n@@ -524,76 +369,26 @@ bool CheckInvalidValues(const OptionTestEntry& entry, SRTSOCKET sock, const char\n     return true;\n }\n \n-void TestDefaultValues(SRTSOCKET s)\n+TEST_F(TestSocketOptions, DefaultVals)\n {\n-    const char* test_desc = \"[Caller, default]\";\n     for (const auto& entry : g_test_matrix_options)\n     {\n-        // Check flags. An option must be RW to test default value\n-        const bool is_group = (s & SRTGROUP_MASK) != 0;\n-\n-        if (!(entry.flags & Flags::R))\n-        {\n-            // TODO: Check reading returns an error.\n-            LOGD(cerr << \"Skipping \" << entry.optname << \": not readable.\\n\");\n-            continue; // The flag must be READABLE and WRITABLE for this.\n-        }\n-\n-        // Check that retrieving a value must fail if the option is not a group option read on a group and not a socket\n-        // option read on a socket.\n-        bool readable = true;\n-        if (is_group)\n-        {\n-            readable = entry.allof(Flags::G) && entry.anyof(Flags::I, Flags::D);\n-            LOGD(cerr << \"Group option \" << entry.optname << \": expected \" << (readable? \"\" : \"NOT \") << \"readable\\n\");\n-        }\n-        else\n-        {\n-            readable = entry.allof(Flags::S);\n-            LOGD(cerr << \"Socket option \" << entry.optname << \": expected \" << (readable? \"\" : \"NOT \") << \"readable\\n\");\n-        }\n-\n-        if (!readable)\n-        {\n-            if (entry.dflt_val.type() == typeid(bool))\n-            {\n-                CheckGetSockOptMustFail<bool>(entry, s, test_desc);\n-            }\n-            else if (entry.dflt_val.type() == typeid(int))\n-            {\n-                CheckGetSockOptMustFail<int>(entry, s, test_desc);\n-            }\n-            else if (entry.dflt_val.type() == typeid(int64_t))\n-            {\n-                CheckGetSockOptMustFail<int64_t>(entry, s, test_desc);\n-            }\n-            else if (entry.dflt_val.type() == typeid(const char*))\n-            {\n-                CheckGetSockOptMustFail<const char*>(entry, s, test_desc);\n-            }\n-            else\n-            {\n-                FAIL() << entry.optname << \": Unexpected type \" << entry.dflt_val.type().name();\n-            }\n-\n-            continue; // s is group && The option is not groupwise-individual option\n-        }\n-\n+        const char* test_desc = \"[Caller, default]\";\n         if (entry.dflt_val.type() == typeid(bool))\n         {\n-            EXPECT_TRUE(CheckDefaultValue<bool>(entry, s, test_desc));\n+            EXPECT_TRUE(CheckDefaultValue<bool>(entry, m_caller_sock, test_desc));\n         }\n         else if (entry.dflt_val.type() == typeid(int))\n         {\n-            EXPECT_TRUE(CheckDefaultValue<int>(entry, s, test_desc));\n+            EXPECT_TRUE(CheckDefaultValue<int>(entry, m_caller_sock, test_desc));\n         }\n         else if (entry.dflt_val.type() == typeid(int64_t))\n         {\n-            EXPECT_TRUE(CheckDefaultValue<int64_t>(entry, s, test_desc));\n+            EXPECT_TRUE(CheckDefaultValue<int64_t>(entry, m_caller_sock, test_desc));\n         }\n         else if (entry.dflt_val.type() == typeid(const char*))\n         {\n-            EXPECT_TRUE(CheckDefaultValue<const char*>(entry, s, test_desc));\n+            EXPECT_TRUE(CheckDefaultValue<const char*>(entry, m_caller_sock, test_desc));\n         }\n         else\n         {\n@@ -602,34 +397,11 @@ void TestDefaultValues(SRTSOCKET s)\n     }\n }\n \n-TEST_F(TestSocketOptions, DefaultVals)\n-{\n-    TestDefaultValues(m_caller_sock);\n-}\n-\n-#if ENABLE_BONDING\n-TEST_F(TestGroupOptions, DefaultVals)\n-{\n-    SRTST_REQUIRES(Bonding);\n-    TestDefaultValues(m_caller_sock);\n-}\n-#endif\n-\n TEST_F(TestSocketOptions, MaxVals)\n {\n     // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation\n     for (const auto& entry : g_test_matrix_options)\n     {\n-        if (!(entry.flags & Flags::R))\n-        {\n-            cerr << \"Skipping \" << entry.optname << \": option not readable\\n\";\n-        }\n-\n-        if (!(entry.flags & Flags::W))\n-        {\n-            cerr << \"Skipping \" << entry.optname << \": option not writable\\n\";\n-        }\n-\n         if (entry.optid == SRTO_KMPREANNOUNCE || entry.optid == SRTO_KMREFRESHRATE)\n         {\n             cerr << \"Skipping \" << entry.optname << \"\\n\";\n@@ -663,16 +435,6 @@ TEST_F(TestSocketOptions, MinVals)\n     // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation\n     for (const auto& entry : g_test_matrix_options)\n     {\n-        if (!(entry.flags & Flags::R))\n-        {\n-            cerr << \"Skipping \" << entry.optname << \": option not readable\\n\";\n-        }\n-\n-        if (!(entry.flags & Flags::W))\n-        {\n-            cerr << \"Skipping \" << entry.optname << \": option not writable\\n\";\n-        }\n-\n         const char* test_desc = \"[Caller, min val]\";\n         if (entry.min_val.type() == typeid(bool))\n         {\n@@ -695,28 +457,23 @@ TEST_F(TestSocketOptions, MinVals)\n     }\n }\n \n-void TestInvalidValues(SRTSOCKET s)\n+TEST_F(TestSocketOptions, InvalidVals)\n {\n     // Note: Changing SRTO_FC changes SRTO_RCVBUF limitation\n     for (const auto& entry : g_test_matrix_options)\n     {\n-        if (!(entry.flags & Flags::W))\n-        {\n-            cerr << \"Skipping \" << entry.optname << \": option not writable\\n\";\n-        }\n-\n-        const char* desc = \"[Group Caller, invalid val]\";\n+        const char* desc = \"[Caller, invalid val]\";\n         if (entry.dflt_val.type() == typeid(bool))\n         {\n-            EXPECT_TRUE(CheckInvalidValues<bool>(entry, s, desc));\n+            EXPECT_TRUE(CheckInvalidValues<bool>(entry, m_caller_sock, desc));\n         }\n         else if (entry.dflt_val.type() == typeid(int))\n         {\n-            EXPECT_TRUE(CheckInvalidValues<int>(entry, s, desc));\n+            EXPECT_TRUE(CheckInvalidValues<int>(entry, m_caller_sock, desc));\n         }\n         else if (entry.dflt_val.type() == typeid(int64_t))\n         {\n-            EXPECT_TRUE(CheckInvalidValues<int64_t>(entry, s, desc));\n+            EXPECT_TRUE(CheckInvalidValues<int64_t>(entry, m_caller_sock, desc));\n         }\n         else\n         {\n@@ -727,36 +484,25 @@ void TestInvalidValues(SRTSOCKET s)\n     }\n }\n \n-TEST_F(TestSocketOptions, InvalidVals)\n-{\n-    TestInvalidValues(m_caller_sock);\n-}\n \n \n-#if ENABLE_BONDING\n-TEST_F(TestGroupOptions, InvalidVals)\n-{\n-    SRTST_REQUIRES(Bonding);\n-    TestInvalidValues(m_caller_sock);\n-}\n-#endif\n-\n-const char* StateToStr(SRT_SOCKSTATUS st)\n-{\n-    std::map<SRT_SOCKSTATUS, const char* const> st_to_str = {\n-        { SRTS_INIT,       \"SRTS_INIT\" },\n-        { SRTS_OPENED,     \"SRTS_OPENED\" },\n-        { SRTS_LISTENING,  \"SRTS_LISTENING\" },\n-        { SRTS_CONNECTING, \"SRTS_CONNECTING\" },\n-        { SRTS_CONNECTED,  \"SRTS_CONNECTED\" },\n-        { SRTS_BROKEN,     \"SRTS_BROKEN\" },\n-        { SRTS_CLOSING,    \"SRTS_CLOSING\" },\n-        { SRTS_CLOSED,     \"SRTS_CLOSED\" },\n-        { SRTS_NONEXIST,   \"SRTS_NONEXIST\" }\n-    };\n+// TODO: taken from test_enforced_encryption\n+static const char* const socket_state_array[] = {\n+    \"IGNORE_SRTS\",\n+    \"SRTS_INVALID\",\n+    \"SRTS_INIT\",\n+    \"SRTS_OPENED\",\n+    \"SRTS_LISTENING\",\n+    \"SRTS_CONNECTING\",\n+    \"SRTS_CONNECTED\",\n+    \"SRTS_BROKEN\",\n+    \"SRTS_CLOSING\",\n+    \"SRTS_CLOSED\",\n+    \"SRTS_NONEXIST\"\n+};\n \n-    return st_to_str.find(st) != st_to_str.end() ? st_to_str.at(st) : \"INVALID\";\n-}\n+// A trick that allows the array to be indexed by -1\n+const char* const* g_socket_state = socket_state_array + 1;\n \n #if 0\n // No socket option can be set in blocking mode because m_ConnectionLock is required by both srt_setsockopt and srt_connect\n@@ -805,17 +551,17 @@ TEST_F(TestSocketOptions, RestrictionBind)\n         if (entry.dflt_val.type() == typeid(bool))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<bool>(entry, m_listen_sock, expected_res, test_desc))\n-                << \"Sock state : \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << \"Sock state : \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else if (entry.dflt_val.type() == typeid(int))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<int>(entry, m_listen_sock, expected_res, test_desc))\n-                << \"Sock state : \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << \"Sock state : \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else if (entry.dflt_val.type() == typeid(int64_t))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<int64_t>(entry, m_listen_sock, expected_res, test_desc))\n-                << \"Sock state : \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << \"Sock state : \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else\n         {\n@@ -839,17 +585,17 @@ TEST_F(TestSocketOptions, RestrictionListening)\n         if (entry.dflt_val.type() == typeid(bool))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<bool>(entry, m_listen_sock, expected_res, test_desc))\n-                << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else if (entry.dflt_val.type() == typeid(int))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<int>(entry, m_listen_sock, expected_res, test_desc))\n-                << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else if (entry.dflt_val.type() == typeid(int64_t))\n         {\n             EXPECT_TRUE(CheckSetNonDefaultValue<int64_t>(entry, m_listen_sock, expected_res, test_desc))\n-                << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(m_listen_sock));\n+                << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(m_listen_sock)];\n         }\n         else\n         {\n@@ -876,17 +622,17 @@ TEST_F(TestSocketOptions, RestrictionConnected)\n             if (entry.dflt_val.type() == typeid(bool))\n             {\n                 EXPECT_TRUE(CheckSetNonDefaultValue<bool>(entry, sock, expected_res, test_desc))\n-                    << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(sock));\n+                    << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(sock)];\n             }\n             else if (entry.dflt_val.type() == typeid(int))\n             {\n                 EXPECT_TRUE(CheckSetNonDefaultValue<int>(entry, sock, expected_res, test_desc))\n-                    << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(sock));\n+                    << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(sock)];\n             }\n             else if (entry.dflt_val.type() == typeid(int64_t))\n             {\n                 EXPECT_TRUE(CheckSetNonDefaultValue<int64_t>(entry, sock, expected_res, test_desc))\n-                    << test_desc << entry.optname << \" Sock state: \" << StateToStr(srt_getsockstate(sock));\n+                    << test_desc << entry.optname << \" Sock state: \" << g_socket_state[srt_getsockstate(sock)];\n             }\n             else\n             {\n@@ -1037,7 +783,7 @@ TEST_F(TestSocketOptions, MinInputBWSet)\n {\n     const int64_t mininputbw_dflt = 0;\n     const int64_t mininputbw = 50000000;\n-    auto optlen = (int)(sizeof mininputbw);\n+    int optlen = (int)(sizeof mininputbw);\n \n     int64_t bw = -100;\n     EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_MININPUTBW, &bw, sizeof bw), SRT_ERROR) << \"Has to be a non-negative number\";\n@@ -1103,15 +849,15 @@ TEST_F(TestSocketOptions, MinInputBWRuntime)\n \n TEST_F(TestSocketOptions, StreamIDWrongLen)\n {\n-    std::array<char, CSrtConfig::MAX_SID_LENGTH + 135> buffer;\n-    for (size_t i = 0; i < buffer.size(); ++i)\n+    char buffer[CSrtConfig::MAX_SID_LENGTH + 135];\n+    for (size_t i = 0; i < sizeof buffer; ++i)\n         buffer[i] = 'a' + i % 25;\n \n-    EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), CSrtConfig::MAX_SID_LENGTH + 1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer, CSrtConfig::MAX_SID_LENGTH+1), SRT_ERROR);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n }\n \n-// Check if setting -1 as optlen returns an error \n+//Check if setting -1 as optlen returns an error \n TEST_F(TestSocketOptions, StringOptLenInvalid)\n {\n     const string test_string = \"test1234567\";\n@@ -1119,19 +865,19 @@ TEST_F(TestSocketOptions, StringOptLenInvalid)\n     const string fec_config = \"fec,cols:10,rows:10\";\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, test_string.c_str(), -1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_BINDTODEVICE, test_string.c_str(), -1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_CONGESTION, srto_congestion_string.c_str(), -1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_PACKETFILTER, fec_config.c_str(), -1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_PASSPHRASE, test_string.c_str(), -1), SRT_ERROR);\n-    EXPECT_EQ(srt_getlasterror(nullptr), SRT_EINVPARAM);\n+    EXPECT_EQ(srt_getlasterror(NULL), SRT_EINVPARAM);\n }\n \n // Try to set/get a 13-character string in SRTO_STREAMID.\n@@ -1144,22 +890,23 @@ TEST_F(TestSocketOptions, StreamIDOdd)\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_odd.c_str(), (int)sid_odd.size()), SRT_SUCCESS);\n \n-    std::array<char, CSrtConfig::MAX_SID_LENGTH + 135> buffer;\n-    auto buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n-    EXPECT_EQ(std::string(buffer.data()), sid_odd);\n+    char buffer[CSrtConfig::MAX_SID_LENGTH + 135];\n+    int buffer_len = sizeof buffer;\n+    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n+    EXPECT_EQ(std::string(buffer), sid_odd);\n     EXPECT_EQ(size_t(buffer_len), sid_odd.size());\n-    EXPECT_EQ(strlen(buffer.data()), sid_odd.size());\n+    EXPECT_EQ(strlen(buffer), sid_odd.size());\n \n     StartListener();\n     const SRTSOCKET accepted_sock = EstablishConnection();\n \n     // Check accepted socket inherits values\n-    fill(buffer.begin(), buffer.end(), 'a');\n-    buffer_len = (int) buffer.size();\n+    for (size_t i = 0; i < sizeof buffer; ++i)\n+        buffer[i] = 'a';\n+    buffer_len = (int)(sizeof buffer);\n     EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n     EXPECT_EQ(size_t(buffer_len), sid_odd.size());\n-    EXPECT_EQ(strlen(buffer.data()), sid_odd.size());\n+    EXPECT_EQ(strlen(buffer), sid_odd.size());\n \n     ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);\n }\n@@ -1172,22 +919,23 @@ TEST_F(TestSocketOptions, StreamIDEven)\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_even.c_str(), (int)sid_even.size()), SRT_SUCCESS);\n \n-    array<char, CSrtConfig::MAX_SID_LENGTH + 135> buffer;\n-    auto buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n-    EXPECT_EQ(std::string(buffer.data()), sid_even);\n+    char buffer[CSrtConfig::MAX_SID_LENGTH + 135];\n+    int buffer_len = sizeof buffer;\n+    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n+    EXPECT_EQ(std::string(buffer), sid_even);\n     EXPECT_EQ(size_t(buffer_len), sid_even.size());\n-    EXPECT_EQ(strlen(buffer.data()), sid_even.size());\n+    EXPECT_EQ(strlen(buffer), sid_even.size());\n \n     StartListener();\n     const SRTSOCKET accepted_sock = EstablishConnection();\n \n     // Check accepted socket inherits values\n-    fill(buffer.begin(), buffer.end(), 'a');\n-    buffer_len = (int) buffer.size();\n+    for (size_t i = 0; i < sizeof buffer; ++i)\n+        buffer[i] = 'a';\n+    buffer_len = (int)(sizeof buffer);\n     EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n     EXPECT_EQ(size_t(buffer_len), sid_even.size());\n-    EXPECT_EQ(strlen(buffer.data()), sid_even.size());\n+    EXPECT_EQ(strlen(buffer), sid_even.size());\n \n     ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);\n }\n@@ -1197,18 +945,20 @@ TEST_F(TestSocketOptions, StreamIDEven)\n TEST_F(TestSocketOptions, StreamIDAlmostFull)\n {\n     // 12 characters = 4*3, that is, aligned to 4\n-    array<char, CSrtConfig::MAX_SID_LENGTH - 2> sid_almost_full;\n+    std::array<char, CSrtConfig::MAX_SID_LENGTH - 2> sid_almost_full;\n     const size_t size = sid_almost_full.size();\n+    for (size_t i = 0; i < size; ++i)\n+        sid_almost_full[i] += 'x';\n+\n     // Just to manipulate the last ones.\n-    sid_almost_full.fill('x');\n     sid_almost_full[size-2] = '\\0';\n     sid_almost_full[size-1] = 'z';\n \n     EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_almost_full.data(), (int)size), SRT_SUCCESS);\n \n     std::array<char, CSrtConfig::MAX_SID_LENGTH + 135> buffer;\n-    auto buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n+    int buffer_len = (int) buffer.size();\n+    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n     EXPECT_EQ(size_t(buffer_len), sid_almost_full.size());\n     EXPECT_EQ(std::memcmp(buffer.data(), sid_almost_full.data(), buffer_len), 0);\n \n@@ -1217,7 +967,8 @@ TEST_F(TestSocketOptions, StreamIDAlmostFull)\n \n     // Check accepted socket inherits values\n     buffer_len = (int) buffer.size();\n-    fill(buffer.begin(), buffer.end(), 'a');\n+    for (int i = 0; i < buffer_len; ++i)\n+        buffer[i] = 'a';\n     EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n     EXPECT_EQ(size_t(buffer_len), sid_almost_full.size());\n     EXPECT_EQ(std::memcmp(buffer.data(), sid_almost_full.data(), buffer_len), 0);\n@@ -1230,31 +981,35 @@ TEST_F(TestSocketOptions, StreamIDAlmostFull)\n TEST_F(TestSocketOptions, StreamIDFull)\n {\n     // 12 characters = 4*3, that is, aligned to 4\n-    array<char, CSrtConfig::MAX_SID_LENGTH> sid_full;\n-    sid_full.fill('x');\n+    string sid_full;\n+    for (size_t i = 0; i < CSrtConfig::MAX_SID_LENGTH; ++i)\n+        sid_full += 'x';\n \n     // Just to manipulate the last ones.\n     size_t size = sid_full.size();\n-    sid_full[size-2] = '\\0';\n+    sid_full[size-2] = 'y';\n     sid_full[size-1] = 'z';\n \n-    EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_full.data(), (int)sid_full.size()), SRT_SUCCESS);\n+    EXPECT_EQ(srt_setsockopt(m_caller_sock, 0, SRTO_STREAMID, sid_full.c_str(), (int)sid_full.size()), SRT_SUCCESS);\n \n-    array<char, CSrtConfig::MAX_SID_LENGTH + 135> buffer;\n-    auto buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n-    EXPECT_EQ(memcmp(buffer.data(), sid_full.data(), sid_full.size()), 0);\n+    char buffer[CSrtConfig::MAX_SID_LENGTH + 135];\n+    int buffer_len = sizeof buffer;\n+    EXPECT_EQ(srt_getsockopt(m_caller_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n+    EXPECT_EQ(std::string(buffer), sid_full);\n     EXPECT_EQ(size_t(buffer_len), sid_full.size());\n+    EXPECT_EQ(strlen(buffer), sid_full.size());\n \n     StartListener();\n     const SRTSOCKET accepted_sock = EstablishConnection();\n \n     // Check accepted socket inherits values\n-    fill(buffer.begin(), buffer.end(), 'a');\n-    buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n+    for (size_t i = 0; i < sizeof buffer; ++i)\n+        buffer[i] = 'a';\n+    buffer_len = (int)(sizeof buffer);\n+    EXPECT_EQ(srt_getsockopt(accepted_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n     EXPECT_EQ(size_t(buffer_len), sid_full.size());\n-    EXPECT_EQ(std::memcmp(buffer.data(), sid_full.data(), buffer_len), 0);\n+    EXPECT_EQ(strlen(buffer), sid_full.size());\n+    EXPECT_EQ(buffer[sid_full.size()-1], 'z');\n \n     ASSERT_NE(srt_close(accepted_sock), SRT_ERROR);\n }\n@@ -1267,10 +1022,10 @@ TEST_F(TestSocketOptions, StreamIDLenListener)\n \n     EXPECT_EQ(srt_setsockopt(m_listen_sock, 0, SRTO_STREAMID, stream_id_13.c_str(), (int)stream_id_13.size()), SRT_SUCCESS);\n \n-    array<char, 648> buffer;\n-    auto buffer_len = (int) buffer.size();\n-    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n-    EXPECT_EQ(string(buffer.data()), stream_id_13);\n+    char buffer[648];\n+    int buffer_len = sizeof buffer;\n+    EXPECT_EQ(srt_getsockopt(m_listen_sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n+    EXPECT_EQ(string(buffer), stream_id_13);\n     EXPECT_EQ(size_t(buffer_len), stream_id_13.size());\n \n     StartListener();\n@@ -1279,9 +1034,9 @@ TEST_F(TestSocketOptions, StreamIDLenListener)\n     // Check accepted and caller sockets do not inherit StreamID.\n     for (SRTSOCKET sock : { m_caller_sock, accepted_sock })\n     {\n-        buffer_len = (int) buffer.size();\n-        fill_n(buffer.data(), buffer_len, 'a');\n-        EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_STREAMID, buffer.data(), &buffer_len), SRT_SUCCESS);\n+        buffer_len = (int)(sizeof buffer);\n+        fill_n(buffer, buffer_len, 'a');\n+        EXPECT_EQ(srt_getsockopt(sock, 0, SRTO_STREAMID, &buffer, &buffer_len), SRT_SUCCESS);\n         EXPECT_EQ(buffer_len, 0) << (sock == accepted_sock ? \"ACCEPTED\" : \"CALLER\");\n     }\n \ndiff --git a/test/test_sync.cpp b/test/test_sync.cpp\nindex ffbbc2b..d06b5e5 100644\n--- a/test/test_sync.cpp\n+++ b/test/test_sync.cpp\n@@ -609,8 +609,6 @@ TEST(SyncThread, Joinable)\n     EXPECT_FALSE(foo.joinable());\n }\n \n-#if !HAVE_CXX17\n-\n /*****************************************************************************/\n /*\n  * SharedMutex\n@@ -695,7 +693,6 @@ TEST(SharedMutex, LockedReadCount)\n     EXPECT_TRUE(mut.try_lock());\n }\n \n-#endif\n \n /*****************************************************************************/\n /*\n@@ -740,14 +737,14 @@ TEST(Sync, FormatTime)\n     const string time4 = FormatTime(a + seconds_from(1));\n     const string time5 = FormatTime(a + seconds_from(5));\n     const string time6 = FormatTime(a + milliseconds_from(-4350));\n-    cerr << \"Current time formatted:    \" << time1 << endl;\n+    cerr << \"Current time formated:    \" << time1 << endl;\n     const long long diff_2_1 = parse_time(time2) - parse_time(time1);\n-    cerr << \"Same time formatted again: \" << time2 << \" (\" << diff_2_1 << \" us)\" << endl;\n-    print_timediff(\"Same time formatted again: \", time2, time1);\n-    print_timediff(\"Time +500 ms formatted:    \", time3, time1);\n-    print_timediff(\"Time +1  sec formatted:    \", time4, time1);\n-    print_timediff(\"Time +5  sec formatted:    \", time5, time1);\n-    print_timediff(\"Time -4350 ms formatted:   \", time6, time1);\n+    cerr << \"Same time formated again: \" << time2 << \" (\" << diff_2_1 << \" us)\" << endl;\n+    print_timediff(\"Same time formated again: \", time2, time1);\n+    print_timediff(\"Time +500 ms formated:    \", time3, time1);\n+    print_timediff(\"Time +1  sec formated:    \", time4, time1);\n+    print_timediff(\"Time +5  sec formated:    \", time5, time1);\n+    print_timediff(\"Time -4350 ms formated:   \", time6, time1);\n \n     EXPECT_TRUE(time1 == time2);\n }\n@@ -782,14 +779,14 @@ TEST(Sync, FormatTimeSys)\n     const string                   time4 = FormatTimeSys(a + seconds_from(1));\n     const string                   time5 = FormatTimeSys(a + seconds_from(5));\n     const string                   time6 = FormatTimeSys(a + milliseconds_from(-4350));\n-    cerr << \"Current time formatted:    \" << time1 << endl;\n+    cerr << \"Current time formated:    \" << time1 << endl;\n     const long long diff_2_1 = parse_time(time2) - parse_time(time1);\n-    cerr << \"Same time formatted again: \" << time2 << \" (\" << diff_2_1 << \" us)\" << endl;\n-    print_timediff(\"Same time formatted again: \", time2, time1);\n-    print_timediff(\"Time +500 ms formatted:    \", time3, time1);\n-    print_timediff(\"Time +1  sec formatted:    \", time4, time1);\n-    print_timediff(\"Time +5  sec formatted:    \", time5, time1);\n-    print_timediff(\"Time -4350 ms formatted:   \", time6, time1);\n+    cerr << \"Same time formated again: \" << time2 << \" (\" << diff_2_1 << \" us)\" << endl;\n+    print_timediff(\"Same time formated again: \", time2, time1);\n+    print_timediff(\"Time +500 ms formated:    \", time3, time1);\n+    print_timediff(\"Time +1  sec formated:    \", time4, time1);\n+    print_timediff(\"Time +5  sec formated:    \", time5, time1);\n+    print_timediff(\"Time -4350 ms formated:   \", time6, time1);\n \n     EXPECT_TRUE(time1 == time2);\n }\ndiff --git a/test/test_utilities.cpp b/test/test_utilities.cpp\nindex d14f5f9..28c1404 100644\n--- a/test/test_utilities.cpp\n+++ b/test/test_utilities.cpp\n@@ -22,7 +22,7 @@ struct Double\n     Double(): d(0.0)\n     {\n         instance = ++sourceid;\n-        IF_HEAVY_LOGGING(cerr << \"(Double/\" << instance << \": empty construction)\\n\");\n+        IF_HEAVY_LOGGING(cerr << \"(Double/\" << instance << \": empty costruction)\\n\");\n     }\n \n     Double(double dd): d(dd)\n@@ -272,4 +272,3 @@ TEST(ConfigString, Setting)\n     EXPECT_EQ(s.size(), 0U);\n     EXPECT_TRUE(s.empty());\n }\n-\ndiff --git a/testing/srt-test-live.cpp b/testing/srt-test-live.cpp\nindex abc37e0..12478e4 100644\n--- a/testing/srt-test-live.cpp\n+++ b/testing/srt-test-live.cpp\n@@ -934,7 +934,7 @@ int main( int argc, char** argv )\n \n         if (!skip_flushing)\n         {\n-            Verror(\"(DEBUG) EOF when reading file. Looping until the sending buffer depletes.\\n\");\n+            Verror(\"(DEBUG) EOF when reading file. Looping until the sending bufer depletes.\\n\");\n             for (;;)\n             {\n                 size_t still = tar->Still();\n@@ -1011,7 +1011,7 @@ void TestLogHandler(void* opaque, int level, const char* file, int line, const c\n \n #ifdef _MSC_VER\n     // That's something weird that happens on Microsoft Visual Studio 2013\n-    // Trying to keep portability, while every version of MSVS is a different platform.\n+    // Trying to keep portability, while every version of MSVS is a different plaform.\n     // On MSVS 2015 there's already a standard-compliant snprintf, whereas _snprintf\n     // is available on backward compatibility and it doesn't work exactly the same way.\n #define snprintf _snprintf\ndiff --git a/testing/srt-test-mpbond.cpp b/testing/srt-test-mpbond.cpp\nindex 3635ff5..157fa97 100644\n--- a/testing/srt-test-mpbond.cpp\n+++ b/testing/srt-test-mpbond.cpp\n@@ -274,7 +274,7 @@ int main( int argc, char** argv )\n \n         if (!skip_flushing)\n         {\n-            Verror() << \"(DEBUG) EOF when reading file. Looping until the sending buffer depletes.\\n\";\n+            Verror() << \"(DEBUG) EOF when reading file. Looping until the sending bufer depletes.\\n\";\n             for (;;)\n             {\n                 size_t still = tar->Still();\ndiff --git a/testing/srt-test-multiplex.cpp b/testing/srt-test-multiplex.cpp\nindex 31dc0b5..857557a 100644\n--- a/testing/srt-test-multiplex.cpp\n+++ b/testing/srt-test-multiplex.cpp\n@@ -436,7 +436,7 @@ void Help(string program)\n \"The URIs specified as -i INPUT... will be used for input and therefore SRT for output,\\n\"\n \"and in the other way around if you use -o OUTPUT...\\n\"\n \"For every such URI you must specify additionally a parameter named 'id', which will be\\n\"\n-\"interpreted by the application and used to set resource id on an SRT socket when connecting\\n\"\n+\"interperted by the application and used to set resource id on an SRT socket when connecting\\n\"\n \"or to match with the id extracted from the accepted socket of incoming connection.\\n\"\n \"Example:\\n\"\n \"\\tSender:    srt-multiplex srt://remhost:2000 -i udp://:5000?id=low udp://:6000?id=high\\n\"\n@@ -501,7 +501,7 @@ int main( int argc, char** argv )\n     // Extra parameters:\n     //\n     // mode: caller/listener/rendezvous. Default: if host empty, listener, otherwise caller.\n-    // adapter: IP to select network device for listener or rendezvous. Default: for listener taken from host, otherwise 0.0.0.0\n+    // adapter: IP to select network device for listner or rendezvous. Default: for listener taken from host, otherwise 0.0.0.0\n     // port: default=0. Used only for caller mode, sets the outgoing port number. If 0, system-selected (default behavior)\n     //\n     // Syntax cases for -i:\n@@ -511,7 +511,7 @@ int main( int argc, char** argv )\n     //\n     // Syntax cases for -o:\n     //\n-    // EMPTY ARGS...: use 'output%.dat' file pattern for every stream.\n+    // EMPTY ARGS...: use 'output%.dat' file patter for every stream.\n     // PATTERN (one argument that contains % somewhere): define the output file pattern\n     // URI...: try to match the input stream to particular URI by 'name' parameter. If none matches, ignore.\n \ndiff --git a/testing/srt-test-relay.cpp b/testing/srt-test-relay.cpp\nindex d22cba4..912af55 100755\n--- a/testing/srt-test-relay.cpp\n+++ b/testing/srt-test-relay.cpp\n@@ -240,7 +240,7 @@ int main( int argc, char** argv )\n \n     if (input_spec != \"\" && input_echoback)\n     {\n-        cerr << \"ERROR: input-echoback is treated as input specification, -i can't be specified together.\\n\";\n+        cerr << \"ERROR: input-echoback is treated as input specifcation, -i can't be specified together.\\n\";\n         return 1;\n     }\n \n@@ -274,7 +274,7 @@ int main( int argc, char** argv )\n     for (auto& s: output_spec)\n         Verb() << \"\\t\" << s;\n \n-#if defined(_MSC_VER) || defined(__MINGW32__)\n+#ifdef _MSC_VER\n \t// Replacement for sigaction, just use 'signal'\n \t// This may make this working kinda impaired and unexpected,\n \t// but still better that not compiling at all.\n@@ -375,7 +375,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin\n     {\n         // Initialize input medium and do not add SRT medium\n         // to the output list, as this will be fed directly\n-        // by the data from this input medium in a separate engine.\n+        // by the data from this input medium in a spearate engine.\n         Verb() << \"Setting up input: \" << input_spec;\n         m_input_medium.Setup(Source::Create(input_spec), g_chunksize);\n \ndiff --git a/testing/testactivemedia.cpp b/testing/testactivemedia.cpp\nindex 5e75ecc..dd0393e 100644\n--- a/testing/testactivemedia.cpp\n+++ b/testing/testactivemedia.cpp\n@@ -43,7 +43,7 @@ MediaPacket SourceMedium::Extract()\n         }\n         else\n         {\n-            // Don't worry about the media status as long as you have something in the buffer.\n+            // Don't worry about the media status as long as you have somthing in the buffer.\n             // Purge the buffer first, then worry about the other things.\n             if (!running)\n             {\ndiff --git a/testing/testmedia.cpp b/testing/testmedia.cpp\nindex 90b02a7..a7eb054 100755\n--- a/testing/testmedia.cpp\n+++ b/testing/testmedia.cpp\n@@ -1513,7 +1513,7 @@ void SrtCommon::UpdateGroupStatus(const SRT_SOCKGROUPDATA* grpdata, size_t grpda\n     {\n         // This happens when you passed too small array. Treat this as error and stop.\n         cerr << \"ERROR: broadcast group update reports \" << grpdata_size\n-            << \" existing sockets, but app registered only \" << m_group_nodes.size() << endl;\n+            << \" existing sockets, but app registerred only \" << m_group_nodes.size() << endl;\n         Error(\"Too many unpredicted sockets in the group\");\n     }\n \n@@ -2251,7 +2251,7 @@ RETRY_READING:\n     if (have_ready || have_connectors)\n     {\n         Verb() << \"(still have: \" << (have_ready ? \"+\" : \"-\") << \"ready, \"\n-            << (have_connectors ? \"+\" : \"-\") << \"connectors).\";\n+            << (have_connectors ? \"+\" : \"-\") << \"conenctors).\";\n         goto RETRY_READING;\n     }\n \n@@ -2747,28 +2747,26 @@ static inline bool IsMulticast(in_addr adr)\n void UdpCommon::Setup(string host, int port, map<string,string> attr)\n {\n     m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);\n-    if (m_sock == SYSSOCKET_INVALID)\n+    if (m_sock == -1)\n         Error(SysError(), \"UdpCommon::Setup: socket\");\n \n     int yes = 1;\n     ::setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof yes);\n \n-    interface_addr = CreateAddr(\"\", port, AF_INET);\n-    target_addr = CreateAddr(host, port);\n-\n-    is_multicast = false;\n+    sadr = CreateAddr(host, port);\n \n-    if (target_addr.family() == AF_INET)\n+    bool is_multicast = false;\n+    if (sadr.family() == AF_INET)\n     {\n         if (attr.count(\"multicast\"))\n         {\n-            if (!IsMulticast(target_addr.sin.sin_addr))\n+            if (!IsMulticast(sadr.sin.sin_addr))\n             {\n                 throw std::runtime_error(\"UdpCommon: requested multicast for a non-multicast-type IP address\");\n             }\n             is_multicast = true;\n         }\n-        else if (IsMulticast(target_addr.sin.sin_addr))\n+        else if (IsMulticast(sadr.sin.sin_addr))\n         {\n             is_multicast = true;\n         }\n@@ -2776,19 +2774,23 @@ void UdpCommon::Setup(string host, int port, map<string,string> attr)\n         if (is_multicast)\n         {\n             ip_mreq mreq;\n+            sockaddr_any maddr (AF_INET);\n             int opt_name;\n-            const char* mreq_arg_ptr;\n+            void* mreq_arg_ptr;\n             socklen_t mreq_arg_size;\n \n             adapter = attr.count(\"adapter\") ? attr.at(\"adapter\") : string();\n             if (adapter == \"\")\n             {\n                 Verb() << \"Multicast: home address: INADDR_ANY:\" << port;\n+                maddr.sin.sin_family = AF_INET;\n+                maddr.sin.sin_addr.s_addr = htonl(INADDR_ANY);\n+                maddr.sin.sin_port = htons(port); // necessary for temporary use\n             }\n             else\n             {\n                 Verb() << \"Multicast: home address: \" << adapter << \":\" << port;\n-                interface_addr = CreateAddr(adapter, port);\n+                maddr = CreateAddr(adapter, port);\n             }\n \n             if (attr.count(\"source\"))\n@@ -2797,11 +2799,11 @@ void UdpCommon::Setup(string host, int port, map<string,string> attr)\n                 ip_mreq_source mreq_ssm;\n                 /* this is an ssm.  we need to use the right struct and opt */\n                 opt_name = IP_ADD_SOURCE_MEMBERSHIP;\n-                mreq_ssm.imr_multiaddr.s_addr = target_addr.sin.sin_addr.s_addr;\n-                mreq_ssm.imr_interface.s_addr = interface_addr.sin.sin_addr.s_addr;\n+                mreq_ssm.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr;\n+                mreq_ssm.imr_interface.s_addr = maddr.sin.sin_addr.s_addr;\n                 inet_pton(AF_INET, attr.at(\"source\").c_str(), &mreq_ssm.imr_sourceaddr);\n                 mreq_arg_size = sizeof(mreq_ssm);\n-                mreq_arg_ptr = (const char*)&mreq_ssm;\n+                mreq_arg_ptr = &mreq_ssm;\n #else\n                 throw std::runtime_error(\"UdpCommon: source-filter multicast not supported by OS\");\n #endif\n@@ -2809,18 +2811,37 @@ void UdpCommon::Setup(string host, int port, map<string,string> attr)\n             else\n             {\n                 opt_name = IP_ADD_MEMBERSHIP;\n-                mreq.imr_multiaddr.s_addr = target_addr.sin.sin_addr.s_addr;\n-                mreq.imr_interface.s_addr = interface_addr.sin.sin_addr.s_addr;\n+                mreq.imr_multiaddr.s_addr = sadr.sin.sin_addr.s_addr;\n+                mreq.imr_interface.s_addr = maddr.sin.sin_addr.s_addr;\n                 mreq_arg_size = sizeof(mreq);\n-                mreq_arg_ptr = (const char*)&mreq;\n+                mreq_arg_ptr = &mreq;\n             }\n \n #ifdef _WIN32\n+            const char* mreq_arg = (const char*)mreq_arg_ptr;\n             const auto status_error = SOCKET_ERROR;\n #else\n+            const void* mreq_arg = mreq_arg_ptr;\n             const auto status_error = -1;\n #endif\n-            auto res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg_ptr, mreq_arg_size);\n+\n+#if defined(_WIN32) || defined(__CYGWIN__)\n+            // On Windows it somehow doesn't work when bind()\n+            // is called with multicast address. Write the address\n+            // that designates the network device here.\n+            // Also, sets port sharing when working with multicast\n+            sadr = maddr;\n+            int reuse = 1;\n+            int shareAddrRes = setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&reuse), sizeof(reuse));\n+            if (shareAddrRes == status_error)\n+            {\n+                throw runtime_error(\"marking socket for shared use failed\");\n+            }\n+            Verb() << \"Multicast(Windows): will bind to home address\";\n+#else\n+            Verb() << \"Multicast(POSIX): will bind to IGMP address: \" << host;\n+#endif\n+            int res = setsockopt(m_sock, IPPROTO_IP, opt_name, mreq_arg, mreq_arg_size);\n \n             if (res == status_error)\n             {\n@@ -2878,11 +2899,11 @@ void UdpCommon::Error(int err, string src)\n UdpCommon::~UdpCommon()\n {\n #ifdef _WIN32\n-    if (m_sock != SYSSOCKET_INVALID)\n+    if (m_sock != -1)\n     {\n         shutdown(m_sock, SD_BOTH);\n         closesocket(m_sock);\n-        m_sock = SYSSOCKET_INVALID;\n+        m_sock = -1;\n     }\n #else\n     close(m_sock);\n@@ -2892,34 +2913,7 @@ UdpCommon::~UdpCommon()\n UdpSource::UdpSource(string host, int port, const map<string,string>& attr)\n {\n     Setup(host, port, attr);\n-\n-    // On Windows it somehow doesn't work when bind()\n-    // is called with multicast address. Write the address\n-    // that designates the network device here, always.\n-\n-    // Hance we have two fields holding the address:\n-    // * target_addr: address from which reading will be done\n-    //   * unicast: local address of the interface\n-    //   * multicast: the IGMP address\n-    // * interface_addr: address of the local interface\n-    //   (same as target_addr for unicast)\n-\n-    // In case of multicast, binding should be done:\n-    // On most POSIX systems, to the multicast address (target_addr in this case)\n-    // On Windows, to a local address (hence use interface_addr, as in this\n-    // case it differs to target_addr).\n-\n-#if defined(_WIN32) || defined(__CYGWIN__)\n-    sockaddr_any baddr = is_multicast ? interface_addr : target_addr;\n-    static const char* const sysname = \"Windows\";\n-#else\n-    static const char* const sysname = \"POSIX\";\n-    sockaddr_any baddr = target_addr;\n-#endif\n-    Verb(\"UDP:\", is_multicast ? \"Multicast\" : \"Unicast\", \"(\", sysname,\n-            \"): will bind to: \", baddr.str());\n-    int stat = ::bind(m_sock, baddr.get(), baddr.size());\n-\n+    int stat = ::bind(m_sock, sadr.get(), sadr.size());\n     if (stat == -1)\n         Error(SysError(), \"Binding address for UDP\");\n     eof = false;\n@@ -2933,7 +2927,7 @@ UdpSource::UdpSource(string host, int port, const map<string,string>& attr)\n MediaPacket UdpSource::Read(size_t chunk)\n {\n     bytevector data(chunk);\n-    sockaddr_any sa(target_addr.family());\n+    sockaddr_any sa(sadr.family());\n     int64_t srctime = 0;\n AGAIN:\n     int stat = recvfrom(m_sock, data.data(), (int) chunk, 0, sa.get(), &sa.syslen());\n@@ -2981,7 +2975,7 @@ UdpTarget::UdpTarget(string host, int port, const map<string,string>& attr)\n \n void UdpTarget::Write(const MediaPacket& data)\n {\n-    int stat = sendto(m_sock, data.payload.data(), int(data.payload.size()), 0, target_addr.get(), (int)target_addr.size());\n+    int stat = sendto(m_sock, data.payload.data(), int(data.payload.size()), 0, (sockaddr*)&sadr, int(sizeof sadr));\n     if (stat == -1)\n         Error(SysError(), \"UDP Write/sendto\");\n }\ndiff --git a/testing/testmedia.hpp b/testing/testmedia.hpp\nindex 56eea65..470e825 100644\n--- a/testing/testmedia.hpp\n+++ b/testing/testmedia.hpp\n@@ -303,11 +303,9 @@ public:\n class UdpCommon\n {\n protected:\n-    SYSSOCKET m_sock = -1;\n+    int m_sock = -1;\n+    srt::sockaddr_any sadr;\n     std::string adapter;\n-    srt::sockaddr_any interface_addr;\n-    srt::sockaddr_any target_addr;\n-    bool is_multicast = false;\n     std::map<std::string, std::string> m_options;\n     void Setup(std::string host, int port, std::map<std::string,std::string> attr);\n     void Error(int err, std::string src);\n@@ -325,7 +323,7 @@ public:\n \n     MediaPacket Read(size_t chunk) override;\n \n-    bool IsOpen() override { return m_sock != SYSSOCKET_INVALID; }\n+    bool IsOpen() override { return m_sock != -1; }\n     bool End() override { return eof; }\n };\n \n@@ -335,7 +333,7 @@ public:\n     UdpTarget(std::string host, int port, const std::map<std::string,std::string>& attr);\n \n     void Write(const MediaPacket& data) override;\n-    bool IsOpen() override { return m_sock != SYSSOCKET_INVALID; }\n+    bool IsOpen() override { return m_sock != -1; }\n     bool Broken() override { return false; }\n };\n \n@@ -348,7 +346,7 @@ public:\n     {\n     }\n \n-    bool IsOpen() override { return m_sock != SYSSOCKET_INVALID; }\n+    bool IsOpen() override { return m_sock != -1; }\n };\n \n \n","content_type":"text/plain","diff_type":"vcs","new_revision":"git-v1:7e33d0f55e985d9663e1b1c066897bd7724af340"}