mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Upgrade libsrt to v1.5.3. v5.0.183 v6.0.81 (#3808)
fix https://github.com/ossrs/srs/issues/3155 Build srt-1-fit fails with `standard attributes in middle of decl-specifiers` on GCC 12,Arch Linux. See https://github.com/Haivision/srt/releases/tag/v1.5.3
This commit is contained in:
parent
f9bba0a9b0
commit
c5e067fb0b
94 changed files with 5974 additions and 6273 deletions
4
trunk/3rdparty/README.md
vendored
4
trunk/3rdparty/README.md
vendored
|
@ -9,8 +9,8 @@ nginx-1.5.7.zip
|
|||
* for srs to support hls streaming.
|
||||
|
||||
srt-1-fit
|
||||
srt-1.4.1.tar.gz
|
||||
* https://github.com/Haivision/srt/releases/tag/v1.4.1
|
||||
srt-1.5.3.tar.gz
|
||||
* https://github.com/Haivision/srt/releases/tag/v1.5.3
|
||||
* https://ossrs.net/lts/zh-cn/license#srt
|
||||
|
||||
openssl-1.1-fit
|
||||
|
|
106
trunk/3rdparty/srt-1-fit/CMakeLists.txt
vendored
106
trunk/3rdparty/srt-1-fit/CMakeLists.txt
vendored
|
@ -8,7 +8,7 @@
|
|||
#
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.12 FATAL_ERROR)
|
||||
set (SRT_VERSION 1.5.1)
|
||||
set (SRT_VERSION 1.5.3)
|
||||
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/scripts")
|
||||
include(haiUtil) # needed for set_version_variables
|
||||
|
@ -117,6 +117,9 @@ if (ENABLE_DEBUG)
|
|||
set(ENABLE_HEAVY_LOGGING_DEFAULT ON)
|
||||
endif()
|
||||
|
||||
# Note that the IP_PKTINFO has a limited portability and may not work on some platforms
|
||||
# (Windows, FreeBSD, ...).
|
||||
set (ENABLE_PKTINFO_DEFAULT OFF)
|
||||
|
||||
set(ENABLE_STDCXX_SYNC_DEFAULT OFF)
|
||||
set(ENABLE_MONOTONIC_CLOCK_DEFAULT OFF)
|
||||
|
@ -144,10 +147,13 @@ option(ENABLE_HEAVY_LOGGING "Should heavy debug logging be enabled" ${ENABLE_HEA
|
|||
option(ENABLE_HAICRYPT_LOGGING "Should logging in haicrypt be enabled" 0)
|
||||
option(ENABLE_SHARED "Should libsrt be built as a shared library" ON)
|
||||
option(ENABLE_STATIC "Should libsrt be built as a static library" ON)
|
||||
option(ENABLE_PKTINFO "Enable using IP_PKTINFO to allow the listener extracting the target IP address from incoming packets" ${ENABLE_PKTINFO_DEFAULT})
|
||||
option(ENABLE_RELATIVE_LIBPATH "Should application contain relative library paths, like ../lib" OFF)
|
||||
option(ENABLE_GETNAMEINFO "In-logs sockaddr-to-string should do rev-dns" OFF)
|
||||
option(ENABLE_UNITTESTS "Enable unit tests" OFF)
|
||||
option(ENABLE_ENCRYPTION "Enable encryption in SRT" ON)
|
||||
option(ENABLE_AEAD_API_PREVIEW "Enable AEAD API preview in SRT" Off)
|
||||
option(ENABLE_MAXREXMITBW "Enable SRTO_MAXREXMITBW (v1.6.0 API preview)" Off)
|
||||
option(ENABLE_CXX_DEPS "Extra library dependencies in srt.pc for the CXX libraries useful with C language" ON)
|
||||
option(USE_STATIC_LIBSTDCXX "Should use static rather than shared libstdc++" OFF)
|
||||
option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON)
|
||||
|
@ -160,7 +166,6 @@ option(USE_BUSY_WAITING "Enable more accurate sending times at a cost of potenti
|
|||
option(USE_GNUSTL "Get c++ library/headers from the gnustl.pc" OFF)
|
||||
option(ENABLE_SOCK_CLOEXEC "Enable setting SOCK_CLOEXEC on a socket" ON)
|
||||
option(ENABLE_SHOW_PROJECT_CONFIG "Enable show Project Configuration" OFF)
|
||||
option(ENABLE_NEW_RCVBUFFER "Enable new receiver buffer implementation" ON)
|
||||
|
||||
option(ENABLE_CLANG_TSA "Enable Clang Thread Safety Analysis" OFF)
|
||||
|
||||
|
@ -200,6 +205,16 @@ else()
|
|||
message(STATUS "USE_BUSY_WAITING: OFF (default)")
|
||||
endif()
|
||||
|
||||
# Reduce the frequency of some frequent logs, milliseconds
|
||||
set(SRT_LOG_SLOWDOWN_FREQ_MS_DEFAULT 1000) # 1s
|
||||
if (NOT DEFINED SRT_LOG_SLOWDOWN_FREQ_MS)
|
||||
if (ENABLE_HEAVY_LOGGING)
|
||||
set(SRT_LOG_SLOWDOWN_FREQ_MS 0) # Just show every log message.
|
||||
else()
|
||||
set(SRT_LOG_SLOWDOWN_FREQ_MS ${SRT_LOG_SLOWDOWN_FREQ_MS_DEFAULT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if ( CYGWIN AND NOT CYGWIN_USE_POSIX )
|
||||
set(WIN32 1)
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 1)
|
||||
|
@ -285,7 +300,13 @@ if(WIN32)
|
|||
if(ENABLE_INET_PTON)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ws2_32)
|
||||
check_function_exists(inet_pton HAVE_INET_PTON)
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
try_compile(AT_LEAST_VISTA
|
||||
${CMAKE_BINARY_DIR}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/test_vista.c")
|
||||
if(NOT AT_LEAST_VISTA)
|
||||
# force targeting Vista
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-D_WIN32_WINNT=0x0501)
|
||||
endif()
|
||||
|
@ -422,8 +443,21 @@ if (ENABLE_ENCRYPTION)
|
|||
add_definitions(-DSRT_ENABLE_ENCRYPTION)
|
||||
message(STATUS "ENCRYPTION: ENABLED, using: ${SSL_REQUIRED_MODULES}")
|
||||
message (STATUS "SSL libraries: ${SSL_LIBRARIES}")
|
||||
|
||||
if (ENABLE_AEAD_API_PREVIEW)
|
||||
if ("${USE_ENCLIB}" STREQUAL "openssl-evp")
|
||||
add_definitions(-DENABLE_AEAD_API_PREVIEW)
|
||||
message(STATUS "ENCRYPTION AEAD API: ENABLED")
|
||||
else()
|
||||
message(FATAL_ERROR "ENABLE_AEAD_API_PREVIEW is only available with USE_ENCLIB=openssl-evp!")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "ENCRYPTION AEAD API: DISABLED")
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(STATUS "ENCRYPTION: DISABLED")
|
||||
message(STATUS "ENCRYPTION AEAD API: N/A")
|
||||
endif()
|
||||
|
||||
if (USE_GNUSTL)
|
||||
|
@ -433,8 +467,15 @@ if (USE_GNUSTL)
|
|||
set (SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${GNUSTL_LIBRARIES} ${GNUSTL_LDFLAGS})
|
||||
endif()
|
||||
|
||||
if (ENABLE_MAXREXMITBW)
|
||||
add_definitions(-DENABLE_MAXREXMITBW)
|
||||
message(STATUS "MAXREXMITBW API: ENABLED")
|
||||
else()
|
||||
message(STATUS "MAXREXMITBW API: DISABLED")
|
||||
endif()
|
||||
|
||||
if (USING_DEFAULT_COMPILER_PREFIX)
|
||||
# Detect if the compiler is GNU compatable for flags
|
||||
# Detect if the compiler is GNU compatible for flags
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Intel|Clang|AppleClang")
|
||||
message(STATUS "COMPILER: ${CMAKE_CXX_COMPILER_ID} (${CMAKE_CXX_COMPILER}) - GNU compat")
|
||||
set(HAVE_COMPILER_GNU_COMPAT 1)
|
||||
|
@ -478,6 +519,15 @@ CheckGCCAtomicIntrinsics()
|
|||
include(CheckCXXAtomic)
|
||||
CheckCXXAtomic()
|
||||
|
||||
# Check for std::put_time():
|
||||
# Sets:
|
||||
# HAVE_CXX_STD_PUT_TIME
|
||||
include(CheckCXXStdPutTime)
|
||||
CheckCXXStdPutTime()
|
||||
if (HAVE_CXX_STD_PUT_TIME)
|
||||
add_definitions(-DHAVE_CXX_STD_PUT_TIME=1)
|
||||
endif()
|
||||
|
||||
if (DISABLE_CXX11)
|
||||
set (ENABLE_CXX11 0)
|
||||
elseif( DEFINED ENABLE_CXX11 )
|
||||
|
@ -533,14 +583,6 @@ if (ENABLE_SOCK_CLOEXEC)
|
|||
add_definitions(-DENABLE_SOCK_CLOEXEC=1)
|
||||
endif()
|
||||
|
||||
if (ENABLE_NEW_RCVBUFFER)
|
||||
add_definitions(-DENABLE_NEW_RCVBUFFER=1)
|
||||
message(STATUS "RECEIVER_BUFFER: NEW")
|
||||
else()
|
||||
remove_definitions(-DENABLE_NEW_RCVBUFFER)
|
||||
message(STATUS "RECEIVER_BUFFER: OLD")
|
||||
endif()
|
||||
|
||||
if (CMAKE_MAJOR_VERSION LESS 3)
|
||||
set (FORCE_CXX_STANDARD_GNUONLY 1)
|
||||
endif()
|
||||
|
@ -614,6 +656,9 @@ endif()
|
|||
# add extra warning flags for gccish compilers
|
||||
if (HAVE_COMPILER_GNU_COMPAT)
|
||||
set (SRT_GCC_WARN "-Wall -Wextra")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set (SRT_GCC_WARN "${SRT_GCC_WARN} -Wshadow=local")
|
||||
endif()
|
||||
else()
|
||||
# cpp debugging on Windows :D
|
||||
#set (SRT_GCC_WARN "/showIncludes")
|
||||
|
@ -720,6 +765,15 @@ if (ENABLE_GETNAMEINFO)
|
|||
list(APPEND SRT_EXTRA_CFLAGS "-DENABLE_GETNAMEINFO=1")
|
||||
endif()
|
||||
|
||||
if (ENABLE_PKTINFO)
|
||||
if (WIN32 OR BSD)
|
||||
message(FATAL_ERROR "PKTINFO is not implemented on Windows or *BSD.")
|
||||
endif()
|
||||
|
||||
list(APPEND SRT_EXTRA_CFLAGS "-DSRT_ENABLE_PKTINFO=1")
|
||||
endif()
|
||||
|
||||
|
||||
# ENABLE_EXPERIMENTAL_BONDING is deprecated. Use ENABLE_BONDING. ENABLE_EXPERIMENTAL_BONDING is be removed in v1.6.0.
|
||||
if (ENABLE_EXPERIMENTAL_BONDING)
|
||||
message(DEPRECATION "ENABLE_EXPERIMENTAL_BONDING is deprecated. Please use ENABLE_BONDING instead.")
|
||||
|
@ -1040,6 +1094,8 @@ if (ENABLE_SHARED)
|
|||
target_compile_definitions(srt_virtual PUBLIC -DSRT_DYNAMIC)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(srt_virtual PRIVATE -DSRT_LOG_SLOWDOWN_FREQ_MS=${SRT_LOG_SLOWDOWN_FREQ_MS})
|
||||
|
||||
if (srt_libspec_shared)
|
||||
if (MICROSOFT)
|
||||
target_link_libraries(${TARGET_srt}_shared PUBLIC Ws2_32.lib)
|
||||
|
@ -1064,6 +1120,11 @@ elseif (HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES_STATIC)
|
|||
if (srt_libspec_static)
|
||||
target_link_libraries(${TARGET_srt}_static PUBLIC atomic)
|
||||
endif()
|
||||
elseif (LINUX AND HAVE_LIBATOMIC AND HAVE_LIBATOMIC_COMPILES)
|
||||
# This is a workaround for some older Linux Toolchains.
|
||||
if (srt_libspec_static)
|
||||
target_link_libraries(${TARGET_srt}_static PUBLIC atomic)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Cygwin installs the *.dll libraries in bin directory and uses PATH.
|
||||
|
@ -1122,7 +1183,7 @@ endif()
|
|||
# obtained by `pkg-config --libs`.
|
||||
if(ENABLE_CXX_DEPS)
|
||||
foreach(LIB ${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES})
|
||||
if(IS_ABSOLUTE ${LIB} AND EXISTS ${LIB})
|
||||
if((IS_ABSOLUTE ${LIB} AND EXISTS ${LIB}) OR (${LIB} MATCHES "^-l"))
|
||||
set(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} ${LIB})
|
||||
else()
|
||||
set(SRT_LIBS_PRIVATE ${SRT_LIBS_PRIVATE} "-l${LIB}")
|
||||
|
@ -1334,6 +1395,10 @@ if (ENABLE_EXAMPLES)
|
|||
|
||||
srt_add_example(recvfile.cpp)
|
||||
|
||||
srt_add_example(sendmsg.cpp)
|
||||
|
||||
srt_add_example(recvmsg.cpp)
|
||||
|
||||
srt_add_example(test-c-client.c)
|
||||
|
||||
srt_add_example(example-client-nonblock.c)
|
||||
|
@ -1363,7 +1428,13 @@ if (ENABLE_UNITTESTS AND ENABLE_CXX11)
|
|||
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
find_package(GTest 1.8)
|
||||
# Version ranges are only supported with CMake 3.19 or later.
|
||||
# Need GTest v1.10 or higher to support GTEST_SKIP.
|
||||
if (${CMAKE_VERSION} VERSION_LESS "3.19.0")
|
||||
find_package(GTest 1.10)
|
||||
else()
|
||||
find_package(GTest 1.10...1.12)
|
||||
endif()
|
||||
if (NOT GTEST_FOUND)
|
||||
message(STATUS "GTEST not found! Fetching from git.")
|
||||
include(googletest)
|
||||
|
@ -1395,12 +1466,13 @@ if (ENABLE_UNITTESTS AND ENABLE_CXX11)
|
|||
NAME test-srt
|
||||
COMMAND ${CMAKE_BINARY_DIR}/test-srt
|
||||
)
|
||||
#set_tests_properties(test-srt PROPERTIES RUN_SERIAL TRUE)
|
||||
else()
|
||||
gtest_add_tests(
|
||||
test-srt
|
||||
""
|
||||
AUTO
|
||||
TEST_LIST tests_srt
|
||||
TARGET test-srt
|
||||
)
|
||||
set_tests_properties(${tests_srt} PROPERTIES RUN_SERIAL TRUE)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
|
1
trunk/3rdparty/srt-1-fit/configure-data.tcl
vendored
1
trunk/3rdparty/srt-1-fit/configure-data.tcl
vendored
|
@ -43,6 +43,7 @@ set cmake_options {
|
|||
enable-logging "Should logging be enabled (default: ON)"
|
||||
enable-heavy-logging "Should heavy debug logging be enabled (default: OFF)"
|
||||
enable-haicrypt-logging "Should logging in haicrypt be enabled (default: OFF)"
|
||||
enable-pktinfo "Should pktinfo reading and using be enabled (POSIX only) (default: OFF)"
|
||||
enable-shared "Should libsrt be built as a shared library (default: ON)"
|
||||
enable-static "Should libsrt be built as a static library (default: ON)"
|
||||
enable-relative-libpath "Should applications contain relative library paths, like ../lib (default: OFF)"
|
||||
|
|
|
@ -16,7 +16,7 @@ written by
|
|||
2022-05-19 (jdube)
|
||||
CRYSPR2 adaptation
|
||||
2019-06-27 (jdube)
|
||||
GnuTLS/Nettle CRYSPR/4SRT (CRYypto Service PRovider for SRT)
|
||||
MBedTLS CRYSPR/4SRT (CRYypto Service PRovider for SRT)
|
||||
*****************************************************************************/
|
||||
|
||||
#include "hcrypt.h"
|
||||
|
@ -32,7 +32,7 @@ written by
|
|||
static mbedtls_ctr_drbg_context crysprMbedtls_ctr_drbg;
|
||||
static mbedtls_entropy_context crysprMbedtls_entropy;
|
||||
|
||||
typedef struct tag_crysprGnuTLS_AES_cb {
|
||||
typedef struct tag_crysprMBedTLS_AES_cb {
|
||||
CRYSPR_cb ccb; /* CRYSPR control block */
|
||||
/* Add other cryptolib specific data here */
|
||||
#ifdef CRYSPR2
|
||||
|
@ -75,9 +75,9 @@ int crysprMbedtls_AES_SetKey(
|
|||
// kstr_len is in "bytes" convention (16, 24, 32).
|
||||
|
||||
if (bEncrypt) { /* Encrypt key */
|
||||
ret = mbedtls_aes_setkey_enc(aes_key, kstr, kstr_len*8);
|
||||
ret = mbedtls_aes_setkey_enc(aes_key, kstr, (unsigned int)kstr_len*8);
|
||||
} else { /* Decrypt key */
|
||||
ret = mbedtls_aes_setkey_dec(aes_key, kstr, kstr_len*8);
|
||||
ret = mbedtls_aes_setkey_dec(aes_key, kstr, (unsigned int)kstr_len*8);
|
||||
}
|
||||
|
||||
return ret == 0 ? 0 : -1;
|
||||
|
@ -91,8 +91,8 @@ int crysprMbedtls_AES_EcbCipher( /* AES Electronic Codebook cipher*/
|
|||
unsigned char *out_txt, /* dst (cipher text) */
|
||||
size_t *outlen) /* dst len */
|
||||
{
|
||||
int nblk = inlen/CRYSPR_AESBLKSZ;
|
||||
int nmore = inlen%CRYSPR_AESBLKSZ;
|
||||
int nblk = (int)(inlen/CRYSPR_AESBLKSZ);
|
||||
int nmore = (int)(inlen%CRYSPR_AESBLKSZ);
|
||||
int i;
|
||||
|
||||
if (bEncrypt) {
|
||||
|
@ -160,7 +160,6 @@ int crysprMbedtls_AES_CtrCipher( /* AES-CTR128 Encryption */
|
|||
static CRYSPR_cb *crysprMbedtls_Open(CRYSPR_methods *cryspr, size_t max_len)
|
||||
{
|
||||
crysprMbedtls_cb *aes_data;
|
||||
CRYSPR_cb *cryspr_cb;
|
||||
|
||||
aes_data = (crysprMbedtls_cb *)crysprHelper_Open(cryspr, sizeof(crysprMbedtls_cb), max_len);
|
||||
if (NULL == aes_data) {
|
||||
|
@ -216,7 +215,7 @@ int crysprMbedtls_KmPbkdf2(
|
|||
|
||||
ret = mbedtls_pkcs5_pbkdf2_hmac(&mdctx,
|
||||
(unsigned char*)passwd, passwd_len, salt, salt_len,
|
||||
itr, key_len, out);
|
||||
itr, (uint32_t)key_len, out);
|
||||
|
||||
mbedtls_md_free(&mdctx);
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@ written by
|
|||
Haivision Systems Inc.
|
||||
|
||||
2019-06-27 (jdube)
|
||||
GnuTLS/Nettle CRYSPR/4SRT (CRYypto Service PRovider for SRT)
|
||||
MBedTLS CRYSPR/4SRT (CRYypto Service PRovider for SRT)
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef CRYSPR_GNUTLS_H
|
||||
#define CRYSPR_GNUTLS_H
|
||||
#ifndef CRYSPR_MBEDTLS_H
|
||||
#define CRYSPR_MBEDTLS_H
|
||||
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/aes.h>
|
||||
|
@ -59,5 +59,5 @@ typedef mbedtls_aes_context CRYSPR_AESCTX; /* CRYpto Service PRovider AES key
|
|||
|
||||
struct tag_CRYSPR_methods *crysprMbedtls(void);
|
||||
|
||||
#endif /* CRYSPR_GNUTLS_H */
|
||||
#endif /* CRYSPR_MBEDTLS_H */
|
||||
|
||||
|
|
|
@ -34,9 +34,11 @@ int crysprOpenSSL_EVP_Prng(unsigned char* rn, int len)
|
|||
const EVP_CIPHER* (*Xcipher_fnptr)(void) = EVP_aes_128_ecb;
|
||||
|
||||
const EVP_CIPHER* (*_crysprOpenSSL_EVP_cipher_fnptr[][3])(void) = {
|
||||
{NULL, NULL, NULL},
|
||||
{EVP_aes_128_ecb, EVP_aes_192_ecb, EVP_aes_256_ecb},
|
||||
{EVP_aes_128_ctr, EVP_aes_192_ctr, EVP_aes_256_ctr},
|
||||
{NULL, NULL, NULL}, // HCRYPT_CTX_MODE_CLRTXT
|
||||
{EVP_aes_128_ecb, EVP_aes_192_ecb, EVP_aes_256_ecb}, // HCRYPT_CTX_MODE_AESECB
|
||||
{EVP_aes_128_ctr, EVP_aes_192_ctr, EVP_aes_256_ctr}, // HCRYPT_CTX_MODE_AESCTR
|
||||
{NULL, NULL, NULL}, // HCRYPT_CTX_MODE_AESCBC
|
||||
{EVP_aes_128_gcm, EVP_aes_192_gcm, EVP_aes_256_gcm}, // HCRYPT_CTX_MODE_AESGCM
|
||||
};
|
||||
|
||||
int crysprOpenSSL_EVP_AES_SetKey(
|
||||
|
@ -47,7 +49,7 @@ int crysprOpenSSL_EVP_AES_SetKey(
|
|||
CRYSPR_AESCTX* aes_key) /* CRYpto Service PRovider AES Key context */
|
||||
{
|
||||
const EVP_CIPHER* cipher = NULL;
|
||||
int idxKlen = (kstr_len / 8) - 2; /* key_len index in cipher_fnptr array in [0,1,2] range */
|
||||
int idxKlen = (int)((kstr_len / 8) - 2); /* key_len index in cipher_fnptr array in [0,1,2] range */
|
||||
|
||||
switch (cipher_type)
|
||||
{
|
||||
|
@ -61,6 +63,8 @@ int crysprOpenSSL_EVP_AES_SetKey(
|
|||
cipher_type = HCRYPT_CTX_MODE_AESECB;
|
||||
#endif
|
||||
break;
|
||||
case HCRYPT_CTX_MODE_AESGCM:
|
||||
break;
|
||||
default:
|
||||
HCRYPT_LOG(LOG_ERR,
|
||||
"invalid cipher type (%d). Expected: [%d..%d]\n",
|
||||
|
@ -139,7 +143,7 @@ int crysprOpenSSL_EVP_AES_EcbCipher(bool bEncrypt, /* true:encry
|
|||
size_t* outlen_p) /* in/out dst len */
|
||||
{
|
||||
int nmore = inlen % CRYSPR_AESBLKSZ; /* bytes in last incomplete block */
|
||||
int nblk = inlen / CRYSPR_AESBLKSZ + (nmore ? 1 : 0); /* blocks including incomplete */
|
||||
int nblk = (int)(inlen / CRYSPR_AESBLKSZ + (nmore ? 1 : 0)); /* blocks including incomplete */
|
||||
size_t outsiz = (outlen_p ? *outlen_p : 0);
|
||||
int c_len = 0, f_len = 0;
|
||||
|
||||
|
@ -156,7 +160,7 @@ int crysprOpenSSL_EVP_AES_EcbCipher(bool bEncrypt, /* true:encry
|
|||
return (-1); /* output buf size must have room for PKCS7 padding */
|
||||
}
|
||||
/* allows reusing of 'e' for multiple encryption cycles */
|
||||
if (!EVP_CipherInit_ex(aes_key, NULL, NULL, NULL, NULL, -1))
|
||||
if (!EVP_CipherInit_ex(aes_key, NULL, NULL, NULL, NULL, bEncrypt))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "EVP_CipherInit_ex(%p,NULL,...,-1) failed\n", aes_key);
|
||||
return -1;
|
||||
|
@ -170,7 +174,7 @@ int crysprOpenSSL_EVP_AES_EcbCipher(bool bEncrypt, /* true:encry
|
|||
/* update ciphertext, c_len is filled with the length of ciphertext generated,
|
||||
* cryptoPtr->cipher_in_len is the size of plain/cipher text in bytes
|
||||
*/
|
||||
if (!EVP_CipherUpdate(aes_key, out_txt, &c_len, indata, inlen))
|
||||
if (!EVP_CipherUpdate(aes_key, out_txt, &c_len, indata, (int)inlen))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "EVP_CipherUpdate(%p, out, %d, in, %d) failed\n", aes_key, c_len, inlen);
|
||||
return -1;
|
||||
|
@ -223,7 +227,7 @@ int crysprOpenSSL_EVP_AES_CtrCipher(bool bEncrypt, /* true:encry
|
|||
/* update ciphertext, c_len is filled with the length of ciphertext generated,
|
||||
* cryptoPtr->cipher_in_len is the size of plain/cipher text in bytes
|
||||
*/
|
||||
if (!EVP_CipherUpdate(aes_key, out_txt, &c_len, indata, inlen))
|
||||
if (!EVP_CipherUpdate(aes_key, out_txt, &c_len, indata, (int)inlen))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_CipherUpdate() failed");
|
||||
return -1;
|
||||
|
@ -247,6 +251,83 @@ int crysprOpenSSL_EVP_AES_CtrCipher(bool bEncrypt, /* true:encry
|
|||
return 0;
|
||||
}
|
||||
|
||||
int crysprOpenSSL_EVP_AES_GCMCipher(bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX* aes_key, /* CRYpto Service PRovider AES Key context */
|
||||
unsigned char* iv, /* iv */
|
||||
const unsigned char* aad, /* associated data */
|
||||
size_t aadlen,
|
||||
const unsigned char* indata, /* src */
|
||||
size_t inlen, /* length */
|
||||
unsigned char* out_txt,
|
||||
unsigned char* out_tag) /* auth tag */
|
||||
{
|
||||
int c_len, f_len;
|
||||
|
||||
/* allows reusing of 'e' for multiple encryption cycles */
|
||||
if (!EVP_CipherInit_ex(aes_key, NULL, NULL, NULL, iv, -1))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_CipherInit_ex() failed");
|
||||
return -1;
|
||||
}
|
||||
if (!EVP_CIPHER_CTX_set_padding(aes_key, 0))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_CIPHER_CTX_set_padding() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide any AAD data. This can be called zero or more times as
|
||||
* required
|
||||
*/
|
||||
if (1 != EVP_CipherUpdate(aes_key, NULL, &c_len, aad, (int) aadlen))
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_EncryptUpdate failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* update ciphertext, c_len is filled with the length of ciphertext generated,
|
||||
* cryptoPtr->cipher_in_len is the size of plain/cipher text in bytes
|
||||
*/
|
||||
if (!EVP_CipherUpdate(aes_key, out_txt, &c_len, indata, (int) inlen))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_CipherUpdate() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!bEncrypt && !EVP_CIPHER_CTX_ctrl(aes_key, EVP_CTRL_GCM_SET_TAG, HAICRYPT_AUTHTAG_MAX, out_tag)) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_EncryptUpdate failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* update ciphertext with the final remaining bytes */
|
||||
/* Useless with pre-padding */
|
||||
f_len = 0;
|
||||
if (0 == EVP_CipherFinal_ex(aes_key, &out_txt[c_len], &f_len))
|
||||
{
|
||||
#if ENABLE_HAICRYPT_LOGGING
|
||||
char szErrBuf[256];
|
||||
HCRYPT_LOG(LOG_ERR,
|
||||
"EVP_CipherFinal_ex(ctx,&out[%d],%d)) failed: %s\n",
|
||||
c_len,
|
||||
f_len,
|
||||
ERR_error_string(ERR_get_error(), szErrBuf));
|
||||
#endif /*ENABLE_HAICRYPT_LOGGING*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the tag if we are encrypting */
|
||||
if (bEncrypt && !EVP_CIPHER_CTX_ctrl(aes_key, EVP_CTRL_GCM_GET_TAG, HAICRYPT_AUTHTAG_MAX, out_tag))
|
||||
{
|
||||
ERR_print_errors_fp(stderr);
|
||||
HCRYPT_LOG(LOG_ERR, "%s\n", "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_GET_TAG) failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password-based Key Derivation Function
|
||||
*/
|
||||
|
@ -260,7 +341,7 @@ int crysprOpenSSL_EVP_KmPbkdf2(CRYSPR_cb* cryspr_cb,
|
|||
unsigned char* out) /* derived key */
|
||||
{
|
||||
(void)cryspr_cb;
|
||||
int rc = PKCS5_PBKDF2_HMAC_SHA1(passwd, passwd_len, salt, salt_len, itr, key_len, out);
|
||||
int rc = PKCS5_PBKDF2_HMAC_SHA1(passwd, (int)passwd_len, salt, (int)salt_len, itr, (int)key_len, out);
|
||||
return (rc == 1 ? 0 : -1);
|
||||
}
|
||||
|
||||
|
@ -300,6 +381,7 @@ CRYSPR_methods* crysprOpenSSL_EVP(void)
|
|||
#if CRYSPR_HAS_AESCTR
|
||||
crysprOpenSSL_EVP_methods.aes_ctr_cipher = crysprOpenSSL_EVP_AES_CtrCipher;
|
||||
#endif
|
||||
crysprOpenSSL_EVP_methods.aes_gcm_cipher = crysprOpenSSL_EVP_AES_GCMCipher;
|
||||
#if !(CRYSPR_HAS_AESCTR && CRYSPR_HAS_AESKWRAP)
|
||||
/* AES-ECB only required if cryspr has no AES-CTR and no AES KeyWrap */
|
||||
/* OpenSSL has both AESCTR and AESKWRP and the AESECB wrapper is only used
|
||||
|
|
|
@ -34,6 +34,10 @@ written by
|
|||
*/
|
||||
#define CRYSPR_HAS_AESCTR 1
|
||||
|
||||
/* Define CRYSPR_HAS_AESGCM to 1 if this CRYSPR has AES GCM cipher mode. OpenSSL EVP supports GCM.
|
||||
*/
|
||||
#define CRYSPR_HAS_AESGCM 1
|
||||
|
||||
/* Define CRYSPR_HAS_AESKWRAP to 1 if this CRYSPR has AES Key Wrap
|
||||
if not set to 0 to enable default/fallback crysprFallback_AES_WrapKey/crysprFallback_AES_UnwrapKey methods
|
||||
and provide the aes_ecb_cipher method .
|
||||
|
|
|
@ -48,12 +48,12 @@ int crysprOpenSSL_AES_SetKey(
|
|||
(void)cipher_type;
|
||||
|
||||
if (bEncrypt) { /* Encrypt key */
|
||||
if (AES_set_encrypt_key(kstr, kstr_len * 8, aes_key)) {
|
||||
if (AES_set_encrypt_key(kstr, (int)(kstr_len * 8), aes_key)) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "AES_set_encrypt_key(kek) failed\n");
|
||||
return(-1);
|
||||
}
|
||||
} else { /* Decrypt key */
|
||||
if (AES_set_decrypt_key(kstr, kstr_len * 8, aes_key)) {
|
||||
if (AES_set_decrypt_key(kstr, (int)(kstr_len * 8), aes_key)) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "AES_set_decrypt_key(kek) failed\n");
|
||||
return(-1);
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ int crysprOpenSSL_KmPbkdf2(
|
|||
unsigned char *out) /* derived key */
|
||||
{
|
||||
(void)cryspr_cb;
|
||||
int rc = PKCS5_PBKDF2_HMAC_SHA1(passwd,passwd_len,salt,salt_len,itr,key_len,out);
|
||||
int rc = PKCS5_PBKDF2_HMAC_SHA1(passwd,(int)passwd_len,salt,(int)salt_len,itr,(int)key_len,out);
|
||||
return(rc == 1? 0 : -1);
|
||||
}
|
||||
|
||||
|
|
415
trunk/3rdparty/srt-1-fit/haicrypt/cryspr.c
vendored
415
trunk/3rdparty/srt-1-fit/haicrypt/cryspr.c
vendored
|
@ -14,7 +14,7 @@ written by
|
|||
Haivision Systems Inc.
|
||||
|
||||
2019-06-28 (jdube)
|
||||
CRYSPR/4SRT Initial implementation.
|
||||
CRYSPR/4SRT Initial implementation.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "hcrypt.h"
|
||||
|
@ -25,111 +25,135 @@ written by
|
|||
|
||||
int crysprStub_Prng(unsigned char *rn, int len)
|
||||
{
|
||||
(void)rn;
|
||||
(void)len;
|
||||
return(0);
|
||||
(void)rn;
|
||||
(void)len;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int crysprStub_AES_SetKey(
|
||||
int cipher_type, /* One of HCRYPT_CTX_MODE_[CLRTXT|AESECB|AESCTR|AESGDM] */
|
||||
bool bEncrypt, /* true Enxcrypt key, false: decrypt */
|
||||
const unsigned char *kstr, /* key sttring*/
|
||||
size_t kstr_len, /* kstr len in bytes (16, 24, or 32 bytes (for AES128,AES192, or AES256) */
|
||||
CRYSPR_AESCTX *aes_key) /* Cryptolib Specific AES key context */
|
||||
int cipher_type, /* One of HCRYPT_CTX_MODE_[CLRTXT|AESECB|AESCTR|AESGDM] */
|
||||
bool bEncrypt, /* true Enxcrypt key, false: decrypt */
|
||||
const unsigned char *kstr, /* key sttring*/
|
||||
size_t kstr_len, /* kstr len in bytes (16, 24, or 32 bytes (for AES128,AES192, or AES256) */
|
||||
CRYSPR_AESCTX *aes_key) /* Cryptolib Specific AES key context */
|
||||
{
|
||||
(void)cipher_type;
|
||||
(void)bEncrypt;
|
||||
(void)kstr;
|
||||
(void)kstr_len;
|
||||
(void)aes_key;
|
||||
(void)cipher_type;
|
||||
(void)bEncrypt;
|
||||
(void)kstr;
|
||||
(void)kstr_len;
|
||||
(void)aes_key;
|
||||
|
||||
return(0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int crysprStub_AES_EcbCipher(
|
||||
bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX *aes_key, /* AES context */
|
||||
const unsigned char *indata,/* src (clear text)*/
|
||||
size_t inlen, /* length */
|
||||
unsigned char *out_txt, /* dst (cipher text) */
|
||||
size_t *outlen) /* dst len */
|
||||
bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX *aes_key, /* AES context */
|
||||
const unsigned char *indata,/* src (clear text)*/
|
||||
size_t inlen, /* length */
|
||||
unsigned char *out_txt, /* dst (cipher text) */
|
||||
size_t *outlen) /* dst len */
|
||||
{
|
||||
(void)bEncrypt;
|
||||
(void)aes_key;
|
||||
(void)indata;
|
||||
(void)inlen;
|
||||
(void)out_txt;
|
||||
(void)outlen;
|
||||
(void)bEncrypt;
|
||||
(void)aes_key;
|
||||
(void)indata;
|
||||
(void)inlen;
|
||||
(void)out_txt;
|
||||
(void)outlen;
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int crysprStub_AES_CtrCipher(
|
||||
bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX *aes_key, /* AES context */
|
||||
unsigned char *iv, /* iv */
|
||||
const unsigned char *indata,/* src */
|
||||
size_t inlen, /* length */
|
||||
unsigned char *out_txt) /* dest */
|
||||
bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX *aes_key, /* AES context */
|
||||
unsigned char *iv, /* iv */
|
||||
const unsigned char *indata,/* src */
|
||||
size_t inlen, /* length */
|
||||
unsigned char *out_txt) /* dest */
|
||||
{
|
||||
(void)bEncrypt;
|
||||
(void)aes_key;
|
||||
(void)iv;
|
||||
(void)indata;
|
||||
(void)inlen;
|
||||
(void)out_txt;
|
||||
(void)bEncrypt;
|
||||
(void)aes_key;
|
||||
(void)iv;
|
||||
(void)indata;
|
||||
(void)inlen;
|
||||
(void)out_txt;
|
||||
|
||||
return(-1);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int crysprStub_AES_GCMCipher(
|
||||
bool bEncrypt, /* true:encrypt, false:decrypt */
|
||||
CRYSPR_AESCTX *aes_key, /* AES context */
|
||||
unsigned char *iv, /* iv */
|
||||
const unsigned char *aad, /* associated data */
|
||||
size_t aadlen,
|
||||
const unsigned char * indata,
|
||||
size_t inlen,
|
||||
unsigned char *out_txt,
|
||||
unsigned char* out_tag)
|
||||
{
|
||||
(void)bEncrypt;
|
||||
(void)aes_key;
|
||||
(void)iv;
|
||||
(void)aad;
|
||||
(void)aadlen;
|
||||
(void)indata;
|
||||
(void)inlen;
|
||||
(void)out_txt;
|
||||
(void)out_tag;
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
unsigned char *crysprStub_SHA1_MsgDigest(
|
||||
const unsigned char *m, /* in: message */
|
||||
size_t m_len, /* message length */
|
||||
unsigned char *md) /* out: message digest buffer *160 bytes */
|
||||
const unsigned char *m, /* in: message */
|
||||
size_t m_len, /* message length */
|
||||
unsigned char *md) /* out: message digest buffer *160 bytes */
|
||||
{
|
||||
(void)m;
|
||||
(void)m_len;
|
||||
(void)md;
|
||||
(void)m;
|
||||
(void)m_len;
|
||||
(void)md;
|
||||
|
||||
return(NULL);//return md;
|
||||
return(NULL);//return md;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password-based Key Derivation Function
|
||||
*/
|
||||
int crysprStub_KmPbkdf2(
|
||||
CRYSPR_cb *cryspr_cb,
|
||||
char *passwd, /* passphrase */
|
||||
size_t passwd_len, /* passphrase len */
|
||||
unsigned char *salt, /* salt */
|
||||
size_t salt_len, /* salt_len */
|
||||
int itr, /* iterations */
|
||||
size_t key_len, /* key_len */
|
||||
unsigned char *out) /* derived key */
|
||||
CRYSPR_cb *cryspr_cb,
|
||||
char *passwd, /* passphrase */
|
||||
size_t passwd_len, /* passphrase len */
|
||||
unsigned char *salt, /* salt */
|
||||
size_t salt_len, /* salt_len */
|
||||
int itr, /* iterations */
|
||||
size_t key_len, /* key_len */
|
||||
unsigned char *out) /* derived key */
|
||||
{
|
||||
(void)cryspr_cb;
|
||||
(void)passwd;
|
||||
(void)passwd_len;
|
||||
(void)salt;
|
||||
(void)salt_len;
|
||||
(void)itr;
|
||||
(void)key_len;
|
||||
(void)out;
|
||||
(void)cryspr_cb;
|
||||
(void)passwd;
|
||||
(void)passwd_len;
|
||||
(void)salt;
|
||||
(void)salt_len;
|
||||
(void)itr;
|
||||
(void)key_len;
|
||||
(void)out;
|
||||
|
||||
/* >>Todo:
|
||||
* develop PBKDF2 using SHA1 primitive cryspr_cb->cryspr->sha1_msg_digest() for cryptolibs not providing it
|
||||
*/
|
||||
return(-1);
|
||||
/* >>Todo:
|
||||
* develop PBKDF2 using SHA1 primitive cryspr_cb->cryspr->sha1_msg_digest() for cryptolibs not providing it
|
||||
*/
|
||||
return(-1);
|
||||
}
|
||||
|
||||
static int crysprFallback_KmSetKey(CRYSPR_cb *cryspr_cb, bool bWrap, const unsigned char *kek, size_t kek_len)
|
||||
{
|
||||
CRYSPR_AESCTX *aes_kek = CRYSPR_GETKEK(cryspr_cb);
|
||||
CRYSPR_AESCTX *aes_kek = CRYSPR_GETKEK(cryspr_cb);
|
||||
|
||||
if (cryspr_cb->cryspr->aes_set_key(HCRYPT_CTX_MODE_AESECB, bWrap, kek, kek_len, aes_kek)) {
|
||||
HCRYPT_LOG(LOG_ERR, "aes_set_%s_key(kek) failed\n", bWrap? "encrypt": "decrypt");
|
||||
return(-1);
|
||||
}
|
||||
if (cryspr_cb->cryspr->aes_set_key(HCRYPT_CTX_MODE_AESECB, bWrap, kek, kek_len, aes_kek)) {
|
||||
HCRYPT_LOG(LOG_ERR, "aes_set_%s_key(kek) failed\n", bWrap? "encrypt": "decrypt");
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -144,7 +168,7 @@ static const unsigned char default_iv[] = {
|
|||
int crysprFallback_AES_WrapKey(CRYSPR_cb *cryspr_cb,
|
||||
unsigned char *out,
|
||||
const unsigned char *in,
|
||||
unsigned int inlen)
|
||||
unsigned int inlen)
|
||||
{
|
||||
unsigned char *A, B[16], *R;
|
||||
const unsigned char *iv = default_iv;
|
||||
|
@ -180,13 +204,13 @@ int crysprFallback_AES_WrapKey(CRYSPR_cb *cryspr_cb,
|
|||
}
|
||||
}
|
||||
memcpy(out, A, 8);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crysprFallback_AES_UnwrapKey(CRYSPR_cb *cryspr_cb,
|
||||
unsigned char *out,
|
||||
const unsigned char *in,
|
||||
unsigned int inlen)
|
||||
unsigned int inlen)
|
||||
{
|
||||
unsigned char *A, B[16], *R;
|
||||
const unsigned char *iv = default_iv;
|
||||
|
@ -225,9 +249,9 @@ int crysprFallback_AES_UnwrapKey(CRYSPR_cb *cryspr_cb,
|
|||
if (memcmp(A, iv, 8))
|
||||
{
|
||||
memset(out, 0, inlen);
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *_crysprFallback_GetOutbuf(CRYSPR_cb *cryspr_cb, size_t pfx_len, size_t out_len)
|
||||
|
@ -249,12 +273,12 @@ CRYSPR_cb *crysprHelper_Open(CRYSPR_methods *cryspr, size_t cb_len, size_t max_l
|
|||
unsigned char *membuf;
|
||||
size_t memsiz, padded_len = hcryptMsg_PaddedLen(max_len, 128/8);
|
||||
|
||||
if(cb_len < sizeof(*cryspr_cb)) {
|
||||
HCRYPT_LOG(LOG_ERR, "crysprHelper_Open() cb_len too small (%zd < %zd)n",
|
||||
cb_len, sizeof(*cryspr_cb));
|
||||
return(NULL);
|
||||
}
|
||||
memsiz = cb_len + (CRYSPR_OUTMSGMAX * padded_len);
|
||||
if(cb_len < sizeof(*cryspr_cb)) {
|
||||
HCRYPT_LOG(LOG_ERR, "crysprHelper_Open() cb_len too small (%zd < %zd)n",
|
||||
cb_len, sizeof(*cryspr_cb));
|
||||
return(NULL);
|
||||
}
|
||||
memsiz = cb_len + (CRYSPR_OUTMSGMAX * padded_len);
|
||||
#if !CRYSPR_HAS_AESCTR
|
||||
memsiz += HCRYPT_CTR_STREAM_SZ;
|
||||
#endif /* !CRYSPR_HAS_AESCTR */
|
||||
|
@ -267,8 +291,8 @@ CRYSPR_cb *crysprHelper_Open(CRYSPR_methods *cryspr, size_t cb_len, size_t max_l
|
|||
membuf = (unsigned char *)cryspr_cb;
|
||||
membuf += sizeof(*cryspr_cb);
|
||||
|
||||
/*reserve cryspr's private data that caller will initialize */
|
||||
membuf += (cb_len-sizeof(CRYSPR_cb));
|
||||
/*reserve cryspr's private data that caller will initialize */
|
||||
membuf += (cb_len-sizeof(CRYSPR_cb));
|
||||
|
||||
#if !CRYSPR_HAS_AESCTR
|
||||
cryspr_cb->ctr_stream = membuf;
|
||||
|
@ -289,28 +313,33 @@ CRYSPR_cb *crysprHelper_Open(CRYSPR_methods *cryspr, size_t cb_len, size_t max_l
|
|||
|
||||
int crysprHelper_Close(CRYSPR_cb *cryspr_cb)
|
||||
{
|
||||
free(cryspr_cb);
|
||||
return(0);
|
||||
free(cryspr_cb);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static CRYSPR_cb *crysprFallback_Open(CRYSPR_methods *cryspr, size_t max_len)
|
||||
{
|
||||
CRYSPR_cb *cryspr_cb;
|
||||
CRYSPR_cb *cryspr_cb;
|
||||
|
||||
cryspr_cb = crysprHelper_Open(cryspr, sizeof(CRYSPR_cb), max_len);
|
||||
return(cryspr_cb);
|
||||
cryspr_cb = crysprHelper_Open(cryspr, sizeof(CRYSPR_cb), max_len);
|
||||
return(cryspr_cb);
|
||||
}
|
||||
|
||||
static int crysprFallback_Close(CRYSPR_cb *cryspr_cb)
|
||||
{
|
||||
return(crysprHelper_Close(cryspr_cb));
|
||||
return(crysprHelper_Close(cryspr_cb));
|
||||
}
|
||||
|
||||
static int crysprFallback_MsSetKey(CRYSPR_cb *cryspr_cb, hcrypt_Ctx *ctx, const unsigned char *key, size_t key_len)
|
||||
{
|
||||
CRYSPR_AESCTX *aes_sek = CRYSPR_GETSEK(cryspr_cb, hcryptCtx_GetKeyIndex(ctx)); /* Ctx tells if it's for odd or even key */
|
||||
|
||||
if ((ctx->flags & HCRYPT_CTX_F_ENCRYPT) /* Encrypt key */
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM) { /* AES GCM mode */
|
||||
if (cryspr_cb->cryspr->aes_set_key(HCRYPT_CTX_MODE_AESGCM, (ctx->flags & HCRYPT_CTX_F_ENCRYPT) != 0, key, key_len, aes_sek)) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "CRYSPR->set_encrypt_key(sek) failed\n");
|
||||
return(-1);
|
||||
}
|
||||
} else if ((ctx->flags & HCRYPT_CTX_F_ENCRYPT) /* Encrypt key */
|
||||
|| (ctx->mode == HCRYPT_CTX_MODE_AESCTR)) { /* CTR mode decrypts using encryption methods */
|
||||
if (cryspr_cb->cryspr->aes_set_key(HCRYPT_CTX_MODE_AESCTR, true, key, key_len, aes_sek)) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "CRYSPR->set_encrypt_key(sek) failed\n");
|
||||
|
@ -395,10 +424,17 @@ static int crysprFallback_MsEncrypt(
|
|||
* to reserve room for unencrypted message header in output buffer
|
||||
*/
|
||||
pfx_len = ctx->msg_info->pfx_len;
|
||||
/* Extra 16 bytes are needed for an authentication tag in GCM. */
|
||||
const int aux_len = (ctx->mode == HCRYPT_CTX_MODE_AESGCM) ? HAICRYPT_AUTHTAG_MAX : 0;
|
||||
|
||||
/* Get buffer room from the internal circular output buffer */
|
||||
out_msg = _crysprFallback_GetOutbuf(cryspr_cb, pfx_len, in_data[0].len);
|
||||
/* Auth tag produced by AES GCM. */
|
||||
unsigned char tag[HAICRYPT_AUTHTAG_MAX];
|
||||
|
||||
/*
|
||||
* Get buffer room from the internal circular output buffer.
|
||||
* Reserve additional 16 bytes for auth tag in AES GCM mode when needed.
|
||||
*/
|
||||
out_msg = _crysprFallback_GetOutbuf(cryspr_cb, pfx_len, in_data[0].len + aux_len);
|
||||
if (NULL == out_msg) {
|
||||
/* input data too big */
|
||||
return(-1);
|
||||
|
@ -406,6 +442,7 @@ static int crysprFallback_MsEncrypt(
|
|||
|
||||
switch(ctx->mode) {
|
||||
case HCRYPT_CTX_MODE_AESCTR: /* Counter mode */
|
||||
case HCRYPT_CTX_MODE_AESGCM:
|
||||
{
|
||||
/* Get current key (odd|even) from context */
|
||||
CRYSPR_AESCTX *aes_key = CRYSPR_GETSEK(cryspr_cb, hcryptCtx_GetKeyIndex(ctx)); /* Ctx tells if it's for odd or even key */
|
||||
|
@ -416,48 +453,64 @@ static int crysprFallback_MsEncrypt(
|
|||
hcrypt_Pki pki = hcryptMsg_GetPki(ctx->msg_info, in_data[0].pfx, 1);
|
||||
|
||||
/*
|
||||
* Compute the Initial Vector
|
||||
* IV (128-bit):
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0s | pki | ctr |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* XOR
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | nonce +
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* pki (32-bit): packet index
|
||||
* ctr (16-bit): block counter
|
||||
* nonce (112-bit): number used once (salt)
|
||||
*/
|
||||
* Compute the Initial Vector
|
||||
* IV (128-bit):
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0s | pki | ctr |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* XOR
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | nonce +
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* pki (32-bit): packet index
|
||||
* ctr (16-bit): block counter
|
||||
* nonce (112-bit): number used once (salt)
|
||||
*/
|
||||
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);
|
||||
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
|
||||
{
|
||||
const int iret = cryspr_cb->cryspr->aes_gcm_cipher(true, aes_key, iv, in_data[0].pfx, pfx_len, in_data[0].payload, in_data[0].len,
|
||||
&out_msg[pfx_len], tag);
|
||||
if (iret) {
|
||||
return(iret);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#if CRYSPR_HAS_AESCTR
|
||||
cryspr_cb->cryspr->aes_ctr_cipher(true, aes_key, iv, in_data[0].payload, in_data[0].len,
|
||||
&out_msg[pfx_len]);
|
||||
cryspr_cb->cryspr->aes_ctr_cipher(true, aes_key, iv, in_data[0].payload, in_data[0].len,
|
||||
&out_msg[pfx_len]);
|
||||
#else /*CRYSPR_HAS_AESCTR*/
|
||||
/* Create CtrStream. May be longer than in_len (next cryspr block size boundary) */
|
||||
int iret = _crysprFallback_AES_SetCtrStream(cryspr_cb, ctx, in_data[0].len, iv);
|
||||
if (iret) {
|
||||
return(iret);
|
||||
}
|
||||
/* Reserve output buffer for cryspr */
|
||||
out_msg = _crysprFallback_GetOutbuf(cryspr_cb, pfx_len, cryspr_cb->ctr_stream_len);
|
||||
|
||||
/* Create KeyStream (encrypt CtrStream) */
|
||||
iret = cryspr_cb->cryspr->aes_ecb_cipher(true, aes_key,
|
||||
cryspr_cb->ctr_stream, cryspr_cb->ctr_stream_len,
|
||||
&out_msg[pfx_len], &out_len);
|
||||
if (iret) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "hcOpenSSL_AES_ecb_cipher(encrypt, failed\n");
|
||||
return(iret);
|
||||
}
|
||||
/* Create CtrStream. May be longer than in_len (next cryspr block size boundary) */
|
||||
int iret = _crysprFallback_AES_SetCtrStream(cryspr_cb, ctx, in_data[0].len, iv);
|
||||
if (iret) {
|
||||
return(iret);
|
||||
}
|
||||
/* Reserve output buffer for cryspr */
|
||||
out_msg = _crysprFallback_GetOutbuf(cryspr_cb, pfx_len, cryspr_cb->ctr_stream_len);
|
||||
|
||||
/* Create KeyStream (encrypt CtrStream) */
|
||||
iret = cryspr_cb->cryspr->aes_ecb_cipher(true, aes_key,
|
||||
cryspr_cb->ctr_stream, cryspr_cb->ctr_stream_len,
|
||||
&out_msg[pfx_len], &out_len);
|
||||
if (iret) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "hcOpenSSL_AES_ecb_cipher(encrypt, failed\n");
|
||||
return(iret);
|
||||
}
|
||||
#endif/*CRYSPR_HAS_AESCTR*/
|
||||
}
|
||||
/* Prepend packet prefix (clear text) in output buffer */
|
||||
memcpy(out_msg, in_data[0].pfx, pfx_len);
|
||||
/* CTR mode output length is same as input, no padding */
|
||||
out_len = in_data[0].len;
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
|
||||
{
|
||||
memcpy(out_msg + pfx_len + out_len, tag, sizeof(tag));
|
||||
out_len += sizeof(tag);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCRYPT_CTX_MODE_CLRTXT: /* Clear text mode (transparent mode for tests) */
|
||||
|
@ -497,8 +550,12 @@ static int crysprFallback_MsEncrypt(
|
|||
memcpy(in_data[0].payload, &out_msg[pfx_len], out_len);
|
||||
}
|
||||
#else /* CRYSPR_HAS_AESCTR */
|
||||
/* Copy output data back in input buffer */
|
||||
memcpy(in_data[0].payload, &out_msg[pfx_len], out_len);
|
||||
/* Copy output data back in input buffer */
|
||||
memcpy(in_data[0].payload, &out_msg[pfx_len], out_len);
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM) {
|
||||
// Encoding produced more payload (auth tag).
|
||||
return (int)out_len;
|
||||
}
|
||||
#endif /* CRYSPR_HAS_AESCTR */
|
||||
} else {
|
||||
/* Copy header in output buffer if needed */
|
||||
|
@ -533,8 +590,8 @@ static int crysprFallback_MsDecrypt(CRYSPR_cb *cryspr_cb, hcrypt_Ctx *ctx,
|
|||
if (NULL != out_txt) {
|
||||
switch(ctx->mode) {
|
||||
case HCRYPT_CTX_MODE_AESCTR:
|
||||
case HCRYPT_CTX_MODE_AESGCM:
|
||||
{
|
||||
#if CRYSPR_HAS_AESCTR
|
||||
/* Get current key (odd|even) from context */
|
||||
CRYSPR_AESCTX *aes_key = CRYSPR_GETSEK(cryspr_cb, hcryptCtx_GetKeyIndex(ctx));
|
||||
unsigned char iv[CRYSPR_AESBLKSZ];
|
||||
|
@ -560,54 +617,63 @@ static int crysprFallback_MsDecrypt(CRYSPR_cb *cryspr_cb, hcrypt_Ctx *ctx,
|
|||
*/
|
||||
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);
|
||||
|
||||
cryspr_cb->cryspr->aes_ctr_cipher(false, aes_key, iv, in_data[0].payload, in_data[0].len,
|
||||
out_txt);
|
||||
out_len = in_data[0].len;
|
||||
#else /*CRYSPR_HAS_AESCTR*/
|
||||
/* Get current key (odd|even) from context */
|
||||
CRYSPR_AESCTX *aes_key = CRYSPR_GETSEK(cryspr_cb, hcryptCtx_GetKeyIndex(ctx));
|
||||
unsigned char iv[CRYSPR_AESBLKSZ];
|
||||
int iret = 0;
|
||||
|
||||
/* Get input packet index (in network order) */
|
||||
hcrypt_Pki pki = hcryptMsg_GetPki(ctx->msg_info, in_data[0].pfx, 1);
|
||||
|
||||
/*
|
||||
* Compute the Initial Vector
|
||||
* IV (128-bit):
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0s | pki | ctr |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* XOR
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | nonce +
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* pki (32-bit): packet index
|
||||
* ctr (16-bit): block counter
|
||||
* nonce (112-bit): number used once (salt)
|
||||
*/
|
||||
hcrypt_SetCtrIV((unsigned char *)&pki, ctx->salt, iv);
|
||||
|
||||
/* Create CtrStream. May be longer than in_len (next cipher block size boundary) */
|
||||
iret = _crysprFallback_AES_SetCtrStream(cryspr_cb, ctx, in_data[0].len, iv);
|
||||
if (iret) {
|
||||
return(iret);
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
|
||||
{
|
||||
unsigned char* tag = in_data[0].payload + in_data[0].len - HAICRYPT_AUTHTAG_MAX;
|
||||
int liret = cryspr_cb->cryspr->aes_gcm_cipher(false, aes_key, iv, in_data[0].pfx, ctx->msg_info->pfx_len, in_data[0].payload, in_data[0].len - HAICRYPT_AUTHTAG_MAX,
|
||||
out_txt, tag);
|
||||
if (liret) {
|
||||
return(liret);
|
||||
}
|
||||
out_len = in_data[0].len - HAICRYPT_AUTHTAG_MAX;
|
||||
}
|
||||
/* Reserve output buffer for cryspr */
|
||||
out_txt = _crysprFallback_GetOutbuf(cryspr_cb, 0, cryspr_cb->ctr_stream_len);
|
||||
else {
|
||||
#if CRYSPR_HAS_AESCTR
|
||||
cryspr_cb->cryspr->aes_ctr_cipher(false, aes_key, iv, in_data[0].payload, in_data[0].len,
|
||||
out_txt);
|
||||
out_len = in_data[0].len;
|
||||
#else /*CRYSPR_HAS_AESCTR*/
|
||||
|
||||
/* Create KeyStream (encrypt CtrStream) */
|
||||
iret = cryspr_cb->cryspr->aes_ecb_cipher(true, aes_key,
|
||||
/* Get input packet index (in network order) */
|
||||
hcrypt_Pki pki = hcryptMsg_GetPki(ctx->msg_info, in_data[0].pfx, 1);
|
||||
|
||||
/*
|
||||
* Compute the Initial Vector
|
||||
* IV (128-bit):
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | 0s | pki | ctr |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* XOR
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* | nonce +
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
* pki (32-bit): packet index
|
||||
* ctr (16-bit): block counter
|
||||
* nonce (112-bit): number used once (salt)
|
||||
*/
|
||||
hcrypt_SetCtrIV((unsigned char*)&pki, ctx->salt, iv);
|
||||
|
||||
/* Create CtrStream. May be longer than in_len (next cipher block size boundary) */
|
||||
int liret = _crysprFallback_AES_SetCtrStream(cryspr_cb, ctx, in_data[0].len, iv);
|
||||
if (liret) {
|
||||
return(liret);
|
||||
}
|
||||
/* Reserve output buffer for cryspr */
|
||||
out_txt = _crysprFallback_GetOutbuf(cryspr_cb, 0, cryspr_cb->ctr_stream_len);
|
||||
|
||||
/* Create KeyStream (encrypt CtrStream) */
|
||||
liret = cryspr_cb->cryspr->aes_ecb_cipher(true, aes_key,
|
||||
cryspr_cb->ctr_stream, cryspr_cb->ctr_stream_len,
|
||||
out_txt, &out_len);
|
||||
if (iret) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "crysprNatural_AES_ecb_cipher(encrypt failed\n");
|
||||
return(iret);
|
||||
}
|
||||
if (liret) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "crysprNatural_AES_ecb_cipher(encrypt failed\n");
|
||||
return(liret);
|
||||
}
|
||||
|
||||
#endif /*CRYSPR_HAS_AESCTR*/
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HCRYPT_CTX_MODE_CLRTXT:
|
||||
|
@ -638,6 +704,7 @@ static int crysprFallback_MsDecrypt(CRYSPR_cb *cryspr_cb, hcrypt_Ctx *ctx,
|
|||
#else /* CRYSPR_HAS_AESCTR */
|
||||
/* Copy output data back in input buffer */
|
||||
memcpy(in_data[0].payload, out_txt, out_len);
|
||||
in_data->len = out_len;
|
||||
#endif /* CRYSPR_HAS_AESCTR */
|
||||
} else {
|
||||
/* Copy header in output buffer if needed */
|
||||
|
@ -683,9 +750,9 @@ CRYSPR_methods *crysprInit(CRYSPR_methods *cryspr)
|
|||
cryspr->aes_set_key = crysprStub_AES_SetKey;
|
||||
cryspr->aes_ecb_cipher = crysprStub_AES_EcbCipher;
|
||||
cryspr->aes_ctr_cipher = crysprStub_AES_CtrCipher;
|
||||
cryspr->aes_gcm_cipher = crysprStub_AES_GCMCipher;
|
||||
cryspr->sha1_msg_digest = crysprStub_SHA1_MsgDigest;
|
||||
|
||||
|
||||
/* Crypto Session API */
|
||||
cryspr->open = crysprFallback_Open;
|
||||
cryspr->close = crysprFallback_Close;
|
||||
|
@ -704,5 +771,5 @@ CRYSPR_methods *crysprInit(CRYSPR_methods *cryspr)
|
|||
|
||||
HaiCrypt_Cryspr HaiCryptCryspr_Get_Instance(void)
|
||||
{
|
||||
return((HaiCrypt_Cryspr)cryspr4SRT());
|
||||
return((HaiCrypt_Cryspr)cryspr4SRT());
|
||||
}
|
||||
|
|
33
trunk/3rdparty/srt-1-fit/haicrypt/cryspr.h
vendored
33
trunk/3rdparty/srt-1-fit/haicrypt/cryspr.h
vendored
|
@ -40,32 +40,32 @@ extern "C" {
|
|||
|
||||
typedef struct tag_CRYSPR_cb {
|
||||
#ifdef CRYSPR2
|
||||
CRYSPR_AESCTX *aes_kek; /* Key Encrypting Key (KEK) */
|
||||
CRYSPR_AESCTX *aes_sek[2]; /* even/odd Stream Encrypting Key (SEK) */
|
||||
CRYSPR_AESCTX *aes_kek; /* Key Encrypting Key (KEK) */
|
||||
CRYSPR_AESCTX *aes_sek[2]; /* even/odd Stream Encrypting Key (SEK) */
|
||||
#define CRYSPR_GETKEK(cb) ((cb)->aes_kek)
|
||||
#define CRYSPR_GETSEK(cb,kk) ((cb)->aes_sek[kk])
|
||||
#else /*CRYSPR2*/
|
||||
CRYSPR_AESCTX aes_kek; /* Key Encrypting Key (KEK) */
|
||||
CRYSPR_AESCTX aes_sek[2]; /* even/odd Stream Encrypting Key (SEK) */
|
||||
CRYSPR_AESCTX aes_kek; /* Key Encrypting Key (KEK) */
|
||||
CRYSPR_AESCTX aes_sek[2]; /* even/odd Stream Encrypting Key (SEK) */
|
||||
#define CRYSPR_GETKEK(cb) (&((cb)->aes_kek))
|
||||
#define CRYSPR_GETSEK(cb,kk) (&((cb)->aes_sek[kk]))
|
||||
#endif /*CRYSPR2*/
|
||||
|
||||
struct tag_CRYSPR_methods *cryspr;
|
||||
struct tag_CRYSPR_methods *cryspr;
|
||||
|
||||
#if !CRYSPR_HAS_AESCTR
|
||||
/* Reserve room to build the counter stream ourself */
|
||||
#define HCRYPT_CTR_BLK_SZ CRYSPR_AESBLKSZ
|
||||
#define HCRYPT_CTR_STREAM_SZ 2048
|
||||
unsigned char * ctr_stream;
|
||||
size_t ctr_stream_len; /* Content size */
|
||||
size_t ctr_stream_siz; /* Allocated length */
|
||||
unsigned char * ctr_stream;
|
||||
size_t ctr_stream_len; /* Content size */
|
||||
size_t ctr_stream_siz; /* Allocated length */
|
||||
#endif /* !CRYSPR_HAS_AESCTR */
|
||||
|
||||
#define CRYSPR_OUTMSGMAX 6
|
||||
uint8_t * outbuf; /* output circle buffer */
|
||||
size_t outbuf_ofs; /* write offset in circle buffer */
|
||||
size_t outbuf_siz; /* circle buffer size */
|
||||
uint8_t * outbuf; /* output circle buffer */
|
||||
size_t outbuf_ofs; /* write offset in circle buffer */
|
||||
size_t outbuf_siz; /* circle buffer size */
|
||||
} CRYSPR_cb;
|
||||
|
||||
typedef struct tag_CRYSPR_methods {
|
||||
|
@ -100,6 +100,17 @@ typedef struct tag_CRYSPR_methods {
|
|||
size_t inlen, /* src length */
|
||||
unsigned char *out_txt);/* dest */
|
||||
|
||||
int (*aes_gcm_cipher)(
|
||||
bool bEncrypt, /* true:encrypt false:decrypt (don't care with CTR) */
|
||||
CRYSPR_AESCTX* aes_key, /* ctx */
|
||||
unsigned char* iv, /* iv */
|
||||
const unsigned char* aad, /* associated data */
|
||||
size_t aadlen,
|
||||
const unsigned char* indata, /* src (clear text) */
|
||||
size_t inlen, /* src length */
|
||||
unsigned char* out_txt, /* dest */
|
||||
unsigned char* out_tag);
|
||||
|
||||
unsigned char *(*sha1_msg_digest)(
|
||||
const unsigned char *m, /* in: message */
|
||||
size_t m_len, /* message length */
|
||||
|
|
8
trunk/3rdparty/srt-1-fit/haicrypt/haicrypt.h
vendored
8
trunk/3rdparty/srt-1-fit/haicrypt/haicrypt.h
vendored
|
@ -36,7 +36,7 @@ HaiCrypt_Cryspr HaiCryptCryspr_Get_Instance (void); /* Return a default crys
|
|||
#define HAICRYPT_PWD_MAX_SZ 80 /* MAX password (for Password-based Key Derivation) */
|
||||
#define HAICRYPT_KEY_MAX_SZ 32 /* MAX key */
|
||||
#define HAICRYPT_SECRET_MAX_SZ (HAICRYPT_PWD_MAX_SZ > HAICRYPT_KEY_MAX_SZ ? HAICRYPT_PWD_MAX_SZ : HAICRYPT_KEY_MAX_SZ)
|
||||
|
||||
#define HAICRYPT_AUTHTAG_MAX 16 /* maximum length of the auth tag (e.g. GCM) */
|
||||
|
||||
#define HAICRYPT_SALT_SZ 16
|
||||
|
||||
|
@ -60,6 +60,7 @@ typedef struct {
|
|||
#define HAICRYPT_CFG_F_TX 0x01 /* !TX -> RX */
|
||||
#define HAICRYPT_CFG_F_CRYPTO 0x02 /* Perform crypto Tx:Encrypt Rx:Decrypt */
|
||||
#define HAICRYPT_CFG_F_FEC 0x04 /* Do Forward Error Correction */
|
||||
#define HAICRYPT_CFG_F_GCM 0x08 /* Use AES-GCM */
|
||||
unsigned flags;
|
||||
|
||||
HaiCrypt_Secret secret; /* Security Association */
|
||||
|
@ -108,10 +109,15 @@ int HaiCrypt_Tx_ManageKeys(HaiCrypt_Handle hhc, void *out_p[], size_t out_len_p
|
|||
int HaiCrypt_Tx_Data(HaiCrypt_Handle hhc, unsigned char *pfx, unsigned char *data, size_t data_len);
|
||||
int HaiCrypt_Rx_Data(HaiCrypt_Handle hhc, unsigned char *pfx, unsigned char *data, size_t data_len);
|
||||
|
||||
/// @brief Check if the crypto service provider supports AES GCM.
|
||||
/// @return returns 1 if AES GCM is supported, 0 otherwise.
|
||||
int HaiCrypt_IsAESGCM_Supported(void);
|
||||
|
||||
/* Status values */
|
||||
|
||||
#define HAICRYPT_ERROR -1
|
||||
#define HAICRYPT_ERROR_WRONG_SECRET -2
|
||||
#define HAICRYPT_ERROR_CIPHER -3
|
||||
#define HAICRYPT_OK 0
|
||||
|
||||
|
||||
|
|
|
@ -44,10 +44,10 @@ int HaiCrypt_SetLogLevel(int level, int logfa)
|
|||
#define HAICRYPT_DEFINE_LOG_DISPATCHER(LOGLEVEL, dispatcher) \
|
||||
int HaiCrypt_LogF_##LOGLEVEL ( const char* file, int line, const char* function, const char* format, ...) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
va_start(ap, format); \
|
||||
srt_logging::LogDispatcher& lg = hclog.dispatcher; \
|
||||
if (!lg.CheckEnabled()) return -1; \
|
||||
va_list ap; \
|
||||
va_start(ap, format); \
|
||||
lg().setloc(file, line, function).vform(format, ap); \
|
||||
va_end(ap); \
|
||||
return 0; \
|
||||
|
|
|
@ -21,7 +21,7 @@ HAICRYPT_DECLARE_LOG_DISPATCHER(LOG_EMERG);
|
|||
|
||||
#define HCRYPT_LOG_INIT()
|
||||
#define HCRYPT_LOG_EXIT()
|
||||
#define HCRYPT_LOG(lvl, fmt, ...) HaiCrypt_LogF_##lvl (__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__)
|
||||
#define HCRYPT_LOG(lvl, ...) HaiCrypt_LogF_##lvl (__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
|
||||
|
||||
#if ENABLE_HAICRYPT_LOGGING == 2
|
||||
#define HCRYPT_DEV 1
|
||||
|
|
18
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt.c
vendored
18
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt.c
vendored
|
@ -197,6 +197,9 @@ int HaiCrypt_ExtractConfig(HaiCrypt_Handle hhcSrc, HaiCrypt_Cfg* pcfg)
|
|||
if ((ctx->flags & HCRYPT_CTX_F_ENCRYPT) == HCRYPT_CTX_F_ENCRYPT)
|
||||
pcfg->flags |= HAICRYPT_CFG_F_TX;
|
||||
|
||||
if (ctx->mode == HCRYPT_CTX_MODE_AESGCM)
|
||||
pcfg->flags |= HAICRYPT_CFG_F_GCM;
|
||||
|
||||
/* Set this explicitly - this use of this library is SRT only. */
|
||||
pcfg->xport = HAICRYPT_XPT_SRT;
|
||||
pcfg->cryspr = crypto->cryspr;
|
||||
|
@ -237,7 +240,8 @@ int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handl
|
|||
|
||||
if (tx) {
|
||||
HaiCrypt_Cfg crypto_config;
|
||||
HaiCrypt_ExtractConfig(hhcSrc, &crypto_config);
|
||||
if (-1 == HaiCrypt_ExtractConfig(hhcSrc, &crypto_config))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Just invert the direction written in flags and use the
|
||||
|
@ -303,8 +307,7 @@ int HaiCrypt_Clone(HaiCrypt_Handle hhcSrc, HaiCrypt_CryptoDir tx, HaiCrypt_Handl
|
|||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Configure contexts */
|
||||
/* Configure contexts. Note that GCM mode has been already copied from the source context. */
|
||||
if (hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[0], NULL)
|
||||
|| hcryptCtx_Rx_Init(cryptoClone, &cryptoClone->ctx_pair[1], NULL)) {
|
||||
free(cryptoClone);
|
||||
|
@ -336,3 +339,12 @@ int HaiCrypt_Close(HaiCrypt_Handle hhc)
|
|||
HCRYPT_LOG_EXIT();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int HaiCrypt_IsAESGCM_Supported(void)
|
||||
{
|
||||
#if CRYSPR_HAS_AESGCM
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
15
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt.h
vendored
15
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt.h
vendored
|
@ -32,10 +32,6 @@ written by
|
|||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4018)
|
||||
#endif
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
@ -163,7 +159,18 @@ int hcryptCtx_Tx_AsmKM(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *a
|
|||
int hcryptCtx_Tx_ManageKM(hcrypt_Session *crypto);
|
||||
int hcryptCtx_Tx_InjectKM(hcrypt_Session *crypto, void *out_p[], size_t out_len_p[], int maxout);
|
||||
|
||||
/// @brief Initialize receiving crypto context.
|
||||
/// @param crypto library instance handle.
|
||||
/// @param ctx additional crypto context.
|
||||
/// @param cfg crypto configuration.
|
||||
/// @return -1 on error, 0 otherwise.
|
||||
int hcryptCtx_Rx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cfg *cfg);
|
||||
|
||||
/// @brief Parse an incoming message related to cryptography module.
|
||||
/// @param crypto library instance handle.
|
||||
/// @param msg a message to parse.
|
||||
/// @param msg_len length of the message in bytes.
|
||||
/// @return 0 on success; -3 on cipher mode mismatch; -2 on unmatched shared secret; -1 on other failures.
|
||||
int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *msg, size_t msg_len);
|
||||
|
||||
#endif /* HCRYPT_H */
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef struct {
|
|||
typedef struct tag_hcrypt_Ctx {
|
||||
struct tag_hcrypt_Ctx * alt; /* Alternative ctx (even/odd) */
|
||||
|
||||
#define HCRYPT_CTX_F_MSG 0x00FF /* Aligned wiht message header flags */
|
||||
#define HCRYPT_CTX_F_MSG 0x00FF /* Aligned with message header flags */
|
||||
#define HCRYPT_CTX_F_eSEK HCRYPT_MSG_F_eSEK
|
||||
#define HCRYPT_CTX_F_oSEK HCRYPT_MSG_F_oSEK
|
||||
#define HCRYPT_CTX_F_xSEK HCRYPT_MSG_F_xSEK
|
||||
|
@ -68,6 +68,7 @@ typedef struct tag_hcrypt_Ctx {
|
|||
#define HCRYPT_CTX_MODE_AESECB 1 /* Electronic Code Book mode */
|
||||
#define HCRYPT_CTX_MODE_AESCTR 2 /* Counter mode */
|
||||
#define HCRYPT_CTX_MODE_AESCBC 3 /* Cipher-block chaining mode */
|
||||
#define HCRYPT_CTX_MODE_AESGCM 4 /* AES GCM authenticated encryption */
|
||||
unsigned mode;
|
||||
|
||||
struct {
|
||||
|
|
|
@ -14,9 +14,9 @@ written by
|
|||
Haivision Systems Inc.
|
||||
|
||||
2011-06-23 (jdube)
|
||||
HaiCrypt initial implementation.
|
||||
HaiCrypt initial implementation.
|
||||
2014-03-11 (jdube)
|
||||
Adaptation for SRT.
|
||||
Adaptation for SRT.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
@ -24,16 +24,18 @@ written by
|
|||
|
||||
int hcryptCtx_Rx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cfg *cfg)
|
||||
{
|
||||
ctx->mode = HCRYPT_CTX_MODE_AESCTR;
|
||||
ctx->status = HCRYPT_CTX_S_INIT;
|
||||
if (cfg) {
|
||||
ctx->mode = (cfg->flags & HAICRYPT_CFG_F_GCM) ? HCRYPT_CTX_MODE_AESGCM : HCRYPT_CTX_MODE_AESCTR;
|
||||
}
|
||||
ctx->status = HCRYPT_CTX_S_INIT;
|
||||
|
||||
ctx->msg_info = crypto->msg_info;
|
||||
ctx->msg_info = crypto->msg_info;
|
||||
|
||||
if (cfg && hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
|
||||
return(-1);
|
||||
}
|
||||
ctx->status = HCRYPT_CTX_S_SARDY;
|
||||
return(0);
|
||||
if (cfg && hcryptCtx_SetSecret(crypto, ctx, &cfg->secret)) {
|
||||
return(-1);
|
||||
}
|
||||
ctx->status = HCRYPT_CTX_S_SARDY;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int hcryptCtx_Rx_Rekey(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *sek, size_t sek_len)
|
||||
|
@ -98,9 +100,31 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m
|
|||
}
|
||||
|
||||
/* Check options support */
|
||||
if ((HCRYPT_CIPHER_AES_CTR != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
|
||||
|| (HCRYPT_AUTH_NONE != km_msg[HCRYPT_MSG_KM_OFS_AUTH])) {
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported option\n");
|
||||
if (HCRYPT_CIPHER_AES_CTR != km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
|
||||
&& HCRYPT_CIPHER_AES_GCM != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
|
||||
{
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported cipher\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
#if !CRYSPR_HAS_AESGCM
|
||||
/* Only OpenSSL EVP crypto provider allows the use of GCM.Add this condition. Reject if GCM is not supported by the CRYSPR. */
|
||||
if (HCRYPT_CIPHER_AES_GCM == km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
|
||||
{
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported GCM cipher\n");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (HCRYPT_CIPHER_AES_GCM == km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
|
||||
&& HCRYPT_AUTH_AES_GCM != km_msg[HCRYPT_MSG_KM_OFS_AUTH]) {
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg GCM auth method was expected.\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (HCRYPT_CIPHER_AES_CTR == km_msg[HCRYPT_MSG_KM_OFS_CIPHER]
|
||||
&& HCRYPT_AUTH_NONE != km_msg[HCRYPT_MSG_KM_OFS_AUTH]) {
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "KMmsg unsupported auth method\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
@ -144,6 +168,13 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m
|
|||
do_pbkdf = 1; /* Impact on password derived kek */
|
||||
}
|
||||
|
||||
/* Check cipher mode */
|
||||
if (ctx->mode != km_msg[HCRYPT_MSG_KM_OFS_CIPHER])
|
||||
{
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "cipher mode mismatch\n");
|
||||
return(-3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Regenerate KEK if it is password derived
|
||||
* and Salt or SEK length changed
|
||||
|
@ -159,7 +190,7 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m
|
|||
/* Unwrap SEK(s) and set in context */
|
||||
if (0 > crypto->cryspr->km_unwrap(crypto->cryspr_cb, seks,
|
||||
&km_msg[HCRYPT_MSG_KM_OFS_SALT + salt_len],
|
||||
(sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ)) {
|
||||
(unsigned int)((sek_cnt * sek_len) + HAICRYPT_WRAPKEY_SIGN_SZ))) {
|
||||
HCRYPT_LOG(LOG_WARNING, "%s", "unwrap key failed\n");
|
||||
return(-2); //Report unmatched shared secret
|
||||
}
|
||||
|
@ -184,7 +215,6 @@ int hcryptCtx_Rx_ParseKM(hcrypt_Session *crypto, unsigned char *km_msg, size_t m
|
|||
alt->salt_len = salt_len;
|
||||
|
||||
if (kek_len) { /* New or changed KEK */
|
||||
// memcpy(&alt->aes_kek, &ctx->aes_kek, sizeof(alt->aes_kek));
|
||||
alt->status = HCRYPT_CTX_S_SARDY;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,18 +14,18 @@ written by
|
|||
Haivision Systems Inc.
|
||||
|
||||
2011-06-23 (jdube)
|
||||
HaiCrypt initial implementation.
|
||||
HaiCrypt initial implementation.
|
||||
2014-03-11 (jdube)
|
||||
Adaptation for SRT.
|
||||
Adaptation for SRT.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <win/wintime.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <win/wintime.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include "hcrypt.h"
|
||||
|
||||
|
@ -33,7 +33,7 @@ int hcryptCtx_Tx_Init(hcrypt_Session *crypto, hcrypt_Ctx *ctx, const HaiCrypt_Cf
|
|||
{
|
||||
ctx->cfg.key_len = cfg->key_len;
|
||||
|
||||
ctx->mode = HCRYPT_CTX_MODE_AESCTR;
|
||||
ctx->mode = (cfg->flags & HAICRYPT_CFG_F_GCM) ? HCRYPT_CTX_MODE_AESGCM : HCRYPT_CTX_MODE_AESCTR;
|
||||
ctx->status = HCRYPT_CTX_S_INIT;
|
||||
|
||||
ctx->msg_info = crypto->msg_info;
|
||||
|
@ -52,14 +52,14 @@ int hcryptCtx_Tx_Rekey(hcrypt_Session *crypto, hcrypt_Ctx *ctx)
|
|||
|
||||
/* Generate Salt */
|
||||
ctx->salt_len = HAICRYPT_SALT_SZ;
|
||||
if (0 > (iret = crypto->cryspr->prng(ctx->salt, ctx->salt_len))) {
|
||||
if (0 > (iret = crypto->cryspr->prng(ctx->salt, (int)ctx->salt_len))) {
|
||||
HCRYPT_LOG(LOG_ERR, "PRNG(salt[%zd]) failed\n", ctx->salt_len);
|
||||
return(iret);
|
||||
}
|
||||
|
||||
/* Generate SEK */
|
||||
ctx->sek_len = ctx->cfg.key_len;
|
||||
if (0 > (iret = crypto->cryspr->prng(ctx->sek, ctx->sek_len))) {
|
||||
if (0 > (iret = crypto->cryspr->prng(ctx->sek, (int)ctx->sek_len))) {
|
||||
HCRYPT_LOG(LOG_ERR, "PRNG(sek[%zd] failed\n", ctx->sek_len);
|
||||
return(iret);
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ int hcryptCtx_Tx_Refresh(hcrypt_Session *crypto)
|
|||
|
||||
HCRYPT_LOG(LOG_DEBUG, "refresh/generate SEK. salt_len=%d sek_len=%d\n", (int)new_ctx->salt_len, (int)new_ctx->sek_len);
|
||||
|
||||
if (0 > crypto->cryspr->prng(new_ctx->sek, new_ctx->sek_len)) {
|
||||
if (0 > crypto->cryspr->prng(new_ctx->sek, (int)new_ctx->sek_len)) {
|
||||
HCRYPT_LOG(LOG_ERR, "PRNG(sek[%zd] failed\n", new_ctx->sek_len);
|
||||
return(-1);
|
||||
}
|
||||
|
@ -299,9 +299,9 @@ int hcryptCtx_Tx_AsmKM(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *a
|
|||
2 == sek_cnt ? HCRYPT_MSG_F_xSEK : (ctx->flags & HCRYPT_MSG_F_xSEK));
|
||||
|
||||
/* crypto->KMmsg_cache[4..7]: KEKI=0 */
|
||||
km_msg[HCRYPT_MSG_KM_OFS_CIPHER] = HCRYPT_CIPHER_AES_CTR;
|
||||
km_msg[HCRYPT_MSG_KM_OFS_AUTH] = HCRYPT_AUTH_NONE;
|
||||
km_msg[HCRYPT_MSG_KM_OFS_SE] = crypto->se;
|
||||
km_msg[HCRYPT_MSG_KM_OFS_CIPHER] = (ctx->mode == HCRYPT_CTX_MODE_AESGCM) ? HCRYPT_CIPHER_AES_GCM : HCRYPT_CIPHER_AES_CTR;
|
||||
km_msg[HCRYPT_MSG_KM_OFS_AUTH] = (ctx->mode == HCRYPT_CTX_MODE_AESGCM) ? HCRYPT_AUTH_AES_GCM : HCRYPT_AUTH_NONE;
|
||||
km_msg[HCRYPT_MSG_KM_OFS_SE] = (char) crypto->se;
|
||||
hcryptMsg_KM_SetSaltLen(km_msg, ctx->salt_len);
|
||||
hcryptMsg_KM_SetSekLen(km_msg, ctx->sek_len);
|
||||
|
||||
|
@ -322,7 +322,7 @@ int hcryptCtx_Tx_AsmKM(hcrypt_Session *crypto, hcrypt_Ctx *ctx, unsigned char *a
|
|||
}
|
||||
if (0 > crypto->cryspr->km_wrap(crypto->cryspr_cb,
|
||||
&km_msg[HCRYPT_MSG_KM_OFS_SALT + ctx->salt_len],
|
||||
seks, sek_cnt * ctx->sek_len)) {
|
||||
seks, (unsigned int)(sek_cnt * ctx->sek_len))) {
|
||||
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "wrap key failed\n");
|
||||
return(-1);
|
||||
|
|
|
@ -122,8 +122,10 @@ typedef struct {
|
|||
#define HCRYPT_CIPHER_AES_ECB 1
|
||||
#define HCRYPT_CIPHER_AES_CTR 2
|
||||
#define HCRYPT_CIPHER_AES_CBC 3
|
||||
#define HCRYPT_CIPHER_AES_GCM 4
|
||||
|
||||
#define HCRYPT_AUTH_NONE 0
|
||||
#define HCRYPT_AUTH_AES_GCM 1
|
||||
|
||||
#define HCRYPT_SE_TSUDP 1
|
||||
hcrypt_MsgInfo * hcryptMsg_STA_MsgInfo(void);
|
||||
|
@ -148,8 +150,8 @@ typedef struct {
|
|||
#define hcryptMsg_KM_GetSaltLen(msg) (size_t)((msg)[HCRYPT_MSG_KM_OFS_SLEN] * 4)
|
||||
#define hcryptMsg_KM_GetSekLen(msg) (size_t)((msg)[HCRYPT_MSG_KM_OFS_KLEN] * 4)
|
||||
|
||||
#define hcryptMsg_KM_SetSaltLen(msg,len)do {(msg)[HCRYPT_MSG_KM_OFS_SLEN] = (len)/4;} while(0)
|
||||
#define hcryptMsg_KM_SetSekLen(msg,len) do {(msg)[HCRYPT_MSG_KM_OFS_KLEN] = (len)/4;} while(0)
|
||||
#define hcryptMsg_KM_SetSaltLen(msg,len)do {(msg)[HCRYPT_MSG_KM_OFS_SLEN] = (unsigned char)(len)/4;} while(0)
|
||||
#define hcryptMsg_KM_SetSekLen(msg,len) do {(msg)[HCRYPT_MSG_KM_OFS_KLEN] = (unsigned char)(len)/4;} while(0)
|
||||
|
||||
|
||||
#endif /* HCRYPT_MSG_H */
|
||||
|
|
|
@ -53,7 +53,7 @@ int HaiCrypt_Rx_Data(HaiCrypt_Handle hhc,
|
|||
if (0 > (nb = crypto->cryspr->ms_decrypt(crypto->cryspr_cb, ctx, &indata, 1, NULL, NULL, NULL))) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "ms_decrypt failed\n");
|
||||
} else {
|
||||
nb = indata.len;
|
||||
nb = (int)indata.len;
|
||||
}
|
||||
} else { /* No key received yet */
|
||||
nb = 0;
|
||||
|
@ -124,9 +124,6 @@ int HaiCrypt_Rx_Process(HaiCrypt_Handle hhc,
|
|||
|| (0 != memcmp(ctx->KMmsg_cache, in_msg, in_len))) { /* or different */
|
||||
|
||||
nbout = hcryptCtx_Rx_ParseKM(crypto, in_msg, in_len);
|
||||
//-2: unmatched shared secret
|
||||
//-1: other failures
|
||||
//0: success
|
||||
} else {
|
||||
nbout = 0;
|
||||
}
|
||||
|
|
49
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt_tx.c
vendored
49
trunk/3rdparty/srt-1-fit/haicrypt/hcrypt_tx.c
vendored
|
@ -14,20 +14,20 @@ written by
|
|||
Haivision Systems Inc.
|
||||
|
||||
2011-06-23 (jdube)
|
||||
HaiCrypt initial implementation.
|
||||
HaiCrypt initial implementation.
|
||||
2014-03-11 (jdube)
|
||||
Adaptation for SRT.
|
||||
Adaptation for SRT.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h> /* NULL */
|
||||
#include <string.h> /* memcpy */
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdint.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <arpa/inet.h> /* htonl */
|
||||
#include <arpa/inet.h> /* htonl */
|
||||
#endif
|
||||
#include "hcrypt.h"
|
||||
|
||||
|
@ -55,26 +55,25 @@ int HaiCrypt_Tx_GetBuf(HaiCrypt_Handle hhc, size_t data_len, unsigned char **in_
|
|||
int HaiCrypt_Tx_ManageKeys(HaiCrypt_Handle hhc, void *out_p[], size_t out_len_p[], int maxout)
|
||||
{
|
||||
hcrypt_Session *crypto = (hcrypt_Session *)hhc;
|
||||
hcrypt_Ctx *ctx = crypto->ctx;
|
||||
int nbout = 0;
|
||||
|
||||
if ((NULL == crypto)
|
||||
|| (NULL == ctx)
|
||||
|| (NULL == crypto->ctx)
|
||||
|| (NULL == out_p)
|
||||
|| (NULL == out_len_p)) {
|
||||
HCRYPT_LOG(LOG_ERR, "ManageKeys: invalid params: crypto=%p crypto->ctx=%p\n", crypto, ctx);
|
||||
HCRYPT_LOG(LOG_ERR, "ManageKeys: invalid params: crypto=%p out_p=%p out_len_p=%p\n",
|
||||
crypto, out_p, out_len_p);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Manage Key Material (refresh, announce, decommission) */
|
||||
hcryptCtx_Tx_ManageKM(crypto);
|
||||
|
||||
ctx = crypto->ctx;
|
||||
if (NULL == ctx) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "crypto context not defined\n");
|
||||
if (NULL == crypto->ctx) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "crypto context NULL after ManageKM call\n");
|
||||
return(-1);
|
||||
}
|
||||
ASSERT(ctx->status == HCRYPT_CTX_S_ACTIVE);
|
||||
ASSERT(crypto->ctx->status == HCRYPT_CTX_S_ACTIVE);
|
||||
|
||||
nbout = hcryptCtx_Tx_InjectKM(crypto, out_p, out_len_p, maxout);
|
||||
return(nbout);
|
||||
|
@ -83,31 +82,36 @@ int HaiCrypt_Tx_ManageKeys(HaiCrypt_Handle hhc, void *out_p[], size_t out_len_p[
|
|||
int HaiCrypt_Tx_GetKeyFlags(HaiCrypt_Handle hhc)
|
||||
{
|
||||
hcrypt_Session *crypto = (hcrypt_Session *)hhc;
|
||||
hcrypt_Ctx *ctx = crypto->ctx;
|
||||
hcrypt_Ctx *ctx = NULL;
|
||||
|
||||
if ((NULL == crypto)
|
||||
|| (NULL == ctx)){
|
||||
|| (NULL == (ctx = crypto->ctx))) {
|
||||
HCRYPT_LOG(LOG_ERR, "GetKeyFlags: invalid params: crypto=%p crypto->ctx=%p\n", crypto, ctx);
|
||||
return(-1);
|
||||
}
|
||||
return(hcryptCtx_GetKeyFlags(ctx));
|
||||
return(hcryptCtx_GetKeyFlags(crypto->ctx));
|
||||
}
|
||||
|
||||
int HaiCrypt_Tx_Data(HaiCrypt_Handle hhc,
|
||||
unsigned char *in_pfx, unsigned char *in_data, size_t in_len)
|
||||
{
|
||||
hcrypt_Session *crypto = (hcrypt_Session *)hhc;
|
||||
hcrypt_Ctx *ctx = crypto->ctx;
|
||||
hcrypt_Ctx *ctx = NULL;
|
||||
int nbout = 0;
|
||||
|
||||
if ((NULL == crypto)
|
||||
|| (NULL == ctx)){
|
||||
|| (NULL == (ctx = crypto->ctx))) {
|
||||
HCRYPT_LOG(LOG_ERR, "Tx_Data: invalid params: crypto=%p crypto->ctx=%p\n", crypto, ctx);
|
||||
return(-1);
|
||||
}
|
||||
/* Get/Set packet index */
|
||||
ctx->msg_info->indexMsg(in_pfx, ctx->MSpfx_cache);
|
||||
|
||||
if (hcryptMsg_GetKeyIndex(ctx->msg_info, in_pfx) != hcryptCtx_GetKeyIndex(ctx))
|
||||
{
|
||||
HCRYPT_LOG(LOG_ERR, "Tx_Data: Key mismatch!");
|
||||
}
|
||||
|
||||
/* Encrypt */
|
||||
{
|
||||
hcrypt_DataDesc indata;
|
||||
|
@ -130,11 +134,11 @@ int HaiCrypt_Tx_Process(HaiCrypt_Handle hhc,
|
|||
void *out_p[], size_t out_len_p[], int maxout)
|
||||
{
|
||||
hcrypt_Session *crypto = (hcrypt_Session *)hhc;
|
||||
hcrypt_Ctx *ctx = crypto->ctx;
|
||||
hcrypt_Ctx *ctx = NULL;
|
||||
int nb, nbout = 0;
|
||||
|
||||
if ((NULL == crypto)
|
||||
|| (NULL == ctx)
|
||||
|| (NULL == (ctx = crypto->ctx))
|
||||
|| (NULL == out_p)
|
||||
|| (NULL == out_len_p)) {
|
||||
HCRYPT_LOG(LOG_ERR, "Tx_Process: invalid params: crypto=%p crypto->ctx=%p\n", crypto, ctx);
|
||||
|
@ -144,11 +148,6 @@ int HaiCrypt_Tx_Process(HaiCrypt_Handle hhc,
|
|||
/* Manage Key Material (refresh, announce, decommission) */
|
||||
hcryptCtx_Tx_ManageKM(crypto);
|
||||
|
||||
ctx = crypto->ctx;
|
||||
if (NULL == ctx) {
|
||||
HCRYPT_LOG(LOG_ERR, "%s", "crypto context not defined\n");
|
||||
return(-1);
|
||||
}
|
||||
ASSERT(ctx->status == HCRYPT_CTX_S_ACTIVE);
|
||||
|
||||
nbout += hcryptCtx_Tx_InjectKM(crypto, out_p, out_len_p, maxout);
|
||||
|
|
57
trunk/3rdparty/srt-1-fit/scripts/CheckCXXStdPutTime.cmake
vendored
Normal file
57
trunk/3rdparty/srt-1-fit/scripts/CheckCXXStdPutTime.cmake
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
# SRT - Secure, Reliable, Transport Copyright (c) 2022 Haivision Systems Inc.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
# obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
|
||||
# Check for C++11 std::put_time().
|
||||
#
|
||||
# Sets:
|
||||
# HAVE_CXX_STD_PUT_TIME
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
function(CheckCXXStdPutTime)
|
||||
|
||||
unset(HAVE_CXX_STD_PUT_TIME CACHE)
|
||||
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE) # CMake 3.6
|
||||
|
||||
unset(CMAKE_REQUIRED_FLAGS)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
unset(CMAKE_REQUIRED_LINK_OPTIONS)
|
||||
|
||||
set(CheckCXXStdPutTime_CODE
|
||||
"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
int main(void)
|
||||
{
|
||||
const int result = 0;
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::tm tm = *std::localtime(&t);
|
||||
std::cout
|
||||
<< std::put_time(&tm, \"%FT%T\")
|
||||
<< std::setfill('0')
|
||||
<< std::setw(6)
|
||||
<< std::endl;
|
||||
return result;
|
||||
}
|
||||
"
|
||||
)
|
||||
|
||||
# NOTE: Should we set -std or use the current compiler configuration.
|
||||
# It seems that the top level build does not track the compiler
|
||||
# in a consistent manner. So Maybe we need this?
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11")
|
||||
|
||||
# Check that the compiler can build the std::put_time() example:
|
||||
message(STATUS "Checking for C++ 'std::put_time()':")
|
||||
check_cxx_source_compiles(
|
||||
"${CheckCXXStdPutTime_CODE}"
|
||||
HAVE_CXX_STD_PUT_TIME)
|
||||
|
||||
endfunction(CheckCXXStdPutTime)
|
|
@ -36,7 +36,7 @@ function(CheckGCCAtomicIntrinsics)
|
|||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
unset(CMAKE_REQUIRED_LINK_OPTIONS)
|
||||
|
||||
# Check for existance of libatomic and whether this symbol is present.
|
||||
# Check for existence of libatomic and whether this symbol is present.
|
||||
check_library_exists(atomic __atomic_fetch_add_8 "" HAVE_LIBATOMIC)
|
||||
|
||||
set(CheckLibAtomicCompiles_CODE
|
||||
|
|
|
@ -141,6 +141,7 @@ function(ShowProjectConfig)
|
|||
" HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC: ${HAVE_GCCATOMIC_INTRINSICS_REQUIRES_LIBATOMIC}\n"
|
||||
" HAVE_CXX_ATOMIC: ${HAVE_CXX_ATOMIC}\n"
|
||||
" HAVE_CXX_ATOMIC_STATIC: ${HAVE_CXX_ATOMIC_STATIC}\n"
|
||||
" HAVE_CXX_STD_PUT_TIME: ${HAVE_CXX_STD_PUT_TIME}\n"
|
||||
" Project Configuration:\n"
|
||||
" ENABLE_DEBUG: ${ENABLE_DEBUG}\n"
|
||||
" ENABLE_CXX11: ${ENABLE_CXX11}\n"
|
||||
|
|
3
trunk/3rdparty/srt-1-fit/scripts/build-android/README.md
vendored
Normal file
3
trunk/3rdparty/srt-1-fit/scripts/build-android/README.md
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
## Scripts for building SRT for Android
|
||||
|
||||
See [Building SRT for Android](../../docs/build/build-android.md) for the instructions.
|
111
trunk/3rdparty/srt-1-fit/scripts/build-android/build-android
vendored
Executable file
111
trunk/3rdparty/srt-1-fit/scripts/build-android/build-android
vendored
Executable file
|
@ -0,0 +1,111 @@
|
|||
#!/bin/sh
|
||||
|
||||
echo_help()
|
||||
{
|
||||
echo "Usage: $0 [options...]"
|
||||
echo " -n NDK root path for the build"
|
||||
echo " -a Target API level"
|
||||
echo " -t Space-separated list of target architectures"
|
||||
echo " Android supports the following architectures: armeabi-v7a arm64-v8a x86 x86_64"
|
||||
echo " -e Encryption library to be used. Possible options: openssl (default) mbedtls"
|
||||
echo " -o OpenSSL version. E.g. 1.1.1l"
|
||||
echo " -m Mbed TLS version. E.g. v2.26.0"
|
||||
echo
|
||||
echo "Example: ./build-android -n /home/username/Android/Sdk/ndk/23.0.7599858 -a 28 -t \"arm64-v8a x86_64\""
|
||||
echo
|
||||
}
|
||||
|
||||
# Init optional command line vars
|
||||
NDK_ROOT=""
|
||||
API_LEVEL=28
|
||||
BUILD_TARGETS="armeabi-v7a arm64-v8a x86 x86_64"
|
||||
OPENSSL_VERSION=1.1.1l
|
||||
ENC_LIB=openssl
|
||||
MBEDTLS_VERSION=v2.26.0
|
||||
|
||||
while getopts n:a:t:o:s:e:m: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
n) NDK_ROOT=${OPTARG};;
|
||||
a) API_LEVEL=${OPTARG};;
|
||||
t) BUILD_TARGETS=${OPTARG};;
|
||||
o) OPENSSL_VERSION=${OPTARG};;
|
||||
s) SRT_VERSION=${OPTARG};;
|
||||
e) ENC_LIB=${OPTARG};;
|
||||
m) MBEDTLS_VERSION=${OPTARG};;
|
||||
*) twentytwo=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
echo_help
|
||||
|
||||
if [ -z "$NDK_ROOT" ] ; then
|
||||
echo "NDK directory not set."
|
||||
exit 128
|
||||
else
|
||||
if [ ! -d "$NDK_ROOT" ]; then
|
||||
echo "NDK directory does not exist: $NDK_ROOT"
|
||||
exit 128
|
||||
fi
|
||||
fi
|
||||
|
||||
SCRIPT_DIR=$(pwd)
|
||||
HOST_TAG='unknown'
|
||||
unamestr=$(uname -s)
|
||||
if [ "$unamestr" = 'Linux' ]; then
|
||||
HOST_TAG='linux-x86_64'
|
||||
elif [ "$unamestr" = 'Darwin' ]; then
|
||||
if [ $(uname -p) = 'arm' ]; then
|
||||
echo "NDK does not currently support ARM64"
|
||||
exit 128
|
||||
else
|
||||
HOST_TAG='darwin-x86_64'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Write files relative to current location
|
||||
BASE_DIR=$(pwd)
|
||||
case "${BASE_DIR}" in
|
||||
*\ * )
|
||||
echo "Your path contains whitespaces, which is not supported by 'make install'."
|
||||
exit 128
|
||||
;;
|
||||
esac
|
||||
cd "${BASE_DIR}"
|
||||
|
||||
if [ $ENC_LIB = 'openssl' ]; then
|
||||
echo "Building OpenSSL $OPENSSL_VERSION"
|
||||
$SCRIPT_DIR/mkssl -n $NDK_ROOT -a $API_LEVEL -t "$BUILD_TARGETS" -o $OPENSSL_VERSION -d $BASE_DIR -h $HOST_TAG
|
||||
elif [ $ENC_LIB = 'mbedtls' ]; then
|
||||
if [ ! -d $BASE_DIR/mbedtls ]; then
|
||||
git clone https://github.com/ARMmbed/mbedtls mbedtls
|
||||
if [ ! -z "$MBEDTLS_VERSION" ]; then
|
||||
git -C $BASE_DIR/mbedtls checkout $MBEDTLS_VERSION
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Unknown encryption library. Possible options: openssl mbedtls"
|
||||
exit 128
|
||||
fi
|
||||
|
||||
# Build working copy of srt repository
|
||||
REPO_DIR="../.."
|
||||
|
||||
for build_target in $BUILD_TARGETS; do
|
||||
LIB_DIR=$BASE_DIR/$build_target/lib
|
||||
JNI_DIR=$BASE_DIR/prebuilt/$build_target
|
||||
|
||||
mkdir -p $JNI_DIR
|
||||
|
||||
if [ $ENC_LIB = 'mbedtls' ]; then
|
||||
$SCRIPT_DIR/mkmbedtls -n $NDK_ROOT -a $API_LEVEL -t $build_target -s $BASE_DIR/mbedtls -i $BASE_DIR/$build_target
|
||||
cp $LIB_DIR/libmbedcrypto.so $JNI_DIR/libmbedcrypto.so
|
||||
cp $LIB_DIR/libmbedtls.so $JNI_DIR/libmbedtls.so
|
||||
cp $LIB_DIR/libmbedx509.so $JNI_DIR/libmbedx509.so
|
||||
fi
|
||||
|
||||
git -C $REPO_DIR clean -fd -e scripts
|
||||
$SCRIPT_DIR/mksrt -n $NDK_ROOT -a $API_LEVEL -t $build_target -e $ENC_LIB -s $REPO_DIR -i $BASE_DIR/$build_target
|
||||
cp $LIB_DIR/libsrt.so $JNI_DIR/libsrt.so
|
||||
done
|
27
trunk/3rdparty/srt-1-fit/scripts/build-android/mkmbedtls
vendored
Executable file
27
trunk/3rdparty/srt-1-fit/scripts/build-android/mkmbedtls
vendored
Executable file
|
@ -0,0 +1,27 @@
|
|||
#!/bin/sh
|
||||
|
||||
while getopts s:i:t:n:a: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
s) SRC_DIR=${OPTARG};;
|
||||
i) INSTALL_DIR=${OPTARG};;
|
||||
t) ARCH_ABI=${OPTARG};;
|
||||
n) NDK_ROOT=${OPTARG};;
|
||||
a) API_LEVEL=${OPTARG};;
|
||||
*) twentytwo=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
BUILD_DIR=/tmp/mbedtls_android_build
|
||||
rm -rf $BUILD_DIR
|
||||
mkdir $BUILD_DIR
|
||||
cd $BUILD_DIR
|
||||
cmake -DENABLE_TESTING=Off -DUSE_SHARED_MBEDTLS_LIBRARY=On \
|
||||
-DCMAKE_PREFIX_PATH=$INSTALL_DIR -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DCMAKE_ANDROID_NDK=$NDK_ROOT \
|
||||
-DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=$API_LEVEL -DCMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \
|
||||
-DCMAKE_C_FLAGS="-fPIC" -DCMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo $SRC_DIR
|
||||
cmake --build .
|
||||
cmake --install .
|
32
trunk/3rdparty/srt-1-fit/scripts/build-android/mksrt
vendored
Executable file
32
trunk/3rdparty/srt-1-fit/scripts/build-android/mksrt
vendored
Executable file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
while getopts s:i:t:n:a:e: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
s) SRC_DIR=${OPTARG};;
|
||||
i) INSTALL_DIR=${OPTARG};;
|
||||
t) ARCH_ABI=${OPTARG};;
|
||||
n) NDK_ROOT=${OPTARG};;
|
||||
a) API_LEVEL=${OPTARG};;
|
||||
e) ENC_LIB=${OPTARG};;
|
||||
*) twentytwo=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
cd $SRC_DIR
|
||||
./configure --use-enclib=$ENC_LIB \
|
||||
--use-openssl-pc=OFF \
|
||||
--OPENSSL_INCLUDE_DIR=$INSTALL_DIR/include \
|
||||
--OPENSSL_CRYPTO_LIBRARY=$INSTALL_DIR/lib/libcrypto.a --OPENSSL_SSL_LIBRARY=$INSTALL_DIR/lib/libssl.a \
|
||||
--STATIC_MBEDTLS=FALSE \
|
||||
--MBEDTLS_INCLUDE_DIR=$INSTALL_DIR/include --MBEDTLS_INCLUDE_DIRS=$INSTALL_DIR/include \
|
||||
--MBEDTLS_LIBRARIES=$INSTALL_DIR/lib/libmbedtls.so \
|
||||
--CMAKE_PREFIX_PATH=$INSTALL_DIR --CMAKE_INSTALL_PREFIX=$INSTALL_DIR --CMAKE_ANDROID_NDK=$NDK_ROOT \
|
||||
--CMAKE_SYSTEM_NAME=Android --CMAKE_SYSTEM_VERSION=$API_LEVEL --CMAKE_ANDROID_ARCH_ABI=$ARCH_ABI \
|
||||
--CMAKE_C_FLAGS="-fPIC" --CMAKE_SHARED_LINKER_FLAGS="-Wl,--build-id" \
|
||||
--enable-c++11 --enable-stdcxx-sync \
|
||||
--enable-debug=2 --enable-logging=0 --enable-heavy-logging=0 --enable-apps=0
|
||||
make
|
||||
make install
|
85
trunk/3rdparty/srt-1-fit/scripts/build-android/mkssl
vendored
Executable file
85
trunk/3rdparty/srt-1-fit/scripts/build-android/mkssl
vendored
Executable file
|
@ -0,0 +1,85 @@
|
|||
#!/bin/sh
|
||||
|
||||
while getopts n:o:a:t:d:h: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
n) ANDROID_NDK=${OPTARG};;
|
||||
o) OPENSSL_VERSION=${OPTARG};;
|
||||
a) API_LEVEL=${OPTARG};;
|
||||
t) BUILD_TARGETS=${OPTARG};;
|
||||
d) OUT_DIR=${OPTARG};;
|
||||
h) HOST_TAG=${OPTARG};;
|
||||
*) twentytwo=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
BUILD_DIR=/tmp/openssl_android_build
|
||||
|
||||
if [ ! -d openssl-${OPENSSL_VERSION} ]
|
||||
then
|
||||
if [ ! -f openssl-${OPENSSL_VERSION}.tar.gz ]
|
||||
then
|
||||
wget https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz || exit 128
|
||||
fi
|
||||
tar xzf openssl-${OPENSSL_VERSION}.tar.gz || exit 128
|
||||
fi
|
||||
|
||||
cd openssl-${OPENSSL_VERSION} || exit 128
|
||||
|
||||
|
||||
##### export ndk directory. Required by openssl-build-scripts #####
|
||||
case ${OPENSSL_VERSION} in
|
||||
1.1.1*)
|
||||
export ANDROID_NDK_HOME=$ANDROID_NDK
|
||||
;;
|
||||
*)
|
||||
export ANDROID_NDK_ROOT=$ANDROID_NDK
|
||||
;;
|
||||
esac
|
||||
|
||||
export PATH=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG/bin:$PATH
|
||||
|
||||
##### build-function #####
|
||||
build_the_thing() {
|
||||
make clean
|
||||
./Configure $SSL_TARGET -D__ANDROID_API__=$API_LEVEL && \
|
||||
make SHLIB_EXT=.so && \
|
||||
make install SHLIB_EXT=.so DESTDIR=$DESTDIR || exit 128
|
||||
}
|
||||
|
||||
##### set variables according to build-tagret #####
|
||||
for build_target in $BUILD_TARGETS
|
||||
do
|
||||
case $build_target in
|
||||
armeabi-v7a)
|
||||
DESTDIR="$BUILD_DIR/armeabi-v7a"
|
||||
SSL_TARGET="android-arm"
|
||||
;;
|
||||
x86)
|
||||
DESTDIR="$BUILD_DIR/x86"
|
||||
SSL_TARGET="android-x86"
|
||||
;;
|
||||
x86_64)
|
||||
DESTDIR="$BUILD_DIR/x86_64"
|
||||
SSL_TARGET="android-x86_64"
|
||||
;;
|
||||
arm64-v8a)
|
||||
DESTDIR="$BUILD_DIR/arm64-v8a"
|
||||
SSL_TARGET="android-arm64"
|
||||
;;
|
||||
esac
|
||||
|
||||
rm -rf $DESTDIR
|
||||
build_the_thing
|
||||
#### copy libraries and includes to output-directory #####
|
||||
mkdir -p $OUT_DIR/$build_target/include
|
||||
cp -R $DESTDIR/usr/local/include/* $OUT_DIR/$build_target/include
|
||||
cp -R $DESTDIR/usr/local/ssl/* $OUT_DIR/$build_target/
|
||||
mkdir -p $OUT_DIR/$build_target/lib
|
||||
cp -R $DESTDIR/usr/local/lib/*.so $OUT_DIR/$build_target/lib
|
||||
cp -R $DESTDIR/usr/local/lib/*.a $OUT_DIR/$build_target/lib
|
||||
done
|
||||
|
||||
echo Success
|
|
@ -101,7 +101,7 @@ if ( $null -eq (Get-Command "cmake.exe" -ErrorAction SilentlyContinue) ) {
|
|||
|
||||
# get pthreads from nuget if CXX11 is not enabled
|
||||
if ( $CXX11 -eq "OFF" ) {
|
||||
# get pthreads (this is legacy, and is only availble in nuget for VS2015 and VS2013)
|
||||
# get pthreads (this is legacy, and is only available in nuget for VS2015 and VS2013)
|
||||
if ( $VS_VERSION -gt 2015 ) {
|
||||
Write-Output "Pthreads is not recommended for use beyond VS2015 and is not supported by this build script - aborting build"
|
||||
throw
|
||||
|
|
|
@ -114,7 +114,7 @@ set errortypes {
|
|||
SIDINVAL "Invalid socket ID"
|
||||
ISUNBOUND "Cannot do this operation on an UNBOUND socket"
|
||||
NOLISTEN "Socket is not in listening state"
|
||||
ISRENDEZVOUS "Listen/accept is not supported in rendezous connection setup"
|
||||
ISRENDEZVOUS "Listen/accept is not supported in rendezvous connection setup"
|
||||
ISRENDUNBOUND "Cannot call connect on UNBOUND socket in rendezvous connection setup"
|
||||
INVALMSGAPI "Incorrect use of Message API (sendmsg/recvmsg)."
|
||||
INVALBUFFERAPI "Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile)."
|
||||
|
|
|
@ -11,7 +11,7 @@ ExternalProject_Add(
|
|||
BINARY_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build"
|
||||
GIT_REPOSITORY
|
||||
https://github.com/google/googletest.git
|
||||
GIT_TAG release-1.8.1
|
||||
GIT_TAG release-1.10.0
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
|
|
@ -4,15 +4,24 @@ Script designed to generate release notes template with main sections, contribut
|
|||
|
||||
In order to obtain the git log file since the previous release (e.g., v1.4.0), use the following command:
|
||||
|
||||
```shell
|
||||
git log --pretty=format:"%h|%s|%an|%ae" v1.4.0...HEAD > commits.csv
|
||||
```
|
||||
git log --pretty=format:"%h|%s|%an|%ae" v1.4.0...HEAD^ > commits.csv
|
||||
|
||||
Use the produced `commits.csv` file as an input to the script:
|
||||
|
||||
```shell
|
||||
python scripts/release-notes/generate-release-notes.py commits.csv
|
||||
```
|
||||
|
||||
The script produces `release-notes.md` as an output.
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* Python 3.6+
|
||||
|
||||
To install Python libraries use:
|
||||
```
|
||||
```shell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
|
4
trunk/3rdparty/srt-1-fit/scripts/srt-dev.lua
vendored
4
trunk/3rdparty/srt-1-fit/scripts/srt-dev.lua
vendored
|
@ -115,7 +115,7 @@ fields.tsbpd_delay = ProtoField.uint16("srt_dev.tsbpd_delay", "TsbPd Delay", bas
|
|||
fields.rcv_tsbpd_delay = ProtoField.uint16("srt_dev.rcv_tsbpd_delay", "Receiver TsbPd Delay", base.DEC)
|
||||
fields.snd_tsbpd_delay = ProtoField.uint16("srt_dev.snd_tsbpd_delay", "Sender TsbPd Delay", base.DEC)
|
||||
|
||||
-- V adn PT status flag
|
||||
-- V and PT status flag
|
||||
local V_state_select = {
|
||||
[1] = "Initial version"
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ function srt_dev.dissector (tvb, pinfo, tree)
|
|||
offset = offset + 4
|
||||
|
||||
if UDT_version == 4 then
|
||||
-- UDT version is 4, packet is diffrent from UDT version 5
|
||||
-- UDT version is 4, packet is different from UDT version 5
|
||||
-- Handle sock type
|
||||
local sock_type = tvb(offset, 4):uint()
|
||||
if sock_type == 1 then
|
||||
|
|
10
trunk/3rdparty/srt-1-fit/scripts/test_vista.c
vendored
Normal file
10
trunk/3rdparty/srt-1-fit/scripts/test_vista.c
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* Copyright © 2023 Steve Lhomme */
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#include <windows.h>
|
||||
#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 /* _WIN32_WINNT_VISTA */
|
||||
#error NOPE
|
||||
#endif
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -125,9 +125,11 @@ Section "Install"
|
|||
; Header files.
|
||||
CreateDirectory "$INSTDIR\include\srt"
|
||||
SetOutPath "$INSTDIR\include\srt"
|
||||
File "${RepoDir}\srtcore\access_control.h"
|
||||
File "${RepoDir}\srtcore\logging_api.h"
|
||||
File "${RepoDir}\srtcore\platform_sys.h"
|
||||
File "${RepoDir}\srtcore\srt.h"
|
||||
File "${RepoDir}\srtcore\udt.h"
|
||||
File "${Build64Dir}\version.h"
|
||||
|
||||
CreateDirectory "$INSTDIR\include\win"
|
||||
|
|
|
@ -41,7 +41,7 @@ written by
|
|||
// CODE NOT IN USE 408: unused: no timeout predicted for listener callback
|
||||
#define SRT_REJX_CONFLICT 1409 // The resource being accessed is already locked for modification. This is in case of m=publish and the specified resource is currently read-only.
|
||||
// CODE NOT IN USE 410: unused: treated as a specific case of 404
|
||||
// CODE NOT IN USE 411: unused: no reason to include lenght in the protocol
|
||||
// CODE NOT IN USE 411: unused: no reason to include length in the protocol
|
||||
// CODE NOT IN USE 412: unused: preconditions not predicted in AC
|
||||
// CODE NOT IN USE 413: unused: AC size is already defined as 512
|
||||
// CODE NOT IN USE 414: unused: AC size is already defined as 512
|
||||
|
|
340
trunk/3rdparty/srt-1-fit/srtcore/api.cpp
vendored
340
trunk/3rdparty/srt-1-fit/srtcore/api.cpp
vendored
|
@ -326,6 +326,7 @@ SRTSOCKET srt::CUDTUnited::generateSocketID(bool for_group)
|
|||
// We have a rollover on the socket value, so
|
||||
// definitely we haven't made the Columbus mistake yet.
|
||||
m_SocketIDGenerator = MAX_SOCKET_VAL;
|
||||
sockval = MAX_SOCKET_VAL;
|
||||
}
|
||||
|
||||
// Check all sockets if any of them has this value.
|
||||
|
@ -459,10 +460,8 @@ SRTSOCKET srt::CUDTUnited::newSocket(CUDTSocket** pps)
|
|||
// failure and rollback
|
||||
delete ns;
|
||||
ns = NULL;
|
||||
}
|
||||
|
||||
if (!ns)
|
||||
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
|
||||
}
|
||||
|
||||
if (pps)
|
||||
*pps = ns;
|
||||
|
@ -563,7 +562,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen,
|
|||
}
|
||||
catch (const CUDTException&)
|
||||
{
|
||||
LOGF(cnlog.Fatal, "newConnection: IPE: all sockets occupied? Last gen=%d", m_SocketIDGenerator);
|
||||
LOGC(cnlog.Fatal, log << "newConnection: IPE: all sockets occupied? Last gen=" << m_SocketIDGenerator);
|
||||
// generateSocketID throws exception, which can be naturally handled
|
||||
// when the call is derived from the API call, but here it's called
|
||||
// internally in response to receiving a handshake. It must be handled
|
||||
|
@ -600,7 +599,8 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen,
|
|||
// this call causes sending the SRT Handshake through this socket.
|
||||
// Without this mapping the socket cannot be found and therefore
|
||||
// the SRT Handshake message would fail.
|
||||
HLOGF(cnlog.Debug, "newConnection: incoming %s, mapping socket %d", peer.str().c_str(), ns->m_SocketID);
|
||||
HLOGC(cnlog.Debug, log <<
|
||||
"newConnection: incoming " << peer.str() << ", mapping socket " << ns->m_SocketID);
|
||||
{
|
||||
ScopedLock cg(m_GlobControlLock);
|
||||
m_Sockets[ns->m_SocketID] = ns;
|
||||
|
@ -619,7 +619,14 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen,
|
|||
|
||||
// bind to the same addr of listening socket
|
||||
ns->core().open();
|
||||
updateListenerMux(ns, ls);
|
||||
if (!updateListenerMux(ns, ls))
|
||||
{
|
||||
// This is highly unlikely if not impossible, but there's
|
||||
// a theoretical runtime chance of failure so it should be
|
||||
// handled
|
||||
ns->core().m_RejectReason = SRT_REJ_IPE;
|
||||
throw false; // let it jump directly into the omni exception handler
|
||||
}
|
||||
|
||||
ns->core().acceptAndRespond(ls->m_SelfAddr, peer, hspkt, (w_hs));
|
||||
}
|
||||
|
@ -647,7 +654,8 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen,
|
|||
ScopedLock glock(m_GlobControlLock);
|
||||
try
|
||||
{
|
||||
HLOGF(cnlog.Debug, "newConnection: mapping peer %d to that socket (%d)\n", ns->m_PeerID, ns->m_SocketID);
|
||||
HLOGC(cnlog.Debug, log << "newConnection: mapping peer " << ns->m_PeerID
|
||||
<< " to that socket (" << ns->m_SocketID << ")");
|
||||
m_PeerRec[ns->getPeerSpec()].insert(ns->m_SocketID);
|
||||
}
|
||||
catch (...)
|
||||
|
@ -666,7 +674,7 @@ int srt::CUDTUnited::newConnection(const SRTSOCKET listen,
|
|||
// XXX this might require another check of group type.
|
||||
// For redundancy group, at least, update the status in the group
|
||||
CUDTGroup* g = ns->m_GroupOf;
|
||||
ScopedLock glock(g->m_GroupLock);
|
||||
ScopedLock grlock(g->m_GroupLock);
|
||||
if (g->m_bClosing)
|
||||
{
|
||||
error = 1; // "INTERNAL REJECTION"
|
||||
|
@ -911,6 +919,15 @@ int srt::CUDTUnited::bind(CUDTSocket* s, const sockaddr_any& name)
|
|||
if (s->m_Status != SRTS_INIT)
|
||||
throw CUDTException(MJ_NOTSUP, MN_NONE, 0);
|
||||
|
||||
if (s->core().m_config.iIpV6Only == -1 && name.family() == AF_INET6 && name.isany())
|
||||
{
|
||||
// V6ONLY option must be set explicitly if you want to bind to a wildcard address in IPv6
|
||||
HLOGP(smlog.Error,
|
||||
"bind: when binding to :: (IPv6 wildcard), SRTO_IPV6ONLY option must be set explicitly to 0 or 1");
|
||||
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
|
||||
s->core().open();
|
||||
updateMux(s, name);
|
||||
s->m_Status = SRTS_OPENED;
|
||||
|
@ -1078,7 +1095,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int
|
|||
SRTSOCKET u = CUDT::INVALID_SOCK;
|
||||
bool accepted = false;
|
||||
|
||||
// !!only one conection can be set up each time!!
|
||||
// !!only one connection can be set up each time!!
|
||||
while (!accepted)
|
||||
{
|
||||
UniqueLock accept_lock(ls->m_AcceptLock);
|
||||
|
@ -1179,7 +1196,7 @@ SRTSOCKET srt::CUDTUnited::accept(const SRTSOCKET listen, sockaddr* pw_addr, int
|
|||
int srt::CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockaddr* tarname, int namelen)
|
||||
{
|
||||
// Here both srcname and tarname must be specified
|
||||
if (!srcname || !tarname || size_t(namelen) < sizeof(sockaddr_in))
|
||||
if (!srcname || !tarname || namelen < int(sizeof(sockaddr_in)))
|
||||
{
|
||||
LOGC(aclog.Error,
|
||||
log << "connect(with source): invalid call: srcname=" << srcname << " tarname=" << tarname
|
||||
|
@ -1224,6 +1241,12 @@ int srt::CUDTUnited::connect(SRTSOCKET u, const sockaddr* srcname, const sockadd
|
|||
|
||||
int srt::CUDTUnited::connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn)
|
||||
{
|
||||
if (!name || namelen < int(sizeof(sockaddr_in)))
|
||||
{
|
||||
LOGC(aclog.Error, log << "connect(): invalid call: name=" << name << " namelen=" << namelen);
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL);
|
||||
}
|
||||
|
||||
sockaddr_any target_addr(name, namelen);
|
||||
if (target_addr.len == 0)
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
@ -1458,7 +1481,7 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i
|
|||
ns->m_GroupMemberData = f;
|
||||
ns->m_GroupOf = &g;
|
||||
f->weight = targets[tii].weight;
|
||||
LOGC(aclog.Note, log << "srt_connect_group: socket @" << sid << " added to group $" << g.m_GroupID);
|
||||
HLOGC(aclog.Debug, log << "srt_connect_group: socket @" << sid << " added to group $" << g.m_GroupID);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1474,21 +1497,13 @@ int srt::CUDTUnited::groupConnect(CUDTGroup* pg, SRT_SOCKGROUPCONFIG* targets, i
|
|||
|
||||
// XXX This should be reenabled later, this should
|
||||
// be probably still in use to exchange information about
|
||||
// packets assymetrically lost. But for no other purpose.
|
||||
// packets asymmetrically lost. But for no other purpose.
|
||||
/*
|
||||
ns->core().m_cbPacketArrival.set(ns->m_pUDT, &CUDT::groupPacketArrival);
|
||||
*/
|
||||
|
||||
int isn = g.currentSchedSequence();
|
||||
|
||||
// Don't synchronize ISN in case of synch on msgno. Every link
|
||||
// may send their own payloads independently.
|
||||
if (g.synconmsgno())
|
||||
{
|
||||
HLOGC(aclog.Debug, log << "groupConnect: NOT synchronizing sequence numbers: will sync on msgno");
|
||||
isn = -1;
|
||||
}
|
||||
|
||||
// Set it the groupconnect option, as all in-group sockets should have.
|
||||
ns->core().m_config.iGroupConnect = 1;
|
||||
|
||||
|
@ -1867,6 +1882,8 @@ int srt::CUDTUnited::connectIn(CUDTSocket* s, const sockaddr_any& target_addr, i
|
|||
*/
|
||||
try
|
||||
{
|
||||
// record peer address
|
||||
s->m_PeerAddr = target_addr;
|
||||
s->core().startConnect(target_addr, forced_isn);
|
||||
}
|
||||
catch (const CUDTException&) // Interceptor, just to change the state.
|
||||
|
@ -1946,9 +1963,9 @@ void srt::CUDTUnited::deleteGroup_LOCKED(CUDTGroup* g)
|
|||
|
||||
int srt::CUDTUnited::close(CUDTSocket* s)
|
||||
{
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSE. Acquiring control lock");
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << "CLOSE. Acquiring control lock");
|
||||
ScopedLock socket_cg(s->m_ControlLock);
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSING (removing from listening, closing CUDT)");
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << "CLOSING (removing from listening, closing CUDT)");
|
||||
|
||||
const bool synch_close_snd = s->core().m_config.bSynSending;
|
||||
|
||||
|
@ -1971,14 +1988,16 @@ int srt::CUDTUnited::close(CUDTSocket* s)
|
|||
// be unable to bind to this port that the about-to-delete listener
|
||||
// is currently occupying (due to blocked slot in the RcvQueue).
|
||||
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << " CLOSING (removing listener immediately)");
|
||||
HLOGC(smlog.Debug, log << s->core().CONID() << "CLOSING (removing listener immediately)");
|
||||
s->core().notListening();
|
||||
s->m_Status = SRTS_CLOSING;
|
||||
|
||||
// broadcast all "accept" waiting
|
||||
CSync::lock_notify_all(s->m_AcceptCond, s->m_AcceptLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->m_Status = SRTS_CLOSING;
|
||||
// Note: this call may be done on a socket that hasn't finished
|
||||
// sending all packets scheduled for sending, which means, this call
|
||||
// may block INDEFINITELY. As long as it's acceptable to block the
|
||||
|
@ -1989,7 +2008,7 @@ int srt::CUDTUnited::close(CUDTSocket* s)
|
|||
// synchronize with garbage collection.
|
||||
HLOGC(smlog.Debug,
|
||||
log << "@" << u << "U::close done. GLOBAL CLOSE: " << s->core().CONID()
|
||||
<< ". Acquiring GLOBAL control lock");
|
||||
<< "Acquiring GLOBAL control lock");
|
||||
ScopedLock manager_cg(m_GlobControlLock);
|
||||
// since "s" is located before m_GlobControlLock, locate it again in case
|
||||
// it became invalid
|
||||
|
@ -2101,6 +2120,7 @@ int srt::CUDTUnited::close(CUDTSocket* s)
|
|||
...
|
||||
}
|
||||
*/
|
||||
CSync::notify_one_relaxed(m_GCStopCond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2597,11 +2617,7 @@ void srt::CUDTUnited::checkBrokenSockets()
|
|||
// NOT WHETHER THEY ARE ALSO READY TO PLAY at the time when
|
||||
// this function is called (isRcvDataReady also checks if the
|
||||
// available data is "ready to play").
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
&& s->core().m_pRcvBuffer->hasAvailablePackets())
|
||||
#else
|
||||
&& s->core().m_pRcvBuffer->isRcvDataAvailable())
|
||||
#endif
|
||||
{
|
||||
const int bc = s->core().m_iBrokenCounter.load();
|
||||
if (bc > 0)
|
||||
|
@ -2615,7 +2631,7 @@ void srt::CUDTUnited::checkBrokenSockets()
|
|||
#if ENABLE_BONDING
|
||||
if (s->m_GroupOf)
|
||||
{
|
||||
LOGC(smlog.Note,
|
||||
HLOGC(smlog.Debug,
|
||||
log << "@" << s->m_SocketID << " IS MEMBER OF $" << s->m_GroupOf->id() << " - REMOVING FROM GROUP");
|
||||
s->removeFromGroup(true);
|
||||
}
|
||||
|
@ -2644,7 +2660,7 @@ void srt::CUDTUnited::checkBrokenSockets()
|
|||
|
||||
for (sockets_t::iterator j = m_ClosedSockets.begin(); j != m_ClosedSockets.end(); ++j)
|
||||
{
|
||||
// HLOGF(smlog.Debug, "checking CLOSED socket: %d\n", j->first);
|
||||
// HLOGC(smlog.Debug, log << "checking CLOSED socket: " << j->first);
|
||||
if (!is_zero(j->second->core().m_tsLingerExpiration))
|
||||
{
|
||||
// asynchronous close:
|
||||
|
@ -2671,7 +2687,7 @@ void srt::CUDTUnited::checkBrokenSockets()
|
|||
log << "checkBrokenSockets: @" << j->second->m_SocketID << " closed "
|
||||
<< FormatDuration(closed_ago) << " ago and removed from RcvQ - will remove");
|
||||
|
||||
// HLOGF(smlog.Debug, "will unref socket: %d\n", j->first);
|
||||
// HLOGC(smlog.Debug, log << "will unref socket: " << j->first);
|
||||
tbr.push_back(j->first);
|
||||
}
|
||||
}
|
||||
|
@ -2826,12 +2842,41 @@ uint16_t srt::CUDTUnited::installMuxer(CUDTSocket* w_s, CMultiplexer& fw_sm)
|
|||
return sa.hport();
|
||||
}
|
||||
|
||||
bool srt::CUDTUnited::channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket)
|
||||
bool srt::CUDTUnited::inet6SettingsCompat(const sockaddr_any& muxaddr, const CSrtMuxerConfig& cfgMuxer,
|
||||
const sockaddr_any& reqaddr, const CSrtMuxerConfig& cfgSocket)
|
||||
{
|
||||
return cfgMuxer.bReuseAddr && cfgMuxer == cfgSocket;
|
||||
if (muxaddr.family() != AF_INET6)
|
||||
return true; // Don't check - the family has been checked already
|
||||
|
||||
if (reqaddr.isany())
|
||||
{
|
||||
if (cfgSocket.iIpV6Only == -1) // Treat as "adaptive"
|
||||
return true;
|
||||
|
||||
// If set explicitly, then it must be equal to the one of found muxer.
|
||||
return cfgSocket.iIpV6Only == cfgMuxer.iIpV6Only;
|
||||
}
|
||||
|
||||
// If binding to the certain IPv6 address, then this setting doesn't matter.
|
||||
return true;
|
||||
}
|
||||
|
||||
void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const UDPSOCKET* udpsock /*[[nullable]]*/)
|
||||
bool srt::CUDTUnited::channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket)
|
||||
{
|
||||
if (!cfgMuxer.bReuseAddr)
|
||||
{
|
||||
HLOGP(smlog.Debug, "channelSettingsMatch: fail: the multiplexer is not reusable");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfgMuxer.isCompatWith(cfgSocket))
|
||||
return true;
|
||||
|
||||
HLOGP(smlog.Debug, "channelSettingsMatch: fail: some options have different values");
|
||||
return false;
|
||||
}
|
||||
|
||||
void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& reqaddr, const UDPSOCKET* udpsock /*[[nullable]]*/)
|
||||
{
|
||||
ScopedLock cg(m_GlobControlLock);
|
||||
|
||||
|
@ -2844,9 +2889,23 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U
|
|||
{
|
||||
// If not, we need to see if there exist already a multiplexer bound
|
||||
// to the same endpoint.
|
||||
const int port = addr.hport();
|
||||
const int port = reqaddr.hport();
|
||||
const CSrtConfig& cfgSocket = s->core().m_config;
|
||||
|
||||
// This loop is going to check the attempted binding of
|
||||
// address:port and socket settings against every existing
|
||||
// multiplexer. Possible results of the check are:
|
||||
|
||||
// 1. MATCH: identical address - reuse it and quit.
|
||||
// 2. CONFLICT: report error: the binding partially overlaps
|
||||
// so it neither can be reused nor is free to bind.
|
||||
// 3. PASS: different and not overlapping - continue searching.
|
||||
|
||||
// In this function the convention is:
|
||||
// MATCH: do nothing and proceed with binding reusage, THEN break.
|
||||
// CONFLICT: throw an exception.
|
||||
// PASS: use 'continue' to pass to the next element.
|
||||
|
||||
bool reuse_attempt = false;
|
||||
for (map<int, CMultiplexer>::iterator i = m_mMultiplexer.begin(); i != m_mMultiplexer.end(); ++i)
|
||||
{
|
||||
|
@ -2862,74 +2921,166 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U
|
|||
}
|
||||
|
||||
// If this is bound to the wildcard address, it can be reused if:
|
||||
// - addr is also a wildcard
|
||||
// - reqaddr is also a wildcard
|
||||
// - channel settings match
|
||||
// Otherwise it's a conflict.
|
||||
sockaddr_any sa;
|
||||
m.m_pChannel->getSockAddr((sa));
|
||||
sockaddr_any mux_addr;
|
||||
m.m_pChannel->getSockAddr((mux_addr));
|
||||
|
||||
HLOGC(smlog.Debug,
|
||||
log << "bind: Found existing muxer @" << m.m_iID << " : " << sa.str() << " - check against "
|
||||
<< addr.str());
|
||||
log << "bind: Found existing muxer @" << m.m_iID << " : " << mux_addr.str() << " - check against "
|
||||
<< reqaddr.str());
|
||||
|
||||
if (sa.isany())
|
||||
if (mux_addr.isany())
|
||||
{
|
||||
if (!addr.isany())
|
||||
if (mux_addr.family() == AF_INET6)
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << addr.str()
|
||||
<< " conflicts with existing wildcard binding: " << sa.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
// With IPv6 we need to research two possibilities:
|
||||
// iIpV6Only == 1 -> This means that it binds only :: wildcard, but not 0.0.0.0
|
||||
// iIpV6Only == 0 -> This means that it binds both :: and 0.0.0.0.
|
||||
// iIpV6Only == -1 -> Hard to say what to do, but treat it as a potential conflict in any doubtful case.
|
||||
|
||||
if (m.m_mcfg.iIpV6Only == 1)
|
||||
{
|
||||
// PASS IF: candidate is IPv4, no matter the address
|
||||
// MATCH IF: candidate is IPv6 with only=1
|
||||
// CONFLICT IF: candidate is IPv6 with only != 1 or IPv6 non-wildcard.
|
||||
|
||||
if (reqaddr.family() == AF_INET)
|
||||
{
|
||||
HLOGC(smlog.Debug, log << "bind: muxer @" << m.m_iID
|
||||
<< " is :: v6only - requested IPv4 ANY is NOT IN THE WAY. Searching on.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Candidate is AF_INET6
|
||||
|
||||
if (cfgSocket.iIpV6Only != 1 || !reqaddr.isany())
|
||||
{
|
||||
// CONFLICT:
|
||||
// 1. attempting to make a wildcard IPv4 + IPv6
|
||||
// while the multiplexer for wildcard IPv6 exists.
|
||||
// 2. If binding to a given address, it conflicts with the wildcard
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << reqaddr.str()
|
||||
<< " conflicts with existing IPv6 wildcard binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
|
||||
// Otherwise, MATCH.
|
||||
}
|
||||
else if (m.m_mcfg.iIpV6Only == 0)
|
||||
{
|
||||
// Muxer's address is a wildcard for :: and 0.0.0.0 at once.
|
||||
// This way only IPv6 wildcard with v6only=0 is a perfect match and everything
|
||||
// else is a conflict.
|
||||
|
||||
if (reqaddr.family() == AF_INET6 && reqaddr.isany() && cfgSocket.iIpV6Only == 0)
|
||||
{
|
||||
// MATCH
|
||||
}
|
||||
else
|
||||
{
|
||||
// CONFLICT: attempting to make a wildcard IPv4 + IPv6 while
|
||||
// the multiplexer for wildcard IPv6 exists.
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << reqaddr.str() << " v6only=" << cfgSocket.iIpV6Only
|
||||
<< " conflicts with existing IPv6 + IPv4 wildcard binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
}
|
||||
else // Case -1, by unknown reason. Accept only with -1 setting, others are conflict.
|
||||
{
|
||||
if (reqaddr.family() == AF_INET6 && reqaddr.isany() && cfgSocket.iIpV6Only == -1)
|
||||
{
|
||||
// MATCH
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << reqaddr.str() << " v6only=" << cfgSocket.iIpV6Only
|
||||
<< " conflicts with existing IPv6 v6only=unknown wildcard binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // muxer is IPv4 wildcard
|
||||
{
|
||||
// Then only IPv4 wildcard is a match and:
|
||||
// - IPv6 with only=true is PASS (not a conflict)
|
||||
// - IPv6 with only=false is CONFLICT
|
||||
// - IPv6 with only=undefined is CONFLICT
|
||||
// REASON: we need to make a potential conflict a conflict as there will be
|
||||
// no bind() call to check if this wouldn't be a conflict in result. If you want
|
||||
// to have a binding to IPv6 that should avoid conflict with IPv4 wildcard binding,
|
||||
// then SRTO_IPV6ONLY option must be explicitly set before binding.
|
||||
// Also:
|
||||
if (reqaddr.family() == AF_INET)
|
||||
{
|
||||
if (reqaddr.isany())
|
||||
{
|
||||
// MATCH
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << reqaddr.str()
|
||||
<< " conflicts with existing IPv4 wildcard binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
}
|
||||
else // AF_INET6
|
||||
{
|
||||
if (cfgSocket.iIpV6Only == 1 || !reqaddr.isany())
|
||||
{
|
||||
// PASS
|
||||
HLOGC(smlog.Debug, log << "bind: muxer @" << m.m_iID
|
||||
<< " is IPv4 wildcard - requested " << reqaddr.str() << " v6only=" << cfgSocket.iIpV6Only
|
||||
<< " is NOT IN THE WAY. Searching on.");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << reqaddr.str() << " v6only=" << cfgSocket.iIpV6Only
|
||||
<< " conflicts with existing IPv4 wildcard binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still, for ANY you need either the same family, or open
|
||||
// for families.
|
||||
if (m.m_mcfg.iIpV6Only != -1 && m.m_mcfg.iIpV6Only != cfgSocket.iIpV6Only)
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << addr.str()
|
||||
<< " conflicts with existing IPv6 wildcard binding: " << sa.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
|
||||
if ((m.m_mcfg.iIpV6Only == 0 || cfgSocket.iIpV6Only == 0) && m.m_iIPversion != addr.family())
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << addr.str() << " conflicts with IPv6 wildcard binding: " << sa.str()
|
||||
<< " : family " << (m.m_iIPversion == AF_INET ? "IPv4" : "IPv6") << " vs. "
|
||||
<< (addr.family() == AF_INET ? "IPv4" : "IPv6"));
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
reuse_attempt = true;
|
||||
HLOGC(smlog.Debug, log << "bind: wildcard address - multiplexer reusable");
|
||||
}
|
||||
else if (addr.isany() && addr.family() == sa.family())
|
||||
// Muxer address is NOT a wildcard, so conflicts only with WILDCARD of the same type
|
||||
else if (reqaddr.isany() && reqaddr.family() == mux_addr.family())
|
||||
{
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Wildcard address: " << addr.str()
|
||||
<< " conflicts with existting IP binding: " << sa.str());
|
||||
log << "bind: Wildcard address: " << reqaddr.str()
|
||||
<< " conflicts with existting IP binding: " << mux_addr.str());
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
// If this is bound to a certain address, AND:
|
||||
else if (sa.equal_address(addr))
|
||||
else if (mux_addr.equal_address(reqaddr))
|
||||
{
|
||||
// - the address is the same as addr
|
||||
// - the address is the same as reqaddr
|
||||
reuse_attempt = true;
|
||||
HLOGC(smlog.Debug, log << "bind: same IP address - multiplexer reusable");
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(smlog.Debug, log << "bind: IP addresses differ - ALLOWED to create a new multiplexer");
|
||||
continue;
|
||||
}
|
||||
// Otherwise:
|
||||
// - the address is different than addr
|
||||
// - the address is different than reqaddr
|
||||
// - the address can't be reused, but this can go on with new one.
|
||||
|
||||
// If this is a reusage attempt:
|
||||
if (reuse_attempt)
|
||||
{
|
||||
// - if the channel settings match, it can be reused
|
||||
if (channelSettingsMatch(m.m_mcfg, cfgSocket))
|
||||
if (channelSettingsMatch(m.m_mcfg, cfgSocket) && inet6SettingsCompat(mux_addr, m.m_mcfg, reqaddr, cfgSocket))
|
||||
{
|
||||
HLOGC(smlog.Debug, log << "bind: reusing multiplexer for port " << port);
|
||||
// reuse the existing multiplexer
|
||||
|
@ -2941,7 +3092,7 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U
|
|||
{
|
||||
// - if not, it's a conflict
|
||||
LOGC(smlog.Error,
|
||||
log << "bind: Address: " << addr.str() << " conflicts with binding: " << sa.str()
|
||||
log << "bind: Address: " << reqaddr.str() << " conflicts with binding: " << mux_addr.str()
|
||||
<< " due to channel settings");
|
||||
throw CUDTException(MJ_NOTSUP, MN_BUSYPORT, 0);
|
||||
}
|
||||
|
@ -2950,13 +3101,15 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U
|
|||
// candidates, proceed with creating a new multiplexer.
|
||||
|
||||
// Note that a binding to a different IP address is not treated
|
||||
// as a candidate for either reuseage or conflict.
|
||||
// as a candidate for either reusage or conflict.
|
||||
LOGC(smlog.Fatal, log << "SHOULD NOT GET HERE!!!");
|
||||
SRT_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
// a new multiplexer is needed
|
||||
CMultiplexer m;
|
||||
configureMuxer((m), s, addr.family());
|
||||
configureMuxer((m), s, reqaddr.family());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -2965,25 +3118,39 @@ void srt::CUDTUnited::updateMux(CUDTSocket* s, const sockaddr_any& addr, const U
|
|||
|
||||
if (udpsock)
|
||||
{
|
||||
// In this case, addr contains the address
|
||||
// In this case, reqaddr contains the address
|
||||
// that has been extracted already from the
|
||||
// given socket
|
||||
m.m_pChannel->attach(*udpsock, addr);
|
||||
m.m_pChannel->attach(*udpsock, reqaddr);
|
||||
}
|
||||
else if (addr.empty())
|
||||
else if (reqaddr.empty())
|
||||
{
|
||||
// The case of previously used case of a NULL address.
|
||||
// This here is used to pass family only, in this case
|
||||
// just automatically bind to the "0" address to autoselect
|
||||
// everything.
|
||||
m.m_pChannel->open(addr.family());
|
||||
m.m_pChannel->open(reqaddr.family());
|
||||
}
|
||||
else
|
||||
{
|
||||
// If at least the IP address is specified, then bind to that
|
||||
// address, but still possibly autoselect the outgoing port, if the
|
||||
// port was specified as 0.
|
||||
m.m_pChannel->open(addr);
|
||||
m.m_pChannel->open(reqaddr);
|
||||
}
|
||||
|
||||
// AFTER OPENING, check the matter of IPV6_V6ONLY option,
|
||||
// as it decides about the fact that the occupied binding address
|
||||
// in case of wildcard is both :: and 0.0.0.0, or only ::.
|
||||
if (reqaddr.family() == AF_INET6 && m.m_mcfg.iIpV6Only == -1)
|
||||
{
|
||||
// XXX We don't know how probable it is to get the error here
|
||||
// and resulting -1 value. As a fallback for that case, the value -1
|
||||
// is honored here, just all side-bindings for other sockes will be
|
||||
// rejected as a potential conflict, even if binding would be accepted
|
||||
// in these circumstances. Only a perfect match in case of potential
|
||||
// overlapping will be accepted on the same port.
|
||||
m.m_mcfg.iIpV6Only = m.m_pChannel->sockopt(IPPROTO_IPV6, IPV6_V6ONLY, -1);
|
||||
}
|
||||
|
||||
m.m_pTimer = new CTimer;
|
||||
|
@ -3032,8 +3199,14 @@ bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls)
|
|||
CMultiplexer* mux = map_getp(m_mMultiplexer, ls->m_iMuxID);
|
||||
|
||||
// NOTE:
|
||||
// THIS BELOW CODE is only for a highly unlikely, and probably buggy,
|
||||
// situation when the Multiplexer wasn't found by ID recorded in the listener.
|
||||
// THIS BELOW CODE is only for a highly unlikely situation when the listener
|
||||
// socket has been closed in the meantime when the accepted socket is being
|
||||
// processed. This procedure is different than updateMux because this time we
|
||||
// only want to have a multiplexer socket to be assigned to the accepted socket.
|
||||
// It is also unlikely that the listener socket is garbage-collected so fast, so
|
||||
// this procedure will most likely find the multiplexer of the zombie listener socket,
|
||||
// which no longer accepts new connections (the listener is withdrawn immediately from
|
||||
// the port) that wasn't yet completely deleted.
|
||||
CMultiplexer* fallback = NULL;
|
||||
if (!mux)
|
||||
{
|
||||
|
@ -3060,8 +3233,9 @@ bool srt::CUDTUnited::updateListenerMux(CUDTSocket* s, const CUDTSocket* ls)
|
|||
mux = &m; // best match
|
||||
break;
|
||||
}
|
||||
else
|
||||
else if (m.m_iIPversion == AF_INET6)
|
||||
{
|
||||
// Allowed fallback case when we only need an accepted socket.
|
||||
fallback = &m;
|
||||
}
|
||||
}
|
||||
|
@ -4369,7 +4543,7 @@ int epoll_wait2(int eid,
|
|||
int* lwnum)
|
||||
{
|
||||
// This API is an alternative format for epoll_wait, created for
|
||||
// compatability with other languages. Users need to pass in an array
|
||||
// compatibility with other languages. Users need to pass in an array
|
||||
// for holding the returned sockets, with the maximum array length
|
||||
// stored in *rnum, etc., which will be updated with returned number
|
||||
// of sockets.
|
||||
|
|
11
trunk/3rdparty/srt-1-fit/srtcore/api.h
vendored
11
trunk/3rdparty/srt-1-fit/srtcore/api.h
vendored
|
@ -193,6 +193,15 @@ public:
|
|||
/// to finish sending the data that were scheduled for sending so far.
|
||||
void setClosed();
|
||||
|
||||
// This is necessary to be called from the group before the group clears
|
||||
// the connection with the socket. As for managed groups (and there are
|
||||
// currently no other group types), a socket disconnected from the group
|
||||
// is no longer usable.
|
||||
void setClosing()
|
||||
{
|
||||
core().m_bClosing = true;
|
||||
}
|
||||
|
||||
/// This does the same as setClosed, plus sets the m_bBroken to true.
|
||||
/// Such a socket can still be read from so that remaining data from
|
||||
/// the receiver buffer can be read, but no longer sends anything.
|
||||
|
@ -447,6 +456,8 @@ private:
|
|||
/// @param cfgSocket socket configuration.
|
||||
/// @return tru if configurations match, false otherwise.
|
||||
static bool channelSettingsMatch(const CSrtMuxerConfig& cfgMuxer, const CSrtConfig& cfgSocket);
|
||||
static bool inet6SettingsCompat(const sockaddr_any& muxaddr, const CSrtMuxerConfig& cfgMuxer,
|
||||
const sockaddr_any& reqaddr, const CSrtMuxerConfig& cfgSocket);
|
||||
|
||||
private:
|
||||
std::map<int, CMultiplexer> m_mMultiplexer; // UDP multiplexer
|
||||
|
|
2298
trunk/3rdparty/srt-1-fit/srtcore/buffer.cpp
vendored
2298
trunk/3rdparty/srt-1-fit/srtcore/buffer.cpp
vendored
File diff suppressed because it is too large
Load diff
611
trunk/3rdparty/srt-1-fit/srtcore/buffer.h
vendored
611
trunk/3rdparty/srt-1-fit/srtcore/buffer.h
vendored
|
@ -1,611 +0,0 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 05/05/2009
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_BUFFER_H
|
||||
#define INC_SRT_BUFFER_H
|
||||
|
||||
#include "udt.h"
|
||||
#include "list.h"
|
||||
#include "queue.h"
|
||||
#include "tsbpd_time.h"
|
||||
#include "utilities.h"
|
||||
|
||||
// The notation used for "circular numbers" in comments:
|
||||
// The "cicrular numbers" are numbers that when increased up to the
|
||||
// maximum become zero, and similarly, when the zero value is decreased,
|
||||
// it turns into the maximum value minus one. This wrapping works the
|
||||
// same for adding and subtracting. Circular numbers cannot be multiplied.
|
||||
|
||||
// Operations done on these numbers are marked with additional % character:
|
||||
// a %> b : a is later than b
|
||||
// a ++% (++%a) : shift a by 1 forward
|
||||
// a +% b : shift a by b
|
||||
// a == b : equality is same as for just numbers
|
||||
|
||||
namespace srt {
|
||||
|
||||
/// The AvgBufSize class is used to calculate moving average of the buffer (RCV or SND)
|
||||
class AvgBufSize
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
|
||||
public:
|
||||
AvgBufSize()
|
||||
: m_dBytesCountMAvg(0.0)
|
||||
, m_dCountMAvg(0.0)
|
||||
, m_dTimespanMAvg(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool isTimeToUpdate(const time_point& now) const;
|
||||
void update(const time_point& now, int pkts, int bytes, int timespan_ms);
|
||||
|
||||
public:
|
||||
inline double pkts() const { return m_dCountMAvg; }
|
||||
inline double timespan_ms() const { return m_dTimespanMAvg; }
|
||||
inline double bytes() const { return m_dBytesCountMAvg; }
|
||||
|
||||
private:
|
||||
time_point m_tsLastSamplingTime;
|
||||
double m_dBytesCountMAvg;
|
||||
double m_dCountMAvg;
|
||||
double m_dTimespanMAvg;
|
||||
};
|
||||
|
||||
/// The class to estimate source bitrate based on samples submitted to the buffer.
|
||||
/// Is currently only used by the CSndBuffer.
|
||||
class CRateEstimator
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
public:
|
||||
CRateEstimator();
|
||||
|
||||
public:
|
||||
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_iInRateBps; }
|
||||
|
||||
void setInputRateSmpPeriod(int period);
|
||||
|
||||
/// Update input rate calculation.
|
||||
/// @param [in] time current time in microseconds
|
||||
/// @param [in] pkts number of packets newly added to the buffer
|
||||
/// @param [in] bytes number of payload bytes in those newly added packets
|
||||
///
|
||||
/// @return Current size of the data in the sending list.
|
||||
void updateInputRate(const time_point& time, int pkts = 0, int bytes = 0);
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US); }
|
||||
|
||||
private: // Constants
|
||||
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
|
||||
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
|
||||
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
|
||||
static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE;
|
||||
|
||||
private:
|
||||
int m_iInRatePktsCount; // number of payload bytes added since InRateStartTime
|
||||
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime
|
||||
time_point m_tsInRateStartTime;
|
||||
uint64_t m_InRatePeriod; // usec
|
||||
int m_iInRateBps; // Input Rate in Bytes/sec
|
||||
};
|
||||
|
||||
class CSndBuffer
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the buffer is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
/// @brief CSndBuffer constructor.
|
||||
/// @param size initial number of blocks (each block to store one packet payload).
|
||||
/// @param maxpld maximum packet payload.
|
||||
CSndBuffer(int size = 32, int maxpld = 1500);
|
||||
~CSndBuffer();
|
||||
|
||||
public:
|
||||
/// Insert a user buffer into the sending list.
|
||||
/// For @a w_mctrl the following fields are used:
|
||||
/// INPUT:
|
||||
/// - msgttl: timeout for retransmitting the message, if lost
|
||||
/// - inorder: request to deliver the message in order of sending
|
||||
/// - srctime: local time as a base for packet's timestamp (0 if unused)
|
||||
/// - pktseq: sequence number to be stamped on the packet (-1 if unused)
|
||||
/// - msgno: message number to be stamped on the packet (-1 if unused)
|
||||
/// OUTPUT:
|
||||
/// - srctime: local time stamped on the packet (same as input, if input wasn't 0)
|
||||
/// - pktseq: sequence number to be stamped on the next packet
|
||||
/// - msgno: message number stamped on the packet
|
||||
/// @param [in] data pointer to the user data block.
|
||||
/// @param [in] len size of the block.
|
||||
/// @param [inout] w_mctrl Message control data
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
void addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl);
|
||||
|
||||
/// Read a block of data from file and insert it into the sending list.
|
||||
/// @param [in] ifs input file stream.
|
||||
/// @param [in] len size of the block.
|
||||
/// @return actual size of data added from the file.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int addBufferFromFile(std::fstream& ifs, int len);
|
||||
|
||||
/// Find data position to pack a DATA packet from the furthest reading point.
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [in] kflags Odd|Even crypto key flag
|
||||
/// @param [out] seqnoinc the number of packets skipped due to TTL, so that seqno should be incremented.
|
||||
/// @return Actual length of data read.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(CPacket& w_packet, time_point& w_origintime, int kflgs, int& w_seqnoinc);
|
||||
|
||||
/// Peek an information on the next original data packet to send.
|
||||
/// @return origin time stamp of the next packet; epoch start time otherwise.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point peekNextOriginal() const;
|
||||
|
||||
/// Find data position to pack a DATA packet for a retransmission.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [out] msglen length of the message
|
||||
/// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded).
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen);
|
||||
|
||||
/// Get the time of the last retransmission (if any) of the DATA packet.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
///
|
||||
/// @return Last time of the last retransmission event for the corresponding DATA packet.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point getPacketRexmitTime(const int offset);
|
||||
|
||||
/// Update the ACK point and may release/unmap/return the user data according to the flag.
|
||||
/// @param [in] offset number of packets acknowledged.
|
||||
int32_t getMsgNoAt(const int offset);
|
||||
|
||||
void ackData(int offset);
|
||||
|
||||
/// Read size of data still in the sending list.
|
||||
/// @return Current size of the data in the sending list.
|
||||
int getCurrBufSize() const;
|
||||
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int dropLateData(int& bytes, int32_t& w_first_msgno, const time_point& too_late_time);
|
||||
|
||||
void updAvgBufSize(const time_point& time);
|
||||
int getAvgBufSize(int& bytes, int& timespan);
|
||||
int getCurrBufSize(int& bytes, int& timespan);
|
||||
|
||||
/// @brief Get the buffering delay of the oldest message in the buffer.
|
||||
/// @return the delay value.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
duration getBufferingDelay(const time_point& tnow) const;
|
||||
|
||||
uint64_t getInRatePeriod() const { return m_rateEstimator.getInRatePeriod(); }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_rateEstimator.getInputRate(); }
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { m_rateEstimator.resetInputRateSmpPeriod(disable); }
|
||||
|
||||
const CRateEstimator& getRateEstimator() const { return m_rateEstimator; }
|
||||
|
||||
void setRateEstimator(const CRateEstimator& other) { m_rateEstimator = other; }
|
||||
|
||||
private:
|
||||
void increase();
|
||||
|
||||
private:
|
||||
mutable sync::Mutex m_BufLock; // used to synchronize buffer operation
|
||||
|
||||
struct Block
|
||||
{
|
||||
char* m_pcData; // pointer to the data block
|
||||
int m_iLength; // payload length of the block.
|
||||
|
||||
int32_t m_iMsgNoBitset; // message number
|
||||
int32_t m_iSeqNo; // sequence number for scheduling
|
||||
time_point m_tsOriginTime; // block origin time (either provided from above or equals the time a message was submitted for sending.
|
||||
time_point m_tsRexmitTime; // packet retransmission time
|
||||
int m_iTTL; // time to live (milliseconds)
|
||||
|
||||
Block* m_pNext; // next block
|
||||
|
||||
int32_t getMsgSeq()
|
||||
{
|
||||
// NOTE: this extracts message ID with regard to REXMIT flag.
|
||||
// This is valid only for message ID that IS GENERATED in this instance,
|
||||
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
|
||||
// for the peer that it uses LESS bits to represent the message.
|
||||
return m_iMsgNoBitset & MSGNO_SEQ::mask;
|
||||
}
|
||||
|
||||
} * m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
|
||||
|
||||
// m_pBlock: The head pointer
|
||||
// m_pFirstBlock: The first block
|
||||
// m_pCurrBlock: The current block
|
||||
// m_pLastBlock: The last block (if first == last, buffer is empty)
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
char* m_pcData; // buffer
|
||||
int m_iSize; // size
|
||||
Buffer* m_pNext; // next buffer
|
||||
} * m_pBuffer; // physical buffer
|
||||
|
||||
int32_t m_iNextMsgNo; // next message number
|
||||
|
||||
int m_iSize; // buffer size (number of packets)
|
||||
const int m_iBlockLen; // maximum length of a block holding packet payload (excluding packet header).
|
||||
int m_iCount; // number of used blocks
|
||||
|
||||
int m_iBytesCount; // number of payload bytes in queue
|
||||
time_point m_tsLastOriginTime;
|
||||
|
||||
AvgBufSize m_mavg;
|
||||
CRateEstimator m_rateEstimator;
|
||||
|
||||
private:
|
||||
CSndBuffer(const CSndBuffer&);
|
||||
CSndBuffer& operator=(const CSndBuffer&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (!ENABLE_NEW_RCVBUFFER)
|
||||
|
||||
class CRcvBuffer
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the queue is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
static const int DEFAULT_SIZE = 65536;
|
||||
/// Construct the buffer.
|
||||
/// @param [in] queue CUnitQueue that actually holds the units (packets)
|
||||
/// @param [in] bufsize_pkts in units (packets)
|
||||
CRcvBuffer(CUnitQueue* queue, int bufsize_pkts = DEFAULT_SIZE);
|
||||
~CRcvBuffer();
|
||||
|
||||
public:
|
||||
/// Write data into the buffer.
|
||||
/// @param [in] unit pointer to a data unit containing new packet
|
||||
/// @param [in] offset offset from last ACK point.
|
||||
/// @return 0 is success, -1 if data is repeated.
|
||||
int addData(CUnit* unit, int offset);
|
||||
|
||||
/// Read data into a user buffer.
|
||||
/// @param [in] data pointer to user buffer.
|
||||
/// @param [in] len length of user buffer.
|
||||
/// @return size of data read.
|
||||
int readBuffer(char* data, int len);
|
||||
|
||||
/// Read data directly into file.
|
||||
/// @param [in] file C++ file stream.
|
||||
/// @param [in] len expected length of data to write into the file.
|
||||
/// @return size of data read.
|
||||
int readBufferToFile(std::fstream& ofs, int len);
|
||||
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len number of units to be acknowledged.
|
||||
/// @return 1 if a user buffer is fulfilled, otherwise 0.
|
||||
int ackData(int len);
|
||||
|
||||
/// Query how many buffer space left for data receiving.
|
||||
/// Actually only acknowledged packets, that are still in the buffer,
|
||||
/// are considered to take buffer space.
|
||||
///
|
||||
/// @return size of available buffer space (including user buffer) for data receiving.
|
||||
/// Not counting unacknowledged packets.
|
||||
int getAvailBufSize() const;
|
||||
|
||||
/// Query how many data has been continuously received (for reading) and ready to play (tsbpdtime < now).
|
||||
/// @return size of valid (continous) data for reading.
|
||||
int getRcvDataSize() const;
|
||||
|
||||
/// Query how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
int getRcvDataSize(int& bytes, int& spantime);
|
||||
|
||||
/// Query a 1 sec moving average of how many data was received and acknowledged.
|
||||
/// @param [out] bytes bytes
|
||||
/// @param [out] spantime spantime
|
||||
/// @return size in pkts of acked data.
|
||||
int getRcvAvgDataSize(int& bytes, int& spantime);
|
||||
|
||||
/// Query how many data of the receive buffer is acknowledged.
|
||||
/// @param [in] now current time in us.
|
||||
/// @return none.
|
||||
void updRcvAvgDataSize(const time_point& now);
|
||||
|
||||
/// Query the received average payload size.
|
||||
/// @return size (bytes) of payload size
|
||||
unsigned getRcvAvgPayloadSize() const;
|
||||
|
||||
struct ReadingState
|
||||
{
|
||||
time_point tsStart;
|
||||
time_point tsLastAck;
|
||||
time_point tsEnd;
|
||||
int iNumAcknowledged;
|
||||
int iNumUnacknowledged;
|
||||
};
|
||||
|
||||
ReadingState debugGetReadingState() const;
|
||||
|
||||
/// Form a string of the current buffer fullness state.
|
||||
/// number of packets acknowledged, TSBPD readiness, etc.
|
||||
std::string strFullnessState(const time_point& tsNow) const;
|
||||
|
||||
/// Mark the message to be dropped from the message list.
|
||||
/// @param [in] msgno message number.
|
||||
/// @param [in] using_rexmit_flag whether the MSGNO field uses rexmit flag (if not, one more bit is part of the
|
||||
/// msgno value)
|
||||
void dropMsg(int32_t msgno, bool using_rexmit_flag);
|
||||
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @return actuall size of data read.
|
||||
int readMsg(char* data, int len);
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
void readMsgHeavyLogging(int p);
|
||||
#endif
|
||||
|
||||
/// read a message.
|
||||
/// @param [out] data buffer to write the message into.
|
||||
/// @param [in] len size of the buffer.
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// @return actuall size of data read.
|
||||
int readMsg(char* data, int len, SRT_MSGCTRL& w_mctrl, int upto);
|
||||
|
||||
/// Query if data is ready to read (tsbpdtime <= now if TsbPD is active).
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay
|
||||
/// of next packet in recv buffer, ready or not.
|
||||
/// @param [out] curpktseq Sequence number of the packet if there is one ready to play
|
||||
/// @return true if ready to play, false otherwise (tsbpdtime may be !0 in
|
||||
/// both cases).
|
||||
bool isRcvDataReady(time_point& w_tsbpdtime, int32_t& w_curpktseq, int32_t seqdistance);
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_OUTJITTER
|
||||
void debugTraceJitter(time_point t);
|
||||
#else
|
||||
void debugTraceJitter(time_point) {}
|
||||
#endif /* SRT_DEBUG_TSBPD_OUTJITTER */
|
||||
|
||||
bool isRcvDataReady();
|
||||
bool isRcvDataAvailable() { return m_iLastAckPos != m_iStartPos; }
|
||||
CPacket* getRcvReadyPacket(int32_t seqdistance);
|
||||
|
||||
/// Set TimeStamp-Based Packet Delivery Rx Mode
|
||||
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
|
||||
/// @param [in] delay aggreed TsbPD delay
|
||||
void setRcvTsbPdMode(const time_point& timebase, const duration& delay);
|
||||
|
||||
/// Add packet timestamp for drift caclculation and compensation
|
||||
/// @param [in] timestamp packet time stamp
|
||||
/// @param [in] tsPktArrival arrival time of the packet used to extract the drift sample.
|
||||
/// @param [in] rtt RTT sample
|
||||
bool addRcvTsbPdDriftSample(uint32_t timestamp, const time_point& tsPktArrival, int rtt);
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_DRIFT
|
||||
void printDriftHistogram(int64_t iDrift);
|
||||
void printDriftOffset(int tsbPdOffset, int tsbPdDriftAvg);
|
||||
#endif
|
||||
|
||||
/// Get information on the 1st message in queue.
|
||||
// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] w_tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0
|
||||
/// if none
|
||||
/// @param [out] w_passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
|
||||
/// @param [out] w_skipseqno SRT_SEQNO_NONE or seq number of 1st unacknowledged pkt ready to play preceeded by
|
||||
/// missing packets.
|
||||
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base if exist packet ready-to-play
|
||||
/// and larger than base
|
||||
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
|
||||
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
|
||||
/// IF skipseqno != SRT_SEQNO_NONE, packet ready to play preceeded by missing packets.;
|
||||
/// IF skipseqno == SRT_SEQNO_NONE, no missing packet but 1st not ready to play.
|
||||
bool getRcvFirstMsg(time_point& w_tsbpdtime,
|
||||
bool& w_passack,
|
||||
int32_t& w_skipseqno,
|
||||
int32_t& w_curpktseq,
|
||||
int32_t base_seq = SRT_SEQNO_NONE);
|
||||
|
||||
/// Update the ACK point of the buffer.
|
||||
/// @param [in] len size of data to be skip & acknowledged.
|
||||
void skipData(int len);
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
void reportBufferStats() const; // Heavy logging Debug only
|
||||
#endif
|
||||
bool empty() const
|
||||
{
|
||||
// This will not always return the intended value,
|
||||
// that is, it may return false when the buffer really is
|
||||
// empty - but it will return true then in one of next calls.
|
||||
// This function will be always called again at some point
|
||||
// if it returned false, and on true the connection
|
||||
// is going to be broken - so this behavior is acceptable.
|
||||
return m_iStartPos == m_iLastAckPos;
|
||||
}
|
||||
bool full() const { return m_iStartPos == (m_iLastAckPos + 1) % m_iSize; }
|
||||
int capacity() const { return m_iSize; }
|
||||
|
||||
private:
|
||||
/// This gives up unit at index p. The unit is given back to the
|
||||
/// free unit storage for further assignment for the new incoming
|
||||
/// data.
|
||||
size_t freeUnitAt(size_t p)
|
||||
{
|
||||
CUnit* u = m_pUnit[p];
|
||||
m_pUnit[p] = NULL;
|
||||
size_t rmbytes = u->m_Packet.getLength();
|
||||
m_pUnitQueue->makeUnitFree(u);
|
||||
return rmbytes;
|
||||
}
|
||||
|
||||
/// Adjust receive queue to 1st ready to play message (tsbpdtime < now).
|
||||
/// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if
|
||||
/// none
|
||||
/// @param base_seq SRT_SEQNO_NONE or desired, ignore seq smaller than base
|
||||
/// @retval true 1st packet ready to play without discontinuity (no hole)
|
||||
/// @retval false tsbpdtime = 0: no packet ready to play
|
||||
bool getRcvReadyMsg(time_point& w_tsbpdtime, int32_t& w_curpktseq, int upto, int base_seq = SRT_SEQNO_NONE);
|
||||
|
||||
public:
|
||||
/// @brief Get clock drift in microseconds.
|
||||
int64_t getDrift() const { return m_tsbpd.drift(); }
|
||||
|
||||
public:
|
||||
int32_t getTopMsgno() const;
|
||||
|
||||
void getInternalTimeBase(time_point& w_tb, bool& w_wrp, duration& w_udrift);
|
||||
|
||||
void applyGroupTime(const time_point& timebase, bool wrapcheck, uint32_t delay, const duration& udrift);
|
||||
void applyGroupDrift(const time_point& timebase, bool wrapcheck, const duration& udrift);
|
||||
time_point getPktTsbPdTime(uint32_t timestamp);
|
||||
int debugGetSize() const;
|
||||
time_point debugGetDeliveryTime(int offset);
|
||||
|
||||
size_t dropData(int len);
|
||||
|
||||
private:
|
||||
int extractData(char* data, int len, int p, int q, bool passack);
|
||||
bool accessMsg(int& w_p, int& w_q, bool& w_passack, int64_t& w_playtime, int upto);
|
||||
|
||||
/// Describes the state of the first N packets
|
||||
std::string debugTimeState(size_t first_n_pkts) const;
|
||||
|
||||
/// thread safe bytes counter of the Recv & Ack buffer
|
||||
/// @param [in] pkts acked or removed pkts from rcv buffer (used with acked = true)
|
||||
/// @param [in] bytes number of bytes added/delete (if negative) to/from rcv buffer.
|
||||
/// @param [in] acked true when adding new pkt in RcvBuffer; false when acking/removing pkts to/from buffer
|
||||
void countBytes(int pkts, int bytes, bool acked = false);
|
||||
|
||||
private:
|
||||
bool scanMsg(int& w_start, int& w_end, bool& w_passack);
|
||||
|
||||
int shift(int basepos, int shift) const { return (basepos + shift) % m_iSize; }
|
||||
|
||||
/// Simplified versions with ++ and --; avoid using division instruction
|
||||
int shiftFwd(int basepos) const
|
||||
{
|
||||
if (++basepos == m_iSize)
|
||||
return 0;
|
||||
return basepos;
|
||||
}
|
||||
|
||||
int shiftBack(int basepos) const
|
||||
{
|
||||
if (basepos == 0)
|
||||
return m_iSize - 1;
|
||||
return --basepos;
|
||||
}
|
||||
|
||||
private:
|
||||
CUnit** m_pUnit; // Array of pointed units collected in the buffer
|
||||
const int m_iSize; // Size of the internal array of CUnit* items
|
||||
CUnitQueue* m_pUnitQueue; // the shared unit queue
|
||||
|
||||
int m_iStartPos; // HEAD: first packet available for reading
|
||||
int m_iLastAckPos; // the last ACKed position (exclusive), follows the last readable
|
||||
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
|
||||
int m_iMaxPos; // delta between acked-TAIL and reception-TAIL
|
||||
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
// (this is required for stream reading mode; it's
|
||||
// the position in the first unit in the list
|
||||
// up to which data are already retrieved;
|
||||
// in message reading mode it's unused and always 0)
|
||||
|
||||
sync::Mutex m_BytesCountLock; // used to protect counters operations
|
||||
int m_iBytesCount; // Number of payload bytes in the buffer
|
||||
int m_iAckedPktsCount; // Number of acknowledged pkts in the buffer
|
||||
int m_iAckedBytesCount; // Number of acknowledged payload bytes in the buffer
|
||||
unsigned m_uAvgPayloadSz; // Average payload size for dropped bytes estimation
|
||||
|
||||
CTsbpdTime m_tsbpd;
|
||||
|
||||
AvgBufSize m_mavg;
|
||||
|
||||
private:
|
||||
CRcvBuffer();
|
||||
CRcvBuffer(const CRcvBuffer&);
|
||||
CRcvBuffer& operator=(const CRcvBuffer&);
|
||||
};
|
||||
|
||||
#endif // !ENABLE_NEW_RCVBUFFER
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
431
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.cpp
vendored
431
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.cpp
vendored
|
@ -1,4 +1,48 @@
|
|||
#if ENABLE_NEW_RCVBUFFER
|
||||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "buffer_rcv.h"
|
||||
|
@ -31,15 +75,15 @@ namespace {
|
|||
|
||||
#define IF_RCVBUF_DEBUG(instr) (void)0
|
||||
|
||||
// Check if iFirstNonreadPos is in range [iStartPos, (iStartPos + iMaxPosInc) % iSize].
|
||||
// Check if iFirstNonreadPos is in range [iStartPos, (iStartPos + iMaxPosOff) % iSize].
|
||||
// The right edge is included because we expect iFirstNonreadPos to be
|
||||
// right after the last valid packet position if all packets are available.
|
||||
bool isInRange(int iStartPos, int iMaxPosInc, size_t iSize, int iFirstNonreadPos)
|
||||
bool isInRange(int iStartPos, int iMaxPosOff, size_t iSize, int iFirstNonreadPos)
|
||||
{
|
||||
if (iFirstNonreadPos == iStartPos)
|
||||
return true;
|
||||
|
||||
const int iLastPos = (iStartPos + iMaxPosInc) % iSize;
|
||||
const int iLastPos = (iStartPos + iMaxPosOff) % iSize;
|
||||
const bool isOverrun = iLastPos < iStartPos;
|
||||
|
||||
if (isOverrun)
|
||||
|
@ -54,7 +98,7 @@ namespace {
|
|||
* RcvBufferNew (circular buffer):
|
||||
*
|
||||
* |<------------------- m_iSize ----------------------------->|
|
||||
* | |<----------- m_iMaxPosInc ------------>| |
|
||||
* | |<----------- m_iMaxPosOff ------------>| |
|
||||
* | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+ +---+
|
||||
* | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |...| 0 | m_pUnit[]
|
||||
|
@ -68,17 +112,17 @@ namespace {
|
|||
* thread safety:
|
||||
* m_iStartPos: CUDT::m_RecvLock
|
||||
* m_iLastAckPos: CUDT::m_AckLock
|
||||
* m_iMaxPosInc: none? (modified on add and ack
|
||||
* m_iMaxPosOff: none? (modified on add and ack
|
||||
*/
|
||||
|
||||
CRcvBufferNew::CRcvBufferNew(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool bMessageAPI)
|
||||
CRcvBuffer::CRcvBuffer(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool bMessageAPI)
|
||||
: m_entries(size)
|
||||
, m_szSize(size) // TODO: maybe just use m_entries.size()
|
||||
, m_pUnitQueue(unitqueue)
|
||||
, m_iStartSeqNo(initSeqNo)
|
||||
, m_iStartPos(0)
|
||||
, m_iFirstNonreadPos(0)
|
||||
, m_iMaxPosInc(0)
|
||||
, m_iMaxPosOff(0)
|
||||
, m_iNotch(0)
|
||||
, m_numOutOfOrderPackets(0)
|
||||
, m_iFirstReadableOutOfOrder(-1)
|
||||
|
@ -91,9 +135,9 @@ CRcvBufferNew::CRcvBufferNew(int initSeqNo, size_t size, CUnitQueue* unitqueue,
|
|||
SRT_ASSERT(size < size_t(std::numeric_limits<int>::max())); // All position pointers are integers
|
||||
}
|
||||
|
||||
CRcvBufferNew::~CRcvBufferNew()
|
||||
CRcvBuffer::~CRcvBuffer()
|
||||
{
|
||||
// Can be optimized by only iterating m_iMaxPosInc from m_iStartPos.
|
||||
// Can be optimized by only iterating m_iMaxPosOff from m_iStartPos.
|
||||
for (FixedArray<Entry>::iterator it = m_entries.begin(); it != m_entries.end(); ++it)
|
||||
{
|
||||
if (!it->pUnit)
|
||||
|
@ -104,14 +148,14 @@ CRcvBufferNew::~CRcvBufferNew()
|
|||
}
|
||||
}
|
||||
|
||||
int CRcvBufferNew::insert(CUnit* unit)
|
||||
int CRcvBuffer::insert(CUnit* unit)
|
||||
{
|
||||
SRT_ASSERT(unit != NULL);
|
||||
const int32_t seqno = unit->m_Packet.getSeqNo();
|
||||
const int offset = CSeqNo::seqoff(m_iStartSeqNo, seqno);
|
||||
|
||||
IF_RCVBUF_DEBUG(ScopedLog scoped_log);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBufferNew::insert: seqno " << seqno);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBuffer::insert: seqno " << seqno);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << " msgno " << unit->m_Packet.getMsgSeq(m_bPeerRexmitFlag));
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << " m_iStartSeqNo " << m_iStartSeqNo << " offset " << offset);
|
||||
|
||||
|
@ -132,8 +176,8 @@ int CRcvBufferNew::insert(CUnit* unit)
|
|||
SRT_ASSERT((m_iStartPos + offset) / m_szSize < 2);
|
||||
|
||||
const int pos = (m_iStartPos + offset) % m_szSize;
|
||||
if (offset >= m_iMaxPosInc)
|
||||
m_iMaxPosInc = offset + 1;
|
||||
if (offset >= m_iMaxPosOff)
|
||||
m_iMaxPosOff = offset + 1;
|
||||
|
||||
// Packet already exists
|
||||
SRT_ASSERT(pos >= 0 && pos < int(m_szSize));
|
||||
|
@ -144,7 +188,7 @@ int CRcvBufferNew::insert(CUnit* unit)
|
|||
}
|
||||
SRT_ASSERT(m_entries[pos].pUnit == NULL);
|
||||
|
||||
m_pUnitQueue->makeUnitGood(unit);
|
||||
m_pUnitQueue->makeUnitTaken(unit);
|
||||
m_entries[pos].pUnit = unit;
|
||||
m_entries[pos].status = EntryState_Avail;
|
||||
countBytes(1, (int)unit->m_Packet.getLength());
|
||||
|
@ -162,10 +206,10 @@ int CRcvBufferNew::insert(CUnit* unit)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::dropUpTo(int32_t seqno)
|
||||
int CRcvBuffer::dropUpTo(int32_t seqno)
|
||||
{
|
||||
IF_RCVBUF_DEBUG(ScopedLog scoped_log);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBufferNew::dropUpTo: seqno " << seqno << " m_iStartSeqNo " << m_iStartSeqNo);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBuffer::dropUpTo: seqno " << seqno << " m_iStartSeqNo " << m_iStartSeqNo);
|
||||
|
||||
int len = CSeqNo::seqoff(m_iStartSeqNo, seqno);
|
||||
if (len <= 0)
|
||||
|
@ -174,9 +218,9 @@ int CRcvBufferNew::dropUpTo(int32_t seqno)
|
|||
return 0;
|
||||
}
|
||||
|
||||
m_iMaxPosInc -= len;
|
||||
if (m_iMaxPosInc < 0)
|
||||
m_iMaxPosInc = 0;
|
||||
m_iMaxPosOff -= len;
|
||||
if (m_iMaxPosOff < 0)
|
||||
m_iMaxPosOff = 0;
|
||||
|
||||
const int iDropCnt = len;
|
||||
while (len > 0)
|
||||
|
@ -192,91 +236,87 @@ int CRcvBufferNew::dropUpTo(int32_t seqno)
|
|||
m_iStartSeqNo = seqno;
|
||||
// Move forward if there are "read/drop" entries.
|
||||
releaseNextFillerEntries();
|
||||
// Set nonread position to the starting position before updating,
|
||||
// because start position was increased, and preceeding packets are invalid.
|
||||
m_iFirstNonreadPos = m_iStartPos;
|
||||
updateNonreadPos();
|
||||
|
||||
// If the nonread position is now behind the starting position, set it to the starting position and update.
|
||||
// Preceding packets were likely missing, and the non read position can probably be moved further now.
|
||||
if (CSeqNo::seqcmp(m_iFirstNonreadPos, m_iStartPos) < 0)
|
||||
{
|
||||
m_iFirstNonreadPos = m_iStartPos;
|
||||
updateNonreadPos();
|
||||
}
|
||||
if (!m_tsbpd.isEnabled() && m_bMessageAPI)
|
||||
updateFirstReadableOutOfOrder();
|
||||
return iDropCnt;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::dropAll()
|
||||
int CRcvBuffer::dropAll()
|
||||
{
|
||||
if (empty())
|
||||
return 0;
|
||||
|
||||
const int end_seqno = CSeqNo::incseq(m_iStartSeqNo, m_iMaxPosInc);
|
||||
const int end_seqno = CSeqNo::incseq(m_iStartSeqNo, m_iMaxPosOff);
|
||||
return dropUpTo(end_seqno);
|
||||
}
|
||||
|
||||
int CRcvBufferNew::dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno)
|
||||
int CRcvBuffer::dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno, DropActionIfExists actionOnExisting)
|
||||
{
|
||||
IF_RCVBUF_DEBUG(ScopedLog scoped_log);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBufferNew::dropMessage: seqnolo " << seqnolo << " seqnohi " << seqnohi << " m_iStartSeqNo " << m_iStartSeqNo);
|
||||
// TODO: count bytes as removed?
|
||||
const int end_pos = incPos(m_iStartPos, m_iMaxPosInc);
|
||||
if (msgno != 0)
|
||||
{
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << " msgno " << msgno);
|
||||
int minDroppedOffset = -1;
|
||||
int iDropCnt = 0;
|
||||
for (int i = m_iStartPos; i != end_pos; i = incPos(i))
|
||||
{
|
||||
// TODO: Maybe check status?
|
||||
if (!m_entries[i].pUnit)
|
||||
continue;
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBuffer::dropMessage(): %(" << seqnolo << " - " << seqnohi << ")"
|
||||
<< " #" << msgno << " actionOnExisting=" << actionOnExisting << " m_iStartSeqNo=%"
|
||||
<< m_iStartSeqNo);
|
||||
|
||||
// TODO: Break the loop if a massege has been found. No need to search further.
|
||||
const int32_t msgseq = m_entries[i].pUnit->m_Packet.getMsgSeq(m_bPeerRexmitFlag);
|
||||
if (msgseq == msgno)
|
||||
{
|
||||
++iDropCnt;
|
||||
dropUnitInPos(i);
|
||||
m_entries[i].status = EntryState_Drop;
|
||||
if (minDroppedOffset == -1)
|
||||
minDroppedOffset = offPos(m_iStartPos, i);
|
||||
}
|
||||
}
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << " iDropCnt " << iDropCnt);
|
||||
// Check if units before m_iFirstNonreadPos are dropped.
|
||||
bool needUpdateNonreadPos = (minDroppedOffset != -1 && minDroppedOffset <= getRcvDataSize());
|
||||
releaseNextFillerEntries();
|
||||
if (needUpdateNonreadPos)
|
||||
{
|
||||
m_iFirstNonreadPos = m_iStartPos;
|
||||
updateNonreadPos();
|
||||
}
|
||||
if (!m_tsbpd.isEnabled() && m_bMessageAPI)
|
||||
{
|
||||
if (!checkFirstReadableOutOfOrder())
|
||||
m_iFirstReadableOutOfOrder = -1;
|
||||
updateFirstReadableOutOfOrder();
|
||||
}
|
||||
return iDropCnt;
|
||||
}
|
||||
|
||||
// Drop by packet seqno range.
|
||||
// Drop by packet seqno range to also wipe those packets that do not exist in the buffer.
|
||||
const int offset_a = CSeqNo::seqoff(m_iStartSeqNo, seqnolo);
|
||||
const int offset_b = CSeqNo::seqoff(m_iStartSeqNo, seqnohi);
|
||||
if (offset_b < 0)
|
||||
{
|
||||
LOGC(rbuflog.Debug, log << "CRcvBufferNew.dropMessage(): nothing to drop. Requested [" << seqnolo << "; "
|
||||
<< seqnohi << "]. Buffer start " << m_iStartSeqNo << ".");
|
||||
LOGC(rbuflog.Debug, log << "CRcvBuffer.dropMessage(): nothing to drop. Requested [" << seqnolo << "; "
|
||||
<< seqnohi << "]. Buffer start " << m_iStartSeqNo << ".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int start_off = max(0, offset_a);
|
||||
const int last_pos = incPos(m_iStartPos, offset_b);
|
||||
const bool bKeepExisting = (actionOnExisting == KEEP_EXISTING);
|
||||
int minDroppedOffset = -1;
|
||||
int iDropCnt = 0;
|
||||
for (int i = incPos(m_iStartPos, start_off); i != end_pos && i != last_pos; i = incPos(i))
|
||||
const int start_off = max(0, offset_a);
|
||||
const int start_pos = incPos(m_iStartPos, start_off);
|
||||
const int end_off = min((int) m_szSize - 1, offset_b + 1);
|
||||
const int end_pos = incPos(m_iStartPos, end_off);
|
||||
bool bDropByMsgNo = msgno > SRT_MSGNO_CONTROL; // Excluding both SRT_MSGNO_NONE (-1) and SRT_MSGNO_CONTROL (0).
|
||||
for (int i = start_pos; i != end_pos; i = incPos(i))
|
||||
{
|
||||
// Don't drop messages, if all its packets are already in the buffer.
|
||||
// TODO: Don't drop a several-packet message if all packets are in the buffer.
|
||||
if (m_entries[i].pUnit && m_entries[i].pUnit->m_Packet.getMsgBoundary() == PB_SOLO)
|
||||
// Check if the unit was already dropped earlier.
|
||||
if (m_entries[i].status == EntryState_Drop)
|
||||
continue;
|
||||
|
||||
if (m_entries[i].pUnit)
|
||||
{
|
||||
const PacketBoundary bnd = packetAt(i).getMsgBoundary();
|
||||
|
||||
// Don't drop messages, if all its packets are already in the buffer.
|
||||
// TODO: Don't drop a several-packet message if all packets are in the buffer.
|
||||
if (bKeepExisting && bnd == PB_SOLO)
|
||||
{
|
||||
bDropByMsgNo = false; // Solo packet, don't search for the rest of the message.
|
||||
LOGC(rbuflog.Debug,
|
||||
log << "CRcvBuffer::dropMessage(): Skipped dropping an existing SOLO packet %"
|
||||
<< packetAt(i).getSeqNo() << ".");
|
||||
continue;
|
||||
}
|
||||
|
||||
const int32_t msgseq = packetAt(i).getMsgSeq(m_bPeerRexmitFlag);
|
||||
if (msgno > SRT_MSGNO_CONTROL && msgseq != msgno)
|
||||
{
|
||||
LOGC(rbuflog.Warn, log << "CRcvBuffer.dropMessage(): Packet seqno %" << packetAt(i).getSeqNo() << " has msgno " << msgseq << " differs from requested " << msgno);
|
||||
}
|
||||
|
||||
if (bDropByMsgNo && bnd == PB_FIRST)
|
||||
{
|
||||
// First packet of the message is about to be dropped. That was the only reason to search for msgno.
|
||||
bDropByMsgNo = false;
|
||||
}
|
||||
}
|
||||
|
||||
dropUnitInPos(i);
|
||||
++iDropCnt;
|
||||
m_entries[i].status = EntryState_Drop;
|
||||
|
@ -284,11 +324,48 @@ int CRcvBufferNew::dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno)
|
|||
minDroppedOffset = offPos(m_iStartPos, i);
|
||||
}
|
||||
|
||||
LOGC(rbuflog.Debug, log << "CRcvBufferNew.dropMessage(): [" << seqnolo << "; "
|
||||
<< seqnohi << "].");
|
||||
if (bDropByMsgNo)
|
||||
{
|
||||
// If msgno is specified, potentially not the whole message was dropped using seqno range.
|
||||
// The sender might have removed the first packets of the message, and thus @a seqnolo may point to a packet in the middle.
|
||||
// The sender should have the last packet of the message it is requesting to be dropped.
|
||||
// Therefore we don't search forward, but need to check earlier packets in the RCV buffer.
|
||||
// Try to drop by the message number in case the message starts earlier than @a seqnolo.
|
||||
const int stop_pos = decPos(m_iStartPos);
|
||||
for (int i = start_pos; i != stop_pos; i = decPos(i))
|
||||
{
|
||||
// Can't drop if message number is not known.
|
||||
if (!m_entries[i].pUnit) // also dropped earlier.
|
||||
continue;
|
||||
|
||||
const PacketBoundary bnd = packetAt(i).getMsgBoundary();
|
||||
const int32_t msgseq = packetAt(i).getMsgSeq(m_bPeerRexmitFlag);
|
||||
if (msgseq != msgno)
|
||||
break;
|
||||
|
||||
if (bKeepExisting && bnd == PB_SOLO)
|
||||
{
|
||||
LOGC(rbuflog.Debug,
|
||||
log << "CRcvBuffer::dropMessage(): Skipped dropping an existing SOLO message packet %"
|
||||
<< packetAt(i).getSeqNo() << ".");
|
||||
break;
|
||||
}
|
||||
|
||||
++iDropCnt;
|
||||
dropUnitInPos(i);
|
||||
m_entries[i].status = EntryState_Drop;
|
||||
// As the search goes backward, i is always earlier than minDroppedOffset.
|
||||
minDroppedOffset = offPos(m_iStartPos, i);
|
||||
|
||||
// Break the loop if the start of the message has been found. No need to search further.
|
||||
if (bnd == PB_FIRST)
|
||||
break;
|
||||
}
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << " iDropCnt " << iDropCnt);
|
||||
}
|
||||
|
||||
// Check if units before m_iFirstNonreadPos are dropped.
|
||||
bool needUpdateNonreadPos = (minDroppedOffset != -1 && minDroppedOffset <= getRcvDataSize());
|
||||
const bool needUpdateNonreadPos = (minDroppedOffset != -1 && minDroppedOffset <= getRcvDataSize());
|
||||
releaseNextFillerEntries();
|
||||
if (needUpdateNonreadPos)
|
||||
{
|
||||
|
@ -305,19 +382,19 @@ int CRcvBufferNew::dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno)
|
|||
return iDropCnt;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)
|
||||
int CRcvBuffer::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)
|
||||
{
|
||||
const bool canReadInOrder = hasReadableInorderPkts();
|
||||
if (!canReadInOrder && m_iFirstReadableOutOfOrder < 0)
|
||||
{
|
||||
LOGC(rbuflog.Warn, log << "CRcvBufferNew.readMessage(): nothing to read. Ignored isRcvDataReady() result?");
|
||||
LOGC(rbuflog.Warn, log << "CRcvBuffer.readMessage(): nothing to read. Ignored isRcvDataReady() result?");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int readPos = canReadInOrder ? m_iStartPos : m_iFirstReadableOutOfOrder;
|
||||
|
||||
IF_RCVBUF_DEBUG(ScopedLog scoped_log);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBufferNew::readMessage. m_iStartSeqNo " << m_iStartSeqNo << " m_iStartPos " << m_iStartPos << " readPos " << readPos);
|
||||
IF_RCVBUF_DEBUG(scoped_log.ss << "CRcvBuffer::readMessage. m_iStartSeqNo " << m_iStartSeqNo << " m_iStartPos " << m_iStartPos << " readPos " << readPos);
|
||||
|
||||
size_t remain = len;
|
||||
char* dst = data;
|
||||
|
@ -329,11 +406,11 @@ int CRcvBufferNew::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)
|
|||
SRT_ASSERT(m_entries[i].pUnit);
|
||||
if (!m_entries[i].pUnit)
|
||||
{
|
||||
LOGC(rbuflog.Error, log << "CRcvBufferNew::readMessage(): null packet encountered.");
|
||||
LOGC(rbuflog.Error, log << "CRcvBuffer::readMessage(): null packet encountered.");
|
||||
break;
|
||||
}
|
||||
|
||||
const CPacket& packet = m_entries[i].pUnit->m_Packet;
|
||||
const CPacket& packet = packetAt(i);
|
||||
const size_t pktsize = packet.getLength();
|
||||
const int32_t pktseqno = packet.getSeqNo();
|
||||
|
||||
|
@ -368,8 +445,8 @@ int CRcvBufferNew::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)
|
|||
if (updateStartPos)
|
||||
{
|
||||
m_iStartPos = incPos(i);
|
||||
--m_iMaxPosInc;
|
||||
SRT_ASSERT(m_iMaxPosInc >= 0);
|
||||
--m_iMaxPosOff;
|
||||
SRT_ASSERT(m_iMaxPosOff >= 0);
|
||||
m_iStartSeqNo = CSeqNo::incseq(pktseqno);
|
||||
}
|
||||
else
|
||||
|
@ -390,7 +467,7 @@ int CRcvBufferNew::readMessage(char* data, size_t len, SRT_MSGCTRL* msgctrl)
|
|||
|
||||
releaseNextFillerEntries();
|
||||
|
||||
if (!isInRange(m_iStartPos, m_iMaxPosInc, m_szSize, m_iFirstNonreadPos))
|
||||
if (!isInRange(m_iStartPos, m_iMaxPosOff, m_szSize, m_iFirstNonreadPos))
|
||||
{
|
||||
m_iFirstNonreadPos = m_iStartPos;
|
||||
//updateNonreadPos();
|
||||
|
@ -440,7 +517,7 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
int CRcvBufferNew::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
||||
int CRcvBuffer::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
||||
{
|
||||
int p = m_iStartPos;
|
||||
const int end_pos = m_iFirstNonreadPos;
|
||||
|
@ -458,7 +535,7 @@ int CRcvBufferNew::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const srt::CPacket& pkt = m_entries[p].pUnit->m_Packet;
|
||||
const srt::CPacket& pkt = packetAt(p);
|
||||
|
||||
if (bTsbPdEnabled)
|
||||
{
|
||||
|
@ -486,8 +563,8 @@ int CRcvBufferNew::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
|||
m_iNotch = 0;
|
||||
|
||||
m_iStartPos = p;
|
||||
--m_iMaxPosInc;
|
||||
SRT_ASSERT(m_iMaxPosInc >= 0);
|
||||
--m_iMaxPosOff;
|
||||
SRT_ASSERT(m_iMaxPosOff >= 0);
|
||||
m_iStartSeqNo = CSeqNo::incseq(m_iStartSeqNo);
|
||||
}
|
||||
else
|
||||
|
@ -502,8 +579,8 @@ int CRcvBufferNew::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
|||
|
||||
// Update positions
|
||||
// Set nonread position to the starting position before updating,
|
||||
// because start position was increased, and preceeding packets are invalid.
|
||||
if (!isInRange(m_iStartPos, m_iMaxPosInc, m_szSize, m_iFirstNonreadPos))
|
||||
// because start position was increased, and preceding packets are invalid.
|
||||
if (!isInRange(m_iStartPos, m_iMaxPosOff, m_szSize, m_iFirstNonreadPos))
|
||||
{
|
||||
m_iFirstNonreadPos = m_iStartPos;
|
||||
}
|
||||
|
@ -516,22 +593,22 @@ int CRcvBufferNew::readBufferTo(int len, copy_to_dst_f funcCopyToDst, void* arg)
|
|||
return iBytesRead;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::readBuffer(char* dst, int len)
|
||||
int CRcvBuffer::readBuffer(char* dst, int len)
|
||||
{
|
||||
return readBufferTo(len, copyBytesToBuf, reinterpret_cast<void*>(dst));
|
||||
}
|
||||
|
||||
int CRcvBufferNew::readBufferToFile(fstream& ofs, int len)
|
||||
int CRcvBuffer::readBufferToFile(fstream& ofs, int len)
|
||||
{
|
||||
return readBufferTo(len, writeBytesToFile, reinterpret_cast<void*>(&ofs));
|
||||
}
|
||||
|
||||
bool CRcvBufferNew::hasAvailablePackets() const
|
||||
bool CRcvBuffer::hasAvailablePackets() const
|
||||
{
|
||||
return hasReadableInorderPkts() || (m_numOutOfOrderPackets > 0 && m_iFirstReadableOutOfOrder != -1);
|
||||
}
|
||||
|
||||
int CRcvBufferNew::getRcvDataSize() const
|
||||
int CRcvBuffer::getRcvDataSize() const
|
||||
{
|
||||
if (m_iFirstNonreadPos >= m_iStartPos)
|
||||
return m_iFirstNonreadPos - m_iStartPos;
|
||||
|
@ -539,36 +616,40 @@ int CRcvBufferNew::getRcvDataSize() const
|
|||
return int(m_szSize + m_iFirstNonreadPos - m_iStartPos);
|
||||
}
|
||||
|
||||
int CRcvBufferNew::getTimespan_ms() const
|
||||
int CRcvBuffer::getTimespan_ms() const
|
||||
{
|
||||
if (!m_tsbpd.isEnabled())
|
||||
return 0;
|
||||
|
||||
if (m_iMaxPosInc == 0)
|
||||
if (m_iMaxPosOff == 0)
|
||||
return 0;
|
||||
|
||||
const int lastpos = incPos(m_iStartPos, m_iMaxPosInc - 1);
|
||||
int startpos = m_iStartPos;
|
||||
|
||||
while (m_entries[startpos].pUnit == NULL)
|
||||
int lastpos = incPos(m_iStartPos, m_iMaxPosOff - 1);
|
||||
// Normally the last position should always be non empty
|
||||
// if TSBPD is enabled (reading out of order is not allowed).
|
||||
// However if decryption of the last packet fails, it may be dropped
|
||||
// from the buffer (AES-GCM), and the position will be empty.
|
||||
SRT_ASSERT(m_entries[lastpos].pUnit != NULL || m_entries[lastpos].status == EntryState_Drop);
|
||||
while (m_entries[lastpos].pUnit == NULL && lastpos != m_iStartPos)
|
||||
{
|
||||
if (startpos == lastpos)
|
||||
break;
|
||||
lastpos = decPos(lastpos);
|
||||
}
|
||||
|
||||
if (m_entries[lastpos].pUnit == NULL)
|
||||
return 0;
|
||||
|
||||
int startpos = m_iStartPos;
|
||||
while (m_entries[startpos].pUnit == NULL && startpos != lastpos)
|
||||
{
|
||||
startpos = incPos(startpos);
|
||||
}
|
||||
|
||||
if (m_entries[startpos].pUnit == NULL)
|
||||
return 0;
|
||||
|
||||
// Should not happen
|
||||
SRT_ASSERT(m_entries[lastpos].pUnit != NULL);
|
||||
if (m_entries[lastpos].pUnit == NULL)
|
||||
return 0;
|
||||
|
||||
const steady_clock::time_point startstamp =
|
||||
getPktTsbPdTime(m_entries[startpos].pUnit->m_Packet.getMsgTimeStamp());
|
||||
const steady_clock::time_point endstamp = getPktTsbPdTime(m_entries[lastpos].pUnit->m_Packet.getMsgTimeStamp());
|
||||
getPktTsbPdTime(packetAt(startpos).getMsgTimeStamp());
|
||||
const steady_clock::time_point endstamp = getPktTsbPdTime(packetAt(lastpos).getMsgTimeStamp());
|
||||
if (endstamp < startstamp)
|
||||
return 0;
|
||||
|
||||
|
@ -577,7 +658,7 @@ int CRcvBufferNew::getTimespan_ms() const
|
|||
return static_cast<int>(count_milliseconds(endstamp - startstamp) + 1);
|
||||
}
|
||||
|
||||
int CRcvBufferNew::getRcvDataSize(int& bytes, int& timespan) const
|
||||
int CRcvBuffer::getRcvDataSize(int& bytes, int& timespan) const
|
||||
{
|
||||
ScopedLock lck(m_BytesCountLock);
|
||||
bytes = m_iBytesCount;
|
||||
|
@ -585,16 +666,16 @@ int CRcvBufferNew::getRcvDataSize(int& bytes, int& timespan) const
|
|||
return m_iPktsCount;
|
||||
}
|
||||
|
||||
CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstValidPacketInfo() const
|
||||
CRcvBuffer::PacketInfo CRcvBuffer::getFirstValidPacketInfo() const
|
||||
{
|
||||
const int end_pos = incPos(m_iStartPos, m_iMaxPosInc);
|
||||
const int end_pos = incPos(m_iStartPos, m_iMaxPosOff);
|
||||
for (int i = m_iStartPos; i != end_pos; i = incPos(i))
|
||||
{
|
||||
// TODO: Maybe check status?
|
||||
if (!m_entries[i].pUnit)
|
||||
continue;
|
||||
|
||||
const CPacket& packet = m_entries[i].pUnit->m_Packet;
|
||||
const CPacket& packet = packetAt(i);
|
||||
const PacketInfo info = { packet.getSeqNo(), i != m_iStartPos, getPktTsbPdTime(packet.getMsgTimeStamp()) };
|
||||
return info;
|
||||
}
|
||||
|
@ -603,20 +684,20 @@ CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstValidPacketInfo() const
|
|||
return info;
|
||||
}
|
||||
|
||||
std::pair<int, int> CRcvBufferNew::getAvailablePacketsRange() const
|
||||
std::pair<int, int> CRcvBuffer::getAvailablePacketsRange() const
|
||||
{
|
||||
const int seqno_last = CSeqNo::incseq(m_iStartSeqNo, (int) countReadable());
|
||||
return std::pair<int, int>(m_iStartSeqNo, seqno_last);
|
||||
}
|
||||
|
||||
size_t CRcvBufferNew::countReadable() const
|
||||
size_t CRcvBuffer::countReadable() const
|
||||
{
|
||||
if (m_iFirstNonreadPos >= m_iStartPos)
|
||||
return m_iFirstNonreadPos - m_iStartPos;
|
||||
return m_szSize + m_iFirstNonreadPos - m_iStartPos;
|
||||
}
|
||||
|
||||
bool CRcvBufferNew::isRcvDataReady(time_point time_now) const
|
||||
bool CRcvBuffer::isRcvDataReady(time_point time_now) const
|
||||
{
|
||||
const bool haveInorderPackets = hasReadableInorderPkts();
|
||||
if (!m_tsbpd.isEnabled())
|
||||
|
@ -636,7 +717,7 @@ bool CRcvBufferNew::isRcvDataReady(time_point time_now) const
|
|||
return info.tsbpd_time <= time_now;
|
||||
}
|
||||
|
||||
CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstReadablePacketInfo(time_point time_now) const
|
||||
CRcvBuffer::PacketInfo CRcvBuffer::getFirstReadablePacketInfo(time_point time_now) const
|
||||
{
|
||||
const PacketInfo unreadableInfo = {SRT_SEQNO_NONE, false, time_point()};
|
||||
const bool hasInorderPackets = hasReadableInorderPkts();
|
||||
|
@ -645,7 +726,7 @@ CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstReadablePacketInfo(time_point t
|
|||
{
|
||||
if (hasInorderPackets)
|
||||
{
|
||||
const CPacket& packet = m_entries[m_iStartPos].pUnit->m_Packet;
|
||||
const CPacket& packet = packetAt(m_iStartPos);
|
||||
const PacketInfo info = {packet.getSeqNo(), false, time_point()};
|
||||
return info;
|
||||
}
|
||||
|
@ -653,7 +734,7 @@ CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstReadablePacketInfo(time_point t
|
|||
if (m_iFirstReadableOutOfOrder >= 0)
|
||||
{
|
||||
SRT_ASSERT(m_numOutOfOrderPackets > 0);
|
||||
const CPacket& packet = m_entries[m_iFirstReadableOutOfOrder].pUnit->m_Packet;
|
||||
const CPacket& packet = packetAt(m_iFirstReadableOutOfOrder);
|
||||
const PacketInfo info = {packet.getSeqNo(), true, time_point()};
|
||||
return info;
|
||||
}
|
||||
|
@ -671,7 +752,7 @@ CRcvBufferNew::PacketInfo CRcvBufferNew::getFirstReadablePacketInfo(time_point t
|
|||
return unreadableInfo;
|
||||
}
|
||||
|
||||
void CRcvBufferNew::countBytes(int pkts, int bytes)
|
||||
void CRcvBuffer::countBytes(int pkts, int bytes)
|
||||
{
|
||||
ScopedLock lock(m_BytesCountLock);
|
||||
m_iBytesCount += bytes; // added or removed bytes from rcv buffer
|
||||
|
@ -680,7 +761,7 @@ void CRcvBufferNew::countBytes(int pkts, int bytes)
|
|||
m_uAvgPayloadSz = avg_iir<100>(m_uAvgPayloadSz, (unsigned) bytes);
|
||||
}
|
||||
|
||||
void CRcvBufferNew::releaseUnitInPos(int pos)
|
||||
void CRcvBuffer::releaseUnitInPos(int pos)
|
||||
{
|
||||
CUnit* tmp = m_entries[pos].pUnit;
|
||||
m_entries[pos] = Entry(); // pUnit = NULL; status = Empty
|
||||
|
@ -688,15 +769,15 @@ void CRcvBufferNew::releaseUnitInPos(int pos)
|
|||
m_pUnitQueue->makeUnitFree(tmp);
|
||||
}
|
||||
|
||||
bool CRcvBufferNew::dropUnitInPos(int pos)
|
||||
bool CRcvBuffer::dropUnitInPos(int pos)
|
||||
{
|
||||
if (!m_entries[pos].pUnit)
|
||||
return false;
|
||||
if (m_tsbpd.isEnabled())
|
||||
{
|
||||
updateTsbPdTimeBase(m_entries[pos].pUnit->m_Packet.getMsgTimeStamp());
|
||||
updateTsbPdTimeBase(packetAt(pos).getMsgTimeStamp());
|
||||
}
|
||||
else if (m_bMessageAPI && !m_entries[pos].pUnit->m_Packet.getMsgOrderFlag())
|
||||
else if (m_bMessageAPI && !packetAt(pos).getMsgOrderFlag())
|
||||
{
|
||||
--m_numOutOfOrderPackets;
|
||||
if (pos == m_iFirstReadableOutOfOrder)
|
||||
|
@ -706,7 +787,7 @@ bool CRcvBufferNew::dropUnitInPos(int pos)
|
|||
return true;
|
||||
}
|
||||
|
||||
void CRcvBufferNew::releaseNextFillerEntries()
|
||||
void CRcvBuffer::releaseNextFillerEntries()
|
||||
{
|
||||
int pos = m_iStartPos;
|
||||
while (m_entries[pos].status == EntryState_Read || m_entries[pos].status == EntryState_Drop)
|
||||
|
@ -715,24 +796,24 @@ void CRcvBufferNew::releaseNextFillerEntries()
|
|||
releaseUnitInPos(pos);
|
||||
pos = incPos(pos);
|
||||
m_iStartPos = pos;
|
||||
--m_iMaxPosInc;
|
||||
if (m_iMaxPosInc < 0)
|
||||
m_iMaxPosInc = 0;
|
||||
--m_iMaxPosOff;
|
||||
if (m_iMaxPosOff < 0)
|
||||
m_iMaxPosOff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Is this function complete? There are some comments left inside.
|
||||
void CRcvBufferNew::updateNonreadPos()
|
||||
void CRcvBuffer::updateNonreadPos()
|
||||
{
|
||||
if (m_iMaxPosInc == 0)
|
||||
if (m_iMaxPosOff == 0)
|
||||
return;
|
||||
|
||||
const int end_pos = incPos(m_iStartPos, m_iMaxPosInc); // The empty position right after the last valid entry.
|
||||
const int end_pos = incPos(m_iStartPos, m_iMaxPosOff); // The empty position right after the last valid entry.
|
||||
|
||||
int pos = m_iFirstNonreadPos;
|
||||
while (m_entries[pos].pUnit && m_entries[pos].status == EntryState_Avail)
|
||||
{
|
||||
if (m_bMessageAPI && (m_entries[pos].pUnit->m_Packet.getMsgBoundary() & PB_FIRST) == 0)
|
||||
if (m_bMessageAPI && (packetAt(pos).getMsgBoundary() & PB_FIRST) == 0)
|
||||
break;
|
||||
|
||||
for (int i = pos; i != end_pos; i = incPos(i))
|
||||
|
@ -743,7 +824,7 @@ void CRcvBufferNew::updateNonreadPos()
|
|||
}
|
||||
|
||||
// Check PB_LAST only in message mode.
|
||||
if (!m_bMessageAPI || m_entries[i].pUnit->m_Packet.getMsgBoundary() & PB_LAST)
|
||||
if (!m_bMessageAPI || packetAt(i).getMsgBoundary() & PB_LAST)
|
||||
{
|
||||
m_iFirstNonreadPos = incPos(i);
|
||||
break;
|
||||
|
@ -757,13 +838,13 @@ void CRcvBufferNew::updateNonreadPos()
|
|||
}
|
||||
}
|
||||
|
||||
int CRcvBufferNew::findLastMessagePkt()
|
||||
int CRcvBuffer::findLastMessagePkt()
|
||||
{
|
||||
for (int i = m_iStartPos; i != m_iFirstNonreadPos; i = incPos(i))
|
||||
{
|
||||
SRT_ASSERT(m_entries[i].pUnit);
|
||||
|
||||
if (m_entries[i].pUnit->m_Packet.getMsgBoundary() & PB_LAST)
|
||||
if (packetAt(i).getMsgBoundary() & PB_LAST)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
@ -772,7 +853,7 @@ int CRcvBufferNew::findLastMessagePkt()
|
|||
return -1;
|
||||
}
|
||||
|
||||
void CRcvBufferNew::onInsertNotInOrderPacket(int insertPos)
|
||||
void CRcvBuffer::onInsertNotInOrderPacket(int insertPos)
|
||||
{
|
||||
if (m_numOutOfOrderPackets == 0)
|
||||
return;
|
||||
|
@ -788,9 +869,9 @@ void CRcvBufferNew::onInsertNotInOrderPacket(int insertPos)
|
|||
|
||||
// Just a sanity check. This function is called when a new packet is added.
|
||||
// So the should be unacknowledged packets.
|
||||
SRT_ASSERT(m_iMaxPosInc > 0);
|
||||
SRT_ASSERT(m_iMaxPosOff > 0);
|
||||
SRT_ASSERT(m_entries[insertPos].pUnit);
|
||||
const CPacket& pkt = m_entries[insertPos].pUnit->m_Packet;
|
||||
const CPacket& pkt = packetAt(insertPos);
|
||||
const PacketBoundary boundary = pkt.getMsgBoundary();
|
||||
|
||||
//if ((boundary & PB_FIRST) && (boundary & PB_LAST))
|
||||
|
@ -816,19 +897,19 @@ void CRcvBufferNew::onInsertNotInOrderPacket(int insertPos)
|
|||
return;
|
||||
}
|
||||
|
||||
bool CRcvBufferNew::checkFirstReadableOutOfOrder()
|
||||
bool CRcvBuffer::checkFirstReadableOutOfOrder()
|
||||
{
|
||||
if (m_numOutOfOrderPackets <= 0 || m_iFirstReadableOutOfOrder < 0 || m_iMaxPosInc == 0)
|
||||
if (m_numOutOfOrderPackets <= 0 || m_iFirstReadableOutOfOrder < 0 || m_iMaxPosOff == 0)
|
||||
return false;
|
||||
|
||||
const int endPos = incPos(m_iStartPos, m_iMaxPosInc);
|
||||
const int endPos = incPos(m_iStartPos, m_iMaxPosOff);
|
||||
int msgno = -1;
|
||||
for (int pos = m_iFirstReadableOutOfOrder; pos != endPos; pos = incPos(pos))
|
||||
{
|
||||
if (!m_entries[pos].pUnit)
|
||||
return false;
|
||||
|
||||
const CPacket& pkt = m_entries[pos].pUnit->m_Packet;
|
||||
const CPacket& pkt = packetAt(pos);
|
||||
if (pkt.getMsgOrderFlag())
|
||||
return false;
|
||||
|
||||
|
@ -844,12 +925,12 @@ bool CRcvBufferNew::checkFirstReadableOutOfOrder()
|
|||
return false;
|
||||
}
|
||||
|
||||
void CRcvBufferNew::updateFirstReadableOutOfOrder()
|
||||
void CRcvBuffer::updateFirstReadableOutOfOrder()
|
||||
{
|
||||
if (hasReadableInorderPkts() || m_numOutOfOrderPackets <= 0 || m_iFirstReadableOutOfOrder >= 0)
|
||||
return;
|
||||
|
||||
if (m_iMaxPosInc == 0)
|
||||
if (m_iMaxPosOff == 0)
|
||||
return;
|
||||
|
||||
// TODO: unused variable outOfOrderPktsRemain?
|
||||
|
@ -857,7 +938,7 @@ void CRcvBufferNew::updateFirstReadableOutOfOrder()
|
|||
|
||||
// Search further packets to the right.
|
||||
// First check if there are packets to the right.
|
||||
const int lastPos = (m_iStartPos + m_iMaxPosInc - 1) % m_szSize;
|
||||
const int lastPos = (m_iStartPos + m_iMaxPosOff - 1) % m_szSize;
|
||||
|
||||
int posFirst = -1;
|
||||
int posLast = -1;
|
||||
|
@ -871,7 +952,7 @@ void CRcvBufferNew::updateFirstReadableOutOfOrder()
|
|||
continue;
|
||||
}
|
||||
|
||||
const CPacket& pkt = m_entries[pos].pUnit->m_Packet;
|
||||
const CPacket& pkt = packetAt(pos);
|
||||
|
||||
if (pkt.getMsgOrderFlag()) // Skip in order packet
|
||||
{
|
||||
|
@ -907,11 +988,11 @@ void CRcvBufferNew::updateFirstReadableOutOfOrder()
|
|||
return;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::scanNotInOrderMessageRight(const int startPos, int msgNo) const
|
||||
int CRcvBuffer::scanNotInOrderMessageRight(const int startPos, int msgNo) const
|
||||
{
|
||||
// Search further packets to the right.
|
||||
// First check if there are packets to the right.
|
||||
const int lastPos = (m_iStartPos + m_iMaxPosInc - 1) % m_szSize;
|
||||
const int lastPos = (m_iStartPos + m_iMaxPosOff - 1) % m_szSize;
|
||||
if (startPos == lastPos)
|
||||
return -1;
|
||||
|
||||
|
@ -922,7 +1003,7 @@ int CRcvBufferNew::scanNotInOrderMessageRight(const int startPos, int msgNo) con
|
|||
if (!m_entries[pos].pUnit)
|
||||
break;
|
||||
|
||||
const CPacket& pkt = m_entries[pos].pUnit->m_Packet;
|
||||
const CPacket& pkt = packetAt(pos);
|
||||
|
||||
if (pkt.getMsgSeq(m_bPeerRexmitFlag) != msgNo)
|
||||
{
|
||||
|
@ -938,9 +1019,9 @@ int CRcvBufferNew::scanNotInOrderMessageRight(const int startPos, int msgNo) con
|
|||
return -1;
|
||||
}
|
||||
|
||||
int CRcvBufferNew::scanNotInOrderMessageLeft(const int startPos, int msgNo) const
|
||||
int CRcvBuffer::scanNotInOrderMessageLeft(const int startPos, int msgNo) const
|
||||
{
|
||||
// Search preceeding packets to the left.
|
||||
// Search preceding packets to the left.
|
||||
// First check if there are packets to the left.
|
||||
if (startPos == m_iStartPos)
|
||||
return -1;
|
||||
|
@ -953,7 +1034,7 @@ int CRcvBufferNew::scanNotInOrderMessageLeft(const int startPos, int msgNo) cons
|
|||
if (!m_entries[pos].pUnit)
|
||||
return -1;
|
||||
|
||||
const CPacket& pkt = m_entries[pos].pUnit->m_Packet;
|
||||
const CPacket& pkt = packetAt(pos);
|
||||
|
||||
if (pkt.getMsgSeq(m_bPeerRexmitFlag) != msgNo)
|
||||
{
|
||||
|
@ -969,17 +1050,17 @@ int CRcvBufferNew::scanNotInOrderMessageLeft(const int startPos, int msgNo) cons
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool CRcvBufferNew::addRcvTsbPdDriftSample(uint32_t usTimestamp, const time_point& tsPktArrival, int usRTTSample)
|
||||
bool CRcvBuffer::addRcvTsbPdDriftSample(uint32_t usTimestamp, const time_point& tsPktArrival, int usRTTSample)
|
||||
{
|
||||
return m_tsbpd.addDriftSample(usTimestamp, tsPktArrival, usRTTSample);
|
||||
}
|
||||
|
||||
void CRcvBufferNew::setTsbPdMode(const steady_clock::time_point& timebase, bool wrap, duration delay)
|
||||
void CRcvBuffer::setTsbPdMode(const steady_clock::time_point& timebase, bool wrap, duration delay)
|
||||
{
|
||||
m_tsbpd.setTsbPdMode(timebase, wrap, delay);
|
||||
}
|
||||
|
||||
void CRcvBufferNew::applyGroupTime(const steady_clock::time_point& timebase,
|
||||
void CRcvBuffer::applyGroupTime(const steady_clock::time_point& timebase,
|
||||
bool wrp,
|
||||
uint32_t delay,
|
||||
const steady_clock::duration& udrift)
|
||||
|
@ -987,41 +1068,44 @@ void CRcvBufferNew::applyGroupTime(const steady_clock::time_point& timebase,
|
|||
m_tsbpd.applyGroupTime(timebase, wrp, delay, udrift);
|
||||
}
|
||||
|
||||
void CRcvBufferNew::applyGroupDrift(const steady_clock::time_point& timebase,
|
||||
void CRcvBuffer::applyGroupDrift(const steady_clock::time_point& timebase,
|
||||
bool wrp,
|
||||
const steady_clock::duration& udrift)
|
||||
{
|
||||
m_tsbpd.applyGroupDrift(timebase, wrp, udrift);
|
||||
}
|
||||
|
||||
CRcvBufferNew::time_point CRcvBufferNew::getTsbPdTimeBase(uint32_t usPktTimestamp) const
|
||||
CRcvBuffer::time_point CRcvBuffer::getTsbPdTimeBase(uint32_t usPktTimestamp) const
|
||||
{
|
||||
return m_tsbpd.getTsbPdTimeBase(usPktTimestamp);
|
||||
}
|
||||
|
||||
void CRcvBufferNew::updateTsbPdTimeBase(uint32_t usPktTimestamp)
|
||||
void CRcvBuffer::updateTsbPdTimeBase(uint32_t usPktTimestamp)
|
||||
{
|
||||
m_tsbpd.updateTsbPdTimeBase(usPktTimestamp);
|
||||
}
|
||||
|
||||
string CRcvBufferNew::strFullnessState(int iFirstUnackSeqNo, const time_point& tsNow) const
|
||||
string CRcvBuffer::strFullnessState(int iFirstUnackSeqNo, const time_point& tsNow) const
|
||||
{
|
||||
stringstream ss;
|
||||
|
||||
ss << "Space avail " << getAvailSize(iFirstUnackSeqNo) << "/" << m_szSize;
|
||||
ss << " pkts. ";
|
||||
if (m_tsbpd.isEnabled() && m_iMaxPosInc > 0)
|
||||
ss << "iFirstUnackSeqNo=" << iFirstUnackSeqNo << " m_iStartSeqNo=" << m_iStartSeqNo
|
||||
<< " m_iStartPos=" << m_iStartPos << " m_iMaxPosOff=" << m_iMaxPosOff << ". ";
|
||||
|
||||
ss << "Space avail " << getAvailSize(iFirstUnackSeqNo) << "/" << m_szSize << " pkts. ";
|
||||
|
||||
if (m_tsbpd.isEnabled() && m_iMaxPosOff > 0)
|
||||
{
|
||||
const PacketInfo nextValidPkt = getFirstValidPacketInfo();
|
||||
ss << "(TSBPD ready in ";
|
||||
if (!is_zero(nextValidPkt.tsbpd_time))
|
||||
{
|
||||
ss << count_milliseconds(nextValidPkt.tsbpd_time - tsNow) << "ms";
|
||||
const int iLastPos = incPos(m_iStartPos, m_iMaxPosInc - 1);
|
||||
const int iLastPos = incPos(m_iStartPos, m_iMaxPosOff - 1);
|
||||
if (m_entries[iLastPos].pUnit)
|
||||
{
|
||||
ss << ", timespan ";
|
||||
const uint32_t usPktTimestamp = m_entries[iLastPos].pUnit->m_Packet.getMsgTimeStamp();
|
||||
const uint32_t usPktTimestamp = packetAt(iLastPos).getMsgTimeStamp();
|
||||
ss << count_milliseconds(m_tsbpd.getPktTsbPdTime(usPktTimestamp) - nextValidPkt.tsbpd_time);
|
||||
ss << " ms";
|
||||
}
|
||||
|
@ -1030,7 +1114,6 @@ string CRcvBufferNew::strFullnessState(int iFirstUnackSeqNo, const time_point& t
|
|||
{
|
||||
ss << "n/a";
|
||||
}
|
||||
|
||||
ss << "). ";
|
||||
}
|
||||
|
||||
|
@ -1038,13 +1121,13 @@ string CRcvBufferNew::strFullnessState(int iFirstUnackSeqNo, const time_point& t
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
CRcvBufferNew::time_point CRcvBufferNew::getPktTsbPdTime(uint32_t usPktTimestamp) const
|
||||
CRcvBuffer::time_point CRcvBuffer::getPktTsbPdTime(uint32_t usPktTimestamp) const
|
||||
{
|
||||
return m_tsbpd.getPktTsbPdTime(usPktTimestamp);
|
||||
}
|
||||
|
||||
/* Return moving average of acked data pkts, bytes, and timespan (ms) of the receive buffer */
|
||||
int CRcvBufferNew::getRcvAvgDataSize(int& bytes, int& timespan)
|
||||
int CRcvBuffer::getRcvAvgDataSize(int& bytes, int& timespan)
|
||||
{
|
||||
// Average number of packets and timespan could be small,
|
||||
// so rounding is beneficial, while for the number of
|
||||
|
@ -1056,7 +1139,7 @@ int CRcvBufferNew::getRcvAvgDataSize(int& bytes, int& timespan)
|
|||
}
|
||||
|
||||
/* Update moving average of acked data pkts, bytes, and timespan (ms) of the receive buffer */
|
||||
void CRcvBufferNew::updRcvAvgDataSize(const steady_clock::time_point& now)
|
||||
void CRcvBuffer::updRcvAvgDataSize(const steady_clock::time_point& now)
|
||||
{
|
||||
if (!m_mavg.isTimeToUpdate(now))
|
||||
return;
|
||||
|
@ -1068,5 +1151,3 @@ void CRcvBufferNew::updRcvAvgDataSize(const steady_clock::time_point& now)
|
|||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif // ENABLE_NEW_RCVBUFFER
|
||||
|
|
73
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.h
vendored
73
trunk/3rdparty/srt-1-fit/srtcore/buffer_rcv.h
vendored
|
@ -11,12 +11,9 @@
|
|||
#ifndef INC_SRT_BUFFER_RCV_H
|
||||
#define INC_SRT_BUFFER_RCV_H
|
||||
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
|
||||
#include "buffer.h" // AvgBufSize
|
||||
#include "buffer_tools.h" // AvgBufSize
|
||||
#include "common.h"
|
||||
#include "queue.h"
|
||||
#include "sync.h"
|
||||
#include "tsbpd_time.h"
|
||||
|
||||
namespace srt
|
||||
|
@ -26,7 +23,7 @@ namespace srt
|
|||
* Circular receiver buffer.
|
||||
*
|
||||
* |<------------------- m_szSize ---------------------------->|
|
||||
* | |<------------ m_iMaxPosInc ----------->| |
|
||||
* | |<------------ m_iMaxPosOff ----------->| |
|
||||
* | | | |
|
||||
* +---+---+---+---+---+---+---+---+---+---+---+---+---+ +---+
|
||||
* | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 |...| 0 | m_pUnit[]
|
||||
|
@ -45,15 +42,15 @@ namespace srt
|
|||
* first_nonread_pos_:
|
||||
*/
|
||||
|
||||
class CRcvBufferNew
|
||||
class CRcvBuffer
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
CRcvBufferNew(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool bMessageAPI);
|
||||
CRcvBuffer(int initSeqNo, size_t size, CUnitQueue* unitqueue, bool bMessageAPI);
|
||||
|
||||
~CRcvBufferNew();
|
||||
~CRcvBuffer();
|
||||
|
||||
public:
|
||||
/// Insert a unit into the buffer.
|
||||
|
@ -77,14 +74,29 @@ public:
|
|||
/// @return the number of dropped packets.
|
||||
int dropAll();
|
||||
|
||||
/// @brief Drop the whole message from the buffer.
|
||||
/// If message number is 0, then use sequence numbers to locate sequence range to drop [seqnolo, seqnohi].
|
||||
/// When one packet of the message is in the range of dropping, the whole message is to be dropped.
|
||||
enum DropActionIfExists {
|
||||
DROP_EXISTING = 0,
|
||||
KEEP_EXISTING = 1
|
||||
};
|
||||
|
||||
/// @brief Drop a sequence of packets from the buffer.
|
||||
/// If @a msgno is valid, sender has requested to drop the whole message by TTL. In this case it has to also provide a pkt seqno range.
|
||||
/// However, if a message has been partially acknowledged and already removed from the SND buffer,
|
||||
/// the @a seqnolo might specify some position in the middle of the message, not the very first packet.
|
||||
/// If those packets have been acknowledged, they must exist in the receiver buffer unless already read.
|
||||
/// In this case the @a msgno should be used to determine starting packets of the message.
|
||||
/// Some packets of the message can be missing on the receiver, therefore the actual drop should still be performed by pkt seqno range.
|
||||
/// If message number is 0 or SRT_MSGNO_NONE, then use sequence numbers to locate sequence range to drop [seqnolo, seqnohi].
|
||||
/// A SOLO message packet can be kept depending on @a actionOnExisting value.
|
||||
/// TODO: A message in general can be kept if all of its packets are in the buffer, depending on @a actionOnExisting value.
|
||||
/// This is done to avoid dropping existing packet when the sender was asked to re-transmit a packet from an outdated loss report,
|
||||
/// which is already not available in the SND buffer.
|
||||
/// @param seqnolo sequence number of the first packet in the dropping range.
|
||||
/// @param seqnohi sequence number of the last packet in the dropping range.
|
||||
/// @param msgno message number to drop (0 if unknown)
|
||||
/// @param actionOnExisting Should an exising SOLO packet be dropped from the buffer or preserved?
|
||||
/// @return the number of packets actually dropped.
|
||||
int dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno);
|
||||
int dropMessage(int32_t seqnolo, int32_t seqnohi, int32_t msgno, DropActionIfExists actionOnExisting);
|
||||
|
||||
/// Read the whole message from one or several packets.
|
||||
///
|
||||
|
@ -130,9 +142,8 @@ public:
|
|||
const int iRBufSeqNo = getStartSeqNo();
|
||||
if (CSeqNo::seqcmp(iRBufSeqNo, iFirstUnackSeqNo) >= 0) // iRBufSeqNo >= iFirstUnackSeqNo
|
||||
{
|
||||
// Full capacity is available, still don't want to encourage extra packets to come.
|
||||
// Note: CSeqNo::seqlen(n, n) returns 1.
|
||||
return capacity() - CSeqNo::seqlen(iFirstUnackSeqNo, iRBufSeqNo) + 1;
|
||||
// Full capacity is available.
|
||||
return capacity();
|
||||
}
|
||||
|
||||
// Note: CSeqNo::seqlen(n, n) returns 1.
|
||||
|
@ -140,13 +151,14 @@ public:
|
|||
}
|
||||
|
||||
/// @brief Checks if the buffer has packets available for reading regardless of the TSBPD.
|
||||
/// A message is available for reading only if all of its packets are present in the buffer.
|
||||
/// @return true if there are packets available for reading, false otherwise.
|
||||
bool hasAvailablePackets() const;
|
||||
|
||||
/// Query how many data has been continuously received (for reading) and available for reading out
|
||||
/// regardless of the TSBPD.
|
||||
/// TODO: Rename to countAvailablePackets().
|
||||
/// @return size of valid (continous) data for reading.
|
||||
/// @return size of valid (continuous) data for reading.
|
||||
int getRcvDataSize() const;
|
||||
|
||||
/// Get the number of packets, bytes and buffer timespan.
|
||||
|
@ -165,11 +177,11 @@ public:
|
|||
/// Parameters (of the 1st packet queue, ready to play or not):
|
||||
/// @param [out] tsbpdtime localtime-based (uSec) packet time stamp including buffering delay of 1st packet or 0 if
|
||||
/// none
|
||||
/// @param [out] passack true if 1st ready packet is not yet acknowleged (allowed to be delivered to the app)
|
||||
/// @param [out] skipseqno -1 or seq number of 1st unacknowledged pkt ready to play preceeded by missing packets.
|
||||
/// @param [out] passack true if 1st ready packet is not yet acknowledged (allowed to be delivered to the app)
|
||||
/// @param [out] skipseqno -1 or sequence number of 1st unacknowledged packet (after one or more missing packets) that is ready to play.
|
||||
/// @retval true 1st packet ready to play (tsbpdtime <= now). Not yet acknowledged if passack == true
|
||||
/// @retval false IF tsbpdtime = 0: rcv buffer empty; ELSE:
|
||||
/// IF skipseqno != -1, packet ready to play preceeded by missing packets.;
|
||||
/// IF skipseqno != -1, packet ready to play preceded by missing packets.;
|
||||
/// IF skipseqno == -1, no missing packet but 1st not ready to play.
|
||||
PacketInfo getFirstValidPacketInfo() const;
|
||||
|
||||
|
@ -185,7 +197,7 @@ public:
|
|||
|
||||
bool empty() const
|
||||
{
|
||||
return (m_iMaxPosInc == 0);
|
||||
return (m_iMaxPosOff == 0);
|
||||
}
|
||||
|
||||
/// Return buffer capacity.
|
||||
|
@ -227,6 +239,18 @@ private:
|
|||
inline int incPos(int pos, int inc = 1) const { return (pos + inc) % m_szSize; }
|
||||
inline int decPos(int pos) const { return (pos - 1) >= 0 ? (pos - 1) : int(m_szSize - 1); }
|
||||
inline int offPos(int pos1, int pos2) const { return (pos2 >= pos1) ? (pos2 - pos1) : int(m_szSize + pos2 - pos1); }
|
||||
inline int cmpPos(int pos2, int pos1) const
|
||||
{
|
||||
// XXX maybe not the best implementation, but this keeps up to the rule
|
||||
const int off1 = pos1 >= m_iStartPos ? pos1 - m_iStartPos : pos1 + (int)m_szSize - m_iStartPos;
|
||||
const int off2 = pos2 >= m_iStartPos ? pos2 - m_iStartPos : pos2 + (int)m_szSize - m_iStartPos;
|
||||
|
||||
return off2 - off1;
|
||||
}
|
||||
|
||||
// NOTE: Assumes that pUnit != NULL
|
||||
CPacket& packetAt(int pos) { return m_entries[pos].pUnit->m_Packet; }
|
||||
const CPacket& packetAt(int pos) const { return m_entries[pos].pUnit->m_Packet; }
|
||||
|
||||
private:
|
||||
void countBytes(int pkts, int bytes);
|
||||
|
@ -268,7 +292,7 @@ private:
|
|||
int getTimespan_ms() const;
|
||||
|
||||
private:
|
||||
// TODO: Call makeUnitGood upon assignment, and makeUnitFree upon clearing.
|
||||
// TODO: Call makeUnitTaken upon assignment, and makeUnitFree upon clearing.
|
||||
// TODO: CUnitPtr is not in use at the moment, but may be a smart pointer.
|
||||
// class CUnitPtr
|
||||
// {
|
||||
|
@ -313,7 +337,7 @@ private:
|
|||
int m_iStartSeqNo;
|
||||
int m_iStartPos; // the head position for I/O (inclusive)
|
||||
int m_iFirstNonreadPos; // First position that can't be read (<= m_iLastAckPos)
|
||||
int m_iMaxPosInc; // the furthest data position
|
||||
int m_iMaxPosOff; // the furthest data position
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
|
||||
size_t m_numOutOfOrderPackets; // The number of stored packets with "inorder" flag set to false
|
||||
|
@ -326,7 +350,7 @@ public: // TSBPD public functions
|
|||
/// Set TimeStamp-Based Packet Delivery Rx Mode
|
||||
/// @param [in] timebase localtime base (uSec) of packet time stamps including buffering delay
|
||||
/// @param [in] wrap Is in wrapping period
|
||||
/// @param [in] delay aggreed TsbPD delay
|
||||
/// @param [in] delay agreed TsbPD delay
|
||||
///
|
||||
/// @return 0
|
||||
void setTsbPdMode(const time_point& timebase, bool wrap, duration delay);
|
||||
|
@ -344,6 +368,8 @@ public: // TSBPD public functions
|
|||
time_point getTsbPdTimeBase(uint32_t usPktTimestamp) const;
|
||||
void updateTsbPdTimeBase(uint32_t usPktTimestamp);
|
||||
|
||||
bool isTsbPd() const { return m_tsbpd.isEnabled(); }
|
||||
|
||||
/// Form a string of the current buffer fullness state.
|
||||
/// number of packets acknowledged, TSBPD readiness, etc.
|
||||
std::string strFullnessState(int iFirstUnackSeqNo, const time_point& tsNow) const;
|
||||
|
@ -363,5 +389,4 @@ private: // Statistics
|
|||
|
||||
} // namespace srt
|
||||
|
||||
#endif // ENABLE_NEW_RCVBUFFER
|
||||
#endif // INC_SRT_BUFFER_RCV_H
|
||||
|
|
730
trunk/3rdparty/srt-1-fit/srtcore/buffer_snd.cpp
vendored
Normal file
730
trunk/3rdparty/srt-1-fit/srtcore/buffer_snd.cpp
vendored
Normal file
|
@ -0,0 +1,730 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 03/12/2011
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cmath>
|
||||
#include "buffer_snd.h"
|
||||
#include "packet.h"
|
||||
#include "core.h" // provides some constants
|
||||
#include "logging.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
using namespace std;
|
||||
using namespace srt_logging;
|
||||
using namespace sync;
|
||||
|
||||
CSndBuffer::CSndBuffer(int size, int maxpld, int authtag)
|
||||
: m_BufLock()
|
||||
, m_pBlock(NULL)
|
||||
, m_pFirstBlock(NULL)
|
||||
, m_pCurrBlock(NULL)
|
||||
, m_pLastBlock(NULL)
|
||||
, m_pBuffer(NULL)
|
||||
, m_iNextMsgNo(1)
|
||||
, m_iSize(size)
|
||||
, m_iBlockLen(maxpld)
|
||||
, m_iAuthTagSize(authtag)
|
||||
, m_iCount(0)
|
||||
, m_iBytesCount(0)
|
||||
{
|
||||
// initial physical buffer of "size"
|
||||
m_pBuffer = new Buffer;
|
||||
m_pBuffer->m_pcData = new char[m_iSize * m_iBlockLen];
|
||||
m_pBuffer->m_iSize = m_iSize;
|
||||
m_pBuffer->m_pNext = NULL;
|
||||
|
||||
// circular linked list for out bound packets
|
||||
m_pBlock = new Block;
|
||||
Block* pb = m_pBlock;
|
||||
char* pc = m_pBuffer->m_pcData;
|
||||
|
||||
for (int i = 0; i < m_iSize; ++i)
|
||||
{
|
||||
pb->m_iMsgNoBitset = 0;
|
||||
pb->m_pcData = pc;
|
||||
pc += m_iBlockLen;
|
||||
|
||||
if (i < m_iSize - 1)
|
||||
{
|
||||
pb->m_pNext = new Block;
|
||||
pb = pb->m_pNext;
|
||||
}
|
||||
}
|
||||
pb->m_pNext = m_pBlock;
|
||||
|
||||
m_pFirstBlock = m_pCurrBlock = m_pLastBlock = m_pBlock;
|
||||
|
||||
setupMutex(m_BufLock, "Buf");
|
||||
}
|
||||
|
||||
CSndBuffer::~CSndBuffer()
|
||||
{
|
||||
Block* pb = m_pBlock->m_pNext;
|
||||
while (pb != m_pBlock)
|
||||
{
|
||||
Block* temp = pb;
|
||||
pb = pb->m_pNext;
|
||||
delete temp;
|
||||
}
|
||||
delete m_pBlock;
|
||||
|
||||
while (m_pBuffer != NULL)
|
||||
{
|
||||
Buffer* temp = m_pBuffer;
|
||||
m_pBuffer = m_pBuffer->m_pNext;
|
||||
delete[] temp->m_pcData;
|
||||
delete temp;
|
||||
}
|
||||
|
||||
releaseMutex(m_BufLock);
|
||||
}
|
||||
|
||||
void CSndBuffer::addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl)
|
||||
{
|
||||
int32_t& w_msgno = w_mctrl.msgno;
|
||||
int32_t& w_seqno = w_mctrl.pktseq;
|
||||
int64_t& w_srctime = w_mctrl.srctime;
|
||||
const int& ttl = w_mctrl.msgttl;
|
||||
const int iPktLen = getMaxPacketLen();
|
||||
const int iNumBlocks = countNumPacketsRequired(len, iPktLen);
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "addBuffer: needs=" << iNumBlocks << " buffers for " << len << " bytes. Taken=" << m_iCount << "/" << m_iSize);
|
||||
// Retrieve current time before locking the mutex to be closer to packet submission event.
|
||||
const steady_clock::time_point tnow = steady_clock::now();
|
||||
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
// Dynamically increase sender buffer if there is not enough room.
|
||||
while (iNumBlocks + m_iCount >= m_iSize)
|
||||
{
|
||||
HLOGC(bslog.Debug, log << "addBuffer: ... still lacking " << (iNumBlocks + m_iCount - m_iSize) << " buffers...");
|
||||
increase();
|
||||
}
|
||||
|
||||
const int32_t inorder = w_mctrl.inorder ? MSGNO_PACKET_INORDER::mask : 0;
|
||||
HLOGC(bslog.Debug,
|
||||
log << CONID() << "addBuffer: adding " << iNumBlocks << " packets (" << len << " bytes) to send, msgno="
|
||||
<< (w_msgno > 0 ? w_msgno : m_iNextMsgNo) << (inorder ? "" : " NOT") << " in order");
|
||||
|
||||
// Calculate origin time (same for all blocks of the message).
|
||||
m_tsLastOriginTime = w_srctime ? time_point() + microseconds_from(w_srctime) : tnow;
|
||||
// Rewrite back the actual value, even if it stays the same, so that the calling facilities can reuse it.
|
||||
// May also be a subject to conversion error, thus the actual value is signalled back.
|
||||
w_srctime = count_microseconds(m_tsLastOriginTime.time_since_epoch());
|
||||
|
||||
// The sequence number passed to this function is the sequence number
|
||||
// that the very first packet from the packet series should get here.
|
||||
// If there's more than one packet, this function must increase it by itself
|
||||
// and then return the accordingly modified sequence number in the reference.
|
||||
|
||||
Block* s = m_pLastBlock;
|
||||
|
||||
if (w_msgno == SRT_MSGNO_NONE) // DEFAULT-UNCHANGED msgno supplied
|
||||
{
|
||||
HLOGC(bslog.Debug, log << "addBuffer: using internally managed msgno=" << m_iNextMsgNo);
|
||||
w_msgno = m_iNextMsgNo;
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(bslog.Debug, log << "addBuffer: OVERWRITTEN by msgno supplied by caller: msgno=" << w_msgno);
|
||||
m_iNextMsgNo = w_msgno;
|
||||
}
|
||||
|
||||
for (int i = 0; i < iNumBlocks; ++i)
|
||||
{
|
||||
int pktlen = len - i * iPktLen;
|
||||
if (pktlen > iPktLen)
|
||||
pktlen = iPktLen;
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "addBuffer: %" << w_seqno << " #" << w_msgno << " offset=" << (i * iPktLen)
|
||||
<< " size=" << pktlen << " TO BUFFER:" << (void*)s->m_pcData);
|
||||
memcpy((s->m_pcData), data + i * iPktLen, pktlen);
|
||||
s->m_iLength = pktlen;
|
||||
|
||||
s->m_iSeqNo = w_seqno;
|
||||
w_seqno = CSeqNo::incseq(w_seqno);
|
||||
|
||||
s->m_iMsgNoBitset = m_iNextMsgNo | inorder;
|
||||
if (i == 0)
|
||||
s->m_iMsgNoBitset |= PacketBoundaryBits(PB_FIRST);
|
||||
if (i == iNumBlocks - 1)
|
||||
s->m_iMsgNoBitset |= PacketBoundaryBits(PB_LAST);
|
||||
// NOTE: if i is neither 0 nor size-1, it resuls with PB_SUBSEQUENT.
|
||||
// if i == 0 == size-1, it results with PB_SOLO.
|
||||
// Packets assigned to one message can be:
|
||||
// [PB_FIRST] [PB_SUBSEQUENT] [PB_SUBSEQUENT] [PB_LAST] - 4 packets per message
|
||||
// [PB_FIRST] [PB_LAST] - 2 packets per message
|
||||
// [PB_SOLO] - 1 packet per message
|
||||
|
||||
s->m_iTTL = ttl;
|
||||
s->m_tsRexmitTime = time_point();
|
||||
s->m_tsOriginTime = m_tsLastOriginTime;
|
||||
|
||||
// Should never happen, as the call to increase() should ensure enough buffers.
|
||||
SRT_ASSERT(s->m_pNext);
|
||||
s = s->m_pNext;
|
||||
}
|
||||
m_pLastBlock = s;
|
||||
|
||||
m_iCount += iNumBlocks;
|
||||
m_iBytesCount += len;
|
||||
|
||||
m_rateEstimator.updateInputRate(m_tsLastOriginTime, iNumBlocks, len);
|
||||
updAvgBufSize(m_tsLastOriginTime);
|
||||
|
||||
// MSGNO_SEQ::mask has a form: 00000011111111...
|
||||
// At least it's known that it's from some index inside til the end (to bit 0).
|
||||
// If this value has been reached in a step of incrementation, it means that the
|
||||
// maximum value has been reached. Casting to int32_t to ensure the same sign
|
||||
// in comparison, although it's far from reaching the sign bit.
|
||||
|
||||
const int nextmsgno = ++MsgNo(m_iNextMsgNo);
|
||||
HLOGC(bslog.Debug, log << "CSndBuffer::addBuffer: updating msgno: #" << m_iNextMsgNo << " -> #" << nextmsgno);
|
||||
m_iNextMsgNo = nextmsgno;
|
||||
}
|
||||
|
||||
int CSndBuffer::addBufferFromFile(fstream& ifs, int len)
|
||||
{
|
||||
const int iPktLen = getMaxPacketLen();
|
||||
const int iNumBlocks = countNumPacketsRequired(len, iPktLen);
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "addBufferFromFile: size=" << m_iCount << " reserved=" << m_iSize << " needs=" << iPktLen
|
||||
<< " buffers for " << len << " bytes");
|
||||
|
||||
// dynamically increase sender buffer
|
||||
while (iNumBlocks + m_iCount >= m_iSize)
|
||||
{
|
||||
HLOGC(bslog.Debug,
|
||||
log << "addBufferFromFile: ... still lacking " << (iNumBlocks + m_iCount - m_iSize) << " buffers...");
|
||||
increase();
|
||||
}
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << CONID() << "addBufferFromFile: adding " << iPktLen << " packets (" << len
|
||||
<< " bytes) to send, msgno=" << m_iNextMsgNo);
|
||||
|
||||
Block* s = m_pLastBlock;
|
||||
int total = 0;
|
||||
for (int i = 0; i < iNumBlocks; ++i)
|
||||
{
|
||||
if (ifs.bad() || ifs.fail() || ifs.eof())
|
||||
break;
|
||||
|
||||
int pktlen = len - i * iPktLen;
|
||||
if (pktlen > iPktLen)
|
||||
pktlen = iPktLen;
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "addBufferFromFile: reading from=" << (i * iPktLen) << " size=" << pktlen
|
||||
<< " TO BUFFER:" << (void*)s->m_pcData);
|
||||
ifs.read(s->m_pcData, pktlen);
|
||||
if ((pktlen = int(ifs.gcount())) <= 0)
|
||||
break;
|
||||
|
||||
// currently file transfer is only available in streaming mode, message is always in order, ttl = infinite
|
||||
s->m_iMsgNoBitset = m_iNextMsgNo | MSGNO_PACKET_INORDER::mask;
|
||||
if (i == 0)
|
||||
s->m_iMsgNoBitset |= PacketBoundaryBits(PB_FIRST);
|
||||
if (i == iNumBlocks - 1)
|
||||
s->m_iMsgNoBitset |= PacketBoundaryBits(PB_LAST);
|
||||
// NOTE: PB_FIRST | PB_LAST == PB_SOLO.
|
||||
// none of PB_FIRST & PB_LAST == PB_SUBSEQUENT.
|
||||
|
||||
s->m_iLength = pktlen;
|
||||
s->m_iTTL = SRT_MSGTTL_INF;
|
||||
s = s->m_pNext;
|
||||
|
||||
total += pktlen;
|
||||
}
|
||||
m_pLastBlock = s;
|
||||
|
||||
enterCS(m_BufLock);
|
||||
m_iCount += iNumBlocks;
|
||||
m_iBytesCount += total;
|
||||
|
||||
leaveCS(m_BufLock);
|
||||
|
||||
m_iNextMsgNo++;
|
||||
if (m_iNextMsgNo == int32_t(MSGNO_SEQ::mask))
|
||||
m_iNextMsgNo = 1;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int CSndBuffer::readData(CPacket& w_packet, steady_clock::time_point& w_srctime, int kflgs, int& w_seqnoinc)
|
||||
{
|
||||
int readlen = 0;
|
||||
w_seqnoinc = 0;
|
||||
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
while (m_pCurrBlock != m_pLastBlock)
|
||||
{
|
||||
// Make the packet REFLECT the data stored in the buffer.
|
||||
w_packet.m_pcData = m_pCurrBlock->m_pcData;
|
||||
readlen = m_pCurrBlock->m_iLength;
|
||||
w_packet.setLength(readlen, m_iBlockLen);
|
||||
w_packet.m_iSeqNo = m_pCurrBlock->m_iSeqNo;
|
||||
|
||||
// 1. On submission (addBuffer), the KK flag is set to EK_NOENC (0).
|
||||
// 2. The readData() is called to get the original (unique) payload not ever sent yet.
|
||||
// The payload must be encrypted for the first time if the encryption
|
||||
// is enabled (arg kflgs != EK_NOENC). The KK encryption flag of the data packet
|
||||
// header must be set and remembered accordingly (see EncryptionKeySpec).
|
||||
// 3. The next time this packet is read (only for retransmission), the payload is already
|
||||
// encrypted, and the proper flag value is already stored.
|
||||
|
||||
// TODO: Alternatively, encryption could happen before the packet is submitted to the buffer
|
||||
// (before the addBuffer() call), and corresponding flags could be set accordingly.
|
||||
// This may also put an encryption burden on the application thread, rather than the sending thread,
|
||||
// which could be more efficient. Note that packet sequence number must be properly set in that case,
|
||||
// as it is used as a counter for the AES encryption.
|
||||
if (kflgs == -1)
|
||||
{
|
||||
HLOGC(bslog.Debug, log << CONID() << " CSndBuffer: ERROR: encryption required and not possible. NOT SENDING.");
|
||||
readlen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pCurrBlock->m_iMsgNoBitset |= MSGNO_ENCKEYSPEC::wrap(kflgs);
|
||||
}
|
||||
|
||||
Block* p = m_pCurrBlock;
|
||||
w_packet.m_iMsgNo = m_pCurrBlock->m_iMsgNoBitset;
|
||||
w_srctime = m_pCurrBlock->m_tsOriginTime;
|
||||
m_pCurrBlock = m_pCurrBlock->m_pNext;
|
||||
|
||||
if ((p->m_iTTL >= 0) && (count_milliseconds(steady_clock::now() - w_srctime) > p->m_iTTL))
|
||||
{
|
||||
LOGC(bslog.Warn, log << CONID() << "CSndBuffer: skipping packet %" << p->m_iSeqNo << " #" << p->getMsgSeq() << " with TTL=" << p->m_iTTL);
|
||||
// Skip this packet due to TTL expiry.
|
||||
readlen = 0;
|
||||
++w_seqnoinc;
|
||||
continue;
|
||||
}
|
||||
|
||||
HLOGC(bslog.Debug, log << CONID() << "CSndBuffer: extracting packet size=" << readlen << " to send");
|
||||
break;
|
||||
}
|
||||
|
||||
return readlen;
|
||||
}
|
||||
|
||||
CSndBuffer::time_point CSndBuffer::peekNextOriginal() const
|
||||
{
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
if (m_pCurrBlock == m_pLastBlock)
|
||||
return time_point();
|
||||
|
||||
return m_pCurrBlock->m_tsOriginTime;
|
||||
}
|
||||
|
||||
int32_t CSndBuffer::getMsgNoAt(const int offset)
|
||||
{
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
|
||||
Block* p = m_pFirstBlock;
|
||||
|
||||
if (p)
|
||||
{
|
||||
HLOGC(bslog.Debug,
|
||||
log << "CSndBuffer::getMsgNoAt: FIRST MSG: size=" << p->m_iLength << " %" << p->m_iSeqNo << " #"
|
||||
<< p->getMsgSeq() << " !" << BufferStamp(p->m_pcData, p->m_iLength));
|
||||
}
|
||||
|
||||
if (offset >= m_iCount)
|
||||
{
|
||||
// Prevent accessing the last "marker" block
|
||||
LOGC(bslog.Error,
|
||||
log << "CSndBuffer::getMsgNoAt: IPE: offset=" << offset << " not found, max offset=" << m_iCount);
|
||||
return SRT_MSGNO_CONTROL;
|
||||
}
|
||||
|
||||
// XXX Suboptimal procedure to keep the blocks identifiable
|
||||
// by sequence number. Consider using some circular buffer.
|
||||
int i;
|
||||
Block* ee SRT_ATR_UNUSED = 0;
|
||||
for (i = 0; i < offset && p; ++i)
|
||||
{
|
||||
ee = p;
|
||||
p = p->m_pNext;
|
||||
}
|
||||
|
||||
if (!p)
|
||||
{
|
||||
LOGC(bslog.Error,
|
||||
log << "CSndBuffer::getMsgNoAt: IPE: offset=" << offset << " not found, stopped at " << i << " with #"
|
||||
<< (ee ? ee->getMsgSeq() : SRT_MSGNO_NONE));
|
||||
return SRT_MSGNO_CONTROL;
|
||||
}
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "CSndBuffer::getMsgNoAt: offset=" << offset << " found, size=" << p->m_iLength << " %" << p->m_iSeqNo
|
||||
<< " #" << p->getMsgSeq() << " !" << BufferStamp(p->m_pcData, p->m_iLength));
|
||||
|
||||
return p->getMsgSeq();
|
||||
}
|
||||
|
||||
int CSndBuffer::readData(const int offset, CPacket& w_packet, steady_clock::time_point& w_srctime, int& w_msglen)
|
||||
{
|
||||
int32_t& msgno_bitset = w_packet.m_iMsgNo;
|
||||
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
|
||||
Block* p = m_pFirstBlock;
|
||||
|
||||
// XXX Suboptimal procedure to keep the blocks identifiable
|
||||
// by sequence number. Consider using some circular buffer.
|
||||
for (int i = 0; i < offset && p != m_pLastBlock; ++i)
|
||||
{
|
||||
p = p->m_pNext;
|
||||
}
|
||||
if (p == m_pLastBlock)
|
||||
{
|
||||
LOGC(qslog.Error, log << "CSndBuffer::readData: offset " << offset << " too large!");
|
||||
return 0;
|
||||
}
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
const int32_t first_seq = p->m_iSeqNo;
|
||||
int32_t last_seq = p->m_iSeqNo;
|
||||
#endif
|
||||
|
||||
// Check if the block that is the next candidate to send (m_pCurrBlock pointing) is stale.
|
||||
|
||||
// If so, then inform the caller that it should first take care of the whole
|
||||
// message (all blocks with that message id). Shift the m_pCurrBlock pointer
|
||||
// to the position past the last of them. Then return -1 and set the
|
||||
// msgno_bitset return reference to the message id that should be dropped as
|
||||
// a whole.
|
||||
|
||||
// After taking care of that, the caller should immediately call this function again,
|
||||
// this time possibly in order to find the real data to be sent.
|
||||
|
||||
// if found block is stale
|
||||
// (This is for messages that have declared TTL - messages that fail to be sent
|
||||
// before the TTL defined time comes, will be dropped).
|
||||
|
||||
if ((p->m_iTTL >= 0) && (count_milliseconds(steady_clock::now() - p->m_tsOriginTime) > p->m_iTTL))
|
||||
{
|
||||
int32_t msgno = p->getMsgSeq();
|
||||
w_msglen = 1;
|
||||
p = p->m_pNext;
|
||||
bool move = false;
|
||||
while (p != m_pLastBlock && msgno == p->getMsgSeq())
|
||||
{
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
last_seq = p->m_iSeqNo;
|
||||
#endif
|
||||
if (p == m_pCurrBlock)
|
||||
move = true;
|
||||
p = p->m_pNext;
|
||||
if (move)
|
||||
m_pCurrBlock = p;
|
||||
w_msglen++;
|
||||
}
|
||||
|
||||
HLOGC(qslog.Debug,
|
||||
log << "CSndBuffer::readData: due to TTL exceeded, SEQ " << first_seq << " - " << last_seq << ", "
|
||||
<< w_msglen << " packets to drop, msgno=" << msgno);
|
||||
|
||||
// If readData returns -1, then msgno_bitset is understood as a Message ID to drop.
|
||||
// This means that in this case it should be written by the message sequence value only
|
||||
// (not the whole 4-byte bitset written at PH_MSGNO).
|
||||
msgno_bitset = msgno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
w_packet.m_pcData = p->m_pcData;
|
||||
const int readlen = p->m_iLength;
|
||||
w_packet.setLength(readlen, m_iBlockLen);
|
||||
|
||||
// XXX Here the value predicted to be applied to PH_MSGNO field is extracted.
|
||||
// As this function is predicted to extract the data to send as a rexmited packet,
|
||||
// the packet must be in the form ready to send - so, in case of encryption,
|
||||
// encrypted, and with all ENC flags already set. So, the first call to send
|
||||
// the packet originally (the other overload of this function) must set these
|
||||
// flags.
|
||||
w_packet.m_iMsgNo = p->m_iMsgNoBitset;
|
||||
w_srctime = p->m_tsOriginTime;
|
||||
|
||||
// This function is called when packet retransmission is triggered.
|
||||
// Therefore we are setting the rexmit time.
|
||||
p->m_tsRexmitTime = steady_clock::now();
|
||||
|
||||
HLOGC(qslog.Debug,
|
||||
log << CONID() << "CSndBuffer: getting packet %" << p->m_iSeqNo << " as per %" << w_packet.m_iSeqNo
|
||||
<< " size=" << readlen << " to send [REXMIT]");
|
||||
|
||||
return readlen;
|
||||
}
|
||||
|
||||
sync::steady_clock::time_point CSndBuffer::getPacketRexmitTime(const int offset)
|
||||
{
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
const Block* p = m_pFirstBlock;
|
||||
|
||||
// XXX Suboptimal procedure to keep the blocks identifiable
|
||||
// by sequence number. Consider using some circular buffer.
|
||||
for (int i = 0; i < offset; ++i)
|
||||
{
|
||||
SRT_ASSERT(p);
|
||||
p = p->m_pNext;
|
||||
}
|
||||
|
||||
SRT_ASSERT(p);
|
||||
return p->m_tsRexmitTime;
|
||||
}
|
||||
|
||||
void CSndBuffer::ackData(int offset)
|
||||
{
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
|
||||
bool move = false;
|
||||
for (int i = 0; i < offset; ++i)
|
||||
{
|
||||
m_iBytesCount -= m_pFirstBlock->m_iLength;
|
||||
if (m_pFirstBlock == m_pCurrBlock)
|
||||
move = true;
|
||||
m_pFirstBlock = m_pFirstBlock->m_pNext;
|
||||
}
|
||||
if (move)
|
||||
m_pCurrBlock = m_pFirstBlock;
|
||||
|
||||
m_iCount -= offset;
|
||||
|
||||
updAvgBufSize(steady_clock::now());
|
||||
}
|
||||
|
||||
int CSndBuffer::getCurrBufSize() const
|
||||
{
|
||||
return m_iCount;
|
||||
}
|
||||
|
||||
int CSndBuffer::getMaxPacketLen() const
|
||||
{
|
||||
return m_iBlockLen - m_iAuthTagSize;
|
||||
}
|
||||
|
||||
int CSndBuffer::countNumPacketsRequired(int iPldLen) const
|
||||
{
|
||||
const int iPktLen = getMaxPacketLen();
|
||||
return countNumPacketsRequired(iPldLen, iPktLen);
|
||||
}
|
||||
|
||||
int CSndBuffer::countNumPacketsRequired(int iPldLen, int iPktLen) const
|
||||
{
|
||||
return (iPldLen + iPktLen - 1) / iPktLen;
|
||||
}
|
||||
|
||||
namespace {
|
||||
int round_val(double val)
|
||||
{
|
||||
return static_cast<int>(round(val));
|
||||
}
|
||||
}
|
||||
|
||||
int CSndBuffer::getAvgBufSize(int& w_bytes, int& w_tsp)
|
||||
{
|
||||
ScopedLock bufferguard(m_BufLock); /* Consistency of pkts vs. bytes vs. spantime */
|
||||
|
||||
/* update stats in case there was no add/ack activity lately */
|
||||
updAvgBufSize(steady_clock::now());
|
||||
|
||||
// Average number of packets and timespan could be small,
|
||||
// so rounding is beneficial, while for the number of
|
||||
// bytes in the buffer is a higher value, so rounding can be omitted,
|
||||
// but probably better to round all three values.
|
||||
w_bytes = round_val(m_mavg.bytes());
|
||||
w_tsp = round_val(m_mavg.timespan_ms());
|
||||
return round_val(m_mavg.pkts());
|
||||
}
|
||||
|
||||
void CSndBuffer::updAvgBufSize(const steady_clock::time_point& now)
|
||||
{
|
||||
if (!m_mavg.isTimeToUpdate(now))
|
||||
return;
|
||||
|
||||
int bytes = 0;
|
||||
int timespan_ms = 0;
|
||||
const int pkts = getCurrBufSize((bytes), (timespan_ms));
|
||||
m_mavg.update(now, pkts, bytes, timespan_ms);
|
||||
}
|
||||
|
||||
int CSndBuffer::getCurrBufSize(int& w_bytes, int& w_timespan) const
|
||||
{
|
||||
w_bytes = m_iBytesCount;
|
||||
/*
|
||||
* Timespan can be less then 1000 us (1 ms) if few packets.
|
||||
* Also, if there is only one pkt in buffer, the time difference will be 0.
|
||||
* Therefore, always add 1 ms if not empty.
|
||||
*/
|
||||
w_timespan = 0 < m_iCount ? (int) count_milliseconds(m_tsLastOriginTime - m_pFirstBlock->m_tsOriginTime) + 1 : 0;
|
||||
|
||||
return m_iCount;
|
||||
}
|
||||
|
||||
CSndBuffer::duration CSndBuffer::getBufferingDelay(const time_point& tnow) const
|
||||
{
|
||||
ScopedLock lck(m_BufLock);
|
||||
SRT_ASSERT(m_pFirstBlock);
|
||||
if (m_iCount == 0)
|
||||
return duration(0);
|
||||
|
||||
return tnow - m_pFirstBlock->m_tsOriginTime;
|
||||
}
|
||||
|
||||
int CSndBuffer::dropLateData(int& w_bytes, int32_t& w_first_msgno, const steady_clock::time_point& too_late_time)
|
||||
{
|
||||
int dpkts = 0;
|
||||
int dbytes = 0;
|
||||
bool move = false;
|
||||
int32_t msgno = 0;
|
||||
|
||||
ScopedLock bufferguard(m_BufLock);
|
||||
for (int i = 0; i < m_iCount && m_pFirstBlock->m_tsOriginTime < too_late_time; ++i)
|
||||
{
|
||||
dpkts++;
|
||||
dbytes += m_pFirstBlock->m_iLength;
|
||||
msgno = m_pFirstBlock->getMsgSeq();
|
||||
|
||||
if (m_pFirstBlock == m_pCurrBlock)
|
||||
move = true;
|
||||
m_pFirstBlock = m_pFirstBlock->m_pNext;
|
||||
}
|
||||
|
||||
if (move)
|
||||
{
|
||||
m_pCurrBlock = m_pFirstBlock;
|
||||
}
|
||||
m_iCount -= dpkts;
|
||||
|
||||
m_iBytesCount -= dbytes;
|
||||
w_bytes = dbytes;
|
||||
|
||||
// We report the increased number towards the last ever seen
|
||||
// by the loop, as this last one is the last received. So remained
|
||||
// (even if "should remain") is the first after the last removed one.
|
||||
w_first_msgno = ++MsgNo(msgno);
|
||||
|
||||
updAvgBufSize(steady_clock::now());
|
||||
|
||||
return (dpkts);
|
||||
}
|
||||
|
||||
void CSndBuffer::increase()
|
||||
{
|
||||
int unitsize = m_pBuffer->m_iSize;
|
||||
|
||||
// new physical buffer
|
||||
Buffer* nbuf = NULL;
|
||||
try
|
||||
{
|
||||
nbuf = new Buffer;
|
||||
nbuf->m_pcData = new char[unitsize * m_iBlockLen];
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete nbuf;
|
||||
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
|
||||
}
|
||||
nbuf->m_iSize = unitsize;
|
||||
nbuf->m_pNext = NULL;
|
||||
|
||||
// insert the buffer at the end of the buffer list
|
||||
Buffer* p = m_pBuffer;
|
||||
while (p->m_pNext != NULL)
|
||||
p = p->m_pNext;
|
||||
p->m_pNext = nbuf;
|
||||
|
||||
// new packet blocks
|
||||
Block* nblk = NULL;
|
||||
try
|
||||
{
|
||||
nblk = new Block;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete nblk;
|
||||
throw CUDTException(MJ_SYSTEMRES, MN_MEMORY, 0);
|
||||
}
|
||||
Block* pb = nblk;
|
||||
for (int i = 1; i < unitsize; ++i)
|
||||
{
|
||||
pb->m_pNext = new Block;
|
||||
pb = pb->m_pNext;
|
||||
}
|
||||
|
||||
// insert the new blocks onto the existing one
|
||||
pb->m_pNext = m_pLastBlock->m_pNext;
|
||||
m_pLastBlock->m_pNext = nblk;
|
||||
|
||||
pb = nblk;
|
||||
char* pc = nbuf->m_pcData;
|
||||
for (int i = 0; i < unitsize; ++i)
|
||||
{
|
||||
pb->m_pcData = pc;
|
||||
pb = pb->m_pNext;
|
||||
pc += m_iBlockLen;
|
||||
}
|
||||
|
||||
m_iSize += unitsize;
|
||||
|
||||
HLOGC(bslog.Debug,
|
||||
log << "CSndBuffer: BUFFER FULL - adding " << (unitsize * m_iBlockLen) << " bytes spread to " << unitsize
|
||||
<< " blocks"
|
||||
<< " (total size: " << m_iSize << " bytes)");
|
||||
}
|
||||
|
||||
} // namespace srt
|
259
trunk/3rdparty/srt-1-fit/srtcore/buffer_snd.h
vendored
Normal file
259
trunk/3rdparty/srt-1-fit/srtcore/buffer_snd.h
vendored
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 05/05/2009
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_BUFFER_SND_H
|
||||
#define INC_SRT_BUFFER_SND_H
|
||||
|
||||
#include "srt.h"
|
||||
#include "packet.h"
|
||||
#include "buffer_tools.h"
|
||||
|
||||
// The notation used for "circular numbers" in comments:
|
||||
// The "cicrular numbers" are numbers that when increased up to the
|
||||
// maximum become zero, and similarly, when the zero value is decreased,
|
||||
// it turns into the maximum value minus one. This wrapping works the
|
||||
// same for adding and subtracting. Circular numbers cannot be multiplied.
|
||||
|
||||
// Operations done on these numbers are marked with additional % character:
|
||||
// a %> b : a is later than b
|
||||
// a ++% (++%a) : shift a by 1 forward
|
||||
// a +% b : shift a by b
|
||||
// a == b : equality is same as for just numbers
|
||||
|
||||
namespace srt {
|
||||
|
||||
class CSndBuffer
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
|
||||
public:
|
||||
// XXX There's currently no way to access the socket ID set for
|
||||
// whatever the buffer is currently working for. Required to find
|
||||
// some way to do this, possibly by having a "reverse pointer".
|
||||
// Currently just "unimplemented".
|
||||
std::string CONID() const { return ""; }
|
||||
|
||||
/// @brief CSndBuffer constructor.
|
||||
/// @param size initial number of blocks (each block to store one packet payload).
|
||||
/// @param maxpld maximum packet payload (including auth tag).
|
||||
/// @param authtag auth tag length in bytes (16 for GCM, 0 otherwise).
|
||||
CSndBuffer(int size = 32, int maxpld = 1500, int authtag = 0);
|
||||
~CSndBuffer();
|
||||
|
||||
public:
|
||||
/// Insert a user buffer into the sending list.
|
||||
/// For @a w_mctrl the following fields are used:
|
||||
/// INPUT:
|
||||
/// - msgttl: timeout for retransmitting the message, if lost
|
||||
/// - inorder: request to deliver the message in order of sending
|
||||
/// - srctime: local time as a base for packet's timestamp (0 if unused)
|
||||
/// - pktseq: sequence number to be stamped on the packet (-1 if unused)
|
||||
/// - msgno: message number to be stamped on the packet (-1 if unused)
|
||||
/// OUTPUT:
|
||||
/// - srctime: local time stamped on the packet (same as input, if input wasn't 0)
|
||||
/// - pktseq: sequence number to be stamped on the next packet
|
||||
/// - msgno: message number stamped on the packet
|
||||
/// @param [in] data pointer to the user data block.
|
||||
/// @param [in] len size of the block.
|
||||
/// @param [inout] w_mctrl Message control data
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
void addBuffer(const char* data, int len, SRT_MSGCTRL& w_mctrl);
|
||||
|
||||
/// Read a block of data from file and insert it into the sending list.
|
||||
/// @param [in] ifs input file stream.
|
||||
/// @param [in] len size of the block.
|
||||
/// @return actual size of data added from the file.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int addBufferFromFile(std::fstream& ifs, int len);
|
||||
|
||||
/// Find data position to pack a DATA packet from the furthest reading point.
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [in] kflags Odd|Even crypto key flag
|
||||
/// @param [out] seqnoinc the number of packets skipped due to TTL, so that seqno should be incremented.
|
||||
/// @return Actual length of data read.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(CPacket& w_packet, time_point& w_origintime, int kflgs, int& w_seqnoinc);
|
||||
|
||||
/// Peek an information on the next original data packet to send.
|
||||
/// @return origin time stamp of the next packet; epoch start time otherwise.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point peekNextOriginal() const;
|
||||
|
||||
/// Find data position to pack a DATA packet for a retransmission.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
/// @param [out] packet the packet to read.
|
||||
/// @param [out] origintime origin time stamp of the message
|
||||
/// @param [out] msglen length of the message
|
||||
/// @return Actual length of data read (return 0 if offset too large, -1 if TTL exceeded).
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int readData(const int offset, CPacket& w_packet, time_point& w_origintime, int& w_msglen);
|
||||
|
||||
/// Get the time of the last retransmission (if any) of the DATA packet.
|
||||
/// @param [in] offset offset from the last ACK point (backward sequence number difference)
|
||||
///
|
||||
/// @return Last time of the last retransmission event for the corresponding DATA packet.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
time_point getPacketRexmitTime(const int offset);
|
||||
|
||||
/// Update the ACK point and may release/unmap/return the user data according to the flag.
|
||||
/// @param [in] offset number of packets acknowledged.
|
||||
int32_t getMsgNoAt(const int offset);
|
||||
|
||||
void ackData(int offset);
|
||||
|
||||
/// Read size of data still in the sending list.
|
||||
/// @return Current size of the data in the sending list.
|
||||
int getCurrBufSize() const;
|
||||
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
int dropLateData(int& bytes, int32_t& w_first_msgno, const time_point& too_late_time);
|
||||
|
||||
void updAvgBufSize(const time_point& time);
|
||||
int getAvgBufSize(int& bytes, int& timespan);
|
||||
int getCurrBufSize(int& bytes, int& timespan) const;
|
||||
|
||||
|
||||
/// Het maximum payload length per packet.
|
||||
int getMaxPacketLen() const;
|
||||
|
||||
/// @brief Count the number of required packets to store the payload (message).
|
||||
/// @param iPldLen the length of the payload to check.
|
||||
/// @return the number of required data packets.
|
||||
int countNumPacketsRequired(int iPldLen) const;
|
||||
|
||||
/// @brief Count the number of required packets to store the payload (message).
|
||||
/// @param iPldLen the length of the payload to check.
|
||||
/// @param iMaxPktLen the maximum payload length of the packet (the value returned from getMaxPacketLen()).
|
||||
/// @return the number of required data packets.
|
||||
int countNumPacketsRequired(int iPldLen, int iMaxPktLen) const;
|
||||
|
||||
/// @brief Get the buffering delay of the oldest message in the buffer.
|
||||
/// @return the delay value.
|
||||
SRT_ATTR_EXCLUDES(m_BufLock)
|
||||
duration getBufferingDelay(const time_point& tnow) const;
|
||||
|
||||
uint64_t getInRatePeriod() const { return m_rateEstimator.getInRatePeriod(); }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_rateEstimator.getInputRate(); }
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { m_rateEstimator.resetInputRateSmpPeriod(disable); }
|
||||
|
||||
const CRateEstimator& getRateEstimator() const { return m_rateEstimator; }
|
||||
|
||||
void setRateEstimator(const CRateEstimator& other) { m_rateEstimator = other; }
|
||||
|
||||
private:
|
||||
void increase();
|
||||
|
||||
private:
|
||||
mutable sync::Mutex m_BufLock; // used to synchronize buffer operation
|
||||
|
||||
struct Block
|
||||
{
|
||||
char* m_pcData; // pointer to the data block
|
||||
int m_iLength; // payload length of the block (excluding auth tag).
|
||||
|
||||
int32_t m_iMsgNoBitset; // message number
|
||||
int32_t m_iSeqNo; // sequence number for scheduling
|
||||
time_point m_tsOriginTime; // block origin time (either provided from above or equals the time a message was submitted for sending.
|
||||
time_point m_tsRexmitTime; // packet retransmission time
|
||||
int m_iTTL; // time to live (milliseconds)
|
||||
|
||||
Block* m_pNext; // next block
|
||||
|
||||
int32_t getMsgSeq()
|
||||
{
|
||||
// NOTE: this extracts message ID with regard to REXMIT flag.
|
||||
// This is valid only for message ID that IS GENERATED in this instance,
|
||||
// not provided by the peer. This can be otherwise sent to the peer - it doesn't matter
|
||||
// for the peer that it uses LESS bits to represent the message.
|
||||
return m_iMsgNoBitset & MSGNO_SEQ::mask;
|
||||
}
|
||||
|
||||
} * m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock;
|
||||
|
||||
// m_pBlock: The head pointer
|
||||
// m_pFirstBlock: The first block
|
||||
// m_pCurrBlock: The current block
|
||||
// m_pLastBlock: The last block (if first == last, buffer is empty)
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
char* m_pcData; // buffer
|
||||
int m_iSize; // size
|
||||
Buffer* m_pNext; // next buffer
|
||||
} * m_pBuffer; // physical buffer
|
||||
|
||||
int32_t m_iNextMsgNo; // next message number
|
||||
|
||||
int m_iSize; // buffer size (number of packets)
|
||||
const int m_iBlockLen; // maximum length of a block holding packet payload and AUTH tag (excluding packet header).
|
||||
const int m_iAuthTagSize; // Authentication tag size (if GCM is enabled).
|
||||
int m_iCount; // number of used blocks
|
||||
|
||||
int m_iBytesCount; // number of payload bytes in queue
|
||||
time_point m_tsLastOriginTime;
|
||||
|
||||
AvgBufSize m_mavg;
|
||||
CRateEstimator m_rateEstimator;
|
||||
|
||||
private:
|
||||
CSndBuffer(const CSndBuffer&);
|
||||
CSndBuffer& operator=(const CSndBuffer&);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
275
trunk/3rdparty/srt-1-fit/srtcore/buffer_tools.cpp
vendored
Normal file
275
trunk/3rdparty/srt-1-fit/srtcore/buffer_tools.cpp
vendored
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 03/12/2011
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "platform_sys.h"
|
||||
#include "buffer_tools.h"
|
||||
#include "packet.h"
|
||||
#include "logger_defs.h"
|
||||
#include "utilities.h"
|
||||
|
||||
namespace srt {
|
||||
|
||||
using namespace std;
|
||||
using namespace srt_logging;
|
||||
using namespace sync;
|
||||
|
||||
// You can change this value at build config by using "ENFORCE" options.
|
||||
#if !defined(SRT_MAVG_SAMPLING_RATE)
|
||||
#define SRT_MAVG_SAMPLING_RATE 40
|
||||
#endif
|
||||
|
||||
bool AvgBufSize::isTimeToUpdate(const time_point& now) const
|
||||
{
|
||||
const int usMAvgBasePeriod = 1000000; // 1s in microseconds
|
||||
const int us2ms = 1000;
|
||||
const int msMAvgPeriod = (usMAvgBasePeriod / SRT_MAVG_SAMPLING_RATE) / us2ms;
|
||||
const uint64_t elapsed_ms = count_milliseconds(now - m_tsLastSamplingTime); // ms since last sampling
|
||||
return (elapsed_ms >= msMAvgPeriod);
|
||||
}
|
||||
|
||||
void AvgBufSize::update(const steady_clock::time_point& now, int pkts, int bytes, int timespan_ms)
|
||||
{
|
||||
const uint64_t elapsed_ms = count_milliseconds(now - m_tsLastSamplingTime); // ms since last sampling
|
||||
m_tsLastSamplingTime = now;
|
||||
const uint64_t one_second_in_ms = 1000;
|
||||
if (elapsed_ms > one_second_in_ms)
|
||||
{
|
||||
// No sampling in last 1 sec, initialize average
|
||||
m_dCountMAvg = pkts;
|
||||
m_dBytesCountMAvg = bytes;
|
||||
m_dTimespanMAvg = timespan_ms;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// weight last average value between -1 sec and last sampling time (LST)
|
||||
// and new value between last sampling time and now
|
||||
// |elapsed_ms|
|
||||
// +----------------------------------+-------+
|
||||
// -1 LST 0(now)
|
||||
//
|
||||
m_dCountMAvg = avg_iir_w<1000, double>(m_dCountMAvg, pkts, elapsed_ms);
|
||||
m_dBytesCountMAvg = avg_iir_w<1000, double>(m_dBytesCountMAvg, bytes, elapsed_ms);
|
||||
m_dTimespanMAvg = avg_iir_w<1000, double>(m_dTimespanMAvg, timespan_ms, elapsed_ms);
|
||||
}
|
||||
|
||||
CRateEstimator::CRateEstimator()
|
||||
: m_iInRatePktsCount(0)
|
||||
, m_iInRateBytesCount(0)
|
||||
, m_InRatePeriod(INPUTRATE_FAST_START_US) // 0.5 sec (fast start)
|
||||
, m_iInRateBps(INPUTRATE_INITIAL_BYTESPS)
|
||||
{}
|
||||
|
||||
void CRateEstimator::setInputRateSmpPeriod(int period)
|
||||
{
|
||||
m_InRatePeriod = (uint64_t)period; //(usec) 0=no input rate calculation
|
||||
}
|
||||
|
||||
void CRateEstimator::updateInputRate(const time_point& time, int pkts, int bytes)
|
||||
{
|
||||
// no input rate calculation
|
||||
if (m_InRatePeriod == 0)
|
||||
return;
|
||||
|
||||
if (is_zero(m_tsInRateStartTime))
|
||||
{
|
||||
m_tsInRateStartTime = time;
|
||||
return;
|
||||
}
|
||||
else if (time < m_tsInRateStartTime)
|
||||
{
|
||||
// Old packets are being submitted for estimation, e.g. during the backup link activation.
|
||||
return;
|
||||
}
|
||||
|
||||
m_iInRatePktsCount += pkts;
|
||||
m_iInRateBytesCount += bytes;
|
||||
|
||||
// Trigger early update in fast start mode
|
||||
const bool early_update = (m_InRatePeriod < INPUTRATE_RUNNING_US) && (m_iInRatePktsCount > INPUTRATE_MAX_PACKETS);
|
||||
|
||||
const uint64_t period_us = count_microseconds(time - m_tsInRateStartTime);
|
||||
if (!early_update && period_us <= m_InRatePeriod)
|
||||
return;
|
||||
|
||||
// Required Byte/sec rate (payload + headers)
|
||||
m_iInRateBytesCount += (m_iInRatePktsCount * CPacket::SRT_DATA_HDR_SIZE);
|
||||
m_iInRateBps = (int)(((int64_t)m_iInRateBytesCount * 1000000) / period_us);
|
||||
HLOGC(bslog.Debug,
|
||||
log << "updateInputRate: pkts:" << m_iInRateBytesCount << " bytes:" << m_iInRatePktsCount
|
||||
<< " rate=" << (m_iInRateBps * 8) / 1000 << "kbps interval=" << period_us);
|
||||
m_iInRatePktsCount = 0;
|
||||
m_iInRateBytesCount = 0;
|
||||
m_tsInRateStartTime = time;
|
||||
|
||||
setInputRateSmpPeriod(INPUTRATE_RUNNING_US);
|
||||
}
|
||||
|
||||
CSndRateEstimator::CSndRateEstimator(const time_point& tsNow)
|
||||
: m_tsFirstSampleTime(tsNow)
|
||||
, m_iFirstSampleIdx(0)
|
||||
, m_iCurSampleIdx(0)
|
||||
, m_iRateBps(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CSndRateEstimator::addSample(const time_point& ts, int pkts, size_t bytes)
|
||||
{
|
||||
const int iSampleDeltaIdx = (int) count_milliseconds(ts - m_tsFirstSampleTime) / SAMPLE_DURATION_MS;
|
||||
const int delta = NUM_PERIODS - iSampleDeltaIdx;
|
||||
|
||||
// TODO: -delta <= NUM_PERIODS, then just reset the state on the estimator.
|
||||
|
||||
if (iSampleDeltaIdx >= 2 * NUM_PERIODS)
|
||||
{
|
||||
// Just reset the estimator and start like if new.
|
||||
for (int i = 0; i < NUM_PERIODS; ++i)
|
||||
{
|
||||
const int idx = incSampleIdx(m_iFirstSampleIdx, i);
|
||||
m_Samples[idx].reset();
|
||||
|
||||
if (idx == m_iCurSampleIdx)
|
||||
break;
|
||||
}
|
||||
|
||||
m_iFirstSampleIdx = 0;
|
||||
m_iCurSampleIdx = 0;
|
||||
m_iRateBps = 0;
|
||||
m_tsFirstSampleTime += milliseconds_from(iSampleDeltaIdx * SAMPLE_DURATION_MS);
|
||||
}
|
||||
else if (iSampleDeltaIdx > NUM_PERIODS)
|
||||
{
|
||||
// In run-time a constant flow of samples is expected. Once all periods are filled (after 1 second of sampling),
|
||||
// the iSampleDeltaIdx should be either (NUM_PERIODS - 1),
|
||||
// or NUM_PERIODS. In the later case it means the start of a new sampling period.
|
||||
int d = delta;
|
||||
while (d < 0)
|
||||
{
|
||||
m_Samples[m_iFirstSampleIdx].reset();
|
||||
m_iFirstSampleIdx = incSampleIdx(m_iFirstSampleIdx);
|
||||
m_tsFirstSampleTime += milliseconds_from(SAMPLE_DURATION_MS);
|
||||
m_iCurSampleIdx = incSampleIdx(m_iCurSampleIdx);
|
||||
++d;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the new sample period has started.
|
||||
const int iNewDeltaIdx = (int) count_milliseconds(ts - m_tsFirstSampleTime) / SAMPLE_DURATION_MS;
|
||||
if (incSampleIdx(m_iFirstSampleIdx, iNewDeltaIdx) != m_iCurSampleIdx)
|
||||
{
|
||||
// Now there should be some periods (at most last NUM_PERIODS) ready to be summed,
|
||||
// rate estimation updated, after which all the new entry should be added.
|
||||
Sample sum;
|
||||
int iNumPeriods = 0;
|
||||
bool bMetNonEmpty = false;
|
||||
for (int i = 0; i < NUM_PERIODS; ++i)
|
||||
{
|
||||
const int idx = incSampleIdx(m_iFirstSampleIdx, i);
|
||||
const Sample& s = m_Samples[idx];
|
||||
sum += s;
|
||||
if (bMetNonEmpty || !s.empty())
|
||||
{
|
||||
++iNumPeriods;
|
||||
bMetNonEmpty = true;
|
||||
}
|
||||
|
||||
if (idx == m_iCurSampleIdx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (iNumPeriods == 0)
|
||||
{
|
||||
m_iRateBps = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iRateBps = sum.m_iBytesCount * 1000 / (iNumPeriods * SAMPLE_DURATION_MS);
|
||||
}
|
||||
|
||||
HLOGC(bslog.Note,
|
||||
log << "CSndRateEstimator: new rate estimation :" << (m_iRateBps * 8) / 1000 << " kbps. Based on "
|
||||
<< iNumPeriods << " periods, " << sum.m_iPktsCount << " packets, " << sum.m_iBytesCount << " bytes.");
|
||||
|
||||
// Shift one sampling period to start collecting the new one.
|
||||
m_iCurSampleIdx = incSampleIdx(m_iCurSampleIdx);
|
||||
m_Samples[m_iCurSampleIdx].reset();
|
||||
|
||||
// If all NUM_SAMPLES are recorded, the first position has to be shifted as well.
|
||||
if (delta <= 0)
|
||||
{
|
||||
m_iFirstSampleIdx = incSampleIdx(m_iFirstSampleIdx);
|
||||
m_tsFirstSampleTime += milliseconds_from(SAMPLE_DURATION_MS);
|
||||
}
|
||||
}
|
||||
|
||||
m_Samples[m_iCurSampleIdx].m_iBytesCount += bytes;
|
||||
m_Samples[m_iCurSampleIdx].m_iPktsCount += pkts;
|
||||
}
|
||||
|
||||
int CSndRateEstimator::getCurrentRate() const
|
||||
{
|
||||
SRT_ASSERT(m_iCurSampleIdx >= 0 && m_iCurSampleIdx < NUM_PERIODS);
|
||||
return (int) avg_iir<16, unsigned long long>(m_iRateBps, m_Samples[m_iCurSampleIdx].m_iBytesCount * 1000 / SAMPLE_DURATION_MS);
|
||||
}
|
||||
|
||||
int CSndRateEstimator::incSampleIdx(int val, int inc) const
|
||||
{
|
||||
SRT_ASSERT(inc >= 0 && inc <= NUM_PERIODS);
|
||||
val += inc;
|
||||
while (val >= NUM_PERIODS)
|
||||
val -= NUM_PERIODS;
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
201
trunk/3rdparty/srt-1-fit/srtcore/buffer_tools.h
vendored
Normal file
201
trunk/3rdparty/srt-1-fit/srtcore/buffer_tools.h
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* SRT - Secure, Reliable, Transport
|
||||
* Copyright (c) 2018 Haivision Systems Inc.
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the
|
||||
above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Illinois
|
||||
nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
written by
|
||||
Yunhong Gu, last updated 05/05/2009
|
||||
modified by
|
||||
Haivision Systems Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef INC_SRT_BUFFER_TOOLS_H
|
||||
#define INC_SRT_BUFFER_TOOLS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
/// The AvgBufSize class is used to calculate moving average of the buffer (RCV or SND)
|
||||
class AvgBufSize
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
|
||||
public:
|
||||
AvgBufSize()
|
||||
: m_dBytesCountMAvg(0.0)
|
||||
, m_dCountMAvg(0.0)
|
||||
, m_dTimespanMAvg(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool isTimeToUpdate(const time_point& now) const;
|
||||
void update(const time_point& now, int pkts, int bytes, int timespan_ms);
|
||||
|
||||
public:
|
||||
inline double pkts() const { return m_dCountMAvg; }
|
||||
inline double timespan_ms() const { return m_dTimespanMAvg; }
|
||||
inline double bytes() const { return m_dBytesCountMAvg; }
|
||||
|
||||
private:
|
||||
time_point m_tsLastSamplingTime;
|
||||
double m_dBytesCountMAvg;
|
||||
double m_dCountMAvg;
|
||||
double m_dTimespanMAvg;
|
||||
};
|
||||
|
||||
/// The class to estimate source bitrate based on samples submitted to the buffer.
|
||||
/// Is currently only used by the CSndBuffer.
|
||||
class CRateEstimator
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
typedef sync::steady_clock::duration duration;
|
||||
public:
|
||||
CRateEstimator();
|
||||
|
||||
public:
|
||||
uint64_t getInRatePeriod() const { return m_InRatePeriod; }
|
||||
|
||||
/// Retrieve input bitrate in bytes per second
|
||||
int getInputRate() const { return m_iInRateBps; }
|
||||
|
||||
void setInputRateSmpPeriod(int period);
|
||||
|
||||
/// Update input rate calculation.
|
||||
/// @param [in] time current time
|
||||
/// @param [in] pkts number of packets newly added to the buffer
|
||||
/// @param [in] bytes number of payload bytes in those newly added packets
|
||||
void updateInputRate(const time_point& time, int pkts = 0, int bytes = 0);
|
||||
|
||||
void resetInputRateSmpPeriod(bool disable = false) { setInputRateSmpPeriod(disable ? 0 : INPUTRATE_FAST_START_US); }
|
||||
|
||||
private: // Constants
|
||||
static const uint64_t INPUTRATE_FAST_START_US = 500000; // 500 ms
|
||||
static const uint64_t INPUTRATE_RUNNING_US = 1000000; // 1000 ms
|
||||
static const int64_t INPUTRATE_MAX_PACKETS = 2000; // ~ 21 Mbps of 1316 bytes payload
|
||||
static const int INPUTRATE_INITIAL_BYTESPS = BW_INFINITE;
|
||||
|
||||
private:
|
||||
int m_iInRatePktsCount; // number of payload packets added since InRateStartTime.
|
||||
int m_iInRateBytesCount; // number of payload bytes added since InRateStartTime.
|
||||
time_point m_tsInRateStartTime;
|
||||
uint64_t m_InRatePeriod; // usec
|
||||
int m_iInRateBps; // Input Rate in Bytes/sec
|
||||
};
|
||||
|
||||
|
||||
class CSndRateEstimator
|
||||
{
|
||||
typedef sync::steady_clock::time_point time_point;
|
||||
|
||||
public:
|
||||
CSndRateEstimator(const time_point& tsNow);
|
||||
|
||||
/// Add sample.
|
||||
/// @param [in] time sample (sending) time.
|
||||
/// @param [in] pkts number of packets in the sample.
|
||||
/// @param [in] bytes number of payload bytes in the sample.
|
||||
void addSample(const time_point& time, int pkts = 0, size_t bytes = 0);
|
||||
|
||||
/// Retrieve estimated bitrate in bytes per second
|
||||
int getRate() const { return m_iRateBps; }
|
||||
|
||||
/// Retrieve estimated bitrate in bytes per second inluding the current sampling interval.
|
||||
int getCurrentRate() const;
|
||||
|
||||
private:
|
||||
static const int NUM_PERIODS = 10;
|
||||
static const int SAMPLE_DURATION_MS = 100; // 100 ms
|
||||
struct Sample
|
||||
{
|
||||
int m_iPktsCount; // number of payload packets
|
||||
int m_iBytesCount; // number of payload bytes
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_iPktsCount = 0;
|
||||
m_iBytesCount = 0;
|
||||
}
|
||||
|
||||
Sample()
|
||||
: m_iPktsCount(0)
|
||||
, m_iBytesCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
Sample(int iPkts, int iBytes)
|
||||
: m_iPktsCount(iPkts)
|
||||
, m_iBytesCount(iBytes)
|
||||
{
|
||||
}
|
||||
|
||||
Sample operator+(const Sample& other)
|
||||
{
|
||||
return Sample(m_iPktsCount + other.m_iPktsCount, m_iBytesCount + other.m_iBytesCount);
|
||||
}
|
||||
|
||||
Sample& operator+=(const Sample& other)
|
||||
{
|
||||
*this = *this + other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const { return m_iPktsCount == 0; }
|
||||
};
|
||||
|
||||
int incSampleIdx(int val, int inc = 1) const;
|
||||
|
||||
Sample m_Samples[NUM_PERIODS];
|
||||
|
||||
time_point m_tsFirstSampleTime; //< Start time of the first sameple.
|
||||
int m_iFirstSampleIdx; //< Index of the first sample.
|
||||
int m_iCurSampleIdx; //< Index of the current sample being collected.
|
||||
int m_iRateBps; // Input Rate in Bytes/sec
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#endif
|
2
trunk/3rdparty/srt-1-fit/srtcore/cache.cpp
vendored
2
trunk/3rdparty/srt-1-fit/srtcore/cache.cpp
vendored
|
@ -62,7 +62,7 @@ srt::CInfoBlock& srt::CInfoBlock::copyFrom(const CInfoBlock& obj)
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool srt::CInfoBlock::operator==(const CInfoBlock& obj)
|
||||
bool srt::CInfoBlock::operator==(const CInfoBlock& obj) const
|
||||
{
|
||||
if (m_iIPversion != obj.m_iIPversion)
|
||||
return false;
|
||||
|
|
2
trunk/3rdparty/srt-1-fit/srtcore/cache.h
vendored
2
trunk/3rdparty/srt-1-fit/srtcore/cache.h
vendored
|
@ -253,7 +253,7 @@ public:
|
|||
CInfoBlock& copyFrom(const CInfoBlock& obj);
|
||||
CInfoBlock(const CInfoBlock& src) { copyFrom(src); }
|
||||
CInfoBlock& operator=(const CInfoBlock& src) { return copyFrom(src); }
|
||||
bool operator==(const CInfoBlock& obj);
|
||||
bool operator==(const CInfoBlock& obj) const;
|
||||
CInfoBlock* clone();
|
||||
int getKey();
|
||||
void release() {}
|
||||
|
|
168
trunk/3rdparty/srt-1-fit/srtcore/channel.cpp
vendored
168
trunk/3rdparty/srt-1-fit/srtcore/channel.cpp
vendored
|
@ -139,7 +139,23 @@ static int set_cloexec(int fd, int set)
|
|||
|
||||
srt::CChannel::CChannel()
|
||||
: m_iSocket(INVALID_SOCKET)
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
, m_bBindMasked(true)
|
||||
#endif
|
||||
{
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
// Do the check for ancillary data buffer size, kinda assertion
|
||||
static const size_t CMSG_MAX_SPACE = sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6);
|
||||
|
||||
if (CMSG_MAX_SPACE < CMSG_SPACE(sizeof(in_pktinfo)) + CMSG_SPACE(sizeof(in6_pktinfo)))
|
||||
{
|
||||
LOGC(kmlog.Fatal, log << "Size of CMSG_MAX_SPACE="
|
||||
<< CMSG_MAX_SPACE << " too short for cmsg "
|
||||
<< CMSG_SPACE(sizeof(in_pktinfo)) << ", "
|
||||
<< CMSG_SPACE(sizeof(in6_pktinfo)) << " - PLEASE FIX");
|
||||
throw CUDTException(MJ_SETUP, MN_NONE, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
srt::CChannel::~CChannel() {}
|
||||
|
@ -207,6 +223,9 @@ void srt::CChannel::open(const sockaddr_any& addr)
|
|||
throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);
|
||||
|
||||
m_BindAddr = addr;
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
m_bBindMasked = m_BindAddr.isany();
|
||||
#endif
|
||||
LOGC(kmlog.Debug, log << "CHANNEL: Bound to local address: " << m_BindAddr.str());
|
||||
|
||||
setUDPSockOpt();
|
||||
|
@ -247,6 +266,12 @@ void srt::CChannel::open(int family)
|
|||
}
|
||||
m_BindAddr = sockaddr_any(res->ai_addr, (sockaddr_any::len_t)res->ai_addrlen);
|
||||
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
// We know that this is intentionally bound now to "any",
|
||||
// so the requester-destination address must be remembered and passed.
|
||||
m_bBindMasked = true;
|
||||
#endif
|
||||
|
||||
::freeaddrinfo(res);
|
||||
|
||||
HLOGC(kmlog.Debug, log << "CHANNEL: Bound to local address: " << m_BindAddr.str());
|
||||
|
@ -472,6 +497,27 @@ void srt::CChannel::setUDPSockOpt()
|
|||
if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(timeval)))
|
||||
throw CUDTException(MJ_SETUP, MN_NORES, NET_ERROR);
|
||||
#endif
|
||||
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
if (m_bBindMasked)
|
||||
{
|
||||
HLOGP(kmlog.Debug, "Socket bound to ANY - setting PKTINFO for address retrieval");
|
||||
const int on = 1, off SRT_ATR_UNUSED = 0;
|
||||
|
||||
if (m_BindAddr.family() == AF_INET || m_mcfg.iIpV6Only == 0)
|
||||
{
|
||||
::setsockopt(m_iSocket, IPPROTO_IP, IP_PKTINFO, (char*)&on, sizeof(on));
|
||||
}
|
||||
|
||||
if (m_BindAddr.family() == AF_INET6)
|
||||
{
|
||||
::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
|
||||
}
|
||||
|
||||
// XXX Unknown why this has to be off. RETEST.
|
||||
//::setsockopt(m_iSocket, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void srt::CChannel::close() const
|
||||
|
@ -502,6 +548,11 @@ void srt::CChannel::setConfig(const CSrtMuxerConfig& config)
|
|||
m_mcfg = config;
|
||||
}
|
||||
|
||||
void srt::CChannel::getSocketOption(int level, int option, char* pw_dataptr, socklen_t& w_len, int& w_status)
|
||||
{
|
||||
w_status = ::getsockopt(m_iSocket, level, option, (pw_dataptr), (&w_len));
|
||||
}
|
||||
|
||||
int srt::CChannel::getIpTTL() const
|
||||
{
|
||||
if (m_iSocket == INVALID_SOCKET)
|
||||
|
@ -610,11 +661,19 @@ void srt::CChannel::getPeerAddr(sockaddr_any& w_addr) const
|
|||
w_addr.len = namelen;
|
||||
}
|
||||
|
||||
int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const
|
||||
int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet, const sockaddr_any& source_addr SRT_ATR_UNUSED) const
|
||||
{
|
||||
HLOGC(kslog.Debug,
|
||||
log << "CChannel::sendto: SENDING NOW DST=" << addr.str() << " target=@" << packet.m_iID
|
||||
<< " size=" << packet.getLength() << " pkt.ts=" << packet.m_iTimeStamp << " " << packet.Info());
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
ostringstream dsrc;
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
dsrc << " sourceIP=" << (m_bBindMasked && !source_addr.isany() ? source_addr.str() : "default");
|
||||
#endif
|
||||
|
||||
LOGC(kslog.Debug,
|
||||
log << "CChannel::sendto: SENDING NOW DST=" << addr.str() << " target=@" << packet.m_iID
|
||||
<< " size=" << packet.getLength() << " pkt.ts=" << packet.m_iTimeStamp
|
||||
<< dsrc.str() << " " << packet.Info());
|
||||
#endif
|
||||
|
||||
#ifdef SRT_TEST_FAKE_LOSS
|
||||
|
||||
|
@ -683,16 +742,51 @@ int srt::CChannel::sendto(const sockaddr_any& addr, CPacket& packet) const
|
|||
mh.msg_namelen = addr.size();
|
||||
mh.msg_iov = (iovec*)packet.m_PacketVector;
|
||||
mh.msg_iovlen = 2;
|
||||
mh.msg_control = NULL;
|
||||
mh.msg_controllen = 0;
|
||||
bool have_set_src = false;
|
||||
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
|
||||
// Note that even if PKTINFO is desired, the first caller's packet will be sent
|
||||
// without ancillary info anyway because there's no "peer" yet to know where to send it.
|
||||
if (m_bBindMasked && source_addr.family() != AF_UNSPEC && !source_addr.isany())
|
||||
{
|
||||
if (!setSourceAddress(mh, source_addr))
|
||||
{
|
||||
LOGC(kslog.Error, log << "CChannel::setSourceAddress: source address invalid family #" << source_addr.family() << ", NOT setting.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(kslog.Debug, log << "CChannel::setSourceAddress: setting as " << source_addr.str());
|
||||
have_set_src = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!have_set_src)
|
||||
{
|
||||
mh.msg_control = NULL;
|
||||
mh.msg_controllen = 0;
|
||||
}
|
||||
mh.msg_flags = 0;
|
||||
|
||||
const int res = ::sendmsg(m_iSocket, &mh, 0);
|
||||
const int res = (int)::sendmsg(m_iSocket, &mh, 0);
|
||||
#else
|
||||
DWORD size = (DWORD)(CPacket::HDR_SIZE + packet.getLength());
|
||||
int addrsize = addr.size();
|
||||
int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, NULL, NULL);
|
||||
res = (0 == res) ? size : -1;
|
||||
WSAOVERLAPPED overlapped;
|
||||
SecureZeroMemory((PVOID)&overlapped, sizeof(WSAOVERLAPPED));
|
||||
int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr.get(), addrsize, &overlapped, NULL);
|
||||
|
||||
if (res == SOCKET_ERROR && NET_ERROR == WSA_IO_PENDING)
|
||||
{
|
||||
DWORD dwFlags = 0;
|
||||
const bool bCompleted = WSAGetOverlappedResult(m_iSocket, &overlapped, &size, true, &dwFlags);
|
||||
WSACloseEvent(overlapped.hEvent);
|
||||
res = bCompleted ? 0 : -1;
|
||||
}
|
||||
|
||||
res = (0 == res) ? size : -1;
|
||||
#endif
|
||||
|
||||
packet.toHL();
|
||||
|
@ -725,18 +819,36 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet
|
|||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
msghdr mh; // will not be used on failure
|
||||
|
||||
if (select_ret > 0)
|
||||
{
|
||||
msghdr mh;
|
||||
mh.msg_name = (w_addr.get());
|
||||
mh.msg_namelen = w_addr.size();
|
||||
mh.msg_iov = (w_packet.m_PacketVector);
|
||||
mh.msg_iovlen = 2;
|
||||
|
||||
// Default
|
||||
mh.msg_control = NULL;
|
||||
mh.msg_controllen = 0;
|
||||
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
// Without m_bBindMasked, we don't need ancillary data - the source
|
||||
// address will always be the bound address.
|
||||
if (m_bBindMasked)
|
||||
{
|
||||
// Extract the destination IP address from the ancillary
|
||||
// data. This might be interesting for the connection to
|
||||
// know to which address the packet should be sent back during
|
||||
// the handshake and then addressed when sending during connection.
|
||||
mh.msg_control = (m_acCmsgRecvBuffer);
|
||||
mh.msg_controllen = sizeof m_acCmsgRecvBuffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
mh.msg_flags = 0;
|
||||
|
||||
recv_size = ::recvmsg(m_iSocket, (&mh), 0);
|
||||
recv_size = (int)::recvmsg(m_iSocket, (&mh), 0);
|
||||
msg_flags = mh.msg_flags;
|
||||
}
|
||||
|
||||
|
@ -779,6 +891,17 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet
|
|||
goto Return_error;
|
||||
}
|
||||
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
if (m_bBindMasked)
|
||||
{
|
||||
// Extract the address. Set it explicitly; if this returns address that isany(),
|
||||
// it will simply set this on the packet so that it behaves as if nothing was
|
||||
// extracted (it will "fail the old way").
|
||||
w_packet.m_DestAddr = getTargetAddress(mh);
|
||||
HLOGC(krlog.Debug, log << CONID() << "(sys)recvmsg: ANY BOUND, retrieved DEST ADDR: " << w_packet.m_DestAddr.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
// XXX REFACTORING NEEDED!
|
||||
// This procedure uses the WSARecvFrom function that just reads
|
||||
|
@ -876,9 +999,30 @@ srt::EReadStatus srt::CChannel::recvfrom(sockaddr_any& w_addr, CPacket& w_packet
|
|||
// packet was received, so the packet will be then retransmitted.
|
||||
if (msg_flags != 0)
|
||||
{
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
|
||||
std::ostringstream flg;
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
static const pair<int, const char* const> errmsgflg [] = {
|
||||
make_pair<int>(MSG_OOB, "OOB"),
|
||||
make_pair<int>(MSG_EOR, "EOR"),
|
||||
make_pair<int>(MSG_TRUNC, "TRUNC"),
|
||||
make_pair<int>(MSG_CTRUNC, "CTRUNC")
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < Size(errmsgflg); ++i)
|
||||
if ((msg_flags & errmsgflg[i].first) != 0)
|
||||
flg << " " << errmsgflg[i].second;
|
||||
|
||||
// This doesn't work the same way on Windows, so on Windows just skip it.
|
||||
#endif
|
||||
|
||||
HLOGC(krlog.Debug,
|
||||
log << CONID() << "NET ERROR: packet size=" << recv_size << " msg_flags=0x" << hex << msg_flags
|
||||
<< ", possibly MSG_TRUNC)");
|
||||
<< ", detected flags:" << flg.str());
|
||||
#endif
|
||||
status = RST_AGAIN;
|
||||
goto Return_error;
|
||||
}
|
||||
|
|
133
trunk/3rdparty/srt-1-fit/srtcore/channel.h
vendored
133
trunk/3rdparty/srt-1-fit/srtcore/channel.h
vendored
|
@ -115,9 +115,10 @@ public:
|
|||
/// Send a packet to the given address.
|
||||
/// @param [in] addr pointer to the destination address.
|
||||
/// @param [in] packet reference to a CPacket entity.
|
||||
/// @param [in] src source address to sent on an outgoing packet (if not ANY)
|
||||
/// @return Actual size of data sent.
|
||||
|
||||
int sendto(const sockaddr_any& addr, srt::CPacket& packet) const;
|
||||
int sendto(const sockaddr_any& addr, srt::CPacket& packet, const sockaddr_any& src) const;
|
||||
|
||||
/// Receive a packet from the channel and record the source address.
|
||||
/// @param [in] addr pointer to the source address.
|
||||
|
@ -128,6 +129,21 @@ public:
|
|||
|
||||
void setConfig(const CSrtMuxerConfig& config);
|
||||
|
||||
void getSocketOption(int level, int sockoptname, char* pw_dataptr, socklen_t& w_len, int& w_status);
|
||||
|
||||
template<class Type>
|
||||
Type sockopt(int level, int sockoptname, Type deflt)
|
||||
{
|
||||
Type retval;
|
||||
socklen_t socklen = sizeof retval;
|
||||
int status;
|
||||
getSocketOption(level, sockoptname, ((char*)&retval), (socklen), (status));
|
||||
if (status == -1)
|
||||
return deflt;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
|
@ -160,6 +176,121 @@ private:
|
|||
// although the object itself isn't considered modified.
|
||||
mutable CSrtMuxerConfig m_mcfg; // Note: ReuseAddr is unused and ineffective.
|
||||
sockaddr_any m_BindAddr;
|
||||
|
||||
// This feature is not enabled on Windows, for now.
|
||||
// This is also turned off in case of MinGW
|
||||
#ifdef SRT_ENABLE_PKTINFO
|
||||
bool m_bBindMasked; // True if m_BindAddr is INADDR_ANY. Need for quick check.
|
||||
|
||||
// Calculating the required space is extremely tricky, and whereas on most
|
||||
// platforms it's possible to define it this way:
|
||||
//
|
||||
// size_t s = max( CMSG_SPACE(sizeof(in_pktinfo)), CMSG_SPACE(sizeof(in6_pktinfo)) )
|
||||
//
|
||||
// ...on some platforms however CMSG_SPACE macro can't be resolved as constexpr.
|
||||
//
|
||||
// This structure is exclusively used to determine the required size for
|
||||
// CMSG buffer so that it can be allocated in a solid block with CChannel.
|
||||
// NOT TO BE USED to access any data inside the CMSG message.
|
||||
struct CMSGNodeIPv4
|
||||
{
|
||||
in_pktinfo in4;
|
||||
size_t extrafill;
|
||||
cmsghdr hdr;
|
||||
};
|
||||
|
||||
struct CMSGNodeIPv6
|
||||
{
|
||||
in6_pktinfo in6;
|
||||
size_t extrafill;
|
||||
cmsghdr hdr;
|
||||
};
|
||||
|
||||
// This is 'mutable' because it's a utility buffer defined here
|
||||
// to avoid unnecessary re-allocations.
|
||||
mutable char m_acCmsgRecvBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo
|
||||
mutable char m_acCmsgSendBuffer [sizeof (CMSGNodeIPv4) + sizeof (CMSGNodeIPv6)]; // Reserved space for ancillary data with pktinfo
|
||||
|
||||
// IMPORTANT!!! This function shall be called EXCLUSIVELY just after
|
||||
// calling ::recvmsg function. It uses a static buffer to supply data
|
||||
// for the call, and it's stated that only one thread is trying to
|
||||
// use a CChannel object in receiving mode.
|
||||
sockaddr_any getTargetAddress(const msghdr& msg) const
|
||||
{
|
||||
// Loop through IP header messages
|
||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(((msghdr*)&msg), cmsg))
|
||||
{
|
||||
// This should be safe - this packet contains always either
|
||||
// IPv4 headers or IPv6 headers.
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
in_pktinfo *dest_ip_ptr = (in_pktinfo*)CMSG_DATA(cmsg);
|
||||
return sockaddr_any(dest_ip_ptr->ipi_addr, 0);
|
||||
}
|
||||
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
|
||||
{
|
||||
in6_pktinfo* dest_ip_ptr = (in6_pktinfo*)CMSG_DATA(cmsg);
|
||||
return sockaddr_any(dest_ip_ptr->ipi6_addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for an error
|
||||
return sockaddr_any(m_BindAddr.family());
|
||||
}
|
||||
|
||||
// IMPORTANT!!! This function shall be called EXCLUSIVELY just before
|
||||
// calling ::sendmsg function. It uses a static buffer to supply data
|
||||
// for the call, and it's stated that only one thread is trying to
|
||||
// use a CChannel object in sending mode.
|
||||
bool setSourceAddress(msghdr& mh, const sockaddr_any& adr) const
|
||||
{
|
||||
// In contrast to an advice followed on the net, there's no case of putting
|
||||
// both IPv4 and IPv6 ancillary data, case we could have them. Only one
|
||||
// IP version is used and it's the version as found in @a adr, which should
|
||||
// be the version used for binding.
|
||||
|
||||
if (adr.family() == AF_INET)
|
||||
{
|
||||
mh.msg_control = m_acCmsgSendBuffer;
|
||||
mh.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
|
||||
cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
|
||||
|
||||
// after initializing msghdr & control data to CMSG_SPACE(sizeof(struct in_pktinfo))
|
||||
cmsg_send->cmsg_level = IPPROTO_IP;
|
||||
cmsg_send->cmsg_type = IP_PKTINFO;
|
||||
cmsg_send->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
in_pktinfo* pktinfo = (in_pktinfo*) CMSG_DATA(cmsg_send);
|
||||
pktinfo->ipi_ifindex = 0;
|
||||
pktinfo->ipi_spec_dst = adr.sin.sin_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (adr.family() == AF_INET6)
|
||||
{
|
||||
mh.msg_control = m_acCmsgSendBuffer;
|
||||
mh.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
|
||||
cmsghdr* cmsg_send = CMSG_FIRSTHDR(&mh);
|
||||
|
||||
cmsg_send->cmsg_level = IPPROTO_IPV6;
|
||||
cmsg_send->cmsg_type = IPV6_PKTINFO;
|
||||
cmsg_send->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
|
||||
in6_pktinfo* pktinfo = (in6_pktinfo*) CMSG_DATA(cmsg_send);
|
||||
pktinfo->ipi6_ifindex = 0;
|
||||
pktinfo->ipi6_addr = adr.sin6.sin6_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SRT_ENABLE_PKTINFO
|
||||
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
|
21
trunk/3rdparty/srt-1-fit/srtcore/common.cpp
vendored
21
trunk/3rdparty/srt-1-fit/srtcore/common.cpp
vendored
|
@ -168,11 +168,7 @@ void srt::CIPAddress::ntop(const sockaddr_any& addr, uint32_t ip[4])
|
|||
}
|
||||
else
|
||||
{
|
||||
const sockaddr_in6* a = &addr.sin6;
|
||||
ip[3] = (a->sin6_addr.s6_addr[15] << 24) + (a->sin6_addr.s6_addr[14] << 16) + (a->sin6_addr.s6_addr[13] << 8) + a->sin6_addr.s6_addr[12];
|
||||
ip[2] = (a->sin6_addr.s6_addr[11] << 24) + (a->sin6_addr.s6_addr[10] << 16) + (a->sin6_addr.s6_addr[9] << 8) + a->sin6_addr.s6_addr[8];
|
||||
ip[1] = (a->sin6_addr.s6_addr[7] << 24) + (a->sin6_addr.s6_addr[6] << 16) + (a->sin6_addr.s6_addr[5] << 8) + a->sin6_addr.s6_addr[4];
|
||||
ip[0] = (a->sin6_addr.s6_addr[3] << 24) + (a->sin6_addr.s6_addr[2] << 16) + (a->sin6_addr.s6_addr[1] << 8) + a->sin6_addr.s6_addr[0];
|
||||
std::memcpy(ip, addr.sin6.sin6_addr.s6_addr, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,18 +219,7 @@ void srt::CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const soc
|
|||
// Here both agent and peer use IPv6, in which case
|
||||
// `ip` contains the full IPv6 address, so just copy
|
||||
// it as is.
|
||||
|
||||
// XXX Possibly, a simple
|
||||
// memcpy( (a->sin6_addr.s6_addr), ip, 16);
|
||||
// would do the same thing, and faster. The address in `ip`,
|
||||
// even though coded here as uint32_t, is still big endian.
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
{
|
||||
a->sin6_addr.s6_addr[i * 4 + 0] = ip[i] & 0xFF;
|
||||
a->sin6_addr.s6_addr[i * 4 + 1] = (unsigned char)((ip[i] & 0xFF00) >> 8);
|
||||
a->sin6_addr.s6_addr[i * 4 + 2] = (unsigned char)((ip[i] & 0xFF0000) >> 16);
|
||||
a->sin6_addr.s6_addr[i * 4 + 3] = (unsigned char)((ip[i] & 0xFF000000) >> 24);
|
||||
}
|
||||
std::memcpy(a->sin6_addr.s6_addr, ip, 16);
|
||||
return; // The address is written, nothing left to do.
|
||||
}
|
||||
|
||||
|
@ -457,7 +442,7 @@ std::string TransmissionEventStr(ETransmissionEvent ev)
|
|||
return vals[ev];
|
||||
}
|
||||
|
||||
bool SrtParseConfig(string s, SrtConfig& w_config)
|
||||
bool SrtParseConfig(const string& s, SrtConfig& w_config)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
|
|
16
trunk/3rdparty/srt-1-fit/srtcore/common.h
vendored
16
trunk/3rdparty/srt-1-fit/srtcore/common.h
vendored
|
@ -53,7 +53,6 @@ modified by
|
|||
#ifndef INC_SRT_COMMON_H
|
||||
#define INC_SRT_COMMON_H
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 // silences windows complaints for sscanf
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
@ -1393,8 +1392,11 @@ inline ATR_CONSTEXPR uint32_t SrtVersion(int major, int minor, int patch)
|
|||
inline int32_t SrtParseVersion(const char* v)
|
||||
{
|
||||
int major, minor, patch;
|
||||
#if defined(_MSC_VER)
|
||||
int result = sscanf_s(v, "%d.%d.%d", &major, &minor, &patch);
|
||||
#else
|
||||
int result = sscanf(v, "%d.%d.%d", &major, &minor, &patch);
|
||||
|
||||
#endif
|
||||
if (result != 3)
|
||||
{
|
||||
return 0;
|
||||
|
@ -1409,12 +1411,16 @@ inline std::string SrtVersionString(int version)
|
|||
int minor = (version/0x100)%0x100;
|
||||
int major = version/0x10000;
|
||||
|
||||
char buf[20];
|
||||
sprintf(buf, "%d.%d.%d", major, minor, patch);
|
||||
char buf[22];
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
_snprintf(buf, sizeof(buf) - 1, "%d.%d.%d", major, minor, patch);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d", major, minor, patch);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool SrtParseConfig(std::string s, SrtConfig& w_config);
|
||||
bool SrtParseConfig(const std::string& s, SrtConfig& w_config);
|
||||
|
||||
} // namespace srt
|
||||
|
||||
|
|
2
trunk/3rdparty/srt-1-fit/srtcore/congctl.cpp
vendored
2
trunk/3rdparty/srt-1-fit/srtcore/congctl.cpp
vendored
|
@ -230,7 +230,7 @@ private:
|
|||
* For realtime Transport Stream content, pkts/sec is not a good indication of time to transmit
|
||||
* since packets are not filled to m_iMSS and packet size average is lower than (7*188)
|
||||
* for low bit rates.
|
||||
* If NAK report is lost, another cycle (RTT) is requred which is bad for low latency so we
|
||||
* If NAK report is lost, another cycle (RTT) is required which is bad for low latency so we
|
||||
* accelerate the NAK Reports frequency, at the cost of possible duplicate resend.
|
||||
* Finally, the UDT4 native minimum NAK interval (m_ullMinNakInt_tk) is 300 ms which is too high
|
||||
* (~10 i30 video frames) to maintain low latency.
|
||||
|
|
4
trunk/3rdparty/srt-1-fit/srtcore/congctl.h
vendored
4
trunk/3rdparty/srt-1-fit/srtcore/congctl.h
vendored
|
@ -52,8 +52,8 @@ public:
|
|||
|
||||
struct IsName
|
||||
{
|
||||
std::string n;
|
||||
IsName(std::string nn): n(nn) {}
|
||||
const std::string n;
|
||||
IsName(const std::string& nn): n(nn) {}
|
||||
bool operator()(NamePtr np) { return n == np.first; }
|
||||
};
|
||||
|
||||
|
|
3106
trunk/3rdparty/srt-1-fit/srtcore/core.cpp
vendored
3106
trunk/3rdparty/srt-1-fit/srtcore/core.cpp
vendored
File diff suppressed because it is too large
Load diff
153
trunk/3rdparty/srt-1-fit/srtcore/core.h
vendored
153
trunk/3rdparty/srt-1-fit/srtcore/core.h
vendored
|
@ -59,7 +59,7 @@ modified by
|
|||
#include "srt.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
#include "buffer.h"
|
||||
#include "buffer_snd.h"
|
||||
#include "buffer_rcv.h"
|
||||
#include "window.h"
|
||||
#include "packet.h"
|
||||
|
@ -288,7 +288,7 @@ public: // internal API
|
|||
{
|
||||
#if ENABLE_LOGGING
|
||||
std::ostringstream os;
|
||||
os << "@" << m_SocketID << ":";
|
||||
os << "@" << m_SocketID << ": ";
|
||||
return os.str();
|
||||
#else
|
||||
return "";
|
||||
|
@ -312,8 +312,10 @@ public: // internal API
|
|||
int32_t schedSeqNo() const { return m_iSndNextSeqNo; }
|
||||
bool overrideSndSeqNo(int32_t seq);
|
||||
|
||||
#if ENABLE_BONDING
|
||||
sync::steady_clock::time_point lastRspTime() const { return m_tsLastRspTime.load(); }
|
||||
sync::steady_clock::time_point freshActivationStart() const { return m_tsFreshActivation; }
|
||||
#endif
|
||||
|
||||
int32_t rcvSeqNo() const { return m_iRcvCurrSeqNo; }
|
||||
int flowWindowSize() const { return m_iFlowWindowSize; }
|
||||
|
@ -371,27 +373,34 @@ public: // internal API
|
|||
int minSndSize(int len = 0) const
|
||||
{
|
||||
const int ps = (int) maxPayloadSize();
|
||||
if (len == 0) // wierd, can't use non-static data member as default argument!
|
||||
if (len == 0) // weird, can't use non-static data member as default argument!
|
||||
len = ps;
|
||||
return m_config.bMessageAPI ? (len+ps-1)/ps : 1;
|
||||
}
|
||||
|
||||
int32_t makeTS(const time_point& from_time) const
|
||||
static int32_t makeTS(const time_point& from_time, const time_point& tsStartTime)
|
||||
{
|
||||
// NOTE:
|
||||
// - This calculates first the time difference towards start time.
|
||||
// - This difference value is also CUT OFF THE SEGMENT information
|
||||
// (a multiple of MAX_TIMESTAMP+1)
|
||||
// So, this can be simply defined as: TS = (RTS - STS) % (MAX_TIMESTAMP+1)
|
||||
// XXX Would be nice to check if local_time > m_tsStartTime,
|
||||
// otherwise it may go unnoticed with clock skew.
|
||||
return (int32_t) sync::count_microseconds(from_time - m_stats.tsStartTime);
|
||||
SRT_ASSERT(from_time >= tsStartTime);
|
||||
return (int32_t) sync::count_microseconds(from_time - tsStartTime);
|
||||
}
|
||||
|
||||
void setPacketTS(CPacket& p, const time_point& local_time)
|
||||
{
|
||||
p.m_iTimeStamp = makeTS(local_time);
|
||||
}
|
||||
/// @brief Set the timestamp field of the packet using the provided value (no check)
|
||||
/// @param p the packet structure to set the timestamp on.
|
||||
/// @param ts timestamp to use as a source for packet timestamp.
|
||||
SRT_ATTR_EXCLUDES(m_StatsLock)
|
||||
void setPacketTS(CPacket& p, const time_point& ts);
|
||||
|
||||
/// @brief Set the timestamp field of the packet according the TSBPD mode.
|
||||
/// Also checks the connection start time (m_tsStartTime).
|
||||
/// @param p the packet structure to set the timestamp on.
|
||||
/// @param ts timestamp to use as a source for packet timestamp. Ignored if m_bPeerTsbPd is false.
|
||||
SRT_ATTR_EXCLUDES(m_StatsLock)
|
||||
void setDataPacketTS(CPacket& p, const time_point& ts);
|
||||
|
||||
// Utility used for closing a listening socket
|
||||
// immediately to free the socket
|
||||
|
@ -416,11 +425,7 @@ public: // internal API
|
|||
|
||||
SRTU_PROPERTY_RO(SRTSOCKET, id, m_SocketID);
|
||||
SRTU_PROPERTY_RO(bool, isClosing, m_bClosing);
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
SRTU_PROPERTY_RO(srt::CRcvBufferNew*, rcvBuffer, m_pRcvBuffer);
|
||||
#else
|
||||
SRTU_PROPERTY_RO(CRcvBuffer*, rcvBuffer, m_pRcvBuffer);
|
||||
#endif
|
||||
SRTU_PROPERTY_RO(srt::CRcvBuffer*, rcvBuffer, m_pRcvBuffer);
|
||||
SRTU_PROPERTY_RO(bool, isTLPktDrop, m_bTLPktDrop);
|
||||
SRTU_PROPERTY_RO(bool, isSynReceiving, m_config.bSynRecving);
|
||||
SRTU_PROPERTY_RR(sync::Condition*, recvDataCond, &m_RecvDataCond);
|
||||
|
@ -441,16 +446,13 @@ public: // internal API
|
|||
|
||||
private:
|
||||
/// initialize a UDT entity and bind to a local address.
|
||||
|
||||
void open();
|
||||
|
||||
/// Start listening to any connection request.
|
||||
|
||||
void setListenState();
|
||||
|
||||
/// Connect to a UDT entity listening at address "peer".
|
||||
/// @param peer [in] The address of the listening UDT entity.
|
||||
|
||||
void startConnect(const sockaddr_any& peer, int32_t forced_isn);
|
||||
|
||||
/// Process the response handshake packet. Failure reasons can be:
|
||||
|
@ -461,7 +463,6 @@ private:
|
|||
/// @retval 0 Connection successful
|
||||
/// @retval 1 Connection in progress (m_ConnReq turned into RESPONSE)
|
||||
/// @retval -1 Connection failed
|
||||
|
||||
SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock)
|
||||
EConnectStatus processConnectResponse(const CPacket& pkt, CUDTException* eout) ATR_NOEXCEPT;
|
||||
|
||||
|
@ -484,15 +485,20 @@ private:
|
|||
/// @param rst Current read status to know if the HS packet was freshly received from the peer, or this is only a periodic update (RST_AGAIN)
|
||||
SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock)
|
||||
EConnectStatus processRendezvous(const CPacket* response, const sockaddr_any& serv_addr, EReadStatus, CPacket& reqpkt);
|
||||
void sendRendezvousRejection(const sockaddr_any& serv_addr, CPacket& request);
|
||||
|
||||
/// Create the CryptoControl object based on the HS packet. Allocates sender and receiver buffers and loss lists.
|
||||
/// Create the CryptoControl object based on the HS packet.
|
||||
SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock)
|
||||
bool prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException *eout);
|
||||
bool prepareConnectionObjects(const CHandShake &hs, HandshakeSide hsd, CUDTException* eout);
|
||||
|
||||
/// Allocates sender and receiver buffers and loss lists.
|
||||
SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock)
|
||||
bool prepareBuffers(CUDTException* eout);
|
||||
|
||||
SRT_ATR_NODISCARD SRT_ATTR_REQUIRES(m_ConnectionLock)
|
||||
EConnectStatus postConnect(const CPacket* response, bool rendezvous, CUDTException* eout) ATR_NOEXCEPT;
|
||||
|
||||
SRT_ATR_NODISCARD bool applyResponseSettings() ATR_NOEXCEPT;
|
||||
SRT_ATR_NODISCARD bool applyResponseSettings(const CPacket* hspkt /*[[nullable]]*/) ATR_NOEXCEPT;
|
||||
SRT_ATR_NODISCARD EConnectStatus processAsyncConnectResponse(const CPacket& pkt) ATR_NOEXCEPT;
|
||||
SRT_ATR_NODISCARD bool processAsyncConnectRequest(EReadStatus rst, EConnectStatus cst, const CPacket* response, const sockaddr_any& serv_addr);
|
||||
SRT_ATR_NODISCARD EConnectStatus craftKmResponse(uint32_t* aw_kmdata, size_t& w_kmdatasize);
|
||||
|
@ -662,8 +668,14 @@ private:
|
|||
/// the receiver fresh loss list.
|
||||
void unlose(const CPacket& oldpacket);
|
||||
void dropFromLossLists(int32_t from, int32_t to);
|
||||
bool getFirstNoncontSequence(int32_t& w_seq, std::string& w_log_reason);
|
||||
|
||||
SRT_ATTR_EXCLUDES(m_ConnectionLock)
|
||||
void checkSndTimers();
|
||||
|
||||
/// @brief Check and perform KM refresh if needed.
|
||||
void checkSndKMRefresh();
|
||||
|
||||
void checkSndTimers(Whether2RegenKm regen = DONT_REGEN_KM);
|
||||
void handshakeDone()
|
||||
{
|
||||
m_iSndHsRetryCnt = 0;
|
||||
|
@ -708,18 +720,17 @@ private:
|
|||
SRT_ATTR_EXCLUDES(m_RcvBufferLock)
|
||||
bool isRcvBufferReady() const;
|
||||
|
||||
SRT_ATTR_REQUIRES(m_RcvBufferLock)
|
||||
bool isRcvBufferReadyNoLock() const;
|
||||
|
||||
// TSBPD thread main function.
|
||||
static void* tsbpd(void* param);
|
||||
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
/// Drop too late packets (receiver side). Updaet loss lists and ACK positions.
|
||||
/// Drop too late packets (receiver side). Update loss lists and ACK positions.
|
||||
/// The @a seqno packet itself is not dropped.
|
||||
/// @param seqno [in] The sequence number of the first packets following those to be dropped.
|
||||
/// @return The number of packets dropped.
|
||||
int rcvDropTooLateUpTo(int seqno);
|
||||
#endif
|
||||
|
||||
void updateForgotten(int seqlen, int32_t lastack, int32_t skiptoseqno);
|
||||
|
||||
static loss_seqs_t defaultPacketArrival(void* vself, CPacket& pkt);
|
||||
static loss_seqs_t groupPacketArrival(void* vself, CPacket& pkt);
|
||||
|
@ -811,6 +822,9 @@ private: // Sending related data
|
|||
CSndBuffer* m_pSndBuffer; // Sender buffer
|
||||
CSndLossList* m_pSndLossList; // Sender loss list
|
||||
CPktTimeWindow<16, 16> m_SndTimeWindow; // Packet sending time window
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
CSndRateEstimator m_SndRexmitRate; // Retransmission rate estimation.
|
||||
#endif
|
||||
|
||||
atomic_duration m_tdSendInterval; // Inter-packet time, in CPU clock cycles
|
||||
|
||||
|
@ -826,6 +840,7 @@ private: // Timers
|
|||
|
||||
duration m_tdACKInterval; // ACK interval
|
||||
duration m_tdNAKInterval; // NAK interval
|
||||
|
||||
SRT_ATTR_GUARDED_BY(m_RecvAckLock)
|
||||
atomic_time_point m_tsLastRspTime; // Timestamp of last response from the peer
|
||||
time_point m_tsLastRspAckTime; // (SND) Timestamp of last ACK from the peer
|
||||
|
@ -851,7 +866,7 @@ private: // Timers
|
|||
// and this is the sequence number that refers to the block at position [0]. Upon acknowledgement,
|
||||
// this value is shifted to the acknowledged position, and the blocks are removed from the
|
||||
// m_pSndBuffer buffer up to excluding this sequence number.
|
||||
// XXX CONSIDER removing this field and give up the maintenance of this sequence number
|
||||
// XXX CONSIDER removing this field and giving up the maintenance of this sequence number
|
||||
// to the sending buffer. This way, extraction of an old packet for retransmission should
|
||||
// require only the lost sequence number, and how to find the packet with this sequence
|
||||
// will be up to the sending buffer.
|
||||
|
@ -894,14 +909,22 @@ private: // Timers
|
|||
SRT_ATTR_GUARDED_BY(m_RecvAckLock)
|
||||
int32_t m_iReXmitCount; // Re-Transmit Count since last ACK
|
||||
|
||||
time_point m_tsLogSlowDown; // The last time a log message from the "slow down" group was shown.
|
||||
// The "slow down" group of logs are those that can be printed too often otherwise, but can't be turned off (warnings and errors).
|
||||
// Currently only used by decryption failure message, therefore no mutex protection needed.
|
||||
|
||||
/// @brief Check if a frequent log can be shown.
|
||||
/// @param tnow current time
|
||||
/// @return true if it is ok to print a frequent log message.
|
||||
bool frequentLogAllowed(const time_point& tnow) const;
|
||||
|
||||
private: // Receiving related data
|
||||
#if ENABLE_NEW_RCVBUFFER
|
||||
CRcvBufferNew* m_pRcvBuffer; //< Receiver buffer
|
||||
#else
|
||||
CRcvBuffer* m_pRcvBuffer; //< Receiver buffer
|
||||
#endif
|
||||
SRT_ATTR_GUARDED_BY(m_RcvLossLock)
|
||||
CRcvLossList* m_pRcvLossList; //< Receiver loss list
|
||||
SRT_ATTR_GUARDED_BY(m_RcvLossLock)
|
||||
std::deque<CRcvFreshLoss> m_FreshLoss; //< Lost sequence already added to m_pRcvLossList, but not yet sent UMSG_LOSSREPORT for.
|
||||
|
||||
int m_iReorderTolerance; //< Current value of dynamic reorder tolerance
|
||||
int m_iConsecEarlyDelivery; //< Increases with every OOO packet that came <TTL-2 time, resets with every increased reorder tolerance
|
||||
int m_iConsecOrderedDelivery; //< Increases with every packet coming in order or retransmitted, resets with every out-of-order packet
|
||||
|
@ -913,12 +936,11 @@ private: // Receiving related data
|
|||
#ifdef ENABLE_LOGGING
|
||||
int32_t m_iDebugPrevLastAck;
|
||||
#endif
|
||||
int32_t m_iRcvLastSkipAck; // Last dropped sequence ACK
|
||||
int32_t m_iRcvLastAckAck; // (RCV) Latest packet seqno in a sent ACK acknowledged by ACKACK. RcvQTh (sendCtrlAck {r}, processCtrlAckAck {r}, processCtrlAck {r}, connection {w}).
|
||||
int32_t m_iAckSeqNo; // Last ACK sequence number
|
||||
sync::atomic<int32_t> m_iRcvCurrSeqNo; // (RCV) Largest received sequence number. RcvQTh, TSBPDTh.
|
||||
int32_t m_iRcvCurrPhySeqNo; // Same as m_iRcvCurrSeqNo, but physical only (disregarding a filter)
|
||||
|
||||
bool m_bBufferWasFull; // Indicate that RX buffer was full last time a ack was sent
|
||||
int32_t m_iPeerISN; // Initial Sequence Number of the peer side
|
||||
|
||||
uint32_t m_uPeerSrtVersion;
|
||||
|
@ -959,7 +981,7 @@ private: // synchronization: mutexes and conditions
|
|||
|
||||
mutable sync::Mutex m_RcvBufferLock; // Protects the state of the m_pRcvBuffer
|
||||
// Protects access to m_iSndCurrSeqNo, m_iSndLastAck
|
||||
sync::Mutex m_RecvAckLock; // Protects the state changes while processing incomming ACK (SRT_EPOLL_OUT)
|
||||
sync::Mutex m_RecvAckLock; // Protects the state changes while processing incoming ACK (SRT_EPOLL_OUT)
|
||||
|
||||
sync::Condition m_RecvDataCond; // used to block "srt_recv*" when there is no data. Use together with m_RecvLock
|
||||
sync::Mutex m_RecvLock; // used to synchronize "srt_recv*" call, protects TSBPD drift updates (CRcvBuffer::isRcvDataReady())
|
||||
|
@ -1036,32 +1058,50 @@ private: // Generation and processing of packets
|
|||
void updateSndLossListOnACK(int32_t ackdata_seqno);
|
||||
|
||||
/// Pack a packet from a list of lost packets.
|
||||
///
|
||||
/// @param packet [in, out] a packet structure to fill
|
||||
/// @param origintime [in, out] origin timestamp of the packet
|
||||
///
|
||||
/// @return payload size on success, <=0 on failure
|
||||
int packLostData(CPacket &packet, time_point &origintime);
|
||||
int packLostData(CPacket &packet);
|
||||
|
||||
/// Pack a unique data packet (never sent so far) in CPacket for sending.
|
||||
///
|
||||
/// @param packet [in, out] a CPacket structure to fill.
|
||||
/// @param origintime [in, out] origin timestamp of the packet.
|
||||
///
|
||||
/// @return true if a packet has been packets; false otherwise.
|
||||
bool packUniqueData(CPacket& packet, time_point& origintime);
|
||||
bool packUniqueData(CPacket& packet);
|
||||
|
||||
/// Pack in CPacket the next data to be send.
|
||||
///
|
||||
/// @param packet [in, out] a CPacket structure to fill
|
||||
/// @param packet [out] a CPacket structure to fill
|
||||
/// @param nexttime [out] Time when this socket should be next time picked up for processing.
|
||||
/// @param src_addr [out] Source address to pass to channel's sendto
|
||||
///
|
||||
/// @return A pair of values is returned (is_payload_valid, timestamp).
|
||||
/// If is_payload_valid is false, there was nothing packed for sending,
|
||||
/// and the timestamp value should be ignored.
|
||||
/// The timestamp is the full source/origin timestamp of the data.
|
||||
std::pair<bool, time_point> packData(CPacket& packet);
|
||||
/// @retval true A packet was extracted for sending, the socket should be rechecked at @a nexttime
|
||||
/// @retval false Nothing was extracted for sending, @a nexttime should be ignored
|
||||
bool packData(CPacket& packet, time_point& nexttime, sockaddr_any& src_addr);
|
||||
|
||||
int processData(CUnit* unit);
|
||||
|
||||
/// This function passes the incoming packet to the initial processing
|
||||
/// (like packet filter) and is about to store it effectively to the
|
||||
/// receiver buffer and do some postprocessing (decryption) if necessary
|
||||
/// and report the status thereof.
|
||||
///
|
||||
/// @param incoming [in] The packet coming from the network medium
|
||||
/// @param w_new_inserted [out] Set false, if the packet already exists, otherwise true (packet added)
|
||||
/// @param w_was_sent_in_order [out] Set false, if the packet was belated, but had no R flag set.
|
||||
/// @param w_srt_loss_seqs [out] Gets inserted a loss, if this function has detected it.
|
||||
///
|
||||
/// @return 0 The call was successful (regardless if the packet was accepted or not).
|
||||
/// @return -1 The call has failed: no space left in the buffer.
|
||||
/// @return -2 The incoming packet exceeds the expected sequence by more than a length of the buffer (irrepairable discrepancy).
|
||||
int handleSocketPacketReception(const std::vector<CUnit*>& incoming, bool& w_new_inserted, bool& w_was_sent_in_order, CUDT::loss_seqs_t& w_srt_loss_seqs);
|
||||
|
||||
/// Get the packet's TSBPD time.
|
||||
/// The @a grp passed by void* is not used yet
|
||||
/// and shall not be used when ENABLE_BONDING=0.
|
||||
time_point getPktTsbPdTime(void* grp, const CPacket& packet);
|
||||
|
||||
/// Checks and spawns the TSBPD thread if required.
|
||||
int checkLazySpawnTsbPdThread();
|
||||
void processClose();
|
||||
|
||||
/// Process the request after receiving the handshake from caller.
|
||||
|
@ -1075,12 +1115,7 @@ private: // Generation and processing of packets
|
|||
static void addLossRecord(std::vector<int32_t>& lossrecord, int32_t lo, int32_t hi);
|
||||
int32_t bake(const sockaddr_any& addr, int32_t previous_cookie = 0, int correction = 0);
|
||||
|
||||
/// @brief Acknowledge reading position up to the @p seq.
|
||||
/// Updates m_iRcvLastAck and m_iRcvLastSkipAck to @p seq.
|
||||
/// @param seq first unacknowledged packet sequence number.
|
||||
void ackDataUpTo(int32_t seq);
|
||||
|
||||
#if ENABLE_BONDING && ENABLE_NEW_RCVBUFFER
|
||||
#if ENABLE_BONDING
|
||||
/// @brief Drop packets in the recv buffer behind group_recv_base.
|
||||
/// Updates m_iRcvLastSkipAck if it's behind group_recv_base.
|
||||
void dropToGroupRecvBase();
|
||||
|
@ -1088,9 +1123,6 @@ private: // Generation and processing of packets
|
|||
|
||||
void processKeepalive(const CPacket& ctrlpkt, const time_point& tsArrival);
|
||||
|
||||
/// Locks m_RcvBufferLock and retrieves the available size of the receiver buffer.
|
||||
SRT_ATTR_EXCLUDES(m_RcvBufferLock)
|
||||
size_t getAvailRcvBufferSizeLock() const;
|
||||
|
||||
/// Retrieves the available size of the receiver buffer.
|
||||
/// Expects that m_RcvBufferLock is locked.
|
||||
|
@ -1120,9 +1152,11 @@ public:
|
|||
static const int PACKETPAIR_MASK = 0xF;
|
||||
|
||||
private: // Timers functions
|
||||
#if ENABLE_BONDING
|
||||
time_point m_tsFreshActivation; // GROUPS: time of fresh activation of the link, or 0 if past the activation phase or idle
|
||||
time_point m_tsUnstableSince; // GROUPS: time since unexpected ACK delay experienced, or 0 if link seems healthy
|
||||
time_point m_tsWarySince; // GROUPS: time since an unstable link has first some response
|
||||
#endif
|
||||
|
||||
static const int BECAUSE_NO_REASON = 0, // NO BITS
|
||||
BECAUSE_ACK = 1 << 0,
|
||||
|
@ -1142,6 +1176,7 @@ private: // for UDP multiplexer
|
|||
CSndQueue* m_pSndQueue; // packet sending queue
|
||||
CRcvQueue* m_pRcvQueue; // packet receiving queue
|
||||
sockaddr_any m_PeerAddr; // peer address
|
||||
sockaddr_any m_SourceAddr; // override UDP source address with this one when sending
|
||||
uint32_t m_piSelfIP[4]; // local UDP IP address
|
||||
CSNode* m_pSNode; // node information for UDT list used in snd queue
|
||||
CRNode* m_pRNode; // node information for UDT list used in rcv queue
|
||||
|
|
110
trunk/3rdparty/srt-1-fit/srtcore/crypto.cpp
vendored
110
trunk/3rdparty/srt-1-fit/srtcore/crypto.cpp
vendored
|
@ -57,11 +57,18 @@ std::string KmStateStr(SRT_KM_STATE state)
|
|||
TAKE(SECURING);
|
||||
TAKE(NOSECRET);
|
||||
TAKE(BADSECRET);
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
TAKE(BADCRYPTOMODE);
|
||||
#endif
|
||||
#undef TAKE
|
||||
default:
|
||||
{
|
||||
char buf[256];
|
||||
sprintf(buf, "??? (%d)", state);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
_snprintf(buf, sizeof(buf) - 1, "??? (%d)", state);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "??? (%d)", state);
|
||||
#endif
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +86,15 @@ void srt::CCryptoControl::globalInit()
|
|||
#endif
|
||||
}
|
||||
|
||||
bool srt::CCryptoControl::isAESGCMSupported()
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
return HaiCrypt_IsAESGCM_Supported() != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
std::string srt::CCryptoControl::FormatKmMessage(std::string hdr, int cmd, size_t srtlen)
|
||||
{
|
||||
|
@ -112,7 +128,7 @@ void srt::CCryptoControl::createFakeSndContext()
|
|||
if (!m_iSndKmKeyLen)
|
||||
m_iSndKmKeyLen = 16;
|
||||
|
||||
if (!createCryptoCtx(m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, (m_hSndCrypto)))
|
||||
if (!createCryptoCtx((m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, false))
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "Error: Can't create fake crypto context for sending - sending will return ERROR!");
|
||||
m_hSndCrypto = 0;
|
||||
|
@ -139,7 +155,7 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
|
|||
// what has called this function. The HSv5 handshake only enforces bidirectional
|
||||
// connection.
|
||||
|
||||
bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;
|
||||
const bool bidirectional = hsv > CUDT::HS_VERSION_UDT4;
|
||||
|
||||
// Local macro to return rejection appropriately.
|
||||
// CHANGED. The first version made HSv5 reject the connection.
|
||||
|
@ -152,6 +168,10 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
|
|||
bool wasb4 SRT_ATR_UNUSED = false;
|
||||
size_t sek_len = 0;
|
||||
|
||||
const bool bUseGCM =
|
||||
(m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO && kmdata[HCRYPT_MSG_KM_OFS_CIPHER] == HCRYPT_CIPHER_AES_GCM) ||
|
||||
(m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM);
|
||||
|
||||
// What we have to do:
|
||||
// If encryption is on (we know that by having m_KmSecret nonempty), create
|
||||
// the crypto context (if bidirectional, create for both sending and receiving).
|
||||
|
@ -199,13 +219,16 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
|
|||
}
|
||||
wasb4 = m_hRcvCrypto;
|
||||
|
||||
if (!createCryptoCtx(m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, (m_hRcvCrypto)))
|
||||
if (!createCryptoCtx((m_hRcvCrypto), m_iRcvKmKeyLen, HAICRYPT_CRYPTO_DIR_RX, bUseGCM))
|
||||
{
|
||||
LOGC(cnlog.Error, log << "processSrtMsg_KMREQ: Can't create RCV CRYPTO CTX - must reject...");
|
||||
m_RcvKmState = SRT_KM_S_NOSECRET;
|
||||
KMREQ_RESULT_REJECTION();
|
||||
}
|
||||
|
||||
// Deduce resulting mode.
|
||||
m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;
|
||||
|
||||
if (!wasb4)
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "processSrtMsg_KMREQ: created RX ENC with KeyLen=" << m_iRcvKmKeyLen);
|
||||
|
@ -230,6 +253,15 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
|
|||
w_srtlen = 1;
|
||||
LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure - BADSECRET");
|
||||
break;
|
||||
case HAICRYPT_ERROR_CIPHER:
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
m_RcvKmState = m_SndKmState = SRT_KM_S_BADCRYPTOMODE;
|
||||
#else
|
||||
m_RcvKmState = m_SndKmState = SRT_KM_S_BADSECRET; // Use "bad secret" as a fallback.
|
||||
#endif
|
||||
w_srtlen = 1;
|
||||
LOGC(cnlog.Warn, log << "KMREQ/rcv: (snd) Rx process failure - BADCRYPTOMODE");
|
||||
break;
|
||||
case HAICRYPT_ERROR: //Other errors
|
||||
default:
|
||||
m_RcvKmState = m_SndKmState = SRT_KM_S_NOSECRET;
|
||||
|
@ -244,7 +276,6 @@ int srt::CCryptoControl::processSrtMsg_KMREQ(
|
|||
// until the next KMREQ is received as a key regeneration.
|
||||
m_bErrorReported = false;
|
||||
|
||||
|
||||
if (w_srtlen == 1)
|
||||
goto HSv4_ErrorReport;
|
||||
|
||||
|
@ -379,6 +410,14 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len
|
|||
m_SndKmState = SRT_KM_S_UNSECURED;
|
||||
retstatus = 0;
|
||||
break;
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
case SRT_KM_S_BADCRYPTOMODE:
|
||||
// The peer expects to use a different cryptographic mode (e.g. AES-GCM, not AES-CTR).
|
||||
m_RcvKmState = SRT_KM_S_BADCRYPTOMODE;
|
||||
m_SndKmState = SRT_KM_S_BADCRYPTOMODE;
|
||||
retstatus = -1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
LOGC(cnlog.Fatal, log << "processSrtMsg_KMRSP: IPE: unknown peer error state: "
|
||||
|
@ -427,8 +466,9 @@ int srt::CCryptoControl::processSrtMsg_KMRSP(const uint32_t* srtdata, size_t len
|
|||
return retstatus;
|
||||
}
|
||||
|
||||
void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SRT_ATR_UNUSED, Whether2RegenKm regen SRT_ATR_UNUSED)
|
||||
void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SRT_ATR_UNUSED)
|
||||
{
|
||||
sync::ScopedLock lck(m_mtxLock);
|
||||
if (!m_hSndCrypto || m_SndKmState == SRT_KM_S_UNSECURED)
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "sendKeysToPeer: NOT sending/regenerating keys: "
|
||||
|
@ -461,21 +501,13 @@ void srt::CCryptoControl::sendKeysToPeer(CUDT* sock SRT_ATR_UNUSED, int iSRTT SR
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (regen)
|
||||
{
|
||||
regenCryptoKm(
|
||||
sock, // send UMSG_EXT + SRT_CMD_KMREQ to the peer using this socket
|
||||
false // Do not apply the regenerated key to the to the receiver context
|
||||
); // regenerate and send
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
void srt::CCryptoControl::regenCryptoKm(CUDT* sock, bool bidirectional)
|
||||
void srt::CCryptoControl::regenCryptoKm(CUDT* sock SRT_ATR_UNUSED, bool bidirectional SRT_ATR_UNUSED)
|
||||
{
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
sync::ScopedLock lck(m_mtxLock);
|
||||
if (!m_hSndCrypto)
|
||||
return;
|
||||
|
||||
|
@ -549,8 +581,8 @@ void srt::CCryptoControl::regenCryptoKm(CUDT* sock, bool bidirectional)
|
|||
|
||||
if (sent)
|
||||
m_SndKmLastTime = srt::sync::steady_clock::now();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
|
||||
: m_SocketID(id)
|
||||
|
@ -560,9 +592,9 @@ srt::CCryptoControl::CCryptoControl(SRTSOCKET id)
|
|||
, m_RcvKmState(SRT_KM_S_UNSECURED)
|
||||
, m_KmRefreshRatePkt(0)
|
||||
, m_KmPreAnnouncePkt(0)
|
||||
, m_iCryptoMode(CSrtConfig::CIPHER_MODE_AUTO)
|
||||
, m_bErrorReported(false)
|
||||
{
|
||||
|
||||
m_KmSecret.len = 0;
|
||||
//send
|
||||
m_SndKmMsg[0].MsgLen = 0;
|
||||
|
@ -587,6 +619,19 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
|
|||
|
||||
// Set UNSECURED state as default
|
||||
m_RcvKmState = SRT_KM_S_UNSECURED;
|
||||
m_iCryptoMode = cfg.iCryptoMode;
|
||||
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
if (!cfg.bTSBPD && m_iCryptoMode == CSrtConfig::CIPHER_MODE_AUTO)
|
||||
m_iCryptoMode = CSrtConfig::CIPHER_MODE_AES_CTR;
|
||||
const bool bUseGCM = m_iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM;
|
||||
|
||||
if (bUseGCM && !isAESGCMSupported())
|
||||
{
|
||||
LOGC(cnlog.Warn, log << "CCryptoControl: AES GCM is not supported by the crypto service provider.");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set security-pending state, if a password was set.
|
||||
m_SndKmState = hasPassphrase() ? SRT_KM_S_SECURING : SRT_KM_S_UNSECURED;
|
||||
|
@ -594,7 +639,7 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
|
|||
m_KmPreAnnouncePkt = cfg.uKmPreAnnouncePkt;
|
||||
m_KmRefreshRatePkt = cfg.uKmRefreshRatePkt;
|
||||
|
||||
if ( side == HSD_INITIATOR )
|
||||
if (side == HSD_INITIATOR)
|
||||
{
|
||||
if (hasPassphrase())
|
||||
{
|
||||
|
@ -605,13 +650,13 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
|
|||
m_iSndKmKeyLen = 16;
|
||||
}
|
||||
|
||||
bool ok = createCryptoCtx(m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, (m_hSndCrypto));
|
||||
bool ok = createCryptoCtx((m_hSndCrypto), m_iSndKmKeyLen, HAICRYPT_CRYPTO_DIR_TX, bUseGCM);
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating SND crypto context: " << ok);
|
||||
|
||||
if (ok && bidirectional)
|
||||
{
|
||||
m_iRcvKmKeyLen = m_iSndKmKeyLen;
|
||||
int st = HaiCrypt_Clone(m_hSndCrypto, HAICRYPT_CRYPTO_DIR_RX, &m_hRcvCrypto);
|
||||
const int st = HaiCrypt_Clone(m_hSndCrypto, HAICRYPT_CRYPTO_DIR_RX, &m_hRcvCrypto);
|
||||
HLOGC(cnlog.Debug, log << "CCryptoControl::init: creating CLONED RCV crypto context: status=" << st);
|
||||
ok = st == 0;
|
||||
}
|
||||
|
@ -630,12 +675,14 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
|
|||
NULL, // Do not send the key (the KM msg will be attached to the HSv5 handshake)
|
||||
bidirectional // replicate the key to the receiver context, if bidirectional
|
||||
);
|
||||
|
||||
m_iCryptoMode = bUseGCM ? CSrtConfig::CIPHER_MODE_AES_GCM : CSrtConfig::CIPHER_MODE_AES_CTR;
|
||||
#else
|
||||
// This error would be a consequence of setting the passphrase, while encryption
|
||||
// is turned off at compile time. Setting the password itself should be not allowed
|
||||
// so this could only happen as a consequence of an IPE.
|
||||
LOGC(cnlog.Error, log << "CCryptoControl::init: IPE: encryption not supported");
|
||||
return true;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -654,6 +701,7 @@ bool srt::CCryptoControl::init(HandshakeSide side, const CSrtConfig& cfg, bool b
|
|||
void srt::CCryptoControl::close()
|
||||
{
|
||||
/* Wipeout secrets */
|
||||
sync::ScopedLock lck(m_mtxLock);
|
||||
memset(&m_KmSecret, 0, sizeof(m_KmSecret));
|
||||
}
|
||||
|
||||
|
@ -691,9 +739,8 @@ static std::string CryptoFlags(int flg)
|
|||
} // namespace srt
|
||||
#endif // ENABLE_HEAVY_LOGGING
|
||||
|
||||
bool srt::CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir, HaiCrypt_Handle& w_hCrypto)
|
||||
bool srt::CCryptoControl::createCryptoCtx(HaiCrypt_Handle& w_hCrypto, size_t keylen, HaiCrypt_CryptoDir cdir, bool bAESGCM)
|
||||
{
|
||||
|
||||
if (w_hCrypto)
|
||||
{
|
||||
// XXX You can check here if the existing handle represents
|
||||
|
@ -715,7 +762,7 @@ bool srt::CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir
|
|||
m_KmRefreshRatePkt = 2000;
|
||||
m_KmPreAnnouncePkt = 500;
|
||||
#endif
|
||||
crypto_cfg.flags = HAICRYPT_CFG_F_CRYPTO | (cdir == HAICRYPT_CRYPTO_DIR_TX ? HAICRYPT_CFG_F_TX : 0);
|
||||
crypto_cfg.flags = HAICRYPT_CFG_F_CRYPTO | (cdir == HAICRYPT_CRYPTO_DIR_TX ? HAICRYPT_CFG_F_TX : 0) | (bAESGCM ? HAICRYPT_CFG_F_GCM : 0);
|
||||
crypto_cfg.xport = HAICRYPT_XPT_SRT;
|
||||
crypto_cfg.cryspr = HaiCryptCryspr_Get_Instance();
|
||||
crypto_cfg.key_len = (size_t)keylen;
|
||||
|
@ -724,7 +771,6 @@ bool srt::CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir
|
|||
crypto_cfg.km_refresh_rate_pkt = m_KmRefreshRatePkt == 0 ? HAICRYPT_DEF_KM_REFRESH_RATE : m_KmRefreshRatePkt;
|
||||
crypto_cfg.km_pre_announce_pkt = m_KmPreAnnouncePkt == 0 ? SRT_CRYPT_KM_PRE_ANNOUNCE : m_KmPreAnnouncePkt;
|
||||
crypto_cfg.secret = m_KmSecret;
|
||||
//memcpy(&crypto_cfg.secret, &m_KmSecret, sizeof(crypto_cfg.secret));
|
||||
|
||||
HLOGC(cnlog.Debug, log << "CRYPTO CFG: flags=" << CryptoFlags(crypto_cfg.flags) << " xport=" << crypto_cfg.xport << " cryspr=" << crypto_cfg.cryspr
|
||||
<< " keylen=" << crypto_cfg.key_len << " passphrase_length=" << crypto_cfg.secret.len);
|
||||
|
@ -740,7 +786,7 @@ bool srt::CCryptoControl::createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir cdir
|
|||
return true;
|
||||
}
|
||||
#else
|
||||
bool srt::CCryptoControl::createCryptoCtx(size_t, HaiCrypt_CryptoDir, HaiCrypt_Handle&)
|
||||
bool srt::CCryptoControl::createCryptoCtx(HaiCrypt_Handle&, size_t, HaiCrypt_CryptoDir, bool)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -754,6 +800,8 @@ srt::EncryptionStatus srt::CCryptoControl::encrypt(CPacket& w_packet SRT_ATR_UNU
|
|||
if ( getSndCryptoFlags() == EK_NOENC )
|
||||
return ENCS_CLEAR;
|
||||
|
||||
// Note that in case of GCM the header has to zero Retransmitted Packet Flag (R).
|
||||
// If TSBPD is disabled, timestamp also has to be zeroed.
|
||||
int rc = HaiCrypt_Tx_Data(m_hSndCrypto, ((uint8_t*)w_packet.getHeader()), ((uint8_t*)w_packet.m_pcData), w_packet.getLength());
|
||||
if (rc < 0)
|
||||
{
|
||||
|
@ -826,10 +874,10 @@ srt::EncryptionStatus srt::CCryptoControl::decrypt(CPacket& w_packet SRT_ATR_UNU
|
|||
return ENCS_FAILED;
|
||||
}
|
||||
|
||||
int rc = HaiCrypt_Rx_Data(m_hRcvCrypto, ((uint8_t *)w_packet.getHeader()), ((uint8_t *)w_packet.m_pcData), w_packet.getLength());
|
||||
if ( rc <= 0 )
|
||||
const int rc = HaiCrypt_Rx_Data(m_hRcvCrypto, ((uint8_t *)w_packet.getHeader()), ((uint8_t *)w_packet.m_pcData), w_packet.getLength());
|
||||
if (rc <= 0)
|
||||
{
|
||||
LOGC(cnlog.Error, log << "decrypt ERROR (IPE): HaiCrypt_Rx_Data failure=" << rc << " - returning failed decryption");
|
||||
LOGC(cnlog.Note, log << "decrypt ERROR: HaiCrypt_Rx_Data failure=" << rc << " - returning failed decryption");
|
||||
// -1: decryption failure
|
||||
// 0: key not received yet
|
||||
return ENCS_FAILED;
|
||||
|
|
33
trunk/3rdparty/srt-1-fit/srtcore/crypto.h
vendored
33
trunk/3rdparty/srt-1-fit/srtcore/crypto.h
vendored
|
@ -50,8 +50,6 @@ const size_t SRT_KMR_KMSTATE = 0;
|
|||
#define SRT_CMD_MAXSZ HCRYPT_MSG_KM_MAX_SZ /* Maximum SRT custom messages payload size (bytes) */
|
||||
const size_t SRTDATA_MAXSIZE = SRT_CMD_MAXSZ/sizeof(uint32_t);
|
||||
|
||||
enum Whether2RegenKm {DONT_REGEN_KM = 0, REGEN_KM = 1};
|
||||
|
||||
class CCryptoControl
|
||||
{
|
||||
SRTSOCKET m_SocketID;
|
||||
|
@ -69,10 +67,12 @@ private:
|
|||
// putting the whole HaiCrypt_Cfg object here.
|
||||
int m_KmRefreshRatePkt;
|
||||
int m_KmPreAnnouncePkt;
|
||||
int m_iCryptoMode;
|
||||
|
||||
HaiCrypt_Secret m_KmSecret; //Key material shared secret
|
||||
// Sender
|
||||
sync::steady_clock::time_point m_SndKmLastTime;
|
||||
sync::Mutex m_mtxLock; // A mutex to protect concurrent access to CCryptoControl.
|
||||
struct {
|
||||
unsigned char Msg[HCRYPT_MSG_KM_MAX_SZ];
|
||||
size_t MsgLen;
|
||||
|
@ -87,6 +87,8 @@ private:
|
|||
public:
|
||||
static void globalInit();
|
||||
|
||||
static bool isAESGCMSupported();
|
||||
|
||||
bool sendingAllowed()
|
||||
{
|
||||
// This function is called to state as to whether the
|
||||
|
@ -109,15 +111,16 @@ public:
|
|||
return m_KmSecret.len > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
/// Regenerate cryptographic key material.
|
||||
int getCryptoMode() const
|
||||
{
|
||||
return m_iCryptoMode;
|
||||
}
|
||||
|
||||
/// Regenerate cryptographic key material if needed.
|
||||
/// @param[in] sock If not null, the socket will be used to send the KM message to the peer (e.g. KM refresh).
|
||||
/// @param[in] bidirectional If true, the key material will be regenerated for both directions (receiver and sender).
|
||||
SRT_ATTR_EXCLUDES(m_mtxLock)
|
||||
void regenCryptoKm(CUDT* sock, bool bidirectional);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
size_t KeyLen() { return m_iSndKmKeyLen; }
|
||||
|
||||
|
@ -205,13 +208,17 @@ public:
|
|||
std::string FormatKmMessage(std::string hdr, int cmd, size_t srtlen);
|
||||
|
||||
bool init(HandshakeSide, const CSrtConfig&, bool);
|
||||
SRT_ATTR_EXCLUDES(m_mtxLock)
|
||||
void close();
|
||||
|
||||
/// @return True if the handshake is in progress.
|
||||
/// (Re)send KM request to a peer on timeout.
|
||||
/// This function is used in:
|
||||
/// - HSv4 (initial key material exchange - in HSv5 it's attached to handshake)
|
||||
/// - case of key regeneration, which should be then exchanged again.
|
||||
void sendKeysToPeer(CUDT* sock, int iSRTT, Whether2RegenKm regen);
|
||||
/// - HSv4 (initial key material exchange - in HSv5 it's attached to handshake).
|
||||
/// - The case of key regeneration (KM refresh), when a new key has to be sent again.
|
||||
/// In this case the first sending happens in regenCryptoKm(..). This function
|
||||
/// retransmits the KM request by timeout if not KM response has been received.
|
||||
SRT_ATTR_EXCLUDES(m_mtxLock)
|
||||
void sendKeysToPeer(CUDT* sock, int iSRTT);
|
||||
|
||||
void setCryptoSecret(const HaiCrypt_Secret& secret)
|
||||
{
|
||||
|
@ -224,7 +231,7 @@ public:
|
|||
m_iRcvKmKeyLen = keylen;
|
||||
}
|
||||
|
||||
bool createCryptoCtx(size_t keylen, HaiCrypt_CryptoDir tx, HaiCrypt_Handle& rh);
|
||||
bool createCryptoCtx(HaiCrypt_Handle& rh, size_t keylen, HaiCrypt_CryptoDir tx, bool bAESGCM);
|
||||
|
||||
int getSndCryptoFlags() const
|
||||
{
|
||||
|
|
21
trunk/3rdparty/srt-1-fit/srtcore/epoll.cpp
vendored
21
trunk/3rdparty/srt-1-fit/srtcore/epoll.cpp
vendored
|
@ -66,6 +66,7 @@ modified by
|
|||
#include "epoll.h"
|
||||
#include "logging.h"
|
||||
#include "udt.h"
|
||||
#include "utilities.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace srt::sync;
|
||||
|
@ -214,8 +215,8 @@ void srt::CEPoll::clear_ready_usocks(CEPollDesc& d, int direction)
|
|||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < cleared.size(); ++i)
|
||||
d.removeSubscription(cleared[i]);
|
||||
for (size_t j = 0; j < cleared.size(); ++j)
|
||||
d.removeSubscription(cleared[j]);
|
||||
}
|
||||
|
||||
int srt::CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
|
@ -639,8 +640,8 @@ int srt::CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* wr
|
|||
#ifdef LINUX
|
||||
const int max_events = ed.m_sLocals.size();
|
||||
SRT_ASSERT(max_events > 0);
|
||||
epoll_event ev[max_events];
|
||||
int nfds = ::epoll_wait(ed.m_iLocalID, ev, max_events, 0);
|
||||
srt::FixedArray<epoll_event> ev(max_events);
|
||||
int nfds = ::epoll_wait(ed.m_iLocalID, ev.data(), ev.size(), 0);
|
||||
|
||||
IF_HEAVY_LOGGING(const int prev_total = total);
|
||||
for (int i = 0; i < nfds; ++ i)
|
||||
|
@ -660,23 +661,23 @@ int srt::CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* wr
|
|||
|
||||
#elif defined(BSD) || TARGET_OS_MAC
|
||||
struct timespec tmout = {0, 0};
|
||||
const int max_events = ed.m_sLocals.size();
|
||||
const int max_events = (int)ed.m_sLocals.size();
|
||||
SRT_ASSERT(max_events > 0);
|
||||
struct kevent ke[max_events];
|
||||
srt::FixedArray<struct kevent> ke(max_events);
|
||||
|
||||
int nfds = kevent(ed.m_iLocalID, NULL, 0, ke, max_events, &tmout);
|
||||
int nfds = kevent(ed.m_iLocalID, NULL, 0, ke.data(), (int)ke.size(), &tmout);
|
||||
IF_HEAVY_LOGGING(const int prev_total = total);
|
||||
|
||||
for (int i = 0; i < nfds; ++ i)
|
||||
{
|
||||
if ((NULL != lrfds) && (ke[i].filter == EVFILT_READ))
|
||||
{
|
||||
lrfds->insert(ke[i].ident);
|
||||
lrfds->insert((int)ke[i].ident);
|
||||
++ total;
|
||||
}
|
||||
if ((NULL != lwfds) && (ke[i].filter == EVFILT_WRITE))
|
||||
{
|
||||
lwfds->insert(ke[i].ident);
|
||||
lwfds->insert((int)ke[i].ident);
|
||||
++ total;
|
||||
}
|
||||
}
|
||||
|
@ -702,7 +703,7 @@ int srt::CEPoll::wait(const int eid, set<SRTSOCKET>* readfds, set<SRTSOCKET>* wr
|
|||
if (lwfds)
|
||||
FD_SET(*i, &rqwritefds);
|
||||
if ((int)*i > max_fd)
|
||||
max_fd = *i;
|
||||
max_fd = (int)*i;
|
||||
}
|
||||
|
||||
IF_HEAVY_LOGGING(const int prev_total = total);
|
||||
|
|
5
trunk/3rdparty/srt-1-fit/srtcore/epoll.h
vendored
5
trunk/3rdparty/srt-1-fit/srtcore/epoll.h
vendored
|
@ -69,8 +69,11 @@ class CUDTGroup;
|
|||
|
||||
class CEPollDesc
|
||||
{
|
||||
#ifdef __GNUG__
|
||||
const int m_iID; // epoll ID
|
||||
|
||||
#else
|
||||
const int m_iID SRT_ATR_UNUSED; // epoll ID
|
||||
#endif
|
||||
struct Wait;
|
||||
|
||||
struct Notice: public SRT_EPOLL_EVENT
|
||||
|
|
59
trunk/3rdparty/srt-1-fit/srtcore/fec.cpp
vendored
59
trunk/3rdparty/srt-1-fit/srtcore/fec.cpp
vendored
|
@ -345,13 +345,13 @@ void FECFilterBuiltin::ConfigureColumns(Container& which, int32_t isn)
|
|||
{
|
||||
offset = col + 1; // +1 because we want it for the next column
|
||||
HLOGC(pflog.Debug, log << "ConfigureColumns: [" << (col+1) << "]... (resetting to row 0: +"
|
||||
<< offset << " %" << CSeqNo::incseq(isn, offset) << ")");
|
||||
<< offset << " %" << CSeqNo::incseq(isn, (int32_t)offset) << ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
offset += 1 + sizeRow();
|
||||
HLOGC(pflog.Debug, log << "ConfigureColumns: [" << (col+1) << "] ... (continue +"
|
||||
<< offset << " %" << CSeqNo::incseq(isn, offset) << ")");
|
||||
<< offset << " %" << CSeqNo::incseq(isn, (int32_t)offset) << ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,9 @@ void FECFilterBuiltin::feedSource(CPacket& packet)
|
|||
HLOGC(pflog.Debug, log << "FEC:feedSource: %" << packet.getSeqNo() << " rowoff=" << baseoff
|
||||
<< " column=" << vert_gx << " .base=%" << vert_base << " coloff=" << vert_off);
|
||||
|
||||
if (vert_off >= 0 && sizeCol() > 1)
|
||||
// [[assert sizeCol() >= 2]]; // see the condition above.
|
||||
|
||||
if (vert_off >= 0)
|
||||
{
|
||||
// BEWARE! X % Y with different signedness upgrades int to unsigned!
|
||||
|
||||
|
@ -468,7 +470,7 @@ void FECFilterBuiltin::feedSource(CPacket& packet)
|
|||
return;
|
||||
}
|
||||
|
||||
SRT_ASSERT(vert_off >= 0);
|
||||
// [[assert vert_off >= 0]]; // this condition branch
|
||||
int vert_pos = vert_off / int(sizeRow());
|
||||
|
||||
HLOGC(pflog.Debug, log << "FEC:feedSource: %" << packet.getSeqNo()
|
||||
|
@ -496,7 +498,6 @@ void FECFilterBuiltin::feedSource(CPacket& packet)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
HLOGC(pflog.Debug, log << "FEC:feedSource: %" << packet.getSeqNo()
|
||||
<< " B:%" << baseoff << " H:*[" << horiz_pos << "] V(B=%" << vert_base
|
||||
<< ")[col=" << vert_gx << "]<NO-COLUMN>"
|
||||
|
@ -604,8 +605,8 @@ void FECFilterBuiltin::ClipData(Group& g, uint16_t length_net, uint8_t kflg,
|
|||
}
|
||||
|
||||
// Fill the rest with zeros. When this packet is going to be
|
||||
// recovered, the payload extraced from this process will have
|
||||
// the maximum lenght, but it will be cut to the right length
|
||||
// recovered, the payload extracted from this process will have
|
||||
// the maximum length, but it will be cut to the right length
|
||||
// and these padding 0s taken out.
|
||||
for (size_t i = payload_size; i < payloadSize(); ++i)
|
||||
g.payload_clip[i] = g.payload_clip[i] ^ 0;
|
||||
|
@ -1128,10 +1129,10 @@ static void DebugPrintCells(int32_t base, const std::deque<bool>& cells, size_t
|
|||
for ( ; i < cells.size(); i += row_size )
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "cell[" << i << "-" << (i+row_size-1) << "] %" << CSeqNo::incseq(base, i) << ":";
|
||||
os << "cell[" << i << "-" << (i+row_size-1) << "] %" << CSeqNo::incseq(base, (int32_t)i) << ":";
|
||||
for (size_t y = 0; y < row_size; ++y)
|
||||
{
|
||||
os << " " << CellMark(cells, i+y);
|
||||
os << " " << CellMark(cells, (int)(i+y));
|
||||
}
|
||||
LOGP(pflog.Debug, os.str());
|
||||
}
|
||||
|
@ -1568,11 +1569,10 @@ size_t FECFilterBuiltin::ExtendRows(size_t rowx)
|
|||
const size_t size_in_packets = rowx * numberCols();
|
||||
const int n_series = int(rowx / numberRows());
|
||||
|
||||
if (size_in_packets > rcvBufferSize() && n_series > 2)
|
||||
if (CheckEmergencyShrink(n_series, size_in_packets))
|
||||
{
|
||||
HLOGC(pflog.Debug, log << "FEC: Emergency resize, rowx=" << rowx << " series=" << n_series
|
||||
HLOGC(pflog.Debug, log << "FEC: DONE Emergency resize, rowx=" << rowx << " series=" << n_series
|
||||
<< "npackets=" << size_in_packets << " exceeds buf=" << rcvBufferSize());
|
||||
EmergencyShrink(n_series);
|
||||
}
|
||||
|
||||
// Create and configure next groups.
|
||||
|
@ -1700,8 +1700,27 @@ bool FECFilterBuiltin::IsLost(int32_t seq) const
|
|||
return rcv.cells[offset];
|
||||
}
|
||||
|
||||
void FECFilterBuiltin::EmergencyShrink(size_t n_series)
|
||||
bool FECFilterBuiltin::CheckEmergencyShrink(size_t n_series, size_t size_in_packets)
|
||||
{
|
||||
// The minimum required size of the covered sequence range must be such
|
||||
// that groups for packets from the previous range must be still reachable.
|
||||
// It's then "this and previous" series in case of even arrangement.
|
||||
//
|
||||
// For staircase arrangement the potential range for a single column series
|
||||
// (number of columns equal to a row size) spans for 2 matrices (rows * cols)
|
||||
// minus one row. As dismissal is only allowed to be done by one full series
|
||||
// of rows and columns, the history must keep as many groups as needed to reach
|
||||
// out for this very packet of this group and all packets in the same row.
|
||||
// Hence we need two series of columns to cover a similar range as two row, twice.
|
||||
|
||||
const size_t min_series_history = m_arrangement_staircase ? 4 : 2;
|
||||
|
||||
if (n_series <= min_series_history)
|
||||
return false;
|
||||
|
||||
if (size_in_packets < rcvBufferSize() && n_series < SRT_FEC_MAX_RCV_HISTORY)
|
||||
return false;
|
||||
|
||||
// Shrink is required in order to prepare place for
|
||||
// either vertical or horizontal group in series `n_series`.
|
||||
|
||||
|
@ -1782,7 +1801,7 @@ void FECFilterBuiltin::EmergencyShrink(size_t n_series)
|
|||
else
|
||||
{
|
||||
HLOGC(pflog.Debug, log << "FEC: Shifting rcv row %" << oldbase << " -> %" << newbase);
|
||||
rcv.rowq.erase(rcv.rowq.begin(), rcv.rowq.end() + shift_rows);
|
||||
rcv.rowq.erase(rcv.rowq.begin(), rcv.rowq.begin() + shift_rows);
|
||||
}
|
||||
|
||||
const size_t shift_cols = shift_series * numberCols();
|
||||
|
@ -1816,6 +1835,8 @@ void FECFilterBuiltin::EmergencyShrink(size_t n_series)
|
|||
rcv.cells.push_back(false);
|
||||
}
|
||||
rcv.cell_base = newbase;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FECFilterBuiltin::EHangStatus FECFilterBuiltin::HangVertical(const CPacket& rpkt, signed char fec_col, loss_seqs_t& irrecover)
|
||||
|
@ -1932,7 +1953,7 @@ void FECFilterBuiltin::RcvCheckDismissColumn(int32_t seq, int colgx, loss_seqs_t
|
|||
{
|
||||
HLOGC(pflog.Debug, log << "FEC/V: ... [" << i << "] base=%"
|
||||
<< pg.base << " TOO EARLY (last=%"
|
||||
<< CSeqNo::incseq(pg.base, (sizeCol()-1)*sizeRow())
|
||||
<< CSeqNo::incseq(pg.base, (int32_t)((sizeCol()-1)*sizeRow()))
|
||||
<< ")");
|
||||
continue;
|
||||
}
|
||||
|
@ -1943,7 +1964,7 @@ void FECFilterBuiltin::RcvCheckDismissColumn(int32_t seq, int colgx, loss_seqs_t
|
|||
|
||||
HLOGC(pflog.Debug, log << "FEC/V: ... [" << i << "] base=%"
|
||||
<< pg.base << " - PAST last=%"
|
||||
<< CSeqNo::incseq(pg.base, (sizeCol()-1)*sizeRow())
|
||||
<< CSeqNo::incseq(pg.base, (int32_t)((sizeCol()-1)*sizeRow()))
|
||||
<< " - collecting losses.");
|
||||
|
||||
pg.dismissed = true; // mark irrecover already collected
|
||||
|
@ -2489,11 +2510,11 @@ size_t FECFilterBuiltin::ExtendColumns(size_t colgx)
|
|||
// of packets as many as the number of rows, so simply multiply this.
|
||||
const size_t size_in_packets = colgx * numberRows();
|
||||
const size_t n_series = colgx / numberCols();
|
||||
if (size_in_packets > rcvBufferSize()/2 || n_series > SRT_FEC_MAX_RCV_HISTORY)
|
||||
|
||||
if (CheckEmergencyShrink(n_series, size_in_packets))
|
||||
{
|
||||
HLOGC(pflog.Debug, log << "FEC: Emergency resize, colgx=" << colgx << " series=" << n_series
|
||||
HLOGC(pflog.Debug, log << "FEC: DONE Emergency resize, colgx=" << colgx << " series=" << n_series
|
||||
<< "npackets=" << size_in_packets << " exceeds buf=" << rcvBufferSize());
|
||||
EmergencyShrink(n_series);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
6
trunk/3rdparty/srt-1-fit/srtcore/fec.h
vendored
6
trunk/3rdparty/srt-1-fit/srtcore/fec.h
vendored
|
@ -47,7 +47,7 @@ public:
|
|||
size_t drop; //< by how much the sequence should increase to get to the next series
|
||||
size_t collected; //< how many packets were taken to collect the clip
|
||||
|
||||
Group(): base(CSeqNo::m_iMaxSeqNo), step(0), drop(0), collected(0)
|
||||
Group(): base(SRT_SEQNO_NONE), step(0), drop(0), collected(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ public:
|
|||
#if ENABLE_HEAVY_LOGGING
|
||||
std::string DisplayStats()
|
||||
{
|
||||
if (base == CSeqNo::m_iMaxSeqNo)
|
||||
if (base == SRT_SEQNO_NONE)
|
||||
return "UNINITIALIZED!!!";
|
||||
|
||||
std::ostringstream os;
|
||||
|
@ -222,7 +222,7 @@ private:
|
|||
void RcvRebuild(Group& g, int32_t seqno, Group::Type tp);
|
||||
int32_t RcvGetLossSeqHoriz(Group& g);
|
||||
int32_t RcvGetLossSeqVert(Group& g);
|
||||
void EmergencyShrink(size_t n_series);
|
||||
bool CheckEmergencyShrink(size_t n_series, size_t size_in_packets);
|
||||
|
||||
static void TranslateLossRecords(const std::set<int32_t>& loss, loss_seqs_t& irrecover);
|
||||
void RcvCheckDismissColumn(int32_t seqno, int colgx, loss_seqs_t& irrecover);
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
SOURCES
|
||||
api.cpp
|
||||
buffer.cpp
|
||||
buffer_snd.cpp
|
||||
buffer_rcv.cpp
|
||||
buffer_tools.cpp
|
||||
cache.cpp
|
||||
channel.cpp
|
||||
common.cpp
|
||||
|
@ -53,8 +54,9 @@ udt.h
|
|||
|
||||
PRIVATE HEADERS
|
||||
api.h
|
||||
buffer.h
|
||||
buffer_snd.h
|
||||
buffer_rcv.h
|
||||
buffer_tools.h
|
||||
cache.h
|
||||
channel.h
|
||||
common.h
|
||||
|
|
642
trunk/3rdparty/srt-1-fit/srtcore/group.cpp
vendored
642
trunk/3rdparty/srt-1-fit/srtcore/group.cpp
vendored
|
@ -226,12 +226,12 @@ CUDTGroup::SocketData* CUDTGroup::add(SocketData data)
|
|||
data.sndstate = SRT_GST_PENDING;
|
||||
data.rcvstate = SRT_GST_PENDING;
|
||||
|
||||
HLOGC(gmlog.Debug, log << "CUDTGroup::add: adding new member @" << data.id);
|
||||
LOGC(gmlog.Note, log << "group/add: adding member @" << data.id << " into group $" << id());
|
||||
m_Group.push_back(data);
|
||||
gli_t end = m_Group.end();
|
||||
if (m_iMaxPayloadSize == -1)
|
||||
{
|
||||
int plsize = data.ps->core().OPT_PayloadSize();
|
||||
int plsize = (int)data.ps->core().OPT_PayloadSize();
|
||||
HLOGC(gmlog.Debug,
|
||||
log << "CUDTGroup::add: taking MAX payload size from socket @" << data.ps->m_SocketID << ": " << plsize
|
||||
<< " " << (plsize ? "(explicit)" : "(unspecified = fallback to 1456)"));
|
||||
|
@ -251,7 +251,6 @@ CUDTGroup::CUDTGroup(SRT_GROUP_TYPE gtype)
|
|||
: m_Global(CUDT::uglobal())
|
||||
, m_GroupID(-1)
|
||||
, m_PeerGroupID(-1)
|
||||
, m_bSyncOnMsgNo(false)
|
||||
, m_type(gtype)
|
||||
, m_listener()
|
||||
, m_iBusy()
|
||||
|
@ -336,6 +335,7 @@ void CUDTGroup::GroupContainer::erase(CUDTGroup::gli_t it)
|
|||
}
|
||||
}
|
||||
m_List.erase(it);
|
||||
--m_SizeCache;
|
||||
}
|
||||
|
||||
void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)
|
||||
|
@ -394,12 +394,6 @@ void CUDTGroup::setOpt(SRT_SOCKOPT optName, const void* optval, int optlen)
|
|||
|
||||
break;
|
||||
|
||||
case SRTO_CONGESTION:
|
||||
// Currently no socket groups allow any other
|
||||
// congestion control mode other than live.
|
||||
LOGP(gmlog.Error, "group option: SRTO_CONGESTION is only allowed as 'live' and cannot be changed");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -554,7 +548,7 @@ void CUDTGroup::deriveSettings(CUDT* u)
|
|||
if (u->m_config.CryptoSecret.len)
|
||||
{
|
||||
string password((const char*)u->m_config.CryptoSecret.str, u->m_config.CryptoSecret.len);
|
||||
m_config.push_back(ConfigItem(SRTO_PASSPHRASE, password.c_str(), password.size()));
|
||||
m_config.push_back(ConfigItem(SRTO_PASSPHRASE, password.c_str(), (int)password.size()));
|
||||
}
|
||||
|
||||
IM(SRTO_KMREFRESHRATE, uKmRefreshRatePkt);
|
||||
|
@ -563,7 +557,7 @@ void CUDTGroup::deriveSettings(CUDT* u)
|
|||
string cc = u->m_CongCtl.selected_name();
|
||||
if (cc != "live")
|
||||
{
|
||||
m_config.push_back(ConfigItem(SRTO_CONGESTION, cc.c_str(), cc.size()));
|
||||
m_config.push_back(ConfigItem(SRTO_CONGESTION, cc.c_str(), (int)cc.size()));
|
||||
}
|
||||
|
||||
// NOTE: This is based on information extracted from the "semi-copy-constructor" of CUDT class.
|
||||
|
@ -893,6 +887,16 @@ void CUDTGroup::close()
|
|||
HLOGC(smlog.Debug, log << "group/close: IPE(NF): group member @" << ig->id << " already deleted");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make the socket closing BEFORE withdrawing its group membership
|
||||
// because a socket created as a group member cannot be valid
|
||||
// without the group.
|
||||
// This is not true in case of non-managed groups, which
|
||||
// only collect sockets, but also non-managed groups should not
|
||||
// use common group buffering and tsbpd. Also currently there are
|
||||
// no other groups than managed one.
|
||||
s->setClosing();
|
||||
|
||||
s->m_GroupOf = NULL;
|
||||
s->m_GroupMemberData = NULL;
|
||||
HLOGC(smlog.Debug, log << "group/close: CUTTING OFF @" << ig->id << " (found as @" << s->m_SocketID << ") from the group");
|
||||
|
@ -1219,12 +1223,10 @@ int CUDTGroup::sendBroadcast(const char* buf, int len, SRT_MSGCTRL& w_mc)
|
|||
// and therefore take over the leading role in setting the ISN. If the
|
||||
// second one fails, too, then the only remaining idle link will simply
|
||||
// go with its own original sequence.
|
||||
//
|
||||
// On the opposite side the reader should know that the link is inactive
|
||||
// so the first received payload activates it. Activation of an idle link
|
||||
// means that the very first packet arriving is TAKEN AS A GOOD DEAL, that is,
|
||||
// no LOSSREPORT is sent even if the sequence looks like a "jumped over".
|
||||
// Only for activated links is the LOSSREPORT sent upon seqhole detection.
|
||||
|
||||
// On the opposite side, if the first packet arriving looks like a jump over,
|
||||
// the corresponding LOSSREPORT is sent. For packets that are truly lost,
|
||||
// the sender retransmits them, for packets that before ISN, DROPREQ is sent.
|
||||
|
||||
// Now we can go to the idle links and attempt to send the payload
|
||||
// also over them.
|
||||
|
@ -1714,7 +1716,7 @@ int CUDTGroup::getGroupData_LOCKED(SRT_SOCKGROUPDATA* pdata, size_t* psize)
|
|||
copyGroupData(*d, (pdata[i]));
|
||||
}
|
||||
|
||||
return m_Group.size();
|
||||
return (int)m_Group.size();
|
||||
}
|
||||
|
||||
// [[using locked(this->m_GroupLock)]]
|
||||
|
@ -1888,7 +1890,7 @@ void CUDTGroup::recv_CollectAliveAndBroken(vector<CUDTSocket*>& alive, set<CUDTS
|
|||
// Don't skip packets that are ahead because if we have a situation
|
||||
// that all links are either "elephants" (do not report read readiness)
|
||||
// and "kangaroos" (have already delivered an ahead packet) then
|
||||
// omiting kangaroos will result in only elephants to be polled for
|
||||
// omitting kangaroos will result in only elephants to be polled for
|
||||
// reading. Due to the strict timing requirements and ensurance that
|
||||
// TSBPD on every link will result in exactly the same delivery time
|
||||
// for a packet of given sequence, having an elephant and kangaroo in
|
||||
|
@ -2134,7 +2136,6 @@ static bool isValidSeqno(int32_t iBaseSeqno, int32_t iPktSeqno)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_NEW_RCVBUFFER
|
||||
int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
||||
{
|
||||
// First, acquire GlobControlLock to make sure all member sockets still exist
|
||||
|
@ -2197,7 +2198,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
|||
|
||||
// Find the first readable packet among all member sockets.
|
||||
CUDTSocket* socketToRead = NULL;
|
||||
CRcvBufferNew::PacketInfo infoToRead = {-1, false, time_point()};
|
||||
CRcvBuffer::PacketInfo infoToRead = {-1, false, time_point()};
|
||||
for (vector<CUDTSocket*>::const_iterator si = readySockets.begin(); si != readySockets.end(); ++si)
|
||||
{
|
||||
CUDTSocket* ps = *si;
|
||||
|
@ -2215,7 +2216,7 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
|||
}
|
||||
}
|
||||
|
||||
const CRcvBufferNew::PacketInfo info =
|
||||
const CRcvBuffer::PacketInfo info =
|
||||
ps->core().m_pRcvBuffer->getFirstReadablePacketInfo(steady_clock::now());
|
||||
if (info.seqno == SRT_SEQNO_NONE)
|
||||
{
|
||||
|
@ -2292,13 +2293,14 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
|||
m_stats.recv.count(res);
|
||||
updateAvgPayloadSize(res);
|
||||
|
||||
bool canReadFurther = false;
|
||||
for (vector<CUDTSocket*>::const_iterator si = aliveMembers.begin(); si != aliveMembers.end(); ++si)
|
||||
{
|
||||
CUDTSocket* ps = *si;
|
||||
ScopedLock lg(ps->core().m_RcvBufferLock);
|
||||
if (m_RcvBaseSeqNo != SRT_SEQNO_NONE)
|
||||
{
|
||||
int cnt = ps->core().rcvDropTooLateUpTo(CSeqNo::incseq(m_RcvBaseSeqNo));
|
||||
const int cnt = ps->core().rcvDropTooLateUpTo(CSeqNo::incseq(m_RcvBaseSeqNo));
|
||||
if (cnt > 0)
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
|
@ -2306,596 +2308,22 @@ int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
|||
<< " packets after reading: m_RcvBaseSeqNo=" << m_RcvBaseSeqNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (vector<CUDTSocket*>::const_iterator si = aliveMembers.begin(); si != aliveMembers.end(); ++si)
|
||||
{
|
||||
CUDTSocket* ps = *si;
|
||||
if (!ps->core().isRcvBufferReady())
|
||||
|
||||
if (!ps->core().isRcvBufferReadyNoLock())
|
||||
m_Global.m_EPoll.update_events(ps->m_SocketID, ps->core().m_sPollID, SRT_EPOLL_IN, false);
|
||||
else
|
||||
canReadFurther = true;
|
||||
}
|
||||
|
||||
if (!canReadFurther)
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
|
||||
return res;
|
||||
}
|
||||
LOGC(grlog.Error, log << "grp/recv: UNEXPECTED RUN PATH, ABANDONING.");
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0);
|
||||
}
|
||||
#else
|
||||
// The "app reader" version of the reading function.
|
||||
// This reads the packets from every socket treating them as independent
|
||||
// and prepared to work with the application. Then packets are sorted out
|
||||
// by getting the sequence number.
|
||||
int CUDTGroup::recv(char* buf, int len, SRT_MSGCTRL& w_mc)
|
||||
{
|
||||
typedef map<SRTSOCKET, ReadPos>::iterator pit_t;
|
||||
// Later iteration over it might be less efficient than
|
||||
// by vector, but we'll also often try to check a single id
|
||||
// if it was ever seen broken, so that it's skipped.
|
||||
set<CUDTSocket*> broken;
|
||||
size_t output_size = 0;
|
||||
|
||||
// First, acquire GlobControlLock to make sure all member sockets still exist
|
||||
enterCS(m_Global.m_GlobControlLock);
|
||||
ScopedLock guard(m_GroupLock);
|
||||
|
||||
if (m_bClosing)
|
||||
{
|
||||
// The group could be set closing in the meantime, but if
|
||||
// this is only about to be set by another thread, this thread
|
||||
// must fist wait for being able to acquire this lock.
|
||||
// The group will not be deleted now because it is added usage counter
|
||||
// by this call, but will be released once it exits.
|
||||
leaveCS(m_Global.m_GlobControlLock);
|
||||
throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
|
||||
}
|
||||
|
||||
// Now, still under lock, check if all sockets still can be dispatched
|
||||
send_CheckValidSockets();
|
||||
leaveCS(m_Global.m_GlobControlLock);
|
||||
|
||||
if (m_bClosing)
|
||||
throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (!m_bOpened || !m_bConnected)
|
||||
{
|
||||
LOGC(grlog.Error,
|
||||
log << boolalpha << "group/recv: ERROR opened=" << m_bOpened << " connected=" << m_bConnected);
|
||||
throw CUDTException(MJ_CONNECTION, MN_NOCONN, 0);
|
||||
}
|
||||
|
||||
// Check first the ahead packets if you have any to deliver.
|
||||
if (m_RcvBaseSeqNo != SRT_SEQNO_NONE && !m_Positions.empty())
|
||||
{
|
||||
// This function also updates the group sequence pointer.
|
||||
ReadPos* pos = checkPacketAhead();
|
||||
if (pos)
|
||||
{
|
||||
if (size_t(len) < pos->packet.size())
|
||||
throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);
|
||||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: delivering AHEAD packet %" << pos->mctrl.pktseq << " #" << pos->mctrl.msgno
|
||||
<< ": " << BufferStamp(&pos->packet[0], pos->packet.size()));
|
||||
memcpy(buf, &pos->packet[0], pos->packet.size());
|
||||
fillGroupData((w_mc), pos->mctrl);
|
||||
m_RcvBaseSeqNo = pos->mctrl.pktseq;
|
||||
len = pos->packet.size();
|
||||
pos->packet.clear();
|
||||
|
||||
// Update stats as per delivery
|
||||
m_stats.recv.count(len);
|
||||
updateAvgPayloadSize(len);
|
||||
|
||||
// We predict to have only one packet ahead, others are pending to be reported by tsbpd.
|
||||
// This will be "re-enabled" if the later check puts any new packet into ahead.
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
|
||||
return len;
|
||||
}
|
||||
}
|
||||
|
||||
// LINK QUALIFICATION NAMES:
|
||||
//
|
||||
// HORSE: Correct link, which delivers the very next sequence.
|
||||
// Not necessarily this link is currently active.
|
||||
//
|
||||
// KANGAROO: Got some packets dropped and the sequence number
|
||||
// of the packet jumps over the very next sequence and delivers
|
||||
// an ahead packet.
|
||||
//
|
||||
// ELEPHANT: Is not ready to read, while others are, or reading
|
||||
// up to the current latest delivery sequence number does not
|
||||
// reach this sequence and the link becomes non-readable earlier.
|
||||
|
||||
// The above condition has ruled out one kangaroo and turned it
|
||||
// into a horse.
|
||||
|
||||
// Below there's a loop that will try to extract packets. Kangaroos
|
||||
// will be among the polled ones because skipping them risks that
|
||||
// the elephants will take over the reading. Links already known as
|
||||
// elephants will be also polled in an attempt to revitalize the
|
||||
// connection that experienced just a short living choking.
|
||||
//
|
||||
// After polling we attempt to read from every link that reported
|
||||
// read-readiness and read at most up to the sequence equal to the
|
||||
// current delivery sequence.
|
||||
|
||||
// Links that deliver a packet below that sequence will be retried
|
||||
// until they deliver no more packets or deliver the packet of
|
||||
// expected sequence. Links that don't have a record in m_Positions
|
||||
// and report readiness will be always read, at least to know what
|
||||
// sequence they currently stand on.
|
||||
//
|
||||
// Links that are already known as kangaroos will be polled, but
|
||||
// no reading attempt will be done. If after the reading series
|
||||
// it will turn out that we have no more horses, the slowest kangaroo
|
||||
// will be "upgraded to a horse" (the ahead link with a sequence
|
||||
// closest to the current delivery sequence will get its sequence
|
||||
// set as current delivered and its recorded ahead packet returned
|
||||
// as the read packet).
|
||||
|
||||
// If we find at least one horse, the packet read from that link
|
||||
// will be delivered. All other link will be just ensured update
|
||||
// up to this sequence number, or at worst all available packets
|
||||
// will be read. In this case all kangaroos remain kangaroos,
|
||||
// until the current delivery sequence m_RcvBaseSeqNo will be lifted
|
||||
// to the sequence recorded for these links in m_Positions,
|
||||
// during the next time ahead check, after which they will become
|
||||
// horses.
|
||||
|
||||
const size_t size = m_Group.size();
|
||||
|
||||
// Prepare first the list of sockets to be added as connect-pending
|
||||
// and as read-ready, then unlock the group, and then add them to epoll.
|
||||
vector<CUDTSocket*> aliveMembers;
|
||||
recv_CollectAliveAndBroken(aliveMembers, broken);
|
||||
|
||||
const vector<CUDTSocket*> ready_sockets = recv_WaitForReadReady(aliveMembers, broken);
|
||||
// m_GlobControlLock lifted, m_GroupLock still locked.
|
||||
// Now we can safely do this scoped way.
|
||||
|
||||
if (!m_bSynRecving && ready_sockets.empty())
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/rcv $" << m_GroupID << ": Not available AT THIS TIME, NOT READ-READY now.");
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
throw CUDTException(MJ_AGAIN, MN_RDAVAIL, 0);
|
||||
}
|
||||
|
||||
// Ok, now we need to have some extra qualifications:
|
||||
// 1. If a socket has no registry yet, we read anyway, just
|
||||
// to notify the current position. We read ONLY ONE PACKET this time,
|
||||
// we'll worry later about adjusting it to the current group sequence
|
||||
// position.
|
||||
// 2. If a socket is already position ahead, DO NOT read from it, even
|
||||
// if it is ready.
|
||||
|
||||
// The state of things whether we were able to extract the very next
|
||||
// sequence will be simply defined by the fact that `output` is nonempty.
|
||||
|
||||
int32_t next_seq = m_RcvBaseSeqNo;
|
||||
|
||||
if (m_bClosing)
|
||||
{
|
||||
HLOGC(gslog.Debug, log << "grp/sendBroadcast: GROUP CLOSED, ABANDONING");
|
||||
throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
|
||||
}
|
||||
//
|
||||
// NOTE: Although m_GlobControlLock is lifted here so potentially sockets
|
||||
// colected in ready_sockets could be closed at any time, all of them are member
|
||||
// sockets of this group. Therefore the first socket attempted to be closed will
|
||||
// have to remove the socket from the group, and this will require lock on GroupLock,
|
||||
// which is still applied here. So this will have to wait for this function to finish
|
||||
// (or block on swait, in which case the lock is lifted) anyway.
|
||||
|
||||
for (vector<CUDTSocket*>::const_iterator si = ready_sockets.begin(); si != ready_sockets.end(); ++si)
|
||||
{
|
||||
CUDTSocket* ps = *si;
|
||||
SRTSOCKET id = ps->m_SocketID;
|
||||
ReadPos* p = NULL;
|
||||
pit_t pe = m_Positions.find(id);
|
||||
if (pe != m_Positions.end())
|
||||
{
|
||||
p = &pe->second;
|
||||
|
||||
// Possible results of comparison:
|
||||
// x < 0: the sequence is in the past, the socket should be adjusted FIRST
|
||||
// x = 0: the socket should be ready to get the exactly next packet
|
||||
// x = 1: the case is already handled by GroupCheckPacketAhead.
|
||||
// x > 1: AHEAD. DO NOT READ.
|
||||
const int seqdiff = CSeqNo::seqcmp(p->mctrl.pktseq, m_RcvBaseSeqNo);
|
||||
if (seqdiff > 1)
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: EPOLL: @" << id << " %" << p->mctrl.pktseq << " AHEAD %" << m_RcvBaseSeqNo
|
||||
<< ", not reading.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The position is not known, so get the position on which
|
||||
// the socket is currently standing.
|
||||
pair<pit_t, bool> ee = m_Positions.insert(make_pair(id, ReadPos(ps->core().m_iRcvLastSkipAck)));
|
||||
p = &(ee.first->second);
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: EPOLL: @" << id << " %" << p->mctrl.pktseq << " NEW SOCKET INSERTED");
|
||||
}
|
||||
|
||||
// Read from this socket stubbornly, until:
|
||||
// - reading is no longer possible (AGAIN)
|
||||
// - the sequence difference is >= 1
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SRT_MSGCTRL mctrl = srt_msgctrl_default;
|
||||
|
||||
// Read the data into the user's buffer. This is an optimistic
|
||||
// prediction that we'll read the right data. This will be overwritten
|
||||
// by "more correct data" if found more appropriate later. But we have to
|
||||
// copy these data anyway anywhere, even if they need to fall on the floor later.
|
||||
int stat;
|
||||
char extrabuf[SRT_LIVE_MAX_PLSIZE];
|
||||
char* msgbuf = NULL;
|
||||
if (output_size)
|
||||
{
|
||||
// We already have the target data in `buf`. Now reading extra data potentially redundant (to be ignored)
|
||||
// or AHEAD (to be buffered internally by the group)
|
||||
msgbuf = extrabuf;
|
||||
stat = ps->core().receiveMessage((extrabuf), SRT_LIVE_MAX_PLSIZE, (mctrl), CUDTUnited::ERH_RETURN);
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << id << " EXTRACTED EXTRA data with %" << mctrl.pktseq
|
||||
<< " #" << mctrl.msgno << ": " << (stat <= 0 ? "(NOTHING)" : BufferStamp(extrabuf, stat))
|
||||
<< (CSeqNo::seqcmp(mctrl.pktseq, m_RcvBaseSeqNo) > 1 ? " - TO STORE" : " - TO IGNORE"));
|
||||
}
|
||||
else
|
||||
{
|
||||
msgbuf = buf;
|
||||
stat = ps->core().receiveMessage((buf), len, (mctrl), CUDTUnited::ERH_RETURN);
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << id << " EXTRACTED data with %" << mctrl.pktseq << " #"
|
||||
<< mctrl.msgno << ": " << (stat <= 0 ? "(NOTHING)" : BufferStamp(buf, stat)));
|
||||
}
|
||||
if (stat == 0)
|
||||
{
|
||||
HLOGC(grlog.Debug, log << "group/recv @" << id << ": SPURIOUS epoll, ignoring");
|
||||
// This is returned in case of "again". In case of errors, we have SRT_ERROR.
|
||||
// Do not treat this as spurious, just stop reading.
|
||||
break;
|
||||
}
|
||||
|
||||
if (stat == SRT_ERROR)
|
||||
{
|
||||
HLOGC(grlog.Debug, log << "group/recv: @" << id << ": " << srt_getlasterror_str());
|
||||
broken.insert(ps);
|
||||
break;
|
||||
}
|
||||
|
||||
// NOTE: checks against m_RcvBaseSeqNo and decisions based on it
|
||||
// must NOT be done if m_RcvBaseSeqNo is SRT_SEQNO_NONE, which
|
||||
// means that we are about to deliver the very first packet and we
|
||||
// take its sequence number as a good deal.
|
||||
|
||||
// The order must be:
|
||||
// - check discrepancy
|
||||
// - record the sequence
|
||||
// - check ordering.
|
||||
// The second one must be done always, but failed discrepancy
|
||||
// check should exclude the socket from any further checks.
|
||||
// That's why the common check for m_RcvBaseSeqNo != SRT_SEQNO_NONE can't
|
||||
// embrace everything below.
|
||||
|
||||
// We need to first qualify the sequence, just for a case
|
||||
if (m_RcvBaseSeqNo != SRT_SEQNO_NONE && !isValidSeqno(m_RcvBaseSeqNo, mctrl.pktseq))
|
||||
{
|
||||
// This error should be returned if the link turns out
|
||||
// to be the only one, or set to the group data.
|
||||
// err = SRT_ESECFAIL;
|
||||
LOGC(grlog.Error,
|
||||
log << "group/recv: @" << id << ": SEQUENCE DISCREPANCY: base=%" << m_RcvBaseSeqNo
|
||||
<< " vs pkt=%" << mctrl.pktseq << ", setting ESECFAIL");
|
||||
broken.insert(ps);
|
||||
break;
|
||||
}
|
||||
|
||||
// Rewrite it to the state for a case when next reading
|
||||
// would not succeed. Do not insert the buffer here because
|
||||
// this is only required when the sequence is ahead; for that
|
||||
// it will be fixed later.
|
||||
p->mctrl.pktseq = mctrl.pktseq;
|
||||
|
||||
if (m_RcvBaseSeqNo != SRT_SEQNO_NONE)
|
||||
{
|
||||
// Now we can safely check it.
|
||||
const int seqdiff = CSeqNo::seqcmp(mctrl.pktseq, m_RcvBaseSeqNo);
|
||||
|
||||
if (seqdiff <= 0)
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << id << " %" << mctrl.pktseq << " #" << mctrl.msgno
|
||||
<< " BEHIND base=%" << m_RcvBaseSeqNo << " - discarding");
|
||||
// The sequence is recorded, the packet has to be discarded.
|
||||
m_stats.recvDiscard.count(stat);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now we have only two possibilities:
|
||||
// seqdiff == 1: The very next sequence, we want to read and return the packet.
|
||||
// seqdiff > 1: The packet is ahead - record the ahead packet, but continue with the others.
|
||||
|
||||
if (seqdiff > 1)
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "@" << id << " %" << mctrl.pktseq << " #" << mctrl.msgno << " AHEAD base=%"
|
||||
<< m_RcvBaseSeqNo);
|
||||
p->packet.assign(msgbuf, msgbuf + stat);
|
||||
p->mctrl = mctrl;
|
||||
break; // Don't read from that socket anymore.
|
||||
}
|
||||
}
|
||||
|
||||
// We have seqdiff = 1, or we simply have the very first packet
|
||||
// which's sequence is taken as a good deal. Update the sequence
|
||||
// and record output.
|
||||
|
||||
if (output_size)
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << id << " %" << mctrl.pktseq << " #" << mctrl.msgno << " REDUNDANT");
|
||||
break;
|
||||
}
|
||||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << id << " %" << mctrl.pktseq << " #" << mctrl.msgno << " DELIVERING");
|
||||
output_size = stat;
|
||||
fillGroupData((w_mc), mctrl);
|
||||
|
||||
// Update stats as per delivery
|
||||
m_stats.recv.count(output_size);
|
||||
updateAvgPayloadSize(output_size);
|
||||
|
||||
// Record, but do not update yet, until all sockets are handled.
|
||||
next_seq = mctrl.pktseq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
if (!broken.empty())
|
||||
{
|
||||
std::ostringstream brks;
|
||||
for (set<CUDTSocket*>::iterator b = broken.begin(); b != broken.end(); ++b)
|
||||
brks << "@" << (*b)->m_SocketID << " ";
|
||||
LOGC(grlog.Debug, log << "group/recv: REMOVING BROKEN: " << brks.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<SRTSOCKET> brokenid;
|
||||
// Now remove all broken sockets from aheads, if any.
|
||||
// Even if they have already delivered a packet.
|
||||
for (set<CUDTSocket*>::iterator di = broken.begin(); di != broken.end(); ++di)
|
||||
{
|
||||
CUDTSocket* ps = *di;
|
||||
m_Positions.erase(ps->m_SocketID);
|
||||
//ps->setBrokenClosed();
|
||||
}
|
||||
|
||||
// Force closing
|
||||
{
|
||||
InvertedLock ung (m_GroupLock);
|
||||
for (set<CUDTSocket*>::iterator b = broken.begin(); b != broken.end(); ++b)
|
||||
{
|
||||
CUDT::uglobal().close(*b);
|
||||
}
|
||||
}
|
||||
|
||||
if (broken.size() >= size) // This > is for sanity check
|
||||
{
|
||||
// All broken
|
||||
HLOGC(grlog.Debug, log << "group/recv: All sockets broken");
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_ERR, true);
|
||||
|
||||
throw CUDTException(MJ_CONNECTION, MN_CONNLOST, 0);
|
||||
}
|
||||
|
||||
// May be required to be re-read.
|
||||
broken.clear();
|
||||
|
||||
if (output_size)
|
||||
{
|
||||
// We have extracted something, meaning that we have the sequence shift.
|
||||
// Update it now and don't do anything else with the sockets.
|
||||
|
||||
// Sanity check
|
||||
if (next_seq == SRT_SEQNO_NONE)
|
||||
{
|
||||
LOGP(grlog.Error, "IPE: next_seq not set after output extracted!");
|
||||
|
||||
// This should never happen, but the only way to keep the code
|
||||
// safe an recoverable is to use the incremented sequence. By
|
||||
// leaving the sequence as is there's a risk of hangup.
|
||||
// Not doing it in case of SRT_SEQNO_NONE as it would make a valid %0.
|
||||
if (m_RcvBaseSeqNo != SRT_SEQNO_NONE)
|
||||
m_RcvBaseSeqNo = CSeqNo::incseq(m_RcvBaseSeqNo);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RcvBaseSeqNo = next_seq;
|
||||
}
|
||||
|
||||
const ReadPos* pos = checkPacketAhead();
|
||||
if (!pos)
|
||||
{
|
||||
// Don't clear the read-readinsess state if you have a packet ahead because
|
||||
// if you have, the next read call will return it.
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
}
|
||||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: successfully extracted packet size=" << output_size << " - returning");
|
||||
return output_size;
|
||||
}
|
||||
|
||||
HLOGC(grlog.Debug, log << "group/recv: NOT extracted anything - checking for a need to kick kangaroos");
|
||||
|
||||
// Check if we have any sockets left :D
|
||||
|
||||
// Here we surely don't have any more HORSES,
|
||||
// only ELEPHANTS and KANGAROOS. Qualify them and
|
||||
// attempt to at least take advantage of KANGAROOS.
|
||||
|
||||
// In this position all links are either:
|
||||
// - updated to the current position
|
||||
// - updated to the newest possible possition available
|
||||
// - not yet ready for extraction (not present in the group)
|
||||
|
||||
// If we haven't extracted the very next sequence position,
|
||||
// it means that we might only have the ahead packets read,
|
||||
// that is, the next sequence has been dropped by all links.
|
||||
|
||||
if (!m_Positions.empty())
|
||||
{
|
||||
// This might notify both lingering links, which didn't
|
||||
// deliver the required sequence yet, and links that have
|
||||
// the sequence ahead. Review them, and if you find at
|
||||
// least one packet behind, just wait for it to be ready.
|
||||
// Use again the waiting function because we don't want
|
||||
// the general waiting procedure to skip others.
|
||||
set<SRTSOCKET> elephants;
|
||||
|
||||
// const because it's `typename decltype(m_Positions)::value_type`
|
||||
pair<const SRTSOCKET, ReadPos>* slowest_kangaroo = 0;
|
||||
|
||||
for (pit_t rp = m_Positions.begin(); rp != m_Positions.end(); ++rp)
|
||||
{
|
||||
// NOTE that m_RcvBaseSeqNo in this place wasn't updated
|
||||
// because we haven't successfully extracted anything.
|
||||
int seqdiff = CSeqNo::seqcmp(rp->second.mctrl.pktseq, m_RcvBaseSeqNo);
|
||||
if (seqdiff < 0)
|
||||
{
|
||||
elephants.insert(rp->first);
|
||||
}
|
||||
// If seqdiff == 0, we have a socket ON TRACK.
|
||||
else if (seqdiff > 0)
|
||||
{
|
||||
// If there's already a slowest_kangaroo, seqdiff decides if this one is slower.
|
||||
// Otherwise it is always slower by having no competition.
|
||||
seqdiff = slowest_kangaroo
|
||||
? CSeqNo::seqcmp(slowest_kangaroo->second.mctrl.pktseq, rp->second.mctrl.pktseq)
|
||||
: 1;
|
||||
if (seqdiff > 0)
|
||||
{
|
||||
slowest_kangaroo = &*rp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that if no "slowest_kangaroo" was found, it means
|
||||
// that we don't have kangaroos.
|
||||
if (slowest_kangaroo)
|
||||
{
|
||||
// We have a slowest kangaroo. Elephants must be ignored.
|
||||
// Best case, they will get revived, worst case they will be
|
||||
// soon broken.
|
||||
//
|
||||
// As we already have the packet delivered by the slowest
|
||||
// kangaroo, we can simply return it.
|
||||
|
||||
// Check how many were skipped and add them to the stats
|
||||
const int32_t jump = (CSeqNo(slowest_kangaroo->second.mctrl.pktseq) - CSeqNo(m_RcvBaseSeqNo)) - 1;
|
||||
if (jump > 0)
|
||||
{
|
||||
m_stats.recvDrop.count(stats::BytesPackets(jump * static_cast<uint64_t>(avgRcvPacketSize()), jump));
|
||||
LOGC(grlog.Warn,
|
||||
log << "@" << m_GroupID << " GROUP RCV-DROPPED " << jump << " packet(s): seqno %"
|
||||
<< m_RcvBaseSeqNo << " to %" << slowest_kangaroo->second.mctrl.pktseq);
|
||||
}
|
||||
|
||||
m_RcvBaseSeqNo = slowest_kangaroo->second.mctrl.pktseq;
|
||||
vector<char>& pkt = slowest_kangaroo->second.packet;
|
||||
if (size_t(len) < pkt.size())
|
||||
throw CUDTException(MJ_NOTSUP, MN_XSIZE, 0);
|
||||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "@" << slowest_kangaroo->first << " KANGAROO->HORSE %"
|
||||
<< slowest_kangaroo->second.mctrl.pktseq << " #" << slowest_kangaroo->second.mctrl.msgno
|
||||
<< ": " << BufferStamp(&pkt[0], pkt.size()));
|
||||
|
||||
memcpy(buf, &pkt[0], pkt.size());
|
||||
fillGroupData((w_mc), slowest_kangaroo->second.mctrl);
|
||||
len = pkt.size();
|
||||
pkt.clear();
|
||||
|
||||
// Update stats as per delivery
|
||||
m_stats.recv.count(len);
|
||||
updateAvgPayloadSize(len);
|
||||
|
||||
// It is unlikely to have a packet ahead because usually having one packet jumped-ahead
|
||||
// clears the possibility of having aheads at all.
|
||||
// XXX Research if this is possible at all; if it isn't, then don't waste time on
|
||||
// looking for it.
|
||||
const ReadPos* pos = checkPacketAhead();
|
||||
if (!pos)
|
||||
{
|
||||
// Don't clear the read-readinsess state if you have a packet ahead because
|
||||
// if you have, the next read call will return it.
|
||||
m_Global.m_EPoll.update_events(id(), m_sPollID, SRT_EPOLL_IN, false);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: "
|
||||
<< (elephants.empty() ? "NO LINKS REPORTED ANY FRESHER PACKET." : "ALL LINKS ELEPHANTS.")
|
||||
<< " Re-polling.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(grlog.Debug, log << "group/recv: POSITIONS EMPTY - Re-polling.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// [[using locked(m_GroupLock)]]
|
||||
CUDTGroup::ReadPos* CUDTGroup::checkPacketAhead()
|
||||
{
|
||||
typedef map<SRTSOCKET, ReadPos>::iterator pit_t;
|
||||
ReadPos* out = 0;
|
||||
|
||||
// This map no longer maps only ahead links.
|
||||
// Here are all links, and whether ahead, it's defined by the sequence.
|
||||
for (pit_t i = m_Positions.begin(); i != m_Positions.end(); ++i)
|
||||
{
|
||||
// i->first: socket ID
|
||||
// i->second: ReadPos { sequence, packet }
|
||||
// We are not interested with the socket ID because we
|
||||
// aren't going to read from it - we have the packet already.
|
||||
ReadPos& a = i->second;
|
||||
|
||||
const int seqdiff = CSeqNo::seqcmp(a.mctrl.pktseq, m_RcvBaseSeqNo);
|
||||
if (seqdiff == 1)
|
||||
{
|
||||
// The very next packet. Return it.
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: Base %" << m_RcvBaseSeqNo << " ahead delivery POSSIBLE %" << a.mctrl.pktseq
|
||||
<< " #" << a.mctrl.msgno << " from @" << i->first << ")");
|
||||
out = &a;
|
||||
}
|
||||
else if (seqdiff < 1 && !a.packet.empty())
|
||||
{
|
||||
HLOGC(grlog.Debug,
|
||||
log << "group/recv: @" << i->first << " dropping collected ahead %" << a.mctrl.pktseq << "#"
|
||||
<< a.mctrl.msgno << " with base %" << m_RcvBaseSeqNo);
|
||||
a.packet.clear();
|
||||
}
|
||||
// In case when it's >1, keep it in ahead
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const char* CUDTGroup::StateStr(CUDTGroup::GroupState st)
|
||||
{
|
||||
|
@ -3684,7 +3112,7 @@ void CUDTGroup::sendBackup_CheckUnstableSockets(SendBackupCtx& w_sendBackupCtx,
|
|||
<< " is qualified as unstable, but does not have the 'unstable since' timestamp. Still marking for closure.");
|
||||
}
|
||||
|
||||
const int unstable_for_ms = count_milliseconds(currtime - sock.m_tsUnstableSince);
|
||||
const int unstable_for_ms = (int)count_milliseconds(currtime - sock.m_tsUnstableSince);
|
||||
if (unstable_for_ms < sock.peerIdleTimeout_ms())
|
||||
continue;
|
||||
|
||||
|
@ -4399,7 +3827,7 @@ int CUDTGroup::sendBackupRexmit(CUDT& core, SRT_MSGCTRL& w_mc)
|
|||
{
|
||||
// NOTE: an exception from here will interrupt the loop
|
||||
// and will be caught in the upper level.
|
||||
stat = core.sendmsg2(i->data, i->size, (i->mc));
|
||||
stat = core.sendmsg2(i->data, (int)i->size, (i->mc));
|
||||
if (stat == -1)
|
||||
{
|
||||
// Stop sending if one sending ended up with error
|
||||
|
@ -4529,7 +3957,7 @@ void CUDTGroup::updateLatestRcv(CUDTSocket* s)
|
|||
|
||||
HLOGC(grlog.Debug,
|
||||
log << "updateLatestRcv: BACKUP group, updating from active link @" << s->m_SocketID << " with %"
|
||||
<< s->core().m_iRcvLastSkipAck);
|
||||
<< s->core().m_iRcvLastAck);
|
||||
|
||||
CUDT* source = &s->core();
|
||||
vector<CUDT*> targets;
|
||||
|
|
37
trunk/3rdparty/srt-1-fit/srtcore/group.h
vendored
37
trunk/3rdparty/srt-1-fit/srtcore/group.h
vendored
|
@ -155,7 +155,7 @@ public:
|
|||
srt::sync::ScopedLock g(m_GroupLock);
|
||||
|
||||
bool empty = false;
|
||||
HLOGC(gmlog.Debug, log << "group/remove: going to remove @" << id << " from $" << m_GroupID);
|
||||
LOGC(gmlog.Note, log << "group/remove: removing member @" << id << " from group $" << m_GroupID);
|
||||
|
||||
gli_t f = std::find_if(m_Group.begin(), m_Group.end(), HaveID(id));
|
||||
if (f != m_Group.end())
|
||||
|
@ -194,9 +194,6 @@ public:
|
|||
m_bConnected = false;
|
||||
}
|
||||
|
||||
// XXX BUGFIX
|
||||
m_Positions.erase(id);
|
||||
|
||||
return !empty;
|
||||
}
|
||||
|
||||
|
@ -265,7 +262,7 @@ private:
|
|||
/// @param[in] pktseq Packet sequence number currently tried to be sent
|
||||
/// @param[out] w_u CUDT unit of the current member (to allow calling overrideSndSeqNo)
|
||||
/// @param[out] w_curseq Group's current sequence number (either -1 or the value used already for other links)
|
||||
/// @param[out] w_final_stat w_final_stat = send_status if sending succeded.
|
||||
/// @param[out] w_final_stat w_final_stat = send_status if sending succeeded.
|
||||
///
|
||||
/// @returns true if the sending operation result (submitted in stat) is a success, false otherwise.
|
||||
bool sendBackup_CheckSendStatus(const time_point& currtime,
|
||||
|
@ -406,7 +403,9 @@ private:
|
|||
SRTSOCKET m_PeerGroupID;
|
||||
struct GroupContainer
|
||||
{
|
||||
std::list<SocketData> m_List;
|
||||
private:
|
||||
std::list<SocketData> m_List;
|
||||
sync::atomic<size_t> m_SizeCache;
|
||||
|
||||
/// This field is used only by some types of groups that need
|
||||
/// to keep track as to which link was lately used. Note that
|
||||
|
@ -414,8 +413,11 @@ private:
|
|||
/// must be appropriately reset.
|
||||
gli_t m_LastActiveLink;
|
||||
|
||||
public:
|
||||
|
||||
GroupContainer()
|
||||
: m_LastActiveLink(m_List.end())
|
||||
: m_SizeCache(0)
|
||||
, m_LastActiveLink(m_List.end())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -425,18 +427,18 @@ private:
|
|||
gli_t begin() { return m_List.begin(); }
|
||||
gli_t end() { return m_List.end(); }
|
||||
bool empty() { return m_List.empty(); }
|
||||
void push_back(const SocketData& data) { m_List.push_back(data); }
|
||||
void push_back(const SocketData& data) { m_List.push_back(data); ++m_SizeCache; }
|
||||
void clear()
|
||||
{
|
||||
m_LastActiveLink = end();
|
||||
m_List.clear();
|
||||
m_SizeCache = 0;
|
||||
}
|
||||
size_t size() { return m_List.size(); }
|
||||
size_t size() { return m_SizeCache; }
|
||||
|
||||
void erase(gli_t it);
|
||||
};
|
||||
GroupContainer m_Group;
|
||||
const bool m_bSyncOnMsgNo; // It goes into a dedicated HS field. Could be true for balancing groups (not implemented).
|
||||
SRT_GROUP_TYPE m_type;
|
||||
CUDTSocket* m_listener; // A "group" can only have one listener.
|
||||
srt::sync::atomic<int> m_iBusy;
|
||||
|
@ -641,20 +643,6 @@ private:
|
|||
time_point m_tsStartTime;
|
||||
time_point m_tsRcvPeerStartTime;
|
||||
|
||||
struct ReadPos
|
||||
{
|
||||
std::vector<char> packet;
|
||||
SRT_MSGCTRL mctrl;
|
||||
ReadPos(int32_t s)
|
||||
: mctrl(srt_msgctrl_default)
|
||||
{
|
||||
mctrl.pktseq = s;
|
||||
}
|
||||
};
|
||||
std::map<SRTSOCKET, ReadPos> m_Positions;
|
||||
|
||||
ReadPos* checkPacketAhead();
|
||||
|
||||
void recv_CollectAliveAndBroken(std::vector<srt::CUDTSocket*>& w_alive, std::set<srt::CUDTSocket*>& w_broken);
|
||||
|
||||
/// The function polls alive member sockets and retrieves a list of read-ready.
|
||||
|
@ -813,7 +801,6 @@ public:
|
|||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, int32_t, currentSchedSequence, m_iLastSchedSeqNo);
|
||||
SRTU_PROPERTY_RRW(std::set<int>&, epollset, m_sPollID);
|
||||
SRTU_PROPERTY_RW_CHAIN(CUDTGroup, int64_t, latency, m_iTsbPdDelay_us);
|
||||
SRTU_PROPERTY_RO(bool, synconmsgno, m_bSyncOnMsgNo);
|
||||
SRTU_PROPERTY_RO(bool, closing, m_bClosing);
|
||||
};
|
||||
|
||||
|
|
|
@ -140,7 +140,8 @@ const char* srt_rejectreason_name [] = {
|
|||
"CONGESTION",
|
||||
"FILTER",
|
||||
"GROUP",
|
||||
"TIMEOUT"
|
||||
"TIMEOUT",
|
||||
"CRYPTO"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
115
trunk/3rdparty/srt-1-fit/srtcore/list.cpp
vendored
115
trunk/3rdparty/srt-1-fit/srtcore/list.cpp
vendored
|
@ -61,10 +61,12 @@ namespace srt_logging
|
|||
{
|
||||
extern Logger qrlog;
|
||||
extern Logger qslog;
|
||||
extern Logger tslog;
|
||||
}
|
||||
|
||||
using srt_logging::qrlog;
|
||||
using srt_logging::qslog;
|
||||
using srt_logging::tslog;
|
||||
|
||||
using namespace srt::sync;
|
||||
|
||||
|
@ -504,7 +506,7 @@ srt::CRcvLossList::~CRcvLossList()
|
|||
delete[] m_caSeq;
|
||||
}
|
||||
|
||||
void srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
||||
int srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
||||
{
|
||||
// Data to be inserted must be larger than all those in the list
|
||||
if (m_iLargestSeq != SRT_SEQNO_NONE && CSeqNo::seqcmp(seqno1, m_iLargestSeq) <= 0)
|
||||
|
@ -522,7 +524,7 @@ void srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
|||
log << "RCV-LOSS/insert: (" << seqno1 << "," << seqno2
|
||||
<< ") to be inserted is too small: m_iLargestSeq=" << m_iLargestSeq << ", m_iLength=" << m_iLength
|
||||
<< ", m_iHead=" << m_iHead << ", m_iTail=" << m_iTail << " -- REJECTING");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
m_iLargestSeq = seqno2;
|
||||
|
@ -538,19 +540,19 @@ void srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
|||
|
||||
m_caSeq[m_iHead].inext = -1;
|
||||
m_caSeq[m_iHead].iprior = -1;
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
|
||||
return;
|
||||
const int n = CSeqNo::seqlen(seqno1, seqno2);
|
||||
m_iLength += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
// otherwise searching for the position where the node should be
|
||||
int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno1);
|
||||
const int offset = CSeqNo::seqoff(m_caSeq[m_iHead].seqstart, seqno1);
|
||||
if (offset < 0)
|
||||
{
|
||||
LOGC(qrlog.Error,
|
||||
log << "RCV-LOSS/insert: IPE: new LOSS %(" << seqno1 << "-" << seqno2 << ") PREDATES HEAD %"
|
||||
<< m_caSeq[m_iHead].seqstart << " -- REJECTING");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int loc = (m_iHead + offset) % m_iSize;
|
||||
|
@ -575,7 +577,9 @@ void srt::CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
|||
m_iTail = loc;
|
||||
}
|
||||
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
const int n = CSeqNo::seqlen(seqno1, seqno2);
|
||||
m_iLength += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
bool srt::CRcvLossList::remove(int32_t seqno)
|
||||
|
@ -715,20 +719,43 @@ bool srt::CRcvLossList::remove(int32_t seqno)
|
|||
|
||||
bool srt::CRcvLossList::remove(int32_t seqno1, int32_t seqno2)
|
||||
{
|
||||
if (seqno1 <= seqno2)
|
||||
if (CSeqNo::seqcmp(seqno1, seqno2) > 0)
|
||||
{
|
||||
for (int32_t i = seqno1; i <= seqno2; ++i)
|
||||
remove(i);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
for (int32_t i = seqno1; CSeqNo::seqcmp(i, seqno2) <= 0; i = CSeqNo::incseq(i))
|
||||
{
|
||||
for (int32_t j = seqno1; j < CSeqNo::m_iMaxSeqNo; ++j)
|
||||
remove(j);
|
||||
for (int32_t k = 0; k <= seqno2; ++k)
|
||||
remove(k);
|
||||
remove(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t srt::CRcvLossList::removeUpTo(int32_t seqno_last)
|
||||
{
|
||||
int32_t first = getFirstLostSeq();
|
||||
if (first == SRT_SEQNO_NONE)
|
||||
{
|
||||
//HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " - empty list");
|
||||
return first; // empty, so nothing to remove
|
||||
}
|
||||
|
||||
return true;
|
||||
if (CSeqNo::seqcmp(seqno_last, first) < 0)
|
||||
{
|
||||
//HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " - first %" << first << " is newer, exitting");
|
||||
return first; // seqno_last older than first - nothing to remove
|
||||
}
|
||||
|
||||
HLOGC(tslog.Debug, log << "rcv-loss: DROP to %" << seqno_last << " ...");
|
||||
|
||||
// NOTE: seqno_last is past-the-end here. Removed are only seqs
|
||||
// that are earlier than this.
|
||||
for (int32_t i = first; CSeqNo::seqcmp(i, seqno_last) <= 0; i = CSeqNo::incseq(i))
|
||||
{
|
||||
//HLOGC(tslog.Debug, log << "... removing %" << i);
|
||||
remove(i);
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
bool srt::CRcvLossList::find(int32_t seqno1, int32_t seqno2) const
|
||||
|
@ -839,8 +866,10 @@ srt::CRcvFreshLoss::Emod srt::CRcvFreshLoss::revoke(int32_t lo, int32_t hi)
|
|||
// ITEM: <lo, hi> <--- delete
|
||||
// If the sequence range is older than the range to be revoked,
|
||||
// delete it anyway.
|
||||
if (CSeqNo::seqcmp(lo, seq[1]) > 0)
|
||||
if (lo != SRT_SEQNO_NONE && CSeqNo::seqcmp(lo, seq[1]) > 0)
|
||||
return DELETE;
|
||||
// IF <lo> is NONE, then rely simply on that item.hi <% arg.hi,
|
||||
// which is a condition at the end.
|
||||
|
||||
// LOHI: <lo, hi>
|
||||
// ITEM: <lo, hi> <-- NOTFOUND
|
||||
|
@ -868,3 +897,53 @@ srt::CRcvFreshLoss::Emod srt::CRcvFreshLoss::revoke(int32_t lo, int32_t hi)
|
|||
|
||||
return DELETE;
|
||||
}
|
||||
|
||||
bool srt::CRcvFreshLoss::removeOne(std::deque<CRcvFreshLoss>& w_container, int32_t sequence, int* pw_had_ttl)
|
||||
{
|
||||
for (size_t i = 0; i < w_container.size(); ++i)
|
||||
{
|
||||
const int had_ttl = w_container[i].ttl;
|
||||
Emod wh = w_container[i].revoke(sequence);
|
||||
|
||||
if (wh == NONE)
|
||||
continue; // Not found. Search again.
|
||||
|
||||
if (wh == DELETE) // ... oo ... x ... o ... => ... oo ... o ...
|
||||
{
|
||||
// Removed the only element in the record - remove the record.
|
||||
w_container.erase(w_container.begin() + i);
|
||||
}
|
||||
else if (wh == SPLIT) // ... ooxooo ... => ... oo ... ooo ...
|
||||
{
|
||||
// Create a new element that will hold the upper part of the range,
|
||||
// and the found one modify to be the lower part of the range.
|
||||
|
||||
// Keep the current end-of-sequence value for the second element
|
||||
int32_t next_end = w_container[i].seq[1];
|
||||
|
||||
// seq-1 set to the end of this element
|
||||
w_container[i].seq[1] = CSeqNo::decseq(sequence);
|
||||
// seq+1 set to the begin of the next element
|
||||
int32_t next_begin = CSeqNo::incseq(sequence);
|
||||
|
||||
// Use position of the NEXT element because insertion happens BEFORE pointed element.
|
||||
// Use the same TTL (will stay the same in the other one).
|
||||
w_container.insert(w_container.begin() + i + 1,
|
||||
CRcvFreshLoss(next_begin, next_end, w_container[i].ttl));
|
||||
}
|
||||
// For STRIPPED: ... xooo ... => ... ooo ...
|
||||
// i.e. there's nothing to do.
|
||||
|
||||
// Every loss is unique. We're done here.
|
||||
if (pw_had_ttl)
|
||||
*pw_had_ttl = had_ttl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pw_had_ttl)
|
||||
*pw_had_ttl = 0;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
|
22
trunk/3rdparty/srt-1-fit/srtcore/list.h
vendored
22
trunk/3rdparty/srt-1-fit/srtcore/list.h
vendored
|
@ -53,6 +53,8 @@ modified by
|
|||
#ifndef INC_SRT_LIST_H
|
||||
#define INC_SRT_LIST_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "udt.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -84,6 +86,12 @@ public:
|
|||
|
||||
void traceState() const;
|
||||
|
||||
// Debug/unittest support.
|
||||
|
||||
int head() const { return m_iHead; }
|
||||
int next(int loc) const { return m_caSeq[loc].inext; }
|
||||
int last() const { return m_iLastInsertPos; }
|
||||
|
||||
private:
|
||||
struct Seq
|
||||
{
|
||||
|
@ -118,6 +126,8 @@ private:
|
|||
/// @param seqno2 last sequence number in range (SRT_SEQNO_NONE if no range)
|
||||
bool updateElement(int pos, int32_t seqno1, int32_t seqno2);
|
||||
|
||||
static const int LOC_NONE = -1;
|
||||
|
||||
private:
|
||||
CSndLossList(const CSndLossList&);
|
||||
CSndLossList& operator=(const CSndLossList&);
|
||||
|
@ -134,8 +144,8 @@ public:
|
|||
/// Insert a series of loss seq. no. between "seqno1" and "seqno2" into the receiver's loss list.
|
||||
/// @param [in] seqno1 sequence number starts.
|
||||
/// @param [in] seqno2 seqeunce number ends.
|
||||
|
||||
void insert(int32_t seqno1, int32_t seqno2);
|
||||
/// @return length of the loss record inserted (seqlen(seqno1, seqno2)), -1 on error.
|
||||
int insert(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
/// Remove a loss seq. no. from the receiver's loss list.
|
||||
/// @param [in] seqno sequence number.
|
||||
|
@ -150,6 +160,12 @@ public:
|
|||
|
||||
bool remove(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
|
||||
/// Remove all numbers that precede the given sequence number.
|
||||
/// @param [in] seqno sequence number.
|
||||
/// @return the first removed sequence number
|
||||
int32_t removeUpTo(int32_t seqno);
|
||||
|
||||
/// Find if there is any lost packets whose sequence number falling seqno1 and seqno2.
|
||||
/// @param [in] seqno1 start sequence number.
|
||||
/// @param [in] seqno2 end sequence number.
|
||||
|
@ -264,6 +280,8 @@ struct CRcvFreshLoss
|
|||
|
||||
Emod revoke(int32_t sequence);
|
||||
Emod revoke(int32_t lo, int32_t hi);
|
||||
|
||||
static bool removeOne(std::deque<CRcvFreshLoss>& w_container, int32_t sequence, int* had_ttl = NULL);
|
||||
};
|
||||
|
||||
} // namespace srt
|
||||
|
|
29
trunk/3rdparty/srt-1-fit/srtcore/logging.h
vendored
29
trunk/3rdparty/srt-1-fit/srtcore/logging.h
vendored
|
@ -60,6 +60,7 @@ written by
|
|||
|
||||
// LOGF uses printf-like style formatting.
|
||||
// Usage: LOGF(gglog.Debug, "%s: %d", param1.c_str(), int(param2));
|
||||
// NOTE: LOGF is deprecated and should not be used
|
||||
#define LOGF(logdes, ...) if (logdes.CheckEnabled()) logdes().setloc(__FILE__, __LINE__, __FUNCTION__).form(__VA_ARGS__)
|
||||
|
||||
// LOGP is C++11 only OR with only one string argument.
|
||||
|
@ -165,14 +166,24 @@ public:
|
|||
|
||||
// See Logger::Logger; we know this has normally 2 characters,
|
||||
// except !!FATAL!!, which has 9. Still less than 32.
|
||||
strcpy(prefix, your_pfx);
|
||||
|
||||
// If the size of the FA name together with severity exceeds the size,
|
||||
// just skip the former.
|
||||
if (logger_pfx && strlen(prefix) + strlen(logger_pfx) + 1 < MAX_PREFIX_SIZE)
|
||||
{
|
||||
strcat(prefix, ":");
|
||||
strcat(prefix, logger_pfx);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
_snprintf(prefix, MAX_PREFIX_SIZE, "%s:%s", your_pfx, logger_pfx);
|
||||
#else
|
||||
snprintf(prefix, MAX_PREFIX_SIZE + 1, "%s:%s", your_pfx, logger_pfx);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
strncpy_s(prefix, MAX_PREFIX_SIZE + 1, your_pfx, _TRUNCATE);
|
||||
#else
|
||||
strncpy(prefix, your_pfx, MAX_PREFIX_SIZE);
|
||||
prefix[MAX_PREFIX_SIZE] = '\0';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +253,9 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
DummyProxy& form(const char*, ...)
|
||||
// DEPRECATED: DO NOT use LOGF/HLOGF macros anymore.
|
||||
// Use iostream-style formatting with LOGC or a direct argument with LOGP.
|
||||
SRT_ATR_DEPRECATED_PX DummyProxy& form(const char*, ...) SRT_ATR_DEPRECATED
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
@ -356,7 +369,11 @@ struct LogDispatcher::Proxy
|
|||
{
|
||||
char buf[512];
|
||||
|
||||
vsprintf(buf, fmts, ap);
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
_vsnprintf(buf, sizeof(buf) - 1, fmts, ap);
|
||||
#else
|
||||
vsnprintf(buf, sizeof(buf), fmts, ap);
|
||||
#endif
|
||||
size_t len = strlen(buf);
|
||||
if ( buf[len-1] == '\n' )
|
||||
{
|
||||
|
|
368
trunk/3rdparty/srt-1-fit/srtcore/md5.cpp
vendored
368
trunk/3rdparty/srt-1-fit/srtcore/md5.cpp
vendored
|
@ -27,7 +27,7 @@
|
|||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
|
@ -38,165 +38,166 @@
|
|||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* All symbols have been put under the srt namespace
|
||||
* to avoid potential linkage conflicts.
|
||||
*/
|
||||
namespace srt {
|
||||
namespace srt
|
||||
{
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#ifdef ARCH_IS_BIG_ENDIAN
|
||||
# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
|
||||
#else
|
||||
# define BYTE_ORDER 0
|
||||
#define BYTE_ORDER 0
|
||||
#endif
|
||||
|
||||
#define T_MASK ((md5_word_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
static void
|
||||
md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
||||
static void md5_process(md5_state_t* pms, const md5_byte_t* data /*[64]*/)
|
||||
{
|
||||
md5_word_t
|
||||
a = pms->abcd[0], b = pms->abcd[1],
|
||||
c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3];
|
||||
md5_word_t t;
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
md5_word_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t *X;
|
||||
md5_word_t xbuf[16];
|
||||
const md5_word_t* X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
|
||||
if (*((const md5_byte_t*)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const md5_byte_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
X = (const md5_word_t *)data;
|
||||
} else {
|
||||
/* not aligned */
|
||||
memcpy((xbuf), data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!(uintptr_t(data) & 3))
|
||||
{
|
||||
/* data are properly aligned */
|
||||
X = (const md5_word_t*)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not aligned */
|
||||
memcpy((xbuf), data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t *xp = data;
|
||||
int i;
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const md5_byte_t* xp = data;
|
||||
int i;
|
||||
|
||||
# if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
#else
|
||||
#define xbuf X /* (static only) */
|
||||
#endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -206,184 +207,179 @@ md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
|
|||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + F(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + G(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + H(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
#define SET(a, b, c, d, k, s, Ti) \
|
||||
t = a + I(b, c, d) + X[k] + Ti; \
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
void
|
||||
md5_init(md5_state_t *pms)
|
||||
void md5_init(md5_state_t* pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
|
||||
void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes)
|
||||
{
|
||||
const md5_byte_t *p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
const md5_byte_t* p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
md5_word_t nbits = (md5_word_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
if (offset)
|
||||
{
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy((pms->buf + offset), p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
memcpy((pms->buf + offset), p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy((pms->buf), p, left);
|
||||
memcpy((pms->buf), p, left);
|
||||
}
|
||||
|
||||
void
|
||||
md5_finish(md5_state_t *pms, md5_byte_t digest[16])
|
||||
void md5_finish(md5_state_t* pms, md5_byte_t digest[16])
|
||||
{
|
||||
static const md5_byte_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
md5_byte_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
md5_append(pms, data, 8);
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
|
32
trunk/3rdparty/srt-1-fit/srtcore/md5.h
vendored
32
trunk/3rdparty/srt-1-fit/srtcore/md5.h
vendored
|
@ -27,7 +27,7 @@
|
|||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
|
@ -38,23 +38,24 @@
|
|||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#ifndef md5_INCLUDED
|
||||
# define md5_INCLUDED
|
||||
#define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* All symbols have been put under the srt namespace
|
||||
* to avoid potential linkage conflicts.
|
||||
*/
|
||||
namespace srt {
|
||||
namespace srt
|
||||
{
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
|
@ -67,23 +68,24 @@ namespace srt {
|
|||
*/
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
typedef unsigned int md5_word_t; /* 32-bit word */
|
||||
|
||||
/* Define the state of the MD5 Algorithm. */
|
||||
typedef struct md5_state_s {
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
typedef struct md5_state_s
|
||||
{
|
||||
md5_word_t count[2]; /* message length in bits, lsw first */
|
||||
md5_word_t abcd[4]; /* digest buffer */
|
||||
md5_byte_t buf[64]; /* accumulate block */
|
||||
} md5_state_t;
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
void md5_init(md5_state_t *pms);
|
||||
void md5_init(md5_state_t* pms);
|
||||
|
||||
/* Append a string to the message. */
|
||||
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
|
||||
void md5_append(md5_state_t* pms, const md5_byte_t* data, int nbytes);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
void md5_finish(md5_state_t* pms, md5_byte_t digest[16]);
|
||||
|
||||
} // namespace srt
|
||||
|
||||
|
|
161
trunk/3rdparty/srt-1-fit/srtcore/packet.cpp
vendored
161
trunk/3rdparty/srt-1-fit/srtcore/packet.cpp
vendored
|
@ -151,11 +151,11 @@ modified by
|
|||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// Loss List Field Coding:
|
||||
// For any consectutive lost seqeunce numbers that the differnece between
|
||||
// For any consecutive lost seqeunce numbers that the differnece between
|
||||
// the last and first is more than 1, only record the first (a) and the
|
||||
// the last (b) sequence numbers in the loss list field, and modify the
|
||||
// the first bit of a to 1.
|
||||
// For any single loss or consectutive loss less than 2 packets, use
|
||||
// For any single loss or consecutive loss less than 2 packets, use
|
||||
// the original sequence numbers in the field.
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
@ -172,9 +172,12 @@ extern Logger inlog;
|
|||
}
|
||||
using namespace srt_logging;
|
||||
|
||||
namespace srt {
|
||||
|
||||
// Set up the aliases in the constructure
|
||||
srt::CPacket::CPacket()
|
||||
: m_extra_pad()
|
||||
CPacket::CPacket()
|
||||
: m_nHeader() // Silences GCC 12 warning "used uninitialized".
|
||||
, m_extra_pad()
|
||||
, m_data_owned(false)
|
||||
, m_iSeqNo((int32_t&)(m_nHeader[SRT_PH_SEQNO]))
|
||||
, m_iMsgNo((int32_t&)(m_nHeader[SRT_PH_MSGNO]))
|
||||
|
@ -194,12 +197,12 @@ srt::CPacket::CPacket()
|
|||
m_PacketVector[PV_DATA].set(NULL, 0);
|
||||
}
|
||||
|
||||
char* srt::CPacket::getData()
|
||||
char* CPacket::getData()
|
||||
{
|
||||
return (char*)m_PacketVector[PV_DATA].dataRef();
|
||||
}
|
||||
|
||||
void srt::CPacket::allocate(size_t alloc_buffer_size)
|
||||
void CPacket::allocate(size_t alloc_buffer_size)
|
||||
{
|
||||
if (m_data_owned)
|
||||
{
|
||||
|
@ -213,14 +216,15 @@ void srt::CPacket::allocate(size_t alloc_buffer_size)
|
|||
m_data_owned = true;
|
||||
}
|
||||
|
||||
void srt::CPacket::deallocate()
|
||||
void CPacket::deallocate()
|
||||
{
|
||||
if (m_data_owned)
|
||||
delete[](char*) m_PacketVector[PV_DATA].data();
|
||||
m_PacketVector[PV_DATA].set(NULL, 0);
|
||||
m_data_owned = false;
|
||||
}
|
||||
|
||||
char* srt::CPacket::release()
|
||||
char* CPacket::release()
|
||||
{
|
||||
// When not owned, release returns NULL.
|
||||
char* buffer = NULL;
|
||||
|
@ -234,31 +238,99 @@ char* srt::CPacket::release()
|
|||
return buffer;
|
||||
}
|
||||
|
||||
srt::CPacket::~CPacket()
|
||||
CPacket::~CPacket()
|
||||
{
|
||||
// PV_HEADER is always owned, PV_DATA may use a "borrowed" buffer.
|
||||
// Delete the internal buffer only if it was declared as owned.
|
||||
if (m_data_owned)
|
||||
delete[](char*) m_PacketVector[PV_DATA].data();
|
||||
deallocate();
|
||||
}
|
||||
|
||||
size_t srt::CPacket::getLength() const
|
||||
size_t CPacket::getLength() const
|
||||
{
|
||||
return m_PacketVector[PV_DATA].size();
|
||||
}
|
||||
|
||||
void srt::CPacket::setLength(size_t len)
|
||||
void CPacket::setLength(size_t len)
|
||||
{
|
||||
m_PacketVector[PV_DATA].setLength(len);
|
||||
}
|
||||
|
||||
void srt::CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size)
|
||||
void CPacket::setLength(size_t len, size_t cap)
|
||||
{
|
||||
SRT_ASSERT(len <= cap);
|
||||
setLength(len);
|
||||
m_zCapacity = cap;
|
||||
}
|
||||
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
// Debug only
|
||||
static std::string FormatNumbers(UDTMessageType pkttype, const int32_t* lparam, void* rparam, const size_t size)
|
||||
{
|
||||
// This may be changed over time, so use special interpretation
|
||||
// only for certain types, and still display all data, no matter
|
||||
// if it is expected to provide anything or not.
|
||||
std::ostringstream out;
|
||||
|
||||
out << "ARG=";
|
||||
if (lparam)
|
||||
out << *lparam;
|
||||
else
|
||||
out << "none";
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
out << " [no data]";
|
||||
return out.str();
|
||||
}
|
||||
else if (!rparam)
|
||||
{
|
||||
out << " [ {" << size << "} ]";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
bool interp_as_seq = (pkttype == UMSG_LOSSREPORT || pkttype == UMSG_DROPREQ);
|
||||
bool display_dec = (pkttype == UMSG_ACK || pkttype == UMSG_ACKACK || pkttype == UMSG_DROPREQ);
|
||||
|
||||
out << " [ ";
|
||||
|
||||
// Will be effective only for hex/oct.
|
||||
out << std::showbase;
|
||||
|
||||
const size_t size32 = size/4;
|
||||
for (size_t i = 0; i < size32; ++i)
|
||||
{
|
||||
int32_t val = ((int32_t*)rparam)[i];
|
||||
if (interp_as_seq)
|
||||
{
|
||||
if (val & LOSSDATA_SEQNO_RANGE_FIRST)
|
||||
out << "<" << (val & (~LOSSDATA_SEQNO_RANGE_FIRST)) << ">";
|
||||
else
|
||||
out << val;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!display_dec)
|
||||
{
|
||||
out << std::hex;
|
||||
out << val << "/";
|
||||
out << std::dec;
|
||||
}
|
||||
out << val;
|
||||
|
||||
}
|
||||
out << " ";
|
||||
}
|
||||
|
||||
out << "]";
|
||||
return out.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
void CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rparam, size_t size)
|
||||
{
|
||||
// Set (bit-0 = 1) and (bit-1~15 = type)
|
||||
setControl(pkttype);
|
||||
HLOGC(inlog.Debug,
|
||||
log << "pack: type=" << MessageTypeStr(pkttype) << " ARG=" << (lparam ? Sprint(*lparam) : std::string("NULL"))
|
||||
<< " [ " << (rparam ? Sprint(*(int32_t*)rparam) : std::string()) << " ]");
|
||||
HLOGC(inlog.Debug, log << "pack: type=" << MessageTypeStr(pkttype) << " " << FormatNumbers(pkttype, lparam, rparam, size));
|
||||
|
||||
// Set additional information and control information field
|
||||
switch (pkttype)
|
||||
|
@ -364,7 +436,7 @@ void srt::CPacket::pack(UDTMessageType pkttype, const int32_t* lparam, void* rpa
|
|||
}
|
||||
}
|
||||
|
||||
void srt::CPacket::toNL()
|
||||
void CPacket::toNL()
|
||||
{
|
||||
// XXX USE HtoNLA!
|
||||
if (isControl())
|
||||
|
@ -382,7 +454,7 @@ void srt::CPacket::toNL()
|
|||
}
|
||||
}
|
||||
|
||||
void srt::CPacket::toHL()
|
||||
void CPacket::toHL()
|
||||
{
|
||||
// convert back into local host order
|
||||
uint32_t* p = m_nHeader;
|
||||
|
@ -399,22 +471,22 @@ void srt::CPacket::toHL()
|
|||
}
|
||||
}
|
||||
|
||||
srt::IOVector* srt::CPacket::getPacketVector()
|
||||
IOVector* CPacket::getPacketVector()
|
||||
{
|
||||
return m_PacketVector;
|
||||
}
|
||||
|
||||
srt::UDTMessageType srt::CPacket::getType() const
|
||||
UDTMessageType CPacket::getType() const
|
||||
{
|
||||
return UDTMessageType(SEQNO_MSGTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]));
|
||||
}
|
||||
|
||||
int srt::CPacket::getExtendedType() const
|
||||
int CPacket::getExtendedType() const
|
||||
{
|
||||
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
|
||||
}
|
||||
|
||||
int32_t srt::CPacket::getAckSeqNo() const
|
||||
int32_t CPacket::getAckSeqNo() const
|
||||
{
|
||||
// read additional information field
|
||||
// This field is used only in UMSG_ACK and UMSG_ACKACK,
|
||||
|
@ -423,7 +495,7 @@ int32_t srt::CPacket::getAckSeqNo() const
|
|||
return m_nHeader[SRT_PH_MSGNO];
|
||||
}
|
||||
|
||||
uint16_t srt::CPacket::getControlFlags() const
|
||||
uint16_t CPacket::getControlFlags() const
|
||||
{
|
||||
// This returns exactly the "extended type" value,
|
||||
// which is not used at all in case when the standard
|
||||
|
@ -432,17 +504,17 @@ uint16_t srt::CPacket::getControlFlags() const
|
|||
return SEQNO_EXTTYPE::unwrap(m_nHeader[SRT_PH_SEQNO]);
|
||||
}
|
||||
|
||||
srt::PacketBoundary srt::CPacket::getMsgBoundary() const
|
||||
PacketBoundary CPacket::getMsgBoundary() const
|
||||
{
|
||||
return PacketBoundary(MSGNO_PACKET_BOUNDARY::unwrap(m_nHeader[SRT_PH_MSGNO]));
|
||||
}
|
||||
|
||||
bool srt::CPacket::getMsgOrderFlag() const
|
||||
bool CPacket::getMsgOrderFlag() const
|
||||
{
|
||||
return 0 != MSGNO_PACKET_INORDER::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
}
|
||||
|
||||
int32_t srt::CPacket::getMsgSeq(bool has_rexmit) const
|
||||
int32_t CPacket::getMsgSeq(bool has_rexmit) const
|
||||
{
|
||||
if (has_rexmit)
|
||||
{
|
||||
|
@ -454,13 +526,18 @@ int32_t srt::CPacket::getMsgSeq(bool has_rexmit) const
|
|||
}
|
||||
}
|
||||
|
||||
bool srt::CPacket::getRexmitFlag() const
|
||||
bool CPacket::getRexmitFlag() const
|
||||
{
|
||||
// return false; //
|
||||
return 0 != MSGNO_REXMIT::unwrap(m_nHeader[SRT_PH_MSGNO]);
|
||||
}
|
||||
|
||||
srt::EncryptionKeySpec srt::CPacket::getMsgCryptoFlags() const
|
||||
void CPacket::setRexmitFlag(bool bRexmit)
|
||||
{
|
||||
const int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_REXMIT::mask;
|
||||
m_nHeader[SRT_PH_MSGNO] = clr_msgno | MSGNO_REXMIT::wrap(bRexmit? 1 : 0);
|
||||
}
|
||||
|
||||
EncryptionKeySpec CPacket::getMsgCryptoFlags() const
|
||||
{
|
||||
return EncryptionKeySpec(MSGNO_ENCKEYSPEC::unwrap(m_nHeader[SRT_PH_MSGNO]));
|
||||
}
|
||||
|
@ -468,32 +545,30 @@ srt::EncryptionKeySpec srt::CPacket::getMsgCryptoFlags() const
|
|||
// This is required as the encryption/decryption happens in place.
|
||||
// This is required to clear off the flags after decryption or set
|
||||
// crypto flags after encrypting a packet.
|
||||
void srt::CPacket::setMsgCryptoFlags(EncryptionKeySpec spec)
|
||||
void CPacket::setMsgCryptoFlags(EncryptionKeySpec spec)
|
||||
{
|
||||
int32_t clr_msgno = m_nHeader[SRT_PH_MSGNO] & ~MSGNO_ENCKEYSPEC::mask;
|
||||
m_nHeader[SRT_PH_MSGNO] = clr_msgno | EncryptionKeyBits(spec);
|
||||
}
|
||||
|
||||
uint32_t srt::CPacket::getMsgTimeStamp() const
|
||||
uint32_t CPacket::getMsgTimeStamp() const
|
||||
{
|
||||
// SRT_DEBUG_TSBPD_WRAP may enable smaller timestamp for faster wraparoud handling tests
|
||||
// SRT_DEBUG_TSBPD_WRAP used to enable smaller timestamps for faster testing of how wraparounds are handled
|
||||
return (uint32_t)m_nHeader[SRT_PH_TIMESTAMP] & TIMESTAMP_MASK;
|
||||
}
|
||||
|
||||
srt::CPacket* srt::CPacket::clone() const
|
||||
CPacket* CPacket::clone() const
|
||||
{
|
||||
CPacket* pkt = new CPacket;
|
||||
memcpy((pkt->m_nHeader), m_nHeader, HDR_SIZE);
|
||||
pkt->m_pcData = new char[m_PacketVector[PV_DATA].size()];
|
||||
memcpy((pkt->m_pcData), m_pcData, m_PacketVector[PV_DATA].size());
|
||||
pkt->m_PacketVector[PV_DATA].setLength(m_PacketVector[PV_DATA].size());
|
||||
pkt->allocate(this->getLength());
|
||||
SRT_ASSERT(this->getLength() == pkt->getLength());
|
||||
memcpy((pkt->m_pcData), m_pcData, this->getLength());
|
||||
pkt->m_DestAddr = m_DestAddr;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
namespace srt
|
||||
{
|
||||
|
||||
// Useful for debugging
|
||||
std::string PacketMessageFlagStr(uint32_t msgno_field)
|
||||
{
|
||||
|
@ -522,10 +597,8 @@ inline void SprintSpecialWord(std::ostream& os, int32_t val)
|
|||
os << val;
|
||||
}
|
||||
|
||||
} // namespace srt
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
std::string srt::CPacket::Info()
|
||||
std::string CPacket::Info()
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "TARGET=@" << m_iID << " ";
|
||||
|
@ -580,3 +653,5 @@ std::string srt::CPacket::Info()
|
|||
return os.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace srt
|
||||
|
|
15
trunk/3rdparty/srt-1-fit/srtcore/packet.h
vendored
15
trunk/3rdparty/srt-1-fit/srtcore/packet.h
vendored
|
@ -150,7 +150,7 @@ const int32_t LOSSDATA_SEQNO_RANGE_LAST = 0, LOSSDATA_SEQNO_SOLO = 0;
|
|||
|
||||
inline int32_t CreateControlSeqNo(UDTMessageType type)
|
||||
{
|
||||
return SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(size_t(type));
|
||||
return SEQNO_CONTROL::mask | SEQNO_MSGTYPE::wrap(uint32_t(type));
|
||||
}
|
||||
|
||||
inline int32_t CreateControlExtSeqNo(int exttype)
|
||||
|
@ -236,6 +236,11 @@ public:
|
|||
/// @param len [in] the payload or the control information field length.
|
||||
void setLength(size_t len);
|
||||
|
||||
/// Set the payload or the control information field length.
|
||||
/// @param len [in] the payload or the control information field length.
|
||||
/// @param cap [in] capacity (if known).
|
||||
void setLength(size_t len, size_t cap);
|
||||
|
||||
/// Pack a Control packet.
|
||||
/// @param pkttype [in] packet type filed.
|
||||
/// @param lparam [in] pointer to the first data structure, explained by the packet type.
|
||||
|
@ -286,6 +291,8 @@ public:
|
|||
/// (because the peer will understand this bit as a part of MSGNO field).
|
||||
bool getRexmitFlag() const;
|
||||
|
||||
void setRexmitFlag(bool bRexmit);
|
||||
|
||||
/// Read the message sequence number.
|
||||
/// @return packet header field [1]
|
||||
int32_t getMsgSeq(bool has_rexmit = true) const;
|
||||
|
@ -300,6 +307,8 @@ public:
|
|||
/// @return packet header field [2] (bit 0~31, bit 0-26 if SRT_DEBUG_TSBPD_WRAP).
|
||||
uint32_t getMsgTimeStamp() const;
|
||||
|
||||
sockaddr_any udpDestAddr() const { return m_DestAddr; }
|
||||
|
||||
#ifdef SRT_DEBUG_TSBPD_WRAP // Receiver
|
||||
static const uint32_t MAX_TIMESTAMP = 0x07FFFFFF; // 27 bit fast wraparound for tests (~2m15s)
|
||||
#else
|
||||
|
@ -335,6 +344,8 @@ protected:
|
|||
|
||||
int32_t m_extra_pad;
|
||||
bool m_data_owned;
|
||||
sockaddr_any m_DestAddr;
|
||||
size_t m_zCapacity;
|
||||
|
||||
protected:
|
||||
CPacket& operator=(const CPacket&);
|
||||
|
@ -368,6 +379,8 @@ public:
|
|||
char* data() { return m_pcData; }
|
||||
const char* data() const { return m_pcData; }
|
||||
size_t size() const { return getLength(); }
|
||||
size_t capacity() const { return m_zCapacity; }
|
||||
void setCapacity(size_t cap) { m_zCapacity = cap; }
|
||||
uint32_t header(SrtPktHeaderFields field) const { return m_nHeader[field]; }
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace std;
|
|||
using namespace srt_logging;
|
||||
using namespace srt::sync;
|
||||
|
||||
bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf)
|
||||
bool srt::ParseFilterConfig(const string& s, SrtFilterConfig& w_config, PacketFilter::Factory** ppf)
|
||||
{
|
||||
if (!SrtParseConfig(s, (w_config)))
|
||||
return false;
|
||||
|
@ -43,7 +43,7 @@ bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config, PacketFilter::F
|
|||
return true;
|
||||
}
|
||||
|
||||
bool srt::ParseFilterConfig(string s, SrtFilterConfig& w_config)
|
||||
bool srt::ParseFilterConfig(const string& s, SrtFilterConfig& w_config)
|
||||
{
|
||||
return ParseFilterConfig(s, (w_config), NULL);
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ void srt::PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, lo
|
|||
{
|
||||
// For the sake of rebuilding MARK THIS UNIT GOOD, otherwise the
|
||||
// unit factory will supply it from getNextAvailUnit() as if it were not in use.
|
||||
unit->m_iFlag = CUnit::GOOD;
|
||||
unit->m_bTaken = true;
|
||||
HLOGC(pflog.Debug, log << "FILTER: PASSTHRU current packet %" << unit->m_Packet.getSeqNo());
|
||||
w_incoming.push_back(unit);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ void srt::PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, lo
|
|||
InsertRebuilt(w_incoming, m_unitq);
|
||||
|
||||
ScopedLock lg(m_parent->m_StatsLock);
|
||||
m_parent->m_stats.rcvr.suppliedByFilter.count(nsupply);
|
||||
m_parent->m_stats.rcvr.suppliedByFilter.count((uint32_t)nsupply);
|
||||
}
|
||||
|
||||
// Now that all units have been filled as they should be,
|
||||
|
@ -178,11 +178,11 @@ void srt::PacketFilter::receive(CUnit* unit, std::vector<CUnit*>& w_incoming, lo
|
|||
// Wanted units will be set GOOD flag, unwanted will remain
|
||||
// with FREE and therefore will be returned at the next
|
||||
// call to getNextAvailUnit().
|
||||
unit->m_iFlag = CUnit::FREE;
|
||||
unit->m_bTaken = false;
|
||||
for (vector<CUnit*>::iterator i = w_incoming.begin(); i != w_incoming.end(); ++i)
|
||||
{
|
||||
CUnit* u = *i;
|
||||
u->m_iFlag = CUnit::FREE;
|
||||
u->m_bTaken = false;
|
||||
}
|
||||
|
||||
// Packets must be sorted by sequence number, ascending, in order
|
||||
|
@ -251,9 +251,9 @@ void srt::PacketFilter::InsertRebuilt(vector<CUnit*>& incoming, CUnitQueue* uq)
|
|||
break;
|
||||
}
|
||||
|
||||
// LOCK the unit as GOOD because otherwise the next
|
||||
// LOCK the unit as taken because otherwise the next
|
||||
// call to getNextAvailUnit will return THE SAME UNIT.
|
||||
u->m_iFlag = CUnit::GOOD;
|
||||
u->m_bTaken = true;
|
||||
// After returning from this function, all units will be
|
||||
// set back to FREE so that the buffer can decide whether
|
||||
// it wants them or not.
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
virtual ~Factory();
|
||||
};
|
||||
private:
|
||||
friend bool ParseFilterConfig(std::string s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
friend bool ParseFilterConfig(const std::string& s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
|
||||
template <class Target>
|
||||
class Creator: public Factory
|
||||
|
@ -212,7 +212,7 @@ bool CheckFilterCompat(SrtFilterConfig& w_agent, SrtFilterConfig peer);
|
|||
inline void PacketFilter::feedSource(CPacket& w_packet) { SRT_ASSERT(m_filter); return m_filter->feedSource((w_packet)); }
|
||||
inline SRT_ARQLevel PacketFilter::arqLevel() { SRT_ASSERT(m_filter); return m_filter->arqLevel(); }
|
||||
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
bool ParseFilterConfig(const std::string& s, SrtFilterConfig& out, PacketFilter::Factory** ppf);
|
||||
|
||||
} // namespace srt
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ struct SrtPacket
|
|||
};
|
||||
|
||||
|
||||
bool ParseFilterConfig(std::string s, SrtFilterConfig& w_config);
|
||||
bool ParseFilterConfig(const std::string& s, SrtFilterConfig& w_config);
|
||||
|
||||
|
||||
class SrtPacketFilterBase
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 // silences windows complaints for sscanf
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <ws2ipdef.h>
|
||||
|
@ -40,9 +39,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable: 4251 26812)
|
||||
#endif
|
||||
#else
|
||||
|
||||
#if defined(__APPLE__) && __APPLE__
|
||||
|
|
195
trunk/3rdparty/srt-1-fit/srtcore/queue.cpp
vendored
195
trunk/3rdparty/srt-1-fit/srtcore/queue.cpp
vendored
|
@ -125,7 +125,7 @@ srt::CUnitQueue::CQEntry* srt::CUnitQueue::allocateEntry(const int iNumUnits, co
|
|||
|
||||
for (int i = 0; i < iNumUnits; ++i)
|
||||
{
|
||||
tempu[i].m_iFlag = CUnit::FREE;
|
||||
tempu[i].m_bTaken = false;
|
||||
tempu[i].m_Packet.m_pcData = tempb + i * mss;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ srt::CUnit* srt::CUnitQueue::getNextAvailUnit()
|
|||
const CUnit* end = m_pCurrQueue->m_pUnit + m_pCurrQueue->m_iSize;
|
||||
for (; m_pAvailUnit != end; ++m_pAvailUnit, ++units_checked)
|
||||
{
|
||||
if (m_pAvailUnit->m_iFlag == CUnit::FREE)
|
||||
if (!m_pAvailUnit->m_bTaken)
|
||||
{
|
||||
return m_pAvailUnit;
|
||||
}
|
||||
|
@ -188,19 +188,19 @@ srt::CUnit* srt::CUnitQueue::getNextAvailUnit()
|
|||
void srt::CUnitQueue::makeUnitFree(CUnit* unit)
|
||||
{
|
||||
SRT_ASSERT(unit != NULL);
|
||||
SRT_ASSERT(unit->m_iFlag != CUnit::FREE);
|
||||
unit->m_iFlag.store(CUnit::FREE);
|
||||
SRT_ASSERT(unit->m_bTaken);
|
||||
unit->m_bTaken.store(false);
|
||||
|
||||
--m_iNumTaken;
|
||||
}
|
||||
|
||||
void srt::CUnitQueue::makeUnitGood(CUnit* unit)
|
||||
void srt::CUnitQueue::makeUnitTaken(CUnit* unit)
|
||||
{
|
||||
++m_iNumTaken;
|
||||
|
||||
SRT_ASSERT(unit != NULL);
|
||||
SRT_ASSERT(unit->m_iFlag == CUnit::FREE);
|
||||
unit->m_iFlag.store(CUnit::GOOD);
|
||||
SRT_ASSERT(!unit->m_bTaken);
|
||||
unit->m_bTaken.store(true);
|
||||
}
|
||||
|
||||
srt::CSndUList::CSndUList(sync::CTimer* pTimer)
|
||||
|
@ -481,6 +481,25 @@ bool srt::CSndQueue::getBind(char* dst, size_t len) const
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
static void CSndQueueDebugHighratePrint(const srt::CSndQueue* self, const steady_clock::time_point currtime)
|
||||
{
|
||||
if (self->m_DbgTime <= currtime)
|
||||
{
|
||||
fprintf(stdout,
|
||||
"SndQueue %lu slt:%lu nrp:%lu snt:%lu nrt:%lu ctw:%lu\n",
|
||||
self->m_WorkerStats.lIteration,
|
||||
self->m_WorkerStats.lSleepTo,
|
||||
self->m_WorkerStats.lNotReadyPop,
|
||||
self->m_WorkerStats.lSendTo,
|
||||
self->m_WorkerStats.lNotReadyTs,
|
||||
self->m_WorkerStats.lCondWait);
|
||||
memset(&self->m_WorkerStats, 0, sizeof(self->m_WorkerStats));
|
||||
self->m_DbgTime = currtime + self->m_DbgPeriod;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void* srt::CSndQueue::worker(void* param)
|
||||
{
|
||||
CSndQueue* self = (CSndQueue*)param;
|
||||
|
@ -492,34 +511,32 @@ void* srt::CSndQueue::worker(void* param)
|
|||
#endif
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
CTimer::rdtsc(self->m_ullDbgTime);
|
||||
self->m_ullDbgPeriod = uint64_t(5000000) * CTimer::getCPUFrequency();
|
||||
self->m_ullDbgTime += self->m_ullDbgPeriod;
|
||||
#define IF_DEBUG_HIGHRATE(statement) statement
|
||||
self->m_DbgTime = sync::steady_clock::now();
|
||||
self->m_DbgPeriod = sync::microseconds_from(5000000);
|
||||
self->m_DbgTime += self->m_DbgPeriod;
|
||||
#else
|
||||
#define IF_DEBUG_HIGHRATE(statement) (void)0
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
|
||||
while (!self->m_bClosing)
|
||||
{
|
||||
const steady_clock::time_point next_time = self->m_pSndUList->getNextProcTime();
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lIteration++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
INCREMENT_THREAD_ITERATIONS();
|
||||
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lIteration++);
|
||||
|
||||
if (is_zero(next_time))
|
||||
{
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lNotReadyTs++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lNotReadyTs++);
|
||||
|
||||
// wait here if there is no sockets with data to be sent
|
||||
THREAD_PAUSED();
|
||||
if (!self->m_bClosing)
|
||||
{
|
||||
self->m_pSndUList->waitNonEmpty();
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lCondWait++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lCondWait++);
|
||||
}
|
||||
THREAD_RESUMED();
|
||||
|
||||
|
@ -529,40 +546,20 @@ void* srt::CSndQueue::worker(void* param)
|
|||
// wait until next processing time of the first socket on the list
|
||||
const steady_clock::time_point currtime = steady_clock::now();
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
if (self->m_ullDbgTime <= currtime)
|
||||
{
|
||||
fprintf(stdout,
|
||||
"SndQueue %lu slt:%lu nrp:%lu snt:%lu nrt:%lu ctw:%lu\n",
|
||||
self->m_WorkerStats.lIteration,
|
||||
self->m_WorkerStats.lSleepTo,
|
||||
self->m_WorkerStats.lNotReadyPop,
|
||||
self->m_WorkerStats.lSendTo,
|
||||
self->m_WorkerStats.lNotReadyTs,
|
||||
self->m_WorkerStats.lCondWait);
|
||||
memset(&self->m_WorkerStats, 0, sizeof(self->m_WorkerStats));
|
||||
self->m_ullDbgTime = currtime + self->m_ullDbgPeriod;
|
||||
}
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
|
||||
THREAD_PAUSED();
|
||||
IF_DEBUG_HIGHRATE(CSndQueueDebugHighratePrint(self, currtime));
|
||||
if (currtime < next_time)
|
||||
{
|
||||
THREAD_PAUSED();
|
||||
self->m_pTimer->sleep_until(next_time);
|
||||
|
||||
#if defined(HAI_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lSleepTo++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
THREAD_RESUMED();
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lSleepTo++);
|
||||
}
|
||||
THREAD_RESUMED();
|
||||
|
||||
// Get a socket with a send request if any.
|
||||
CUDT* u = self->m_pSndUList->pop();
|
||||
if (u == NULL)
|
||||
{
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lNotReadyPop++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lNotReadyPop++);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -575,46 +572,44 @@ void* srt::CSndQueue::worker(void* param)
|
|||
|
||||
if (!u->m_bConnected || u->m_bBroken)
|
||||
{
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lNotReadyPop++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lNotReadyPop++);
|
||||
continue;
|
||||
}
|
||||
|
||||
// pack a packet from the socket
|
||||
CPacket pkt;
|
||||
const std::pair<bool, steady_clock::time_point> res_time = u->packData((pkt));
|
||||
steady_clock::time_point next_send_time;
|
||||
sockaddr_any source_addr;
|
||||
const bool res = u->packData((pkt), (next_send_time), (source_addr));
|
||||
|
||||
// Check if payload size is invalid.
|
||||
if (res_time.first == false)
|
||||
// Check if extracted anything to send
|
||||
if (res == false)
|
||||
{
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lNotReadyPop++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lNotReadyPop++);
|
||||
continue;
|
||||
}
|
||||
|
||||
const sockaddr_any addr = u->m_PeerAddr;
|
||||
const steady_clock::time_point next_send_time = res_time.second;
|
||||
if (!is_zero(next_send_time))
|
||||
self->m_pSndUList->update(u, CSndUList::DO_RESCHEDULE, next_send_time);
|
||||
|
||||
HLOGC(qslog.Debug, log << self->CONID() << "chn:SENDING: " << pkt.Info());
|
||||
self->m_pChannel->sendto(addr, pkt);
|
||||
self->m_pChannel->sendto(addr, pkt, source_addr);
|
||||
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE)
|
||||
self->m_WorkerStats.lSendTo++;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
IF_DEBUG_HIGHRATE(self->m_WorkerStats.lSendTo++);
|
||||
}
|
||||
|
||||
THREAD_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int srt::CSndQueue::sendto(const sockaddr_any& w_addr, CPacket& w_packet)
|
||||
int srt::CSndQueue::sendto(const sockaddr_any& addr, CPacket& w_packet, const sockaddr_any& src)
|
||||
{
|
||||
// send out the packet immediately (high priority), this is a control packet
|
||||
m_pChannel->sendto(w_addr, w_packet);
|
||||
// NOTE: w_packet is passed by mutable reference because this function will do
|
||||
// a modification in place and then it will revert it. After returning this object
|
||||
// should look unmodified, hence it is here passed without a reference marker.
|
||||
m_pChannel->sendto(addr, w_packet, src);
|
||||
return (int)w_packet.getLength();
|
||||
}
|
||||
|
||||
|
@ -842,14 +837,42 @@ srt::CUDT* srt::CRendezvousQueue::retrieve(const sockaddr_any& addr, SRTSOCKET&
|
|||
{
|
||||
ScopedLock vg(m_RIDListLock);
|
||||
|
||||
IF_HEAVY_LOGGING(const char* const id_type = w_id ? "THIS ID" : "A NEW CONNECTION");
|
||||
|
||||
// TODO: optimize search
|
||||
for (list<CRL>::const_iterator i = m_lRendezvousID.begin(); i != m_lRendezvousID.end(); ++i)
|
||||
{
|
||||
if (i->m_PeerAddr == addr && ((w_id == 0) || (w_id == i->m_iID)))
|
||||
{
|
||||
// This procedure doesn't exactly respond to the original UDT idea.
|
||||
// As the "rendezvous queue" is used for both handling rendezvous and
|
||||
// the caller sockets in the non-blocking mode (for blocking mode the
|
||||
// entire handshake procedure is handled in a loop-style in CUDT::startConnect),
|
||||
// the RID list should give up a socket entity in the following cases:
|
||||
// 1. For THE SAME id as passed in w_id, respond always, as per a caller
|
||||
// socket that is currently trying to connect and is managed with
|
||||
// HS roundtrips in an event-style. Same for rendezvous.
|
||||
// 2. For the "connection request" ID=0 the found socket should be given up
|
||||
// ONLY IF it is rendezvous. Normally ID=0 is only for listener as a
|
||||
// connection request. But if there was a listener, then this function
|
||||
// wouldn't even be called, as this case would be handled before trying
|
||||
// to call this function.
|
||||
//
|
||||
// This means: if an incoming ID is 0, then this search should succeed ONLY
|
||||
// IF THE FOUND SOCKET WAS RENDEZVOUS.
|
||||
|
||||
if (!w_id && !i->m_pUDT->m_config.bRendezvous)
|
||||
{
|
||||
HLOGC(cnlog.Debug,
|
||||
log << "RID: found id @" << i->m_iID << " while looking for "
|
||||
<< id_type << " FROM " << i->m_PeerAddr.str()
|
||||
<< ", but it's NOT RENDEZVOUS, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
HLOGC(cnlog.Debug,
|
||||
log << "RID: found id @" << i->m_iID << " while looking for "
|
||||
<< (w_id ? "THIS ID FROM " : "A NEW CONNECTION FROM ") << i->m_PeerAddr.str());
|
||||
log << "RID: found id @" << i->m_iID << " while looking for "
|
||||
<< id_type << " FROM " << i->m_PeerAddr.str());
|
||||
w_id = i->m_iID;
|
||||
return i->m_pUDT;
|
||||
}
|
||||
|
@ -908,10 +931,26 @@ void srt::CRendezvousQueue::updateConnStatus(EReadStatus rst, EConnectStatus cst
|
|||
EReadStatus read_st = rst;
|
||||
EConnectStatus conn_st = cst;
|
||||
|
||||
if (i->id != dest_id)
|
||||
if (cst != CONN_RENDEZVOUS && dest_id != 0)
|
||||
{
|
||||
read_st = RST_AGAIN;
|
||||
conn_st = CONN_AGAIN;
|
||||
if (i->id != dest_id)
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "updateConnStatus: cst=" << ConnectStatusStr(cst) << " but for RID @" << i->id
|
||||
<< " dest_id=@" << dest_id << " - resetting to AGAIN");
|
||||
|
||||
read_st = RST_AGAIN;
|
||||
conn_st = CONN_AGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "updateConnStatus: cst=" << ConnectStatusStr(cst) << " for @"
|
||||
<< i->id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HLOGC(cnlog.Debug, log << "updateConnStatus: cst=" << ConnectStatusStr(cst) << " and dest_id=@" << dest_id
|
||||
<< " - NOT checking against RID @" << i->id);
|
||||
}
|
||||
|
||||
HLOGC(cnlog.Debug,
|
||||
|
@ -1123,7 +1162,6 @@ srt::CRcvQueue::~CRcvQueue()
|
|||
while (!i->second.empty())
|
||||
{
|
||||
CPacket* pkt = i->second.front();
|
||||
delete[] pkt->m_pcData;
|
||||
delete pkt;
|
||||
i->second.pop();
|
||||
}
|
||||
|
@ -1182,6 +1220,8 @@ void* srt::CRcvQueue::worker(void* param)
|
|||
{
|
||||
bool have_received = false;
|
||||
EReadStatus rst = self->worker_RetrieveUnit((id), (unit), (sa));
|
||||
|
||||
INCREMENT_THREAD_ITERATIONS();
|
||||
if (rst == RST_OK)
|
||||
{
|
||||
if (id < 0)
|
||||
|
@ -1324,14 +1364,12 @@ srt::EReadStatus srt::CRcvQueue::worker_RetrieveUnit(int32_t& w_id, CUnit*& w_un
|
|||
{
|
||||
// no space, skip this packet
|
||||
CPacket temp;
|
||||
temp.m_pcData = new char[m_szPayloadSize];
|
||||
temp.setLength(m_szPayloadSize);
|
||||
temp.allocate(m_szPayloadSize);
|
||||
THREAD_PAUSED();
|
||||
EReadStatus rst = m_pChannel->recvfrom((w_addr), (temp));
|
||||
THREAD_RESUMED();
|
||||
// Note: this will print nothing about the packet details unless heavy logging is on.
|
||||
LOGC(qrlog.Error, log << CONID() << "LOCAL STORAGE DEPLETED. Dropping 1 packet: " << temp.Info());
|
||||
delete[] temp.m_pcData;
|
||||
|
||||
// Be transparent for RST_ERROR, but ignore the correct
|
||||
// data read and fake that the packet was dropped.
|
||||
|
@ -1500,7 +1538,7 @@ srt::EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUni
|
|||
if (cst == CONN_CONFUSED)
|
||||
{
|
||||
LOGC(cnlog.Warn, log << "AsyncOrRND: PACKET NOT HANDSHAKE - re-requesting handshake from peer");
|
||||
storePkt(id, unit->m_Packet.clone());
|
||||
storePktClone(id, unit->m_Packet);
|
||||
if (!u->processAsyncConnectRequest(RST_AGAIN, CONN_CONTINUE, &unit->m_Packet, u->m_PeerAddr))
|
||||
{
|
||||
// Reuse previous behavior to reject a packet
|
||||
|
@ -1575,7 +1613,7 @@ srt::EConnectStatus srt::CRcvQueue::worker_TryAsyncRend_OrStore(int32_t id, CUni
|
|||
log << "AsyncOrRND: packet RESOLVED TO ID=" << id << " -- continuing through CENTRAL PACKET QUEUE");
|
||||
// This is where also the packets for rendezvous connection will be landing,
|
||||
// in case of a synchronous connection.
|
||||
storePkt(id, unit->m_Packet.clone());
|
||||
storePktClone(id, unit->m_Packet);
|
||||
|
||||
return CONN_CONTINUE;
|
||||
}
|
||||
|
@ -1637,8 +1675,8 @@ int srt::CRcvQueue::recvfrom(int32_t id, CPacket& w_packet)
|
|||
memcpy((w_packet.m_nHeader), newpkt->m_nHeader, CPacket::HDR_SIZE);
|
||||
memcpy((w_packet.m_pcData), newpkt->m_pcData, newpkt->getLength());
|
||||
w_packet.setLength(newpkt->getLength());
|
||||
w_packet.m_DestAddr = newpkt->m_DestAddr;
|
||||
|
||||
delete[] newpkt->m_pcData;
|
||||
delete newpkt;
|
||||
|
||||
// remove this message from queue,
|
||||
|
@ -1693,7 +1731,6 @@ void srt::CRcvQueue::removeConnector(const SRTSOCKET& id)
|
|||
log << "removeConnector: ... and its packet queue with " << i->second.size() << " packets collected");
|
||||
while (!i->second.empty())
|
||||
{
|
||||
delete[] i->second.front()->m_pcData;
|
||||
delete i->second.front();
|
||||
i->second.pop();
|
||||
}
|
||||
|
@ -1726,7 +1763,7 @@ srt::CUDT* srt::CRcvQueue::getNewEntry()
|
|||
return u;
|
||||
}
|
||||
|
||||
void srt::CRcvQueue::storePkt(int32_t id, CPacket* pkt)
|
||||
void srt::CRcvQueue::storePktClone(int32_t id, const CPacket& pkt)
|
||||
{
|
||||
CUniqueSync passcond(m_BufferLock, m_BufferCond);
|
||||
|
||||
|
@ -1734,22 +1771,22 @@ void srt::CRcvQueue::storePkt(int32_t id, CPacket* pkt)
|
|||
|
||||
if (i == m_mBuffer.end())
|
||||
{
|
||||
m_mBuffer[id].push(pkt);
|
||||
m_mBuffer[id].push(pkt.clone());
|
||||
passcond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
// avoid storing too many packets, in case of malfunction or attack
|
||||
// Avoid storing too many packets, in case of malfunction or attack.
|
||||
if (i->second.size() > 16)
|
||||
return;
|
||||
|
||||
i->second.push(pkt);
|
||||
i->second.push(pkt.clone());
|
||||
}
|
||||
}
|
||||
|
||||
void srt::CMultiplexer::destroy()
|
||||
{
|
||||
// Reverse order of the assigned
|
||||
// Reverse order of the assigned.
|
||||
delete m_pRcvQueue;
|
||||
delete m_pSndQueue;
|
||||
delete m_pTimer;
|
||||
|
|
43
trunk/3rdparty/srt-1-fit/srtcore/queue.h
vendored
43
trunk/3rdparty/srt-1-fit/srtcore/queue.h
vendored
|
@ -71,16 +71,7 @@ class CUDT;
|
|||
struct CUnit
|
||||
{
|
||||
CPacket m_Packet; // packet
|
||||
enum Flag
|
||||
{
|
||||
FREE = 0,
|
||||
GOOD = 1,
|
||||
PASSACK = 2,
|
||||
DROPPED = 3
|
||||
};
|
||||
|
||||
// TODO: The new RcvBuffer allows to use atomic_bool here.
|
||||
sync::atomic<Flag> m_iFlag; // 0: free, 1: occupied, 2: msg read but not freed (out-of-order), 3: msg dropped
|
||||
sync::atomic<bool> m_bTaken; // true if the unit is is use (can be stored in the RCV buffer).
|
||||
};
|
||||
|
||||
class CUnitQueue
|
||||
|
@ -106,7 +97,7 @@ public:
|
|||
|
||||
void makeUnitFree(CUnit* unit);
|
||||
|
||||
void makeUnitGood(CUnit* unit);
|
||||
void makeUnitTaken(CUnit* unit);
|
||||
|
||||
private:
|
||||
struct CQEntry
|
||||
|
@ -203,7 +194,7 @@ private:
|
|||
void insert_(const sync::steady_clock::time_point& ts, const CUDT* u);
|
||||
|
||||
/// Insert a new UDT instance into the list without realloc.
|
||||
/// Should be called if there is a gauranteed space for the element.
|
||||
/// Should be called if there is a guaranteed space for the element.
|
||||
///
|
||||
/// @param [in] ts time stamp: next processing time
|
||||
/// @param [in] u pointer to the UDT instance
|
||||
|
@ -419,25 +410,25 @@ public:
|
|||
/// Initialize the sending queue.
|
||||
/// @param [in] c UDP channel to be associated to the queue
|
||||
/// @param [in] t Timer
|
||||
|
||||
void init(CChannel* c, sync::CTimer* t);
|
||||
|
||||
/// Send out a packet to a given address.
|
||||
/// Send out a packet to a given address. The @a src parameter is
|
||||
/// blindly passed by the caller down the call with intention to
|
||||
/// be received eventually by CChannel::sendto, and used only if
|
||||
/// appropriate conditions state so.
|
||||
/// @param [in] addr destination address
|
||||
/// @param [in] packet packet to be sent out
|
||||
/// @param [in,ref] packet packet to be sent out
|
||||
/// @param [in] src The source IP address (details above)
|
||||
/// @return Size of data sent out.
|
||||
|
||||
int sendto(const sockaddr_any& addr, CPacket& packet);
|
||||
int sendto(const sockaddr_any& addr, CPacket& packet, const sockaddr_any& src);
|
||||
|
||||
/// Get the IP TTL.
|
||||
/// @param [in] ttl IP Time To Live.
|
||||
/// @return TTL.
|
||||
|
||||
int getIpTTL() const;
|
||||
|
||||
/// Get the IP Type of Service.
|
||||
/// @return ToS.
|
||||
|
||||
int getIpToS() const;
|
||||
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
|
@ -460,9 +451,10 @@ private:
|
|||
|
||||
sync::atomic<bool> m_bClosing; // closing the worker
|
||||
|
||||
public:
|
||||
#if defined(SRT_DEBUG_SNDQ_HIGHRATE) //>>debug high freq worker
|
||||
uint64_t m_ullDbgPeriod;
|
||||
uint64_t m_ullDbgTime;
|
||||
sync::steady_clock::duration m_DbgPeriod;
|
||||
mutable sync::steady_clock::time_point m_DbgTime;
|
||||
struct
|
||||
{
|
||||
unsigned long lIteration; //
|
||||
|
@ -471,14 +463,15 @@ private:
|
|||
unsigned long lSendTo;
|
||||
unsigned long lNotReadyTs;
|
||||
unsigned long lCondWait; // block on m_WindowCond
|
||||
} m_WorkerStats;
|
||||
} mutable m_WorkerStats;
|
||||
#endif /* SRT_DEBUG_SNDQ_HIGHRATE */
|
||||
|
||||
private:
|
||||
|
||||
#if ENABLE_LOGGING
|
||||
static int m_counter;
|
||||
#endif
|
||||
|
||||
private:
|
||||
CSndQueue(const CSndQueue&);
|
||||
CSndQueue& operator=(const CSndQueue&);
|
||||
};
|
||||
|
@ -533,7 +526,7 @@ private:
|
|||
CUnitQueue* m_pUnitQueue; // The received packet queue
|
||||
CRcvUList* m_pRcvUList; // List of UDT instances that will read packets from the queue
|
||||
CHash* m_pHash; // Hash table for UDT socket looking up
|
||||
CChannel* m_pChannel; // UDP channel for receving packets
|
||||
CChannel* m_pChannel; // UDP channel for receiving packets
|
||||
sync::CTimer* m_pTimer; // shared timer with the snd queue
|
||||
|
||||
int m_iIPversion; // IP version
|
||||
|
@ -558,7 +551,7 @@ private:
|
|||
bool ifNewEntry();
|
||||
CUDT* getNewEntry();
|
||||
|
||||
void storePkt(int32_t id, CPacket* pkt);
|
||||
void storePktClone(int32_t id, const CPacket& pkt);
|
||||
|
||||
private:
|
||||
sync::Mutex m_LSLock;
|
||||
|
|
|
@ -69,7 +69,7 @@ struct CSrtConfigSetter<SRTO_MSS>
|
|||
{
|
||||
static void set(CSrtConfig& co, const void* optval, int optlen)
|
||||
{
|
||||
int ival = cast_optval<int>(optval, optlen);
|
||||
const int ival = cast_optval<int>(optval, optlen);
|
||||
if (ival < int(CPacket::UDP_HDR_SIZE + CHandShake::m_iContentSize))
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
|
@ -236,6 +236,21 @@ struct CSrtConfigSetter<SRTO_MAXBW>
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
template<>
|
||||
struct CSrtConfigSetter<SRTO_MAXREXMITBW>
|
||||
{
|
||||
static void set(CSrtConfig& co, const void* optval, int optlen)
|
||||
{
|
||||
const int64_t val = cast_optval<int64_t>(optval, optlen);
|
||||
if (val < -1)
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
co.llMaxRexmitBW = val;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template<>
|
||||
struct CSrtConfigSetter<SRTO_IPTTL>
|
||||
{
|
||||
|
@ -333,7 +348,17 @@ struct CSrtConfigSetter<SRTO_TSBPDMODE>
|
|||
{
|
||||
static void set(CSrtConfig& co, const void* optval, int optlen)
|
||||
{
|
||||
co.bTSBPD = cast_optval<bool>(optval, optlen);
|
||||
const bool val = cast_optval<bool>(optval, optlen);
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
if (val == false && co.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM)
|
||||
{
|
||||
using namespace srt_logging;
|
||||
LOGC(aclog.Error, log << "Can't disable TSBPD as long as AES GCM is enabled.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
co.bTSBPD = val;
|
||||
}
|
||||
};
|
||||
template<>
|
||||
|
@ -502,7 +527,7 @@ struct CSrtConfigSetter<SRTO_CONNTIMEO>
|
|||
if (val < 0)
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
using namespace sync;
|
||||
using namespace srt::sync;
|
||||
co.tdConnTimeOut = milliseconds_from(val);
|
||||
}
|
||||
};
|
||||
|
@ -601,7 +626,7 @@ struct CSrtConfigSetter<SRTO_PAYLOADSIZE>
|
|||
|
||||
if (val > SRT_LIVE_MAX_PLSIZE)
|
||||
{
|
||||
LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE, maximum payload per MTU.");
|
||||
LOGC(aclog.Error, log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << ", maximum payload per MTU.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
|
||||
|
@ -622,12 +647,22 @@ struct CSrtConfigSetter<SRTO_PAYLOADSIZE>
|
|||
if (size_t(val) > efc_max_payload_size)
|
||||
{
|
||||
LOGC(aclog.Error,
|
||||
log << "SRTO_PAYLOADSIZE: value exceeds SRT_LIVE_MAX_PLSIZE decreased by " << fc.extra_size
|
||||
log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << " bytes decreased by " << fc.extra_size
|
||||
<< " required for packet filter header");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Not checking AUTO to allow defaul 1456 bytes.
|
||||
if ((co.iCryptoMode == CSrtConfig::CIPHER_MODE_AES_GCM)
|
||||
&& (val > (SRT_LIVE_MAX_PLSIZE - HAICRYPT_AUTHTAG_MAX)))
|
||||
{
|
||||
LOGC(aclog.Error,
|
||||
log << "SRTO_PAYLOADSIZE: value exceeds " << SRT_LIVE_MAX_PLSIZE << " bytes decreased by " << HAICRYPT_AUTHTAG_MAX
|
||||
<< " required for AES-GCM.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
|
||||
co.zExpPayloadSize = val;
|
||||
}
|
||||
};
|
||||
|
@ -883,6 +918,40 @@ struct CSrtConfigSetter<SRTO_RETRANSMITALGO>
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
template<>
|
||||
struct CSrtConfigSetter<SRTO_CRYPTOMODE>
|
||||
{
|
||||
static void set(CSrtConfig& co, const void* optval, int optlen)
|
||||
{
|
||||
using namespace srt_logging;
|
||||
const int val = cast_optval<int>(optval, optlen);
|
||||
#ifdef SRT_ENABLE_ENCRYPTION
|
||||
if (val < CSrtConfig::CIPHER_MODE_AUTO || val > CSrtConfig::CIPHER_MODE_AES_GCM)
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
|
||||
if (val == CSrtConfig::CIPHER_MODE_AES_GCM && !HaiCrypt_IsAESGCM_Supported())
|
||||
{
|
||||
LOGC(aclog.Error, log << "AES GCM is not supported by the crypto provider.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
|
||||
if (val == CSrtConfig::CIPHER_MODE_AES_GCM && !co.bTSBPD)
|
||||
{
|
||||
LOGC(aclog.Error, log << "Enable TSBPD to use AES GCM.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
}
|
||||
|
||||
co.iCryptoMode = val;
|
||||
#else
|
||||
LOGC(aclog.Error, log << "SRT was built without crypto module.");
|
||||
throw CUDTException(MJ_NOTSUP, MN_INVAL, 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
int dispatchSet(SRT_SOCKOPT optName, CSrtConfig& co, const void* optval, int optlen)
|
||||
{
|
||||
switch (optName)
|
||||
|
@ -940,6 +1009,12 @@ int dispatchSet(SRT_SOCKOPT optName, CSrtConfig& co, const void* optval, int opt
|
|||
DISPATCH(SRTO_IPV6ONLY);
|
||||
DISPATCH(SRTO_PACKETFILTER);
|
||||
DISPATCH(SRTO_RETRANSMITALGO);
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
DISPATCH(SRTO_CRYPTOMODE);
|
||||
#endif
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
DISPATCH(SRTO_MAXREXMITBW);
|
||||
#endif
|
||||
|
||||
#undef DISPATCH
|
||||
default:
|
||||
|
@ -987,7 +1062,7 @@ bool SRT_SocketOptionObject::add(SRT_SOCKOPT optname, const void* optval, size_t
|
|||
case SRTO_PEERIDLETIMEO:
|
||||
case SRTO_RCVBUF:
|
||||
//SRTO_RCVSYN - must be always false in groups
|
||||
//SRTO_RCVTIMEO - must be alwyas -1 in groups
|
||||
//SRTO_RCVTIMEO - must be always -1 in groups
|
||||
case SRTO_SNDBUF:
|
||||
case SRTO_SNDDROPDELAY:
|
||||
//SRTO_TLPKTDROP - per transmission setting
|
||||
|
|
43
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.h
vendored
43
trunk/3rdparty/srt-1-fit/srtcore/socketconfig.h
vendored
|
@ -91,19 +91,27 @@ struct CSrtMuxerConfig
|
|||
int iUDPSndBufSize; // UDP sending buffer size
|
||||
int iUDPRcvBufSize; // UDP receiving buffer size
|
||||
|
||||
bool operator==(const CSrtMuxerConfig& other) const
|
||||
// NOTE: this operator is not reversable. The syntax must use:
|
||||
// muxer_entry == socket_entry
|
||||
bool isCompatWith(const CSrtMuxerConfig& other) const
|
||||
{
|
||||
#define CEQUAL(field) (field == other.field)
|
||||
return CEQUAL(iIpTTL)
|
||||
&& CEQUAL(iIpToS)
|
||||
&& CEQUAL(iIpV6Only)
|
||||
&& CEQUAL(bReuseAddr)
|
||||
#ifdef SRT_ENABLE_BINDTODEVICE
|
||||
&& CEQUAL(sBindToDevice)
|
||||
#endif
|
||||
&& CEQUAL(iUDPSndBufSize)
|
||||
&& CEQUAL(iUDPRcvBufSize);
|
||||
&& CEQUAL(iUDPRcvBufSize)
|
||||
&& (other.iIpV6Only == -1 || CEQUAL(iIpV6Only))
|
||||
// NOTE: iIpV6Only is not regarded because
|
||||
// this matches only in case of IPv6 with "any" address.
|
||||
// And this aspect must be checked separately because here
|
||||
// this procedure has no access to neither the address,
|
||||
// nor the IP version (family).
|
||||
#undef CEQUAL
|
||||
&& true;
|
||||
}
|
||||
|
||||
CSrtMuxerConfig()
|
||||
|
@ -150,6 +158,16 @@ public:
|
|||
return set(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
size_t copy(char* s, size_t length) const
|
||||
{
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
size_t copy_len = std::min((size_t)len, length);
|
||||
memcpy(s, stor, copy_len);
|
||||
return copy_len;
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
{
|
||||
return len == 0 ? std::string() : std::string(stor);
|
||||
|
@ -176,6 +194,13 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
DEF_LINGER_S = 3*60, // 3 minutes
|
||||
DEF_CONNTIMEO_S = 3; // 3 seconds
|
||||
|
||||
enum
|
||||
{
|
||||
CIPHER_MODE_AUTO = 0,
|
||||
CIPHER_MODE_AES_CTR = 1,
|
||||
CIPHER_MODE_AES_GCM = 2
|
||||
};
|
||||
|
||||
static const int COMM_RESPONSE_TIMEOUT_MS = 5 * 1000; // 5 seconds
|
||||
static const uint32_t COMM_DEF_MIN_STABILITY_TIMEOUT_MS = 60; // 60 ms
|
||||
|
||||
|
@ -189,8 +214,8 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
size_t zExpPayloadSize; // Expected average payload size (user option)
|
||||
|
||||
// Options
|
||||
bool bSynSending; // Sending syncronization mode
|
||||
bool bSynRecving; // Receiving syncronization mode
|
||||
bool bSynSending; // Sending synchronization mode
|
||||
bool bSynRecving; // Receiving synchronization mode
|
||||
int iFlightFlagSize; // Maximum number of packets in flight from the peer side
|
||||
int iSndBufSize; // Maximum UDT sender buffer size
|
||||
int iRcvBufSize; // Maximum UDT receiver buffer size
|
||||
|
@ -202,6 +227,9 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
int iSndTimeOut; // sending timeout in milliseconds
|
||||
int iRcvTimeOut; // receiving timeout in milliseconds
|
||||
int64_t llMaxBW; // maximum data transfer rate (threshold)
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
int64_t llMaxRexmitBW; // maximum bandwidth limit for retransmissions (Bytes/s).
|
||||
#endif
|
||||
|
||||
// These fields keep the options for encryption
|
||||
// (SRTO_PASSPHRASE, SRTO_PBKEYLEN). Crypto object is
|
||||
|
@ -224,6 +252,7 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
int iPeerIdleTimeout_ms; // Timeout for hearing anything from the peer (ms).
|
||||
uint32_t uMinStabilityTimeout_ms;
|
||||
int iRetransmitAlgo;
|
||||
int iCryptoMode; // SRTO_CRYPTOMODE
|
||||
|
||||
int64_t llInputBW; // Input stream rate (bytes/sec). 0: use internally estimated input bandwidth
|
||||
int64_t llMinInputBW; // Minimum input stream rate estimate (bytes/sec)
|
||||
|
@ -263,6 +292,9 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
, iSndTimeOut(-1)
|
||||
, iRcvTimeOut(-1)
|
||||
, llMaxBW(-1)
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
, llMaxRexmitBW(-1)
|
||||
#endif
|
||||
, bDataSender(false)
|
||||
, bMessageAPI(true)
|
||||
, bTSBPD(true)
|
||||
|
@ -275,6 +307,7 @@ struct CSrtConfig: CSrtMuxerConfig
|
|||
, iPeerIdleTimeout_ms(COMM_RESPONSE_TIMEOUT_MS)
|
||||
, uMinStabilityTimeout_ms(COMM_DEF_MIN_STABILITY_TIMEOUT_MS)
|
||||
, iRetransmitAlgo(1)
|
||||
, iCryptoMode(CIPHER_MODE_AUTO)
|
||||
, llInputBW(0)
|
||||
, llMinInputBW(0)
|
||||
, iOverheadBW(25)
|
||||
|
|
26
trunk/3rdparty/srt-1-fit/srtcore/srt.h
vendored
26
trunk/3rdparty/srt-1-fit/srtcore/srt.h
vendored
|
@ -72,7 +72,7 @@ written by
|
|||
#endif
|
||||
|
||||
|
||||
// Stadnard attributes
|
||||
// Standard attributes
|
||||
|
||||
// When compiling in C++17 mode, use the standard C++17 attributes
|
||||
// (out of these, only [[deprecated]] is supported in C++14, so
|
||||
|
@ -238,7 +238,13 @@ typedef enum SRT_SOCKOPT {
|
|||
SRTO_GROUPMINSTABLETIMEO, // Minimum Link Stability timeout (backup mode) in milliseconds (ENABLE_BONDING)
|
||||
SRTO_GROUPTYPE, // Group type to which an accepted socket is about to be added, available in the handshake (ENABLE_BONDING)
|
||||
SRTO_PACKETFILTER = 60, // Add and configure a packet filter
|
||||
SRTO_RETRANSMITALGO = 61, // An option to select packet retransmission algorithm
|
||||
SRTO_RETRANSMITALGO = 61, // An option to select packet retransmission algorithm
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
SRTO_CRYPTOMODE = 62, // Encryption cipher mode (AES-CTR, AES-GCM, ...).
|
||||
#endif
|
||||
#ifdef ENABLE_MAXREXMITBW
|
||||
SRTO_MAXREXMITBW = 63, // Maximum bandwidth limit for retransmision (Bytes/s)
|
||||
#endif
|
||||
|
||||
SRTO_E_SIZE // Always last element, not a valid option.
|
||||
} SRT_SOCKOPT;
|
||||
|
@ -553,6 +559,9 @@ enum SRT_REJECT_REASON
|
|||
SRT_REJ_FILTER, // incompatible packet filter
|
||||
SRT_REJ_GROUP, // incompatible group
|
||||
SRT_REJ_TIMEOUT, // connection timeout
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
SRT_REJ_CRYPTO, // conflicting cryptographic configurations
|
||||
#endif
|
||||
|
||||
SRT_REJ_E_SIZE,
|
||||
};
|
||||
|
@ -634,11 +643,14 @@ enum SRT_REJECT_REASON
|
|||
|
||||
enum SRT_KM_STATE
|
||||
{
|
||||
SRT_KM_S_UNSECURED = 0, //No encryption
|
||||
SRT_KM_S_SECURING = 1, //Stream encrypted, exchanging Keying Material
|
||||
SRT_KM_S_SECURED = 2, //Stream encrypted, keying Material exchanged, decrypting ok.
|
||||
SRT_KM_S_NOSECRET = 3, //Stream encrypted and no secret to decrypt Keying Material
|
||||
SRT_KM_S_BADSECRET = 4 //Stream encrypted and wrong secret, cannot decrypt Keying Material
|
||||
SRT_KM_S_UNSECURED = 0, // No encryption
|
||||
SRT_KM_S_SECURING = 1, // Stream encrypted, exchanging Keying Material
|
||||
SRT_KM_S_SECURED = 2, // Stream encrypted, keying Material exchanged, decrypting ok.
|
||||
SRT_KM_S_NOSECRET = 3, // Stream encrypted and no secret to decrypt Keying Material
|
||||
SRT_KM_S_BADSECRET = 4 // Stream encrypted and wrong secret is used, cannot decrypt Keying Material
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
,SRT_KM_S_BADCRYPTOMODE = 5 // Stream encrypted but wrong cryptographic mode is used, cannot decrypt. Since v1.5.2.
|
||||
#endif
|
||||
};
|
||||
|
||||
enum SRT_EPOLL_OPT
|
||||
|
|
|
@ -89,7 +89,7 @@ used by SRT library internally.
|
|||
// - Other compilers: none.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#if _MSC_VER >= 1920
|
||||
// In case of MSVC these attributes have to preceed the attributed objects (variable, function).
|
||||
// In case of MSVC these attributes have to precede the attributed objects (variable, function).
|
||||
// E.g. SRT_ATTR_GUARDED_BY(mtx) int object;
|
||||
// It is tricky to annotate e.g. the following function, as clang complaints it does not know 'm'.
|
||||
// SRT_ATTR_EXCLUDES(m) SRT_ATTR_ACQUIRE(m)
|
||||
|
|
|
@ -439,6 +439,9 @@ const char* const srt_rejection_reason_msg [] = {
|
|||
"Packet Filter settings error",
|
||||
"Group settings collision",
|
||||
"Connection timeout"
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
,"Crypto mode"
|
||||
#endif
|
||||
};
|
||||
|
||||
// Deprecated, available in SRT API.
|
||||
|
@ -460,6 +463,9 @@ extern const char* const srt_rejectreason_msg[] = {
|
|||
srt_rejection_reason_msg[14],
|
||||
srt_rejection_reason_msg[15],
|
||||
srt_rejection_reason_msg[16]
|
||||
#ifdef ENABLE_AEAD_API_PREVIEW
|
||||
, srt_rejection_reason_msg[17]
|
||||
#endif
|
||||
};
|
||||
|
||||
const char* srt_rejectreason_str(int id)
|
||||
|
|
|
@ -70,7 +70,7 @@ extern const char * SysStrError(int errnum, char * buf, size_t buflen)
|
|||
// your compilation fails when you use wide characters.
|
||||
// The problem is that when TCHAR != char, then the buffer written this way
|
||||
// would have to be converted to ASCII, not just copied by strncpy.
|
||||
FormatMessage(0
|
||||
FormatMessageA(0
|
||||
| FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
|
@ -87,8 +87,12 @@ extern const char * SysStrError(int errnum, char * buf, size_t buflen)
|
|||
|
||||
if (lpMsgBuf)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
strncpy_s(buf, buflen, lpMsgBuf, _TRUNCATE);
|
||||
#else
|
||||
strncpy(buf, lpMsgBuf, buflen-1);
|
||||
buf[buflen-1] = 0;
|
||||
#endif
|
||||
LocalFree((HLOCAL)lpMsgBuf);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -71,12 +71,12 @@ const char* strerror_msgs_notsup [] = {
|
|||
"Operation not supported: Invalid socket ID", // MN_SIDINVAL = 4
|
||||
"Operation not supported: Cannot do this operation on an UNBOUND socket", // MN_ISUNBOUND = 5
|
||||
"Operation not supported: Socket is not in listening state", // MN_NOLISTEN = 6
|
||||
"Operation not supported: Listen/accept is not supported in rendezous connection setup", // MN_ISRENDEZVOUS = 7
|
||||
"Operation not supported: Listen/accept is not supported in rendezvous connection setup", // MN_ISRENDEZVOUS = 7
|
||||
"Operation not supported: Cannot call connect on UNBOUND socket in rendezvous connection setup", // MN_ISRENDUNBOUND = 8
|
||||
"Operation not supported: Incorrect use of Message API (sendmsg/recvmsg).", // MN_INVALMSGAPI = 9
|
||||
"Operation not supported: Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile).", // MN_INVALBUFFERAPI = 10
|
||||
"Operation not supported: Incorrect use of Message API (sendmsg/recvmsg)", // MN_INVALMSGAPI = 9
|
||||
"Operation not supported: Incorrect use of Buffer API (send/recv) or File API (sendfile/recvfile)", // MN_INVALBUFFERAPI = 10
|
||||
"Operation not supported: Another socket is already listening on the same port", // MN_BUSY = 11
|
||||
"Operation not supported: Message is too large to send (it must be less than the SRT send buffer size)", // MN_XSIZE = 12
|
||||
"Operation not supported: Message is too large to send", // MN_XSIZE = 12
|
||||
"Operation not supported: Invalid epoll ID", // MN_EIDINVAL = 13
|
||||
"Operation not supported: All sockets removed from epoll, waiting would deadlock", // MN_EEMPTY = 14
|
||||
"Operation not supported: Another socket is bound to that port and is not reusable for requested settings", // MN_BUSYPORT = 15
|
||||
|
|
6
trunk/3rdparty/srt-1-fit/srtcore/sync.cpp
vendored
6
trunk/3rdparty/srt-1-fit/srtcore/sync.cpp
vendored
|
@ -66,7 +66,7 @@ std::string FormatTimeSys(const steady_clock::time_point& timestamp)
|
|||
const steady_clock::time_point now_timestamp = steady_clock::now();
|
||||
const int64_t delta_us = count_microseconds(timestamp - now_timestamp);
|
||||
const int64_t delta_s =
|
||||
floor((static_cast<int64_t>(count_microseconds(now_timestamp.time_since_epoch()) % 1000000) + delta_us) / 1000000.0);
|
||||
static_cast<int64_t>(floor((static_cast<double>(count_microseconds(now_timestamp.time_since_epoch()) % 1000000) + delta_us) / 1000000.0));
|
||||
const time_t tt = now_s + delta_s;
|
||||
struct tm tm = SysLocalTime(tt); // in seconds
|
||||
char tmp_buf[512];
|
||||
|
@ -94,7 +94,11 @@ bool StartThread(CThread& th, void* (*f) (void*), void* args, const string& name
|
|||
th.create_thread(f, args);
|
||||
#endif
|
||||
}
|
||||
#if ENABLE_HEAVY_LOGGING
|
||||
catch (const CThreadException& e)
|
||||
#else
|
||||
catch (const CThreadException&)
|
||||
#endif
|
||||
{
|
||||
HLOGC(inlog.Debug, log << name << ": failed to start thread. " << e.what());
|
||||
return false;
|
||||
|
|
10
trunk/3rdparty/srt-1-fit/srtcore/sync.h
vendored
10
trunk/3rdparty/srt-1-fit/srtcore/sync.h
vendored
|
@ -11,6 +11,8 @@
|
|||
#ifndef INC_SRT_SYNC_H
|
||||
#define INC_SRT_SYNC_H
|
||||
|
||||
#include "platform_sys.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#ifdef ENABLE_STDCXX_SYNC
|
||||
|
@ -233,7 +235,7 @@ inline Duration<steady_clock> operator*(const int& lhs, const Duration<steady_cl
|
|||
|
||||
#endif // ENABLE_STDCXX_SYNC
|
||||
|
||||
// NOTE: Moved the following class definitons to "atomic_clock.h"
|
||||
// NOTE: Moved the following class definitions to "atomic_clock.h"
|
||||
// template <class Clock>
|
||||
// class AtomicDuration;
|
||||
// template <class Clock>
|
||||
|
@ -602,7 +604,7 @@ public:
|
|||
/// Causes the current thread to block until
|
||||
/// a specific time is reached.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// @return true if condition occurred or spuriously woken up
|
||||
/// false on timeout
|
||||
bool lock_wait_until(const steady_clock::time_point& tp);
|
||||
|
||||
|
@ -613,7 +615,7 @@ public:
|
|||
/// It may also be unblocked spuriously.
|
||||
/// Uses internal mutex to lock.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// @return true if condition occurred or spuriously woken up
|
||||
/// false on timeout
|
||||
bool lock_wait_for(const steady_clock::duration& rel_time);
|
||||
|
||||
|
@ -624,7 +626,7 @@ public:
|
|||
/// It may also be unblocked spuriously.
|
||||
/// When unblocked, regardless of the reason, lock is reacquiredand wait_for() exits.
|
||||
///
|
||||
/// @return true if condition occured or spuriously woken up
|
||||
/// @return true if condition occurred or spuriously woken up
|
||||
/// false on timeout
|
||||
bool wait_for(UniqueLock& lk, const steady_clock::duration& rel_time);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ static void rdtsc(uint64_t& x)
|
|||
asm("mov %0=ar.itc" : "=r"(x)::"memory");
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_AMD64_RDTSC
|
||||
uint32_t lval, hval;
|
||||
asm("rdtsc" : "=a"(lval), "=d"(hval));
|
||||
asm volatile("rdtsc" : "=a"(lval), "=d"(hval));
|
||||
x = hval;
|
||||
x = (x << 32) | lval;
|
||||
#elif SRT_SYNC_CLOCK == SRT_SYNC_CLOCK_WINQPC
|
||||
|
|
12
trunk/3rdparty/srt-1-fit/srtcore/window.cpp
vendored
12
trunk/3rdparty/srt-1-fit/srtcore/window.cpp
vendored
|
@ -93,7 +93,7 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3
|
|||
r_ack = r_aSeq[i].iACK;
|
||||
|
||||
// Calculate RTT estimate
|
||||
const int rtt = count_microseconds(currtime - r_aSeq[i].tsTimeStamp);
|
||||
const int rtt = (int)count_microseconds(currtime - r_aSeq[i].tsTimeStamp);
|
||||
|
||||
if (i + 1 == r_iHead)
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3
|
|||
}
|
||||
|
||||
// Head has exceeded the physical window boundary, so it is behind tail
|
||||
for (int j = r_iTail, n = r_iHead + size; j < n; ++ j)
|
||||
for (int j = r_iTail, n = r_iHead + (int)size; j < n; ++ j)
|
||||
{
|
||||
// Looking for an identical ACK Seq. No.
|
||||
if (seq == r_aSeq[j % size].iACKSeqNo)
|
||||
|
@ -122,7 +122,7 @@ int acknowledge(Seq* r_aSeq, const size_t size, int& r_iHead, int& r_iTail, int3
|
|||
r_ack = r_aSeq[j].iACK;
|
||||
|
||||
// Calculate RTT estimate
|
||||
const int rtt = count_microseconds(currtime - r_aSeq[j].tsTimeStamp);
|
||||
const int rtt = (int)count_microseconds(currtime - r_aSeq[j].tsTimeStamp);
|
||||
|
||||
if (j == r_iHead)
|
||||
{
|
||||
|
@ -176,7 +176,7 @@ int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica,
|
|||
const int* bp = abytes;
|
||||
// median filtering
|
||||
const int* p = window;
|
||||
for (int i = 0, n = asize; i < n; ++ i)
|
||||
for (int i = 0, n = (int)asize; i < n; ++ i)
|
||||
{
|
||||
if ((*p < upper) && (*p > lower))
|
||||
{
|
||||
|
@ -192,7 +192,7 @@ int srt::CPktTimeWindowTools::getPktRcvSpeed_in(const int* window, int* replica,
|
|||
if (count > (asize >> 1))
|
||||
{
|
||||
bytes += (srt::CPacket::SRT_DATA_HDR_SIZE * count); //Add protocol headers to bytes received
|
||||
bytesps = (unsigned long)ceil(1000000.0 / (double(sum) / double(bytes)));
|
||||
bytesps = (int)ceil(1000000.0 / (double(sum) / double(bytes)));
|
||||
return (int)ceil(1000000.0 / (sum / count));
|
||||
}
|
||||
else
|
||||
|
@ -240,7 +240,7 @@ int srt::CPktTimeWindowTools::getBandwidth_in(const int* window, int* replica, s
|
|||
|
||||
// median filtering
|
||||
const int* p = window;
|
||||
for (int i = 0, n = psize; i < n; ++ i)
|
||||
for (int i = 0, n = (int)psize; i < n; ++ i)
|
||||
{
|
||||
if ((*p < upper) && (*p > lower))
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ The changelog for SRS.
|
|||
<a name="v6-changes"></a>
|
||||
|
||||
## SRS 6.0 Changelog
|
||||
* v6.0, 2023-09-21, Merge [#3808](https://github.com/ossrs/srs/pull/3808): Upgrade libsrt to v1.5.3. v6.0.81 (#3808)
|
||||
* v6.0, 2023-09-21, Merge [#3404](https://github.com/ossrs/srs/pull/3404): WebRTC: Support WHEP for play. v6.0.80 (#3404)
|
||||
* v6.0, 2023-09-21, Merge [#3807](https://github.com/ossrs/srs/pull/3807): Prevent the output of srt logs in utest. v6.0.79 (#3807)
|
||||
* v6.0, 2023-09-21, Merge [#3696](https://github.com/ossrs/srs/pull/3696): SRT: modify log level from error to debug when no socket to accept. v6.0.78 (#3696)
|
||||
|
@ -92,6 +93,7 @@ The changelog for SRS.
|
|||
<a name="v5-changes"></a>
|
||||
|
||||
## SRS 5.0 Changelog
|
||||
* v5.0, 2023-09-21, Merge [#3808](https://github.com/ossrs/srs/pull/3808): Upgrade libsrt to v1.5.3. v5.0.183 (#3808)
|
||||
* v5.0, 2023-09-21, Merge [#3404](https://github.com/ossrs/srs/pull/3404): WebRTC: Support WHEP for play. v5.0.182 (#3404)
|
||||
* v5.0, 2023-09-21, Merge [#3807](https://github.com/ossrs/srs/pull/3807): Prevent the output of srt logs in utest. v5.0.181 (#3807)
|
||||
* v5.0, 2023-09-21, Merge [#3696](https://github.com/ossrs/srs/pull/3696): SRT: modify log level from error to debug when no socket to accept. v5.0.180 (#3696)
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 182
|
||||
#define VERSION_REVISION 183
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 6
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 80
|
||||
#define VERSION_REVISION 81
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue