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