Sync develop with master #4
106 changed files with 4725 additions and 15554 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -4,3 +4,6 @@
|
|||
[submodule "vendor/websocketpp"]
|
||||
path = vendor/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
[submodule "vendor/diff-match-patch-cpp-stl"]
|
||||
path = vendor/diff-match-patch-cpp-stl
|
||||
url = https://github.com/leutloff/diff-match-patch-cpp-stl
|
||||
|
|
|
|||
175
CMakeLists.txt
175
CMakeLists.txt
|
|
@ -49,7 +49,7 @@ ELSE( ECC_IMPL STREQUAL openssl )
|
|||
ENDIF( ECC_IMPL STREQUAL openssl )
|
||||
|
||||
# Configure secp256k1-zkp
|
||||
if ( WIN32 )
|
||||
if ( MSVC )
|
||||
# autoconf won't work here, hard code the defines
|
||||
set( SECP256K1_DIR "${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp" )
|
||||
|
||||
|
|
@ -65,8 +65,18 @@ if ( WIN32 )
|
|||
USE_SCALAR_8X32
|
||||
USE_SCALAR_INV_BUILTIN )
|
||||
set_target_properties( secp256k1 PROPERTIES COMPILE_DEFINITIONS "${SECP256K1_BUILD_DEFINES}" LINKER_LANGUAGE C )
|
||||
else ( WIN32 )
|
||||
else ( MSVC )
|
||||
include(ExternalProject)
|
||||
if ( MINGW )
|
||||
ExternalProject_Add( project_secp256k1
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||
CONFIGURE_COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/configure --prefix=${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp --with-bignum=no --host=x86_64-w64-mingw32
|
||||
BUILD_COMMAND make
|
||||
INSTALL_COMMAND true
|
||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp/src/project_secp256k1-build/.libs/libsecp256k1.a
|
||||
)
|
||||
else ( MINGW )
|
||||
ExternalProject_Add( project_secp256k1
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||
|
|
@ -75,6 +85,7 @@ else ( WIN32 )
|
|||
INSTALL_COMMAND true
|
||||
BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/vendor/secp256k1-zkp/src/project_secp256k1-build/.libs/libsecp256k1.a
|
||||
)
|
||||
endif ( MINGW )
|
||||
ExternalProject_Add_Step(project_secp256k1 autogen
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/autogen.sh
|
||||
|
|
@ -87,13 +98,13 @@ else ( WIN32 )
|
|||
set_property(TARGET secp256k1 PROPERTY IMPORTED_LOCATION ${binary_dir}/.libs/libsecp256k1${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
set_property(TARGET secp256k1 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp/include)
|
||||
add_dependencies(secp256k1 project_secp256k1)
|
||||
endif ( WIN32 )
|
||||
endif ( MSVC )
|
||||
# End configure secp256k1-zkp
|
||||
|
||||
IF( WIN32 )
|
||||
MESSAGE(STATUS "Configuring fc to build on Win32")
|
||||
|
||||
set( RPCRT4 Rpcrt4 )
|
||||
set( RPCRT4 rpcrt4 )
|
||||
|
||||
#boost
|
||||
SET(BOOST_ROOT $ENV{BOOST_ROOT})
|
||||
|
|
@ -110,7 +121,7 @@ IF( WIN32 )
|
|||
SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES})
|
||||
ENDIF()
|
||||
|
||||
set( PLATFORM_SPECIFIC_LIBS WS2_32.lib Userenv.lib)
|
||||
set( PLATFORM_SPECIFIC_LIBS wsock32.lib ws2_32.lib userenv.lib)
|
||||
# iphlpapi.lib
|
||||
|
||||
ELSE(WIN32)
|
||||
|
|
@ -142,17 +153,6 @@ find_package(OpenSSL REQUIRED)
|
|||
|
||||
set( CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_LIB_SUFFIXES} )
|
||||
|
||||
# We are now building in support for deflate compression into our websockets layer by default,
|
||||
# which requires zlib. Aside from that, all of fc compiles without zlib, so this could be
|
||||
# made optional without much effort
|
||||
# (important exception, apple: as of 10.10 yosemite, the OpenSSL static libraries shipped with
|
||||
# os x have a dependency on zlib)
|
||||
# On a side note, fc's fc::zlib_compress() function uses a separate implementation of zlib
|
||||
# from the miniz library. If we're comfortable requiring an external zlib, we can
|
||||
# reimplement fc::zlib_compress() to call the real zlib, and remove miniz.c from our
|
||||
# repository.
|
||||
find_package( ZLIB REQUIRED )
|
||||
|
||||
option( UNITY_BUILD OFF )
|
||||
|
||||
set( fc_sources
|
||||
|
|
@ -187,10 +187,12 @@ set( fc_sources
|
|||
src/interprocess/signals.cpp
|
||||
src/interprocess/file_mapping.cpp
|
||||
src/interprocess/mmap_struct.cpp
|
||||
src/interprocess/file_mutex.cpp
|
||||
src/rpc/cli.cpp
|
||||
src/rpc/http_api.cpp
|
||||
src/rpc/json_connection.cpp
|
||||
src/rpc/state.cpp
|
||||
src/rpc/bstate.cpp
|
||||
src/rpc/websocket_api.cpp
|
||||
src/log/log_message.cpp
|
||||
src/log/logger.cpp
|
||||
|
|
@ -218,12 +220,12 @@ set( fc_sources
|
|||
src/crypto/dh.cpp
|
||||
src/crypto/blowfish.cpp
|
||||
src/crypto/elliptic_common.cpp
|
||||
src/crypto/equihash.cpp
|
||||
${ECC_REST}
|
||||
src/crypto/elliptic_${ECC_IMPL}.cpp
|
||||
src/crypto/rand.cpp
|
||||
src/network/tcp_socket.cpp
|
||||
src/network/udp_socket.cpp
|
||||
src/network/udt_socket.cpp
|
||||
src/network/http/http_connection.cpp
|
||||
src/network/http/http_server.cpp
|
||||
src/network/http/websocket.cpp
|
||||
|
|
@ -250,7 +252,7 @@ list(APPEND sources "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp")
|
|||
list(APPEND sources ${fc_headers})
|
||||
|
||||
add_subdirectory( vendor/websocketpp EXCLUDE_FROM_ALL )
|
||||
add_subdirectory( vendor/udt4 )
|
||||
add_subdirectory( vendor/equihash )
|
||||
|
||||
setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC )
|
||||
install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include )
|
||||
|
|
@ -274,6 +276,10 @@ if(WIN32)
|
|||
endif(WIN32)
|
||||
# end readline stuff
|
||||
|
||||
if( NOT CPP_STANDARD )
|
||||
set( CPP_STANDARD, "-std=c++11" )
|
||||
endif()
|
||||
|
||||
IF(WIN32)
|
||||
target_compile_definitions(fc PUBLIC WIN32 NOMINMAX _WIN32_WINNT=0x0501 _CRT_SECURE_NO_WARNINGS
|
||||
_SCL_SERCURE_NO_WARNINGS
|
||||
|
|
@ -284,22 +290,53 @@ IF(WIN32)
|
|||
# autodetecting code to do the right thing.
|
||||
_WEBSOCKETPP_CPP11_CHRONO_
|
||||
)
|
||||
# Activate C++ exception handling, assume extern C calls don't throw
|
||||
# Add /U options to be sure settings specific to dynamic boost link are ineffective
|
||||
target_compile_options(fc PUBLIC /EHsc /UBOOST_ALL_DYN_LINK /UBOOST_LINKING_PYTHON /UBOOST_DEBUG_PYTHON)
|
||||
if( MSVC )
|
||||
# Activate C++ exception handling, assume extern C calls don't throw
|
||||
# Add /U options to be sure settings specific to dynamic boost link are ineffective
|
||||
target_compile_options(fc PUBLIC /EHsc /UBOOST_ALL_DYN_LINK /UBOOST_LINKING_PYTHON /UBOOST_DEBUG_PYTHON)
|
||||
elseif( MINGW )
|
||||
# Put MinGW specific compiler settings here
|
||||
endif()
|
||||
ELSE()
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall")
|
||||
|
||||
IF(APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPP_STANDARD} -stdlib=libc++ -Wall")
|
||||
ELSE()
|
||||
if( NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
target_compile_options(fc PUBLIC -std=c++11 -Wall -fnon-call-exceptions)
|
||||
target_compile_options(fc PUBLIC ${CPP_STANDARD} -Wall -fnon-call-exceptions)
|
||||
endif()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -fnon-call-exceptions")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPP_STANDARD} -Wall -fnon-call-exceptions")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(APPLE)
|
||||
# As of 10.10 yosemite, the OpenSSL static libraries shipped with os x have a dependency
|
||||
# on zlib, so any time you link in openssl you also need to link zlib. . We really want to detect whether openssl was configured with the --no-zlib
|
||||
# option or not when it was built, but that's difficult to do in practice, so we
|
||||
# just always try to link it in on mac.
|
||||
find_package( ZLIB REQUIRED )
|
||||
ELSE(APPLE)
|
||||
find_package( ZLIB )
|
||||
ENDIF(APPLE)
|
||||
|
||||
if( ZLIB_FOUND )
|
||||
MESSAGE( STATUS "zlib found" )
|
||||
add_definitions( -DHAS_ZLIB )
|
||||
else()
|
||||
MESSAGE( STATUS "zlib not found" )
|
||||
set( ZLIB_LIBRARIES "" )
|
||||
endif( ZLIB_FOUND )
|
||||
|
||||
find_package( BZip2 )
|
||||
if( BZIP2_FOUND )
|
||||
MESSAGE( STATUS "bzip2 found" )
|
||||
add_definitions( -DHAS_BZIP2 )
|
||||
else()
|
||||
MESSAGE( STATUS "bzip2 not found" )
|
||||
set( BZIP2_LIBRARIES "" )
|
||||
endif( BZIP2_FOUND )
|
||||
|
||||
# This will become unnecessary once we update to websocketpp which fixes upstream issue #395
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWEBSOCKETPP_STRICT_MASKING")
|
||||
|
||||
|
|
@ -309,21 +346,22 @@ target_include_directories(fc
|
|||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${Boost_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
"vendor/diff-match-patch-cpp-stl"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/websocketpp
|
||||
"${readline_includes}"
|
||||
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/boost_1.51/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/cyoencode-1.0.2/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/udt4/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/websocketpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/secp256k1-zkp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vendor/equihash
|
||||
)
|
||||
|
||||
#target_link_libraries( fc PUBLIC udt ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${ECC_LIB} )
|
||||
#target_link_libraries( fc PUBLIC ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${ECC_LIB} )
|
||||
IF(NOT WIN32)
|
||||
set(LINK_USR_LOCAL_LIB -L/usr/local/lib)
|
||||
ENDIF()
|
||||
target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} udt ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${readline_libraries} ${ECC_LIB} )
|
||||
target_link_libraries( fc PUBLIC ${LINK_USR_LOCAL_LIB} equihash ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PLATFORM_SPECIFIC_LIBS} ${RPCRT4} ${CMAKE_DL_LIBS} ${rt_library} ${readline_libraries} ${ECC_LIB} )
|
||||
|
||||
if(MSVC)
|
||||
set_source_files_properties( src/network/http/websocket.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
|
|
@ -331,77 +369,17 @@ endif(MSVC)
|
|||
|
||||
|
||||
IF(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY MATCHES "\\.(a|lib)$")
|
||||
IF(WIN32)
|
||||
IF(MSVC)
|
||||
add_definitions(/DBOOST_TEST_DYN_LINK)
|
||||
ELSE(WIN32)
|
||||
ELSE(MSVC)
|
||||
add_definitions(-DBOOST_TEST_DYN_LINK)
|
||||
ENDIF(WIN32)
|
||||
ENDIF(MSVC)
|
||||
ENDIF()
|
||||
|
||||
add_executable( api tests/api.cpp )
|
||||
target_link_libraries( api fc )
|
||||
|
||||
if( ECC_IMPL STREQUAL secp256k1 )
|
||||
add_executable( blind tests/all_tests.cpp tests/crypto/blind.cpp )
|
||||
target_link_libraries( blind fc )
|
||||
endif()
|
||||
|
||||
include_directories( vendor/websocketpp )
|
||||
include_directories( vendor/equihash )
|
||||
|
||||
add_executable( ntp_test tests/all_tests.cpp tests/network/ntp_test.cpp )
|
||||
target_link_libraries( ntp_test fc )
|
||||
|
||||
add_executable( task_cancel_test tests/all_tests.cpp tests/thread/task_cancel.cpp )
|
||||
target_link_libraries( task_cancel_test fc )
|
||||
|
||||
|
||||
add_executable( bloom_test tests/all_tests.cpp tests/bloom_test.cpp )
|
||||
target_link_libraries( bloom_test fc )
|
||||
|
||||
add_executable( real128_test tests/all_tests.cpp tests/real128_test.cpp )
|
||||
target_link_libraries( real128_test fc )
|
||||
|
||||
add_executable( hmac_test tests/hmac_test.cpp )
|
||||
target_link_libraries( hmac_test fc )
|
||||
|
||||
add_executable( blinding_test tests/blinding_test.cpp )
|
||||
target_link_libraries( blinding_test fc )
|
||||
|
||||
|
||||
add_executable( udt_server tests/udts.cpp )
|
||||
target_link_libraries( udt_server fc udt )
|
||||
|
||||
add_executable( udt_client tests/udtc.cpp )
|
||||
target_link_libraries( udt_client fc udt )
|
||||
|
||||
add_executable( ecc_test tests/crypto/ecc_test.cpp )
|
||||
target_link_libraries( ecc_test fc )
|
||||
|
||||
#add_executable( test_aes tests/aes_test.cpp )
|
||||
#target_link_libraries( test_aes fc ${rt_library} ${pthread_library} )
|
||||
#add_executable( test_sleep tests/sleep.cpp )
|
||||
#target_link_libraries( test_sleep fc )
|
||||
#add_executable( test_rate_limiting tests/rate_limiting.cpp )
|
||||
#target_link_libraries( test_rate_limiting fc )
|
||||
|
||||
add_executable( all_tests tests/all_tests.cpp
|
||||
tests/compress/compress.cpp
|
||||
tests/crypto/aes_test.cpp
|
||||
tests/crypto/base_n_tests.cpp
|
||||
tests/crypto/bigint_test.cpp
|
||||
tests/crypto/blind.cpp
|
||||
tests/crypto/blowfish_test.cpp
|
||||
tests/crypto/dh_test.cpp
|
||||
tests/crypto/rand_test.cpp
|
||||
tests/crypto/sha_tests.cpp
|
||||
tests/network/ntp_test.cpp
|
||||
tests/network/http/websocket_test.cpp
|
||||
tests/thread/task_cancel.cpp
|
||||
tests/bloom_test.cpp
|
||||
tests/real128_test.cpp
|
||||
tests/utf8_test.cpp
|
||||
)
|
||||
target_link_libraries( all_tests fc )
|
||||
add_subdirectory(tests)
|
||||
|
||||
if(WIN32)
|
||||
# add addtional import library on windows platform
|
||||
|
|
@ -493,8 +471,15 @@ ELSE()
|
|||
ENDIF()
|
||||
|
||||
IF(WIN32)
|
||||
SET(POST_BUILD_STEP_COMMANDS ${POST_BUILD_STEP_COMMANDS}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OPENSSL_ROOT_DIR}/ssl/openssl.cnf" "${OPENSSL_CONF_TARGET}/openssl.cnf")
|
||||
IF("${OPENSSL_ROOT_DIR}" STREQUAL "")
|
||||
get_filename_component(OPENSSL_ROOT_DIR "${OPENSSL_INCLUDE_DIR}/.." REALPATH)
|
||||
ENDIF()
|
||||
SET(OPENSSL_CONF_SOURCE "${OPENSSL_ROOT_DIR}/ssl/openssl.cnf")
|
||||
IF(MINGW)
|
||||
SET(OPENSSL_CONF_SOURCE "${OPENSSL_ROOT_DIR}/openssl.cnf")
|
||||
ENDIF(MINGW)
|
||||
SET(POST_BUILD_STEP_COMMANDS ${POST_BUILD_STEP_COMMANDS}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OPENSSL_CONF_SOURCE}" "${OPENSSL_CONF_TARGET}/openssl.cnf")
|
||||
ENDIF(WIN32)
|
||||
|
||||
ADD_CUSTOM_COMMAND(TARGET fc POST_BUILD ${POST_BUILD_STEP_COMMANDS}
|
||||
|
|
|
|||
|
|
@ -45,3 +45,5 @@ mark_as_advanced(
|
|||
Readline_INCLUDE_DIR
|
||||
Readline_LIBRARY
|
||||
)
|
||||
|
||||
MESSAGE( STATUS "Found Readline: ${Readline_LIBRARY}" )
|
||||
|
|
|
|||
|
|
@ -38,8 +38,33 @@ namespace fc {
|
|||
OtherType& _source;
|
||||
};
|
||||
|
||||
template<typename Interface, typename Transform >
|
||||
class api;
|
||||
|
||||
class api_connection;
|
||||
|
||||
typedef uint32_t api_id_type;
|
||||
|
||||
class api_base
|
||||
{
|
||||
public:
|
||||
api_base() {}
|
||||
virtual ~api_base() {}
|
||||
|
||||
virtual uint64_t get_handle()const = 0;
|
||||
|
||||
virtual api_id_type register_api( api_connection& conn )const = 0;
|
||||
|
||||
// defined in api_connection.hpp
|
||||
template< typename T >
|
||||
api<T, identity_member> as();
|
||||
};
|
||||
typedef std::shared_ptr< api_base > api_ptr;
|
||||
|
||||
class api_connection;
|
||||
|
||||
template<typename Interface, typename Transform = identity_member >
|
||||
class api {
|
||||
class api : public api_base {
|
||||
public:
|
||||
typedef vtable<Interface,Transform> vtable_type;
|
||||
|
||||
|
|
@ -58,10 +83,12 @@ namespace fc {
|
|||
}
|
||||
|
||||
api( const api& cpy ):_vtable(cpy._vtable),_data(cpy._data) {}
|
||||
virtual ~api() {}
|
||||
|
||||
friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; }
|
||||
friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); }
|
||||
uint64_t get_handle()const { return uint64_t(_data.get()); }
|
||||
virtual uint64_t get_handle()const override { return uint64_t(_data.get()); }
|
||||
virtual api_id_type register_api( api_connection& conn )const override; // defined in api_connection.hpp
|
||||
|
||||
vtable_type& operator*()const { FC_ASSERT( _vtable ); return *_vtable; }
|
||||
vtable_type* operator->()const { FC_ASSERT( _vtable ); return _vtable.get(); }
|
||||
|
|
|
|||
|
|
@ -20,11 +20,17 @@ namespace fc {
|
|||
T& at( size_t pos ) { assert( pos < N); return data[pos]; }
|
||||
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T& operator[]( size_t pos ) { assert( pos < N); return data[pos]; }
|
||||
const T& operator[]( size_t pos )const { assert( pos < N); return data[pos]; }
|
||||
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
T* end() { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace fc {
|
|||
value.insert( std::move(tmp) );
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename K, typename V>
|
||||
inline void pack( Stream& s, const flat_map<K,V>& value ) {
|
||||
template<typename Stream, typename K, typename... V>
|
||||
inline void pack( Stream& s, const flat_map<K,V...>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
|
|
@ -40,8 +40,8 @@ namespace fc {
|
|||
++itr;
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename K, typename V>
|
||||
inline void unpack( Stream& s, flat_map<K,V>& value )
|
||||
template<typename Stream, typename K, typename V, typename... A>
|
||||
inline void unpack( Stream& s, flat_map<K,V,A...>& value )
|
||||
{
|
||||
unsigned_int size; unpack( s, size );
|
||||
value.clear();
|
||||
|
|
@ -54,6 +54,35 @@ namespace fc {
|
|||
value.insert( std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const bip::vector<T,A>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
++itr;
|
||||
}
|
||||
} else {
|
||||
s.write( (const char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, bip::vector<T,A>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
value.resize( size );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( auto& item : value )
|
||||
unpack( s, item );
|
||||
} else {
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
||||
|
||||
|
|
@ -76,8 +105,8 @@ namespace fc {
|
|||
vo.insert( itr->as<T>() );
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
void to_variant( const flat_map<K, T>& var, variant& vo )
|
||||
template<typename K, typename... T>
|
||||
void to_variant( const flat_map<K, T...>& var, variant& vo )
|
||||
{
|
||||
std::vector< variant > vars(var.size());
|
||||
size_t i = 0;
|
||||
|
|
@ -85,8 +114,8 @@ namespace fc {
|
|||
vars[i] = fc::variant(*itr);
|
||||
vo = vars;
|
||||
}
|
||||
template<typename K, typename T>
|
||||
void from_variant( const variant& var, flat_map<K, T>& vo )
|
||||
template<typename K, typename T, typename... A>
|
||||
void from_variant( const variant& var, flat_map<K, T, A...>& vo )
|
||||
{
|
||||
const variants& vars = var.get_array();
|
||||
vo.clear();
|
||||
|
|
|
|||
|
|
@ -1,21 +1,29 @@
|
|||
#pragma once
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/interprocess/containers/vector.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
using boost::container::flat_map;
|
||||
using boost::container::flat_set;
|
||||
namespace bip = boost::interprocess;
|
||||
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
void pack( Stream& s, const flat_set<T>& value );
|
||||
template<typename Stream, typename T>
|
||||
void unpack( Stream& s, flat_set<T>& value );
|
||||
template<typename Stream, typename K, typename V>
|
||||
void pack( Stream& s, const flat_map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V>
|
||||
void unpack( Stream& s, flat_map<K,V>& value ) ;
|
||||
template<typename Stream, typename K, typename... V>
|
||||
void pack( Stream& s, const flat_map<K,V...>& value );
|
||||
template<typename Stream, typename K, typename... V>
|
||||
void unpack( Stream& s, flat_map<K,V...>& value ) ;
|
||||
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const bip::vector<T,A>& value );
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, bip::vector<T,A>& value );
|
||||
} // namespace raw
|
||||
|
||||
} // fc
|
||||
|
|
|
|||
22
include/fc/crypto/equihash.hpp
Normal file
22
include/fc/crypto/equihash.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
|
||||
namespace fc { namespace equihash {
|
||||
|
||||
struct proof
|
||||
{
|
||||
uint32_t n;
|
||||
uint32_t k;
|
||||
sha256 seed;
|
||||
std::vector< uint32_t > inputs;
|
||||
|
||||
bool is_valid( bool test_canonical_order = false, bool test_intermediate_zeros = false ) const;
|
||||
void canonize_indexes();
|
||||
|
||||
static proof hash( uint32_t n, uint32_t k, sha256 seed );
|
||||
};
|
||||
|
||||
} } // fc
|
||||
|
||||
FC_REFLECT( fc::equihash::proof, (n)(k)(seed)(inputs) )
|
||||
|
|
@ -68,15 +68,34 @@ class sha256
|
|||
friend bool operator > ( const sha256& h1, const sha256& h2 );
|
||||
friend bool operator < ( const sha256& h1, const sha256& h2 );
|
||||
|
||||
uint32_t pop_count()
|
||||
uint32_t pop_count()const
|
||||
{
|
||||
return (uint32_t)(__builtin_popcountll(_hash[0]) +
|
||||
__builtin_popcountll(_hash[1]) +
|
||||
__builtin_popcountll(_hash[2]) +
|
||||
__builtin_popcountll(_hash[3]));
|
||||
}
|
||||
|
||||
uint64_t _hash[4];
|
||||
|
||||
/**
|
||||
* Count leading zero bits
|
||||
*/
|
||||
uint16_t clz()const;
|
||||
|
||||
/**
|
||||
* Approximate (log_2(x) + 1) * 2**24.
|
||||
*
|
||||
* Detailed specs:
|
||||
* - Return 0 when x == 0.
|
||||
* - High 8 bits of result simply counts nonzero bits.
|
||||
* - Low 24 bits of result are the 24 bits of input immediately after the most significant 1 in the input.
|
||||
* - If above would require reading beyond the end of the input, zeros are used instead.
|
||||
*/
|
||||
uint32_t approx_log_32()const;
|
||||
|
||||
void set_to_inverse_approx_log_32( uint32_t x );
|
||||
static double inverse_approx_log_32_double( uint32_t x );
|
||||
|
||||
uint64_t _hash[4];
|
||||
};
|
||||
|
||||
typedef sha256 uint256;
|
||||
|
|
@ -99,5 +118,17 @@ namespace std
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<>
|
||||
struct hash<fc::sha256>
|
||||
{
|
||||
size_t operator()( const fc::sha256& s )const
|
||||
{
|
||||
return s._hash[3];//*((size_t*)&s);
|
||||
}
|
||||
};
|
||||
}
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
FC_REFLECT_TYPENAME( fc::sha256 )
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace fc
|
|||
const std::string& what_value = "unspecified");
|
||||
exception( const exception& e );
|
||||
exception( exception&& e );
|
||||
~exception();
|
||||
virtual ~exception();
|
||||
|
||||
const char* name()const throw();
|
||||
int64_t code()const throw();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace fc {
|
|||
path();
|
||||
~path();
|
||||
path( const boost::filesystem::path& );
|
||||
path( const fc::string& p );
|
||||
path( const std::string& p );
|
||||
/// Constructor to build path using unicode native characters.
|
||||
path(const std::wstring& p);
|
||||
path( const char* );
|
||||
|
|
@ -54,12 +54,12 @@ namespace fc {
|
|||
fc::path extension()const;
|
||||
fc::path filename()const;
|
||||
fc::path parent_path()const;
|
||||
fc::string string()const;
|
||||
fc::string generic_string()const;
|
||||
std::string string()const;
|
||||
std::string generic_string()const;
|
||||
/** On windows, returns a path where all path separators are '\' suitable for displaying
|
||||
* to users. On other platforms, it does the same as generic_string()
|
||||
*/
|
||||
fc::string preferred_string() const;
|
||||
std::string preferred_string() const;
|
||||
|
||||
std::wstring wstring() const;
|
||||
std::wstring generic_wstring() const;
|
||||
|
|
@ -77,7 +77,7 @@ namespace fc {
|
|||
*
|
||||
* @note not part of boost::filesystem::path
|
||||
*/
|
||||
fc::string windows_string()const;
|
||||
std::string windows_string()const;
|
||||
|
||||
bool is_relative()const;
|
||||
bool is_absolute()const;
|
||||
|
|
|
|||
161
include/fc/fixed_string.hpp
Normal file
161
include/fc/fixed_string.hpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
|
||||
namespace fc {
|
||||
|
||||
|
||||
/**
|
||||
* This class is designed to offer in-place memory allocation of a string up to Length equal to
|
||||
* sizeof(Storage).
|
||||
*
|
||||
* The string will serialize the same way as std::string for variant and raw formats
|
||||
* The string will sort according to the comparison operators defined for Storage, this enables effecient
|
||||
* sorting.
|
||||
*/
|
||||
template<typename Storage = std::pair<uint64_t,uint64_t> >
|
||||
class fixed_string {
|
||||
public:
|
||||
fixed_string(){}
|
||||
fixed_string( const fixed_string& c ):data(c.data){}
|
||||
|
||||
fixed_string( const std::string& str ) {
|
||||
if( str.size() <= sizeof(data) )
|
||||
memcpy( (char*)&data, str.c_str(), str.size() );
|
||||
else {
|
||||
memcpy( (char*)&data, str.c_str(), sizeof(data) );
|
||||
}
|
||||
}
|
||||
fixed_string( const char* str ) {
|
||||
auto l = strlen(str);
|
||||
if( l <= sizeof(data) )
|
||||
memcpy( (char*)&data, str, l );
|
||||
else {
|
||||
memcpy( (char*)&data, str, sizeof(data) );
|
||||
}
|
||||
}
|
||||
|
||||
operator std::string()const {
|
||||
const char* self = (const char*)&data;
|
||||
return std::string( self, self + size() );
|
||||
}
|
||||
|
||||
uint32_t size()const {
|
||||
if( *(((const char*)&data)+sizeof(data) - 1) )
|
||||
return sizeof(data);
|
||||
return strnlen( (const char*)&data, sizeof(data) );
|
||||
}
|
||||
uint32_t length()const { return size(); }
|
||||
|
||||
fixed_string& operator=( const fixed_string& str ) {
|
||||
data = str.data;
|
||||
return *this;
|
||||
}
|
||||
fixed_string& operator=( const char* str ) {
|
||||
return *this = fixed_string(str);
|
||||
}
|
||||
|
||||
fixed_string& operator=( const std::string& str ) {
|
||||
if( str.size() <= sizeof(data) ) {
|
||||
data = Storage();
|
||||
memcpy( (char*)&data, str.c_str(), str.size() );
|
||||
}
|
||||
else {
|
||||
memcpy( (char*)&data, str.c_str(), sizeof(data) );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::string operator + ( const fixed_string& a, const std::string& b ) {
|
||||
return std::string(a) + b;
|
||||
}
|
||||
friend std::string operator + ( const std::string& a, const fixed_string& b ) {
|
||||
return a + std::string(b);
|
||||
}
|
||||
|
||||
friend bool operator < ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data < b.data;
|
||||
}
|
||||
friend bool operator <= ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data <= b.data;
|
||||
}
|
||||
friend bool operator > ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data > b.data;
|
||||
}
|
||||
friend bool operator >= ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data >= b.data;
|
||||
}
|
||||
friend bool operator == ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data == b.data;
|
||||
}
|
||||
friend bool operator != ( const fixed_string& a, const fixed_string& b ) {
|
||||
return a.data != b.data;
|
||||
}
|
||||
//private:
|
||||
Storage data;
|
||||
};
|
||||
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream, typename Storage>
|
||||
inline void pack( Stream& s, const fc::fixed_string<Storage>& u ) {
|
||||
unsigned_int size = u.size();
|
||||
pack( s, size );
|
||||
s.write( (const char*)&u.data, size );
|
||||
}
|
||||
|
||||
template<typename Stream, typename Storage>
|
||||
inline void unpack( Stream& s, fc::fixed_string<Storage>& u ) {
|
||||
unsigned_int size;
|
||||
fc::raw::unpack( s, size );
|
||||
if( size.value > 0 ) {
|
||||
if( size.value > sizeof(Storage) ) {
|
||||
s.read( (char*)&u.data, sizeof(Storage) );
|
||||
char buf[1024];
|
||||
size_t left = size.value - sizeof(Storage);
|
||||
while( left >= 1024 )
|
||||
{
|
||||
s.read( buf, 1024 );
|
||||
left -= 1024;
|
||||
}
|
||||
s.read( buf, left );
|
||||
|
||||
/*
|
||||
s.seekp( s.tellp() + (size.value - sizeof(Storage)) );
|
||||
char tmp;
|
||||
size.value -= sizeof(storage);
|
||||
while( size.value ){ s.read( &tmp, 1 ); --size.value; }
|
||||
*/
|
||||
// s.skip( size.value - sizeof(Storage) );
|
||||
} else {
|
||||
s.read( (char*)&u.data, size.value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
template<typename Stream, typename... Args>
|
||||
inline void pack( Stream& s, const boost::multiprecision::number<Args...>& d ) {
|
||||
s.write( (const char*)&d, sizeof(d) );
|
||||
}
|
||||
|
||||
template<typename Stream, typename... Args>
|
||||
inline void unpack( Stream& s, boost::multiprecision::number<Args...>& u ) {
|
||||
s.read( (const char*)&u, sizeof(u) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#include <fc/variant.hpp>
|
||||
namespace fc {
|
||||
template<typename Storage>
|
||||
void to_variant( const fixed_string<Storage>& s, variant& v ) {
|
||||
v = std::string(s);
|
||||
}
|
||||
|
||||
template<typename Storage>
|
||||
void from_variant( const variant& v, fixed_string<Storage>& s ) {
|
||||
s = v.as_string();
|
||||
}
|
||||
}
|
||||
143
include/fc/interprocess/container.hpp
Normal file
143
include/fc/interprocess/container.hpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#pragma once
|
||||
|
||||
#include <fc/variant.hpp>
|
||||
#include <boost/interprocess/allocators/allocator.hpp>
|
||||
#include <boost/interprocess/containers/string.hpp>
|
||||
#include <boost/interprocess/containers/vector.hpp>
|
||||
#include <boost/interprocess/containers/map.hpp>
|
||||
#include <boost/interprocess/containers/flat_map.hpp>
|
||||
#include <boost/interprocess/containers/set.hpp>
|
||||
#include <boost/interprocess/containers/deque.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace bip = boost::interprocess;
|
||||
|
||||
template<typename... T >
|
||||
void to_variant( const bip::deque< T... >& t, fc::variant& v ) {
|
||||
std::vector<variant> vars(t.size());
|
||||
for( size_t i = 0; i < t.size(); ++i ) {
|
||||
vars[i] = t[i];
|
||||
}
|
||||
v = std::move(vars);
|
||||
}
|
||||
|
||||
template<typename T, typename... A>
|
||||
void from_variant( const fc::variant& v, bip::deque< T, A... >& d ) {
|
||||
const variants& vars = v.get_array();
|
||||
d.clear();
|
||||
d.resize( vars.size() );
|
||||
for( uint32_t i = 0; i < vars.size(); ++i ) {
|
||||
from_variant( vars[i], d[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//bip::map == boost::map
|
||||
template<typename K, typename V, typename... T >
|
||||
void to_variant( const bip::map< K, V, T... >& var, fc::variant& vo ) {
|
||||
std::vector< variant > vars(var.size());
|
||||
size_t i = 0;
|
||||
for( auto itr = var.begin(); itr != var.end(); ++itr, ++i )
|
||||
vars[i] = fc::variant(*itr);
|
||||
vo = vars;
|
||||
}
|
||||
/*
|
||||
template<typename K, typename V, typename... A>
|
||||
void from_variant( const variant& var, bip::map<K, V, A...>& vo )
|
||||
{
|
||||
const variants& vars = var.get_array();
|
||||
vo.clear();
|
||||
for( auto itr = vars.begin(); itr != vars.end(); ++itr )
|
||||
vo.insert( itr->as< std::pair<K,V> >() ); Not safe for interprocess. Needs allocator
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename... T >
|
||||
void to_variant( const bip::vector< T... >& t, fc::variant& v ) {
|
||||
std::vector<variant> vars(t.size());
|
||||
for( size_t i = 0; i < t.size(); ++i ) {
|
||||
vars[i] = t[i];
|
||||
}
|
||||
v = std::move(vars);
|
||||
}
|
||||
|
||||
template<typename T, typename... A>
|
||||
void from_variant( const fc::variant& v, bip::vector< T, A... >& d ) {
|
||||
const variants& vars = v.get_array();
|
||||
d.clear();
|
||||
d.resize( vars.size() );
|
||||
for( uint32_t i = 0; i < vars.size(); ++i ) {
|
||||
from_variant( vars[i], d[i] );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... T >
|
||||
void to_variant( const bip::set< T... >& t, fc::variant& v ) {
|
||||
std::vector<variant> vars;
|
||||
vars.reserve(t.size());
|
||||
for( const auto& item : t ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
v = std::move(vars);
|
||||
}
|
||||
|
||||
/*
|
||||
template<typename T, typename... A>
|
||||
void from_variant( const fc::variant& v, bip::set< T, A... >& d ) {
|
||||
const variants& vars = v.get_array();
|
||||
d.clear();
|
||||
d.reserve( vars.size() );
|
||||
for( uint32_t i = 0; i < vars.size(); ++i ) {
|
||||
from_variant( vars[i], d[i] ); Not safe for interprocess. Needs allocator
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template<typename... A>
|
||||
void to_variant( const bip::vector<char, A...>& t, fc::variant& v )
|
||||
{
|
||||
if( t.size() )
|
||||
v = variant(fc::to_hex(t.data(), t.size()));
|
||||
else
|
||||
v = "";
|
||||
}
|
||||
|
||||
template<typename... A>
|
||||
void from_variant( const fc::variant& v, bip::vector<char, A...>& d )
|
||||
{
|
||||
auto str = v.as_string();
|
||||
d.resize( str.size() / 2 );
|
||||
if( d.size() )
|
||||
{
|
||||
size_t r = fc::from_hex( str, d.data(), d.size() );
|
||||
FC_ASSERT( r == d.size() );
|
||||
}
|
||||
// std::string b64 = base64_decode( var.as_string() );
|
||||
// vo = std::vector<char>( b64.c_str(), b64.c_str() + b64.size() );
|
||||
}
|
||||
|
||||
namespace raw {
|
||||
namespace bip = boost::interprocess;
|
||||
|
||||
template<typename Stream, typename T, typename... A>
|
||||
inline void pack( Stream& s, const bip::vector<T,A...>& value ) {
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
auto itr = value.begin();
|
||||
auto end = value.end();
|
||||
while( itr != end ) {
|
||||
fc::raw::pack( s, *itr );
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
template<typename Stream, typename T, typename... A>
|
||||
inline void unpack( Stream& s, bip::vector<T,A...>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
value.clear(); value.resize(size);
|
||||
for( auto& item : value )
|
||||
fc::raw::unpack( s, item );
|
||||
}
|
||||
}
|
||||
}
|
||||
44
include/fc/interprocess/file_mutex.hpp
Normal file
44
include/fc/interprocess/file_mutex.hpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/thread/spin_yield_lock.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace fc {
|
||||
class microseconds;
|
||||
class time_point;
|
||||
class path;
|
||||
struct context;
|
||||
|
||||
namespace detail { class file_mutex_impl; }
|
||||
|
||||
/**
|
||||
* The purpose of this class is to support synchronization of
|
||||
* processes, threads, and coop-threads.
|
||||
*
|
||||
* Before grabbing the lock for a thread or coop, a file_mutex will first
|
||||
* grab a process-level lock. After grabbing the process level lock, it will
|
||||
* synchronize in the same way as a local process lock.
|
||||
*/
|
||||
class file_mutex {
|
||||
public:
|
||||
file_mutex( const fc::path& filename );
|
||||
~file_mutex();
|
||||
|
||||
bool try_lock();
|
||||
bool try_lock_for( const microseconds& rel_time );
|
||||
bool try_lock_until( const time_point& abs_time );
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
void lock_shared();
|
||||
void unlock_shared();
|
||||
bool try_lock_shared();
|
||||
|
||||
int readers()const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<detail::file_mutex_impl> my;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
|
@ -123,6 +123,7 @@ namespace fc { namespace json_relaxed
|
|||
char c2 = in.peek();
|
||||
if( c2 == q )
|
||||
{
|
||||
in.get();
|
||||
char c3 = in.peek();
|
||||
if( c3 == q )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@
|
|||
|
||||
namespace fc {
|
||||
namespace raw {
|
||||
|
||||
template<typename Stream, typename Arg0, typename... Args>
|
||||
inline void pack( Stream& s, const Arg0& a0, Args... args ) {
|
||||
pack( s, a0 );
|
||||
pack( s, args... );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
inline void pack( Stream& s, const fc::exception& e )
|
||||
{
|
||||
|
|
@ -547,6 +554,20 @@ namespace fc {
|
|||
return vec;
|
||||
}
|
||||
|
||||
template<typename T, typename... Next>
|
||||
inline std::vector<char> pack( const T& v, Next... next ) {
|
||||
datastream<size_t> ps;
|
||||
fc::raw::pack(ps,v,next...);
|
||||
std::vector<char> vec(ps.tellp());
|
||||
|
||||
if( vec.size() ) {
|
||||
datastream<char*> ds( vec.data(), size_t(vec.size()) );
|
||||
fc::raw::pack(ds,v,next...);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline T unpack( const std::vector<char>& s )
|
||||
{ try {
|
||||
|
|
|
|||
|
|
@ -25,12 +25,22 @@ namespace fc {
|
|||
namespace ip { class endpoint; }
|
||||
|
||||
namespace ecc { class public_key; class private_key; }
|
||||
template<typename Storage> class fixed_string;
|
||||
|
||||
namespace raw {
|
||||
template<typename T>
|
||||
inline size_t pack_size( const T& v );
|
||||
|
||||
template<typename Stream, typename Storage> inline void pack( Stream& s, const fc::fixed_string<Storage>& u );
|
||||
template<typename Stream, typename Storage> inline void unpack( Stream& s, fc::fixed_string<Storage>& u );
|
||||
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void pack( Stream& s, const fc::enum_type<IntType,EnumType>& tp );
|
||||
template<typename Stream, typename IntType, typename EnumType>
|
||||
inline void unpack( Stream& s, fc::enum_type<IntType,EnumType>& tp );
|
||||
|
||||
|
||||
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::set<T>& value );
|
||||
template<typename Stream, typename T> inline void unpack( Stream& s, std::set<T>& value );
|
||||
template<typename Stream, typename T> inline void pack( Stream& s, const std::unordered_set<T>& value );
|
||||
|
|
@ -51,8 +61,8 @@ namespace fc {
|
|||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::map<K,V>& value );
|
||||
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const flat_map<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, flat_map<K,V>& value );
|
||||
template<typename Stream, typename K, typename... V> inline void pack( Stream& s, const flat_map<K,V...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... A> inline void unpack( Stream& s, flat_map<K,V,A...>& value );
|
||||
|
||||
template<typename Stream, typename K, typename V> inline void pack( Stream& s, const std::pair<K,V>& value );
|
||||
template<typename Stream, typename K, typename V> inline void unpack( Stream& s, std::pair<K,V>& value );
|
||||
|
|
|
|||
|
|
@ -40,11 +40,12 @@ namespace fc {
|
|||
struct request
|
||||
{
|
||||
fc::string get_header( const fc::string& key )const;
|
||||
fc::string remote_endpoint;
|
||||
fc::string method;
|
||||
fc::string domain;
|
||||
fc::string path;
|
||||
std::vector<header> headers;
|
||||
std::vector<char> body;
|
||||
std::vector<header> headers;
|
||||
std::vector<char> body;
|
||||
};
|
||||
|
||||
std::vector<header> parse_urlencoded_params( const fc::string& f );
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
|
||||
namespace fc { namespace http {
|
||||
namespace detail {
|
||||
class abstract_websocket_server;
|
||||
class websocket_server_impl;
|
||||
class websocket_tls_server_impl;
|
||||
class websocket_client_impl;
|
||||
class websocket_tls_client_impl;
|
||||
} // namespace detail;
|
||||
|
|
@ -41,7 +42,7 @@ namespace fc { namespace http {
|
|||
class websocket_server
|
||||
{
|
||||
public:
|
||||
websocket_server(bool enable_permessage_deflate = true);
|
||||
websocket_server();
|
||||
~websocket_server();
|
||||
|
||||
void on_connection( const on_connection_handler& handler);
|
||||
|
|
@ -50,16 +51,16 @@ namespace fc { namespace http {
|
|||
void start_accept();
|
||||
|
||||
private:
|
||||
std::unique_ptr<detail::abstract_websocket_server> my;
|
||||
friend class detail::websocket_server_impl;
|
||||
std::unique_ptr<detail::websocket_server_impl> my;
|
||||
};
|
||||
|
||||
|
||||
class websocket_tls_server
|
||||
{
|
||||
public:
|
||||
websocket_tls_server(const std::string& server_pem = std::string(),
|
||||
const std::string& ssl_password = std::string(),
|
||||
bool enable_permessage_deflate = false);
|
||||
websocket_tls_server( const std::string& server_pem = std::string(),
|
||||
const std::string& ssl_password = std::string());
|
||||
~websocket_tls_server();
|
||||
|
||||
void on_connection( const on_connection_handler& handler);
|
||||
|
|
@ -68,13 +69,14 @@ namespace fc { namespace http {
|
|||
void start_accept();
|
||||
|
||||
private:
|
||||
std::unique_ptr<detail::abstract_websocket_server> my;
|
||||
friend class detail::websocket_tls_server_impl;
|
||||
std::unique_ptr<detail::websocket_tls_server_impl> my;
|
||||
};
|
||||
|
||||
class websocket_client
|
||||
{
|
||||
public:
|
||||
websocket_client();
|
||||
websocket_client( const std::string& ca_filename = "_default" );
|
||||
~websocket_client();
|
||||
|
||||
websocket_connection_ptr connect( const std::string& uri );
|
||||
|
|
@ -86,7 +88,7 @@ namespace fc { namespace http {
|
|||
class websocket_tls_client
|
||||
{
|
||||
public:
|
||||
websocket_tls_client();
|
||||
websocket_tls_client( const std::string& ca_filename = "_default" );
|
||||
~websocket_tls_client();
|
||||
|
||||
websocket_connection_ptr connect( const std::string& uri );
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <fc/io/iostream.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/noncopyable.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace ip { class endpoint; }
|
||||
|
||||
class udt_socket : public virtual iostream, public noncopyable
|
||||
{
|
||||
public:
|
||||
udt_socket();
|
||||
~udt_socket();
|
||||
|
||||
void bind( const fc::ip::endpoint& local_endpoint );
|
||||
void connect_to( const fc::ip::endpoint& remote_endpoint );
|
||||
|
||||
fc::ip::endpoint remote_endpoint() const;
|
||||
fc::ip::endpoint local_endpoint() const;
|
||||
|
||||
using istream::get;
|
||||
void get( char& c )
|
||||
{
|
||||
read( &c, 1 );
|
||||
}
|
||||
|
||||
|
||||
/// istream interface
|
||||
/// @{
|
||||
virtual size_t readsome( char* buffer, size_t max );
|
||||
virtual size_t readsome( const std::shared_ptr<char>& buf, size_t len, size_t offset );
|
||||
virtual bool eof()const;
|
||||
/// @}
|
||||
|
||||
/// ostream interface
|
||||
/// @{
|
||||
virtual size_t writesome( const char* buffer, size_t len );
|
||||
virtual size_t writesome( const std::shared_ptr<const char>& buf, size_t len, size_t offset );
|
||||
virtual void flush();
|
||||
virtual void close();
|
||||
/// @}
|
||||
|
||||
void open();
|
||||
bool is_open()const;
|
||||
|
||||
private:
|
||||
friend class udt_server;
|
||||
int _udt_socket_id;
|
||||
};
|
||||
typedef std::shared_ptr<udt_socket> udt_socket_ptr;
|
||||
|
||||
class udt_server : public noncopyable
|
||||
{
|
||||
public:
|
||||
udt_server();
|
||||
~udt_server();
|
||||
|
||||
void close();
|
||||
void accept( udt_socket& s );
|
||||
|
||||
void listen( const fc::ip::endpoint& ep );
|
||||
fc::ip::endpoint local_endpoint() const;
|
||||
|
||||
private:
|
||||
int _udt_socket_id;
|
||||
};
|
||||
|
||||
} // fc
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <fc/utility.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
|
|
@ -111,7 +112,7 @@ void fc::reflector<TYPE>::visit( const Visitor& v ) { \
|
|||
|
||||
|
||||
#define FC_REFLECT_VISIT_ENUM( r, enum_type, elem ) \
|
||||
v.TEMPLATE operator()<enum_type::elem>(BOOST_PP_STRINGIZE(elem));
|
||||
v.operator()(BOOST_PP_STRINGIZE(elem), int64_t(enum_type::elem) );
|
||||
#define FC_REFLECT_ENUM_TO_STRING( r, enum_type, elem ) \
|
||||
case enum_type::elem: return BOOST_PP_STRINGIZE(elem);
|
||||
#define FC_REFLECT_ENUM_TO_FC_STRING( r, enum_type, elem ) \
|
||||
|
|
@ -119,7 +120,8 @@ void fc::reflector<TYPE>::visit( const Visitor& v ) { \
|
|||
|
||||
#define FC_REFLECT_ENUM_FROM_STRING( r, enum_type, elem ) \
|
||||
if( strcmp( s, BOOST_PP_STRINGIZE(elem) ) == 0 ) return enum_type::elem;
|
||||
|
||||
#define FC_REFLECT_ENUM_FROM_STRING_CASE( r, enum_type, elem ) \
|
||||
case enum_type::elem:
|
||||
|
||||
#define FC_REFLECT_ENUM( ENUM, FIELDS ) \
|
||||
namespace fc { \
|
||||
|
|
@ -146,11 +148,37 @@ template<> struct reflector<ENUM> { \
|
|||
static fc::string to_fc_string(int64_t i) { \
|
||||
return to_fc_string(ENUM(i)); \
|
||||
} \
|
||||
static ENUM from_int(int64_t i) { \
|
||||
ENUM e = ENUM(i); \
|
||||
switch( e ) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING_CASE, ENUM, FIELDS ) \
|
||||
break; \
|
||||
default: \
|
||||
fc::throw_bad_enum_cast( i, BOOST_PP_STRINGIZE(ENUM) ); \
|
||||
} \
|
||||
return e;\
|
||||
} \
|
||||
static ENUM from_string( const char* s ) { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_ENUM_FROM_STRING, ENUM, FIELDS ) \
|
||||
return ENUM(atoi(s));\
|
||||
int64_t i = 0; \
|
||||
try \
|
||||
{ \
|
||||
i = boost::lexical_cast<int64_t>(s); \
|
||||
} \
|
||||
catch( const boost::bad_lexical_cast& e ) \
|
||||
{ \
|
||||
fc::throw_bad_enum_cast( s, BOOST_PP_STRINGIZE(ENUM) ); \
|
||||
} \
|
||||
return from_int(i); \
|
||||
} \
|
||||
template< typename Visitor > \
|
||||
static void visit( Visitor& v ) \
|
||||
{ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_ENUM, ENUM, FIELDS ) \
|
||||
} \
|
||||
}; \
|
||||
template<> struct get_typename<ENUM> { static const char* name() { return BOOST_PP_STRINGIZE(ENUM); } }; \
|
||||
}
|
||||
|
||||
/* Note: FC_REFLECT_ENUM previously defined this function, but I don't think it ever
|
||||
|
|
|
|||
|
|
@ -88,8 +88,8 @@ namespace fc
|
|||
{
|
||||
if( v.is_string() )
|
||||
o = fc::reflector<T>::from_string( v.get_string().c_str() );
|
||||
else
|
||||
o = static_cast<T>(v.as_int64());
|
||||
else
|
||||
o = fc::reflector<T>::from_int( v.as_int64() );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
namespace fc {
|
||||
class api_connection;
|
||||
|
||||
typedef uint32_t api_id_type;
|
||||
|
||||
namespace detail {
|
||||
template<typename Signature>
|
||||
|
|
@ -68,6 +66,33 @@ namespace fc {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* If api<T> is returned from a remote method, the API is eagerly bound to api<T> of
|
||||
* the correct type in api_visitor::from_variant(). This binding [1] needs a reference
|
||||
* to the api_connection, which is made available to from_variant() as a parameter.
|
||||
*
|
||||
* However, in the case of a remote method which returns api_base which can subsequently
|
||||
* be cast by the caller with as<T>, we need to keep track of the connection because
|
||||
* the binding is done later (when the client code actually calls as<T>).
|
||||
*
|
||||
* [1] The binding actually happens in get_remote_api().
|
||||
*/
|
||||
class any_api : public api_base
|
||||
{
|
||||
public:
|
||||
any_api( api_id_type api_id, const std::shared_ptr<fc::api_connection>& con )
|
||||
: _api_id(api_id), _api_connection(con) {}
|
||||
|
||||
virtual uint64_t get_handle()const override
|
||||
{ return _api_id; }
|
||||
|
||||
virtual api_id_type register_api( api_connection& conn )const override
|
||||
{ FC_ASSERT( false ); return api_id_type(); }
|
||||
|
||||
api_id_type _api_id;
|
||||
std::weak_ptr<fc::api_connection> _api_connection;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class generic_api
|
||||
|
|
@ -143,7 +168,7 @@ namespace fc {
|
|||
|
||||
struct api_visitor
|
||||
{
|
||||
api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):api(a),_api_con(s){ }
|
||||
api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):_api(a),_api_con(s){ }
|
||||
|
||||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
|
||||
|
|
@ -151,6 +176,9 @@ namespace fc {
|
|||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::optional<api<Interface,Adaptor>>(Args...)>& f )const;
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::api_ptr(Args...)>& f )const;
|
||||
|
||||
template<typename R, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const;
|
||||
|
||||
|
|
@ -159,11 +187,11 @@ namespace fc {
|
|||
|
||||
template<typename Result, typename... Args>
|
||||
void operator()( const char* name, std::function<Result(Args...)>& memb )const {
|
||||
api._methods.emplace_back( to_generic( memb ) );
|
||||
api._by_name[name] = api._methods.size() - 1;
|
||||
_api._methods.emplace_back( to_generic( memb ) );
|
||||
_api._by_name[name] = _api._methods.size() - 1;
|
||||
}
|
||||
|
||||
generic_api& api;
|
||||
generic_api& _api;
|
||||
const std::weak_ptr<fc::api_connection>& _api_con;
|
||||
};
|
||||
|
||||
|
|
@ -267,6 +295,17 @@ namespace fc {
|
|||
return con->get_remote_api<ResultInterface>( v.as_uint64() );
|
||||
}
|
||||
|
||||
static fc::api_ptr from_variant(
|
||||
const variant& v,
|
||||
fc::api_ptr* /* used for template deduction */,
|
||||
const std::shared_ptr<fc::api_connection>& con
|
||||
)
|
||||
{
|
||||
if( v.is_null() )
|
||||
return fc::api_ptr();
|
||||
return fc::api_ptr( new detail::any_api( v.as_uint64(), con ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>&, const T& v )
|
||||
{
|
||||
|
|
@ -345,7 +384,7 @@ namespace fc {
|
|||
const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &api;
|
||||
auto gapi = &_api;
|
||||
return [=]( const variants& args ) {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
|
@ -359,7 +398,7 @@ namespace fc {
|
|||
const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &api;
|
||||
auto gapi = &_api;
|
||||
return [=]( const variants& args )-> fc::variant {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
|
@ -370,10 +409,28 @@ namespace fc {
|
|||
return variant();
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
|
||||
const std::function<fc::api_ptr(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &_api;
|
||||
return [=]( const variants& args ) -> fc::variant {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
||||
auto api_result = gapi->call_generic( f, args.begin(), args.end() );
|
||||
if( !api_result )
|
||||
return variant();
|
||||
return api_result->register_api( *con );
|
||||
};
|
||||
}
|
||||
|
||||
template<typename R, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
|
||||
{
|
||||
generic_api* gapi = &api;
|
||||
generic_api* gapi = &_api;
|
||||
return [f,gapi]( const variants& args ) {
|
||||
return variant( gapi->call_generic( f, args.begin(), args.end() ) );
|
||||
};
|
||||
|
|
@ -382,13 +439,47 @@ namespace fc {
|
|||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
|
||||
{
|
||||
generic_api* gapi = &api;
|
||||
generic_api* gapi = &_api;
|
||||
return [f,gapi]( const variants& args ) {
|
||||
gapi->call_generic( f, args.begin(), args.end() );
|
||||
return variant();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* It is slightly unclean tight coupling to have this method in the api class.
|
||||
* It breaks encapsulation by requiring an api class method to have a pointer
|
||||
* to an api_connection. The reason this is necessary is we have a goal of being
|
||||
* able to call register_api() on an api<T> through its base class api_base. But
|
||||
* register_api() must know the template parameters!
|
||||
*
|
||||
* The only reasonable way to achieve the goal is to implement register_api()
|
||||
* as a method in api<T> (which obviously knows the template parameter T),
|
||||
* then make the implementation accessible through the base class (by making
|
||||
* it a pure virtual method in the base class which is overridden by the subclass's
|
||||
* implementation).
|
||||
*/
|
||||
template< typename Interface, typename Transform >
|
||||
api_id_type api< Interface, Transform >::register_api( api_connection& conn )const
|
||||
{
|
||||
return conn.register_api( *this );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
api<T> api_base::as()
|
||||
{
|
||||
// TODO: this method should probably be const (if it is not too hard)
|
||||
api<T>* maybe_requested_type = dynamic_cast< api<T>* >(this);
|
||||
if( maybe_requested_type != nullptr )
|
||||
return *maybe_requested_type;
|
||||
|
||||
detail::any_api* maybe_any = dynamic_cast< detail::any_api* >(this);
|
||||
FC_ASSERT( maybe_any != nullptr );
|
||||
std::shared_ptr< api_connection > api_conn = maybe_any->_api_connection.lock();
|
||||
FC_ASSERT( api_conn );
|
||||
return api_conn->get_remote_api<T>( maybe_any->_api_id );
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template<typename Signature>
|
||||
template<typename... Args>
|
||||
|
|
|
|||
532
include/fc/rpc/binary_api_connection.hpp
Normal file
532
include/fc/rpc/binary_api_connection.hpp
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
#pragma once
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/any.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <fc/signals.hpp>
|
||||
//#include <fc/rpc/json_connection.hpp>
|
||||
|
||||
namespace fc {
|
||||
class binary_api_connection;
|
||||
|
||||
namespace detail {
|
||||
template<typename Signature>
|
||||
class callback_functor
|
||||
{
|
||||
public:
|
||||
typedef typename std::function<Signature>::result_type result_type;
|
||||
|
||||
callback_functor( std::weak_ptr< fc::binary_api_connection > con, uint64_t id )
|
||||
:_callback_id(id),_binary_api_connection(con){}
|
||||
|
||||
template<typename... Args>
|
||||
result_type operator()( Args... args )const;
|
||||
|
||||
private:
|
||||
uint64_t _callback_id;
|
||||
std::weak_ptr< fc::binary_api_connection > _binary_api_connection;
|
||||
};
|
||||
|
||||
template<typename R, typename Arg0, typename ... Args>
|
||||
std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )
|
||||
{
|
||||
return [=]( Args... args ) { return f( a0, args... ); };
|
||||
}
|
||||
template<typename R>
|
||||
R call_generic( const std::function<R()>& f, variants::const_iterator a0, variants::const_iterator e )
|
||||
{
|
||||
return f();
|
||||
}
|
||||
|
||||
template<typename R, typename Arg0, typename ... Args>
|
||||
R call_generic( const std::function<R(Arg0,Args...)>& f, variants::const_iterator a0, variants::const_iterator e )
|
||||
{
|
||||
FC_ASSERT( a0 != e );
|
||||
return call_generic<R,Args...>( bind_first_arg<R,Arg0,Args...>( f, a0->as< typename std::decay<Arg0>::type >() ), a0+1, e );
|
||||
}
|
||||
|
||||
template<typename R, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )
|
||||
{
|
||||
return [=]( const variants& args ) {
|
||||
return variant( call_generic( f, args.begin(), args.end() ) );
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )
|
||||
{
|
||||
return [=]( const variants& args ) {
|
||||
call_generic( f, args.begin(), args.end() );
|
||||
return variant();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* If api<T> is returned from a remote method, the API is eagerly bound to api<T> of
|
||||
* the correct type in api_visitor::from_variant(). This binding [1] needs a reference
|
||||
* to the binary_api_connection, which is made available to from_variant() as a parameter.
|
||||
*
|
||||
* However, in the case of a remote method which returns api_base which can subsequently
|
||||
* be cast by the caller with as<T>, we need to keep track of the connection because
|
||||
* the binding is done later (when the client code actually calls as<T>).
|
||||
*
|
||||
* [1] The binding actually happens in get_remote_api().
|
||||
*/
|
||||
class any_api : public api_base
|
||||
{
|
||||
public:
|
||||
any_api( api_id_type api_id, const std::shared_ptr<fc::binary_api_connection>& con )
|
||||
: _api_id(api_id), _binary_api_connection(con) {}
|
||||
|
||||
virtual uint64_t get_handle()const override
|
||||
{ return _api_id; }
|
||||
|
||||
virtual api_id_type register_api( binary_api_connection& conn )const override
|
||||
{ FC_ASSERT( false ); return api_id_type(); }
|
||||
|
||||
api_id_type _api_id;
|
||||
std::weak_ptr<fc::binary_api_connection> _binary_api_connection;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class generic_api
|
||||
{
|
||||
public:
|
||||
template<typename Api>
|
||||
generic_api( const Api& a, const std::shared_ptr<fc::binary_api_connection>& c );
|
||||
|
||||
generic_api( const generic_api& cpy ) = delete;
|
||||
|
||||
vector<char> call( const string& name, const vector<char>& args )
|
||||
{
|
||||
auto itr = _by_name.find(name);
|
||||
FC_ASSERT( itr != _by_name.end(), "no method with name '${name}'", ("name",name)("api",_by_name) );
|
||||
return call( itr->second, args );
|
||||
}
|
||||
|
||||
vector<char> call( uint32_t method_id, const vector<char>& args )
|
||||
{
|
||||
FC_ASSERT( method_id < _methods.size() );
|
||||
return _methods[method_id](args);
|
||||
}
|
||||
|
||||
std::weak_ptr< fc::binary_api_connection > get_connection()
|
||||
{
|
||||
return _binary_api_connection;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_method_names()const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
result.reserve( _by_name.size() );
|
||||
for( auto& m : _by_name ) result.push_back(m.first);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct api_visitor;
|
||||
|
||||
template<typename R, typename Arg0, typename ... Args>
|
||||
std::function<R(Args...)> bind_first_arg( const std::function<R(Arg0,Args...)>& f, Arg0 a0 )const
|
||||
{
|
||||
return [=]( Args... args ) { return f( a0, args... ); };
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
R call_generic( const std::function<R()>& f, datastream<const char*>& ds )const
|
||||
{
|
||||
return f();
|
||||
}
|
||||
|
||||
template<typename R, typename Signature, typename ... Args>
|
||||
R call_generic( const std::function<R(std::function<Signature>,Args...)>& f, datastream<const char*>& ds )
|
||||
{
|
||||
uint64_t callback_id = 0;
|
||||
fc::raw::unpack( ds, callback_id );
|
||||
detail::callback_functor<Signature> arg0( get_connection(), callback_id );
|
||||
return call_generic<R,Args...>( this->bind_first_arg<R,std::function<Signature>,Args...>( f, std::function<Signature>(arg0) ), ds );
|
||||
}
|
||||
template<typename R, typename Signature, typename ... Args>
|
||||
R call_generic( const std::function<R(const std::function<Signature>&,Args...)>& f, fc::datastream<const char*>& ds )
|
||||
{
|
||||
uint64_t callback_id = 0;
|
||||
fc::raw::unpack( ds, callback_id );
|
||||
detail::callback_functor<Signature> arg0( get_connection(), callback_id );
|
||||
return call_generic<R,Args...>( this->bind_first_arg<R,const std::function<Signature>&,Args...>( f, arg0 ), ds );
|
||||
}
|
||||
|
||||
template<typename R, typename Arg0, typename ... Args>
|
||||
R call_generic( const std::function<R(Arg0,Args...)>& f, fc::datastream<const char*>& ds )
|
||||
{
|
||||
std::decay<Arg0>::type a0;
|
||||
fc::raw::unpack( ds, a0 );
|
||||
return call_generic<R,Args...>( this->bind_first_arg<R,Arg0,Args...>( f, a0 ), ds );
|
||||
}
|
||||
|
||||
struct api_visitor
|
||||
{
|
||||
api_visitor( generic_api& a, const std::weak_ptr<fc::binary_api_connection>& s ):api(a),_api_con(s){ }
|
||||
|
||||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
|
||||
|
||||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::optional<api<Interface,Adaptor>>(Args...)>& f )const;
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::api_ptr(Args...)>& f )const;
|
||||
|
||||
template<typename R, typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const;
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<variant(const fc::variants&)> to_generic( const std::function<void(Args...)>& f )const;
|
||||
|
||||
template<typename Result, typename... Args>
|
||||
void operator()( const char* name, std::function<Result(Args...)>& memb )const {
|
||||
api._methods.emplace_back( to_generic( memb ) );
|
||||
api._by_name[name] = api._methods.size() - 1;
|
||||
}
|
||||
|
||||
generic_api& api;
|
||||
const std::weak_ptr<fc::binary_api_connection>& _api_con;
|
||||
};
|
||||
|
||||
|
||||
std::weak_ptr<fc::binary_api_connection> _binary_api_connection;
|
||||
fc::any _api;
|
||||
std::map< std::string, uint32_t > _by_name;
|
||||
std::vector< std::function<vector<char>(const vector<char>&)> > _methods;
|
||||
}; // class generic_api
|
||||
|
||||
|
||||
|
||||
class binary_api_connection : public std::enable_shared_from_this<fc::binary_api_connection>
|
||||
{
|
||||
public:
|
||||
typedef std::vector<char> params_type;
|
||||
typedef std::vector<char> result_type;
|
||||
|
||||
binary_api_connection(){}
|
||||
virtual ~binary_api_connection(){};
|
||||
|
||||
|
||||
template<typename T>
|
||||
api<T> get_remote_api( api_id_type api_id = 0 )
|
||||
{
|
||||
api<T> result;
|
||||
result->visit( api_visitor( api_id, this->shared_from_this() ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
/** makes calls to the remote server */
|
||||
virtual result_type send_call( api_id_type api_id, string method_name, params_type args = params_type() ) = 0;
|
||||
virtual result_type send_callback( uint64_t callback_id, params_type args = params_type() ) = 0;
|
||||
virtual void send_notice( uint64_t callback_id, params_type args = params_type() ) = 0;
|
||||
|
||||
result_type receive_call( api_id_type api_id, const string& method_name, const params_type& args = params_type() )const
|
||||
{
|
||||
FC_ASSERT( _local_apis.size() > api_id );
|
||||
return _local_apis[api_id]->call( method_name, args );
|
||||
}
|
||||
result_type receive_callback( uint64_t callback_id, const params_type& args = params_type() )const
|
||||
{
|
||||
FC_ASSERT( _local_callbacks.size() > callback_id );
|
||||
return _local_callbacks[callback_id]( args );
|
||||
}
|
||||
void receive_notice( uint64_t callback_id, const params_type& args = params_type() )const
|
||||
{
|
||||
FC_ASSERT( _local_callbacks.size() > callback_id );
|
||||
_local_callbacks[callback_id]( args );
|
||||
}
|
||||
|
||||
template<typename Interface>
|
||||
api_id_type register_api( const Interface& a )
|
||||
{
|
||||
auto handle = a.get_handle();
|
||||
auto itr = _handle_to_id.find(handle);
|
||||
if( itr != _handle_to_id.end() ) return itr->second;
|
||||
|
||||
_local_apis.push_back( std::unique_ptr<generic_api>( new generic_api(a, shared_from_this() ) ) );
|
||||
_handle_to_id[handle] = _local_apis.size() - 1;
|
||||
return _local_apis.size() - 1;
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
uint64_t register_callback( const std::function<Signature>& cb )
|
||||
{
|
||||
_local_callbacks.push_back( detail::to_generic( cb ) );
|
||||
return _local_callbacks.size() - 1;
|
||||
}
|
||||
|
||||
std::vector<std::string> get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); }
|
||||
|
||||
fc::signal<void()> closed;
|
||||
private:
|
||||
std::vector< std::unique_ptr<generic_api> > _local_apis;
|
||||
std::map< uint64_t, api_id_type > _handle_to_id;
|
||||
std::vector< std::function<variant(const variants&)> > _local_callbacks;
|
||||
|
||||
|
||||
struct api_visitor
|
||||
{
|
||||
uint32_t _api_id;
|
||||
std::shared_ptr<fc::binary_api_connection> _connection;
|
||||
|
||||
api_visitor( uint32_t api_id, std::shared_ptr<fc::binary_api_connection> con )
|
||||
:_api_id(api_id),_connection(std::move(con))
|
||||
{
|
||||
}
|
||||
|
||||
api_visitor() = delete;
|
||||
|
||||
template<typename Result>
|
||||
static Result from_vector( const vector<char>& v, Result*, const std::shared_ptr<fc::binary_api_connection>& )
|
||||
{
|
||||
return fc::raw::unpack<Result>( v );
|
||||
}
|
||||
|
||||
template<typename ResultInterface>
|
||||
static fc::api<ResultInterface> from_vector( const vector<char>& v,
|
||||
fc::api<ResultInterface>* /*used for template deduction*/,
|
||||
const std::shared_ptr<fc::binary_api_connection>& con
|
||||
)
|
||||
{
|
||||
return con->get_remote_api<ResultInterface>( fc::raw::unpack<uint64_t>( v ) );
|
||||
}
|
||||
|
||||
static fc::api_ptr from_vector(
|
||||
const vector<char>& v,
|
||||
fc::api_ptr* /* used for template deduction */,
|
||||
const std::shared_ptr<fc::binary_api_connection>& con
|
||||
)
|
||||
{
|
||||
return fc::api_ptr( new detail::any_api( fc::raw::unpack<uint64_t>(v), con ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static result_type convert_callbacks( const std::shared_ptr<fc::binary_api_connection>&, const T& v )
|
||||
{
|
||||
return fc::raw::pack(v);
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
static result_type convert_callbacks( const std::shared_ptr<fc::binary_api_connection>& con, const std::function<Signature>& v )
|
||||
{
|
||||
return con->register_callback( v );
|
||||
}
|
||||
|
||||
template<typename Result, typename... Args>
|
||||
void operator()( const char* name, std::function<Result(Args...)>& memb )const
|
||||
{
|
||||
auto con = _connection;
|
||||
auto api_id = _api_id;
|
||||
memb = [con,api_id,name]( Args... args ) {
|
||||
auto var_result = con->send_call( api_id, name, { convert_callbacks(con,args)...} );
|
||||
return from_vector( var_result, (Result*)nullptr, con );
|
||||
};
|
||||
}
|
||||
template<typename... Args>
|
||||
void operator()( const char* name, std::function<void(Args...)>& memb )const
|
||||
{
|
||||
auto con = _connection;
|
||||
auto api_id = _api_id;
|
||||
memb = [con,api_id,name]( Args... args ) {
|
||||
con->send_call( api_id, name, { convert_callbacks(con,args)...} );
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class local_binary_api_connection : public binary_api_connection
|
||||
{
|
||||
public:
|
||||
/** makes calls to the remote server */
|
||||
virtual result_type send_call( api_id_type api_id, string method_name, params_type args = params_type() ) override
|
||||
{
|
||||
FC_ASSERT( _remote_connection );
|
||||
return _remote_connection->receive_call( api_id, method_name, std::move(args) );
|
||||
}
|
||||
virtual result_type send_callback( uint64_t callback_id, params_type args = params_type() ) override
|
||||
{
|
||||
FC_ASSERT( _remote_connection );
|
||||
return _remote_connection->receive_callback( callback_id, args );
|
||||
}
|
||||
virtual void send_notice( uint64_t callback_id, params_type args = params_type() ) override
|
||||
{
|
||||
FC_ASSERT( _remote_connection );
|
||||
_remote_connection->receive_notice( callback_id, args );
|
||||
}
|
||||
|
||||
|
||||
void set_remote_connection( const std::shared_ptr<fc::binary_api_connection>& rc )
|
||||
{
|
||||
FC_ASSERT( !_remote_connection );
|
||||
FC_ASSERT( rc != this->shared_from_this() );
|
||||
_remote_connection = rc;
|
||||
}
|
||||
const std::shared_ptr<fc::binary_api_connection>& remote_connection()const { return _remote_connection; }
|
||||
|
||||
std::shared_ptr<fc::binary_api_connection> _remote_connection;
|
||||
};
|
||||
|
||||
template<typename Api>
|
||||
generic_api::generic_api( const Api& a, const std::shared_ptr<fc::binary_api_connection>& c )
|
||||
:_binary_api_connection(c),_api(a)
|
||||
{
|
||||
boost::any_cast<const Api&>(a)->visit( api_visitor( *this, c ) );
|
||||
}
|
||||
|
||||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<result_type(const params_type&)> generic_api::api_visitor::to_generic(
|
||||
const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &api;
|
||||
return [=]( const params_type& args ) {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
||||
fc::raw::datastream<const char*> ds( args.data(), args.size() );
|
||||
auto api_result = gapi->call_generic( f, args );
|
||||
return con->register_api( api_result );
|
||||
};
|
||||
}
|
||||
template<typename Interface, typename Adaptor, typename ... Args>
|
||||
std::function<result_type(const params_type&)> generic_api::api_visitor::to_generic(
|
||||
const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &api;
|
||||
return [=]( const params_type& args )-> fc::variant {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
||||
fc::raw::datastream<const char*> ds( args.data(), args.size() );
|
||||
auto api_result = gapi->call_generic( f, ds );
|
||||
if( api_result )
|
||||
return con->register_api( *api_result );
|
||||
return result_type();
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<result_type(const params_type&)> generic_api::api_visitor::to_generic(
|
||||
const std::function<fc::api_ptr(Args...)>& f )const
|
||||
{
|
||||
auto api_con = _api_con;
|
||||
auto gapi = &api;
|
||||
return [=]( const variants& args ) -> fc::variant {
|
||||
auto con = api_con.lock();
|
||||
FC_ASSERT( con, "not connected" );
|
||||
|
||||
fc::raw::datastream<const char*> ds( args.data(), args.size() );
|
||||
auto api_result = gapi->call_generic( f, ds );
|
||||
if( !api_result )
|
||||
return result_type();
|
||||
return api_result->register_api( *con );
|
||||
};
|
||||
}
|
||||
|
||||
template<typename R, typename ... Args>
|
||||
std::function<result_type(const params_type&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
|
||||
{
|
||||
generic_api* gapi = &api;
|
||||
return [f,gapi]( const params_type& args ) {
|
||||
fc::raw::datastream<const char*> ds( args.data(), args.size() );
|
||||
return fc::raw::pack(gapi->call_generic( f, ds ));
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ... Args>
|
||||
std::function<result_type(const params_type&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
|
||||
{
|
||||
generic_api* gapi = &api;
|
||||
return [f,gapi]( const params_type& args ) {
|
||||
fc::raw::datastream<const char*> ds( args.data(), args.size() );
|
||||
gapi->call_generic( f, ds );
|
||||
return result_type();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* It is slightly unclean tight coupling to have this method in the api class.
|
||||
* It breaks encapsulation by requiring an api class method to have a pointer
|
||||
* to an binary_api_connection. The reason this is necessary is we have a goal of being
|
||||
* able to call register_api() on an api<T> through its base class api_base. But
|
||||
* register_api() must know the template parameters!
|
||||
*
|
||||
* The only reasonable way to achieve the goal is to implement register_api()
|
||||
* as a method in api<T> (which obviously knows the template parameter T),
|
||||
* then make the implementation accessible through the base class (by making
|
||||
* it a pure virtual method in the base class which is overridden by the subclass's
|
||||
* implementation).
|
||||
*/
|
||||
template< typename Interface, typename Transform >
|
||||
api_id_type api< Interface, Transform >::register_api( binary_api_connection& conn )const
|
||||
{
|
||||
return conn.register_api( *this );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
api<T> api_base::as()
|
||||
{
|
||||
// TODO: this method should probably be const (if it is not too hard)
|
||||
api<T>* maybe_requested_type = dynamic_cast< api<T>* >(this);
|
||||
if( maybe_requested_type != nullptr )
|
||||
return *maybe_requested_type;
|
||||
|
||||
detail::any_api* maybe_any = dynamic_cast< detail::any_api* >(this);
|
||||
FC_ASSERT( maybe_any != nullptr );
|
||||
std::shared_ptr< binary_api_connection > api_conn = maybe_any->_binary_api_connection.lock();
|
||||
FC_ASSERT( api_conn );
|
||||
return api_conn->get_remote_api<T>( maybe_any->_api_id );
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template<typename Signature>
|
||||
template<typename... Args>
|
||||
typename callback_functor<Signature>::result_type callback_functor<Signature>::operator()( Args... args )const
|
||||
{
|
||||
std::shared_ptr< fc::binary_api_connection > locked = _binary_api_connection.lock();
|
||||
// TODO: make new exception type for this instead of recycling eof_exception
|
||||
if( !locked )
|
||||
throw fc::eof_exception();
|
||||
|
||||
/// TODO------------->>> pack args...
|
||||
locked->send_callback( _callback_id, fc::raw::pack( args... ) ).template as< result_type >();
|
||||
}
|
||||
|
||||
|
||||
template<typename... Args>
|
||||
class callback_functor<void(Args...)>
|
||||
{
|
||||
public:
|
||||
typedef void result_type;
|
||||
|
||||
callback_functor( std::weak_ptr< fc::binary_api_connection > con, uint64_t id )
|
||||
:_callback_id(id),_binary_api_connection(con){}
|
||||
|
||||
void operator()( Args... args )const
|
||||
{
|
||||
std::shared_ptr< fc::binary_api_connection > locked = _binary_api_connection.lock();
|
||||
// TODO: make new exception type for this instead of recycling eof_exception
|
||||
if( !locked )
|
||||
throw fc::eof_exception();
|
||||
locked->send_notice( _callback_id, fc::variants{ args... } );
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _callback_id;
|
||||
std::weak_ptr< fc::binary_api_connection > _binary_api_connection;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
} // fc
|
||||
58
include/fc/rpc/bstate.hpp
Normal file
58
include/fc/rpc/bstate.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include <fc/variant.hpp>
|
||||
#include <functional>
|
||||
#include <fc/thread/future.hpp>
|
||||
#include <fc/rpc/state.hpp>
|
||||
|
||||
namespace fc { namespace rpc {
|
||||
typedef std::vector<char> params_type;
|
||||
typedef std::vector<char> result_type;
|
||||
|
||||
struct brequest
|
||||
{
|
||||
optional<uint64_t> id;
|
||||
std::string method;
|
||||
params_type params;
|
||||
};
|
||||
|
||||
struct bresponse
|
||||
{
|
||||
bresponse(){}
|
||||
bresponse( int64_t i, result_type r ):id(i),result(r){}
|
||||
bresponse( int64_t i, error_object r ):id(i),error(r){}
|
||||
int64_t id = 0;
|
||||
optional<result_type> result;
|
||||
optional<error_object> error;
|
||||
};
|
||||
|
||||
/** binary RPC state */
|
||||
class bstate
|
||||
{
|
||||
public:
|
||||
typedef std::function<result_type(const params_type&)> method;
|
||||
~bstate();
|
||||
|
||||
void add_method( const fc::string& name, method m );
|
||||
void remove_method( const fc::string& name );
|
||||
|
||||
result_type local_call( const string& method_name, const params_type& args );
|
||||
void handle_reply( const bresponse& response );
|
||||
|
||||
brequest start_remote_call( const string& method_name, params_type args );
|
||||
result_type wait_for_response( uint64_t request_id );
|
||||
|
||||
void close();
|
||||
|
||||
void on_unhandled( const std::function<result_type(const string&,const params_type&)>& unhandled );
|
||||
|
||||
private:
|
||||
uint64_t _next_id = 1;
|
||||
std::unordered_map<uint64_t, fc::promise<result_type>::ptr> _awaiting;
|
||||
std::unordered_map<std::string, method> _methods;
|
||||
std::function<result_type(const string&,const params_type&)> _unhandled;
|
||||
};
|
||||
} } // namespace fc::rpc
|
||||
|
||||
FC_REFLECT( fc::rpc::brequest, (id)(method)(params) );
|
||||
FC_REFLECT( fc::rpc::bresponse, (id)(result)(error) )
|
||||
|
||||
32
include/fc/scoped_exit.hpp
Normal file
32
include/fc/scoped_exit.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
namespace fc {
|
||||
|
||||
template<typename Callback>
|
||||
class scoped_exit {
|
||||
public:
|
||||
template<typename C>
|
||||
scoped_exit( C&& c ):callback( std::forward<C>(c) ){}
|
||||
scoped_exit( scoped_exit&& mv ):callback( std::move( mv.callback ) ){}
|
||||
|
||||
~scoped_exit() {
|
||||
try { callback(); } catch( ... ) {}
|
||||
}
|
||||
|
||||
scoped_exit& operator = ( scoped_exit&& mv ) {
|
||||
callback = std::move(mv);
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
scoped_exit( const scoped_exit& );
|
||||
scoped_exit& operator=( const scoped_exit& );
|
||||
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
template<typename Callback>
|
||||
scoped_exit<Callback> make_scoped_exit( Callback&& c ) {
|
||||
return scoped_exit<Callback>( std::forward<Callback>(c) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,6 +29,8 @@ namespace fc
|
|||
fc::string trim( const fc::string& );
|
||||
fc::string to_lower( const fc::string& );
|
||||
string trim_and_normalize_spaces( const string& s );
|
||||
|
||||
uint64_t parse_size( const string& s );
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ namespace fc {
|
|||
*
|
||||
* @code
|
||||
* void write_message() {
|
||||
* boost::unique_lock<cmt::mutex> lock(sock->write_lock);
|
||||
* boost::unique_lock<fc::mutex> lock(sock->write_lock);
|
||||
* sock->write(part1); // may yield
|
||||
* sock->write(part2); // may yield
|
||||
* sock->write(part3); // may yield
|
||||
|
|
|
|||
|
|
@ -8,19 +8,21 @@
|
|||
namespace fc
|
||||
{
|
||||
|
||||
bool is_utf8( const std::string& str );
|
||||
std::string prune_invalid_utf8( const std::string& str );
|
||||
|
||||
/** Decodes utf 8 std::string into unicode string.
|
||||
@param input - input string to be decoded and stored in 'storage'
|
||||
@param storage - buffer for converted text. Cannot be nullptr.
|
||||
*/
|
||||
void decodeUtf8(const std::string& input, std::wstring* storage);
|
||||
|
||||
/** Encodes given wide (unicode) string into UTF-8 representation.
|
||||
@param input - input string to be encoded and stored in 'storage'
|
||||
@param storage - buffer for converted text. Cannot be nullptr.
|
||||
*/
|
||||
void encodeUtf8(const std::wstring& input, std::string* storage);
|
||||
bool is_utf8( const std::string& str );
|
||||
|
||||
/** Decodes utf 8 std::string into unicode string.
|
||||
@param input - input string to be decoded and stored in 'storage'
|
||||
@param storage - buffer for converted text. Cannot be nullptr.
|
||||
*/
|
||||
void decodeUtf8(const std::string& input, std::wstring* storage);
|
||||
|
||||
/** Encodes given wide (unicode) string into UTF-8 representation.
|
||||
@param input - input string to be encoded and stored in 'storage'
|
||||
@param storage - buffer for converted text. Cannot be nullptr.
|
||||
*/
|
||||
void encodeUtf8(const std::wstring& input, std::string* storage);
|
||||
|
||||
} /// namespace fc
|
||||
|
||||
|
|
|
|||
|
|
@ -88,15 +88,22 @@ namespace fc
|
|||
template<typename K, typename T>
|
||||
void from_variant( const variant& var, std::unordered_map<K,T>& vo );
|
||||
|
||||
template<typename K, typename T>
|
||||
void to_variant( const fc::flat_map<K,T>& var, variant& vo );
|
||||
template<typename K, typename T>
|
||||
void from_variant( const variant& var, fc::flat_map<K,T>& vo );
|
||||
template<typename K, typename... T>
|
||||
void to_variant( const fc::flat_map<K,T...>& var, variant& vo );
|
||||
template<typename K, typename... T>
|
||||
void from_variant( const variant& var, fc::flat_map<K,T...>& vo );
|
||||
|
||||
template<typename T>
|
||||
void to_variant( const std::map<string,T>& var, variant& vo );
|
||||
template<typename T>
|
||||
void from_variant( const variant& var, std::map<string,T>& vo );
|
||||
|
||||
template<typename K, typename T>
|
||||
void to_variant( const std::map<K,T>& var, variant& vo );
|
||||
template<typename K, typename T>
|
||||
void from_variant( const variant& var, std::map<K,T>& vo );
|
||||
|
||||
|
||||
template<typename K, typename T>
|
||||
void to_variant( const std::multimap<K,T>& var, variant& vo );
|
||||
template<typename K, typename T>
|
||||
|
|
@ -305,6 +312,12 @@ namespace fc
|
|||
return tmp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void as( T& v )const
|
||||
{
|
||||
from_variant( *this, v );
|
||||
}
|
||||
|
||||
variant& operator=( variant&& v );
|
||||
variant& operator=( const variant& v );
|
||||
|
||||
|
|
@ -401,6 +414,8 @@ namespace fc
|
|||
vo.insert( itr->as< std::pair<K,T> >() );
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename K, typename T>
|
||||
void to_variant( const std::map<K, T>& var, variant& vo )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
namespace fc
|
||||
{
|
||||
using std::map;
|
||||
class mutable_variant_object;
|
||||
|
||||
/**
|
||||
|
|
@ -66,6 +67,15 @@ namespace fc
|
|||
|
||||
/** initializes the first key/value pair in the object */
|
||||
variant_object( string key, variant val );
|
||||
|
||||
template<typename T>
|
||||
variant_object( const map<string,T>& values )
|
||||
:_key_value( new std::vector<entry>() ) {
|
||||
_key_value->reserve( values.size() );
|
||||
for( const auto& item : values ) {
|
||||
_key_value->emplace_back( entry( item.first, fc::variant(item.second) ) );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
variant_object( string key, T&& val )
|
||||
|
|
@ -196,6 +206,15 @@ namespace fc
|
|||
|
||||
mutable_variant_object();
|
||||
|
||||
template<typename T>
|
||||
mutable_variant_object( const map<string,T>& values )
|
||||
:_key_value( new std::vector<entry>() ) {
|
||||
_key_value->reserve( values.size() );
|
||||
for( const auto& item : values ) {
|
||||
_key_value->emplace_back( variant_object::entry( item.first, fc::variant(item.second) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** initializes the first key/value pair in the object */
|
||||
mutable_variant_object( string key, variant val );
|
||||
template<typename T>
|
||||
|
|
@ -212,6 +231,8 @@ namespace fc
|
|||
mutable_variant_object& operator=( mutable_variant_object&& );
|
||||
mutable_variant_object& operator=( const mutable_variant_object& );
|
||||
mutable_variant_object& operator=( const variant_object& );
|
||||
|
||||
|
||||
private:
|
||||
std::unique_ptr< std::vector< entry > > _key_value;
|
||||
friend class variant_object;
|
||||
|
|
@ -221,4 +242,19 @@ namespace fc
|
|||
/** @ingroup Serializable */
|
||||
void from_variant( const variant& var, mutable_variant_object& vo );
|
||||
|
||||
template<typename T>
|
||||
void to_variant( const std::map<string, T>& var, variant& vo )
|
||||
{
|
||||
vo = variant_object( var );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void from_variant( const variant& var, std::map<string, T>& vo )
|
||||
{
|
||||
const auto& obj = var.get_object();
|
||||
vo.clear();
|
||||
for( auto itr = obj.begin(); itr != obj.end(); ++itr )
|
||||
vo[itr->key()] = itr->value().as<T>();
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
|
|
|||
68
src/asio.cpp
68
src/asio.cpp
|
|
@ -93,45 +93,51 @@ namespace fc {
|
|||
struct default_io_service_scope
|
||||
{
|
||||
boost::asio::io_service* io;
|
||||
boost::thread* asio_thread;
|
||||
std::vector<boost::thread*> asio_threads;
|
||||
boost::asio::io_service::work* the_work;
|
||||
|
||||
default_io_service_scope()
|
||||
{
|
||||
io = new boost::asio::io_service();
|
||||
the_work = new boost::asio::io_service::work(*io);
|
||||
asio_thread = new boost::thread( [=]()
|
||||
{
|
||||
fc::thread::current().set_name("asio");
|
||||
while (!io->stopped())
|
||||
{
|
||||
try
|
||||
{
|
||||
io->run();
|
||||
}
|
||||
catch (const fc::exception& e)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e.what()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop");
|
||||
}
|
||||
}
|
||||
});
|
||||
for( int i = 0; i < 8; ++i ) {
|
||||
asio_threads.push_back( new boost::thread( [=]()
|
||||
{
|
||||
fc::thread::current().set_name("asio");
|
||||
while (!io->stopped())
|
||||
{
|
||||
try
|
||||
{
|
||||
io->run();
|
||||
}
|
||||
catch (const fc::exception& e)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e.what()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
elog("Caught unhandled exception in asio service loop");
|
||||
}
|
||||
}
|
||||
}) );
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
delete the_work;
|
||||
io->stop();
|
||||
asio_thread->join();
|
||||
for( auto asio_thread : asio_threads ) {
|
||||
asio_thread->join();
|
||||
}
|
||||
delete io;
|
||||
delete asio_thread;
|
||||
for( auto asio_thread : asio_threads ) {
|
||||
delete asio_thread;
|
||||
}
|
||||
}
|
||||
|
||||
~default_io_service_scope()
|
||||
|
|
@ -140,10 +146,12 @@ namespace fc {
|
|||
|
||||
/// If cleanup is true, do not use the return value; it is a null reference
|
||||
boost::asio::io_service& default_io_service(bool cleanup) {
|
||||
static default_io_service_scope fc_asio_service;
|
||||
if (cleanup)
|
||||
fc_asio_service.cleanup();
|
||||
return *fc_asio_service.io;
|
||||
static default_io_service_scope fc_asio_service[1];
|
||||
if (cleanup) {
|
||||
for( int i = 0; i < 1; ++i )
|
||||
fc_asio_service[i].cleanup();
|
||||
}
|
||||
return *fc_asio_service[0].io;
|
||||
}
|
||||
|
||||
namespace tcp {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
# include <stdlib.h>
|
||||
# define bswap_64(x) _byteswap_uint64(x)
|
||||
#elif defined(__APPLE__)
|
||||
|
|
|
|||
|
|
@ -2848,7 +2848,7 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
|
|||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW64__)
|
||||
#if defined(_MSC_VER)
|
||||
static FILE *mz_fopen(const char *pFilename, const char *pMode)
|
||||
{
|
||||
FILE* pFile = NULL;
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
#endif
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <Windows.h>
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
|
|
@ -396,7 +396,7 @@ boost::mutex* openssl_thread_config::openssl_mutexes = nullptr;
|
|||
|
||||
unsigned long openssl_thread_config::get_thread_id()
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
return (unsigned long)::GetCurrentThreadId();
|
||||
#else
|
||||
return (unsigned long)(&fc::thread::current()); // TODO: should expose boost thread id
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ static uint32_t UNALIGNED_LOAD32(const char *p) {
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <stdlib.h>
|
||||
#define bswap_32(x) _byteswap_ulong(x)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <fc/crypto/openssl.hpp>
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _WIN32
|
||||
# include <malloc.h>
|
||||
#else
|
||||
# include <alloca.h>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <assert.h>
|
||||
#include <secp256k1.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _WIN32
|
||||
# include <malloc.h>
|
||||
#else
|
||||
# include <alloca.h>
|
||||
|
|
|
|||
57
src/crypto/equihash.cpp
Normal file
57
src/crypto/equihash.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <equihash/pow.hpp>
|
||||
|
||||
#include <fc/crypto/equihash.hpp>
|
||||
|
||||
#define EQUIHASH_NONCE 2
|
||||
|
||||
namespace fc { namespace equihash {
|
||||
|
||||
_POW::Seed sha_to_seed( sha256 seed )
|
||||
{
|
||||
_POW::Seed new_seed;
|
||||
|
||||
// Seed is 128 bits. Half of sha256 to create seed. Should still have enough randomness
|
||||
new_seed.v[0] = (unsigned int) seed._hash[0];
|
||||
new_seed.v[0] ^= (unsigned int) seed._hash[2];
|
||||
new_seed.v[1] = (unsigned int)( seed._hash[0] >> 32 );
|
||||
new_seed.v[1] ^= (unsigned int)( seed._hash[2] >> 32 );
|
||||
new_seed.v[2] = (unsigned int) seed._hash[1];
|
||||
new_seed.v[2] ^= (unsigned int) seed._hash[3];
|
||||
new_seed.v[3] = (unsigned int)( seed._hash[1] >> 32 );
|
||||
new_seed.v[3] ^= (unsigned int)( seed._hash[3] >> 32 );
|
||||
|
||||
return new_seed;
|
||||
}
|
||||
|
||||
bool proof::is_valid( bool test_canonical_order, bool test_intermediate_zeros ) const
|
||||
{
|
||||
_POW::Proof test( n, k, sha_to_seed( seed ), EQUIHASH_NONCE, inputs );
|
||||
if( test_canonical_order && !test.CheckIndexesCanon() )
|
||||
return false;
|
||||
if( test_intermediate_zeros )
|
||||
return test.FullTest();
|
||||
return test.Test();
|
||||
}
|
||||
|
||||
void proof::canonize_indexes()
|
||||
{
|
||||
_POW::Proof p( n, k, sha_to_seed( seed ), EQUIHASH_NONCE, inputs );
|
||||
_POW::Proof p_canon = p.CanonizeIndexes();
|
||||
inputs = p_canon.inputs;
|
||||
}
|
||||
|
||||
proof proof::hash( uint32_t n, uint32_t k, sha256 seed )
|
||||
{
|
||||
auto hash = _POW::Equihash( n, k, sha_to_seed( seed ) );
|
||||
auto result = hash.FindProof( EQUIHASH_NONCE );
|
||||
|
||||
proof p;
|
||||
p.n = n;
|
||||
p.k = k;
|
||||
p.seed = seed;
|
||||
p.inputs = result.inputs;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} } // fc::equihash
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include <fc/fwd_impl.hpp>
|
||||
#include <openssl/sha.h>
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
|
@ -97,7 +98,102 @@ namespace fc {
|
|||
bool operator == ( const sha256& h1, const sha256& h2 ) {
|
||||
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t sha256::approx_log_32()const
|
||||
{
|
||||
uint16_t lzbits = clz();
|
||||
if( lzbits >= 0x100 )
|
||||
return 0;
|
||||
uint8_t nzbits = 0xFF-lzbits;
|
||||
size_t offset = (size_t) (lzbits >> 3);
|
||||
uint8_t* my_bytes = (uint8_t*) data();
|
||||
size_t n = data_size();
|
||||
uint32_t y = (uint32_t( my_bytes[offset ] ) << 0x18)
|
||||
| (uint32_t(offset+1 < n ? my_bytes[offset+1] : 0) << 0x10)
|
||||
| (uint32_t(offset+2 < n ? my_bytes[offset+2] : 0) << 0x08)
|
||||
| (uint32_t(offset+3 < n ? my_bytes[offset+3] : 0) )
|
||||
;
|
||||
//
|
||||
// lzbits&7 == 7 : 00000001 iff nzbits&7 == 0
|
||||
// lzbits&7 == 6 : 0000001x iff nzbits&7 == 1
|
||||
// lzbits&7 == 5 : 000001xx iff nzbits&7 == 2
|
||||
//
|
||||
y >>= (nzbits & 7);
|
||||
y ^= 1 << 0x18;
|
||||
y |= uint32_t( nzbits ) << 0x18;
|
||||
return y;
|
||||
}
|
||||
|
||||
void sha256::set_to_inverse_approx_log_32( uint32_t x )
|
||||
{
|
||||
uint8_t nzbits = uint8_t( x >> 0x18 );
|
||||
_hash[0] = 0;
|
||||
_hash[1] = 0;
|
||||
_hash[2] = 0;
|
||||
_hash[3] = 0;
|
||||
if( nzbits == 0 )
|
||||
return;
|
||||
uint8_t x0 = uint8_t((x ) & 0xFF);
|
||||
uint8_t x1 = uint8_t((x >> 0x08) & 0xFF);
|
||||
uint8_t x2 = uint8_t((x >> 0x10) & 0xFF);
|
||||
uint8_t* my_bytes = (uint8_t*) data();
|
||||
my_bytes[0x1F] = x0;
|
||||
my_bytes[0x1E] = x1;
|
||||
my_bytes[0x1D] = x2;
|
||||
my_bytes[0x1C] = 1;
|
||||
|
||||
if( nzbits <= 0x18 )
|
||||
{
|
||||
(*this) = (*this) >> (0x18 - nzbits);
|
||||
}
|
||||
else
|
||||
(*this) = (*this) << (nzbits - 0x18);
|
||||
return;
|
||||
}
|
||||
|
||||
double sha256::inverse_approx_log_32_double( uint32_t x )
|
||||
{
|
||||
uint8_t nzbits = uint8_t( x >> 0x18 );
|
||||
if( nzbits == 0 )
|
||||
return 0.0;
|
||||
uint32_t b = 1 << 0x18;
|
||||
uint32_t y = (x & (b-1)) | b;
|
||||
return std::ldexp( y, int( nzbits ) - 0x18 );
|
||||
}
|
||||
|
||||
uint16_t sha256::clz()const
|
||||
{
|
||||
const uint8_t* my_bytes = (uint8_t*) data();
|
||||
size_t size = data_size();
|
||||
size_t lzbits = 0;
|
||||
static const uint8_t char2lzbits[] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
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, 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, 0, 0
|
||||
};
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
while( true )
|
||||
{
|
||||
uint8_t c = my_bytes[i];
|
||||
lzbits += char2lzbits[c];
|
||||
if( c != 0 )
|
||||
break;
|
||||
++i;
|
||||
if( i >= size )
|
||||
return 0x100;
|
||||
}
|
||||
|
||||
return lzbits;
|
||||
}
|
||||
|
||||
void to_variant( const sha256& bi, variant& v )
|
||||
{
|
||||
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#ifdef WIN32
|
||||
# include <Windows.h>
|
||||
# include <UserEnv.h>
|
||||
# include <ShlObj.h>
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <userenv.h>
|
||||
# include <shlobj.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
|
|||
100
src/interprocess/file_mutex.cpp
Normal file
100
src/interprocess/file_mutex.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#include <fc/interprocess/file_mutex.hpp>
|
||||
//#include <fc/thread/mutex.hpp>
|
||||
#include <fc/thread/mutex.hpp>
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <boost/interprocess/sync/file_lock.hpp>
|
||||
#include <boost/interprocess/sync/scoped_lock.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace bip = boost::interprocess;
|
||||
|
||||
void yield();
|
||||
|
||||
namespace detail {
|
||||
class file_mutex_impl {
|
||||
public:
|
||||
file_mutex_impl( const char* f )
|
||||
:_file_mutex( f ),_reader_count(0){}
|
||||
|
||||
fc::mutex _write_lock;
|
||||
bip::file_lock _file_mutex;
|
||||
boost::atomic<int> _reader_count;
|
||||
};
|
||||
}
|
||||
|
||||
file_mutex::file_mutex( const fc::path& file )
|
||||
{
|
||||
my.reset( new detail::file_mutex_impl( file.generic_string().c_str() ) );
|
||||
}
|
||||
|
||||
file_mutex::~file_mutex() {
|
||||
}
|
||||
|
||||
int file_mutex::readers()const {
|
||||
return my->_reader_count.load();
|
||||
}
|
||||
|
||||
bool file_mutex::try_lock() {
|
||||
return false;
|
||||
if( my->_write_lock.try_lock() ) {
|
||||
if( my->_file_mutex.try_lock() )
|
||||
return true;
|
||||
}
|
||||
if( my->_file_mutex.try_lock() ) {
|
||||
if( my->_write_lock.try_lock() ) {
|
||||
return true;
|
||||
} else {
|
||||
my->_file_mutex.unlock();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool file_mutex::try_lock_for( const microseconds& rel_time ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool file_mutex::try_lock_until( const time_point& abs_time ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void file_mutex::lock() {
|
||||
my->_write_lock.lock();
|
||||
while( my->_reader_count.load() > 0 ) {
|
||||
fc::usleep( fc::microseconds(10) );
|
||||
}
|
||||
my->_file_mutex.lock();
|
||||
}
|
||||
|
||||
void file_mutex::unlock() {
|
||||
my->_file_mutex.unlock();
|
||||
my->_write_lock.unlock();
|
||||
}
|
||||
|
||||
void file_mutex::lock_shared() {
|
||||
bip::scoped_lock< fc::mutex > lock( my->_write_lock );
|
||||
if( 0 == my->_reader_count.fetch_add( 1, boost::memory_order_relaxed ) )
|
||||
my->_file_mutex.lock_sharable();
|
||||
}
|
||||
|
||||
void file_mutex::unlock_shared() {
|
||||
if( 1 == my->_reader_count.fetch_add( -1, boost::memory_order_relaxed ) )
|
||||
my->_file_mutex.unlock_sharable();
|
||||
}
|
||||
|
||||
bool file_mutex::try_lock_shared() {
|
||||
return false;
|
||||
if( my->_write_lock.try_lock() ) {
|
||||
if( my->_reader_count.load() == 0 && my->_file_mutex.try_lock_sharable() ) {
|
||||
my->_reader_count++;
|
||||
}
|
||||
my->_write_lock.unlock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
|
@ -517,24 +517,61 @@ namespace fc
|
|||
{
|
||||
switch( *itr )
|
||||
{
|
||||
case '\t':
|
||||
os << "\\t";
|
||||
case '\b': // \x08
|
||||
os << "\\b";
|
||||
break;
|
||||
case '\n':
|
||||
case '\f': // \x0c
|
||||
os << "\\f";
|
||||
break;
|
||||
case '\n': // \x0a
|
||||
os << "\\n";
|
||||
break;
|
||||
case '\r': // \x0d
|
||||
os << "\\r";
|
||||
break;
|
||||
case '\t': // \x09
|
||||
os << "\\t";
|
||||
break;
|
||||
case '\\':
|
||||
os << "\\\\";
|
||||
break;
|
||||
case '\r':
|
||||
os << "\\r";
|
||||
break;
|
||||
case '\a':
|
||||
os << "\\a";
|
||||
break;
|
||||
case '\"':
|
||||
os << "\\\"";
|
||||
break;
|
||||
case '\x00': os << "\\u0000"; break;
|
||||
case '\x01': os << "\\u0001"; break;
|
||||
case '\x02': os << "\\u0002"; break;
|
||||
case '\x03': os << "\\u0003"; break;
|
||||
case '\x04': os << "\\u0004"; break;
|
||||
case '\x05': os << "\\u0005"; break;
|
||||
case '\x06': os << "\\u0006"; break;
|
||||
case '\x07': os << "\\u0007"; break; // \a is not valid JSON
|
||||
// case '\x08': os << "\\u0008"; break; // \b
|
||||
// case '\x09': os << "\\u0009"; break; // \t
|
||||
// case '\x0a': os << "\\u000a"; break; // \n
|
||||
case '\x0b': os << "\\u000b"; break;
|
||||
// case '\x0c': os << "\\u000c"; break; // \f
|
||||
// case '\x0d': os << "\\u000d"; break; // \r
|
||||
case '\x0e': os << "\\u000e"; break;
|
||||
case '\x0f': os << "\\u000f"; break;
|
||||
|
||||
case '\x10': os << "\\u0010"; break;
|
||||
case '\x11': os << "\\u0011"; break;
|
||||
case '\x12': os << "\\u0012"; break;
|
||||
case '\x13': os << "\\u0013"; break;
|
||||
case '\x14': os << "\\u0014"; break;
|
||||
case '\x15': os << "\\u0015"; break;
|
||||
case '\x16': os << "\\u0016"; break;
|
||||
case '\x17': os << "\\u0017"; break;
|
||||
case '\x18': os << "\\u0018"; break;
|
||||
case '\x19': os << "\\u0019"; break;
|
||||
case '\x1a': os << "\\u001a"; break;
|
||||
case '\x1b': os << "\\u001b"; break;
|
||||
case '\x1c': os << "\\u001c"; break;
|
||||
case '\x1d': os << "\\u001d"; break;
|
||||
case '\x1e': os << "\\u001e"; break;
|
||||
case '\x1f': os << "\\u001f"; break;
|
||||
|
||||
default:
|
||||
os << *itr;
|
||||
//toUTF8( *itr, os );
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ fc::tcp_socket& connection::get_socket()const {
|
|||
|
||||
http::request connection::read_request()const {
|
||||
http::request req;
|
||||
req.remote_endpoint = fc::variant(get_socket().remote_endpoint()).as_string();
|
||||
std::vector<char> line(1024*8);
|
||||
int s = my->read_until( line.data(), line.data()+line.size(), ' ' ); // METHOD
|
||||
req.method = line.data();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <websocketpp/config/asio.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/config/asio_client.hpp>
|
||||
#include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
#include <websocketpp/client.hpp>
|
||||
#include <websocketpp/logger/stub.hpp>
|
||||
|
||||
|
|
@ -20,11 +19,12 @@
|
|||
namespace fc { namespace http {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct asio_with_stub_log : public websocketpp::config::asio {
|
||||
|
||||
typedef asio_with_stub_log type;
|
||||
typedef asio base;
|
||||
|
||||
//// All boilerplate copying the base class's config, except as noted
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
|
|
@ -33,8 +33,15 @@ namespace fc { namespace http {
|
|||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
/// Custom Logging policies, use do-nothing log::stub instead of log::basic
|
||||
|
||||
/// Custom Logging policies
|
||||
/*typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::elevel> elog_type;
|
||||
typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::alevel> alog_type;
|
||||
*/
|
||||
//typedef base::alog_type alog_type;
|
||||
//typedef base::elog_type elog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
|
||||
|
|
@ -53,15 +60,13 @@ namespace fc { namespace http {
|
|||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
// override default value of 5 sec timeout
|
||||
static const long timeout_open_handshake = 0;
|
||||
};
|
||||
|
||||
struct asio_with_stub_log_and_deflate : public websocketpp::config::asio {
|
||||
typedef asio_with_stub_log_and_deflate type;
|
||||
typedef asio base;
|
||||
struct asio_tls_with_stub_log : public websocketpp::config::asio_tls {
|
||||
|
||||
typedef asio_with_stub_log type;
|
||||
typedef asio_tls base;
|
||||
|
||||
//// All boilerplate copying the base class's config, except as noted
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
|
|
@ -71,7 +76,14 @@ namespace fc { namespace http {
|
|||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
/// Custom Logging policies, use do-nothing log::stub instead of log::basic
|
||||
/// Custom Logging policies
|
||||
/*typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::elevel> elog_type;
|
||||
typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::alevel> alog_type;
|
||||
*/
|
||||
//typedef base::alog_type alog_type;
|
||||
//typedef base::elog_type elog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
|
||||
|
|
@ -83,94 +95,54 @@ namespace fc { namespace http {
|
|||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::basic_socket::endpoint
|
||||
socket_type;
|
||||
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// enable the permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
|
||||
// override default value of 5 sec timeout
|
||||
static const long timeout_open_handshake = 0;
|
||||
};
|
||||
|
||||
struct asio_tls_stub_log : public websocketpp::config::asio_tls {
|
||||
typedef asio_tls_stub_log type;
|
||||
typedef asio_tls base;
|
||||
typedef asio_tls_stub_log type;
|
||||
typedef asio_tls base;
|
||||
|
||||
//// All boilerplate copying the base class's config, except as noted
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
/// Custom Logging policies, use do-nothing log::stub instead of log::basic
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
//typedef base::alog_type alog_type;
|
||||
//typedef base::elog_type elog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
};
|
||||
|
||||
struct asio_tls_stub_log_and_deflate : public websocketpp::config::asio_tls {
|
||||
typedef asio_tls_stub_log_and_deflate type;
|
||||
typedef asio_tls base;
|
||||
|
||||
//// All boilerplate copying the base class's config, except as noted
|
||||
typedef base::concurrency_type concurrency_type;
|
||||
|
||||
typedef base::request_type request_type;
|
||||
typedef base::response_type response_type;
|
||||
|
||||
typedef base::message_type message_type;
|
||||
typedef base::con_msg_manager_type con_msg_manager_type;
|
||||
typedef base::endpoint_msg_manager_type endpoint_msg_manager_type;
|
||||
|
||||
/// Custom Logging policies, use do-nothing log::stub instead of log::basic
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_type;
|
||||
|
||||
typedef base::rng_type rng_type;
|
||||
|
||||
struct transport_config : public base::transport_config {
|
||||
typedef type::concurrency_type concurrency_type;
|
||||
typedef type::alog_type alog_type;
|
||||
typedef type::elog_type elog_type;
|
||||
typedef type::request_type request_type;
|
||||
typedef type::response_type response_type;
|
||||
typedef websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
/// enable the permessage_compress extension
|
||||
struct permessage_deflate_config {};
|
||||
typedef websocketpp::extensions::permessage_deflate::enabled
|
||||
<permessage_deflate_config> permessage_deflate_type;
|
||||
};
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
typedef websocketpp::server<asio_with_stub_log> websocket_server_type;
|
||||
typedef websocketpp::server<asio_tls_stub_log> websocket_tls_server_type;
|
||||
|
||||
template<typename T>
|
||||
class websocket_connection_impl : public websocket_connection
|
||||
|
|
@ -201,19 +173,7 @@ namespace fc { namespace http {
|
|||
|
||||
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
|
||||
class abstract_websocket_server
|
||||
{
|
||||
public:
|
||||
virtual ~abstract_websocket_server() {}
|
||||
|
||||
virtual void on_connection( const on_connection_handler& handler) = 0;
|
||||
virtual void listen( uint16_t port ) = 0;
|
||||
virtual void listen( const fc::ip::endpoint& ep ) = 0;
|
||||
virtual void start_accept() = 0;
|
||||
};
|
||||
|
||||
template <typename config>
|
||||
class websocket_server_impl : public abstract_websocket_server
|
||||
class websocket_server_impl
|
||||
{
|
||||
public:
|
||||
websocket_server_impl()
|
||||
|
|
@ -225,15 +185,15 @@ namespace fc { namespace http {
|
|||
_server.set_reuse_addr(true);
|
||||
_server.set_open_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
websocket_connection_ptr new_con = std::make_shared<websocket_connection_impl<typename websocketpp::server<config>::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
auto new_con = std::make_shared<websocket_connection_impl<websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
_on_connection( _connections[hdl] = new_con );
|
||||
}).wait();
|
||||
});
|
||||
_server.set_message_handler( [&]( connection_hdl hdl, typename websocketpp::server<config>::message_ptr msg ){
|
||||
_server.set_message_handler( [&]( connection_hdl hdl, websocket_server_type::message_ptr msg ){
|
||||
_server_thread.async( [&](){
|
||||
auto current_con = _connections.find(hdl);
|
||||
assert( current_con != _connections.end() );
|
||||
//wdump(("server")(msg->get_payload()));
|
||||
wdump(("server")(msg->get_payload()));
|
||||
//std::cerr<<"recv: "<<msg->get_payload()<<"\n";
|
||||
auto payload = msg->get_payload();
|
||||
std::shared_ptr<websocket_connection> con = current_con->second;
|
||||
|
|
@ -244,15 +204,20 @@ namespace fc { namespace http {
|
|||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_socket_init_handler( [&](websocketpp::connection_hdl hdl, boost::asio::ip::tcp::socket& s ) {
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
s.lowest_layer().set_option(option);
|
||||
} );
|
||||
|
||||
_server.set_http_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
auto current_con = std::make_shared<websocket_connection_impl<typename websocketpp::server<config>::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
auto current_con = std::make_shared<websocket_connection_impl<websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
_on_connection( current_con );
|
||||
|
||||
auto con = _server.get_con_from_hdl(hdl);
|
||||
con->defer_http_response();
|
||||
std::string request_body = con->get_request_body();
|
||||
//wdump(("server")(request_body));
|
||||
wdump(("server")(request_body));
|
||||
|
||||
fc::async([current_con, request_body, con] {
|
||||
std::string response = current_con->on_http(request_body);
|
||||
|
|
@ -314,62 +279,132 @@ namespace fc { namespace http {
|
|||
if( _closed ) _closed->wait();
|
||||
}
|
||||
|
||||
void on_connection( const on_connection_handler& handler ) override
|
||||
{
|
||||
_on_connection = handler;
|
||||
}
|
||||
|
||||
void listen( uint16_t port ) override
|
||||
{
|
||||
_server.listen(port);
|
||||
}
|
||||
|
||||
void listen( const fc::ip::endpoint& ep ) override
|
||||
{
|
||||
_server.listen( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
|
||||
}
|
||||
|
||||
void start_accept() override
|
||||
{
|
||||
_server.start_accept();
|
||||
}
|
||||
|
||||
typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map;
|
||||
|
||||
con_map _connections;
|
||||
fc::thread& _server_thread;
|
||||
websocketpp::server<config> _server;
|
||||
websocket_server_type _server;
|
||||
on_connection_handler _on_connection;
|
||||
fc::promise<void>::ptr _closed;
|
||||
uint32_t _pending_messages = 0;
|
||||
};
|
||||
|
||||
template <typename config>
|
||||
class websocket_tls_server_impl : public websocket_server_impl<config>
|
||||
class websocket_tls_server_impl
|
||||
{
|
||||
public:
|
||||
websocket_tls_server_impl( const string& server_pem, const string& ssl_password )
|
||||
:_server_thread( fc::thread::current() )
|
||||
{
|
||||
this->_server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr {
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
ctx->set_password_callback([=](std::size_t max_length, boost::asio::ssl::context::password_purpose){ return ssl_password;});
|
||||
ctx->use_certificate_chain_file(server_pem);
|
||||
ctx->use_private_key_file(server_pem, boost::asio::ssl::context::pem);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
//if( server_pem.size() )
|
||||
{
|
||||
_server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr {
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
ctx->set_password_callback([=](std::size_t max_length, boost::asio::ssl::context::password_purpose){ return ssl_password;});
|
||||
ctx->use_certificate_chain_file(server_pem);
|
||||
ctx->use_private_key_file(server_pem, boost::asio::ssl::context::pem);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
_server.clear_access_channels( websocketpp::log::alevel::all );
|
||||
_server.init_asio(&fc::asio::default_io_service());
|
||||
_server.set_reuse_addr(true);
|
||||
_server.set_open_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
auto new_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
_on_connection( _connections[hdl] = new_con );
|
||||
}).wait();
|
||||
});
|
||||
_server.set_message_handler( [&]( connection_hdl hdl, websocket_server_type::message_ptr msg ){
|
||||
_server_thread.async( [&](){
|
||||
auto current_con = _connections.find(hdl);
|
||||
assert( current_con != _connections.end() );
|
||||
auto received = msg->get_payload();
|
||||
std::shared_ptr<websocket_connection> con = current_con->second;
|
||||
fc::async([con,received](){ con->on_message( received ); });
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_http_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
|
||||
auto current_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
try{
|
||||
_on_connection( current_con );
|
||||
|
||||
auto con = _server.get_con_from_hdl(hdl);
|
||||
wdump(("server")(con->get_request_body()));
|
||||
auto response = current_con->on_http( con->get_request_body() );
|
||||
|
||||
con->set_body( response );
|
||||
con->set_status( websocketpp::http::status_code::ok );
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
}
|
||||
current_con->closed();
|
||||
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_close_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
_connections[hdl]->closed();
|
||||
_connections.erase( hdl );
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_fail_handler( [&]( connection_hdl hdl ){
|
||||
if( _server.is_listening() )
|
||||
{
|
||||
_server_thread.async( [&](){
|
||||
if( _connections.find(hdl) != _connections.end() )
|
||||
{
|
||||
_connections[hdl]->closed();
|
||||
_connections.erase( hdl );
|
||||
}
|
||||
}).wait();
|
||||
}
|
||||
});
|
||||
}
|
||||
~websocket_tls_server_impl()
|
||||
{
|
||||
if( _server.is_listening() )
|
||||
_server.stop_listening();
|
||||
auto cpy_con = _connections;
|
||||
for( auto item : cpy_con )
|
||||
_server.close( item.first, 0, "server exit" );
|
||||
}
|
||||
|
||||
typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map;
|
||||
|
||||
con_map _connections;
|
||||
fc::thread& _server_thread;
|
||||
websocket_tls_server_type _server;
|
||||
on_connection_handler _on_connection;
|
||||
fc::promise<void>::ptr _closed;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef websocketpp::client<asio_with_stub_log> websocket_client_type;
|
||||
typedef websocketpp::client<asio_tls_stub_log> websocket_tls_client_type;
|
||||
|
||||
|
|
@ -427,6 +462,7 @@ namespace fc { namespace http {
|
|||
fc::thread& _client_thread;
|
||||
websocket_client_type _client;
|
||||
websocket_connection_ptr _connection;
|
||||
std::string _uri;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -436,9 +472,13 @@ namespace fc { namespace http {
|
|||
public:
|
||||
typedef websocket_tls_client_type::message_ptr message_ptr;
|
||||
|
||||
websocket_tls_client_impl()
|
||||
websocket_tls_client_impl( const std::string& ca_filename )
|
||||
:_client_thread( fc::thread::current() )
|
||||
{
|
||||
// ca_filename has special values:
|
||||
// "_none" disables cert checking (potentially insecure!)
|
||||
// "_default" uses default CA's provided by OS
|
||||
|
||||
_client.clear_access_channels( websocketpp::log::alevel::all );
|
||||
_client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){
|
||||
_client_thread.async( [&](){
|
||||
|
|
@ -475,6 +515,22 @@ namespace fc { namespace http {
|
|||
_closed->set_value();
|
||||
});
|
||||
|
||||
//
|
||||
// We need ca_filename to be copied into the closure, as the referenced object might be destroyed by the caller by the time
|
||||
// tls_init_handler() is called. According to [1], capture-by-value results in the desired behavior (i.e. creation of
|
||||
// a copy which is stored in the closure) on standards compliant compilers, but some compilers on some optimization levels
|
||||
// are buggy and are not standards compliant in this situation. Also, keep in mind this is the opinion of a single forum
|
||||
// poster and might be wrong.
|
||||
//
|
||||
// To be safe, the following line explicitly creates a non-reference string which is captured by value, which should have the
|
||||
// correct behavior on all compilers.
|
||||
//
|
||||
// [1] http://www.cplusplus.com/forum/general/142165/
|
||||
// [2] http://stackoverflow.com/questions/21443023/capturing-a-reference-by-reference-in-a-c11-lambda
|
||||
//
|
||||
|
||||
std::string ca_filename_copy = ca_filename;
|
||||
|
||||
_client.set_tls_init_handler( [=](websocketpp::connection_hdl) {
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
|
||||
try {
|
||||
|
|
@ -482,6 +538,8 @@ namespace fc { namespace http {
|
|||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
|
||||
setup_peer_verify( ctx, ca_filename_copy );
|
||||
} catch (std::exception& e) {
|
||||
edump((e.what()));
|
||||
std::cout << e.what() << std::endl;
|
||||
|
|
@ -501,75 +559,89 @@ namespace fc { namespace http {
|
|||
_closed->wait();
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_host()const
|
||||
{
|
||||
return websocketpp::uri( _uri ).get_host();
|
||||
}
|
||||
|
||||
void setup_peer_verify( context_ptr& ctx, const std::string& ca_filename )
|
||||
{
|
||||
if( ca_filename == "_none" )
|
||||
return;
|
||||
ctx->set_verify_mode( boost::asio::ssl::verify_peer );
|
||||
if( ca_filename == "_default" )
|
||||
ctx->set_default_verify_paths();
|
||||
else
|
||||
ctx->load_verify_file( ca_filename );
|
||||
ctx->set_verify_depth(10);
|
||||
ctx->set_verify_callback( boost::asio::ssl::rfc2818_verification( get_host() ) );
|
||||
}
|
||||
|
||||
bool _shutting_down = false;
|
||||
fc::promise<void>::ptr _connected;
|
||||
fc::promise<void>::ptr _closed;
|
||||
fc::thread& _client_thread;
|
||||
websocket_tls_client_type _client;
|
||||
websocket_tls_client_type _client;
|
||||
websocket_connection_ptr _connection;
|
||||
std::string _uri;
|
||||
};
|
||||
|
||||
|
||||
} // namespace detail
|
||||
|
||||
websocket_server::websocket_server(bool enable_permessage_deflate /* = true */) :
|
||||
my( enable_permessage_deflate ?
|
||||
(detail::abstract_websocket_server*)new detail::websocket_server_impl<detail::asio_with_stub_log_and_deflate> :
|
||||
(detail::abstract_websocket_server*)new detail::websocket_server_impl<detail::asio_with_stub_log> )
|
||||
{}
|
||||
websocket_server::websocket_server():my( new detail::websocket_server_impl() ) {}
|
||||
websocket_server::~websocket_server(){}
|
||||
|
||||
void websocket_server::on_connection( const on_connection_handler& handler )
|
||||
{
|
||||
my->on_connection(handler);
|
||||
my->_on_connection = handler;
|
||||
}
|
||||
|
||||
void websocket_server::listen( uint16_t port )
|
||||
{
|
||||
my->listen(port);
|
||||
my->_server.listen(port);
|
||||
}
|
||||
void websocket_server::listen( const fc::ip::endpoint& ep )
|
||||
{
|
||||
my->listen(ep);
|
||||
my->_server.listen( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
|
||||
}
|
||||
|
||||
void websocket_server::start_accept() {
|
||||
my->start_accept();
|
||||
my->_server.start_accept();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
websocket_tls_server::websocket_tls_server(const string& server_pem,
|
||||
const string& ssl_password,
|
||||
bool enable_permessage_deflate /* = true */) :
|
||||
my( enable_permessage_deflate ?
|
||||
(detail::abstract_websocket_server*)new detail::websocket_tls_server_impl<detail::asio_tls_stub_log_and_deflate>(server_pem, ssl_password) :
|
||||
(detail::abstract_websocket_server*)new detail::websocket_tls_server_impl<detail::asio_tls_stub_log>(server_pem, ssl_password) )
|
||||
{}
|
||||
websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {}
|
||||
websocket_tls_server::~websocket_tls_server(){}
|
||||
|
||||
void websocket_tls_server::on_connection( const on_connection_handler& handler )
|
||||
{
|
||||
my->on_connection(handler);
|
||||
my->_on_connection = handler;
|
||||
}
|
||||
|
||||
void websocket_tls_server::listen( uint16_t port )
|
||||
{
|
||||
my->listen(port);
|
||||
my->_server.listen(port);
|
||||
}
|
||||
void websocket_tls_server::listen( const fc::ip::endpoint& ep )
|
||||
{
|
||||
my->listen(ep);
|
||||
my->_server.listen( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
|
||||
}
|
||||
|
||||
void websocket_tls_server::start_accept()
|
||||
{
|
||||
my->start_accept();
|
||||
void websocket_tls_server::start_accept() {
|
||||
my->_server.start_accept();
|
||||
}
|
||||
|
||||
|
||||
websocket_client::websocket_client():my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl()) {}
|
||||
websocket_tls_client::websocket_tls_client( const std::string& ca_filename ):my( new detail::websocket_tls_client_impl( ca_filename ) ) {}
|
||||
websocket_tls_client::~websocket_tls_client(){ }
|
||||
|
||||
|
||||
|
||||
websocket_client::websocket_client( const std::string& ca_filename ):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {}
|
||||
websocket_client::~websocket_client(){ }
|
||||
|
||||
websocket_connection_ptr websocket_client::connect( const std::string& uri )
|
||||
|
|
@ -581,6 +653,7 @@ namespace fc { namespace http {
|
|||
// wlog( "connecting to ${uri}", ("uri",uri));
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
my->_uri = uri;
|
||||
my->_connected = fc::promise<void>::ptr( new fc::promise<void>("websocket::connect") );
|
||||
|
||||
my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
||||
|
|
@ -607,6 +680,7 @@ namespace fc { namespace http {
|
|||
// wlog( "connecting to ${uri}", ("uri",uri));
|
||||
websocketpp::lib::error_code ec;
|
||||
|
||||
smy->_uri = uri;
|
||||
smy->_connected = fc::promise<void>::ptr( new fc::promise<void>("websocket::connect") );
|
||||
|
||||
smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include <fc/exception/exception.hpp>
|
||||
|
||||
#if defined _WIN32 || defined WIN32 || defined OS_WIN64 || defined _WIN64 || defined WIN64 || defined WINNT
|
||||
# include <MSTcpIP.h>
|
||||
# include <mstcpip.h>
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
|
|
@ -154,12 +154,12 @@ namespace fc {
|
|||
{
|
||||
try
|
||||
{
|
||||
my->_sock.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(local_endpoint.get_address()),
|
||||
my->_sock.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(local_endpoint.get_address()),
|
||||
local_endpoint.port()));
|
||||
}
|
||||
catch (const std::exception& except)
|
||||
{
|
||||
elog("Exception binding outgoing connection to desired local endpoint: ${what}", ("what", except.what()));
|
||||
elog("Exception binding outgoing connection to desired local endpoint ${endpoint}: ${what}", ("endpoint", local_endpoint)("what", except.what()));
|
||||
FC_THROW("error binding to ${endpoint}: ${what}", ("endpoint", local_endpoint)("what", except.what()));
|
||||
}
|
||||
}
|
||||
|
|
@ -309,7 +309,7 @@ namespace fc {
|
|||
try
|
||||
{
|
||||
my->_accept.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), port));
|
||||
my->_accept.listen();
|
||||
my->_accept.listen(256);
|
||||
}
|
||||
FC_RETHROW_EXCEPTIONS(warn, "error listening on socket");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,405 +0,0 @@
|
|||
#include <fc/network/udt_socket.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <fc/thread/mutex.hpp>
|
||||
#include <fc/thread/unique_lock.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
#include <udt.h>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
|
||||
void check_udt_errors()
|
||||
{
|
||||
UDT::ERRORINFO& error_info = UDT::getlasterror();
|
||||
if( error_info.getErrorCode() )
|
||||
{
|
||||
std::string error_message = error_info.getErrorMessage();
|
||||
error_info.clear();
|
||||
FC_CAPTURE_AND_THROW( udt_exception, (error_message) );
|
||||
}
|
||||
}
|
||||
|
||||
class udt_epoll_service
|
||||
{
|
||||
public:
|
||||
udt_epoll_service()
|
||||
:_epoll_thread("udt_epoll")
|
||||
{
|
||||
UDT::startup();
|
||||
check_udt_errors();
|
||||
_epoll_id = UDT::epoll_create();
|
||||
_epoll_loop = _epoll_thread.async( [=](){ poll_loop(); }, "udt_poll_loop" );
|
||||
}
|
||||
|
||||
~udt_epoll_service()
|
||||
{
|
||||
_epoll_loop.cancel("udt_epoll_service is destructing");
|
||||
_epoll_loop.wait();
|
||||
UDT::cleanup();
|
||||
}
|
||||
|
||||
void poll_loop()
|
||||
{
|
||||
std::set<UDTSOCKET> read_ready;
|
||||
std::set<UDTSOCKET> write_ready;
|
||||
while( !_epoll_loop.canceled() )
|
||||
{
|
||||
UDT::epoll_wait( _epoll_id,
|
||||
&read_ready,
|
||||
&write_ready, 100000000 );
|
||||
|
||||
{ synchronized(_read_promises_mutex)
|
||||
for( auto sock : read_ready )
|
||||
{
|
||||
auto itr = _read_promises.find( sock );
|
||||
if( itr != _read_promises.end() )
|
||||
{
|
||||
itr->second->set_value();
|
||||
_read_promises.erase(itr);
|
||||
}
|
||||
}
|
||||
} // synchronized read promise mutex
|
||||
|
||||
{ synchronized(_write_promises_mutex)
|
||||
for( auto sock : write_ready )
|
||||
{
|
||||
auto itr = _write_promises.find( sock );
|
||||
if( itr != _write_promises.end() )
|
||||
{
|
||||
itr->second->set_value();
|
||||
_write_promises.erase(itr);
|
||||
}
|
||||
}
|
||||
} // synchronized write promise mutex
|
||||
} // while not canceled
|
||||
} // poll_loop
|
||||
|
||||
|
||||
void notify_read( int udt_socket_id,
|
||||
const promise<void>::ptr& p )
|
||||
{
|
||||
int events = UDT_EPOLL_IN | UDT_EPOLL_ERR;
|
||||
if( 0 != UDT::epoll_add_usock( _epoll_id,
|
||||
udt_socket_id,
|
||||
&events ) )
|
||||
{
|
||||
check_udt_errors();
|
||||
}
|
||||
{ synchronized(_read_promises_mutex)
|
||||
|
||||
_read_promises[udt_socket_id] = p;
|
||||
}
|
||||
}
|
||||
|
||||
void notify_write( int udt_socket_id,
|
||||
const promise<void>::ptr& p )
|
||||
{
|
||||
int events = UDT_EPOLL_OUT | UDT_EPOLL_ERR;
|
||||
if( 0 != UDT::epoll_add_usock( _epoll_id,
|
||||
udt_socket_id,
|
||||
&events ) )
|
||||
{
|
||||
check_udt_errors();
|
||||
}
|
||||
|
||||
{ synchronized(_write_promises_mutex)
|
||||
_write_promises[udt_socket_id] = p;
|
||||
}
|
||||
}
|
||||
void remove( int udt_socket_id )
|
||||
{
|
||||
{ synchronized(_read_promises_mutex)
|
||||
auto read_itr = _read_promises.find( udt_socket_id );
|
||||
if( read_itr != _read_promises.end() )
|
||||
{
|
||||
read_itr->second->set_exception( fc::copy_exception( fc::exception() ) );
|
||||
_read_promises.erase(read_itr);
|
||||
}
|
||||
}
|
||||
{ synchronized(_write_promises_mutex)
|
||||
auto write_itr = _write_promises.find( udt_socket_id );
|
||||
if( write_itr != _write_promises.end() )
|
||||
{
|
||||
write_itr->second->set_exception( fc::copy_exception( fc::exception() ) );
|
||||
_write_promises.erase(write_itr);
|
||||
}
|
||||
}
|
||||
UDT::epoll_remove_usock( _epoll_id, udt_socket_id );
|
||||
}
|
||||
|
||||
private:
|
||||
fc::mutex _read_promises_mutex;
|
||||
fc::mutex _write_promises_mutex;
|
||||
std::unordered_map<int, promise<void>::ptr > _read_promises;
|
||||
std::unordered_map<int, promise<void>::ptr > _write_promises;
|
||||
|
||||
fc::future<void> _epoll_loop;
|
||||
fc::thread _epoll_thread;
|
||||
int _epoll_id;
|
||||
};
|
||||
|
||||
|
||||
udt_epoll_service& default_epool_service()
|
||||
{
|
||||
static udt_epoll_service* default_service = new udt_epoll_service();
|
||||
return *default_service;
|
||||
}
|
||||
|
||||
|
||||
|
||||
udt_socket::udt_socket()
|
||||
:_udt_socket_id( UDT::INVALID_SOCK )
|
||||
{
|
||||
}
|
||||
|
||||
udt_socket::~udt_socket()
|
||||
{
|
||||
try {
|
||||
close();
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
wlog( "${e}", ("e", e.to_detail_string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void udt_socket::bind( const fc::ip::endpoint& local_endpoint )
|
||||
{ try {
|
||||
if( !is_open() )
|
||||
open();
|
||||
|
||||
sockaddr_in local_addr;
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_port = htons(local_endpoint.port());
|
||||
local_addr.sin_addr.s_addr = htonl(local_endpoint.get_address());
|
||||
|
||||
if( UDT::ERROR == UDT::bind(_udt_socket_id, (sockaddr*)&local_addr, sizeof(local_addr)) )
|
||||
check_udt_errors();
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void udt_socket::connect_to( const ip::endpoint& remote_endpoint )
|
||||
{ try {
|
||||
if( !is_open() )
|
||||
open();
|
||||
|
||||
sockaddr_in serv_addr;
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(remote_endpoint.port());
|
||||
serv_addr.sin_addr.s_addr = htonl(remote_endpoint.get_address());
|
||||
|
||||
// UDT doesn't allow now blocking connects...
|
||||
fc::thread connect_thread("connect_thread");
|
||||
connect_thread.async( [&](){
|
||||
if( UDT::ERROR == UDT::connect(_udt_socket_id, (sockaddr*)&serv_addr, sizeof(serv_addr)) )
|
||||
check_udt_errors();
|
||||
}, "udt_socket::connect_to").wait();
|
||||
|
||||
bool block = false;
|
||||
UDT::setsockopt(_udt_socket_id, 0, UDT_SNDSYN, &block, sizeof(bool));
|
||||
UDT::setsockopt(_udt_socket_id, 0, UDT_RCVSYN, &block, sizeof(bool));
|
||||
check_udt_errors();
|
||||
|
||||
} FC_CAPTURE_AND_RETHROW( (remote_endpoint) ) }
|
||||
|
||||
ip::endpoint udt_socket::remote_endpoint() const
|
||||
{ try {
|
||||
sockaddr_in peer_addr;
|
||||
int peer_addr_size = sizeof(peer_addr);
|
||||
int error_code = UDT::getpeername( _udt_socket_id, (struct sockaddr*)&peer_addr, &peer_addr_size );
|
||||
if( error_code == UDT::ERROR )
|
||||
check_udt_errors();
|
||||
return ip::endpoint( ip::address( htonl( peer_addr.sin_addr.s_addr ) ), htons(peer_addr.sin_port) );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
ip::endpoint udt_socket::local_endpoint() const
|
||||
{ try {
|
||||
sockaddr_in sock_addr;
|
||||
int addr_size = sizeof(sock_addr);
|
||||
int error_code = UDT::getsockname( _udt_socket_id, (struct sockaddr*)&sock_addr, &addr_size );
|
||||
if( error_code == UDT::ERROR )
|
||||
check_udt_errors();
|
||||
return ip::endpoint( ip::address( htonl( sock_addr.sin_addr.s_addr ) ), htons(sock_addr.sin_port) );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
|
||||
/// @{
|
||||
size_t udt_socket::readsome( char* buffer, size_t max )
|
||||
{ try {
|
||||
auto bytes_read = UDT::recv( _udt_socket_id, buffer, max, 0 );
|
||||
while( bytes_read == UDT::ERROR )
|
||||
{
|
||||
if( UDT::getlasterror().getErrorCode() == CUDTException::EASYNCRCV )
|
||||
{
|
||||
UDT::getlasterror().clear();
|
||||
promise<void>::ptr p(new promise<void>("udt_socket::readsome"));
|
||||
default_epool_service().notify_read( _udt_socket_id, p );
|
||||
p->wait();
|
||||
bytes_read = UDT::recv( _udt_socket_id, buffer, max, 0 );
|
||||
}
|
||||
else
|
||||
check_udt_errors();
|
||||
}
|
||||
return bytes_read;
|
||||
} FC_CAPTURE_AND_RETHROW( (max) ) }
|
||||
|
||||
size_t udt_socket::readsome( const std::shared_ptr<char>& buf, size_t len, size_t offset )
|
||||
{
|
||||
return readsome(buf.get() + offset, len);
|
||||
}
|
||||
|
||||
bool udt_socket::eof()const
|
||||
{
|
||||
// TODO...
|
||||
return false;
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// ostream interface
|
||||
/// @{
|
||||
size_t udt_socket::writesome( const char* buffer, size_t len )
|
||||
{ try {
|
||||
auto bytes_sent = UDT::send(_udt_socket_id, buffer, len, 0);
|
||||
|
||||
while( UDT::ERROR == bytes_sent )
|
||||
{
|
||||
if( UDT::getlasterror().getErrorCode() == CUDTException::EASYNCSND )
|
||||
{
|
||||
UDT::getlasterror().clear();
|
||||
promise<void>::ptr p(new promise<void>("udt_socket::writesome"));
|
||||
default_epool_service().notify_write( _udt_socket_id, p );
|
||||
p->wait();
|
||||
bytes_sent = UDT::send(_udt_socket_id, buffer, len, 0);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
check_udt_errors();
|
||||
}
|
||||
return bytes_sent;
|
||||
} FC_CAPTURE_AND_RETHROW( (len) ) }
|
||||
|
||||
size_t udt_socket::writesome( const std::shared_ptr<const char>& buf, size_t len, size_t offset )
|
||||
{
|
||||
return writesome(buf.get() + offset, len);
|
||||
}
|
||||
|
||||
void udt_socket::flush(){}
|
||||
|
||||
void udt_socket::close()
|
||||
{ try {
|
||||
if( is_open() )
|
||||
{
|
||||
default_epool_service().remove( _udt_socket_id );
|
||||
UDT::close( _udt_socket_id );
|
||||
check_udt_errors();
|
||||
_udt_socket_id = UDT::INVALID_SOCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
wlog( "already closed" );
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
/// @}
|
||||
|
||||
void udt_socket::open()
|
||||
{
|
||||
_udt_socket_id = UDT::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( _udt_socket_id == UDT::INVALID_SOCK )
|
||||
check_udt_errors();
|
||||
}
|
||||
|
||||
bool udt_socket::is_open()const
|
||||
{
|
||||
return _udt_socket_id != UDT::INVALID_SOCK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
udt_server::udt_server()
|
||||
:_udt_socket_id( UDT::INVALID_SOCK )
|
||||
{
|
||||
_udt_socket_id = UDT::socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( _udt_socket_id == UDT::INVALID_SOCK )
|
||||
check_udt_errors();
|
||||
|
||||
bool block = false;
|
||||
UDT::setsockopt(_udt_socket_id, 0, UDT_SNDSYN, &block, sizeof(bool));
|
||||
check_udt_errors();
|
||||
UDT::setsockopt(_udt_socket_id, 0, UDT_RCVSYN, &block, sizeof(bool));
|
||||
check_udt_errors();
|
||||
}
|
||||
|
||||
udt_server::~udt_server()
|
||||
{
|
||||
try {
|
||||
close();
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
wlog( "${e}", ("e", e.to_detail_string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void udt_server::close()
|
||||
{ try {
|
||||
if( _udt_socket_id != UDT::INVALID_SOCK )
|
||||
{
|
||||
UDT::close( _udt_socket_id );
|
||||
check_udt_errors();
|
||||
default_epool_service().remove( _udt_socket_id );
|
||||
_udt_socket_id = UDT::INVALID_SOCK;
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void udt_server::accept( udt_socket& s )
|
||||
{ try {
|
||||
FC_ASSERT( !s.is_open() );
|
||||
int namelen;
|
||||
sockaddr_in their_addr;
|
||||
|
||||
|
||||
while( s._udt_socket_id == UDT::INVALID_SOCK )
|
||||
{
|
||||
s._udt_socket_id = UDT::accept( _udt_socket_id, (sockaddr*)&their_addr, &namelen );
|
||||
if( UDT::getlasterror().getErrorCode() == CUDTException::EASYNCRCV )
|
||||
{
|
||||
UDT::getlasterror().clear();
|
||||
promise<void>::ptr p(new promise<void>("udt_server::accept"));
|
||||
default_epool_service().notify_read( _udt_socket_id, p );
|
||||
p->wait();
|
||||
s._udt_socket_id = UDT::accept( _udt_socket_id, (sockaddr*)&their_addr, &namelen );
|
||||
}
|
||||
else
|
||||
check_udt_errors();
|
||||
}
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
void udt_server::listen( const ip::endpoint& ep )
|
||||
{ try {
|
||||
sockaddr_in my_addr;
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(ep.port());
|
||||
my_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
memset(&(my_addr.sin_zero), '\0', 8);
|
||||
|
||||
if( UDT::ERROR == UDT::bind(_udt_socket_id, (sockaddr*)&my_addr, sizeof(my_addr)) )
|
||||
check_udt_errors();
|
||||
|
||||
UDT::listen(_udt_socket_id, 10);
|
||||
check_udt_errors();
|
||||
} FC_CAPTURE_AND_RETHROW( (ep) ) }
|
||||
|
||||
fc::ip::endpoint udt_server::local_endpoint() const
|
||||
{ try {
|
||||
sockaddr_in sock_addr;
|
||||
int addr_size = sizeof(sock_addr);
|
||||
int error_code = UDT::getsockname( _udt_socket_id, (struct sockaddr*)&sock_addr, &addr_size );
|
||||
if( error_code == UDT::ERROR )
|
||||
check_udt_errors();
|
||||
return ip::endpoint( ip::address( htonl( sock_addr.sin_addr.s_addr ) ), htons(sock_addr.sin_port) );
|
||||
} FC_CAPTURE_AND_RETHROW() }
|
||||
|
||||
}
|
||||
68
src/rpc/bstate.cpp
Normal file
68
src/rpc/bstate.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include <fc/rpc/bstate.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <fc/reflect/variant.hpp>
|
||||
|
||||
namespace fc { namespace rpc {
|
||||
bstate::~bstate()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void bstate::add_method( const fc::string& name, method m )
|
||||
{
|
||||
_methods.emplace(std::pair<std::string,method>(name,fc::move(m)));
|
||||
}
|
||||
|
||||
void bstate::remove_method( const fc::string& name )
|
||||
{
|
||||
_methods.erase(name);
|
||||
}
|
||||
|
||||
result_type bstate::local_call( const string& method_name, const params_type& args )
|
||||
{
|
||||
auto method_itr = _methods.find(method_name);
|
||||
if( method_itr == _methods.end() && _unhandled )
|
||||
return _unhandled( method_name, args );
|
||||
FC_ASSERT( method_itr != _methods.end(), "Unknown Method: ${name}", ("name",method_name) );
|
||||
return method_itr->second(args);
|
||||
}
|
||||
|
||||
void bstate::handle_reply( const bresponse& bresponse )
|
||||
{
|
||||
auto await = _awaiting.find( bresponse.id );
|
||||
FC_ASSERT( await != _awaiting.end(), "Unknown Response ID: ${id}", ("id",bresponse.id)("bresponse",bresponse) );
|
||||
if( bresponse.result )
|
||||
await->second->set_value( *bresponse.result );
|
||||
else if( bresponse.error )
|
||||
{
|
||||
await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",bresponse.error->message)("data",bresponse) ) ) );
|
||||
}
|
||||
else
|
||||
await->second->set_value( params_type() );
|
||||
_awaiting.erase(await);
|
||||
}
|
||||
|
||||
brequest bstate::start_remote_call( const string& method_name, params_type args )
|
||||
{
|
||||
brequest brequest{ _next_id++, method_name, std::move(args) };
|
||||
_awaiting[*brequest.id] = fc::promise<result_type>::ptr( new fc::promise<result_type>("json_connection::async_call") );
|
||||
return brequest;
|
||||
}
|
||||
result_type bstate::wait_for_response( uint64_t request_id )
|
||||
{
|
||||
auto itr = _awaiting.find(request_id);
|
||||
FC_ASSERT( itr != _awaiting.end() );
|
||||
return fc::future<result_type>( itr->second ).wait();
|
||||
}
|
||||
void bstate::close()
|
||||
{
|
||||
for( auto item : _awaiting )
|
||||
item.second->set_exception( fc::exception_ptr(new FC_EXCEPTION( eof_exception, "connection closed" )) );
|
||||
_awaiting.clear();
|
||||
}
|
||||
void bstate::on_unhandled( const std::function<result_type(const string&, const params_type&)>& unhandled )
|
||||
{
|
||||
_unhandled = unhandled;
|
||||
}
|
||||
|
||||
} } // namespace fc::rpc
|
||||
|
|
@ -11,9 +11,22 @@ http_api_connection::http_api_connection()
|
|||
{
|
||||
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
|
||||
{
|
||||
// TODO: This logic is duplicated between http_api_connection and websocket_api_connection
|
||||
// it should be consolidated into one place instead of copy-pasted
|
||||
FC_ASSERT( args.size() == 3 && args[2].is_array() );
|
||||
api_id_type api_id;
|
||||
if( args[0].is_string() )
|
||||
{
|
||||
variants subargs;
|
||||
subargs.push_back( args[0] );
|
||||
variant subresult = this->receive_call( 1, "get_api_by_name", subargs );
|
||||
api_id = subresult.as_uint64();
|
||||
}
|
||||
else
|
||||
api_id = args[0].as_uint64();
|
||||
|
||||
return this->receive_call(
|
||||
args[0].as_uint64(),
|
||||
api_id,
|
||||
args[1].as_string(),
|
||||
args[2].get_array() );
|
||||
} );
|
||||
|
|
@ -85,9 +98,13 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht
|
|||
auto call = var.as<fc::rpc::request>();
|
||||
try
|
||||
{
|
||||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) );
|
||||
resp_status = http::reply::OK;
|
||||
try
|
||||
{
|
||||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) );
|
||||
resp_status = http::reply::OK;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) );
|
||||
}
|
||||
catch ( const fc::exception& e )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,8 +13,19 @@ websocket_api_connection::websocket_api_connection( fc::http::websocket_connecti
|
|||
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
|
||||
{
|
||||
FC_ASSERT( args.size() == 3 && args[2].is_array() );
|
||||
api_id_type api_id;
|
||||
if( args[0].is_string() )
|
||||
{
|
||||
variants subargs;
|
||||
subargs.push_back( args[0] );
|
||||
variant subresult = this->receive_call( 1, "get_api_by_name", subargs );
|
||||
api_id = subresult.as_uint64();
|
||||
}
|
||||
else
|
||||
api_id = args[0].as_uint64();
|
||||
|
||||
return this->receive_call(
|
||||
args[0].as_uint64(),
|
||||
api_id,
|
||||
args[1].as_string(),
|
||||
args[2].get_array() );
|
||||
} );
|
||||
|
|
@ -74,6 +85,7 @@ std::string websocket_api_connection::on_message(
|
|||
const std::string& message,
|
||||
bool send_message /* = true */ )
|
||||
{
|
||||
wdump((message));
|
||||
try
|
||||
{
|
||||
auto var = fc::json::from_string(message);
|
||||
|
|
@ -84,14 +96,18 @@ std::string websocket_api_connection::on_message(
|
|||
exception_ptr optexcept;
|
||||
try
|
||||
{
|
||||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
if( call.id )
|
||||
try
|
||||
{
|
||||
auto reply = fc::json::to_string( response( *call.id, result ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
return reply;
|
||||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
if( call.id )
|
||||
{
|
||||
auto reply = fc::json::to_string( response( *call.id, result ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) )
|
||||
}
|
||||
catch ( const fc::exception& e )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -172,6 +172,91 @@ namespace fc {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a size including an optional multiplicative suffix.
|
||||
*
|
||||
* M -> 1024*1024 bytes
|
||||
* MB -> 1000*1000 bytes
|
||||
* MiB -> 1024*1024 bytes
|
||||
*
|
||||
* The 'M' may be any of KMGTPEZY (upper or lower case)
|
||||
*/
|
||||
uint64_t parse_size( const string& s )
|
||||
{
|
||||
try
|
||||
{
|
||||
size_t i = 0, n = s.size(), suffix_start = n;
|
||||
for( i=0; i<n; i++ )
|
||||
{
|
||||
if( !((s[i] >= '0') && (s[i] <= '9')) )
|
||||
{
|
||||
suffix_start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint64_t u = to_uint64( s.substr( 0, suffix_start ) );
|
||||
|
||||
FC_ASSERT( n - suffix_start <= 3 );
|
||||
|
||||
uint64_t m = 1;
|
||||
uint64_t thousand = 1024;
|
||||
|
||||
if( suffix_start == n )
|
||||
{
|
||||
return u;
|
||||
}
|
||||
else if( suffix_start == n-1 )
|
||||
{
|
||||
}
|
||||
else if( suffix_start == n-2 )
|
||||
{
|
||||
FC_ASSERT( (s[suffix_start+1] == 'b') || (s[suffix_start+1] == 'B') );
|
||||
thousand = 1000;
|
||||
}
|
||||
else if( suffix_start == n-3 )
|
||||
{
|
||||
FC_ASSERT( (s[suffix_start+1] == 'i') || (s[suffix_start+1] == 'I') );
|
||||
FC_ASSERT( (s[suffix_start+2] == 'b') || (s[suffix_start+2] == 'B') );
|
||||
}
|
||||
switch( s[suffix_start] )
|
||||
{
|
||||
case 'y':
|
||||
case 'Y':
|
||||
m *= thousand;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
m *= thousand;
|
||||
case 'e':
|
||||
case 'E':
|
||||
m *= thousand;
|
||||
case 'p':
|
||||
case 'P':
|
||||
m *= thousand;
|
||||
case 't':
|
||||
case 'T':
|
||||
m *= thousand;
|
||||
case 'g':
|
||||
case 'G':
|
||||
m *= thousand;
|
||||
case 'm':
|
||||
case 'M':
|
||||
m *= thousand;
|
||||
case 'k':
|
||||
case 'K':
|
||||
m *= thousand;
|
||||
break;
|
||||
default:
|
||||
FC_ASSERT( false );
|
||||
}
|
||||
return u*m;
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "Couldn't parse size" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#include <fc/exception/exception.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 105400
|
||||
|
|
@ -43,12 +45,17 @@ namespace fc {
|
|||
struct context {
|
||||
typedef fc::context* ptr;
|
||||
|
||||
#if BOOST_VERSION >= 105400
|
||||
#if BOOST_VERSION >= 105400 // && BOOST_VERSION <= 106100
|
||||
bco::stack_context stack_ctx;
|
||||
#endif
|
||||
|
||||
#if BOOST_VERSION >= 106100
|
||||
typedef bc::detail::transfer_t transfer_t;
|
||||
#else
|
||||
typedef intptr_t transfer_t;
|
||||
#endif
|
||||
|
||||
context( void (*sf)(intptr_t), stack_allocator& alloc, fc::thread* t )
|
||||
context( void (*sf)(transfer_t), stack_allocator& alloc, fc::thread* t )
|
||||
: caller_context(0),
|
||||
stack_alloc(&alloc),
|
||||
next_blocked(0),
|
||||
|
|
@ -63,7 +70,13 @@ namespace fc {
|
|||
cur_task(0),
|
||||
context_posted_num(0)
|
||||
{
|
||||
#if BOOST_VERSION >= 105600
|
||||
#if BOOST_VERSION >= 106100
|
||||
// std::cerr<< "HERE: "<< BOOST_VERSION <<"\n";
|
||||
//my_context = new bc::execution_context<intptr_t>( [=]( bc::execution_context<intptr_t> sink, intptr_t self ){ std::cerr<<"in ex\n"; sf(self); std::cerr<<"exit ex\n"; return sink; } );
|
||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
||||
alloc.allocate(stack_ctx, stack_size);
|
||||
my_context = bc::detail::make_fcontext( stack_ctx.sp, stack_ctx.size, sf );
|
||||
#elif BOOST_VERSION >= 105600
|
||||
size_t stack_size = FC_CONTEXT_STACK_SIZE;
|
||||
alloc.allocate(stack_ctx, stack_size);
|
||||
my_context = bc::make_fcontext( stack_ctx.sp, stack_ctx.size, sf);
|
||||
|
|
@ -84,7 +97,7 @@ namespace fc {
|
|||
}
|
||||
|
||||
context( fc::thread* t) :
|
||||
#if BOOST_VERSION >= 105600
|
||||
#if BOOST_VERSION >= 105600 && BOOST_VERSION <= 106100
|
||||
my_context(nullptr),
|
||||
#elif BOOST_VERSION >= 105300
|
||||
my_context(new bc::fcontext_t),
|
||||
|
|
@ -102,10 +115,21 @@ namespace fc {
|
|||
complete(false),
|
||||
cur_task(0),
|
||||
context_posted_num(0)
|
||||
{}
|
||||
{
|
||||
|
||||
#if BOOST_VERSION >= 106100
|
||||
/*
|
||||
bc::execution_context<intptr_t> tmp( [=]( bc::execution_context<intptr_t> sink, intptr_t ) { std::cerr<<"get current\n"; return sink; } );
|
||||
auto result = tmp(0);
|
||||
my_context = new bc::execution_context<intptr_t>( std::move( std::get<0>(result) ) );
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
~context() {
|
||||
#if BOOST_VERSION >= 105600
|
||||
#if BOOST_VERSION >= 106100
|
||||
// delete my_context;
|
||||
#elif BOOST_VERSION >= 105600
|
||||
if(stack_alloc)
|
||||
stack_alloc->deallocate( stack_ctx );
|
||||
#elif BOOST_VERSION >= 105400
|
||||
|
|
@ -209,7 +233,11 @@ namespace fc {
|
|||
|
||||
|
||||
|
||||
#if BOOST_VERSION >= 105300 && BOOST_VERSION < 105600
|
||||
|
||||
#if BOOST_VERSION >= 106100
|
||||
//bc::execution_context<intptr_t>* my_context;
|
||||
bc::detail::fcontext_t my_context;
|
||||
#elif BOOST_VERSION >= 105300 && BOOST_VERSION < 105600
|
||||
bc::fcontext_t* my_context;
|
||||
#else
|
||||
bc::fcontext_t my_context;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "thread_d.hpp"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(NDEBUG)
|
||||
# include <Windows.h>
|
||||
# include <windows.h>
|
||||
const DWORD MS_VC_EXCEPTION=0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
|
|
@ -92,7 +92,7 @@ namespace fc {
|
|||
p->wait();
|
||||
my->boost_thread = t;
|
||||
my->name = name;
|
||||
wlog("name:${n} tid:${tid}", ("n", name)("tid", (uintptr_t)my->boost_thread->native_handle()) );
|
||||
//wlog("name:${n} tid:${tid}", ("n", name)("tid", (uintptr_t)my->boost_thread->native_handle()) );
|
||||
}
|
||||
thread::thread( thread_d* ) {
|
||||
my = new thread_d(*this);
|
||||
|
|
@ -118,24 +118,24 @@ namespace fc {
|
|||
}
|
||||
|
||||
thread& thread::current() {
|
||||
if( !current_thread() )
|
||||
if( !current_thread() )
|
||||
current_thread() = new thread((thread_d*)0);
|
||||
return *current_thread();
|
||||
}
|
||||
|
||||
const string& thread::name()const
|
||||
{
|
||||
return my->name;
|
||||
const string& thread::name()const
|
||||
{
|
||||
return my->name;
|
||||
}
|
||||
|
||||
void thread::set_name( const fc::string& n )
|
||||
{
|
||||
{
|
||||
if (!is_current())
|
||||
{
|
||||
async([=](){ set_name(n); }, "set_name").wait();
|
||||
return;
|
||||
}
|
||||
my->name = n;
|
||||
my->name = n;
|
||||
set_thread_name(my->name.c_str()); // set thread's name for the debugger to display
|
||||
}
|
||||
|
||||
|
|
@ -145,17 +145,17 @@ namespace fc {
|
|||
return my->current->cur_task->get_desc();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void thread::debug( const fc::string& d ) { /*my->debug(d);*/ }
|
||||
|
||||
void thread::quit()
|
||||
void thread::quit()
|
||||
{
|
||||
//if quitting from a different thread, start quit task on thread.
|
||||
//If we have and know our attached boost thread, wait for it to finish, then return.
|
||||
if( ¤t() != this )
|
||||
if( ¤t() != this )
|
||||
{
|
||||
async( [=](){quit();}, "thread::quit" );//.wait();
|
||||
if( my->boost_thread )
|
||||
if( my->boost_thread )
|
||||
{
|
||||
//wlog("destroying boost thread ${tid}",("tid",(uintptr_t)my->boost_thread->native_handle()));
|
||||
my->boost_thread->join();
|
||||
|
|
@ -170,23 +170,23 @@ namespace fc {
|
|||
// We are quiting from our own thread...
|
||||
|
||||
// break all promises, thread quit!
|
||||
while( my->blocked )
|
||||
while( my->blocked )
|
||||
{
|
||||
fc::context* cur = my->blocked;
|
||||
while( cur )
|
||||
while( cur )
|
||||
{
|
||||
fc::context* n = cur->next;
|
||||
// this will move the context into the ready list.
|
||||
//cur->prom->set_exception( boost::copy_exception( error::thread_quit() ) );
|
||||
//cur->set_exception_on_blocking_promises( thread_quit() );
|
||||
cur->set_exception_on_blocking_promises( std::make_shared<canceled_exception>(FC_LOG_MESSAGE(error, "cancellation reason: thread quitting")) );
|
||||
|
||||
|
||||
cur = n;
|
||||
}
|
||||
if( my->blocked )
|
||||
{
|
||||
if( my->blocked )
|
||||
{
|
||||
//wlog( "still blocking... whats up with that?");
|
||||
debug( "on quit" );
|
||||
debug( "on quit" );
|
||||
}
|
||||
}
|
||||
BOOST_ASSERT( my->blocked == 0 );
|
||||
|
|
@ -200,7 +200,7 @@ namespace fc {
|
|||
scheduled_task->set_exception(std::make_shared<canceled_exception>(FC_LOG_MESSAGE(error, "cancellation reason: thread quitting")));
|
||||
my->task_sch_queue.clear();
|
||||
|
||||
|
||||
|
||||
|
||||
// move all sleep tasks to ready
|
||||
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
|
||||
|
|
@ -209,7 +209,7 @@ namespace fc {
|
|||
|
||||
// move all idle tasks to ready
|
||||
fc::context* cur = my->pt_head;
|
||||
while( cur )
|
||||
while( cur )
|
||||
{
|
||||
fc::context* n = cur->next;
|
||||
cur->next = 0;
|
||||
|
|
@ -217,7 +217,7 @@ namespace fc {
|
|||
cur = n;
|
||||
}
|
||||
|
||||
// mark all ready tasks (should be everyone)... as canceled
|
||||
// mark all ready tasks (should be everyone)... as canceled
|
||||
for (fc::context* ready_context : my->ready_heap)
|
||||
ready_context->canceled = true;
|
||||
|
||||
|
|
@ -225,22 +225,22 @@ namespace fc {
|
|||
// let them all quit.
|
||||
while (!my->ready_heap.empty())
|
||||
{
|
||||
my->start_next_fiber(true);
|
||||
my->start_next_fiber(true);
|
||||
my->check_for_timeouts();
|
||||
}
|
||||
my->clear_free_list();
|
||||
my->cleanup_thread_specific_data();
|
||||
}
|
||||
|
||||
void thread::exec()
|
||||
|
||||
void thread::exec()
|
||||
{
|
||||
if( !my->current )
|
||||
if( !my->current )
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
|
||||
try
|
||||
|
||||
try
|
||||
{
|
||||
my->process_tasks();
|
||||
}
|
||||
my->process_tasks();
|
||||
}
|
||||
catch( canceled_exception& e )
|
||||
{
|
||||
dlog( "thread canceled: ${e}", ("e", e.to_detail_string()) );
|
||||
|
|
@ -248,40 +248,40 @@ namespace fc {
|
|||
delete my->current;
|
||||
my->current = 0;
|
||||
}
|
||||
|
||||
bool thread::is_running()const
|
||||
|
||||
bool thread::is_running()const
|
||||
{
|
||||
return !my->done;
|
||||
}
|
||||
|
||||
priority thread::current_priority()const
|
||||
|
||||
priority thread::current_priority()const
|
||||
{
|
||||
BOOST_ASSERT(my);
|
||||
if( my->current )
|
||||
if( my->current )
|
||||
return my->current->prio;
|
||||
return priority();
|
||||
}
|
||||
|
||||
void thread::yield(bool reschedule)
|
||||
void thread::yield(bool reschedule)
|
||||
{
|
||||
my->check_fiber_exceptions();
|
||||
my->start_next_fiber(reschedule);
|
||||
my->check_fiber_exceptions();
|
||||
}
|
||||
|
||||
void thread::sleep_until( const time_point& tp )
|
||||
void thread::sleep_until( const time_point& tp )
|
||||
{
|
||||
if( tp <= (time_point::now()+fc::microseconds(10000)) )
|
||||
if( tp <= (time_point::now()+fc::microseconds(10000)) )
|
||||
yield(true);
|
||||
my->yield_until( tp, false );
|
||||
}
|
||||
|
||||
int thread::wait_any_until( std::vector<promise_base::ptr>&& p, const time_point& timeout) {
|
||||
for( size_t i = 0; i < p.size(); ++i )
|
||||
if( p[i]->ready() )
|
||||
if( p[i]->ready() )
|
||||
return i;
|
||||
|
||||
if( timeout < time_point::now() )
|
||||
if( timeout < time_point::now() )
|
||||
{
|
||||
fc::stringstream ss;
|
||||
for( auto i = p.begin(); i != p.end(); ++i )
|
||||
|
|
@ -289,20 +289,20 @@ namespace fc {
|
|||
|
||||
FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task",ss.str()) );
|
||||
}
|
||||
|
||||
|
||||
if( !my->current )
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
|
||||
for( uint32_t i = 0; i < p.size(); ++i )
|
||||
my->current->add_blocking_promise(p[i].get(),false);
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::maximum() )
|
||||
if( timeout != time_point::maximum() )
|
||||
{
|
||||
my->current->resume_time = timeout;
|
||||
my->sleep_pqueue.push_back(my->current);
|
||||
std::push_heap( my->sleep_pqueue.begin(),
|
||||
my->sleep_pqueue.end(),
|
||||
my->sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
|
||||
|
|
@ -311,11 +311,11 @@ namespace fc {
|
|||
|
||||
for( auto i = p.begin(); i != p.end(); ++i )
|
||||
my->current->remove_blocking_promise(i->get());
|
||||
|
||||
|
||||
my->check_fiber_exceptions();
|
||||
|
||||
for( uint32_t i = 0; i < p.size(); ++i )
|
||||
if( p[i]->ready() )
|
||||
if( p[i]->ready() )
|
||||
return i;
|
||||
|
||||
//BOOST_THROW_EXCEPTION( wait_any_error() );
|
||||
|
|
@ -342,8 +342,8 @@ namespace fc {
|
|||
|
||||
// Because only one thread can post the 'first task', only that thread will attempt
|
||||
// to aquire the lock and therefore there should be no contention on this lock except
|
||||
// when *this thread is about to block on a wait condition.
|
||||
if( this != ¤t() && !stale_head ) {
|
||||
// when *this thread is about to block on a wait condition.
|
||||
if( this != ¤t() && !stale_head ) {
|
||||
boost::unique_lock<boost::mutex> lock(my->task_ready_mutex);
|
||||
my->task_ready.notify_one();
|
||||
}
|
||||
|
|
@ -359,42 +359,42 @@ namespace fc {
|
|||
thread::current().sleep_until(tp);
|
||||
}
|
||||
|
||||
void exec()
|
||||
void exec()
|
||||
{
|
||||
return thread::current().exec();
|
||||
}
|
||||
|
||||
int wait_any( std::vector<promise_base::ptr>&& v, const microseconds& timeout_us )
|
||||
int wait_any( std::vector<promise_base::ptr>&& v, const microseconds& timeout_us )
|
||||
{
|
||||
return thread::current().wait_any_until( fc::move(v), time_point::now() + timeout_us );
|
||||
}
|
||||
|
||||
int wait_any_until( std::vector<promise_base::ptr>&& v, const time_point& tp )
|
||||
int wait_any_until( std::vector<promise_base::ptr>&& v, const time_point& tp )
|
||||
{
|
||||
return thread::current().wait_any_until( fc::move(v), tp );
|
||||
}
|
||||
|
||||
void thread::wait_until( promise_base::ptr&& p, const time_point& timeout )
|
||||
void thread::wait_until( promise_base::ptr&& p, const time_point& timeout )
|
||||
{
|
||||
if( p->ready() )
|
||||
if( p->ready() )
|
||||
return;
|
||||
|
||||
if( timeout < time_point::now() )
|
||||
if( timeout < time_point::now() )
|
||||
FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task", p->get_desc()) );
|
||||
|
||||
if( !my->current )
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
|
||||
|
||||
if( !my->current )
|
||||
my->current = new fc::context(&fc::thread::current());
|
||||
|
||||
//slog( " %1% blocking on %2%", my->current, p.get() );
|
||||
my->current->add_blocking_promise(p.get(), true);
|
||||
|
||||
// if not max timeout, added to sleep pqueue
|
||||
if( timeout != time_point::maximum() )
|
||||
if( timeout != time_point::maximum() )
|
||||
{
|
||||
my->current->resume_time = timeout;
|
||||
my->sleep_pqueue.push_back(my->current);
|
||||
std::push_heap( my->sleep_pqueue.begin(),
|
||||
my->sleep_pqueue.end(),
|
||||
my->sleep_pqueue.end(),
|
||||
sleep_priority_less() );
|
||||
}
|
||||
|
||||
|
|
@ -412,34 +412,34 @@ namespace fc {
|
|||
my->check_fiber_exceptions();
|
||||
}
|
||||
|
||||
void thread::notify( const promise_base::ptr& p )
|
||||
void thread::notify( const promise_base::ptr& p )
|
||||
{
|
||||
//slog( "this %p my %p", this, my );
|
||||
BOOST_ASSERT(p->ready());
|
||||
if( !is_current() )
|
||||
if( !is_current() )
|
||||
{
|
||||
this->async( [=](){ notify(p); }, "notify", priority::max() );
|
||||
return;
|
||||
}
|
||||
// TODO: store a list of blocked contexts with the promise
|
||||
// TODO: store a list of blocked contexts with the promise
|
||||
// to accelerate the lookup.... unless it introduces contention...
|
||||
|
||||
|
||||
// iterate over all blocked contexts
|
||||
|
||||
|
||||
fc::context* cur_blocked = my->blocked;
|
||||
fc::context* prev_blocked = 0;
|
||||
while( cur_blocked )
|
||||
while( cur_blocked )
|
||||
{
|
||||
// if the blocked context is waiting on this promise
|
||||
if( cur_blocked->try_unblock( p.get() ) )
|
||||
// if the blocked context is waiting on this promise
|
||||
if( cur_blocked->try_unblock( p.get() ) )
|
||||
{
|
||||
// remove it from the blocked list.
|
||||
|
||||
// remove this context from the sleep queue...
|
||||
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
|
||||
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
|
||||
{
|
||||
if( my->sleep_pqueue[i] == cur_blocked )
|
||||
if( my->sleep_pqueue[i] == cur_blocked )
|
||||
{
|
||||
my->sleep_pqueue[i]->blocking_prom.clear();
|
||||
my->sleep_pqueue[i] = my->sleep_pqueue.back();
|
||||
|
|
@ -449,28 +449,28 @@ namespace fc {
|
|||
}
|
||||
}
|
||||
auto cur = cur_blocked;
|
||||
if( prev_blocked )
|
||||
{
|
||||
prev_blocked->next_blocked = cur_blocked->next_blocked;
|
||||
if( prev_blocked )
|
||||
{
|
||||
prev_blocked->next_blocked = cur_blocked->next_blocked;
|
||||
cur_blocked = prev_blocked->next_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
my->blocked = cur_blocked->next_blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
my->blocked = cur_blocked->next_blocked;
|
||||
cur_blocked = my->blocked;
|
||||
}
|
||||
cur->next_blocked = 0;
|
||||
my->add_context_to_ready_list( cur );
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{ // goto the next blocked task
|
||||
prev_blocked = cur_blocked;
|
||||
cur_blocked = cur_blocked->next_blocked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::is_current()const
|
||||
|
||||
bool thread::is_current()const
|
||||
{
|
||||
return this == ¤t();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ namespace fc {
|
|||
class thread_d {
|
||||
|
||||
public:
|
||||
fc::context* prev_ctx = nullptr;
|
||||
|
||||
thread_d(fc::thread& s)
|
||||
:self(s), boost_thread(0),
|
||||
task_in_queue(0),
|
||||
|
|
@ -397,7 +399,12 @@ namespace fc {
|
|||
}
|
||||
// slog( "jump to %p from %p", next, prev );
|
||||
// fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) );
|
||||
#if BOOST_VERSION >= 105600
|
||||
#if BOOST_VERSION >= 106100
|
||||
prev_ctx = prev;
|
||||
std::cerr<<"start jumping to existing context...\n";
|
||||
bc::detail::jump_fcontext( next->my_context, this );
|
||||
std::cerr<<"back from jumping to existing context\n";
|
||||
#elif BOOST_VERSION >= 105600
|
||||
bc::jump_fcontext( &prev->my_context, next->my_context, 0 );
|
||||
#elif BOOST_VERSION >= 105300
|
||||
bc::jump_fcontext( prev->my_context, next->my_context, 0 );
|
||||
|
|
@ -439,7 +446,16 @@ namespace fc {
|
|||
|
||||
// slog( "jump to %p from %p", next, prev );
|
||||
// fc_dlog( logger::get("fc_context"), "from ${from} to ${to}", ( "from", int64_t(prev) )( "to", int64_t(next) ) );
|
||||
#if BOOST_VERSION >= 105600
|
||||
#if BOOST_VERSION >= 106100
|
||||
//(*next->my_context)( (intptr_t)this );
|
||||
//bc::detail::transfer_t tran; tran.data = this;
|
||||
std::cerr << "start prev->my_context = " << prev->my_context <<"... \n";
|
||||
std::cerr << "jumping to next context... \n";
|
||||
prev_ctx = prev;
|
||||
auto result = bc::detail::jump_fcontext( next->my_context, this );
|
||||
std::cerr << "end prev->my_context = " << prev->my_context <<"... \n";
|
||||
std::cerr << result.fctx <<" <--- result \n";
|
||||
#elif BOOST_VERSION >= 105600
|
||||
bc::jump_fcontext( &prev->my_context, next->my_context, (intptr_t)this );
|
||||
#elif BOOST_VERSION >= 105300
|
||||
bc::jump_fcontext( prev->my_context, next->my_context, (intptr_t)this );
|
||||
|
|
@ -467,9 +483,22 @@ namespace fc {
|
|||
return true;
|
||||
}
|
||||
|
||||
static void start_process_tasks( intptr_t my )
|
||||
static void start_process_tasks( fc::context::transfer_t my )
|
||||
{
|
||||
#if BOOST_VERSION >= 106100
|
||||
std::cerr<<"my data: "<<my.data<<"\n";
|
||||
std::cerr<<"my from: "<<my.fctx<<"\n";
|
||||
thread_d* self = (thread_d*)my.data;
|
||||
if( self->prev_ctx )
|
||||
{
|
||||
std::cerr << "setting prev_ctx to " << int64_t(my.fctx) << "\n";
|
||||
self->prev_ctx->my_context = my.fctx;
|
||||
}
|
||||
std::cerr<<"start process tasks\n" << int64_t(self)<<"\n";
|
||||
assert( self != 0 );
|
||||
#else
|
||||
thread_d* self = (thread_d*)my;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
self->process_tasks();
|
||||
|
|
@ -484,6 +513,7 @@ namespace fc {
|
|||
}
|
||||
self->free_list.push_back(self->current);
|
||||
self->start_next_fiber( false );
|
||||
std::cerr << "existing start process tasks \n ";
|
||||
}
|
||||
|
||||
void run_next_task()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace fc
|
|||
{
|
||||
if (slot + 1 > specific_data->size())
|
||||
specific_data->resize(slot + 1);
|
||||
(*specific_data)[slot] = std::move(detail::specific_data_info(new_value, cleanup));
|
||||
(*specific_data)[slot] = detail::specific_data_info(new_value, cleanup);
|
||||
}
|
||||
|
||||
void* get_thread_specific_data(unsigned slot)
|
||||
|
|
@ -62,4 +62,4 @@ namespace fc
|
|||
}
|
||||
}
|
||||
}
|
||||
} // end namespace fc
|
||||
} // end namespace fc
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
#include <fc/uint128.hpp>
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/crypto/bigint.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include "byteswap.hpp"
|
||||
|
||||
namespace fc
|
||||
{
|
||||
typedef boost::multiprecision::uint128_t m128;
|
||||
|
||||
template <typename T>
|
||||
static void divide(const T &numerator, const T &denominator, T "ient, T &remainder)
|
||||
{
|
||||
|
||||
static const int bits = sizeof(T) * 8;//CHAR_BIT;
|
||||
|
||||
if(denominator == 0) {
|
||||
|
|
@ -220,8 +223,27 @@ namespace fc
|
|||
|
||||
uint128& uint128::operator/=(const uint128 &b)
|
||||
{
|
||||
auto self = (m128(hi) << 64) + m128(lo);
|
||||
auto other = (m128(b.hi) << 64) + m128(b.lo);
|
||||
self /= other;
|
||||
hi = static_cast<uint64_t>(self >> 64);
|
||||
lo = static_cast<uint64_t>((self << 64 ) >> 64);
|
||||
|
||||
/*
|
||||
uint128 remainder;
|
||||
divide(*this, b, *this, remainder);
|
||||
divide(*this, b, *this, remainder ); //, *this);
|
||||
if( tmp.hi != hi || tmp.lo != lo ) {
|
||||
std::cerr << tmp.hi << " " << hi <<"\n";
|
||||
std::cerr << tmp.lo << " " << lo << "\n";
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
const auto& b128 = std::reinterpret_cast<const m128&>(b);
|
||||
auto& this128 = std::reinterpret_cast<m128&>(*this);
|
||||
this128 /= b128;
|
||||
*/
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
20
src/utf8.cpp
20
src/utf8.cpp
|
|
@ -3,16 +3,36 @@
|
|||
#include "utf8/checked.h"
|
||||
#include "utf8/core.h"
|
||||
#include "utf8/unchecked.h"
|
||||
#include <websocketpp/utf8_validator.hpp>
|
||||
|
||||
#include <assert.h>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace fc {
|
||||
|
||||
bool is_utf8( const std::string& str )
|
||||
{
|
||||
auto itr = utf8::find_invalid(str.begin(), str.end());
|
||||
return utf8::is_valid( str.begin(), str.end() );
|
||||
}
|
||||
|
||||
string prune_invalid_utf8( const string& str ) {
|
||||
string result;
|
||||
|
||||
auto itr = utf8::find_invalid(str.begin(), str.end());
|
||||
if( itr == str.end() ) return str;
|
||||
|
||||
result = string( str.begin(), itr );
|
||||
while( itr != str.end() ) {
|
||||
++itr;
|
||||
auto start = itr;
|
||||
itr = utf8::find_invalid( start, str.end());
|
||||
result += string( start, itr );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void decodeUtf8(const std::string& input, std::wstring* storage)
|
||||
{
|
||||
assert(storage != nullptr);
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ void from_variant( const variant& var, std::vector<char>& vo )
|
|||
if( vo.size() )
|
||||
{
|
||||
size_t r = from_hex( str, vo.data(), vo.size() );
|
||||
FC_ASSERT( r = vo.size() );
|
||||
FC_ASSERT( r == vo.size() );
|
||||
}
|
||||
// std::string b64 = base64_decode( var.as_string() );
|
||||
// vo = std::vector<char>( b64.c_str(), b64.c_str() + b64.size() );
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ namespace fc
|
|||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void to_variant( const variant_object& var, variant& vo )
|
||||
{
|
||||
vo = variant(var);
|
||||
|
|
|
|||
62
tests/CMakeLists.txt
Normal file
62
tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
add_executable( bip_lock bip_lock.cpp )
|
||||
target_link_libraries( bip_lock fc )
|
||||
|
||||
add_executable( api api.cpp )
|
||||
target_link_libraries( api fc )
|
||||
|
||||
if( ECC_IMPL STREQUAL secp256k1 )
|
||||
add_executable( blind all_tests.cpp crypto/blind.cpp )
|
||||
target_link_libraries( blind fc )
|
||||
endif()
|
||||
|
||||
add_executable( ntp_test all_tests.cpp network/ntp_test.cpp )
|
||||
target_link_libraries( ntp_test fc )
|
||||
|
||||
add_executable( task_cancel_test all_tests.cpp thread/task_cancel.cpp )
|
||||
target_link_libraries( task_cancel_test fc )
|
||||
|
||||
|
||||
add_executable( bloom_test all_tests.cpp bloom_test.cpp )
|
||||
target_link_libraries( bloom_test fc )
|
||||
|
||||
add_executable( real128_test all_tests.cpp real128_test.cpp )
|
||||
target_link_libraries( real128_test fc )
|
||||
|
||||
add_executable( hmac_test hmac_test.cpp )
|
||||
target_link_libraries( hmac_test fc )
|
||||
|
||||
add_executable( blinding_test blinding_test.cpp )
|
||||
target_link_libraries( blinding_test fc )
|
||||
|
||||
add_executable( ecc_test crypto/ecc_test.cpp )
|
||||
target_link_libraries( ecc_test fc )
|
||||
|
||||
add_executable( log_test crypto/log_test.cpp )
|
||||
target_link_libraries( log_test fc )
|
||||
|
||||
#add_executable( test_aes aes_test.cpp )
|
||||
#target_link_libraries( test_aes fc ${rt_library} ${pthread_library} )
|
||||
#add_executable( test_sleep sleep.cpp )
|
||||
#target_link_libraries( test_sleep fc )
|
||||
#add_executable( test_rate_limiting rate_limiting.cpp )
|
||||
#target_link_libraries( test_rate_limiting fc )
|
||||
|
||||
add_executable( all_tests all_tests.cpp
|
||||
compress/compress.cpp
|
||||
crypto/aes_test.cpp
|
||||
crypto/base_n_tests.cpp
|
||||
crypto/bigint_test.cpp
|
||||
crypto/blind.cpp
|
||||
crypto/blowfish_test.cpp
|
||||
crypto/dh_test.cpp
|
||||
crypto/rand_test.cpp
|
||||
crypto/sha_tests.cpp
|
||||
network/ntp_test.cpp
|
||||
network/http/websocket_test.cpp
|
||||
thread/task_cancel.cpp
|
||||
bloom_test.cpp
|
||||
real128_test.cpp
|
||||
utf8_test.cpp
|
||||
)
|
||||
target_link_libraries( all_tests fc )
|
||||
44
tests/bip_lock.cpp
Normal file
44
tests/bip_lock.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include <iostream>
|
||||
#include <fc/interprocess/file_mutex.hpp>
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
int main( int argc, char** argv ) {
|
||||
if( argc < 2 ) return 0;
|
||||
fc::file_mutex m( argv[1] );
|
||||
auto mptr = &m;
|
||||
|
||||
fc::thread in("in");
|
||||
|
||||
std::string cmd;
|
||||
std::cout << ">>> ";
|
||||
std::cin >> cmd;
|
||||
int i = 0;
|
||||
while( !std::cin.eof() && cmd != "q" ) {
|
||||
++i;
|
||||
fc::async( [i, cmd,mptr]() {
|
||||
ilog( "start ${c} ${i}", ("c",cmd)("i",i) );
|
||||
if( cmd == "L" ) {
|
||||
mptr->lock();
|
||||
} else if( cmd == "l" ) {
|
||||
mptr->lock_shared();
|
||||
} else if( cmd == "U" ) {
|
||||
mptr->unlock();
|
||||
} else if( cmd == "u" ) {
|
||||
mptr->unlock_shared();
|
||||
}
|
||||
ilog( "end ${c} ${i}", ("c",cmd)("i",i) );
|
||||
} );
|
||||
fc::usleep( fc::microseconds( 1000 ) );
|
||||
cmd = in.async( [&]() {
|
||||
std::string tmp;
|
||||
wdump((m.readers()));
|
||||
std::cin >> tmp;
|
||||
return tmp;
|
||||
} );
|
||||
}
|
||||
std::cout << "done";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -50,15 +50,15 @@ BOOST_AUTO_TEST_CASE(blind_test)
|
|||
auto B4 = fc::sha256::hash("B4");
|
||||
auto C1 = fc::ecc::blind( B1, 1 );
|
||||
auto C2 = fc::ecc::blind( B2, 2 );
|
||||
auto c3 = fc::ecc::blind( b3, 3 );
|
||||
auto C4 = fc::ecc::blind( B4, -1 );
|
||||
/*auto c3 = */fc::ecc::blind( b3, 3 );
|
||||
/*auto C4 = */fc::ecc::blind( B4, -1 );
|
||||
|
||||
auto B3 = fc::ecc::blind_sum( {B1,B2}, 2 );
|
||||
auto C3 = fc::ecc::blind( B3, 3 );
|
||||
|
||||
|
||||
auto B2m1 = fc::ecc::blind_sum( {B2,B1}, 1 );
|
||||
auto C2m1 = fc::ecc::blind( B2m1, 1 );
|
||||
/*auto C2m1 = */fc::ecc::blind( B2m1, 1 );
|
||||
|
||||
BOOST_CHECK( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) );
|
||||
BOOST_CHECK( fc::ecc::verify_sum( {C1,C2}, {C3}, 0 ) );
|
||||
|
|
@ -68,9 +68,9 @@ BOOST_AUTO_TEST_CASE(blind_test)
|
|||
|
||||
{
|
||||
auto B1 = fc::sha256::hash("B1");
|
||||
auto B2 = fc::sha256::hash("B2");
|
||||
auto B3 = fc::sha256::hash("B3");
|
||||
auto B4 = fc::sha256::hash("B4");
|
||||
/*auto B2 = */fc::sha256::hash("B2");
|
||||
/*auto B3 = */fc::sha256::hash("B3");
|
||||
/*auto B4 = */fc::sha256::hash("B4");
|
||||
|
||||
//secp256k1_scalar_get_b32((unsigned char*)&B1, (const secp256k1_scalar_t*)&B2);
|
||||
//B1 = fc::variant("b2e5da56ef9f2a34d3e22fd12634bc99261e95c87b9960bf94ed3d27b30").as<fc::sha256>();
|
||||
|
|
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(blind_test)
|
|||
auto C1 = fc::ecc::blind( B1, INT64_MAX );
|
||||
auto C2 = fc::ecc::blind( B1, 0 );
|
||||
auto C3 = fc::ecc::blind( B1, 1 );
|
||||
auto C4 = fc::ecc::blind( B1, 2 );
|
||||
/*auto C4 = */fc::ecc::blind( B1, 2 );
|
||||
|
||||
BOOST_CHECK( fc::ecc::verify_sum( {C2}, {C3}, -1 ) );
|
||||
BOOST_CHECK( fc::ecc::verify_sum( {C1}, {C1}, 0 ) );
|
||||
|
|
|
|||
114
tests/crypto/log_test.cpp
Normal file
114
tests/crypto/log_test.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
uint64_t endian_reverse( uint64_t x )
|
||||
{
|
||||
uint64_t x0 = ((x ) & 0xFF);
|
||||
uint64_t x1 = ((x >> 0x08) & 0xFF);
|
||||
uint64_t x2 = ((x >> 0x10) & 0xFF);
|
||||
uint64_t x3 = ((x >> 0x18) & 0xFF);
|
||||
uint64_t x4 = ((x >> 0x20) & 0xFF);
|
||||
uint64_t x5 = ((x >> 0x28) & 0xFF);
|
||||
uint64_t x6 = ((x >> 0x30) & 0xFF);
|
||||
uint64_t x7 = ((x >> 0x38) & 0xFF);
|
||||
|
||||
return (x0 << 0x38)
|
||||
| (x1 << 0x30)
|
||||
| (x2 << 0x28)
|
||||
| (x3 << 0x20)
|
||||
| (x4 << 0x18)
|
||||
| (x5 << 0x10)
|
||||
| (x6 << 0x08)
|
||||
| (x7 );
|
||||
}
|
||||
|
||||
int main(int argc, char**argv, char** envp)
|
||||
{
|
||||
std::ifstream infile("log_test.txt");
|
||||
uint32_t ref_clz;
|
||||
std::string str_h;
|
||||
uint32_t ref_log;
|
||||
uint32_t cases = 0;
|
||||
uint32_t errors = 0;
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( !(infile >> std::hex >> ref_clz) )
|
||||
break;
|
||||
if( !(infile >> str_h) )
|
||||
break;
|
||||
if( !(infile >> std::hex >> ref_log) )
|
||||
break;
|
||||
fc::sha256 h(str_h);
|
||||
if( ref_clz != h.clz() )
|
||||
{
|
||||
std::cerr << "got error on clz(" << str_h << ")" << std::endl;
|
||||
++errors;
|
||||
}
|
||||
if( ref_log != h.approx_log_32() )
|
||||
{
|
||||
std::cerr << "got error on log(" << str_h << ")" << std::endl;
|
||||
++errors;
|
||||
}
|
||||
double d_ilog_h_test = h.inverse_approx_log_32_double( ref_log );
|
||||
h.set_to_inverse_approx_log_32( ref_log );
|
||||
if( ref_log != h.approx_log_32() )
|
||||
{
|
||||
std::cerr << "got error on ilog(" << ref_log << ")" << std::endl;
|
||||
++errors;
|
||||
}
|
||||
|
||||
std::string str_ilog_h = h.str();
|
||||
boost::multiprecision::uint256_t u256_ilog_h( "0x" + str_ilog_h );
|
||||
double d_ilog_h_ref = u256_ilog_h.template convert_to<double>();
|
||||
if( d_ilog_h_ref != d_ilog_h_test )
|
||||
{
|
||||
std::cerr << "got error on d_ilog(" << ref_log << ")" << std::endl;
|
||||
++errors;
|
||||
}
|
||||
|
||||
if( h != fc::sha256() )
|
||||
{
|
||||
fc::sha256 h_before = h;
|
||||
if( h._hash[3] == 0 )
|
||||
{
|
||||
if( h._hash[2] == 0 )
|
||||
{
|
||||
if( h._hash[1] == 0 )
|
||||
{
|
||||
h._hash[0] = endian_reverse( endian_reverse( h._hash[0] )-1 );
|
||||
}
|
||||
h._hash[1] = endian_reverse( endian_reverse( h._hash[1] )-1 );
|
||||
}
|
||||
h._hash[2] = endian_reverse( endian_reverse( h._hash[2] )-1 );
|
||||
}
|
||||
h._hash[3] = endian_reverse( endian_reverse( h._hash[3] )-1 );
|
||||
bool ok = (h.approx_log_32() < ref_log);
|
||||
if( !ok )
|
||||
{
|
||||
std::cerr << "got error on logm1 for " << ref_log << std::endl;
|
||||
std::cerr << "h0:" << str_h << std::endl;
|
||||
std::cerr << "h1:" << h_before.str() << std::endl;
|
||||
std::cerr << "h2:" << h.str() << std::endl;
|
||||
std::cerr << "ref_log:" << std::hex << std::setw(8) << ref_log << std::endl;
|
||||
std::cerr << "log(h) :" << std::hex << std::setw(8) << h.approx_log_32() << std::endl;
|
||||
std::cerr << std::endl;
|
||||
++errors;
|
||||
}
|
||||
}
|
||||
|
||||
++cases;
|
||||
}
|
||||
|
||||
std::cerr << "sha256_log_test checked " << cases << " cases, got " << errors << " errors" << std::endl;
|
||||
if( errors )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
29
tests/crypto/log_test.py
Executable file
29
tests/crypto/log_test.py
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Independent implementation of algorithm
|
||||
# To create log_test.txt, run ./log_test.py > log_test.txt
|
||||
|
||||
import random
|
||||
|
||||
rand = random.Random(1234)
|
||||
|
||||
result = set()
|
||||
|
||||
result.add((0, 256))
|
||||
result.add(((1 << 256)-1, 0))
|
||||
for i in range(256):
|
||||
y = (1 << i)
|
||||
result.add((y, 255-i))
|
||||
for j in range(32):
|
||||
result.add((y+rand.randrange(0, y), 255-i))
|
||||
|
||||
def get_sem_32(y):
|
||||
bs = "{:0256b}".format(y)
|
||||
if "1" not in bs:
|
||||
return 0
|
||||
bs += 32*"0"
|
||||
i = bs.index("1")
|
||||
return ((255-i) << 24) | int(bs[i+1:i+25], 2)
|
||||
|
||||
for y, lz in sorted(result):
|
||||
print("{:02x}".format(lz), "{:064x}".format(y), "{:08x}".format(get_sem_32(y)))
|
||||
|
|
@ -8,6 +8,10 @@ BOOST_AUTO_TEST_SUITE(fc_network)
|
|||
|
||||
BOOST_AUTO_TEST_CASE( ntp_test )
|
||||
{
|
||||
ilog("start ntp test");
|
||||
fc::usleep( fc::seconds(1) );
|
||||
ilog("done ntp test");
|
||||
/*
|
||||
fc::ntp ntp_service;
|
||||
ntp_service.set_request_interval(5);
|
||||
fc::usleep(fc::seconds(4) );
|
||||
|
|
@ -20,6 +24,7 @@ BOOST_AUTO_TEST_CASE( ntp_test )
|
|||
// auto seconds = delta.count() / 1000000;
|
||||
auto msec= delta.count() / 1000;
|
||||
BOOST_CHECK( msec < 100 );
|
||||
*/
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit aee799a31d08977b166fb19cad794730717e3304
|
||||
19
vendor/equihash/CMakeLists.txt
vendored
Normal file
19
vendor/equihash/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
file(GLOB HEADERS "include/equihash/*.hpp" )
|
||||
|
||||
set( CMAKE_C_FLAGS "-std=c99" )
|
||||
|
||||
add_library( equihash
|
||||
src/pow.cpp
|
||||
src/blake2b.c
|
||||
)
|
||||
|
||||
target_link_libraries( equihash )
|
||||
target_include_directories( equihash PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" )
|
||||
|
||||
install( TARGETS
|
||||
equihash
|
||||
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
72
vendor/equihash/include/equihash/blake2-config.h
vendored
Normal file
72
vendor/equihash/include/equihash/blake2-config.h
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2_CONFIG_H__
|
||||
#define __BLAKE2_CONFIG_H__
|
||||
|
||||
// These don't work everywhere
|
||||
#if defined(__SSE2__)
|
||||
#define HAVE_SSE2
|
||||
#endif
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
#define HAVE_SSSE3
|
||||
#endif
|
||||
|
||||
#if defined(__SSE4_1__)
|
||||
#define HAVE_SSE41
|
||||
#endif
|
||||
|
||||
#if defined(__AVX__)
|
||||
#define HAVE_AVX
|
||||
#endif
|
||||
|
||||
#if defined(__XOP__)
|
||||
#define HAVE_XOP
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_AVX2
|
||||
#ifndef HAVE_AVX
|
||||
#define HAVE_AVX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_XOP
|
||||
#ifndef HAVE_AVX
|
||||
#define HAVE_AVX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVX
|
||||
#ifndef HAVE_SSE41
|
||||
#define HAVE_SSE41
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSE41
|
||||
#ifndef HAVE_SSSE3
|
||||
#define HAVE_SSSE3
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SSSE3
|
||||
#define HAVE_SSE2
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SSE2)
|
||||
#error "This code requires at least SSE2."
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
136
vendor/equihash/include/equihash/blake2-impl.h
vendored
Normal file
136
vendor/equihash/include/equihash/blake2-impl.h
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2_IMPL_H__
|
||||
#define __BLAKE2_IMPL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint32_t load32( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint32_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
uint32_t w = *p++;
|
||||
w |= ( uint32_t )( *p++ ) << 8;
|
||||
w |= ( uint32_t )( *p++ ) << 16;
|
||||
w |= ( uint32_t )( *p++ ) << 24;
|
||||
return w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t load64( const void *src )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
uint64_t w;
|
||||
memcpy(&w, src, sizeof w);
|
||||
return w;
|
||||
#else
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
uint64_t w = *p++;
|
||||
w |= ( uint64_t )( *p++ ) << 8;
|
||||
w |= ( uint64_t )( *p++ ) << 16;
|
||||
w |= ( uint64_t )( *p++ ) << 24;
|
||||
w |= ( uint64_t )( *p++ ) << 32;
|
||||
w |= ( uint64_t )( *p++ ) << 40;
|
||||
w |= ( uint64_t )( *p++ ) << 48;
|
||||
w |= ( uint64_t )( *p++ ) << 56;
|
||||
return w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void store32( void *dst, uint32_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void store64( void *dst, uint64_t w )
|
||||
{
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
memcpy(dst, &w, sizeof w);
|
||||
#else
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline uint64_t load48( const void *src )
|
||||
{
|
||||
const uint8_t *p = ( const uint8_t * )src;
|
||||
uint64_t w = *p++;
|
||||
w |= ( uint64_t )( *p++ ) << 8;
|
||||
w |= ( uint64_t )( *p++ ) << 16;
|
||||
w |= ( uint64_t )( *p++ ) << 24;
|
||||
w |= ( uint64_t )( *p++ ) << 32;
|
||||
w |= ( uint64_t )( *p++ ) << 40;
|
||||
return w;
|
||||
}
|
||||
|
||||
static inline void store48( void *dst, uint64_t w )
|
||||
{
|
||||
uint8_t *p = ( uint8_t * )dst;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w; w >>= 8;
|
||||
*p++ = ( uint8_t )w;
|
||||
}
|
||||
|
||||
static inline uint32_t rotl32( const uint32_t w, const unsigned c )
|
||||
{
|
||||
return ( w << c ) | ( w >> ( 32 - c ) );
|
||||
}
|
||||
|
||||
static inline uint64_t rotl64( const uint64_t w, const unsigned c )
|
||||
{
|
||||
return ( w << c ) | ( w >> ( 64 - c ) );
|
||||
}
|
||||
|
||||
static inline uint32_t rotr32( const uint32_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 32 - c ) );
|
||||
}
|
||||
|
||||
static inline uint64_t rotr64( const uint64_t w, const unsigned c )
|
||||
{
|
||||
return ( w >> c ) | ( w << ( 64 - c ) );
|
||||
}
|
||||
|
||||
/* prevents compiler optimizing out memset() */
|
||||
static inline void secure_zero_memory( void *v, size_t n )
|
||||
{
|
||||
volatile uint8_t *p = ( volatile uint8_t * )v;
|
||||
while( n-- ) *p++ = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
157
vendor/equihash/include/equihash/blake2.h
vendored
Normal file
157
vendor/equihash/include/equihash/blake2.h
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2_H__
|
||||
#define __BLAKE2_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define ALIGN(x) __declspec(align(x))
|
||||
#else
|
||||
#define ALIGN(x) __attribute__ ((__aligned__(x)))
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum blake2s_constant
|
||||
{
|
||||
BLAKE2S_BLOCKBYTES = 64,
|
||||
BLAKE2S_OUTBYTES = 32,
|
||||
BLAKE2S_KEYBYTES = 32,
|
||||
BLAKE2S_SALTBYTES = 8,
|
||||
BLAKE2S_PERSONALBYTES = 8
|
||||
};
|
||||
|
||||
enum blake2b_constant
|
||||
{
|
||||
BLAKE2B_BLOCKBYTES = 128,
|
||||
BLAKE2B_OUTBYTES = 64,
|
||||
BLAKE2B_KEYBYTES = 64,
|
||||
BLAKE2B_SALTBYTES = 16,
|
||||
BLAKE2B_PERSONALBYTES = 16
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct __blake2s_param
|
||||
{
|
||||
uint8_t digest_length; // 1
|
||||
uint8_t key_length; // 2
|
||||
uint8_t fanout; // 3
|
||||
uint8_t depth; // 4
|
||||
uint32_t leaf_length; // 8
|
||||
uint8_t node_offset[6];// 14
|
||||
uint8_t node_depth; // 15
|
||||
uint8_t inner_length; // 16
|
||||
// uint8_t reserved[0];
|
||||
uint8_t salt[BLAKE2S_SALTBYTES]; // 24
|
||||
uint8_t personal[BLAKE2S_PERSONALBYTES]; // 32
|
||||
} blake2s_param;
|
||||
|
||||
ALIGN( 64 ) typedef struct __blake2s_state
|
||||
{
|
||||
uint32_t h[8];
|
||||
uint32_t t[2];
|
||||
uint32_t f[2];
|
||||
uint8_t buf[2 * BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
uint8_t last_node;
|
||||
} blake2s_state;
|
||||
|
||||
typedef struct __blake2b_param
|
||||
{
|
||||
uint8_t digest_length; // 1
|
||||
uint8_t key_length; // 2
|
||||
uint8_t fanout; // 3
|
||||
uint8_t depth; // 4
|
||||
uint32_t leaf_length; // 8
|
||||
uint64_t node_offset; // 16
|
||||
uint8_t node_depth; // 17
|
||||
uint8_t inner_length; // 18
|
||||
uint8_t reserved[14]; // 32
|
||||
uint8_t salt[BLAKE2B_SALTBYTES]; // 48
|
||||
uint8_t personal[BLAKE2B_PERSONALBYTES]; // 64
|
||||
} blake2b_param;
|
||||
|
||||
ALIGN( 64 ) typedef struct __blake2b_state
|
||||
{
|
||||
uint64_t h[8];
|
||||
uint64_t t[2];
|
||||
uint64_t f[2];
|
||||
uint8_t buf[2 * BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
uint8_t last_node;
|
||||
} blake2b_state;
|
||||
|
||||
ALIGN( 64 ) typedef struct __blake2sp_state
|
||||
{
|
||||
blake2s_state S[8][1];
|
||||
blake2s_state R[1];
|
||||
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
} blake2sp_state;
|
||||
|
||||
ALIGN( 64 ) typedef struct __blake2bp_state
|
||||
{
|
||||
blake2b_state S[4][1];
|
||||
blake2b_state R[1];
|
||||
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
|
||||
size_t buflen;
|
||||
} blake2bp_state;
|
||||
#pragma pack(pop)
|
||||
|
||||
// Streaming API
|
||||
int blake2s_init( blake2s_state *S, const uint8_t outlen );
|
||||
int blake2s_init_key( blake2s_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
|
||||
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
|
||||
int blake2s_update( blake2s_state *S, const uint8_t *in, uint64_t inlen );
|
||||
int blake2s_final( blake2s_state *S, uint8_t *out, uint8_t outlen );
|
||||
|
||||
int blake2b_init( blake2b_state *S, const uint8_t outlen );
|
||||
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
|
||||
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen );
|
||||
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen );
|
||||
|
||||
int blake2sp_init( blake2sp_state *S, const uint8_t outlen );
|
||||
int blake2sp_init_key( blake2sp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
|
||||
int blake2sp_update( blake2sp_state *S, const uint8_t *in, uint64_t inlen );
|
||||
int blake2sp_final( blake2sp_state *S, uint8_t *out, uint8_t outlen );
|
||||
|
||||
int blake2bp_init( blake2bp_state *S, const uint8_t outlen );
|
||||
int blake2bp_init_key( blake2bp_state *S, const uint8_t outlen, const void *key, const uint8_t keylen );
|
||||
int blake2bp_update( blake2bp_state *S, const uint8_t *in, uint64_t inlen );
|
||||
int blake2bp_final( blake2bp_state *S, uint8_t *out, uint8_t outlen );
|
||||
|
||||
// Simple API
|
||||
int blake2s( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
|
||||
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
|
||||
int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen);
|
||||
|
||||
int blake2sp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
|
||||
int blake2bp( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen );
|
||||
|
||||
static inline int blake2( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
|
||||
{
|
||||
return blake2b( out, in, key, outlen, inlen, keylen );
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
68
vendor/equihash/include/equihash/blake2b-load-sse2.h
vendored
Normal file
68
vendor/equihash/include/equihash/blake2b-load-sse2.h
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2B_LOAD_SSE2_H__
|
||||
#define __BLAKE2B_LOAD_SSE2_H__
|
||||
|
||||
#define LOAD_MSG_0_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4)
|
||||
#define LOAD_MSG_0_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5)
|
||||
#define LOAD_MSG_0_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12)
|
||||
#define LOAD_MSG_0_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13)
|
||||
#define LOAD_MSG_1_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9)
|
||||
#define LOAD_MSG_1_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15)
|
||||
#define LOAD_MSG_1_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11)
|
||||
#define LOAD_MSG_1_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7)
|
||||
#define LOAD_MSG_2_1(b0, b1) b0 = _mm_set_epi64x(m12, m11); b1 = _mm_set_epi64x(m15, m5)
|
||||
#define LOAD_MSG_2_2(b0, b1) b0 = _mm_set_epi64x(m0, m8); b1 = _mm_set_epi64x(m13, m2)
|
||||
#define LOAD_MSG_2_3(b0, b1) b0 = _mm_set_epi64x(m3, m10); b1 = _mm_set_epi64x(m9, m7)
|
||||
#define LOAD_MSG_2_4(b0, b1) b0 = _mm_set_epi64x(m6, m14); b1 = _mm_set_epi64x(m4, m1)
|
||||
#define LOAD_MSG_3_1(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m13)
|
||||
#define LOAD_MSG_3_2(b0, b1) b0 = _mm_set_epi64x(m1, m9); b1 = _mm_set_epi64x(m14, m12)
|
||||
#define LOAD_MSG_3_3(b0, b1) b0 = _mm_set_epi64x(m5, m2); b1 = _mm_set_epi64x(m15, m4)
|
||||
#define LOAD_MSG_3_4(b0, b1) b0 = _mm_set_epi64x(m10, m6); b1 = _mm_set_epi64x(m8, m0)
|
||||
#define LOAD_MSG_4_1(b0, b1) b0 = _mm_set_epi64x(m5, m9); b1 = _mm_set_epi64x(m10, m2)
|
||||
#define LOAD_MSG_4_2(b0, b1) b0 = _mm_set_epi64x(m7, m0); b1 = _mm_set_epi64x(m15, m4)
|
||||
#define LOAD_MSG_4_3(b0, b1) b0 = _mm_set_epi64x(m11, m14); b1 = _mm_set_epi64x(m3, m6)
|
||||
#define LOAD_MSG_4_4(b0, b1) b0 = _mm_set_epi64x(m12, m1); b1 = _mm_set_epi64x(m13, m8)
|
||||
#define LOAD_MSG_5_1(b0, b1) b0 = _mm_set_epi64x(m6, m2); b1 = _mm_set_epi64x(m8, m0)
|
||||
#define LOAD_MSG_5_2(b0, b1) b0 = _mm_set_epi64x(m10, m12); b1 = _mm_set_epi64x(m3, m11)
|
||||
#define LOAD_MSG_5_3(b0, b1) b0 = _mm_set_epi64x(m7, m4); b1 = _mm_set_epi64x(m1, m15)
|
||||
#define LOAD_MSG_5_4(b0, b1) b0 = _mm_set_epi64x(m5, m13); b1 = _mm_set_epi64x(m9, m14)
|
||||
#define LOAD_MSG_6_1(b0, b1) b0 = _mm_set_epi64x(m1, m12); b1 = _mm_set_epi64x(m4, m14)
|
||||
#define LOAD_MSG_6_2(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m10, m13)
|
||||
#define LOAD_MSG_6_3(b0, b1) b0 = _mm_set_epi64x(m6, m0); b1 = _mm_set_epi64x(m8, m9)
|
||||
#define LOAD_MSG_6_4(b0, b1) b0 = _mm_set_epi64x(m3, m7); b1 = _mm_set_epi64x(m11, m2)
|
||||
#define LOAD_MSG_7_1(b0, b1) b0 = _mm_set_epi64x(m7, m13); b1 = _mm_set_epi64x(m3, m12)
|
||||
#define LOAD_MSG_7_2(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m9, m1)
|
||||
#define LOAD_MSG_7_3(b0, b1) b0 = _mm_set_epi64x(m15, m5); b1 = _mm_set_epi64x(m2, m8)
|
||||
#define LOAD_MSG_7_4(b0, b1) b0 = _mm_set_epi64x(m4, m0); b1 = _mm_set_epi64x(m10, m6)
|
||||
#define LOAD_MSG_8_1(b0, b1) b0 = _mm_set_epi64x(m14, m6); b1 = _mm_set_epi64x(m0, m11)
|
||||
#define LOAD_MSG_8_2(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m8, m3)
|
||||
#define LOAD_MSG_8_3(b0, b1) b0 = _mm_set_epi64x(m13, m12); b1 = _mm_set_epi64x(m10, m1)
|
||||
#define LOAD_MSG_8_4(b0, b1) b0 = _mm_set_epi64x(m7, m2); b1 = _mm_set_epi64x(m5, m4)
|
||||
#define LOAD_MSG_9_1(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m1, m7)
|
||||
#define LOAD_MSG_9_2(b0, b1) b0 = _mm_set_epi64x(m4, m2); b1 = _mm_set_epi64x(m5, m6)
|
||||
#define LOAD_MSG_9_3(b0, b1) b0 = _mm_set_epi64x(m9, m15); b1 = _mm_set_epi64x(m13, m3)
|
||||
#define LOAD_MSG_9_4(b0, b1) b0 = _mm_set_epi64x(m14, m11); b1 = _mm_set_epi64x(m0, m12)
|
||||
#define LOAD_MSG_10_1(b0, b1) b0 = _mm_set_epi64x(m2, m0); b1 = _mm_set_epi64x(m6, m4)
|
||||
#define LOAD_MSG_10_2(b0, b1) b0 = _mm_set_epi64x(m3, m1); b1 = _mm_set_epi64x(m7, m5)
|
||||
#define LOAD_MSG_10_3(b0, b1) b0 = _mm_set_epi64x(m10, m8); b1 = _mm_set_epi64x(m14, m12)
|
||||
#define LOAD_MSG_10_4(b0, b1) b0 = _mm_set_epi64x(m11, m9); b1 = _mm_set_epi64x(m15, m13)
|
||||
#define LOAD_MSG_11_1(b0, b1) b0 = _mm_set_epi64x(m4, m14); b1 = _mm_set_epi64x(m13, m9)
|
||||
#define LOAD_MSG_11_2(b0, b1) b0 = _mm_set_epi64x(m8, m10); b1 = _mm_set_epi64x(m6, m15)
|
||||
#define LOAD_MSG_11_3(b0, b1) b0 = _mm_set_epi64x(m0, m1); b1 = _mm_set_epi64x(m5, m11)
|
||||
#define LOAD_MSG_11_4(b0, b1) b0 = _mm_set_epi64x(m2, m12); b1 = _mm_set_epi64x(m3, m7)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
402
vendor/equihash/include/equihash/blake2b-load-sse41.h
vendored
Normal file
402
vendor/equihash/include/equihash/blake2b-load-sse41.h
vendored
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2B_LOAD_SSE41_H__
|
||||
#define __BLAKE2B_LOAD_SSE41_H__
|
||||
|
||||
#define LOAD_MSG_0_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m0, m1); \
|
||||
b1 = _mm_unpacklo_epi64(m2, m3); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_0_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m0, m1); \
|
||||
b1 = _mm_unpackhi_epi64(m2, m3); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_0_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m4, m5); \
|
||||
b1 = _mm_unpacklo_epi64(m6, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_0_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m4, m5); \
|
||||
b1 = _mm_unpackhi_epi64(m6, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_1_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m7, m2); \
|
||||
b1 = _mm_unpackhi_epi64(m4, m6); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_1_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m5, m4); \
|
||||
b1 = _mm_alignr_epi8(m3, m7, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_1_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \
|
||||
b1 = _mm_unpackhi_epi64(m5, m2); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_1_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m6, m1); \
|
||||
b1 = _mm_unpackhi_epi64(m3, m1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_2_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_alignr_epi8(m6, m5, 8); \
|
||||
b1 = _mm_unpackhi_epi64(m2, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_2_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m4, m0); \
|
||||
b1 = _mm_blend_epi16(m1, m6, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_2_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m5, m1, 0xF0); \
|
||||
b1 = _mm_unpackhi_epi64(m3, m4); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_2_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m7, m3); \
|
||||
b1 = _mm_alignr_epi8(m2, m0, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_3_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m3, m1); \
|
||||
b1 = _mm_unpackhi_epi64(m6, m5); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_3_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m4, m0); \
|
||||
b1 = _mm_unpacklo_epi64(m6, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_3_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m1, m2, 0xF0); \
|
||||
b1 = _mm_blend_epi16(m2, m7, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_3_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m3, m5); \
|
||||
b1 = _mm_unpacklo_epi64(m0, m4); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_4_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m4, m2); \
|
||||
b1 = _mm_unpacklo_epi64(m1, m5); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_4_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m0, m3, 0xF0); \
|
||||
b1 = _mm_blend_epi16(m2, m7, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_4_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m7, m5, 0xF0); \
|
||||
b1 = _mm_blend_epi16(m3, m1, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_4_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_alignr_epi8(m6, m0, 8); \
|
||||
b1 = _mm_blend_epi16(m4, m6, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_5_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m1, m3); \
|
||||
b1 = _mm_unpacklo_epi64(m0, m4); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_5_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m6, m5); \
|
||||
b1 = _mm_unpackhi_epi64(m5, m1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_5_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m2, m3, 0xF0); \
|
||||
b1 = _mm_unpackhi_epi64(m7, m0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_5_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m6, m2); \
|
||||
b1 = _mm_blend_epi16(m7, m4, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_6_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m6, m0, 0xF0); \
|
||||
b1 = _mm_unpacklo_epi64(m7, m2); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_6_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m2, m7); \
|
||||
b1 = _mm_alignr_epi8(m5, m6, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_6_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m0, m3); \
|
||||
b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1,0,3,2)); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_6_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m3, m1); \
|
||||
b1 = _mm_blend_epi16(m1, m5, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_7_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m6, m3); \
|
||||
b1 = _mm_blend_epi16(m6, m1, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_7_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_alignr_epi8(m7, m5, 8); \
|
||||
b1 = _mm_unpackhi_epi64(m0, m4); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_7_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m2, m7); \
|
||||
b1 = _mm_unpacklo_epi64(m4, m1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_7_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m0, m2); \
|
||||
b1 = _mm_unpacklo_epi64(m3, m5); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_8_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m3, m7); \
|
||||
b1 = _mm_alignr_epi8(m0, m5, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_8_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m7, m4); \
|
||||
b1 = _mm_alignr_epi8(m4, m1, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_8_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = m6; \
|
||||
b1 = _mm_alignr_epi8(m5, m0, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_8_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_blend_epi16(m1, m3, 0xF0); \
|
||||
b1 = m2; \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_9_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m5, m4); \
|
||||
b1 = _mm_unpackhi_epi64(m3, m0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_9_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m1, m2); \
|
||||
b1 = _mm_blend_epi16(m3, m2, 0xF0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_9_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m7, m4); \
|
||||
b1 = _mm_unpackhi_epi64(m1, m6); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_9_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_alignr_epi8(m7, m5, 8); \
|
||||
b1 = _mm_unpacklo_epi64(m6, m0); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_10_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m0, m1); \
|
||||
b1 = _mm_unpacklo_epi64(m2, m3); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_10_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m0, m1); \
|
||||
b1 = _mm_unpackhi_epi64(m2, m3); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_10_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m4, m5); \
|
||||
b1 = _mm_unpacklo_epi64(m6, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_10_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpackhi_epi64(m4, m5); \
|
||||
b1 = _mm_unpackhi_epi64(m6, m7); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_11_1(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m7, m2); \
|
||||
b1 = _mm_unpackhi_epi64(m4, m6); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_11_2(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m5, m4); \
|
||||
b1 = _mm_alignr_epi8(m3, m7, 8); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_11_3(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1,0,3,2)); \
|
||||
b1 = _mm_unpackhi_epi64(m5, m2); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define LOAD_MSG_11_4(b0, b1) \
|
||||
do \
|
||||
{ \
|
||||
b0 = _mm_unpacklo_epi64(m6, m1); \
|
||||
b1 = _mm_unpackhi_epi64(m3, m1); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
170
vendor/equihash/include/equihash/blake2b-round.h
vendored
Normal file
170
vendor/equihash/include/equihash/blake2b-round.h
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef __BLAKE2B_ROUND_H__
|
||||
#define __BLAKE2B_ROUND_H__
|
||||
|
||||
#define LOAD(p) _mm_load_si128( (const __m128i *)(p) )
|
||||
#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
|
||||
|
||||
#define LOADU(p) _mm_loadu_si128( (const __m128i *)(p) )
|
||||
#define STOREU(p,r) _mm_storeu_si128((__m128i *)(p), r)
|
||||
|
||||
#define TOF(reg) _mm_castsi128_ps((reg))
|
||||
#define TOI(reg) _mm_castps_si128((reg))
|
||||
|
||||
#define LIKELY(x) __builtin_expect((x),1)
|
||||
|
||||
|
||||
/* Microarchitecture-specific macros */
|
||||
#ifndef HAVE_XOP
|
||||
#ifdef HAVE_SSSE3
|
||||
#define _mm_roti_epi64(x, c) \
|
||||
(-(c) == 32) ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2,3,0,1)) \
|
||||
: (-(c) == 24) ? _mm_shuffle_epi8((x), r24) \
|
||||
: (-(c) == 16) ? _mm_shuffle_epi8((x), r16) \
|
||||
: (-(c) == 63) ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_add_epi64((x), (x))) \
|
||||
: _mm_xor_si128(_mm_srli_epi64((x), -(c)), _mm_slli_epi64((x), 64-(-(c))))
|
||||
#else
|
||||
#define _mm_roti_epi64(r, c) _mm_xor_si128(_mm_srli_epi64( (r), -(c) ),_mm_slli_epi64( (r), 64-(-c) ))
|
||||
#endif
|
||||
#else
|
||||
/* ... */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \
|
||||
row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \
|
||||
row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \
|
||||
\
|
||||
row4l = _mm_xor_si128(row4l, row1l); \
|
||||
row4h = _mm_xor_si128(row4h, row1h); \
|
||||
\
|
||||
row4l = _mm_roti_epi64(row4l, -32); \
|
||||
row4h = _mm_roti_epi64(row4h, -32); \
|
||||
\
|
||||
row3l = _mm_add_epi64(row3l, row4l); \
|
||||
row3h = _mm_add_epi64(row3h, row4h); \
|
||||
\
|
||||
row2l = _mm_xor_si128(row2l, row3l); \
|
||||
row2h = _mm_xor_si128(row2h, row3h); \
|
||||
\
|
||||
row2l = _mm_roti_epi64(row2l, -24); \
|
||||
row2h = _mm_roti_epi64(row2h, -24); \
|
||||
|
||||
#define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \
|
||||
row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \
|
||||
row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \
|
||||
\
|
||||
row4l = _mm_xor_si128(row4l, row1l); \
|
||||
row4h = _mm_xor_si128(row4h, row1h); \
|
||||
\
|
||||
row4l = _mm_roti_epi64(row4l, -16); \
|
||||
row4h = _mm_roti_epi64(row4h, -16); \
|
||||
\
|
||||
row3l = _mm_add_epi64(row3l, row4l); \
|
||||
row3h = _mm_add_epi64(row3h, row4h); \
|
||||
\
|
||||
row2l = _mm_xor_si128(row2l, row3l); \
|
||||
row2h = _mm_xor_si128(row2h, row3h); \
|
||||
\
|
||||
row2l = _mm_roti_epi64(row2l, -63); \
|
||||
row2h = _mm_roti_epi64(row2h, -63); \
|
||||
|
||||
#if defined(HAVE_SSSE3)
|
||||
#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
|
||||
t0 = _mm_alignr_epi8(row2h, row2l, 8); \
|
||||
t1 = _mm_alignr_epi8(row2l, row2h, 8); \
|
||||
row2l = t0; \
|
||||
row2h = t1; \
|
||||
\
|
||||
t0 = row3l; \
|
||||
row3l = row3h; \
|
||||
row3h = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(row4h, row4l, 8); \
|
||||
t1 = _mm_alignr_epi8(row4l, row4h, 8); \
|
||||
row4l = t1; \
|
||||
row4h = t0;
|
||||
|
||||
#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
|
||||
t0 = _mm_alignr_epi8(row2l, row2h, 8); \
|
||||
t1 = _mm_alignr_epi8(row2h, row2l, 8); \
|
||||
row2l = t0; \
|
||||
row2h = t1; \
|
||||
\
|
||||
t0 = row3l; \
|
||||
row3l = row3h; \
|
||||
row3h = t0; \
|
||||
\
|
||||
t0 = _mm_alignr_epi8(row4l, row4h, 8); \
|
||||
t1 = _mm_alignr_epi8(row4h, row4l, 8); \
|
||||
row4l = t1; \
|
||||
row4h = t0;
|
||||
#else
|
||||
|
||||
#define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
|
||||
t0 = row4l;\
|
||||
t1 = row2l;\
|
||||
row4l = row3l;\
|
||||
row3l = row3h;\
|
||||
row3h = row4l;\
|
||||
row4l = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t0, t0)); \
|
||||
row4h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row4h, row4h)); \
|
||||
row2l = _mm_unpackhi_epi64(row2l, _mm_unpacklo_epi64(row2h, row2h)); \
|
||||
row2h = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(t1, t1))
|
||||
|
||||
#define UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
|
||||
t0 = row3l;\
|
||||
row3l = row3h;\
|
||||
row3h = t0;\
|
||||
t0 = row2l;\
|
||||
t1 = row4l;\
|
||||
row2l = _mm_unpackhi_epi64(row2h, _mm_unpacklo_epi64(row2l, row2l)); \
|
||||
row2h = _mm_unpackhi_epi64(t0, _mm_unpacklo_epi64(row2h, row2h)); \
|
||||
row4l = _mm_unpackhi_epi64(row4l, _mm_unpacklo_epi64(row4h, row4h)); \
|
||||
row4h = _mm_unpackhi_epi64(row4h, _mm_unpacklo_epi64(t1, t1))
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSE41)
|
||||
#include <equihash/blake2b-load-sse41.h>
|
||||
#else
|
||||
#include <equihash/blake2b-load-sse2.h>
|
||||
#endif
|
||||
|
||||
#define ROUND(r) \
|
||||
LOAD_MSG_ ##r ##_1(b0, b1); \
|
||||
G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
|
||||
LOAD_MSG_ ##r ##_2(b0, b1); \
|
||||
G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
|
||||
DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \
|
||||
LOAD_MSG_ ##r ##_3(b0, b1); \
|
||||
G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
|
||||
LOAD_MSG_ ##r ##_4(b0, b1); \
|
||||
G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \
|
||||
UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h);
|
||||
|
||||
#endif
|
||||
|
||||
#define BLAKE2_ROUND(row1l,row1h,row2l,row2h,row3l,row3h,row4l,row4h) \
|
||||
G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \
|
||||
G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \
|
||||
\
|
||||
DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \
|
||||
\
|
||||
G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \
|
||||
G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \
|
||||
\
|
||||
UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h);
|
||||
120
vendor/equihash/include/equihash/pow.hpp
vendored
Normal file
120
vendor/equihash/include/equihash/pow.hpp
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*Code by Dmitry Khovratovich, 2016
|
||||
CC0 license
|
||||
*/
|
||||
|
||||
#ifndef __POW
|
||||
#define __POW
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
const int SEED_LENGTH=4; //Length of seed in dwords ;
|
||||
const int NONCE_LENGTH=24; //Length of nonce in bytes;
|
||||
const int MAX_NONCE = 0xFFFFF;
|
||||
const int MAX_N = 32; //Max length of n in bytes, should not exceed 32
|
||||
const int LIST_LENGTH = 5;
|
||||
const unsigned FORK_MULTIPLIER=3; //Maximum collision factor
|
||||
|
||||
/* The block used to initialize the PoW search
|
||||
@v actual values
|
||||
*/
|
||||
namespace _POW{
|
||||
|
||||
struct Seed{
|
||||
std::vector<uint32_t> v;
|
||||
|
||||
Seed(){
|
||||
v.resize(SEED_LENGTH,0);
|
||||
}
|
||||
explicit Seed(uint32_t x){
|
||||
v.resize(SEED_LENGTH, x);
|
||||
}
|
||||
Seed(const Seed&r){
|
||||
v= r.v;
|
||||
}
|
||||
Seed& operator=(const Seed&r){
|
||||
v = r.v;
|
||||
return *this;
|
||||
}
|
||||
const uint32_t& operator[](unsigned i) const{ return v[i]; }
|
||||
};
|
||||
|
||||
/* Different nonces for PoW search
|
||||
@v actual values
|
||||
*/
|
||||
typedef uint32_t Nonce;
|
||||
typedef uint32_t Input;
|
||||
|
||||
/*Actual proof of work
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct Proof{
|
||||
const unsigned n;
|
||||
const unsigned k;
|
||||
const Seed seed;
|
||||
const Nonce nonce;
|
||||
const std::vector<Input> inputs;
|
||||
Proof(unsigned n_v, unsigned k_v, Seed I_v, Nonce V_v, std::vector<Input> inputs_v):
|
||||
n(n_v), k(k_v), seed(I_v), nonce(V_v), inputs(inputs_v){};
|
||||
Proof():n(0),k(1),seed(0),nonce(0),inputs(std::vector<Input>()) {};
|
||||
|
||||
bool Test();
|
||||
bool FullTest()const;
|
||||
bool CheckIndexesCanon()const;
|
||||
Proof CanonizeIndexes()const;
|
||||
};
|
||||
|
||||
class Tuple {
|
||||
public:
|
||||
std::vector<uint32_t> blocks;
|
||||
Input reference;
|
||||
Tuple(unsigned i) { blocks.resize(i); }
|
||||
Tuple& operator=(const Tuple &r) {
|
||||
blocks = r.blocks;
|
||||
reference = r.reference;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class Fork {
|
||||
public:
|
||||
Input ref1, ref2;
|
||||
Fork() {};
|
||||
Fork(Input r1, Input r2) : ref1(r1), ref2(r2) {};
|
||||
};
|
||||
|
||||
/*Algorithm class for creating proof
|
||||
Assumes that n/(k+1) <=32
|
||||
*
|
||||
*/
|
||||
class Equihash{
|
||||
std::vector<std::vector<Tuple>> tupleList;
|
||||
std::vector<unsigned> filledList;
|
||||
std::vector<Proof> solutions;
|
||||
std::vector<std::vector<Fork>> forks;
|
||||
unsigned n;
|
||||
unsigned k;
|
||||
Seed seed;
|
||||
Nonce nonce;
|
||||
public:
|
||||
/*
|
||||
Initializes memory.
|
||||
*/
|
||||
Equihash(unsigned n_in, unsigned k_in, Seed s) :n(n_in), k(k_in), seed(s) {};
|
||||
~Equihash() {};
|
||||
Proof FindProof();
|
||||
Proof FindProof( Nonce n );
|
||||
void FillMemory(uint32_t length); //fill with hash
|
||||
void InitializeMemory(); //allocate memory
|
||||
void ResolveCollisions(bool store);
|
||||
std::vector<Input> ResolveTree(Fork fork);
|
||||
std::vector<Input> ResolveTreeByLevel(Fork fork, unsigned level);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //define __POW
|
||||
469
vendor/equihash/src/blake2b.c
vendored
Normal file
469
vendor/equihash/src/blake2b.c
vendored
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
BLAKE2 reference source code package - optimized C implementations
|
||||
|
||||
Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
|
||||
You should have received a copy of the CC0 Public Domain Dedication along with
|
||||
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <equihash/blake2.h>
|
||||
#include <equihash/blake2-impl.h>
|
||||
|
||||
#include <equihash/blake2-config.h>
|
||||
|
||||
|
||||
#include <emmintrin.h>
|
||||
#if defined(HAVE_SSSE3)
|
||||
#include <tmmintrin.h>
|
||||
#endif
|
||||
#if defined(HAVE_SSE41)
|
||||
#include <smmintrin.h>
|
||||
#endif
|
||||
#if defined(HAVE_AVX)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
#if defined(HAVE_XOP)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#include <equihash/blake2b-round.h>
|
||||
|
||||
ALIGN( 64 ) static const uint64_t blake2b_IV[8] =
|
||||
{
|
||||
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
|
||||
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
|
||||
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
|
||||
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
|
||||
};
|
||||
|
||||
static const uint8_t blake2b_sigma[12][16] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
|
||||
};
|
||||
|
||||
|
||||
/* Some helper functions, not necessarily useful */
|
||||
static inline int blake2b_set_lastnode( blake2b_state *S )
|
||||
{
|
||||
S->f[1] = ~0ULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_clear_lastnode( blake2b_state *S )
|
||||
{
|
||||
S->f[1] = 0ULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_set_lastblock( blake2b_state *S )
|
||||
{
|
||||
if( S->last_node ) blake2b_set_lastnode( S );
|
||||
|
||||
S->f[0] = ~0ULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_clear_lastblock( blake2b_state *S )
|
||||
{
|
||||
if( S->last_node ) blake2b_clear_lastnode( S );
|
||||
|
||||
S->f[0] = 0ULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
|
||||
{
|
||||
#if __x86_64__
|
||||
// ADD/ADC chain
|
||||
__uint128_t t = ( ( __uint128_t )S->t[1] << 64 ) | S->t[0];
|
||||
t += inc;
|
||||
S->t[0] = ( uint64_t )( t >> 0 );
|
||||
S->t[1] = ( uint64_t )( t >> 64 );
|
||||
#else
|
||||
S->t[0] += inc;
|
||||
S->t[1] += ( S->t[0] < inc );
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Parameter-related functions
|
||||
static inline int blake2b_param_set_digest_length( blake2b_param *P, const uint8_t digest_length )
|
||||
{
|
||||
P->digest_length = digest_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_fanout( blake2b_param *P, const uint8_t fanout )
|
||||
{
|
||||
P->fanout = fanout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_max_depth( blake2b_param *P, const uint8_t depth )
|
||||
{
|
||||
P->depth = depth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_leaf_length( blake2b_param *P, const uint32_t leaf_length )
|
||||
{
|
||||
P->leaf_length = leaf_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_node_offset( blake2b_param *P, const uint64_t node_offset )
|
||||
{
|
||||
P->node_offset = node_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_node_depth( blake2b_param *P, const uint8_t node_depth )
|
||||
{
|
||||
P->node_depth = node_depth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_inner_length( blake2b_param *P, const uint8_t inner_length )
|
||||
{
|
||||
P->inner_length = inner_length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_salt( blake2b_param *P, const uint8_t salt[BLAKE2B_SALTBYTES] )
|
||||
{
|
||||
memcpy( P->salt, salt, BLAKE2B_SALTBYTES );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_param_set_personal( blake2b_param *P, const uint8_t personal[BLAKE2B_PERSONALBYTES] )
|
||||
{
|
||||
memcpy( P->personal, personal, BLAKE2B_PERSONALBYTES );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_init0( blake2b_state *S )
|
||||
{
|
||||
memset( S, 0, sizeof( blake2b_state ) );
|
||||
|
||||
for( int i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* init xors IV with input parameter block */
|
||||
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
|
||||
{
|
||||
//blake2b_init0( S );
|
||||
const uint8_t * v = ( const uint8_t * )( blake2b_IV );
|
||||
const uint8_t * p = ( const uint8_t * )( P );
|
||||
uint8_t * h = ( uint8_t * )( S->h );
|
||||
/* IV XOR ParamBlock */
|
||||
memset( S, 0, sizeof( blake2b_state ) );
|
||||
|
||||
for( int i = 0; i < BLAKE2B_OUTBYTES; ++i ) h[i] = v[i] ^ p[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Some sort of default parameter block initialization, for sequential blake2b */
|
||||
int blake2b_init( blake2b_state *S, const uint8_t outlen )
|
||||
{
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
const blake2b_param P =
|
||||
{
|
||||
outlen,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{0},
|
||||
{0},
|
||||
{0}
|
||||
};
|
||||
return blake2b_init_param( S, &P );
|
||||
}
|
||||
|
||||
int blake2b_init_key( blake2b_state *S, const uint8_t outlen, const void *key, const uint8_t keylen )
|
||||
{
|
||||
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
|
||||
|
||||
if ( ( !keylen ) || keylen > BLAKE2B_KEYBYTES ) return -1;
|
||||
|
||||
const blake2b_param P =
|
||||
{
|
||||
outlen,
|
||||
keylen,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{0},
|
||||
{0},
|
||||
{0}
|
||||
};
|
||||
|
||||
if( blake2b_init_param( S, &P ) < 0 )
|
||||
return 0;
|
||||
|
||||
{
|
||||
uint8_t block[BLAKE2B_BLOCKBYTES];
|
||||
memset( block, 0, BLAKE2B_BLOCKBYTES );
|
||||
memcpy( block, key, keylen );
|
||||
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
|
||||
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
|
||||
{
|
||||
__m128i row1l, row1h;
|
||||
__m128i row2l, row2h;
|
||||
__m128i row3l, row3h;
|
||||
__m128i row4l, row4h;
|
||||
__m128i b0, b1;
|
||||
__m128i t0, t1;
|
||||
#if defined(HAVE_SSSE3) && !defined(HAVE_XOP)
|
||||
const __m128i r16 = _mm_setr_epi8( 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9 );
|
||||
const __m128i r24 = _mm_setr_epi8( 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10 );
|
||||
#endif
|
||||
#if defined(HAVE_SSE41)
|
||||
const __m128i m0 = LOADU( block + 00 );
|
||||
const __m128i m1 = LOADU( block + 16 );
|
||||
const __m128i m2 = LOADU( block + 32 );
|
||||
const __m128i m3 = LOADU( block + 48 );
|
||||
const __m128i m4 = LOADU( block + 64 );
|
||||
const __m128i m5 = LOADU( block + 80 );
|
||||
const __m128i m6 = LOADU( block + 96 );
|
||||
const __m128i m7 = LOADU( block + 112 );
|
||||
#else
|
||||
const uint64_t m0 = ( ( uint64_t * )block )[ 0];
|
||||
const uint64_t m1 = ( ( uint64_t * )block )[ 1];
|
||||
const uint64_t m2 = ( ( uint64_t * )block )[ 2];
|
||||
const uint64_t m3 = ( ( uint64_t * )block )[ 3];
|
||||
const uint64_t m4 = ( ( uint64_t * )block )[ 4];
|
||||
const uint64_t m5 = ( ( uint64_t * )block )[ 5];
|
||||
const uint64_t m6 = ( ( uint64_t * )block )[ 6];
|
||||
const uint64_t m7 = ( ( uint64_t * )block )[ 7];
|
||||
const uint64_t m8 = ( ( uint64_t * )block )[ 8];
|
||||
const uint64_t m9 = ( ( uint64_t * )block )[ 9];
|
||||
const uint64_t m10 = ( ( uint64_t * )block )[10];
|
||||
const uint64_t m11 = ( ( uint64_t * )block )[11];
|
||||
const uint64_t m12 = ( ( uint64_t * )block )[12];
|
||||
const uint64_t m13 = ( ( uint64_t * )block )[13];
|
||||
const uint64_t m14 = ( ( uint64_t * )block )[14];
|
||||
const uint64_t m15 = ( ( uint64_t * )block )[15];
|
||||
#endif
|
||||
row1l = LOADU( &S->h[0] );
|
||||
row1h = LOADU( &S->h[2] );
|
||||
row2l = LOADU( &S->h[4] );
|
||||
row2h = LOADU( &S->h[6] );
|
||||
row3l = LOADU( &blake2b_IV[0] );
|
||||
row3h = LOADU( &blake2b_IV[2] );
|
||||
row4l = _mm_xor_si128( LOADU( &blake2b_IV[4] ), LOADU( &S->t[0] ) );
|
||||
row4h = _mm_xor_si128( LOADU( &blake2b_IV[6] ), LOADU( &S->f[0] ) );
|
||||
ROUND( 0 );
|
||||
ROUND( 1 );
|
||||
ROUND( 2 );
|
||||
ROUND( 3 );
|
||||
ROUND( 4 );
|
||||
ROUND( 5 );
|
||||
ROUND( 6 );
|
||||
ROUND( 7 );
|
||||
ROUND( 8 );
|
||||
ROUND( 9 );
|
||||
ROUND( 10 );
|
||||
ROUND( 11 );
|
||||
row1l = _mm_xor_si128( row3l, row1l );
|
||||
row1h = _mm_xor_si128( row3h, row1h );
|
||||
STOREU( &S->h[0], _mm_xor_si128( LOADU( &S->h[0] ), row1l ) );
|
||||
STOREU( &S->h[2], _mm_xor_si128( LOADU( &S->h[2] ), row1h ) );
|
||||
row2l = _mm_xor_si128( row4l, row2l );
|
||||
row2h = _mm_xor_si128( row4h, row2h );
|
||||
STOREU( &S->h[4], _mm_xor_si128( LOADU( &S->h[4] ), row2l ) );
|
||||
STOREU( &S->h[6], _mm_xor_si128( LOADU( &S->h[6] ), row2h ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int blake2b_update( blake2b_state *S, const uint8_t *in, uint64_t inlen )
|
||||
{
|
||||
while( inlen > 0 )
|
||||
{
|
||||
size_t left = S->buflen;
|
||||
size_t fill = 2 * BLAKE2B_BLOCKBYTES - left;
|
||||
|
||||
if( inlen > fill )
|
||||
{
|
||||
memcpy( S->buf + left, in, fill ); // Fill buffer
|
||||
S->buflen += fill;
|
||||
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
|
||||
blake2b_compress( S, S->buf ); // Compress
|
||||
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); // Shift buffer left
|
||||
S->buflen -= BLAKE2B_BLOCKBYTES;
|
||||
in += fill;
|
||||
inlen -= fill;
|
||||
}
|
||||
else // inlen <= fill
|
||||
{
|
||||
memcpy( S->buf + left, in, inlen );
|
||||
S->buflen += inlen; // Be lazy, do not compress
|
||||
in += inlen;
|
||||
inlen -= inlen;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int blake2b_final( blake2b_state *S, uint8_t *out, uint8_t outlen )
|
||||
{
|
||||
if( outlen > BLAKE2B_OUTBYTES )
|
||||
return -1;
|
||||
|
||||
if( S->buflen > BLAKE2B_BLOCKBYTES )
|
||||
{
|
||||
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
|
||||
blake2b_compress( S, S->buf );
|
||||
S->buflen -= BLAKE2B_BLOCKBYTES;
|
||||
memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen );
|
||||
}
|
||||
|
||||
blake2b_increment_counter( S, S->buflen );
|
||||
blake2b_set_lastblock( S );
|
||||
memset( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
|
||||
blake2b_compress( S, S->buf );
|
||||
memcpy( out, &S->h[0], outlen );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int blake2b( uint8_t *out, const void *in, const void *key, const uint8_t outlen, const uint64_t inlen, uint8_t keylen )
|
||||
{
|
||||
blake2b_state S[1];
|
||||
|
||||
/* Verify parameters */
|
||||
if ( NULL == in ) return -1;
|
||||
|
||||
if ( NULL == out ) return -1;
|
||||
|
||||
if( NULL == key ) keylen = 0;
|
||||
|
||||
if( keylen )
|
||||
{
|
||||
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( blake2b_init( S, outlen ) < 0 ) return -1;
|
||||
}
|
||||
|
||||
blake2b_update( S, ( const uint8_t * )in, inlen );
|
||||
blake2b_final( S, out, outlen );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SUPERCOP)
|
||||
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
|
||||
{
|
||||
return blake2b( out, in, NULL, BLAKE2B_OUTBYTES, inlen, 0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BLAKE2B_SELFTEST)
|
||||
#include <string.h>
|
||||
#include "blake2-kat.h"
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
uint8_t key[BLAKE2B_KEYBYTES];
|
||||
uint8_t buf[KAT_LENGTH];
|
||||
|
||||
for( size_t i = 0; i < BLAKE2B_KEYBYTES; ++i )
|
||||
key[i] = ( uint8_t )i;
|
||||
|
||||
for( size_t i = 0; i < KAT_LENGTH; ++i )
|
||||
buf[i] = ( uint8_t )i;
|
||||
|
||||
for( size_t i = 0; i < KAT_LENGTH; ++i )
|
||||
{
|
||||
uint8_t hash[BLAKE2B_OUTBYTES];
|
||||
blake2b( hash, buf, key, BLAKE2B_OUTBYTES, i, BLAKE2B_KEYBYTES );
|
||||
|
||||
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
|
||||
{
|
||||
puts( "error" );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
puts( "ok" );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int blake2b_long(uint8_t *out, const void *in, const uint32_t outlen, const uint64_t inlen)
|
||||
{
|
||||
blake2b_state blake_state;
|
||||
if (outlen <= BLAKE2B_OUTBYTES)
|
||||
{
|
||||
blake2b_init(&blake_state, outlen);
|
||||
blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t));
|
||||
blake2b_update(&blake_state, (const uint8_t *)in, inlen);
|
||||
blake2b_final(&blake_state, out, outlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t out_buffer[BLAKE2B_OUTBYTES];
|
||||
uint8_t in_buffer[BLAKE2B_OUTBYTES];
|
||||
blake2b_init(&blake_state, BLAKE2B_OUTBYTES);
|
||||
blake2b_update(&blake_state, (const uint8_t*)&outlen, sizeof(uint32_t));
|
||||
blake2b_update(&blake_state, (const uint8_t *)in, inlen);
|
||||
blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES);
|
||||
memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
|
||||
out += BLAKE2B_OUTBYTES / 2;
|
||||
uint32_t toproduce = outlen - BLAKE2B_OUTBYTES / 2;
|
||||
while (toproduce > BLAKE2B_OUTBYTES)
|
||||
{
|
||||
memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
|
||||
blake2b(out_buffer, in_buffer, NULL, BLAKE2B_OUTBYTES, BLAKE2B_OUTBYTES, 0);
|
||||
memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
|
||||
out += BLAKE2B_OUTBYTES / 2;
|
||||
toproduce -= BLAKE2B_OUTBYTES / 2;
|
||||
}
|
||||
memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
|
||||
blake2b(out_buffer, in_buffer, NULL, toproduce, BLAKE2B_OUTBYTES, 0);
|
||||
memcpy(out, out_buffer, toproduce);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
415
vendor/equihash/src/pow.cpp
vendored
Normal file
415
vendor/equihash/src/pow.cpp
vendored
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/*Code by Dmitry Khovratovich, 2016
|
||||
CC0 license
|
||||
|
||||
Modifications by Steemit, Inc. 2016
|
||||
*/
|
||||
|
||||
#include <equihash/pow.hpp>
|
||||
#include <equihash/blake2.h>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef EQUIHASH_POW_VERBOSE
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#define EQUIHASH_LOG(s) \
|
||||
std::cerr << s << std::endl;
|
||||
#else
|
||||
#define EQUIHASH_LOG(s)
|
||||
#endif
|
||||
|
||||
static uint64_t rdtsc(void) {
|
||||
#ifdef _MSC_VER
|
||||
return __rdtsc();
|
||||
#else
|
||||
#if defined(__amd64__) || defined(__x86_64__)
|
||||
uint64_t rax, rdx;
|
||||
__asm__ __volatile__("rdtsc" : "=a"(rax), "=d"(rdx) : : );
|
||||
return (rdx << 32) | rax;
|
||||
#elif defined(__i386__) || defined(__i386) || defined(__X86__)
|
||||
uint64_t rax;
|
||||
__asm__ __volatile__("rdtsc" : "=A"(rax) : : );
|
||||
return rax;
|
||||
#else
|
||||
#error "Not implemented!"
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
using namespace _POW;
|
||||
using namespace std;
|
||||
|
||||
void Equihash::InitializeMemory()
|
||||
{
|
||||
uint32_t tuple_n = ((uint32_t)1) << (n / (k + 1));
|
||||
Tuple default_tuple(k); // k blocks to store (one left for index)
|
||||
std::vector<Tuple> def_tuples(LIST_LENGTH, default_tuple);
|
||||
tupleList = std::vector<std::vector<Tuple>>(tuple_n, def_tuples);
|
||||
filledList= std::vector<unsigned>(tuple_n, 0);
|
||||
solutions.resize(0);
|
||||
forks.resize(0);
|
||||
}
|
||||
|
||||
void Equihash::FillMemory(uint32_t length) //works for k<=7
|
||||
{
|
||||
uint32_t input[SEED_LENGTH + 2];
|
||||
for (unsigned i = 0; i < SEED_LENGTH; ++i)
|
||||
input[i] = seed[i];
|
||||
input[SEED_LENGTH] = nonce;
|
||||
input[SEED_LENGTH + 1] = 0;
|
||||
uint32_t buf[MAX_N / 4];
|
||||
for (unsigned i = 0; i < length; ++i, ++input[SEED_LENGTH + 1]) {
|
||||
blake2b((uint8_t*)buf, &input, NULL, sizeof(buf), sizeof(input), 0);
|
||||
uint32_t index = buf[0] >> (32 - n / (k + 1));
|
||||
unsigned count = filledList[index];
|
||||
if (count < LIST_LENGTH) {
|
||||
for (unsigned j = 1; j < (k + 1); ++j) {
|
||||
//select j-th block of n/(k+1) bits
|
||||
tupleList[index][count].blocks[j - 1] = buf[j] >> (32 - n / (k + 1));
|
||||
}
|
||||
tupleList[index][count].reference = i;
|
||||
filledList[index]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Input> Equihash::ResolveTreeByLevel(Fork fork, unsigned level) {
|
||||
if (level == 0)
|
||||
return std::vector<Input>{fork.ref1, fork.ref2};
|
||||
auto v1 = ResolveTreeByLevel(forks[level - 1][fork.ref1], level - 1);
|
||||
auto v2 = ResolveTreeByLevel(forks[level - 1][fork.ref2], level - 1);
|
||||
v1.insert(v1.end(), v2.begin(), v2.end());
|
||||
return v1;
|
||||
}
|
||||
|
||||
std::vector<Input> Equihash::ResolveTree(Fork fork) {
|
||||
return ResolveTreeByLevel(fork, forks.size());
|
||||
}
|
||||
|
||||
|
||||
void Equihash::ResolveCollisions(bool store) {
|
||||
const unsigned tableLength = tupleList.size(); //number of rows in the hashtable
|
||||
const unsigned maxNewCollisions = tupleList.size()*FORK_MULTIPLIER; //max number of collisions to be found
|
||||
const unsigned newBlocks = tupleList[0][0].blocks.size() - 1;// number of blocks in the future collisions
|
||||
std::vector<Fork> newForks(maxNewCollisions); //list of forks created at this step
|
||||
auto tableRow = vector<Tuple>(LIST_LENGTH, Tuple(newBlocks)); //Row in the hash table
|
||||
vector<vector<Tuple>> collisionList(tableLength,tableRow);
|
||||
std::vector<unsigned> newFilledList(tableLength,0); //number of entries in rows
|
||||
uint32_t newColls = 0; //collision counter
|
||||
for (unsigned i = 0; i < tableLength; ++i) {
|
||||
for (unsigned j = 0; j < filledList[i]; ++j) {
|
||||
for (unsigned m = j + 1; m < filledList[i]; ++m) { //Collision
|
||||
//New index
|
||||
uint32_t newIndex = tupleList[i][j].blocks[0] ^ tupleList[i][m].blocks[0];
|
||||
Fork newFork = Fork(tupleList[i][j].reference, tupleList[i][m].reference);
|
||||
//Check if we get a solution
|
||||
if (store) { //last step
|
||||
if (newIndex == 0) {//Solution
|
||||
std::vector<Input> solution_inputs = ResolveTree(newFork);
|
||||
solutions.push_back(Proof(n, k, seed, nonce, solution_inputs));
|
||||
}
|
||||
}
|
||||
else { //Resolve
|
||||
if (newFilledList[newIndex] < LIST_LENGTH && newColls < maxNewCollisions) {
|
||||
for (unsigned l = 0; l < newBlocks; ++l) {
|
||||
collisionList[newIndex][newFilledList[newIndex]].blocks[l]
|
||||
= tupleList[i][j].blocks[l+1] ^ tupleList[i][m].blocks[l+1];
|
||||
}
|
||||
newForks[newColls] = newFork;
|
||||
collisionList[newIndex][newFilledList[newIndex]].reference = newColls;
|
||||
newFilledList[newIndex]++;
|
||||
newColls++;
|
||||
}//end of adding collision
|
||||
}
|
||||
}
|
||||
}//end of collision for i
|
||||
}
|
||||
forks.push_back(newForks);
|
||||
std::swap(tupleList, collisionList);
|
||||
std::swap(filledList, newFilledList);
|
||||
}
|
||||
|
||||
Proof Equihash::FindProof(){
|
||||
this->nonce = 1;
|
||||
while (nonce < MAX_NONCE) {
|
||||
nonce++;
|
||||
uint64_t start_cycles = rdtsc();
|
||||
InitializeMemory(); //allocate
|
||||
FillMemory(4UL << (n / (k + 1)-1)); //fill with hashes
|
||||
uint64_t fill_end = rdtsc();
|
||||
/*fp = fopen("proof.log", "a+");
|
||||
fprintf(fp, "\n===MEMORY FILLED:\n");
|
||||
PrintTuples(fp);
|
||||
fclose(fp);*/
|
||||
for (unsigned i = 1; i <= k; ++i) {
|
||||
uint64_t resolve_start = rdtsc();
|
||||
bool to_store = (i == k);
|
||||
ResolveCollisions(to_store); //XOR collisions, concatenate indices and shift
|
||||
uint64_t resolve_end = rdtsc();
|
||||
/* fp = fopen("proof.log", "a+");
|
||||
fprintf(fp, "\n===RESOLVED AFTER STEP %d:\n", i);
|
||||
PrintTuples(fp);
|
||||
fclose(fp);*/
|
||||
}
|
||||
uint64_t stop_cycles = rdtsc();
|
||||
|
||||
double mcycles_d = (double)(stop_cycles - start_cycles) / (1UL << 20);
|
||||
uint32_t kbytes = (tupleList.size()*LIST_LENGTH*k*sizeof(uint32_t)) / (1UL << 10);
|
||||
|
||||
//Duplicate check
|
||||
for (unsigned i = 0; i < solutions.size(); ++i) {
|
||||
auto vec = solutions[i].inputs;
|
||||
std::sort(vec.begin(), vec.end());
|
||||
bool dup = false;
|
||||
for (unsigned k = 0; k < vec.size() - 1; ++k) {
|
||||
if (vec[k] == vec[k + 1])
|
||||
dup = true;
|
||||
}
|
||||
if (!dup)
|
||||
{
|
||||
return solutions[i].CanonizeIndexes();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Proof(n, k, seed, nonce, std::vector<uint32_t>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Added by Steemit, Inc. for single iteration
|
||||
*/
|
||||
Proof Equihash::FindProof( Nonce _nonce )
|
||||
{
|
||||
this->nonce = _nonce;
|
||||
InitializeMemory(); //allocate
|
||||
FillMemory(4UL << (n / (k + 1)-1)); //fill with hashes
|
||||
|
||||
for (unsigned i = 1; i <= k; ++i) {
|
||||
bool to_store = (i == k);
|
||||
ResolveCollisions(to_store); //XOR collisions, concatenate indices and shift
|
||||
}
|
||||
|
||||
//Duplicate check
|
||||
for (unsigned i = 0; i < solutions.size(); ++i) {
|
||||
auto vec = solutions[i].inputs;
|
||||
std::sort(vec.begin(), vec.end());
|
||||
bool dup = false;
|
||||
for (unsigned k = 0; k < vec.size() - 1; ++k) {
|
||||
if (vec[k] == vec[k + 1])
|
||||
dup = true;
|
||||
}
|
||||
if (!dup)
|
||||
{
|
||||
return solutions[i].CanonizeIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
return Proof(n, k, seed, nonce, std::vector<uint32_t>());
|
||||
}
|
||||
|
||||
Proof Proof::CanonizeIndexes()const
|
||||
{
|
||||
// We consider the index values in the inputs array to be the leaf nodes of a binary
|
||||
// tree, and the inner nodes to be labelled with the XOR of the corresponding vector
|
||||
// elements.
|
||||
//
|
||||
// Define a binary tree to be canonically sorted if, for each inner node, the least
|
||||
// leaf descendant of the left child is less than the least leaf descendant of the
|
||||
// right child.
|
||||
//
|
||||
// This method puts the inputs into canonical order without altering the inner node
|
||||
// labels. Thus canonization preserves the validity of the proof and the
|
||||
// footprint of Wagner's algorithm.
|
||||
//
|
||||
// We use a bottom-up traversal, dividing the input into successively larger power-of-2
|
||||
// blocks and swapping the two half-blocks if non-canonical.
|
||||
//
|
||||
// Say a block is least-first if the least element is the first element.
|
||||
//
|
||||
// If each half-block is least-first, the conditional swap ensures the full block will also
|
||||
// be least-first. The half-blocks in the initial iteration are obviously least-first
|
||||
// (they only have a single element!). So by induction, at each later iteration the half-blocks
|
||||
// of that iteration are least-first (since they were the full blocks of the previous iteration,
|
||||
// which were made least-first by the previous iteration's conditional swap).
|
||||
//
|
||||
// As a consequence, no search is necessary to find the least element in each half-block,
|
||||
// it is always the first element in the half-block.
|
||||
|
||||
std::vector< uint32_t > new_inputs = inputs;
|
||||
|
||||
size_t input_size = inputs.size();
|
||||
size_t half_size = 1;
|
||||
size_t block_size = 2;
|
||||
while( block_size <= input_size )
|
||||
{
|
||||
for( size_t i=0; i+block_size<=input_size; i+=block_size )
|
||||
{
|
||||
auto ita = new_inputs.begin()+i, itb = ita+half_size;
|
||||
if( (*ita) >= (*itb) )
|
||||
{
|
||||
std::swap_ranges( ita, itb, itb );
|
||||
}
|
||||
}
|
||||
half_size = block_size;
|
||||
block_size += block_size;
|
||||
}
|
||||
return Proof(n, k, seed, nonce, new_inputs);
|
||||
}
|
||||
|
||||
bool Proof::CheckIndexesCanon()const
|
||||
{
|
||||
// This method is logically identical to CanonizeIndexes() but will return false
|
||||
// instead of swapping elements.
|
||||
|
||||
size_t input_size = inputs.size();
|
||||
size_t half_size = 1;
|
||||
size_t block_size = 2;
|
||||
while( block_size <= input_size )
|
||||
{
|
||||
for( size_t i=0; i+block_size<=input_size; i+=block_size )
|
||||
{
|
||||
auto ita = inputs.begin()+i, itb = ita+half_size;
|
||||
if( (*ita) >= (*itb) )
|
||||
return false;
|
||||
}
|
||||
half_size = block_size;
|
||||
block_size += block_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Proof::Test()
|
||||
{
|
||||
uint32_t input[SEED_LENGTH + 2];
|
||||
for (unsigned i = 0; i < SEED_LENGTH; ++i)
|
||||
input[i] = seed[i];
|
||||
input[SEED_LENGTH] = nonce;
|
||||
input[SEED_LENGTH + 1] = 0;
|
||||
uint32_t buf[MAX_N / 4];
|
||||
std::vector<uint32_t> blocks(k+1,0);
|
||||
for (unsigned i = 0; i < inputs.size(); ++i) {
|
||||
input[SEED_LENGTH + 1] = inputs[i];
|
||||
blake2b((uint8_t*)buf, &input, NULL, sizeof(buf), sizeof(input), 0);
|
||||
for (unsigned j = 0; j < (k + 1); ++j) {
|
||||
//select j-th block of n/(k+1) bits
|
||||
blocks[j] ^= buf[j] >> (32 - n / (k + 1));
|
||||
}
|
||||
}
|
||||
bool b = inputs.size() != 0;
|
||||
for (unsigned j = 0; j < (k + 1); ++j) {
|
||||
b &= (blocks[j] == 0);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
bool Proof::FullTest()const
|
||||
{
|
||||
// Length must be 2**k
|
||||
if( inputs.size() != size_t(1 << k) )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed length test" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure all values are distinct
|
||||
std::vector<Input> sorted_inputs = inputs;
|
||||
std::sort( sorted_inputs.begin(), sorted_inputs.end() );
|
||||
for( size_t i=1; i<inputs.size(); i++ )
|
||||
{
|
||||
if( sorted_inputs[i-1] >= sorted_inputs[i] )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed distinct test" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure all values are canonically indexed
|
||||
/*
|
||||
if( !CheckIndexesCanon() )
|
||||
return false;
|
||||
*/
|
||||
|
||||
// Initialize blocks array
|
||||
uint32_t input[SEED_LENGTH + 2];
|
||||
for( size_t i=0; i<SEED_LENGTH; i++ )
|
||||
input[i] = seed[i];
|
||||
input[SEED_LENGTH] = nonce;
|
||||
input[SEED_LENGTH + 1] = 0;
|
||||
uint32_t buf[MAX_N / 4];
|
||||
|
||||
std::vector< std::vector< uint32_t > > blocks;
|
||||
|
||||
const uint32_t max_input = uint32_t(1) << (n / (k + 1) + 1);
|
||||
|
||||
for( size_t i=0; i<inputs.size(); i++ )
|
||||
{
|
||||
input[SEED_LENGTH + 1] = inputs[i];
|
||||
if( inputs[i] >= max_input )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed max_input test" );
|
||||
return false;
|
||||
}
|
||||
|
||||
blake2b((uint8_t*)buf, &input, NULL, sizeof(buf), sizeof(input), 0);
|
||||
blocks.emplace_back();
|
||||
std::vector<uint32_t>& x = blocks.back();
|
||||
x.resize(k+1);
|
||||
for( size_t j=0; j<(k+1); j++ )
|
||||
{
|
||||
//select j-th block of n/(k+1) bits
|
||||
x[j] = buf[j] >> (32 - n / (k + 1));
|
||||
}
|
||||
}
|
||||
|
||||
while( true )
|
||||
{
|
||||
#ifdef EQUIHASH_POW_VERBOSE
|
||||
std::cerr << "\n\nBegin loop iteration\n";
|
||||
for( const std::vector< uint32_t >& x : blocks )
|
||||
{
|
||||
for( const uint32_t& e : x )
|
||||
std::cerr << std::hex << std::setw(5) << e << " ";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t count = blocks.size();
|
||||
if( count == 0 )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed with count == 0" );
|
||||
return false;
|
||||
}
|
||||
if( count == 1 )
|
||||
{
|
||||
if( blocks[0].size() != 1 )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed due to vector size" );
|
||||
return false;
|
||||
}
|
||||
if( blocks[0][0] != 0 )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed because final bits are not zero" );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if( (count&1) != 0 )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed with odd count" );
|
||||
return false;
|
||||
}
|
||||
for( size_t i=0,new_i=0; i<count; i+=2,new_i++ )
|
||||
{
|
||||
if( blocks[i][0] != blocks[i+1][0] )
|
||||
{
|
||||
EQUIHASH_LOG( "PoW failed because leading element of vector pair does not match" );
|
||||
return false;
|
||||
}
|
||||
for( size_t j=1; j<blocks[i].size(); j++ )
|
||||
blocks[new_i][j-1] = blocks[i][j] ^ blocks[i+1][j];
|
||||
blocks[new_i].resize(blocks[new_i].size()-1);
|
||||
}
|
||||
blocks.resize(blocks.size() >> 1);
|
||||
}
|
||||
}
|
||||
26
vendor/udt4/CMakeLists.txt
vendored
26
vendor/udt4/CMakeLists.txt
vendored
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
IF( APPLE )
|
||||
add_definitions( -DOSX )
|
||||
ELSEIF( WIN32 )
|
||||
|
||||
ELSE()
|
||||
add_definitions( -DLINUX )
|
||||
ENDIF()
|
||||
|
||||
set( udt_sources
|
||||
src/api.cpp
|
||||
src/buffer.cpp
|
||||
src/cache.cpp
|
||||
src/ccc.cpp
|
||||
src/channel.cpp
|
||||
src/common.cpp
|
||||
src/core.cpp
|
||||
src/epoll.cpp
|
||||
src/list.cpp
|
||||
src/md5.cpp
|
||||
src/packet.cpp
|
||||
src/queue.cpp
|
||||
src/window.cpp
|
||||
)
|
||||
|
||||
add_library( udt ${udt_sources} )
|
||||
32
vendor/udt4/LICENSE.txt
vendored
32
vendor/udt4/LICENSE.txt
vendored
|
|
@ -1,32 +0,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.
|
||||
43
vendor/udt4/README.txt
vendored
43
vendor/udt4/README.txt
vendored
|
|
@ -1,43 +0,0 @@
|
|||
Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
|
||||
All Rights Reserved.
|
||||
Copyright (c) 2011 - 2012, Google, Inc. All Rights Reserved.
|
||||
|
||||
UDP-based Data Transfer (UDT) Library - version 4
|
||||
Author: Yunhong Gu [yunhong.gu @ gmail.com]
|
||||
|
||||
UDT version 4 is free software under BSD License. See ./LICENSE.txt.
|
||||
|
||||
============================================================================
|
||||
|
||||
UDT Website:
|
||||
http://udt.sf.net
|
||||
http://sf.net/projects/udt/
|
||||
|
||||
|
||||
CONTENT:
|
||||
./src: UDT source code
|
||||
./app: Example programs
|
||||
./doc: UDT documentation (HTML)
|
||||
./win: Visual C++ project files for the Windows version of UDT
|
||||
|
||||
|
||||
To make:
|
||||
make -e os=XXX arch=YYY
|
||||
|
||||
XXX: [LINUX(default), BSD, OSX]
|
||||
YYY: [IA32(default), POWERPC, IA64, AMD64]
|
||||
|
||||
For example, on OS X, you may need to do "make -e os=OSX arch=POWERPC";
|
||||
on 32-bit i386 Linux system, simply use "make".
|
||||
|
||||
On Windows systems, use the Visual C++ project files in ./win directory.
|
||||
|
||||
Note for BSD users, please use GNU Make.
|
||||
|
||||
To use UDT in your application:
|
||||
Read index.htm in ./doc. The documentation is in HTML format and requires your
|
||||
browser to support JavaScript.
|
||||
|
||||
|
||||
Questions? please post to the UDT project forum:
|
||||
https://sourceforge.net/projects/udt/forums
|
||||
2392
vendor/udt4/src/api.cpp
vendored
2392
vendor/udt4/src/api.cpp
vendored
File diff suppressed because it is too large
Load diff
268
vendor/udt4/src/api.h
vendored
268
vendor/udt4/src/api.h
vendored
|
|
@ -1,268 +0,0 @@
|
|||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2010, 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 09/28/2010
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_API_H__
|
||||
#define __UDT_API_H__
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
#include "queue.h"
|
||||
#include "cache.h"
|
||||
#include "epoll.h"
|
||||
|
||||
class CUDT;
|
||||
|
||||
class CUDTSocket
|
||||
{
|
||||
public:
|
||||
CUDTSocket();
|
||||
~CUDTSocket();
|
||||
|
||||
UDTSTATUS m_Status; // current socket state
|
||||
|
||||
uint64_t m_TimeStamp; // time when the socket is closed
|
||||
|
||||
int m_iIPversion; // IP version
|
||||
sockaddr* m_pSelfAddr; // pointer to the local address of the socket
|
||||
sockaddr* m_pPeerAddr; // pointer to the peer address of the socket
|
||||
|
||||
UDTSOCKET m_SocketID; // socket ID
|
||||
UDTSOCKET m_ListenSocket; // ID of the listener socket; 0 means this is an independent socket
|
||||
|
||||
UDTSOCKET m_PeerID; // peer socket ID
|
||||
int32_t m_iISN; // initial sequence number, used to tell different connection from same IP:port
|
||||
|
||||
CUDT* m_pUDT; // pointer to the UDT entity
|
||||
|
||||
std::set<UDTSOCKET>* m_pQueuedSockets; // set of connections waiting for accept()
|
||||
std::set<UDTSOCKET>* m_pAcceptSockets; // set of accept()ed connections
|
||||
|
||||
pthread_cond_t m_AcceptCond; // used to block "accept" call
|
||||
pthread_mutex_t m_AcceptLock; // mutex associated to m_AcceptCond
|
||||
|
||||
unsigned int m_uiBackLog; // maximum number of connections in queue
|
||||
|
||||
int m_iMuxID; // multiplexer ID
|
||||
|
||||
pthread_mutex_t m_ControlLock; // lock this socket exclusively for control APIs: bind/listen/connect
|
||||
|
||||
private:
|
||||
CUDTSocket(const CUDTSocket&);
|
||||
CUDTSocket& operator=(const CUDTSocket&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CUDTUnited
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CRendezvousQueue;
|
||||
|
||||
public:
|
||||
CUDTUnited();
|
||||
~CUDTUnited();
|
||||
|
||||
public:
|
||||
|
||||
// Functionality:
|
||||
// initialize the UDT library.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise -1 is returned.
|
||||
|
||||
int startup();
|
||||
|
||||
// Functionality:
|
||||
// release the UDT library.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise -1 is returned.
|
||||
|
||||
int cleanup();
|
||||
|
||||
// Functionality:
|
||||
// Create a new UDT socket.
|
||||
// Parameters:
|
||||
// 0) [in] af: IP version, IPv4 (AF_INET) or IPv6 (AF_INET6).
|
||||
// 1) [in] type: socket type, SOCK_STREAM or SOCK_DGRAM
|
||||
// Returned value:
|
||||
// The new UDT socket ID, or INVALID_SOCK.
|
||||
|
||||
UDTSOCKET newSocket(int af, int type);
|
||||
|
||||
// Functionality:
|
||||
// Create a new UDT connection.
|
||||
// Parameters:
|
||||
// 0) [in] listen: the listening UDT socket;
|
||||
// 1) [in] peer: peer address.
|
||||
// 2) [in/out] hs: handshake information from peer side (in), negotiated value (out);
|
||||
// Returned value:
|
||||
// If the new connection is successfully created: 1 success, 0 already exist, -1 error.
|
||||
|
||||
int newConnection(const UDTSOCKET listen, const sockaddr* peer, CHandShake* hs);
|
||||
|
||||
// Functionality:
|
||||
// look up the UDT entity according to its ID.
|
||||
// Parameters:
|
||||
// 0) [in] u: the UDT socket ID.
|
||||
// Returned value:
|
||||
// Pointer to the UDT entity.
|
||||
|
||||
CUDT* lookup(const UDTSOCKET u);
|
||||
|
||||
// Functionality:
|
||||
// Check the status of the UDT socket.
|
||||
// Parameters:
|
||||
// 0) [in] u: the UDT socket ID.
|
||||
// Returned value:
|
||||
// UDT socket status, or NONEXIST if not found.
|
||||
|
||||
UDTSTATUS getStatus(const UDTSOCKET u);
|
||||
|
||||
// socket APIs
|
||||
|
||||
int bind(const UDTSOCKET u, const sockaddr* name, int namelen);
|
||||
int bind(const UDTSOCKET u, UDPSOCKET udpsock);
|
||||
int listen(const UDTSOCKET u, int backlog);
|
||||
UDTSOCKET accept(const UDTSOCKET listen, sockaddr* addr, int* addrlen);
|
||||
int connect(const UDTSOCKET u, const sockaddr* name, int namelen);
|
||||
int close(const UDTSOCKET u);
|
||||
int getpeername(const UDTSOCKET u, sockaddr* name, int* namelen);
|
||||
int getsockname(const UDTSOCKET u, sockaddr* name, int* namelen);
|
||||
int select(ud_set* readfds, ud_set* writefds, ud_set* exceptfds, const timeval* timeout);
|
||||
int selectEx(const std::vector<UDTSOCKET>& fds, std::vector<UDTSOCKET>* readfds, std::vector<UDTSOCKET>* writefds, std::vector<UDTSOCKET>* exceptfds, int64_t msTimeOut);
|
||||
int epoll_create();
|
||||
int epoll_add_usock(const int eid, const UDTSOCKET u, const int* events = NULL);
|
||||
int epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
int epoll_remove_usock(const int eid, const UDTSOCKET u);
|
||||
int epoll_remove_ssock(const int eid, const SYSSOCKET s);
|
||||
int epoll_wait(const int eid, std::set<UDTSOCKET>* readfds, std::set<UDTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds = NULL, std::set<SYSSOCKET>* lwfds = NULL);
|
||||
int epoll_release(const int eid);
|
||||
|
||||
// Functionality:
|
||||
// record the UDT exception.
|
||||
// Parameters:
|
||||
// 0) [in] e: pointer to a UDT exception instance.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setError(CUDTException* e);
|
||||
|
||||
// Functionality:
|
||||
// look up the most recent UDT exception.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// pointer to a UDT exception instance.
|
||||
|
||||
CUDTException* getError();
|
||||
|
||||
private:
|
||||
// void init();
|
||||
|
||||
private:
|
||||
std::map<UDTSOCKET, CUDTSocket*> m_Sockets; // stores all the socket structures
|
||||
|
||||
pthread_mutex_t m_ControlLock; // used to synchronize UDT API
|
||||
|
||||
pthread_mutex_t m_IDLock; // used to synchronize ID generation
|
||||
UDTSOCKET m_SocketID; // seed to generate a new unique socket ID
|
||||
|
||||
std::map<int64_t, std::set<UDTSOCKET> > m_PeerRec;// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn
|
||||
|
||||
private:
|
||||
pthread_key_t m_TLSError; // thread local error record (last error)
|
||||
#ifndef WIN32
|
||||
static void TLSDestroy(void* e) {if (NULL != e) delete (CUDTException*)e;}
|
||||
#else
|
||||
std::map<DWORD, CUDTException*> m_mTLSRecord;
|
||||
void checkTLSValue();
|
||||
pthread_mutex_t m_TLSLock;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void connect_complete(const UDTSOCKET u);
|
||||
CUDTSocket* locate(const UDTSOCKET u);
|
||||
CUDTSocket* locate(const sockaddr* peer, const UDTSOCKET id, int32_t isn);
|
||||
void updateMux(CUDTSocket* s, const sockaddr* addr = NULL, const UDPSOCKET* = NULL);
|
||||
void updateMux(CUDTSocket* s, const CUDTSocket* ls);
|
||||
|
||||
private:
|
||||
std::map<int, CMultiplexer> m_mMultiplexer; // UDP multiplexer
|
||||
pthread_mutex_t m_MultiplexerLock;
|
||||
|
||||
private:
|
||||
CCache<CInfoBlock>* m_pCache; // UDT network information cache
|
||||
|
||||
private:
|
||||
volatile bool m_bClosing;
|
||||
pthread_mutex_t m_GCStopLock;
|
||||
pthread_cond_t m_GCStopCond;
|
||||
|
||||
pthread_mutex_t m_InitLock;
|
||||
int m_iInstanceCount; // number of startup() called by application
|
||||
bool m_bGCStatus; // if the GC thread is working (true)
|
||||
|
||||
pthread_t m_GCThread;
|
||||
#ifndef WIN32
|
||||
static void* garbageCollect(void*);
|
||||
#else
|
||||
static DWORD WINAPI garbageCollect(LPVOID);
|
||||
#endif
|
||||
|
||||
std::map<UDTSOCKET, CUDTSocket*> m_ClosedSockets; // temporarily store closed sockets
|
||||
|
||||
void checkBrokenSockets();
|
||||
void removeSocket(const UDTSOCKET u);
|
||||
|
||||
private:
|
||||
CEPoll m_EPoll; // handling epoll data structures and events
|
||||
|
||||
private:
|
||||
CUDTUnited(const CUDTUnited&);
|
||||
CUDTUnited& operator=(const CUDTUnited&);
|
||||
};
|
||||
|
||||
#endif
|
||||
652
vendor/udt4/src/buffer.cpp
vendored
652
vendor/udt4/src/buffer.cpp
vendored
|
|
@ -1,652 +0,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
|
||||
*****************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "buffer.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CSndBuffer::CSndBuffer(int size, int mss):
|
||||
m_BufLock(),
|
||||
m_pBlock(NULL),
|
||||
m_pFirstBlock(NULL),
|
||||
m_pCurrBlock(NULL),
|
||||
m_pLastBlock(NULL),
|
||||
m_pBuffer(NULL),
|
||||
m_iNextMsgNo(1),
|
||||
m_iSize(size),
|
||||
m_iMSS(mss),
|
||||
m_iCount(0)
|
||||
{
|
||||
// initial physical buffer of "size"
|
||||
m_pBuffer = new Buffer;
|
||||
m_pBuffer->m_pcData = new char [m_iSize * m_iMSS];
|
||||
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;
|
||||
for (int i = 1; i < m_iSize; ++ i)
|
||||
{
|
||||
pb->m_pNext = new Block;
|
||||
pb->m_iMsgNo = 0;
|
||||
pb = pb->m_pNext;
|
||||
}
|
||||
pb->m_pNext = m_pBlock;
|
||||
|
||||
pb = m_pBlock;
|
||||
char* pc = m_pBuffer->m_pcData;
|
||||
for (int i = 0; i < m_iSize; ++ i)
|
||||
{
|
||||
pb->m_pcData = pc;
|
||||
pb = pb->m_pNext;
|
||||
pc += m_iMSS;
|
||||
}
|
||||
|
||||
m_pFirstBlock = m_pCurrBlock = m_pLastBlock = m_pBlock;
|
||||
|
||||
#ifndef WIN32
|
||||
pthread_mutex_init(&m_BufLock, NULL);
|
||||
#else
|
||||
m_BufLock = CreateMutex(NULL, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
pthread_mutex_destroy(&m_BufLock);
|
||||
#else
|
||||
CloseHandle(m_BufLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CSndBuffer::addBuffer(const char* data, int len, int ttl, bool order)
|
||||
{
|
||||
int size = len / m_iMSS;
|
||||
if ((len % m_iMSS) != 0)
|
||||
size ++;
|
||||
|
||||
// dynamically increase sender buffer
|
||||
while (size + m_iCount >= m_iSize)
|
||||
increase();
|
||||
|
||||
uint64_t time = CTimer::getTime();
|
||||
int32_t inorder = order;
|
||||
inorder <<= 29;
|
||||
|
||||
Block* s = m_pLastBlock;
|
||||
for (int i = 0; i < size; ++ i)
|
||||
{
|
||||
int pktlen = len - i * m_iMSS;
|
||||
if (pktlen > m_iMSS)
|
||||
pktlen = m_iMSS;
|
||||
|
||||
memcpy(s->m_pcData, data + i * m_iMSS, pktlen);
|
||||
s->m_iLength = pktlen;
|
||||
|
||||
s->m_iMsgNo = m_iNextMsgNo | inorder;
|
||||
if (i == 0)
|
||||
s->m_iMsgNo |= 0x80000000;
|
||||
if (i == size - 1)
|
||||
s->m_iMsgNo |= 0x40000000;
|
||||
|
||||
s->m_OriginTime = time;
|
||||
s->m_iTTL = ttl;
|
||||
|
||||
s = s->m_pNext;
|
||||
}
|
||||
m_pLastBlock = s;
|
||||
|
||||
CGuard::enterCS(m_BufLock);
|
||||
m_iCount += size;
|
||||
CGuard::leaveCS(m_BufLock);
|
||||
|
||||
m_iNextMsgNo ++;
|
||||
if (m_iNextMsgNo == CMsgNo::m_iMaxMsgNo)
|
||||
m_iNextMsgNo = 1;
|
||||
}
|
||||
|
||||
int CSndBuffer::addBufferFromFile(fstream& ifs, int len)
|
||||
{
|
||||
int size = len / m_iMSS;
|
||||
if ((len % m_iMSS) != 0)
|
||||
size ++;
|
||||
|
||||
// dynamically increase sender buffer
|
||||
while (size + m_iCount >= m_iSize)
|
||||
increase();
|
||||
|
||||
Block* s = m_pLastBlock;
|
||||
int total = 0;
|
||||
for (int i = 0; i < size; ++ i)
|
||||
{
|
||||
if (ifs.bad() || ifs.fail() || ifs.eof())
|
||||
break;
|
||||
|
||||
int pktlen = len - i * m_iMSS;
|
||||
if (pktlen > m_iMSS)
|
||||
pktlen = m_iMSS;
|
||||
|
||||
ifs.read(s->m_pcData, pktlen);
|
||||
if ((pktlen = ifs.gcount()) <= 0)
|
||||
break;
|
||||
|
||||
// currently file transfer is only available in streaming mode, message is always in order, ttl = infinite
|
||||
s->m_iMsgNo = m_iNextMsgNo | 0x20000000;
|
||||
if (i == 0)
|
||||
s->m_iMsgNo |= 0x80000000;
|
||||
if (i == size - 1)
|
||||
s->m_iMsgNo |= 0x40000000;
|
||||
|
||||
s->m_iLength = pktlen;
|
||||
s->m_iTTL = -1;
|
||||
s = s->m_pNext;
|
||||
|
||||
total += pktlen;
|
||||
}
|
||||
m_pLastBlock = s;
|
||||
|
||||
CGuard::enterCS(m_BufLock);
|
||||
m_iCount += size;
|
||||
CGuard::leaveCS(m_BufLock);
|
||||
|
||||
m_iNextMsgNo ++;
|
||||
if (m_iNextMsgNo == CMsgNo::m_iMaxMsgNo)
|
||||
m_iNextMsgNo = 1;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int CSndBuffer::readData(char** data, int32_t& msgno)
|
||||
{
|
||||
// No data to read
|
||||
if (m_pCurrBlock == m_pLastBlock)
|
||||
return 0;
|
||||
|
||||
*data = m_pCurrBlock->m_pcData;
|
||||
int readlen = m_pCurrBlock->m_iLength;
|
||||
msgno = m_pCurrBlock->m_iMsgNo;
|
||||
|
||||
m_pCurrBlock = m_pCurrBlock->m_pNext;
|
||||
|
||||
return readlen;
|
||||
}
|
||||
|
||||
int CSndBuffer::readData(char** data, const int offset, int32_t& msgno, int& msglen)
|
||||
{
|
||||
CGuard bufferguard(m_BufLock);
|
||||
|
||||
Block* p = m_pFirstBlock;
|
||||
|
||||
for (int i = 0; i < offset; ++ i)
|
||||
p = p->m_pNext;
|
||||
|
||||
if ((p->m_iTTL >= 0) && ((CTimer::getTime() - p->m_OriginTime) / 1000 > (uint64_t)p->m_iTTL))
|
||||
{
|
||||
msgno = p->m_iMsgNo & 0x1FFFFFFF;
|
||||
|
||||
msglen = 1;
|
||||
p = p->m_pNext;
|
||||
bool move = false;
|
||||
while (msgno == (p->m_iMsgNo & 0x1FFFFFFF))
|
||||
{
|
||||
if (p == m_pCurrBlock)
|
||||
move = true;
|
||||
p = p->m_pNext;
|
||||
if (move)
|
||||
m_pCurrBlock = p;
|
||||
msglen ++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
*data = p->m_pcData;
|
||||
int readlen = p->m_iLength;
|
||||
msgno = p->m_iMsgNo;
|
||||
|
||||
return readlen;
|
||||
}
|
||||
|
||||
void CSndBuffer::ackData(int offset)
|
||||
{
|
||||
CGuard bufferguard(m_BufLock);
|
||||
|
||||
for (int i = 0; i < offset; ++ i)
|
||||
m_pFirstBlock = m_pFirstBlock->m_pNext;
|
||||
|
||||
m_iCount -= offset;
|
||||
|
||||
CTimer::triggerEvent();
|
||||
}
|
||||
|
||||
int CSndBuffer::getCurrBufSize() const
|
||||
{
|
||||
return m_iCount;
|
||||
}
|
||||
|
||||
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_iMSS];
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete nbuf;
|
||||
throw CUDTException(3, 2, 0);
|
||||
}
|
||||
nbuf->m_iSize = unitsize;
|
||||
nbuf->m_pNext = NULL;
|
||||
|
||||
// insert the buffer at the end of the buffer list
|
||||
Buffer* p = m_pBuffer;
|
||||
while (NULL != p->m_pNext)
|
||||
p = p->m_pNext;
|
||||
p->m_pNext = nbuf;
|
||||
|
||||
// new packet blocks
|
||||
Block* nblk = NULL;
|
||||
try
|
||||
{
|
||||
nblk = new Block;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
delete nblk;
|
||||
throw CUDTException(3, 2, 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_iMSS;
|
||||
}
|
||||
|
||||
m_iSize += unitsize;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CRcvBuffer::CRcvBuffer(CUnitQueue* queue, int bufsize):
|
||||
m_pUnit(NULL),
|
||||
m_iSize(bufsize),
|
||||
m_pUnitQueue(queue),
|
||||
m_iStartPos(0),
|
||||
m_iLastAckPos(0),
|
||||
m_iMaxPos(0),
|
||||
m_iNotch(0)
|
||||
{
|
||||
m_pUnit = new CUnit* [m_iSize];
|
||||
for (int i = 0; i < m_iSize; ++ i)
|
||||
m_pUnit[i] = NULL;
|
||||
}
|
||||
|
||||
CRcvBuffer::~CRcvBuffer()
|
||||
{
|
||||
for (int i = 0; i < m_iSize; ++ i)
|
||||
{
|
||||
if (NULL != m_pUnit[i])
|
||||
{
|
||||
m_pUnit[i]->m_iFlag = 0;
|
||||
-- m_pUnitQueue->m_iCount;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] m_pUnit;
|
||||
}
|
||||
|
||||
int CRcvBuffer::addData(CUnit* unit, int offset)
|
||||
{
|
||||
int pos = (m_iLastAckPos + offset) % m_iSize;
|
||||
if (offset > m_iMaxPos)
|
||||
m_iMaxPos = offset;
|
||||
|
||||
if (NULL != m_pUnit[pos])
|
||||
return -1;
|
||||
|
||||
m_pUnit[pos] = unit;
|
||||
|
||||
unit->m_iFlag = 1;
|
||||
++ m_pUnitQueue->m_iCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CRcvBuffer::readBuffer(char* data, int len)
|
||||
{
|
||||
int p = m_iStartPos;
|
||||
int lastack = m_iLastAckPos;
|
||||
int rs = len;
|
||||
|
||||
while ((p != lastack) && (rs > 0))
|
||||
{
|
||||
int unitsize = m_pUnit[p]->m_Packet.getLength() - m_iNotch;
|
||||
if (unitsize > rs)
|
||||
unitsize = rs;
|
||||
|
||||
memcpy(data, m_pUnit[p]->m_Packet.m_pcData + m_iNotch, unitsize);
|
||||
data += unitsize;
|
||||
|
||||
if ((rs > unitsize) || (rs == m_pUnit[p]->m_Packet.getLength() - m_iNotch))
|
||||
{
|
||||
CUnit* tmp = m_pUnit[p];
|
||||
m_pUnit[p] = NULL;
|
||||
tmp->m_iFlag = 0;
|
||||
-- m_pUnitQueue->m_iCount;
|
||||
|
||||
if (++ p == m_iSize)
|
||||
p = 0;
|
||||
|
||||
m_iNotch = 0;
|
||||
}
|
||||
else
|
||||
m_iNotch += rs;
|
||||
|
||||
rs -= unitsize;
|
||||
}
|
||||
|
||||
m_iStartPos = p;
|
||||
return len - rs;
|
||||
}
|
||||
|
||||
int CRcvBuffer::readBufferToFile(fstream& ofs, int len)
|
||||
{
|
||||
int p = m_iStartPos;
|
||||
int lastack = m_iLastAckPos;
|
||||
int rs = len;
|
||||
|
||||
while ((p != lastack) && (rs > 0))
|
||||
{
|
||||
int unitsize = m_pUnit[p]->m_Packet.getLength() - m_iNotch;
|
||||
if (unitsize > rs)
|
||||
unitsize = rs;
|
||||
|
||||
ofs.write(m_pUnit[p]->m_Packet.m_pcData + m_iNotch, unitsize);
|
||||
if (ofs.fail())
|
||||
break;
|
||||
|
||||
if ((rs > unitsize) || (rs == m_pUnit[p]->m_Packet.getLength() - m_iNotch))
|
||||
{
|
||||
CUnit* tmp = m_pUnit[p];
|
||||
m_pUnit[p] = NULL;
|
||||
tmp->m_iFlag = 0;
|
||||
-- m_pUnitQueue->m_iCount;
|
||||
|
||||
if (++ p == m_iSize)
|
||||
p = 0;
|
||||
|
||||
m_iNotch = 0;
|
||||
}
|
||||
else
|
||||
m_iNotch += rs;
|
||||
|
||||
rs -= unitsize;
|
||||
}
|
||||
|
||||
m_iStartPos = p;
|
||||
|
||||
return len - rs;
|
||||
}
|
||||
|
||||
void CRcvBuffer::ackData(int len)
|
||||
{
|
||||
m_iLastAckPos = (m_iLastAckPos + len) % m_iSize;
|
||||
m_iMaxPos -= len;
|
||||
if (m_iMaxPos < 0)
|
||||
m_iMaxPos = 0;
|
||||
|
||||
CTimer::triggerEvent();
|
||||
}
|
||||
|
||||
int CRcvBuffer::getAvailBufSize() const
|
||||
{
|
||||
// One slot must be empty in order to tell the difference between "empty buffer" and "full buffer"
|
||||
return m_iSize - getRcvDataSize() - 1;
|
||||
}
|
||||
|
||||
int CRcvBuffer::getRcvDataSize() const
|
||||
{
|
||||
if (m_iLastAckPos >= m_iStartPos)
|
||||
return m_iLastAckPos - m_iStartPos;
|
||||
|
||||
return m_iSize + m_iLastAckPos - m_iStartPos;
|
||||
}
|
||||
|
||||
void CRcvBuffer::dropMsg(int32_t msgno)
|
||||
{
|
||||
for (int i = m_iStartPos, n = (m_iLastAckPos + m_iMaxPos) % m_iSize; i != n; i = (i + 1) % m_iSize)
|
||||
if ((NULL != m_pUnit[i]) && (msgno == m_pUnit[i]->m_Packet.m_iMsgNo))
|
||||
m_pUnit[i]->m_iFlag = 3;
|
||||
}
|
||||
|
||||
int CRcvBuffer::readMsg(char* data, int len)
|
||||
{
|
||||
int p, q;
|
||||
bool passack;
|
||||
if (!scanMsg(p, q, passack))
|
||||
return 0;
|
||||
|
||||
int rs = len;
|
||||
while (p != (q + 1) % m_iSize)
|
||||
{
|
||||
int unitsize = m_pUnit[p]->m_Packet.getLength();
|
||||
if ((rs >= 0) && (unitsize > rs))
|
||||
unitsize = rs;
|
||||
|
||||
if (unitsize > 0)
|
||||
{
|
||||
memcpy(data, m_pUnit[p]->m_Packet.m_pcData, unitsize);
|
||||
data += unitsize;
|
||||
rs -= unitsize;
|
||||
}
|
||||
|
||||
if (!passack)
|
||||
{
|
||||
CUnit* tmp = m_pUnit[p];
|
||||
m_pUnit[p] = NULL;
|
||||
tmp->m_iFlag = 0;
|
||||
-- m_pUnitQueue->m_iCount;
|
||||
}
|
||||
else
|
||||
m_pUnit[p]->m_iFlag = 2;
|
||||
|
||||
if (++ p == m_iSize)
|
||||
p = 0;
|
||||
}
|
||||
|
||||
if (!passack)
|
||||
m_iStartPos = (q + 1) % m_iSize;
|
||||
|
||||
return len - rs;
|
||||
}
|
||||
|
||||
int CRcvBuffer::getRcvMsgNum()
|
||||
{
|
||||
int p, q;
|
||||
bool passack;
|
||||
return scanMsg(p, q, passack) ? 1 : 0;
|
||||
}
|
||||
|
||||
bool CRcvBuffer::scanMsg(int& p, int& q, bool& passack)
|
||||
{
|
||||
// empty buffer
|
||||
if ((m_iStartPos == m_iLastAckPos) && (m_iMaxPos <= 0))
|
||||
return false;
|
||||
|
||||
//skip all bad msgs at the beginning
|
||||
while (m_iStartPos != m_iLastAckPos)
|
||||
{
|
||||
if (NULL == m_pUnit[m_iStartPos])
|
||||
{
|
||||
if (++ m_iStartPos == m_iSize)
|
||||
m_iStartPos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((1 == m_pUnit[m_iStartPos]->m_iFlag) && (m_pUnit[m_iStartPos]->m_Packet.getMsgBoundary() > 1))
|
||||
{
|
||||
bool good = true;
|
||||
|
||||
// look ahead for the whole message
|
||||
for (int i = m_iStartPos; i != m_iLastAckPos;)
|
||||
{
|
||||
if ((NULL == m_pUnit[i]) || (1 != m_pUnit[i]->m_iFlag))
|
||||
{
|
||||
good = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((m_pUnit[i]->m_Packet.getMsgBoundary() == 1) || (m_pUnit[i]->m_Packet.getMsgBoundary() == 3))
|
||||
break;
|
||||
|
||||
if (++ i == m_iSize)
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (good)
|
||||
break;
|
||||
}
|
||||
|
||||
CUnit* tmp = m_pUnit[m_iStartPos];
|
||||
m_pUnit[m_iStartPos] = NULL;
|
||||
tmp->m_iFlag = 0;
|
||||
-- m_pUnitQueue->m_iCount;
|
||||
|
||||
if (++ m_iStartPos == m_iSize)
|
||||
m_iStartPos = 0;
|
||||
}
|
||||
|
||||
p = -1; // message head
|
||||
q = m_iStartPos; // message tail
|
||||
passack = m_iStartPos == m_iLastAckPos;
|
||||
bool found = false;
|
||||
|
||||
// looking for the first message
|
||||
for (int i = 0, n = m_iMaxPos + getRcvDataSize(); i <= n; ++ i)
|
||||
{
|
||||
if ((NULL != m_pUnit[q]) && (1 == m_pUnit[q]->m_iFlag))
|
||||
{
|
||||
switch (m_pUnit[q]->m_Packet.getMsgBoundary())
|
||||
{
|
||||
case 3: // 11
|
||||
p = q;
|
||||
found = true;
|
||||
break;
|
||||
|
||||
case 2: // 10
|
||||
p = q;
|
||||
break;
|
||||
|
||||
case 1: // 01
|
||||
if (p != -1)
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// a hole in this message, not valid, restart search
|
||||
p = -1;
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
// the msg has to be ack'ed or it is allowed to read out of order, and was not read before
|
||||
if (!passack || !m_pUnit[q]->m_Packet.getMsgOrderFlag())
|
||||
break;
|
||||
|
||||
found = false;
|
||||
}
|
||||
|
||||
if (++ q == m_iSize)
|
||||
q = 0;
|
||||
|
||||
if (q == m_iLastAckPos)
|
||||
passack = true;
|
||||
}
|
||||
|
||||
// no msg found
|
||||
if (!found)
|
||||
{
|
||||
// if the message is larger than the receiver buffer, return part of the message
|
||||
if ((p != -1) && ((q + 1) % m_iSize == p))
|
||||
found = true;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
275
vendor/udt4/src/buffer.h
vendored
275
vendor/udt4/src/buffer.h
vendored
|
|
@ -1,275 +0,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
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_BUFFER_H__
|
||||
#define __UDT_BUFFER_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "list.h"
|
||||
#include "queue.h"
|
||||
#include <fstream>
|
||||
|
||||
class CSndBuffer
|
||||
{
|
||||
public:
|
||||
CSndBuffer(int size = 32, int mss = 1500);
|
||||
~CSndBuffer();
|
||||
|
||||
// Functionality:
|
||||
// Insert a user buffer into the sending list.
|
||||
// Parameters:
|
||||
// 0) [in] data: pointer to the user data block.
|
||||
// 1) [in] len: size of the block.
|
||||
// 2) [in] ttl: time to live in milliseconds
|
||||
// 3) [in] order: if the block should be delivered in order, for DGRAM only
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void addBuffer(const char* data, int len, int ttl = -1, bool order = false);
|
||||
|
||||
// Functionality:
|
||||
// Read a block of data from file and insert it into the sending list.
|
||||
// Parameters:
|
||||
// 0) [in] ifs: input file stream.
|
||||
// 1) [in] len: size of the block.
|
||||
// Returned value:
|
||||
// actual size of data added from the file.
|
||||
|
||||
int addBufferFromFile(std::fstream& ifs, int len);
|
||||
|
||||
// Functionality:
|
||||
// Find data position to pack a DATA packet from the furthest reading point.
|
||||
// Parameters:
|
||||
// 0) [out] data: the pointer to the data position.
|
||||
// 1) [out] msgno: message number of the packet.
|
||||
// Returned value:
|
||||
// Actual length of data read.
|
||||
|
||||
int readData(char** data, int32_t& msgno);
|
||||
|
||||
// Functionality:
|
||||
// Find data position to pack a DATA packet for a retransmission.
|
||||
// Parameters:
|
||||
// 0) [out] data: the pointer to the data position.
|
||||
// 1) [in] offset: offset from the last ACK point.
|
||||
// 2) [out] msgno: message number of the packet.
|
||||
// 3) [out] msglen: length of the message
|
||||
// Returned value:
|
||||
// Actual length of data read.
|
||||
|
||||
int readData(char** data, const int offset, int32_t& msgno, int& msglen);
|
||||
|
||||
// Functionality:
|
||||
// Update the ACK point and may release/unmap/return the user data according to the flag.
|
||||
// Parameters:
|
||||
// 0) [in] offset: number of packets acknowledged.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void ackData(int offset);
|
||||
|
||||
// Functionality:
|
||||
// Read size of data still in the sending list.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// Current size of the data in the sending list.
|
||||
|
||||
int getCurrBufSize() const;
|
||||
|
||||
private:
|
||||
void increase();
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_BufLock; // used to synchronize buffer operation
|
||||
|
||||
struct Block
|
||||
{
|
||||
char* m_pcData; // pointer to the data block
|
||||
int m_iLength; // length of the block
|
||||
|
||||
int32_t m_iMsgNo; // message number
|
||||
uint64_t m_OriginTime; // original request time
|
||||
int m_iTTL; // time to live (milliseconds)
|
||||
|
||||
Block* m_pNext; // next block
|
||||
} *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)
|
||||
int m_iMSS; // maximum seqment/packet size
|
||||
|
||||
int m_iCount; // number of used blocks
|
||||
|
||||
private:
|
||||
CSndBuffer(const CSndBuffer&);
|
||||
CSndBuffer& operator=(const CSndBuffer&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CRcvBuffer
|
||||
{
|
||||
public:
|
||||
CRcvBuffer(CUnitQueue* queue, int bufsize = 65536);
|
||||
~CRcvBuffer();
|
||||
|
||||
// Functionality:
|
||||
// Write data into the buffer.
|
||||
// Parameters:
|
||||
// 0) [in] unit: pointer to a data unit containing new packet
|
||||
// 1) [in] offset: offset from last ACK point.
|
||||
// Returned value:
|
||||
// 0 is success, -1 if data is repeated.
|
||||
|
||||
int addData(CUnit* unit, int offset);
|
||||
|
||||
// Functionality:
|
||||
// Read data into a user buffer.
|
||||
// Parameters:
|
||||
// 0) [in] data: pointer to user buffer.
|
||||
// 1) [in] len: length of user buffer.
|
||||
// Returned value:
|
||||
// size of data read.
|
||||
|
||||
int readBuffer(char* data, int len);
|
||||
|
||||
// Functionality:
|
||||
// Read data directly into file.
|
||||
// Parameters:
|
||||
// 0) [in] file: C++ file stream.
|
||||
// 1) [in] len: expected length of data to write into the file.
|
||||
// Returned value:
|
||||
// size of data read.
|
||||
|
||||
int readBufferToFile(std::fstream& ofs, int len);
|
||||
|
||||
// Functionality:
|
||||
// Update the ACK point of the buffer.
|
||||
// Parameters:
|
||||
// 0) [in] len: size of data to be acknowledged.
|
||||
// Returned value:
|
||||
// 1 if a user buffer is fulfilled, otherwise 0.
|
||||
|
||||
void ackData(int len);
|
||||
|
||||
// Functionality:
|
||||
// Query how many buffer space left for data receiving.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// size of available buffer space (including user buffer) for data receiving.
|
||||
|
||||
int getAvailBufSize() const;
|
||||
|
||||
// Functionality:
|
||||
// Query how many data has been continuously received (for reading).
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// size of valid (continous) data for reading.
|
||||
|
||||
int getRcvDataSize() const;
|
||||
|
||||
// Functionality:
|
||||
// mark the message to be dropped from the message list.
|
||||
// Parameters:
|
||||
// 0) [in] msgno: message nuumer.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void dropMsg(int32_t msgno);
|
||||
|
||||
// Functionality:
|
||||
// read a message.
|
||||
// Parameters:
|
||||
// 0) [out] data: buffer to write the message into.
|
||||
// 1) [in] len: size of the buffer.
|
||||
// Returned value:
|
||||
// actuall size of data read.
|
||||
|
||||
int readMsg(char* data, int len);
|
||||
|
||||
// Functionality:
|
||||
// Query how many messages are available now.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// number of messages available for recvmsg.
|
||||
|
||||
int getRcvMsgNum();
|
||||
|
||||
private:
|
||||
bool scanMsg(int& start, int& end, bool& passack);
|
||||
|
||||
private:
|
||||
CUnit** m_pUnit; // pointer to the protocol buffer
|
||||
int m_iSize; // size of the protocol buffer
|
||||
CUnitQueue* m_pUnitQueue; // the shared unit queue
|
||||
|
||||
int m_iStartPos; // the head position for I/O (inclusive)
|
||||
int m_iLastAckPos; // the last ACKed position (exclusive)
|
||||
// EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1
|
||||
int m_iMaxPos; // the furthest data position
|
||||
|
||||
int m_iNotch; // the starting read point of the first unit
|
||||
|
||||
private:
|
||||
CRcvBuffer();
|
||||
CRcvBuffer(const CRcvBuffer&);
|
||||
CRcvBuffer& operator=(const CRcvBuffer&);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
123
vendor/udt4/src/cache.cpp
vendored
123
vendor/udt4/src/cache.cpp
vendored
|
|
@ -1,123 +0,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
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#ifdef LEGACY_WIN32
|
||||
#include <wspiapi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include "cache.h"
|
||||
#include "core.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CInfoBlock& CInfoBlock::operator=(const CInfoBlock& obj)
|
||||
{
|
||||
std::copy(obj.m_piIP, obj.m_piIP + 3, m_piIP);
|
||||
m_iIPversion = obj.m_iIPversion;
|
||||
m_ullTimeStamp = obj.m_ullTimeStamp;
|
||||
m_iRTT = obj.m_iRTT;
|
||||
m_iBandwidth = obj.m_iBandwidth;
|
||||
m_iLossRate = obj.m_iLossRate;
|
||||
m_iReorderDistance = obj.m_iReorderDistance;
|
||||
m_dInterval = obj.m_dInterval;
|
||||
m_dCWnd = obj.m_dCWnd;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CInfoBlock::operator==(const CInfoBlock& obj)
|
||||
{
|
||||
if (m_iIPversion != obj.m_iIPversion)
|
||||
return false;
|
||||
|
||||
else if (m_iIPversion == AF_INET)
|
||||
return (m_piIP[0] == obj.m_piIP[0]);
|
||||
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
{
|
||||
if (m_piIP[i] != obj.m_piIP[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CInfoBlock* CInfoBlock::clone()
|
||||
{
|
||||
CInfoBlock* obj = new CInfoBlock;
|
||||
|
||||
std::copy(m_piIP, m_piIP + 3, obj->m_piIP);
|
||||
obj->m_iIPversion = m_iIPversion;
|
||||
obj->m_ullTimeStamp = m_ullTimeStamp;
|
||||
obj->m_iRTT = m_iRTT;
|
||||
obj->m_iBandwidth = m_iBandwidth;
|
||||
obj->m_iLossRate = m_iLossRate;
|
||||
obj->m_iReorderDistance = m_iReorderDistance;
|
||||
obj->m_dInterval = m_dInterval;
|
||||
obj->m_dCWnd = m_dCWnd;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
int CInfoBlock::getKey()
|
||||
{
|
||||
if (m_iIPversion == AF_INET)
|
||||
return m_piIP[0];
|
||||
|
||||
return m_piIP[0] + m_piIP[1] + m_piIP[2] + m_piIP[3];
|
||||
}
|
||||
|
||||
void CInfoBlock::convert(const sockaddr* addr, int ver, uint32_t ip[])
|
||||
{
|
||||
if (ver == AF_INET)
|
||||
{
|
||||
ip[0] = ((sockaddr_in*)addr)->sin_addr.s_addr;
|
||||
ip[1] = ip[2] = ip[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((char*)ip, (char*)((sockaddr_in6*)addr)->sin6_addr.s6_addr, 16);
|
||||
}
|
||||
}
|
||||
293
vendor/udt4/src/cache.h
vendored
293
vendor/udt4/src/cache.h
vendored
|
|
@ -1,293 +0,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 01/27/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_CACHE_H__
|
||||
#define __UDT_CACHE_H__
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
#include "udt.h"
|
||||
|
||||
class CCacheItem
|
||||
{
|
||||
public:
|
||||
virtual ~CCacheItem() {}
|
||||
|
||||
public:
|
||||
virtual CCacheItem& operator=(const CCacheItem&) = 0;
|
||||
|
||||
// The "==" operator SHOULD only compare key values.
|
||||
virtual bool operator==(const CCacheItem&) = 0;
|
||||
|
||||
// Functionality:
|
||||
// get a deep copy clone of the current item
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// Pointer to the new item, or NULL if failed.
|
||||
|
||||
virtual CCacheItem* clone() = 0;
|
||||
|
||||
// Functionality:
|
||||
// get a random key value between 0 and MAX_INT to be used for the hash in cache
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// A random hash key.
|
||||
|
||||
virtual int getKey() = 0;
|
||||
|
||||
// If there is any shared resources between the cache item and its clone,
|
||||
// the shared resource should be released by this function.
|
||||
virtual void release() {}
|
||||
};
|
||||
|
||||
template<typename T> class CCache
|
||||
{
|
||||
public:
|
||||
CCache(int size = 1024):
|
||||
m_iMaxSize(size),
|
||||
m_iHashSize(size * 3),
|
||||
m_iCurrSize(0)
|
||||
{
|
||||
m_vHashPtr.resize(m_iHashSize);
|
||||
CGuard::createMutex(m_Lock);
|
||||
}
|
||||
|
||||
~CCache()
|
||||
{
|
||||
clear();
|
||||
CGuard::releaseMutex(m_Lock);
|
||||
}
|
||||
|
||||
public:
|
||||
// Functionality:
|
||||
// find the matching item in the cache.
|
||||
// Parameters:
|
||||
// 0) [in/out] data: storage for the retrieved item; initially it must carry the key information
|
||||
// Returned value:
|
||||
// 0 if found a match, otherwise -1.
|
||||
|
||||
int lookup(T* data)
|
||||
{
|
||||
CGuard cacheguard(m_Lock);
|
||||
|
||||
int key = data->getKey();
|
||||
if (key < 0)
|
||||
return -1;
|
||||
if (key >= m_iMaxSize)
|
||||
key %= m_iHashSize;
|
||||
|
||||
const ItemPtrList& item_list = m_vHashPtr[key];
|
||||
for (typename ItemPtrList::const_iterator i = item_list.begin(); i != item_list.end(); ++ i)
|
||||
{
|
||||
if (*data == ***i)
|
||||
{
|
||||
// copy the cached info
|
||||
*data = ***i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Functionality:
|
||||
// update an item in the cache, or insert one if it doesn't exist; oldest item may be removed
|
||||
// Parameters:
|
||||
// 0) [in] data: the new item to updated/inserted to the cache
|
||||
// Returned value:
|
||||
// 0 if success, otherwise -1.
|
||||
|
||||
int update(T* data)
|
||||
{
|
||||
CGuard cacheguard(m_Lock);
|
||||
|
||||
int key = data->getKey();
|
||||
if (key < 0)
|
||||
return -1;
|
||||
if (key >= m_iMaxSize)
|
||||
key %= m_iHashSize;
|
||||
|
||||
T* curr = NULL;
|
||||
|
||||
ItemPtrList& item_list = m_vHashPtr[key];
|
||||
for (typename ItemPtrList::iterator i = item_list.begin(); i != item_list.end(); ++ i)
|
||||
{
|
||||
if (*data == ***i)
|
||||
{
|
||||
// update the existing entry with the new value
|
||||
***i = *data;
|
||||
curr = **i;
|
||||
|
||||
// remove the current entry
|
||||
m_StorageList.erase(*i);
|
||||
item_list.erase(i);
|
||||
|
||||
// re-insert to the front
|
||||
m_StorageList.push_front(curr);
|
||||
item_list.push_front(m_StorageList.begin());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// create new entry and insert to front
|
||||
curr = data->clone();
|
||||
m_StorageList.push_front(curr);
|
||||
item_list.push_front(m_StorageList.begin());
|
||||
|
||||
++ m_iCurrSize;
|
||||
if (m_iCurrSize >= m_iMaxSize)
|
||||
{
|
||||
// Cache overflow, remove oldest entry.
|
||||
T* last_data = m_StorageList.back();
|
||||
int last_key = last_data->getKey() % m_iHashSize;
|
||||
|
||||
item_list = m_vHashPtr[last_key];
|
||||
for (typename ItemPtrList::iterator i = item_list.begin(); i != item_list.end(); ++ i)
|
||||
{
|
||||
if (*last_data == ***i)
|
||||
{
|
||||
item_list.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
last_data->release();
|
||||
delete last_data;
|
||||
m_StorageList.pop_back();
|
||||
-- m_iCurrSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Functionality:
|
||||
// Specify the cache size (i.e., max number of items).
|
||||
// Parameters:
|
||||
// 0) [in] size: max cache size.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setSizeLimit(int size)
|
||||
{
|
||||
m_iMaxSize = size;
|
||||
m_iHashSize = size * 3;
|
||||
m_vHashPtr.resize(m_iHashSize);
|
||||
}
|
||||
|
||||
// Functionality:
|
||||
// Clear all entries in the cache, restore to initialization state.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (typename std::list<T*>::iterator i = m_StorageList.begin(); i != m_StorageList.end(); ++ i)
|
||||
{
|
||||
(*i)->release();
|
||||
delete *i;
|
||||
}
|
||||
m_StorageList.clear();
|
||||
for (typename std::vector<ItemPtrList>::iterator i = m_vHashPtr.begin(); i != m_vHashPtr.end(); ++ i)
|
||||
i->clear();
|
||||
m_iCurrSize = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<T*> m_StorageList;
|
||||
typedef typename std::list<T*>::iterator ItemPtr;
|
||||
typedef std::list<ItemPtr> ItemPtrList;
|
||||
std::vector<ItemPtrList> m_vHashPtr;
|
||||
|
||||
int m_iMaxSize;
|
||||
int m_iHashSize;
|
||||
int m_iCurrSize;
|
||||
|
||||
pthread_mutex_t m_Lock;
|
||||
|
||||
private:
|
||||
CCache(const CCache&);
|
||||
CCache& operator=(const CCache&);
|
||||
};
|
||||
|
||||
|
||||
class CInfoBlock
|
||||
{
|
||||
public:
|
||||
uint32_t m_piIP[4]; // IP address, machine read only, not human readable format
|
||||
int m_iIPversion; // IP version
|
||||
uint64_t m_ullTimeStamp; // last update time
|
||||
int m_iRTT; // RTT
|
||||
int m_iBandwidth; // estimated bandwidth
|
||||
int m_iLossRate; // average loss rate
|
||||
int m_iReorderDistance; // packet reordering distance
|
||||
double m_dInterval; // inter-packet time, congestion control
|
||||
double m_dCWnd; // congestion window size, congestion control
|
||||
|
||||
public:
|
||||
virtual ~CInfoBlock() {}
|
||||
virtual CInfoBlock& operator=(const CInfoBlock& obj);
|
||||
virtual bool operator==(const CInfoBlock& obj);
|
||||
virtual CInfoBlock* clone();
|
||||
virtual int getKey();
|
||||
virtual void release() {}
|
||||
|
||||
public:
|
||||
|
||||
// Functionality:
|
||||
// convert sockaddr structure to an integer array
|
||||
// Parameters:
|
||||
// 0) [in] addr: network address
|
||||
// 1) [in] ver: IP version
|
||||
// 2) [out] ip: the result machine readable IP address in integer array
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
static void convert(const sockaddr* addr, int ver, uint32_t ip[]);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
314
vendor/udt4/src/ccc.cpp
vendored
314
vendor/udt4/src/ccc.cpp
vendored
|
|
@ -1,314 +0,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 02/21/2013
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include "core.h"
|
||||
#include "ccc.h"
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
CCC::CCC():
|
||||
m_iSYNInterval(CUDT::m_iSYNInterval),
|
||||
m_dPktSndPeriod(1.0),
|
||||
m_dCWndSize(16.0),
|
||||
m_iBandwidth(),
|
||||
m_dMaxCWndSize(),
|
||||
m_iMSS(),
|
||||
m_iSndCurrSeqNo(),
|
||||
m_iRcvRate(),
|
||||
m_iRTT(),
|
||||
m_pcParam(NULL),
|
||||
m_iPSize(0),
|
||||
m_UDT(),
|
||||
m_iACKPeriod(0),
|
||||
m_iACKInterval(0),
|
||||
m_bUserDefinedRTO(false),
|
||||
m_iRTO(-1),
|
||||
m_PerfInfo()
|
||||
{
|
||||
}
|
||||
|
||||
CCC::~CCC()
|
||||
{
|
||||
delete [] m_pcParam;
|
||||
}
|
||||
|
||||
void CCC::setACKTimer(int msINT)
|
||||
{
|
||||
m_iACKPeriod = msINT > m_iSYNInterval ? m_iSYNInterval : msINT;
|
||||
}
|
||||
|
||||
void CCC::setACKInterval(int pktINT)
|
||||
{
|
||||
m_iACKInterval = pktINT;
|
||||
}
|
||||
|
||||
void CCC::setRTO(int usRTO)
|
||||
{
|
||||
m_bUserDefinedRTO = true;
|
||||
m_iRTO = usRTO;
|
||||
}
|
||||
|
||||
void CCC::sendCustomMsg(CPacket& pkt) const
|
||||
{
|
||||
CUDT* u = CUDT::getUDTHandle(m_UDT);
|
||||
|
||||
if (NULL != u)
|
||||
{
|
||||
pkt.m_iID = u->m_PeerID;
|
||||
u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
const CPerfMon* CCC::getPerfInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
CUDT* u = CUDT::getUDTHandle(m_UDT);
|
||||
if (NULL != u)
|
||||
u->sample(&m_PerfInfo, false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &m_PerfInfo;
|
||||
}
|
||||
|
||||
void CCC::setMSS(int mss)
|
||||
{
|
||||
m_iMSS = mss;
|
||||
}
|
||||
|
||||
void CCC::setBandwidth(int bw)
|
||||
{
|
||||
m_iBandwidth = bw;
|
||||
}
|
||||
|
||||
void CCC::setSndCurrSeqNo(int32_t seqno)
|
||||
{
|
||||
m_iSndCurrSeqNo = seqno;
|
||||
}
|
||||
|
||||
void CCC::setRcvRate(int rcvrate)
|
||||
{
|
||||
m_iRcvRate = rcvrate;
|
||||
}
|
||||
|
||||
void CCC::setMaxCWndSize(int cwnd)
|
||||
{
|
||||
m_dMaxCWndSize = cwnd;
|
||||
}
|
||||
|
||||
void CCC::setRTT(int rtt)
|
||||
{
|
||||
m_iRTT = rtt;
|
||||
}
|
||||
|
||||
void CCC::setUserParam(const char* param, int size)
|
||||
{
|
||||
delete [] m_pcParam;
|
||||
m_pcParam = new char[size];
|
||||
memcpy(m_pcParam, param, size);
|
||||
m_iPSize = size;
|
||||
}
|
||||
|
||||
//
|
||||
CUDTCC::CUDTCC():
|
||||
m_iRCInterval(),
|
||||
m_LastRCTime(),
|
||||
m_bSlowStart(),
|
||||
m_iLastAck(),
|
||||
m_bLoss(),
|
||||
m_iLastDecSeq(),
|
||||
m_dLastDecPeriod(),
|
||||
m_iNAKCount(),
|
||||
m_iDecRandom(),
|
||||
m_iAvgNAKNum(),
|
||||
m_iDecCount()
|
||||
{
|
||||
}
|
||||
|
||||
void CUDTCC::init()
|
||||
{
|
||||
m_iRCInterval = m_iSYNInterval;
|
||||
m_LastRCTime = CTimer::getTime();
|
||||
setACKTimer(m_iRCInterval);
|
||||
|
||||
m_bSlowStart = true;
|
||||
m_iLastAck = m_iSndCurrSeqNo;
|
||||
m_bLoss = false;
|
||||
m_iLastDecSeq = CSeqNo::decseq(m_iLastAck);
|
||||
m_dLastDecPeriod = 1;
|
||||
m_iAvgNAKNum = 0;
|
||||
m_iNAKCount = 0;
|
||||
m_iDecRandom = 1;
|
||||
|
||||
m_dCWndSize = 16;
|
||||
m_dPktSndPeriod = 1;
|
||||
}
|
||||
|
||||
void CUDTCC::onACK(int32_t ack)
|
||||
{
|
||||
int64_t B = 0;
|
||||
double inc = 0;
|
||||
// Note: 1/24/2012
|
||||
// The minimum increase parameter is increased from "1.0 / m_iMSS" to 0.01
|
||||
// because the original was too small and caused sending rate to stay at low level
|
||||
// for long time.
|
||||
const double min_inc = 0.01;
|
||||
|
||||
uint64_t currtime = CTimer::getTime();
|
||||
if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval)
|
||||
return;
|
||||
|
||||
m_LastRCTime = currtime;
|
||||
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack);
|
||||
m_iLastAck = ack;
|
||||
|
||||
if (m_dCWndSize > m_dMaxCWndSize)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
else
|
||||
m_dPktSndPeriod = (m_iRTT + m_iRCInterval) / m_dCWndSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16;
|
||||
|
||||
// During Slow Start, no rate increase
|
||||
if (m_bSlowStart)
|
||||
return;
|
||||
|
||||
if (m_bLoss)
|
||||
{
|
||||
m_bLoss = false;
|
||||
return;
|
||||
}
|
||||
|
||||
B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod);
|
||||
if ((m_dPktSndPeriod > m_dLastDecPeriod) && ((m_iBandwidth / 9) < B))
|
||||
B = m_iBandwidth / 9;
|
||||
if (B <= 0)
|
||||
inc = min_inc;
|
||||
else
|
||||
{
|
||||
// inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS)
|
||||
// Beta = 1.5 * 10^(-6)
|
||||
|
||||
inc = pow(10.0, ceil(log10(B * m_iMSS * 8.0))) * 0.0000015 / m_iMSS;
|
||||
|
||||
if (inc < min_inc)
|
||||
inc = min_inc;
|
||||
}
|
||||
|
||||
m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval);
|
||||
}
|
||||
|
||||
void CUDTCC::onLoss(const int32_t* losslist, int)
|
||||
{
|
||||
//Slow Start stopped, if it hasn't yet
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
{
|
||||
// Set the sending rate to the receiving rate.
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
return;
|
||||
}
|
||||
// If no receiving rate is observed, we have to compute the sending
|
||||
// rate according to the current window size, and decrease it
|
||||
// using the method below.
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
|
||||
}
|
||||
|
||||
m_bLoss = true;
|
||||
|
||||
if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0)
|
||||
{
|
||||
m_dLastDecPeriod = m_dPktSndPeriod;
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
|
||||
|
||||
m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125);
|
||||
m_iNAKCount = 1;
|
||||
m_iDecCount = 1;
|
||||
|
||||
m_iLastDecSeq = m_iSndCurrSeqNo;
|
||||
|
||||
// remove global synchronization using randomization
|
||||
srand(m_iLastDecSeq);
|
||||
m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX));
|
||||
if (m_iDecRandom < 1)
|
||||
m_iDecRandom = 1;
|
||||
}
|
||||
else if ((m_iDecCount ++ < 5) && (0 == (++ m_iNAKCount % m_iDecRandom)))
|
||||
{
|
||||
// 0.875^5 = 0.51, rate should not be decreased by more than half within a congestion period
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125);
|
||||
m_iLastDecSeq = m_iSndCurrSeqNo;
|
||||
}
|
||||
}
|
||||
|
||||
void CUDTCC::onTimeout()
|
||||
{
|
||||
if (m_bSlowStart)
|
||||
{
|
||||
m_bSlowStart = false;
|
||||
if (m_iRcvRate > 0)
|
||||
m_dPktSndPeriod = 1000000.0 / m_iRcvRate;
|
||||
else
|
||||
m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
m_dLastDecPeriod = m_dPktSndPeriod;
|
||||
m_dPktSndPeriod = ceil(m_dPktSndPeriod * 2);
|
||||
m_iLastDecSeq = m_iLastAck;
|
||||
*/
|
||||
}
|
||||
}
|
||||
278
vendor/udt4/src/ccc.h
vendored
278
vendor/udt4/src/ccc.h
vendored
|
|
@ -1,278 +0,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 02/28/2012
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef __UDT_CCC_H__
|
||||
#define __UDT_CCC_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
class UDT_API CCC
|
||||
{
|
||||
friend class CUDT;
|
||||
|
||||
public:
|
||||
CCC();
|
||||
virtual ~CCC();
|
||||
|
||||
private:
|
||||
CCC(const CCC&);
|
||||
CCC& operator=(const CCC&) {return *this;}
|
||||
|
||||
public:
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called (only) at the start of a UDT connection.
|
||||
// note that this is different from CCC(), which is always called.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void init() {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when a UDT connection is closed.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void close() {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when an ACK packet is received.
|
||||
// Parameters:
|
||||
// 0) [in] ackno: the data sequence number acknowledged by this ACK.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void onACK(int32_t) {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when a loss report is received.
|
||||
// Parameters:
|
||||
// 0) [in] losslist: list of sequence number of packets, in the format describled in packet.cpp.
|
||||
// 1) [in] size: length of the loss list.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void onLoss(const int32_t*, int) {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when a timeout event occurs.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void onTimeout() {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when a data is sent.
|
||||
// Parameters:
|
||||
// 0) [in] seqno: the data sequence number.
|
||||
// 1) [in] size: the payload size.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void onPktSent(const CPacket*) {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to be called when a data is received.
|
||||
// Parameters:
|
||||
// 0) [in] seqno: the data sequence number.
|
||||
// 1) [in] size: the payload size.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void onPktReceived(const CPacket*) {}
|
||||
|
||||
// Functionality:
|
||||
// Callback function to Process a user defined packet.
|
||||
// Parameters:
|
||||
// 0) [in] pkt: the user defined packet.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
virtual void processCustomMsg(const CPacket*) {}
|
||||
|
||||
protected:
|
||||
|
||||
// Functionality:
|
||||
// Set periodical acknowldging and the ACK period.
|
||||
// Parameters:
|
||||
// 0) [in] msINT: the period to send an ACK.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setACKTimer(int msINT);
|
||||
|
||||
// Functionality:
|
||||
// Set packet-based acknowldging and the number of packets to send an ACK.
|
||||
// Parameters:
|
||||
// 0) [in] pktINT: the number of packets to send an ACK.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setACKInterval(int pktINT);
|
||||
|
||||
// Functionality:
|
||||
// Set RTO value.
|
||||
// Parameters:
|
||||
// 0) [in] msRTO: RTO in macroseconds.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setRTO(int usRTO);
|
||||
|
||||
// Functionality:
|
||||
// Send a user defined control packet.
|
||||
// Parameters:
|
||||
// 0) [in] pkt: user defined packet.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void sendCustomMsg(CPacket& pkt) const;
|
||||
|
||||
// Functionality:
|
||||
// retrieve performance information.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// Pointer to a performance info structure.
|
||||
|
||||
const CPerfMon* getPerfInfo();
|
||||
|
||||
// Functionality:
|
||||
// Set user defined parameters.
|
||||
// Parameters:
|
||||
// 0) [in] param: the paramters in one buffer.
|
||||
// 1) [in] size: the size of the buffer.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setUserParam(const char* param, int size);
|
||||
|
||||
private:
|
||||
void setMSS(int mss);
|
||||
void setMaxCWndSize(int cwnd);
|
||||
void setBandwidth(int bw);
|
||||
void setSndCurrSeqNo(int32_t seqno);
|
||||
void setRcvRate(int rcvrate);
|
||||
void setRTT(int rtt);
|
||||
|
||||
protected:
|
||||
const int32_t& m_iSYNInterval; // UDT constant parameter, SYN
|
||||
|
||||
double m_dPktSndPeriod; // Packet sending period, in microseconds
|
||||
double m_dCWndSize; // Congestion window size, in packets
|
||||
|
||||
int m_iBandwidth; // estimated bandwidth, packets per second
|
||||
double m_dMaxCWndSize; // maximum cwnd size, in packets
|
||||
|
||||
int m_iMSS; // Maximum Packet Size, including all packet headers
|
||||
int32_t m_iSndCurrSeqNo; // current maximum seq no sent out
|
||||
int m_iRcvRate; // packet arrive rate at receiver side, packets per second
|
||||
int m_iRTT; // current estimated RTT, microsecond
|
||||
|
||||
char* m_pcParam; // user defined parameter
|
||||
int m_iPSize; // size of m_pcParam
|
||||
|
||||
private:
|
||||
UDTSOCKET m_UDT; // The UDT entity that this congestion control algorithm is bound to
|
||||
|
||||
int m_iACKPeriod; // Periodical timer to send an ACK, in milliseconds
|
||||
int m_iACKInterval; // How many packets to send one ACK, in packets
|
||||
|
||||
bool m_bUserDefinedRTO; // if the RTO value is defined by users
|
||||
int m_iRTO; // RTO value, microseconds
|
||||
|
||||
CPerfMon m_PerfInfo; // protocol statistics information
|
||||
};
|
||||
|
||||
class CCCVirtualFactory
|
||||
{
|
||||
public:
|
||||
virtual ~CCCVirtualFactory() {}
|
||||
|
||||
virtual CCC* create() = 0;
|
||||
virtual CCCVirtualFactory* clone() = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CCCFactory: public CCCVirtualFactory
|
||||
{
|
||||
public:
|
||||
virtual ~CCCFactory() {}
|
||||
|
||||
virtual CCC* create() {return new T;}
|
||||
virtual CCCVirtualFactory* clone() {return new CCCFactory<T>;}
|
||||
};
|
||||
|
||||
class CUDTCC: public CCC
|
||||
{
|
||||
public:
|
||||
CUDTCC();
|
||||
|
||||
public:
|
||||
virtual void init();
|
||||
virtual void onACK(int32_t);
|
||||
virtual void onLoss(const int32_t*, int);
|
||||
virtual void onTimeout();
|
||||
|
||||
private:
|
||||
int m_iRCInterval; // UDT Rate control interval
|
||||
uint64_t m_LastRCTime; // last rate increase time
|
||||
bool m_bSlowStart; // if in slow start phase
|
||||
int32_t m_iLastAck; // last ACKed seq no
|
||||
bool m_bLoss; // if loss happened since last rate increase
|
||||
int32_t m_iLastDecSeq; // max pkt seq no sent out when last decrease happened
|
||||
double m_dLastDecPeriod; // value of pktsndperiod when last decrease happened
|
||||
int m_iNAKCount; // NAK counter
|
||||
int m_iDecRandom; // random threshold on decrease by number of loss events
|
||||
int m_iAvgNAKNum; // average number of NAKs per congestion
|
||||
int m_iDecCount; // number of decreases in a congestion epoch
|
||||
};
|
||||
|
||||
#endif
|
||||
340
vendor/udt4/src/channel.cpp
vendored
340
vendor/udt4/src/channel.cpp
vendored
|
|
@ -1,340 +0,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 01/27/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef WIN32
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#ifdef LEGACY_WIN32
|
||||
#include <wspiapi.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "channel.h"
|
||||
#include "packet.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#define NET_ERROR errno
|
||||
#else
|
||||
#define NET_ERROR WSAGetLastError()
|
||||
#endif
|
||||
|
||||
|
||||
CChannel::CChannel():
|
||||
m_iIPversion(AF_INET),
|
||||
m_iSockAddrSize(sizeof(sockaddr_in)),
|
||||
m_iSocket(),
|
||||
m_iSndBufSize(65536),
|
||||
m_iRcvBufSize(65536)
|
||||
{
|
||||
}
|
||||
|
||||
CChannel::CChannel(int version):
|
||||
m_iIPversion(version),
|
||||
m_iSocket(),
|
||||
m_iSndBufSize(65536),
|
||||
m_iRcvBufSize(65536)
|
||||
{
|
||||
m_iSockAddrSize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
|
||||
}
|
||||
|
||||
CChannel::~CChannel()
|
||||
{
|
||||
}
|
||||
|
||||
void CChannel::open(const sockaddr* addr)
|
||||
{
|
||||
// construct an socket
|
||||
m_iSocket = ::socket(m_iIPversion, SOCK_DGRAM, 0);
|
||||
|
||||
#ifdef WIN32
|
||||
if (INVALID_SOCKET == m_iSocket)
|
||||
#else
|
||||
if (m_iSocket < 0)
|
||||
#endif
|
||||
throw CUDTException(1, 0, NET_ERROR);
|
||||
|
||||
if (NULL != addr)
|
||||
{
|
||||
socklen_t namelen = m_iSockAddrSize;
|
||||
|
||||
if (0 != ::bind(m_iSocket, addr, namelen))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
//sendto or WSASendTo will also automatically bind the socket
|
||||
addrinfo hints;
|
||||
addrinfo* res;
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = m_iIPversion;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
if (0 != ::getaddrinfo(NULL, "0", &hints, &res))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
|
||||
if (0 != ::bind(m_iSocket, res->ai_addr, res->ai_addrlen))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
|
||||
::freeaddrinfo(res);
|
||||
}
|
||||
|
||||
setUDPSockOpt();
|
||||
}
|
||||
|
||||
void CChannel::open(UDPSOCKET udpsock)
|
||||
{
|
||||
m_iSocket = udpsock;
|
||||
setUDPSockOpt();
|
||||
}
|
||||
|
||||
void CChannel::setUDPSockOpt()
|
||||
{
|
||||
#if defined(BSD) || defined(OSX)
|
||||
// BSD system will fail setsockopt if the requested buffer size exceeds system maximum value
|
||||
int maxsize = 64000;
|
||||
if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int)))
|
||||
::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&maxsize, sizeof(int));
|
||||
if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int)))
|
||||
::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&maxsize, sizeof(int));
|
||||
#else
|
||||
// for other systems, if requested is greated than maximum, the maximum value will be automactally used
|
||||
if ((0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int))) ||
|
||||
(0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int))))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
#endif
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
#if defined (BSD) || defined (OSX)
|
||||
// Known BSD bug as the day I wrote this code.
|
||||
// A small time out value will cause the socket to block forever.
|
||||
tv.tv_usec = 10000;
|
||||
#else
|
||||
tv.tv_usec = 100;
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
// Set non-blocking I/O
|
||||
// UNIX does not support SO_RCVTIMEO
|
||||
int opts = ::fcntl(m_iSocket, F_GETFL);
|
||||
if (-1 == ::fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
#elif WIN32
|
||||
DWORD ot = 1; //milliseconds
|
||||
if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeof(DWORD)))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
#else
|
||||
// Set receiving time-out value
|
||||
if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval)))
|
||||
throw CUDTException(1, 3, NET_ERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CChannel::close() const
|
||||
{
|
||||
#ifndef WIN32
|
||||
::close(m_iSocket);
|
||||
#else
|
||||
::closesocket(m_iSocket);
|
||||
#endif
|
||||
}
|
||||
|
||||
int CChannel::getSndBufSize()
|
||||
{
|
||||
socklen_t size = sizeof(socklen_t);
|
||||
::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize, &size);
|
||||
return m_iSndBufSize;
|
||||
}
|
||||
|
||||
int CChannel::getRcvBufSize()
|
||||
{
|
||||
socklen_t size = sizeof(socklen_t);
|
||||
::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, &size);
|
||||
return m_iRcvBufSize;
|
||||
}
|
||||
|
||||
void CChannel::setSndBufSize(int size)
|
||||
{
|
||||
m_iSndBufSize = size;
|
||||
}
|
||||
|
||||
void CChannel::setRcvBufSize(int size)
|
||||
{
|
||||
m_iRcvBufSize = size;
|
||||
}
|
||||
|
||||
void CChannel::getSockAddr(sockaddr* addr) const
|
||||
{
|
||||
socklen_t namelen = m_iSockAddrSize;
|
||||
::getsockname(m_iSocket, addr, &namelen);
|
||||
}
|
||||
|
||||
void CChannel::getPeerAddr(sockaddr* addr) const
|
||||
{
|
||||
socklen_t namelen = m_iSockAddrSize;
|
||||
::getpeername(m_iSocket, addr, &namelen);
|
||||
}
|
||||
|
||||
int CChannel::sendto(const sockaddr* addr, CPacket& packet) const
|
||||
{
|
||||
// convert control information into network order
|
||||
if (packet.getFlag())
|
||||
for (int i = 0, n = packet.getLength() / 4; i < n; ++ i)
|
||||
*((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcData + i));
|
||||
|
||||
// convert packet header into network order
|
||||
//for (int j = 0; j < 4; ++ j)
|
||||
// packet.m_nHeader[j] = htonl(packet.m_nHeader[j]);
|
||||
uint32_t* p = packet.m_nHeader;
|
||||
for (int j = 0; j < 4; ++ j)
|
||||
{
|
||||
*p = htonl(*p);
|
||||
++ p;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
msghdr mh;
|
||||
mh.msg_name = (sockaddr*)addr;
|
||||
mh.msg_namelen = m_iSockAddrSize;
|
||||
mh.msg_iov = (iovec*)packet.m_PacketVector;
|
||||
mh.msg_iovlen = 2;
|
||||
mh.msg_control = NULL;
|
||||
mh.msg_controllen = 0;
|
||||
mh.msg_flags = 0;
|
||||
|
||||
int res = ::sendmsg(m_iSocket, &mh, 0);
|
||||
#else
|
||||
DWORD size = CPacket::m_iPktHdrSize + packet.getLength();
|
||||
int addrsize = m_iSockAddrSize;
|
||||
int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr, addrsize, NULL, NULL);
|
||||
res = (0 == res) ? size : -1;
|
||||
#endif
|
||||
|
||||
// convert back into local host order
|
||||
//for (int k = 0; k < 4; ++ k)
|
||||
// packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]);
|
||||
p = packet.m_nHeader;
|
||||
for (int k = 0; k < 4; ++ k)
|
||||
{
|
||||
*p = ntohl(*p);
|
||||
++ p;
|
||||
}
|
||||
|
||||
if (packet.getFlag())
|
||||
{
|
||||
for (int l = 0, n = packet.getLength() / 4; l < n; ++ l)
|
||||
*((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcData + l));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int CChannel::recvfrom(sockaddr* addr, CPacket& packet) const
|
||||
{
|
||||
#ifndef WIN32
|
||||
msghdr mh;
|
||||
mh.msg_name = addr;
|
||||
mh.msg_namelen = m_iSockAddrSize;
|
||||
mh.msg_iov = packet.m_PacketVector;
|
||||
mh.msg_iovlen = 2;
|
||||
mh.msg_control = NULL;
|
||||
mh.msg_controllen = 0;
|
||||
mh.msg_flags = 0;
|
||||
|
||||
#ifdef UNIX
|
||||
fd_set set;
|
||||
timeval tv;
|
||||
FD_ZERO(&set);
|
||||
FD_SET(m_iSocket, &set);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
::select(m_iSocket+1, &set, NULL, &set, &tv);
|
||||
#endif
|
||||
|
||||
int res = ::recvmsg(m_iSocket, &mh, 0);
|
||||
#else
|
||||
DWORD size = CPacket::m_iPktHdrSize + packet.getLength();
|
||||
DWORD flag = 0;
|
||||
int addrsize = m_iSockAddrSize;
|
||||
|
||||
int res = ::WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, &flag, addr, &addrsize, NULL, NULL);
|
||||
res = (0 == res) ? size : -1;
|
||||
#endif
|
||||
|
||||
if (res <= 0)
|
||||
{
|
||||
packet.setLength(-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
packet.setLength(res - CPacket::m_iPktHdrSize);
|
||||
|
||||
// convert back into local host order
|
||||
//for (int i = 0; i < 4; ++ i)
|
||||
// packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]);
|
||||
uint32_t* p = packet.m_nHeader;
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
{
|
||||
*p = ntohl(*p);
|
||||
++ p;
|
||||
}
|
||||
|
||||
if (packet.getFlag())
|
||||
{
|
||||
for (int j = 0, n = packet.getLength() / 4; j < n; ++ j)
|
||||
*((uint32_t *)packet.m_pcData + j) = ntohl(*((uint32_t *)packet.m_pcData + j));
|
||||
}
|
||||
|
||||
return packet.getLength();
|
||||
}
|
||||
171
vendor/udt4/src/channel.h
vendored
171
vendor/udt4/src/channel.h
vendored
|
|
@ -1,171 +0,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 01/27/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_CHANNEL_H__
|
||||
#define __UDT_CHANNEL_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
class CChannel
|
||||
{
|
||||
public:
|
||||
CChannel();
|
||||
CChannel(int version);
|
||||
~CChannel();
|
||||
|
||||
// Functionality:
|
||||
// Open a UDP channel.
|
||||
// Parameters:
|
||||
// 0) [in] addr: The local address that UDP will use.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void open(const sockaddr* addr = NULL);
|
||||
|
||||
// Functionality:
|
||||
// Open a UDP channel based on an existing UDP socket.
|
||||
// Parameters:
|
||||
// 0) [in] udpsock: UDP socket descriptor.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void open(UDPSOCKET udpsock);
|
||||
|
||||
// Functionality:
|
||||
// Disconnect and close the UDP entity.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void close() const;
|
||||
|
||||
// Functionality:
|
||||
// Get the UDP sending buffer size.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// Current UDP sending buffer size.
|
||||
|
||||
int getSndBufSize();
|
||||
|
||||
// Functionality:
|
||||
// Get the UDP receiving buffer size.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// Current UDP receiving buffer size.
|
||||
|
||||
int getRcvBufSize();
|
||||
|
||||
// Functionality:
|
||||
// Set the UDP sending buffer size.
|
||||
// Parameters:
|
||||
// 0) [in] size: expected UDP sending buffer size.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setSndBufSize(int size);
|
||||
|
||||
// Functionality:
|
||||
// Set the UDP receiving buffer size.
|
||||
// Parameters:
|
||||
// 0) [in] size: expected UDP receiving buffer size.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setRcvBufSize(int size);
|
||||
|
||||
// Functionality:
|
||||
// Query the socket address that the channel is using.
|
||||
// Parameters:
|
||||
// 0) [out] addr: pointer to store the returned socket address.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void getSockAddr(sockaddr* addr) const;
|
||||
|
||||
// Functionality:
|
||||
// Query the peer side socket address that the channel is connect to.
|
||||
// Parameters:
|
||||
// 0) [out] addr: pointer to store the returned socket address.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void getPeerAddr(sockaddr* addr) const;
|
||||
|
||||
// Functionality:
|
||||
// Send a packet to the given address.
|
||||
// Parameters:
|
||||
// 0) [in] addr: pointer to the destination address.
|
||||
// 1) [in] packet: reference to a CPacket entity.
|
||||
// Returned value:
|
||||
// Actual size of data sent.
|
||||
|
||||
int sendto(const sockaddr* addr, CPacket& packet) const;
|
||||
|
||||
// Functionality:
|
||||
// Receive a packet from the channel and record the source address.
|
||||
// Parameters:
|
||||
// 0) [in] addr: pointer to the source address.
|
||||
// 1) [in] packet: reference to a CPacket entity.
|
||||
// Returned value:
|
||||
// Actual size of data received.
|
||||
|
||||
int recvfrom(sockaddr* addr, CPacket& packet) const;
|
||||
|
||||
private:
|
||||
void setUDPSockOpt();
|
||||
|
||||
private:
|
||||
int m_iIPversion; // IP version
|
||||
int m_iSockAddrSize; // socket address structure size (pre-defined to avoid run-time test)
|
||||
|
||||
UDPSOCKET m_iSocket; // socket descriptor
|
||||
|
||||
int m_iSndBufSize; // UDP sending buffer size
|
||||
int m_iRcvBufSize; // UDP receiving buffer size
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
765
vendor/udt4/src/common.cpp
vendored
765
vendor/udt4/src/common.cpp
vendored
|
|
@ -1,765 +0,0 @@
|
|||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2010, 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 07/25/2010
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <unistd.h>
|
||||
#ifdef OSX
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#ifdef LEGACY_WIN32
|
||||
#include <wspiapi.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include "md5.h"
|
||||
#include "common.h"
|
||||
|
||||
bool CTimer::m_bUseMicroSecond = false;
|
||||
uint64_t CTimer::s_ullCPUFrequency = CTimer::readCPUFrequency();
|
||||
#ifndef WIN32
|
||||
pthread_mutex_t CTimer::m_EventLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t CTimer::m_EventCond = PTHREAD_COND_INITIALIZER;
|
||||
#else
|
||||
pthread_mutex_t CTimer::m_EventLock = CreateMutex(NULL, false, NULL);
|
||||
pthread_cond_t CTimer::m_EventCond = CreateEvent(NULL, false, false, NULL);
|
||||
#endif
|
||||
|
||||
CTimer::CTimer():
|
||||
m_ullSchedTime(),
|
||||
m_TickCond(),
|
||||
m_TickLock()
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_init(&m_TickLock, NULL);
|
||||
pthread_cond_init(&m_TickCond, NULL);
|
||||
#else
|
||||
m_TickLock = CreateMutex(NULL, false, NULL);
|
||||
m_TickCond = CreateEvent(NULL, false, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
CTimer::~CTimer()
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_destroy(&m_TickLock);
|
||||
pthread_cond_destroy(&m_TickCond);
|
||||
#else
|
||||
CloseHandle(m_TickLock);
|
||||
CloseHandle(m_TickCond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTimer::rdtsc(uint64_t &x)
|
||||
{
|
||||
if (m_bUseMicroSecond)
|
||||
{
|
||||
x = getTime();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef IA32
|
||||
uint32_t lval, hval;
|
||||
//asm volatile ("push %eax; push %ebx; push %ecx; push %edx");
|
||||
//asm volatile ("xor %eax, %eax; cpuid");
|
||||
asm volatile ("rdtsc" : "=a" (lval), "=d" (hval));
|
||||
//asm volatile ("pop %edx; pop %ecx; pop %ebx; pop %eax");
|
||||
x = hval;
|
||||
x = (x << 32) | lval;
|
||||
#elif defined(IA64)
|
||||
asm ("mov %0=ar.itc" : "=r"(x) :: "memory");
|
||||
#elif defined(AMD64)
|
||||
uint32_t lval, hval;
|
||||
asm ("rdtsc" : "=a" (lval), "=d" (hval));
|
||||
x = hval;
|
||||
x = (x << 32) | lval;
|
||||
#elif defined(WIN32)
|
||||
//HANDLE hCurThread = ::GetCurrentThread();
|
||||
//DWORD_PTR dwOldMask = ::SetThreadAffinityMask(hCurThread, 1);
|
||||
BOOL ret = QueryPerformanceCounter((LARGE_INTEGER *)&x);
|
||||
//SetThreadAffinityMask(hCurThread, dwOldMask);
|
||||
if (!ret)
|
||||
x = getTime() * s_ullCPUFrequency;
|
||||
#elif defined(OSX)
|
||||
x = mach_absolute_time();
|
||||
#else
|
||||
// use system call to read time clock for other archs
|
||||
x = getTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t CTimer::readCPUFrequency()
|
||||
{
|
||||
uint64_t frequency = 1; // 1 tick per microsecond.
|
||||
|
||||
#if defined(IA32) || defined(IA64) || defined(AMD64)
|
||||
uint64_t t1, t2;
|
||||
|
||||
rdtsc(t1);
|
||||
timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000;
|
||||
nanosleep(&ts, NULL);
|
||||
rdtsc(t2);
|
||||
|
||||
// CPU clocks per microsecond
|
||||
frequency = (t2 - t1) / 100000;
|
||||
#elif defined(WIN32)
|
||||
int64_t ccf;
|
||||
if (QueryPerformanceFrequency((LARGE_INTEGER *)&ccf))
|
||||
frequency = ccf / 1000000;
|
||||
#elif defined(OSX)
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
frequency = info.denom * 1000ULL / info.numer;
|
||||
#endif
|
||||
|
||||
// Fall back to microsecond if the resolution is not high enough.
|
||||
if (frequency < 10)
|
||||
{
|
||||
frequency = 1;
|
||||
m_bUseMicroSecond = true;
|
||||
}
|
||||
return frequency;
|
||||
}
|
||||
|
||||
uint64_t CTimer::getCPUFrequency()
|
||||
{
|
||||
return s_ullCPUFrequency;
|
||||
}
|
||||
|
||||
void CTimer::sleep(uint64_t interval)
|
||||
{
|
||||
uint64_t t;
|
||||
rdtsc(t);
|
||||
|
||||
// sleep next "interval" time
|
||||
sleepto(t + interval);
|
||||
}
|
||||
|
||||
void CTimer::sleepto(uint64_t nexttime)
|
||||
{
|
||||
// Use class member such that the method can be interrupted by others
|
||||
m_ullSchedTime = nexttime;
|
||||
|
||||
uint64_t t;
|
||||
rdtsc(t);
|
||||
|
||||
while (t < m_ullSchedTime)
|
||||
{
|
||||
#ifndef NO_BUSY_WAITING
|
||||
#ifdef IA32
|
||||
__asm__ volatile ("pause; rep; nop; nop; nop; nop; nop;");
|
||||
#elif IA64
|
||||
__asm__ volatile ("nop 0; nop 0; nop 0; nop 0; nop 0;");
|
||||
#elif AMD64
|
||||
__asm__ volatile ("nop; nop; nop; nop; nop;");
|
||||
#endif
|
||||
#else
|
||||
#ifndef WIN32
|
||||
timeval now;
|
||||
timespec timeout;
|
||||
gettimeofday(&now, 0);
|
||||
if (now.tv_usec < 990000)
|
||||
{
|
||||
timeout.tv_sec = now.tv_sec;
|
||||
timeout.tv_nsec = (now.tv_usec + 10000) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout.tv_sec = now.tv_sec + 1;
|
||||
timeout.tv_nsec = (now.tv_usec + 10000 - 1000000) * 1000;
|
||||
}
|
||||
pthread_mutex_lock(&m_TickLock);
|
||||
pthread_cond_timedwait(&m_TickCond, &m_TickLock, &timeout);
|
||||
pthread_mutex_unlock(&m_TickLock);
|
||||
#else
|
||||
WaitForSingleObject(m_TickCond, 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
rdtsc(t);
|
||||
}
|
||||
}
|
||||
|
||||
void CTimer::interrupt()
|
||||
{
|
||||
// schedule the sleepto time to the current CCs, so that it will stop
|
||||
rdtsc(m_ullSchedTime);
|
||||
tick();
|
||||
}
|
||||
|
||||
void CTimer::tick()
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_cond_signal(&m_TickCond);
|
||||
#else
|
||||
SetEvent(m_TickCond);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t CTimer::getTime()
|
||||
{
|
||||
//For Cygwin and other systems without microsecond level resolution, uncomment the following three lines
|
||||
//uint64_t x;
|
||||
//rdtsc(x);
|
||||
//return x / s_ullCPUFrequency;
|
||||
//Specific fix may be necessary if rdtsc is not available either.
|
||||
|
||||
#ifndef WIN32
|
||||
timeval t;
|
||||
gettimeofday(&t, 0);
|
||||
return t.tv_sec * 1000000ULL + t.tv_usec;
|
||||
#else
|
||||
LARGE_INTEGER ccf;
|
||||
HANDLE hCurThread = ::GetCurrentThread();
|
||||
DWORD_PTR dwOldMask = ::SetThreadAffinityMask(hCurThread, 1);
|
||||
if (QueryPerformanceFrequency(&ccf))
|
||||
{
|
||||
LARGE_INTEGER cc;
|
||||
if (QueryPerformanceCounter(&cc))
|
||||
{
|
||||
SetThreadAffinityMask(hCurThread, dwOldMask);
|
||||
return (cc.QuadPart * 1000000ULL / ccf.QuadPart);
|
||||
}
|
||||
}
|
||||
|
||||
SetThreadAffinityMask(hCurThread, dwOldMask);
|
||||
return GetTickCount() * 1000ULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTimer::triggerEvent()
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_cond_signal(&m_EventCond);
|
||||
#else
|
||||
SetEvent(m_EventCond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTimer::waitForEvent()
|
||||
{
|
||||
#ifndef WIN32
|
||||
timeval now;
|
||||
timespec timeout;
|
||||
gettimeofday(&now, 0);
|
||||
if (now.tv_usec < 990000)
|
||||
{
|
||||
timeout.tv_sec = now.tv_sec;
|
||||
timeout.tv_nsec = (now.tv_usec + 10000) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout.tv_sec = now.tv_sec + 1;
|
||||
timeout.tv_nsec = (now.tv_usec + 10000 - 1000000) * 1000;
|
||||
}
|
||||
pthread_mutex_lock(&m_EventLock);
|
||||
pthread_cond_timedwait(&m_EventCond, &m_EventLock, &timeout);
|
||||
pthread_mutex_unlock(&m_EventLock);
|
||||
#else
|
||||
WaitForSingleObject(m_EventCond, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTimer::sleep()
|
||||
{
|
||||
#ifndef WIN32
|
||||
usleep(10);
|
||||
#else
|
||||
Sleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Automatically lock in constructor
|
||||
CGuard::CGuard(pthread_mutex_t& lock):
|
||||
m_Mutex(lock),
|
||||
m_iLocked()
|
||||
{
|
||||
#ifndef WIN32
|
||||
m_iLocked = pthread_mutex_lock(&m_Mutex);
|
||||
#else
|
||||
m_iLocked = WaitForSingleObject(m_Mutex, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Automatically unlock in destructor
|
||||
CGuard::~CGuard()
|
||||
{
|
||||
#ifndef WIN32
|
||||
if (0 == m_iLocked)
|
||||
pthread_mutex_unlock(&m_Mutex);
|
||||
#else
|
||||
if (WAIT_FAILED != m_iLocked)
|
||||
ReleaseMutex(m_Mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::enterCS(pthread_mutex_t& lock)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_lock(&lock);
|
||||
#else
|
||||
WaitForSingleObject(lock, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::leaveCS(pthread_mutex_t& lock)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_unlock(&lock);
|
||||
#else
|
||||
ReleaseMutex(lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::createMutex(pthread_mutex_t& lock)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_init(&lock, NULL);
|
||||
#else
|
||||
lock = CreateMutex(NULL, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::releaseMutex(pthread_mutex_t& lock)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_mutex_destroy(&lock);
|
||||
#else
|
||||
CloseHandle(lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::createCond(pthread_cond_t& cond)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_cond_init(&cond, NULL);
|
||||
#else
|
||||
cond = CreateEvent(NULL, false, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGuard::releaseCond(pthread_cond_t& cond)
|
||||
{
|
||||
#ifndef WIN32
|
||||
pthread_cond_destroy(&cond);
|
||||
#else
|
||||
CloseHandle(cond);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
CUDTException::CUDTException(int major, int minor, int err):
|
||||
m_iMajor(major),
|
||||
m_iMinor(minor)
|
||||
{
|
||||
if (-1 == err)
|
||||
#ifndef WIN32
|
||||
m_iErrno = errno;
|
||||
#else
|
||||
m_iErrno = GetLastError();
|
||||
#endif
|
||||
else
|
||||
m_iErrno = err;
|
||||
}
|
||||
|
||||
CUDTException::CUDTException(const CUDTException& e):
|
||||
m_iMajor(e.m_iMajor),
|
||||
m_iMinor(e.m_iMinor),
|
||||
m_iErrno(e.m_iErrno),
|
||||
m_strMsg()
|
||||
{
|
||||
}
|
||||
|
||||
CUDTException::~CUDTException()
|
||||
{
|
||||
}
|
||||
|
||||
const char* CUDTException::getErrorMessage()
|
||||
{
|
||||
// translate "Major:Minor" code into text message.
|
||||
|
||||
switch (m_iMajor)
|
||||
{
|
||||
case 0:
|
||||
m_strMsg = "Success";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_strMsg = "Connection setup failure";
|
||||
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg += ": connection time out";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg += ": connection rejected";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_strMsg += ": unable to create/configure UDP socket";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_strMsg += ": abort for security reasons";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg = "Connection was broken";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg = "Connection does not exist";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_strMsg = "System resource failure";
|
||||
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg += ": unable to create new threads";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg += ": unable to allocate buffers";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_strMsg = "File system failure";
|
||||
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg += ": cannot seek read position";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg += ": failure in read";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_strMsg += ": cannot seek write position";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_strMsg += ": failure in write";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
m_strMsg = "Operation not supported";
|
||||
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg += ": Cannot do this operation on a BOUND socket";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg += ": Cannot do this operation on a CONNECTED socket";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_strMsg += ": Bad parameters";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_strMsg += ": Invalid socket ID";
|
||||
break;
|
||||
|
||||
case 5:
|
||||
m_strMsg += ": Cannot do this operation on an UNBOUND socket";
|
||||
break;
|
||||
|
||||
case 6:
|
||||
m_strMsg += ": Socket is not in listening state";
|
||||
break;
|
||||
|
||||
case 7:
|
||||
m_strMsg += ": Listen/accept is not supported in rendezous connection setup";
|
||||
break;
|
||||
|
||||
case 8:
|
||||
m_strMsg += ": Cannot call connect on UNBOUND socket in rendezvous connection setup";
|
||||
break;
|
||||
|
||||
case 9:
|
||||
m_strMsg += ": This operation is not supported in SOCK_STREAM mode";
|
||||
break;
|
||||
|
||||
case 10:
|
||||
m_strMsg += ": This operation is not supported in SOCK_DGRAM mode";
|
||||
break;
|
||||
|
||||
case 11:
|
||||
m_strMsg += ": Another socket is already listening on the same port";
|
||||
break;
|
||||
|
||||
case 12:
|
||||
m_strMsg += ": Message is too large to send (it must be less than the UDT send buffer size)";
|
||||
break;
|
||||
|
||||
case 13:
|
||||
m_strMsg += ": Invalid epoll ID";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
m_strMsg = "Non-blocking call failure";
|
||||
|
||||
switch (m_iMinor)
|
||||
{
|
||||
case 1:
|
||||
m_strMsg += ": no buffer available for sending";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_strMsg += ": no data available for reading";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 7:
|
||||
m_strMsg = "The peer side has signalled an error";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
m_strMsg = "Unknown error";
|
||||
}
|
||||
|
||||
// Adding "errno" information
|
||||
if ((0 != m_iMajor) && (0 < m_iErrno))
|
||||
{
|
||||
m_strMsg += ": ";
|
||||
#ifndef WIN32
|
||||
char errmsg[1024];
|
||||
if (strerror_r(m_iErrno, errmsg, 1024) == 0)
|
||||
m_strMsg += errmsg;
|
||||
#else
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, m_iErrno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
m_strMsg += (char*)lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
// period
|
||||
#ifndef WIN32
|
||||
m_strMsg += ".";
|
||||
#endif
|
||||
|
||||
return m_strMsg.c_str();
|
||||
}
|
||||
|
||||
int CUDTException::getErrorCode() const
|
||||
{
|
||||
return m_iMajor * 1000 + m_iMinor;
|
||||
}
|
||||
|
||||
void CUDTException::clear()
|
||||
{
|
||||
m_iMajor = 0;
|
||||
m_iMinor = 0;
|
||||
m_iErrno = 0;
|
||||
}
|
||||
|
||||
const int CUDTException::SUCCESS = 0;
|
||||
const int CUDTException::ECONNSETUP = 1000;
|
||||
const int CUDTException::ENOSERVER = 1001;
|
||||
const int CUDTException::ECONNREJ = 1002;
|
||||
const int CUDTException::ESOCKFAIL = 1003;
|
||||
const int CUDTException::ESECFAIL = 1004;
|
||||
const int CUDTException::ECONNFAIL = 2000;
|
||||
const int CUDTException::ECONNLOST = 2001;
|
||||
const int CUDTException::ENOCONN = 2002;
|
||||
const int CUDTException::ERESOURCE = 3000;
|
||||
const int CUDTException::ETHREAD = 3001;
|
||||
const int CUDTException::ENOBUF = 3002;
|
||||
const int CUDTException::EFILE = 4000;
|
||||
const int CUDTException::EINVRDOFF = 4001;
|
||||
const int CUDTException::ERDPERM = 4002;
|
||||
const int CUDTException::EINVWROFF = 4003;
|
||||
const int CUDTException::EWRPERM = 4004;
|
||||
const int CUDTException::EINVOP = 5000;
|
||||
const int CUDTException::EBOUNDSOCK = 5001;
|
||||
const int CUDTException::ECONNSOCK = 5002;
|
||||
const int CUDTException::EINVPARAM = 5003;
|
||||
const int CUDTException::EINVSOCK = 5004;
|
||||
const int CUDTException::EUNBOUNDSOCK = 5005;
|
||||
const int CUDTException::ENOLISTEN = 5006;
|
||||
const int CUDTException::ERDVNOSERV = 5007;
|
||||
const int CUDTException::ERDVUNBOUND = 5008;
|
||||
const int CUDTException::ESTREAMILL = 5009;
|
||||
const int CUDTException::EDGRAMILL = 5010;
|
||||
const int CUDTException::EDUPLISTEN = 5011;
|
||||
const int CUDTException::ELARGEMSG = 5012;
|
||||
const int CUDTException::EINVPOLLID = 5013;
|
||||
const int CUDTException::EASYNCFAIL = 6000;
|
||||
const int CUDTException::EASYNCSND = 6001;
|
||||
const int CUDTException::EASYNCRCV = 6002;
|
||||
const int CUDTException::ETIMEOUT = 6003;
|
||||
const int CUDTException::EPEERERR = 7000;
|
||||
const int CUDTException::EUNKNOWN = -1;
|
||||
|
||||
|
||||
//
|
||||
bool CIPAddress::ipcmp(const sockaddr* addr1, const sockaddr* addr2, int ver)
|
||||
{
|
||||
if (AF_INET == ver)
|
||||
{
|
||||
sockaddr_in* a1 = (sockaddr_in*)addr1;
|
||||
sockaddr_in* a2 = (sockaddr_in*)addr2;
|
||||
|
||||
if ((a1->sin_port == a2->sin_port) && (a1->sin_addr.s_addr == a2->sin_addr.s_addr))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in6* a1 = (sockaddr_in6*)addr1;
|
||||
sockaddr_in6* a2 = (sockaddr_in6*)addr2;
|
||||
|
||||
if (a1->sin6_port == a2->sin6_port)
|
||||
{
|
||||
for (int i = 0; i < 16; ++ i)
|
||||
if (*((char*)&(a1->sin6_addr) + i) != *((char*)&(a2->sin6_addr) + i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CIPAddress::ntop(const sockaddr* addr, uint32_t ip[4], int ver)
|
||||
{
|
||||
if (AF_INET == ver)
|
||||
{
|
||||
sockaddr_in* a = (sockaddr_in*)addr;
|
||||
ip[0] = a->sin_addr.s_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in6* a = (sockaddr_in6*)addr;
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
void CIPAddress::pton(sockaddr* addr, const uint32_t ip[4], int ver)
|
||||
{
|
||||
if (AF_INET == ver)
|
||||
{
|
||||
sockaddr_in* a = (sockaddr_in*)addr;
|
||||
a->sin_addr.s_addr = ip[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
sockaddr_in6* a = (sockaddr_in6*)addr;
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
{
|
||||
a->sin6_addr.s6_addr[i * 4] = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
void CMD5::compute(const char* input, unsigned char result[16])
|
||||
{
|
||||
md5_state_t state;
|
||||
|
||||
md5_init(&state);
|
||||
md5_append(&state, (const md5_byte_t *)input, strlen(input));
|
||||
md5_finish(&state, result);
|
||||
}
|
||||
321
vendor/udt4/src/common.h
vendored
321
vendor/udt4/src/common.h
vendored
|
|
@ -1,321 +0,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 08/01/2009
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_COMMON_H__
|
||||
#define __UDT_COMMON_H__
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <cstdlib>
|
||||
#include <stdint.h>
|
||||
#include "udt.h"
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
// Windows compability
|
||||
typedef HANDLE pthread_t;
|
||||
typedef HANDLE pthread_mutex_t;
|
||||
typedef HANDLE pthread_cond_t;
|
||||
typedef DWORD pthread_key_t;
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CTimer
|
||||
{
|
||||
public:
|
||||
CTimer();
|
||||
~CTimer();
|
||||
|
||||
public:
|
||||
|
||||
// Functionality:
|
||||
// Sleep for "interval" CCs.
|
||||
// Parameters:
|
||||
// 0) [in] interval: CCs to sleep.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void sleep(uint64_t interval);
|
||||
|
||||
// Functionality:
|
||||
// Seelp until CC "nexttime".
|
||||
// Parameters:
|
||||
// 0) [in] nexttime: next time the caller is waken up.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void sleepto(uint64_t nexttime);
|
||||
|
||||
// Functionality:
|
||||
// Stop the sleep() or sleepto() methods.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void interrupt();
|
||||
|
||||
// Functionality:
|
||||
// trigger the clock for a tick, for better granuality in no_busy_waiting timer.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void tick();
|
||||
|
||||
public:
|
||||
|
||||
// Functionality:
|
||||
// Read the CPU clock cycle into x.
|
||||
// Parameters:
|
||||
// 0) [out] x: to record cpu clock cycles.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
static void rdtsc(uint64_t &x);
|
||||
|
||||
// Functionality:
|
||||
// return the CPU frequency.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// CPU frequency.
|
||||
|
||||
static uint64_t getCPUFrequency();
|
||||
|
||||
// Functionality:
|
||||
// check the current time, 64bit, in microseconds.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// current time in microseconds.
|
||||
|
||||
static uint64_t getTime();
|
||||
|
||||
// Functionality:
|
||||
// trigger an event such as new connection, close, new data, etc. for "select" call.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
static void triggerEvent();
|
||||
|
||||
// Functionality:
|
||||
// wait for an event to br triggered by "triggerEvent".
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
static void waitForEvent();
|
||||
|
||||
// Functionality:
|
||||
// sleep for a short interval. exact sleep time does not matter
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
static void sleep();
|
||||
|
||||
private:
|
||||
uint64_t getTimeInMicroSec();
|
||||
|
||||
private:
|
||||
uint64_t m_ullSchedTime; // next schedulled time
|
||||
|
||||
pthread_cond_t m_TickCond;
|
||||
pthread_mutex_t m_TickLock;
|
||||
|
||||
static pthread_cond_t m_EventCond;
|
||||
static pthread_mutex_t m_EventLock;
|
||||
|
||||
private:
|
||||
static uint64_t s_ullCPUFrequency; // CPU frequency : clock cycles per microsecond
|
||||
static uint64_t readCPUFrequency();
|
||||
static bool m_bUseMicroSecond; // No higher resolution timer available, use gettimeofday().
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CGuard
|
||||
{
|
||||
public:
|
||||
CGuard(pthread_mutex_t& lock);
|
||||
~CGuard();
|
||||
|
||||
public:
|
||||
static void enterCS(pthread_mutex_t& lock);
|
||||
static void leaveCS(pthread_mutex_t& lock);
|
||||
|
||||
static void createMutex(pthread_mutex_t& lock);
|
||||
static void releaseMutex(pthread_mutex_t& lock);
|
||||
|
||||
static void createCond(pthread_cond_t& cond);
|
||||
static void releaseCond(pthread_cond_t& cond);
|
||||
|
||||
private:
|
||||
pthread_mutex_t& m_Mutex; // Alias name of the mutex to be protected
|
||||
int m_iLocked; // Locking status
|
||||
|
||||
CGuard& operator=(const CGuard&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// UDT Sequence Number 0 - (2^31 - 1)
|
||||
|
||||
// seqcmp: compare two seq#, considering the wraping
|
||||
// seqlen: length from the 1st to the 2nd seq#, including both
|
||||
// seqoff: offset from the 2nd to the 1st seq#
|
||||
// incseq: increase the seq# by 1
|
||||
// decseq: decrease the seq# by 1
|
||||
// incseq: increase the seq# by a given offset
|
||||
|
||||
class CSeqNo
|
||||
{
|
||||
public:
|
||||
inline static int seqcmp(int32_t seq1, int32_t seq2)
|
||||
{return (abs(seq1 - seq2) < m_iSeqNoTH) ? (seq1 - seq2) : (seq2 - seq1);}
|
||||
|
||||
inline static int seqlen(int32_t seq1, int32_t seq2)
|
||||
{return (seq1 <= seq2) ? (seq2 - seq1 + 1) : (seq2 - seq1 + m_iMaxSeqNo + 2);}
|
||||
|
||||
inline static int seqoff(int32_t seq1, int32_t seq2)
|
||||
{
|
||||
if (abs(seq1 - seq2) < m_iSeqNoTH)
|
||||
return seq2 - seq1;
|
||||
|
||||
if (seq1 < seq2)
|
||||
return seq2 - seq1 - m_iMaxSeqNo - 1;
|
||||
|
||||
return seq2 - seq1 + m_iMaxSeqNo + 1;
|
||||
}
|
||||
|
||||
inline static int32_t incseq(int32_t seq)
|
||||
{return (seq == m_iMaxSeqNo) ? 0 : seq + 1;}
|
||||
|
||||
inline static int32_t decseq(int32_t seq)
|
||||
{return (seq == 0) ? m_iMaxSeqNo : seq - 1;}
|
||||
|
||||
inline static int32_t incseq(int32_t seq, int32_t inc)
|
||||
{return (m_iMaxSeqNo - seq >= inc) ? seq + inc : seq - m_iMaxSeqNo + inc - 1;}
|
||||
|
||||
public:
|
||||
static const int32_t m_iSeqNoTH; // threshold for comparing seq. no.
|
||||
static const int32_t m_iMaxSeqNo; // maximum sequence number used in UDT
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// UDT ACK Sub-sequence Number: 0 - (2^31 - 1)
|
||||
|
||||
class CAckNo
|
||||
{
|
||||
public:
|
||||
inline static int32_t incack(int32_t ackno)
|
||||
{return (ackno == m_iMaxAckSeqNo) ? 0 : ackno + 1;}
|
||||
|
||||
public:
|
||||
static const int32_t m_iMaxAckSeqNo; // maximum ACK sub-sequence number used in UDT
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// UDT Message Number: 0 - (2^29 - 1)
|
||||
|
||||
class CMsgNo
|
||||
{
|
||||
public:
|
||||
inline static int msgcmp(int32_t msgno1, int32_t msgno2)
|
||||
{return (abs(msgno1 - msgno2) < m_iMsgNoTH) ? (msgno1 - msgno2) : (msgno2 - msgno1);}
|
||||
|
||||
inline static int msglen(int32_t msgno1, int32_t msgno2)
|
||||
{return (msgno1 <= msgno2) ? (msgno2 - msgno1 + 1) : (msgno2 - msgno1 + m_iMaxMsgNo + 2);}
|
||||
|
||||
inline static int msgoff(int32_t msgno1, int32_t msgno2)
|
||||
{
|
||||
if (abs(msgno1 - msgno2) < m_iMsgNoTH)
|
||||
return msgno2 - msgno1;
|
||||
|
||||
if (msgno1 < msgno2)
|
||||
return msgno2 - msgno1 - m_iMaxMsgNo - 1;
|
||||
|
||||
return msgno2 - msgno1 + m_iMaxMsgNo + 1;
|
||||
}
|
||||
|
||||
inline static int32_t incmsg(int32_t msgno)
|
||||
{return (msgno == m_iMaxMsgNo) ? 0 : msgno + 1;}
|
||||
|
||||
public:
|
||||
static const int32_t m_iMsgNoTH; // threshold for comparing msg. no.
|
||||
static const int32_t m_iMaxMsgNo; // maximum message number used in UDT
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CIPAddress
|
||||
{
|
||||
static bool ipcmp(const sockaddr* addr1, const sockaddr* addr2, int ver = AF_INET);
|
||||
static void ntop(const sockaddr* addr, uint32_t ip[4], int ver = AF_INET);
|
||||
static void pton(sockaddr* addr, const uint32_t ip[4], int ver = AF_INET);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CMD5
|
||||
{
|
||||
static void compute(const char* input, unsigned char result[16]);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
2675
vendor/udt4/src/core.cpp
vendored
2675
vendor/udt4/src/core.cpp
vendored
File diff suppressed because it is too large
Load diff
458
vendor/udt4/src/core.h
vendored
458
vendor/udt4/src/core.h
vendored
|
|
@ -1,458 +0,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 02/28/2012
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_CORE_H__
|
||||
#define __UDT_CORE_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
#include "buffer.h"
|
||||
#include "window.h"
|
||||
#include "packet.h"
|
||||
#include "channel.h"
|
||||
#include "api.h"
|
||||
#include "ccc.h"
|
||||
#include "cache.h"
|
||||
#include "queue.h"
|
||||
|
||||
enum UDTSockType {UDT_STREAM = 1, UDT_DGRAM};
|
||||
|
||||
class CUDT
|
||||
{
|
||||
friend class CUDTSocket;
|
||||
friend class CUDTUnited;
|
||||
friend class CCC;
|
||||
friend struct CUDTComp;
|
||||
friend class CCache<CInfoBlock>;
|
||||
friend class CRendezvousQueue;
|
||||
friend class CSndQueue;
|
||||
friend class CRcvQueue;
|
||||
friend class CSndUList;
|
||||
friend class CRcvUList;
|
||||
|
||||
private: // constructor and desctructor
|
||||
CUDT();
|
||||
CUDT(const CUDT& ancestor);
|
||||
const CUDT& operator=(const CUDT&) {return *this;}
|
||||
~CUDT();
|
||||
|
||||
public: //API
|
||||
static int startup();
|
||||
static int cleanup();
|
||||
static UDTSOCKET socket(int af, int type = SOCK_STREAM, int protocol = 0);
|
||||
static int bind(UDTSOCKET u, const sockaddr* name, int namelen);
|
||||
static int bind(UDTSOCKET u, UDPSOCKET udpsock);
|
||||
static int listen(UDTSOCKET u, int backlog);
|
||||
static UDTSOCKET accept(UDTSOCKET u, sockaddr* addr, int* addrlen);
|
||||
static int connect(UDTSOCKET u, const sockaddr* name, int namelen);
|
||||
static int close(UDTSOCKET u);
|
||||
static int getpeername(UDTSOCKET u, sockaddr* name, int* namelen);
|
||||
static int getsockname(UDTSOCKET u, sockaddr* name, int* namelen);
|
||||
static int getsockopt(UDTSOCKET u, int level, UDTOpt optname, void* optval, int* optlen);
|
||||
static int setsockopt(UDTSOCKET u, int level, UDTOpt optname, const void* optval, int optlen);
|
||||
static int send(UDTSOCKET u, const char* buf, int len, int flags);
|
||||
static int recv(UDTSOCKET u, char* buf, int len, int flags);
|
||||
static int sendmsg(UDTSOCKET u, const char* buf, int len, int ttl = -1, bool inorder = false);
|
||||
static int recvmsg(UDTSOCKET u, char* buf, int len);
|
||||
static int64_t sendfile(UDTSOCKET u, std::fstream& ifs, int64_t& offset, int64_t size, int block = 364000);
|
||||
static int64_t recvfile(UDTSOCKET u, std::fstream& ofs, int64_t& offset, int64_t size, int block = 7280000);
|
||||
static int select(int nfds, ud_set* readfds, ud_set* writefds, ud_set* exceptfds, const timeval* timeout);
|
||||
static int selectEx(const std::vector<UDTSOCKET>& fds, std::vector<UDTSOCKET>* readfds, std::vector<UDTSOCKET>* writefds, std::vector<UDTSOCKET>* exceptfds, int64_t msTimeOut);
|
||||
static int epoll_create();
|
||||
static int epoll_add_usock(const int eid, const UDTSOCKET u, const int* events = NULL);
|
||||
static int epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
|
||||
static int epoll_remove_usock(const int eid, const UDTSOCKET u);
|
||||
static int epoll_remove_ssock(const int eid, const SYSSOCKET s);
|
||||
static int epoll_wait(const int eid, std::set<UDTSOCKET>* readfds, std::set<UDTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds = NULL, std::set<SYSSOCKET>* wrfds = NULL);
|
||||
static int epoll_release(const int eid);
|
||||
static CUDTException& getlasterror();
|
||||
static int perfmon(UDTSOCKET u, CPerfMon* perf, bool clear = true);
|
||||
static UDTSTATUS getsockstate(UDTSOCKET u);
|
||||
|
||||
public: // internal API
|
||||
static CUDT* getUDTHandle(UDTSOCKET u);
|
||||
|
||||
private:
|
||||
// Functionality:
|
||||
// initialize a UDT entity and bind to a local address.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void open();
|
||||
|
||||
// Functionality:
|
||||
// Start listening to any connection request.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void listen();
|
||||
|
||||
// Functionality:
|
||||
// Connect to a UDT entity listening at address "peer".
|
||||
// Parameters:
|
||||
// 0) [in] peer: The address of the listening UDT entity.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void connect(const sockaddr* peer);
|
||||
|
||||
// Functionality:
|
||||
// Process the response handshake packet.
|
||||
// Parameters:
|
||||
// 0) [in] pkt: handshake packet.
|
||||
// Returned value:
|
||||
// Return 0 if connected, positive value if connection is in progress, otherwise error code.
|
||||
|
||||
int connect(const CPacket& pkt) throw ();
|
||||
|
||||
// Functionality:
|
||||
// Connect to a UDT entity listening at address "peer", which has sent "hs" request.
|
||||
// Parameters:
|
||||
// 0) [in] peer: The address of the listening UDT entity.
|
||||
// 1) [in/out] hs: The handshake information sent by the peer side (in), negotiated value (out).
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void connect(const sockaddr* peer, CHandShake* hs);
|
||||
|
||||
// Functionality:
|
||||
// Close the opened UDT entity.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void close();
|
||||
|
||||
// Functionality:
|
||||
// Request UDT to send out a data block "data" with size of "len".
|
||||
// Parameters:
|
||||
// 0) [in] data: The address of the application data to be sent.
|
||||
// 1) [in] len: The size of the data block.
|
||||
// Returned value:
|
||||
// Actual size of data sent.
|
||||
|
||||
int send(const char* data, int len);
|
||||
|
||||
// Functionality:
|
||||
// Request UDT to receive data to a memory block "data" with size of "len".
|
||||
// Parameters:
|
||||
// 0) [out] data: data received.
|
||||
// 1) [in] len: The desired size of data to be received.
|
||||
// Returned value:
|
||||
// Actual size of data received.
|
||||
|
||||
int recv(char* data, int len);
|
||||
|
||||
// Functionality:
|
||||
// send a message of a memory block "data" with size of "len".
|
||||
// Parameters:
|
||||
// 0) [out] data: data received.
|
||||
// 1) [in] len: The desired size of data to be received.
|
||||
// 2) [in] ttl: the time-to-live of the message.
|
||||
// 3) [in] inorder: if the message should be delivered in order.
|
||||
// Returned value:
|
||||
// Actual size of data sent.
|
||||
|
||||
int sendmsg(const char* data, int len, int ttl, bool inorder);
|
||||
|
||||
// Functionality:
|
||||
// Receive a message to buffer "data".
|
||||
// Parameters:
|
||||
// 0) [out] data: data received.
|
||||
// 1) [in] len: size of the buffer.
|
||||
// Returned value:
|
||||
// Actual size of data received.
|
||||
|
||||
int recvmsg(char* data, int len);
|
||||
|
||||
// Functionality:
|
||||
// Request UDT to send out a file described as "fd", starting from "offset", with size of "size".
|
||||
// Parameters:
|
||||
// 0) [in] ifs: The input file stream.
|
||||
// 1) [in, out] offset: From where to read and send data; output is the new offset when the call returns.
|
||||
// 2) [in] size: How many data to be sent.
|
||||
// 3) [in] block: size of block per read from disk
|
||||
// Returned value:
|
||||
// Actual size of data sent.
|
||||
|
||||
int64_t sendfile(std::fstream& ifs, int64_t& offset, int64_t size, int block = 366000);
|
||||
|
||||
// Functionality:
|
||||
// Request UDT to receive data into a file described as "fd", starting from "offset", with expected size of "size".
|
||||
// Parameters:
|
||||
// 0) [out] ofs: The output file stream.
|
||||
// 1) [in, out] offset: From where to write data; output is the new offset when the call returns.
|
||||
// 2) [in] size: How many data to be received.
|
||||
// 3) [in] block: size of block per write to disk
|
||||
// Returned value:
|
||||
// Actual size of data received.
|
||||
|
||||
int64_t recvfile(std::fstream& ofs, int64_t& offset, int64_t size, int block = 7320000);
|
||||
|
||||
// Functionality:
|
||||
// Configure UDT options.
|
||||
// Parameters:
|
||||
// 0) [in] optName: The enum name of a UDT option.
|
||||
// 1) [in] optval: The value to be set.
|
||||
// 2) [in] optlen: size of "optval".
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void setOpt(UDTOpt optName, const void* optval, int optlen);
|
||||
|
||||
// Functionality:
|
||||
// Read UDT options.
|
||||
// Parameters:
|
||||
// 0) [in] optName: The enum name of a UDT option.
|
||||
// 1) [in] optval: The value to be returned.
|
||||
// 2) [out] optlen: size of "optval".
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void getOpt(UDTOpt optName, void* optval, int& optlen);
|
||||
|
||||
// Functionality:
|
||||
// read the performance data since last sample() call.
|
||||
// Parameters:
|
||||
// 0) [in, out] perf: pointer to a CPerfMon structure to record the performance data.
|
||||
// 1) [in] clear: flag to decide if the local performance trace should be cleared.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void sample(CPerfMon* perf, bool clear = true);
|
||||
|
||||
private:
|
||||
static CUDTUnited s_UDTUnited; // UDT global management base
|
||||
|
||||
public:
|
||||
static const UDTSOCKET INVALID_SOCK; // invalid socket descriptor
|
||||
static const int ERROR; // socket api error returned value
|
||||
|
||||
private: // Identification
|
||||
UDTSOCKET m_SocketID; // UDT socket number
|
||||
UDTSockType m_iSockType; // Type of the UDT connection (SOCK_STREAM or SOCK_DGRAM)
|
||||
UDTSOCKET m_PeerID; // peer id, for multiplexer
|
||||
static const int m_iVersion; // UDT version, for compatibility use
|
||||
|
||||
private: // Packet sizes
|
||||
int m_iPktSize; // Maximum/regular packet size, in bytes
|
||||
int m_iPayloadSize; // Maximum/regular payload size, in bytes
|
||||
|
||||
private: // Options
|
||||
int m_iMSS; // Maximum Segment Size, in bytes
|
||||
bool m_bSynSending; // Sending syncronization mode
|
||||
bool m_bSynRecving; // Receiving syncronization mode
|
||||
int m_iFlightFlagSize; // Maximum number of packets in flight from the peer side
|
||||
int m_iSndBufSize; // Maximum UDT sender buffer size
|
||||
int m_iRcvBufSize; // Maximum UDT receiver buffer size
|
||||
linger m_Linger; // Linger information on close
|
||||
int m_iUDPSndBufSize; // UDP sending buffer size
|
||||
int m_iUDPRcvBufSize; // UDP receiving buffer size
|
||||
int m_iIPversion; // IP version
|
||||
bool m_bRendezvous; // Rendezvous connection mode
|
||||
int m_iSndTimeOut; // sending timeout in milliseconds
|
||||
int m_iRcvTimeOut; // receiving timeout in milliseconds
|
||||
bool m_bReuseAddr; // reuse an exiting port or not, for UDP multiplexer
|
||||
int64_t m_llMaxBW; // maximum data transfer rate (threshold)
|
||||
|
||||
private: // congestion control
|
||||
CCCVirtualFactory* m_pCCFactory; // Factory class to create a specific CC instance
|
||||
CCC* m_pCC; // congestion control class
|
||||
CCache<CInfoBlock>* m_pCache; // network information cache
|
||||
|
||||
private: // Status
|
||||
volatile bool m_bListening; // If the UDT entit is listening to connection
|
||||
volatile bool m_bConnecting; // The short phase when connect() is called but not yet completed
|
||||
volatile bool m_bConnected; // Whether the connection is on or off
|
||||
volatile bool m_bClosing; // If the UDT entity is closing
|
||||
volatile bool m_bShutdown; // If the peer side has shutdown the connection
|
||||
volatile bool m_bBroken; // If the connection has been broken
|
||||
volatile bool m_bPeerHealth; // If the peer status is normal
|
||||
bool m_bOpened; // If the UDT entity has been opened
|
||||
int m_iBrokenCounter; // a counter (number of GC checks) to let the GC tag this socket as disconnected
|
||||
|
||||
int m_iEXPCount; // Expiration counter
|
||||
int m_iBandwidth; // Estimated bandwidth, number of packets per second
|
||||
int m_iRTT; // RTT, in microseconds
|
||||
int m_iRTTVar; // RTT variance
|
||||
int m_iDeliveryRate; // Packet arrival rate at the receiver side
|
||||
|
||||
uint64_t m_ullLingerExpiration; // Linger expiration time (for GC to close a socket with data in sending buffer)
|
||||
|
||||
CHandShake m_ConnReq; // connection request
|
||||
CHandShake m_ConnRes; // connection response
|
||||
int64_t m_llLastReqTime; // last time when a connection request is sent
|
||||
|
||||
private: // Sending related data
|
||||
CSndBuffer* m_pSndBuffer; // Sender buffer
|
||||
CSndLossList* m_pSndLossList; // Sender loss list
|
||||
CPktTimeWindow* m_pSndTimeWindow; // Packet sending time window
|
||||
|
||||
volatile uint64_t m_ullInterval; // Inter-packet time, in CPU clock cycles
|
||||
uint64_t m_ullTimeDiff; // aggregate difference in inter-packet time
|
||||
|
||||
volatile int m_iFlowWindowSize; // Flow control window size
|
||||
volatile double m_dCongestionWindow; // congestion window size
|
||||
|
||||
volatile int32_t m_iSndLastAck; // Last ACK received
|
||||
volatile int32_t m_iSndLastDataAck; // The real last ACK that updates the sender buffer and loss list
|
||||
volatile int32_t m_iSndCurrSeqNo; // The largest sequence number that has been sent
|
||||
int32_t m_iLastDecSeq; // Sequence number sent last decrease occurs
|
||||
int32_t m_iSndLastAck2; // Last ACK2 sent back
|
||||
uint64_t m_ullSndLastAck2Time; // The time when last ACK2 was sent back
|
||||
|
||||
int32_t m_iISN; // Initial Sequence Number
|
||||
|
||||
void CCUpdate();
|
||||
|
||||
private: // Receiving related data
|
||||
CRcvBuffer* m_pRcvBuffer; // Receiver buffer
|
||||
CRcvLossList* m_pRcvLossList; // Receiver loss list
|
||||
CACKWindow* m_pACKWindow; // ACK history window
|
||||
CPktTimeWindow* m_pRcvTimeWindow; // Packet arrival time window
|
||||
|
||||
int32_t m_iRcvLastAck; // Last sent ACK
|
||||
uint64_t m_ullLastAckTime; // Timestamp of last ACK
|
||||
int32_t m_iRcvLastAckAck; // Last sent ACK that has been acknowledged
|
||||
int32_t m_iAckSeqNo; // Last ACK sequence number
|
||||
int32_t m_iRcvCurrSeqNo; // Largest received sequence number
|
||||
|
||||
uint64_t m_ullLastWarningTime; // Last time that a warning message is sent
|
||||
|
||||
int32_t m_iPeerISN; // Initial Sequence Number of the peer side
|
||||
|
||||
private: // synchronization: mutexes and conditions
|
||||
pthread_mutex_t m_ConnectionLock; // used to synchronize connection operation
|
||||
|
||||
pthread_cond_t m_SendBlockCond; // used to block "send" call
|
||||
pthread_mutex_t m_SendBlockLock; // lock associated to m_SendBlockCond
|
||||
|
||||
pthread_mutex_t m_AckLock; // used to protected sender's loss list when processing ACK
|
||||
|
||||
pthread_cond_t m_RecvDataCond; // used to block "recv" when there is no data
|
||||
pthread_mutex_t m_RecvDataLock; // lock associated to m_RecvDataCond
|
||||
|
||||
pthread_mutex_t m_SendLock; // used to synchronize "send" call
|
||||
pthread_mutex_t m_RecvLock; // used to synchronize "recv" call
|
||||
|
||||
void initSynch();
|
||||
void destroySynch();
|
||||
void releaseSynch();
|
||||
|
||||
private: // Generation and processing of packets
|
||||
void sendCtrl(int pkttype, void* lparam = NULL, void* rparam = NULL, int size = 0);
|
||||
void processCtrl(CPacket& ctrlpkt);
|
||||
int packData(CPacket& packet, uint64_t& ts);
|
||||
int processData(CUnit* unit);
|
||||
int listen(sockaddr* addr, CPacket& packet);
|
||||
|
||||
private: // Trace
|
||||
uint64_t m_StartTime; // timestamp when the UDT entity is started
|
||||
int64_t m_llSentTotal; // total number of sent data packets, including retransmissions
|
||||
int64_t m_llRecvTotal; // total number of received packets
|
||||
int m_iSndLossTotal; // total number of lost packets (sender side)
|
||||
int m_iRcvLossTotal; // total number of lost packets (receiver side)
|
||||
int m_iRetransTotal; // total number of retransmitted packets
|
||||
int m_iSentACKTotal; // total number of sent ACK packets
|
||||
int m_iRecvACKTotal; // total number of received ACK packets
|
||||
int m_iSentNAKTotal; // total number of sent NAK packets
|
||||
int m_iRecvNAKTotal; // total number of received NAK packets
|
||||
int64_t m_llSndDurationTotal; // total real time for sending
|
||||
|
||||
uint64_t m_LastSampleTime; // last performance sample time
|
||||
int64_t m_llTraceSent; // number of pakctes sent in the last trace interval
|
||||
int64_t m_llTraceRecv; // number of pakctes received in the last trace interval
|
||||
int m_iTraceSndLoss; // number of lost packets in the last trace interval (sender side)
|
||||
int m_iTraceRcvLoss; // number of lost packets in the last trace interval (receiver side)
|
||||
int m_iTraceRetrans; // number of retransmitted packets in the last trace interval
|
||||
int m_iSentACK; // number of ACKs sent in the last trace interval
|
||||
int m_iRecvACK; // number of ACKs received in the last trace interval
|
||||
int m_iSentNAK; // number of NAKs sent in the last trace interval
|
||||
int m_iRecvNAK; // number of NAKs received in the last trace interval
|
||||
int64_t m_llSndDuration; // real time for sending
|
||||
int64_t m_llSndDurationCounter; // timers to record the sending duration
|
||||
|
||||
private: // Timers
|
||||
uint64_t m_ullCPUFrequency; // CPU clock frequency, used for Timer, ticks per microsecond
|
||||
|
||||
static const int m_iSYNInterval; // Periodical Rate Control Interval, 10000 microsecond
|
||||
static const int m_iSelfClockInterval; // ACK interval for self-clocking
|
||||
|
||||
uint64_t m_ullNextACKTime; // Next ACK time, in CPU clock cycles, same below
|
||||
uint64_t m_ullNextNAKTime; // Next NAK time
|
||||
|
||||
volatile uint64_t m_ullSYNInt; // SYN interval
|
||||
volatile uint64_t m_ullACKInt; // ACK interval
|
||||
volatile uint64_t m_ullNAKInt; // NAK interval
|
||||
volatile uint64_t m_ullLastRspTime; // time stamp of last response from the peer
|
||||
|
||||
uint64_t m_ullMinNakInt; // NAK timeout lower bound; too small value can cause unnecessary retransmission
|
||||
uint64_t m_ullMinExpInt; // timeout lower bound threshold: too small timeout can cause problem
|
||||
|
||||
int m_iPktCount; // packet counter for ACK
|
||||
int m_iLightACKCount; // light ACK counter
|
||||
|
||||
uint64_t m_ullTargetTime; // scheduled time of next packet sending
|
||||
|
||||
void checkTimers();
|
||||
|
||||
private: // for UDP multiplexer
|
||||
CSndQueue* m_pSndQueue; // packet sending queue
|
||||
CRcvQueue* m_pRcvQueue; // packet receiving queue
|
||||
sockaddr* m_pPeerAddr; // peer address
|
||||
uint32_t m_piSelfIP[4]; // local UDP IP address
|
||||
CSNode* m_pSNode; // node information for UDT list used in snd queue
|
||||
CRNode* m_pRNode; // node information for UDT list used in rcv queue
|
||||
|
||||
private: // for epoll
|
||||
std::set<int> m_sPollID; // set of epoll ID to trigger
|
||||
void addEPoll(const int eid);
|
||||
void removeEPoll(const int eid);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
367
vendor/udt4/src/epoll.cpp
vendored
367
vendor/udt4/src/epoll.cpp
vendored
|
|
@ -1,367 +0,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 01/01/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef LINUX
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
#include "common.h"
|
||||
#include "epoll.h"
|
||||
#include "udt.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
CEPoll::CEPoll():
|
||||
m_iIDSeed(0)
|
||||
{
|
||||
CGuard::createMutex(m_EPollLock);
|
||||
}
|
||||
|
||||
CEPoll::~CEPoll()
|
||||
{
|
||||
CGuard::releaseMutex(m_EPollLock);
|
||||
}
|
||||
|
||||
int CEPoll::create()
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
int localid = 0;
|
||||
|
||||
#ifdef LINUX
|
||||
localid = epoll_create(1024);
|
||||
if (localid < 0)
|
||||
throw CUDTException(-1, 0, errno);
|
||||
#else
|
||||
// on BSD, use kqueue
|
||||
// on Solaris, use /dev/poll
|
||||
// on Windows, select
|
||||
#endif
|
||||
|
||||
if (++ m_iIDSeed >= 0x7FFFFFFF)
|
||||
m_iIDSeed = 0;
|
||||
|
||||
CEPollDesc desc;
|
||||
desc.m_iID = m_iIDSeed;
|
||||
desc.m_iLocalID = localid;
|
||||
m_mPolls[desc.m_iID] = desc;
|
||||
|
||||
return desc.m_iID;
|
||||
}
|
||||
|
||||
int CEPoll::add_usock(const int eid, const UDTSOCKET& u, const int* events)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(5, 13);
|
||||
|
||||
if (!events || (*events & UDT_EPOLL_IN))
|
||||
p->second.m_sUDTSocksIn.insert(u);
|
||||
if (!events || (*events & UDT_EPOLL_OUT))
|
||||
p->second.m_sUDTSocksOut.insert(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(5, 13);
|
||||
|
||||
#ifdef LINUX
|
||||
epoll_event ev;
|
||||
memset(&ev, 0, sizeof(epoll_event));
|
||||
|
||||
if (NULL == events)
|
||||
ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
|
||||
else
|
||||
{
|
||||
ev.events = 0;
|
||||
if (*events & UDT_EPOLL_IN)
|
||||
ev.events |= EPOLLIN;
|
||||
if (*events & UDT_EPOLL_OUT)
|
||||
ev.events |= EPOLLOUT;
|
||||
if (*events & UDT_EPOLL_ERR)
|
||||
ev.events |= EPOLLERR;
|
||||
}
|
||||
|
||||
ev.data.fd = s;
|
||||
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_ADD, s, &ev) < 0)
|
||||
throw CUDTException();
|
||||
#endif
|
||||
|
||||
p->second.m_sLocals.insert(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::remove_usock(const int eid, const UDTSOCKET& u)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(5, 13);
|
||||
|
||||
p->second.m_sUDTSocksIn.erase(u);
|
||||
p->second.m_sUDTSocksOut.erase(u);
|
||||
p->second.m_sUDTSocksEx.erase(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
throw CUDTException(5, 13);
|
||||
|
||||
#ifdef LINUX
|
||||
epoll_event ev; // ev is ignored, for compatibility with old Linux kernel only.
|
||||
if (::epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_DEL, s, &ev) < 0)
|
||||
throw CUDTException();
|
||||
#endif
|
||||
|
||||
p->second.m_sLocals.erase(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::wait(const int eid, set<UDTSOCKET>* readfds, set<UDTSOCKET>* writefds, int64_t msTimeOut, set<SYSSOCKET>* lrfds, set<SYSSOCKET>* lwfds)
|
||||
{
|
||||
// if all fields is NULL and waiting time is infinite, then this would be a deadlock
|
||||
if (!readfds && !writefds && !lrfds && lwfds && (msTimeOut < 0))
|
||||
throw CUDTException(5, 3, 0);
|
||||
|
||||
// Clear these sets in case the app forget to do it.
|
||||
if (readfds) readfds->clear();
|
||||
if (writefds) writefds->clear();
|
||||
if (lrfds) lrfds->clear();
|
||||
if (lwfds) lwfds->clear();
|
||||
|
||||
int total = 0;
|
||||
|
||||
int64_t entertime = CTimer::getTime();
|
||||
while (true)
|
||||
{
|
||||
CGuard::enterCS(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
|
||||
if (p == m_mPolls.end())
|
||||
{
|
||||
CGuard::leaveCS(m_EPollLock);
|
||||
throw CUDTException(5, 13);
|
||||
}
|
||||
|
||||
if (p->second.m_sUDTSocksIn.empty() && p->second.m_sUDTSocksOut.empty() && p->second.m_sLocals.empty() && (msTimeOut < 0))
|
||||
{
|
||||
// no socket is being monitored, this may be a deadlock
|
||||
CGuard::leaveCS(m_EPollLock);
|
||||
throw CUDTException(5, 3);
|
||||
}
|
||||
|
||||
// Sockets with exceptions are returned to both read and write sets.
|
||||
if ((NULL != readfds) && (!p->second.m_sUDTReads.empty() || !p->second.m_sUDTExcepts.empty()))
|
||||
{
|
||||
*readfds = p->second.m_sUDTReads;
|
||||
for (set<UDTSOCKET>::const_iterator i = p->second.m_sUDTExcepts.begin(); i != p->second.m_sUDTExcepts.end(); ++ i)
|
||||
readfds->insert(*i);
|
||||
total += p->second.m_sUDTReads.size() + p->second.m_sUDTExcepts.size();
|
||||
}
|
||||
if ((NULL != writefds) && (!p->second.m_sUDTWrites.empty() || !p->second.m_sUDTExcepts.empty()))
|
||||
{
|
||||
*writefds = p->second.m_sUDTWrites;
|
||||
for (set<UDTSOCKET>::const_iterator i = p->second.m_sUDTExcepts.begin(); i != p->second.m_sUDTExcepts.end(); ++ i)
|
||||
writefds->insert(*i);
|
||||
total += p->second.m_sUDTWrites.size() + p->second.m_sUDTExcepts.size();
|
||||
}
|
||||
|
||||
if (lrfds || lwfds)
|
||||
{
|
||||
#ifdef LINUX
|
||||
const int max_events = p->second.m_sLocals.size();
|
||||
epoll_event ev[max_events];
|
||||
int nfds = ::epoll_wait(p->second.m_iLocalID, ev, max_events, 0);
|
||||
|
||||
for (int i = 0; i < nfds; ++ i)
|
||||
{
|
||||
if ((NULL != lrfds) && (ev[i].events & EPOLLIN))
|
||||
{
|
||||
lrfds->insert(ev[i].data.fd);
|
||||
++ total;
|
||||
}
|
||||
if ((NULL != lwfds) && (ev[i].events & EPOLLOUT))
|
||||
{
|
||||
lwfds->insert(ev[i].data.fd);
|
||||
++ total;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//currently "select" is used for all non-Linux platforms.
|
||||
//faster approaches can be applied for specific systems in the future.
|
||||
|
||||
//"select" has a limitation on the number of sockets
|
||||
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
|
||||
for (set<SYSSOCKET>::const_iterator i = p->second.m_sLocals.begin(); i != p->second.m_sLocals.end(); ++ i)
|
||||
{
|
||||
if (lrfds)
|
||||
FD_SET(*i, &readfds);
|
||||
if (lwfds)
|
||||
FD_SET(*i, &writefds);
|
||||
}
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
if (::select(0, &readfds, &writefds, NULL, &tv) > 0)
|
||||
{
|
||||
for (set<SYSSOCKET>::const_iterator i = p->second.m_sLocals.begin(); i != p->second.m_sLocals.end(); ++ i)
|
||||
{
|
||||
if (lrfds && FD_ISSET(*i, &readfds))
|
||||
{
|
||||
lrfds->insert(*i);
|
||||
++ total;
|
||||
}
|
||||
if (lwfds && FD_ISSET(*i, &writefds))
|
||||
{
|
||||
lwfds->insert(*i);
|
||||
++ total;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CGuard::leaveCS(m_EPollLock);
|
||||
|
||||
if (total > 0)
|
||||
return total;
|
||||
|
||||
if ((msTimeOut >= 0) && (int64_t(CTimer::getTime() - entertime) >= msTimeOut * 1000LL))
|
||||
throw CUDTException(6, 3, 0);
|
||||
|
||||
CTimer::waitForEvent();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CEPoll::release(const int eid)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator i = m_mPolls.find(eid);
|
||||
if (i == m_mPolls.end())
|
||||
throw CUDTException(5, 13);
|
||||
|
||||
#ifdef LINUX
|
||||
// release local/system epoll descriptor
|
||||
::close(i->second.m_iLocalID);
|
||||
#endif
|
||||
|
||||
m_mPolls.erase(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void update_epoll_sets(const UDTSOCKET& uid, const set<UDTSOCKET>& watch, set<UDTSOCKET>& result, bool enable)
|
||||
{
|
||||
if (enable && (watch.find(uid) != watch.end()))
|
||||
{
|
||||
result.insert(uid);
|
||||
}
|
||||
else if (!enable)
|
||||
{
|
||||
result.erase(uid);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int CEPoll::update_events(const UDTSOCKET& uid, std::set<int>& eids, int events, bool enable)
|
||||
{
|
||||
CGuard pg(m_EPollLock);
|
||||
|
||||
map<int, CEPollDesc>::iterator p;
|
||||
|
||||
vector<int> lost;
|
||||
for (set<int>::iterator i = eids.begin(); i != eids.end(); ++ i)
|
||||
{
|
||||
p = m_mPolls.find(*i);
|
||||
if (p == m_mPolls.end())
|
||||
{
|
||||
lost.push_back(*i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((events & UDT_EPOLL_IN) != 0)
|
||||
update_epoll_sets(uid, p->second.m_sUDTSocksIn, p->second.m_sUDTReads, enable);
|
||||
if ((events & UDT_EPOLL_OUT) != 0)
|
||||
update_epoll_sets(uid, p->second.m_sUDTSocksOut, p->second.m_sUDTWrites, enable);
|
||||
if ((events & UDT_EPOLL_ERR) != 0)
|
||||
update_epoll_sets(uid, p->second.m_sUDTSocksEx, p->second.m_sUDTExcepts, enable);
|
||||
}
|
||||
}
|
||||
|
||||
for (vector<int>::iterator i = lost.begin(); i != lost.end(); ++ i)
|
||||
eids.erase(*i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
173
vendor/udt4/src/epoll.h
vendored
173
vendor/udt4/src/epoll.h
vendored
|
|
@ -1,173 +0,0 @@
|
|||
/*****************************************************************************
|
||||
Copyright (c) 2001 - 2010, 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 08/20/2010
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_EPOLL_H__
|
||||
#define __UDT_EPOLL_H__
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "udt.h"
|
||||
|
||||
|
||||
struct CEPollDesc
|
||||
{
|
||||
int m_iID; // epoll ID
|
||||
std::set<UDTSOCKET> m_sUDTSocksOut; // set of UDT sockets waiting for write events
|
||||
std::set<UDTSOCKET> m_sUDTSocksIn; // set of UDT sockets waiting for read events
|
||||
std::set<UDTSOCKET> m_sUDTSocksEx; // set of UDT sockets waiting for exceptions
|
||||
|
||||
int m_iLocalID; // local system epoll ID
|
||||
std::set<SYSSOCKET> m_sLocals; // set of local (non-UDT) descriptors
|
||||
|
||||
std::set<UDTSOCKET> m_sUDTWrites; // UDT sockets ready for write
|
||||
std::set<UDTSOCKET> m_sUDTReads; // UDT sockets ready for read
|
||||
std::set<UDTSOCKET> m_sUDTExcepts; // UDT sockets with exceptions (connection broken, etc.)
|
||||
};
|
||||
|
||||
class CEPoll
|
||||
{
|
||||
friend class CUDT;
|
||||
friend class CRendezvousQueue;
|
||||
|
||||
public:
|
||||
CEPoll();
|
||||
~CEPoll();
|
||||
|
||||
public: // for CUDTUnited API
|
||||
|
||||
// Functionality:
|
||||
// create a new EPoll.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// new EPoll ID if success, otherwise an error number.
|
||||
|
||||
int create();
|
||||
|
||||
// Functionality:
|
||||
// add a UDT socket to an EPoll.
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// 1) [in] u: UDT Socket ID.
|
||||
// 2) [in] events: events to watch.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number.
|
||||
|
||||
int add_usock(const int eid, const UDTSOCKET& u, const int* events = NULL);
|
||||
|
||||
// Functionality:
|
||||
// add a system socket to an EPoll.
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// 1) [in] s: system Socket ID.
|
||||
// 2) [in] events: events to watch.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number.
|
||||
|
||||
int add_ssock(const int eid, const SYSSOCKET& s, const int* events = NULL);
|
||||
|
||||
// Functionality:
|
||||
// remove a UDT socket event from an EPoll; socket will be removed if no events to watch
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// 1) [in] u: UDT socket ID.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number.
|
||||
|
||||
int remove_usock(const int eid, const UDTSOCKET& u);
|
||||
|
||||
// Functionality:
|
||||
// remove a system socket event from an EPoll; socket will be removed if no events to watch
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// 1) [in] s: system socket ID.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number.
|
||||
|
||||
int remove_ssock(const int eid, const SYSSOCKET& s);
|
||||
|
||||
// Functionality:
|
||||
// wait for EPoll events or timeout.
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// 1) [out] readfds: UDT sockets available for reading.
|
||||
// 2) [out] writefds: UDT sockets available for writing.
|
||||
// 3) [in] msTimeOut: timeout threshold, in milliseconds.
|
||||
// 4) [out] lrfds: system file descriptors for reading.
|
||||
// 5) [out] lwfds: system file descriptors for writing.
|
||||
// Returned value:
|
||||
// number of sockets available for IO.
|
||||
|
||||
int wait(const int eid, std::set<UDTSOCKET>* readfds, std::set<UDTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds, std::set<SYSSOCKET>* lwfds);
|
||||
|
||||
// Functionality:
|
||||
// close and release an EPoll.
|
||||
// Parameters:
|
||||
// 0) [in] eid: EPoll ID.
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number.
|
||||
|
||||
int release(const int eid);
|
||||
|
||||
public: // for CUDT to acknowledge IO status
|
||||
|
||||
// Functionality:
|
||||
// Update events available for a UDT socket.
|
||||
// Parameters:
|
||||
// 0) [in] uid: UDT socket ID.
|
||||
// 1) [in] eids: EPoll IDs to be set
|
||||
// 1) [in] events: Combination of events to update
|
||||
// 1) [in] enable: true -> enable, otherwise disable
|
||||
// Returned value:
|
||||
// 0 if success, otherwise an error number
|
||||
|
||||
int update_events(const UDTSOCKET& uid, std::set<int>& eids, int events, bool enable);
|
||||
|
||||
private:
|
||||
int m_iIDSeed; // seed to generate a new ID
|
||||
pthread_mutex_t m_SeedLock;
|
||||
|
||||
std::map<int, CEPollDesc> m_mPolls; // all epolls
|
||||
pthread_mutex_t m_EPollLock;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
703
vendor/udt4/src/list.cpp
vendored
703
vendor/udt4/src/list.cpp
vendored
|
|
@ -1,703 +0,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 01/22/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
CSndLossList::CSndLossList(int size):
|
||||
m_piData1(NULL),
|
||||
m_piData2(NULL),
|
||||
m_piNext(NULL),
|
||||
m_iHead(-1),
|
||||
m_iLength(0),
|
||||
m_iSize(size),
|
||||
m_iLastInsertPos(-1),
|
||||
m_ListLock()
|
||||
{
|
||||
m_piData1 = new int32_t [m_iSize];
|
||||
m_piData2 = new int32_t [m_iSize];
|
||||
m_piNext = new int [m_iSize];
|
||||
|
||||
// -1 means there is no data in the node
|
||||
for (int i = 0; i < size; ++ i)
|
||||
{
|
||||
m_piData1[i] = -1;
|
||||
m_piData2[i] = -1;
|
||||
}
|
||||
|
||||
// sender list needs mutex protection
|
||||
#ifndef WIN32
|
||||
pthread_mutex_init(&m_ListLock, 0);
|
||||
#else
|
||||
m_ListLock = CreateMutex(NULL, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
CSndLossList::~CSndLossList()
|
||||
{
|
||||
delete [] m_piData1;
|
||||
delete [] m_piData2;
|
||||
delete [] m_piNext;
|
||||
|
||||
#ifndef WIN32
|
||||
pthread_mutex_destroy(&m_ListLock);
|
||||
#else
|
||||
CloseHandle(m_ListLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
int CSndLossList::insert(int32_t seqno1, int32_t seqno2)
|
||||
{
|
||||
CGuard listguard(m_ListLock);
|
||||
|
||||
if (0 == m_iLength)
|
||||
{
|
||||
// insert data into an empty list
|
||||
|
||||
m_iHead = 0;
|
||||
m_piData1[m_iHead] = seqno1;
|
||||
if (seqno2 != seqno1)
|
||||
m_piData2[m_iHead] = seqno2;
|
||||
|
||||
m_piNext[m_iHead] = -1;
|
||||
m_iLastInsertPos = m_iHead;
|
||||
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
|
||||
return m_iLength;
|
||||
}
|
||||
|
||||
// otherwise find the position where the data can be inserted
|
||||
int origlen = m_iLength;
|
||||
int offset = CSeqNo::seqoff(m_piData1[m_iHead], seqno1);
|
||||
int loc = (m_iHead + offset + m_iSize) % m_iSize;
|
||||
|
||||
if (offset < 0)
|
||||
{
|
||||
// Insert data prior to the head pointer
|
||||
|
||||
m_piData1[loc] = seqno1;
|
||||
if (seqno2 != seqno1)
|
||||
m_piData2[loc] = seqno2;
|
||||
|
||||
// new node becomes head
|
||||
m_piNext[loc] = m_iHead;
|
||||
m_iHead = loc;
|
||||
m_iLastInsertPos = loc;
|
||||
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
}
|
||||
else if (offset > 0)
|
||||
{
|
||||
if (seqno1 == m_piData1[loc])
|
||||
{
|
||||
m_iLastInsertPos = loc;
|
||||
|
||||
// first seqno is equivlent, compare the second
|
||||
if (-1 == m_piData2[loc])
|
||||
{
|
||||
if (seqno2 != seqno1)
|
||||
{
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2) - 1;
|
||||
m_piData2[loc] = seqno2;
|
||||
}
|
||||
}
|
||||
else if (CSeqNo::seqcmp(seqno2, m_piData2[loc]) > 0)
|
||||
{
|
||||
// new seq pair is longer than old pair, e.g., insert [3, 7] to [3, 5], becomes [3, 7]
|
||||
m_iLength += CSeqNo::seqlen(m_piData2[loc], seqno2) - 1;
|
||||
m_piData2[loc] = seqno2;
|
||||
}
|
||||
else
|
||||
// Do nothing if it is already there
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// searching the prior node
|
||||
int i;
|
||||
if ((-1 != m_iLastInsertPos) && (CSeqNo::seqcmp(m_piData1[m_iLastInsertPos], seqno1) < 0))
|
||||
i = m_iLastInsertPos;
|
||||
else
|
||||
i = m_iHead;
|
||||
|
||||
while ((-1 != m_piNext[i]) && (CSeqNo::seqcmp(m_piData1[m_piNext[i]], seqno1) < 0))
|
||||
i = m_piNext[i];
|
||||
|
||||
if ((-1 == m_piData2[i]) || (CSeqNo::seqcmp(m_piData2[i], seqno1) < 0))
|
||||
{
|
||||
m_iLastInsertPos = loc;
|
||||
|
||||
// no overlap, create new node
|
||||
m_piData1[loc] = seqno1;
|
||||
if (seqno2 != seqno1)
|
||||
m_piData2[loc] = seqno2;
|
||||
|
||||
m_piNext[loc] = m_piNext[i];
|
||||
m_piNext[i] = loc;
|
||||
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iLastInsertPos = i;
|
||||
|
||||
// overlap, coalesce with prior node, insert(3, 7) to [2, 5], ... becomes [2, 7]
|
||||
if (CSeqNo::seqcmp(m_piData2[i], seqno2) < 0)
|
||||
{
|
||||
m_iLength += CSeqNo::seqlen(m_piData2[i], seqno2) - 1;
|
||||
m_piData2[i] = seqno2;
|
||||
|
||||
loc = i;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iLastInsertPos = m_iHead;
|
||||
|
||||
// insert to head node
|
||||
if (seqno2 != seqno1)
|
||||
{
|
||||
if (-1 == m_piData2[loc])
|
||||
{
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2) - 1;
|
||||
m_piData2[loc] = seqno2;
|
||||
}
|
||||
else if (CSeqNo::seqcmp(seqno2, m_piData2[loc]) > 0)
|
||||
{
|
||||
m_iLength += CSeqNo::seqlen(m_piData2[loc], seqno2) - 1;
|
||||
m_piData2[loc] = seqno2;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// coalesce with next node. E.g., [3, 7], ..., [6, 9] becomes [3, 9]
|
||||
while ((-1 != m_piNext[loc]) && (-1 != m_piData2[loc]))
|
||||
{
|
||||
int i = m_piNext[loc];
|
||||
|
||||
if (CSeqNo::seqcmp(m_piData1[i], CSeqNo::incseq(m_piData2[loc])) <= 0)
|
||||
{
|
||||
// coalesce if there is overlap
|
||||
if (-1 != m_piData2[i])
|
||||
{
|
||||
if (CSeqNo::seqcmp(m_piData2[i], m_piData2[loc]) > 0)
|
||||
{
|
||||
if (CSeqNo::seqcmp(m_piData2[loc], m_piData1[i]) >= 0)
|
||||
m_iLength -= CSeqNo::seqlen(m_piData1[i], m_piData2[loc]);
|
||||
|
||||
m_piData2[loc] = m_piData2[i];
|
||||
}
|
||||
else
|
||||
m_iLength -= CSeqNo::seqlen(m_piData1[i], m_piData2[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_piData1[i] == CSeqNo::incseq(m_piData2[loc]))
|
||||
m_piData2[loc] = m_piData1[i];
|
||||
else
|
||||
m_iLength --;
|
||||
}
|
||||
|
||||
m_piData1[i] = -1;
|
||||
m_piData2[i] = -1;
|
||||
m_piNext[loc] = m_piNext[i];
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return m_iLength - origlen;
|
||||
}
|
||||
|
||||
void CSndLossList::remove(int32_t seqno)
|
||||
{
|
||||
CGuard listguard(m_ListLock);
|
||||
|
||||
if (0 == m_iLength)
|
||||
return;
|
||||
|
||||
// Remove all from the head pointer to a node with a larger seq. no. or the list is empty
|
||||
int offset = CSeqNo::seqoff(m_piData1[m_iHead], seqno);
|
||||
int loc = (m_iHead + offset + m_iSize) % m_iSize;
|
||||
|
||||
if (0 == offset)
|
||||
{
|
||||
// It is the head. Remove the head and point to the next node
|
||||
loc = (loc + 1) % m_iSize;
|
||||
|
||||
if (-1 == m_piData2[m_iHead])
|
||||
loc = m_piNext[m_iHead];
|
||||
else
|
||||
{
|
||||
m_piData1[loc] = CSeqNo::incseq(seqno);
|
||||
if (CSeqNo::seqcmp(m_piData2[m_iHead], CSeqNo::incseq(seqno)) > 0)
|
||||
m_piData2[loc] = m_piData2[m_iHead];
|
||||
|
||||
m_piData2[m_iHead] = -1;
|
||||
|
||||
m_piNext[loc] = m_piNext[m_iHead];
|
||||
}
|
||||
|
||||
m_piData1[m_iHead] = -1;
|
||||
|
||||
if (m_iLastInsertPos == m_iHead)
|
||||
m_iLastInsertPos = -1;
|
||||
|
||||
m_iHead = loc;
|
||||
|
||||
m_iLength --;
|
||||
}
|
||||
else if (offset > 0)
|
||||
{
|
||||
int h = m_iHead;
|
||||
|
||||
if (seqno == m_piData1[loc])
|
||||
{
|
||||
// target node is not empty, remove part/all of the seqno in the node.
|
||||
int temp = loc;
|
||||
loc = (loc + 1) % m_iSize;
|
||||
|
||||
if (-1 == m_piData2[temp])
|
||||
m_iHead = m_piNext[temp];
|
||||
else
|
||||
{
|
||||
// remove part, e.g., [3, 7] becomes [], [4, 7] after remove(3)
|
||||
m_piData1[loc] = CSeqNo::incseq(seqno);
|
||||
if (CSeqNo::seqcmp(m_piData2[temp], m_piData1[loc]) > 0)
|
||||
m_piData2[loc] = m_piData2[temp];
|
||||
m_iHead = loc;
|
||||
m_piNext[loc] = m_piNext[temp];
|
||||
m_piNext[temp] = loc;
|
||||
m_piData2[temp] = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// target node is empty, check prior node
|
||||
int i = m_iHead;
|
||||
while ((-1 != m_piNext[i]) && (CSeqNo::seqcmp(m_piData1[m_piNext[i]], seqno) < 0))
|
||||
i = m_piNext[i];
|
||||
|
||||
loc = (loc + 1) % m_iSize;
|
||||
|
||||
if (-1 == m_piData2[i])
|
||||
m_iHead = m_piNext[i];
|
||||
else if (CSeqNo::seqcmp(m_piData2[i], seqno) > 0)
|
||||
{
|
||||
// remove part/all seqno in the prior node
|
||||
m_piData1[loc] = CSeqNo::incseq(seqno);
|
||||
if (CSeqNo::seqcmp(m_piData2[i], m_piData1[loc]) > 0)
|
||||
m_piData2[loc] = m_piData2[i];
|
||||
|
||||
m_piData2[i] = seqno;
|
||||
|
||||
m_piNext[loc] = m_piNext[i];
|
||||
m_piNext[i] = loc;
|
||||
|
||||
m_iHead = loc;
|
||||
}
|
||||
else
|
||||
m_iHead = m_piNext[i];
|
||||
}
|
||||
|
||||
// Remove all nodes prior to the new head
|
||||
while (h != m_iHead)
|
||||
{
|
||||
if (m_piData2[h] != -1)
|
||||
{
|
||||
m_iLength -= CSeqNo::seqlen(m_piData1[h], m_piData2[h]);
|
||||
m_piData2[h] = -1;
|
||||
}
|
||||
else
|
||||
m_iLength --;
|
||||
|
||||
m_piData1[h] = -1;
|
||||
|
||||
if (m_iLastInsertPos == h)
|
||||
m_iLastInsertPos = -1;
|
||||
|
||||
h = m_piNext[h];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CSndLossList::getLossLength()
|
||||
{
|
||||
CGuard listguard(m_ListLock);
|
||||
|
||||
return m_iLength;
|
||||
}
|
||||
|
||||
int32_t CSndLossList::getLostSeq()
|
||||
{
|
||||
if (0 == m_iLength)
|
||||
return -1;
|
||||
|
||||
CGuard listguard(m_ListLock);
|
||||
|
||||
if (0 == m_iLength)
|
||||
return -1;
|
||||
|
||||
if (m_iLastInsertPos == m_iHead)
|
||||
m_iLastInsertPos = -1;
|
||||
|
||||
// return the first loss seq. no.
|
||||
int32_t seqno = m_piData1[m_iHead];
|
||||
|
||||
// head moves to the next node
|
||||
if (-1 == m_piData2[m_iHead])
|
||||
{
|
||||
//[3, -1] becomes [], and head moves to next node in the list
|
||||
m_piData1[m_iHead] = -1;
|
||||
m_iHead = m_piNext[m_iHead];
|
||||
}
|
||||
else
|
||||
{
|
||||
// shift to next node, e.g., [3, 7] becomes [], [4, 7]
|
||||
int loc = (m_iHead + 1) % m_iSize;
|
||||
|
||||
m_piData1[loc] = CSeqNo::incseq(seqno);
|
||||
if (CSeqNo::seqcmp(m_piData2[m_iHead], m_piData1[loc]) > 0)
|
||||
m_piData2[loc] = m_piData2[m_iHead];
|
||||
|
||||
m_piData1[m_iHead] = -1;
|
||||
m_piData2[m_iHead] = -1;
|
||||
|
||||
m_piNext[loc] = m_piNext[m_iHead];
|
||||
m_iHead = loc;
|
||||
}
|
||||
|
||||
m_iLength --;
|
||||
|
||||
return seqno;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CRcvLossList::CRcvLossList(int size):
|
||||
m_piData1(NULL),
|
||||
m_piData2(NULL),
|
||||
m_piNext(NULL),
|
||||
m_piPrior(NULL),
|
||||
m_iHead(-1),
|
||||
m_iTail(-1),
|
||||
m_iLength(0),
|
||||
m_iSize(size)
|
||||
{
|
||||
m_piData1 = new int32_t [m_iSize];
|
||||
m_piData2 = new int32_t [m_iSize];
|
||||
m_piNext = new int [m_iSize];
|
||||
m_piPrior = new int [m_iSize];
|
||||
|
||||
// -1 means there is no data in the node
|
||||
for (int i = 0; i < size; ++ i)
|
||||
{
|
||||
m_piData1[i] = -1;
|
||||
m_piData2[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
CRcvLossList::~CRcvLossList()
|
||||
{
|
||||
delete [] m_piData1;
|
||||
delete [] m_piData2;
|
||||
delete [] m_piNext;
|
||||
delete [] m_piPrior;
|
||||
}
|
||||
|
||||
void CRcvLossList::insert(int32_t seqno1, int32_t seqno2)
|
||||
{
|
||||
// Data to be inserted must be larger than all those in the list
|
||||
// guaranteed by the UDT receiver
|
||||
|
||||
if (0 == m_iLength)
|
||||
{
|
||||
// insert data into an empty list
|
||||
m_iHead = 0;
|
||||
m_iTail = 0;
|
||||
m_piData1[m_iHead] = seqno1;
|
||||
if (seqno2 != seqno1)
|
||||
m_piData2[m_iHead] = seqno2;
|
||||
|
||||
m_piNext[m_iHead] = -1;
|
||||
m_piPrior[m_iHead] = -1;
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise searching for the position where the node should be
|
||||
int offset = CSeqNo::seqoff(m_piData1[m_iHead], seqno1);
|
||||
int loc = (m_iHead + offset) % m_iSize;
|
||||
|
||||
if ((-1 != m_piData2[m_iTail]) && (CSeqNo::incseq(m_piData2[m_iTail]) == seqno1))
|
||||
{
|
||||
// coalesce with prior node, e.g., [2, 5], [6, 7] becomes [2, 7]
|
||||
loc = m_iTail;
|
||||
m_piData2[loc] = seqno2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new node
|
||||
m_piData1[loc] = seqno1;
|
||||
|
||||
if (seqno2 != seqno1)
|
||||
m_piData2[loc] = seqno2;
|
||||
|
||||
m_piNext[m_iTail] = loc;
|
||||
m_piPrior[loc] = m_iTail;
|
||||
m_piNext[loc] = -1;
|
||||
m_iTail = loc;
|
||||
}
|
||||
|
||||
m_iLength += CSeqNo::seqlen(seqno1, seqno2);
|
||||
}
|
||||
|
||||
bool CRcvLossList::remove(int32_t seqno)
|
||||
{
|
||||
if (0 == m_iLength)
|
||||
return false;
|
||||
|
||||
// locate the position of "seqno" in the list
|
||||
int offset = CSeqNo::seqoff(m_piData1[m_iHead], seqno);
|
||||
if (offset < 0)
|
||||
return false;
|
||||
|
||||
int loc = (m_iHead + offset) % m_iSize;
|
||||
|
||||
if (seqno == m_piData1[loc])
|
||||
{
|
||||
// This is a seq. no. that starts the loss sequence
|
||||
|
||||
if (-1 == m_piData2[loc])
|
||||
{
|
||||
// there is only 1 loss in the sequence, delete it from the node
|
||||
if (m_iHead == loc)
|
||||
{
|
||||
m_iHead = m_piNext[m_iHead];
|
||||
if (-1 != m_iHead)
|
||||
m_piPrior[m_iHead] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_piNext[m_piPrior[loc]] = m_piNext[loc];
|
||||
if (-1 != m_piNext[loc])
|
||||
m_piPrior[m_piNext[loc]] = m_piPrior[loc];
|
||||
else
|
||||
m_iTail = m_piPrior[loc];
|
||||
}
|
||||
|
||||
m_piData1[loc] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// there are more than 1 loss in the sequence
|
||||
// move the node to the next and update the starter as the next loss inSeqNo(seqno)
|
||||
|
||||
// find next node
|
||||
int i = (loc + 1) % m_iSize;
|
||||
|
||||
// remove the "seqno" and change the starter as next seq. no.
|
||||
m_piData1[i] = CSeqNo::incseq(m_piData1[loc]);
|
||||
|
||||
// process the sequence end
|
||||
if (CSeqNo::seqcmp(m_piData2[loc], CSeqNo::incseq(m_piData1[loc])) > 0)
|
||||
m_piData2[i] = m_piData2[loc];
|
||||
|
||||
// remove the current node
|
||||
m_piData1[loc] = -1;
|
||||
m_piData2[loc] = -1;
|
||||
|
||||
// update list pointer
|
||||
m_piNext[i] = m_piNext[loc];
|
||||
m_piPrior[i] = m_piPrior[loc];
|
||||
|
||||
if (m_iHead == loc)
|
||||
m_iHead = i;
|
||||
else
|
||||
m_piNext[m_piPrior[i]] = i;
|
||||
|
||||
if (m_iTail == loc)
|
||||
m_iTail = i;
|
||||
else
|
||||
m_piPrior[m_piNext[i]] = i;
|
||||
}
|
||||
|
||||
m_iLength --;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// There is no loss sequence in the current position
|
||||
// the "seqno" may be contained in a previous node
|
||||
|
||||
// searching previous node
|
||||
int i = (loc - 1 + m_iSize) % m_iSize;
|
||||
while (-1 == m_piData1[i])
|
||||
i = (i - 1 + m_iSize) % m_iSize;
|
||||
|
||||
// not contained in this node, return
|
||||
if ((-1 == m_piData2[i]) || (CSeqNo::seqcmp(seqno, m_piData2[i]) > 0))
|
||||
return false;
|
||||
|
||||
if (seqno == m_piData2[i])
|
||||
{
|
||||
// it is the sequence end
|
||||
|
||||
if (seqno == CSeqNo::incseq(m_piData1[i]))
|
||||
m_piData2[i] = -1;
|
||||
else
|
||||
m_piData2[i] = CSeqNo::decseq(seqno);
|
||||
}
|
||||
else
|
||||
{
|
||||
// split the sequence
|
||||
|
||||
// construct the second sequence from CSeqNo::incseq(seqno) to the original sequence end
|
||||
// located at "loc + 1"
|
||||
loc = (loc + 1) % m_iSize;
|
||||
|
||||
m_piData1[loc] = CSeqNo::incseq(seqno);
|
||||
if (CSeqNo::seqcmp(m_piData2[i], m_piData1[loc]) > 0)
|
||||
m_piData2[loc] = m_piData2[i];
|
||||
|
||||
// the first (original) sequence is between the original sequence start to CSeqNo::decseq(seqno)
|
||||
if (seqno == CSeqNo::incseq(m_piData1[i]))
|
||||
m_piData2[i] = -1;
|
||||
else
|
||||
m_piData2[i] = CSeqNo::decseq(seqno);
|
||||
|
||||
// update the list pointer
|
||||
m_piNext[loc] = m_piNext[i];
|
||||
m_piNext[i] = loc;
|
||||
m_piPrior[loc] = i;
|
||||
|
||||
if (m_iTail == i)
|
||||
m_iTail = loc;
|
||||
else
|
||||
m_piPrior[m_piNext[loc]] = loc;
|
||||
}
|
||||
|
||||
m_iLength --;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRcvLossList::remove(int32_t seqno1, int32_t seqno2)
|
||||
{
|
||||
if (seqno1 <= seqno2)
|
||||
{
|
||||
for (int32_t i = seqno1; i <= seqno2; ++ i)
|
||||
remove(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int32_t j = seqno1; j < CSeqNo::m_iMaxSeqNo; ++ j)
|
||||
remove(j);
|
||||
for (int32_t k = 0; k <= seqno2; ++ k)
|
||||
remove(k);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRcvLossList::find(int32_t seqno1, int32_t seqno2) const
|
||||
{
|
||||
if (0 == m_iLength)
|
||||
return false;
|
||||
|
||||
int p = m_iHead;
|
||||
|
||||
while (-1 != p)
|
||||
{
|
||||
if ((CSeqNo::seqcmp(m_piData1[p], seqno1) == 0) ||
|
||||
((CSeqNo::seqcmp(m_piData1[p], seqno1) > 0) && (CSeqNo::seqcmp(m_piData1[p], seqno2) <= 0)) ||
|
||||
((CSeqNo::seqcmp(m_piData1[p], seqno1) < 0) && (m_piData2[p] != -1) && CSeqNo::seqcmp(m_piData2[p], seqno1) >= 0))
|
||||
return true;
|
||||
|
||||
p = m_piNext[p];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int CRcvLossList::getLossLength() const
|
||||
{
|
||||
return m_iLength;
|
||||
}
|
||||
|
||||
int CRcvLossList::getFirstLostSeq() const
|
||||
{
|
||||
if (0 == m_iLength)
|
||||
return -1;
|
||||
|
||||
return m_piData1[m_iHead];
|
||||
}
|
||||
|
||||
void CRcvLossList::getLossArray(int32_t* array, int& len, int limit)
|
||||
{
|
||||
len = 0;
|
||||
|
||||
int i = m_iHead;
|
||||
|
||||
while ((len < limit - 1) && (-1 != i))
|
||||
{
|
||||
array[len] = m_piData1[i];
|
||||
if (-1 != m_piData2[i])
|
||||
{
|
||||
// there are more than 1 loss in the sequence
|
||||
array[len] |= 0x80000000;
|
||||
++ len;
|
||||
array[len] = m_piData2[i];
|
||||
}
|
||||
|
||||
++ len;
|
||||
|
||||
i = m_piNext[i];
|
||||
}
|
||||
}
|
||||
202
vendor/udt4/src/list.h
vendored
202
vendor/udt4/src/list.h
vendored
|
|
@ -1,202 +0,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 01/22/2011
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __UDT_LIST_H__
|
||||
#define __UDT_LIST_H__
|
||||
|
||||
|
||||
#include "udt.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
class CSndLossList
|
||||
{
|
||||
public:
|
||||
CSndLossList(int size = 1024);
|
||||
~CSndLossList();
|
||||
|
||||
// Functionality:
|
||||
// Insert a seq. no. into the sender loss list.
|
||||
// Parameters:
|
||||
// 0) [in] seqno1: sequence number starts.
|
||||
// 1) [in] seqno2: sequence number ends.
|
||||
// Returned value:
|
||||
// number of packets that are not in the list previously.
|
||||
|
||||
int insert(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
// Functionality:
|
||||
// Remove ALL the seq. no. that are not greater than the parameter.
|
||||
// Parameters:
|
||||
// 0) [in] seqno: sequence number.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void remove(int32_t seqno);
|
||||
|
||||
// Functionality:
|
||||
// Read the loss length.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// The length of the list.
|
||||
|
||||
int getLossLength();
|
||||
|
||||
// Functionality:
|
||||
// Read the first (smallest) loss seq. no. in the list and remove it.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// The seq. no. or -1 if the list is empty.
|
||||
|
||||
int32_t getLostSeq();
|
||||
|
||||
private:
|
||||
int32_t* m_piData1; // sequence number starts
|
||||
int32_t* m_piData2; // seqnence number ends
|
||||
int* m_piNext; // next node in the list
|
||||
|
||||
int m_iHead; // first node
|
||||
int m_iLength; // loss length
|
||||
int m_iSize; // size of the static array
|
||||
int m_iLastInsertPos; // position of last insert node
|
||||
|
||||
pthread_mutex_t m_ListLock; // used to synchronize list operation
|
||||
|
||||
private:
|
||||
CSndLossList(const CSndLossList&);
|
||||
CSndLossList& operator=(const CSndLossList&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CRcvLossList
|
||||
{
|
||||
public:
|
||||
CRcvLossList(int size = 1024);
|
||||
~CRcvLossList();
|
||||
|
||||
// Functionality:
|
||||
// Insert a series of loss seq. no. between "seqno1" and "seqno2" into the receiver's loss list.
|
||||
// Parameters:
|
||||
// 0) [in] seqno1: sequence number starts.
|
||||
// 1) [in] seqno2: seqeunce number ends.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void insert(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
// Functionality:
|
||||
// Remove a loss seq. no. from the receiver's loss list.
|
||||
// Parameters:
|
||||
// 0) [in] seqno: sequence number.
|
||||
// Returned value:
|
||||
// if the packet is removed (true) or no such lost packet is found (false).
|
||||
|
||||
bool remove(int32_t seqno);
|
||||
|
||||
// Functionality:
|
||||
// Remove all packets between seqno1 and seqno2.
|
||||
// Parameters:
|
||||
// 0) [in] seqno1: start sequence number.
|
||||
// 1) [in] seqno2: end sequence number.
|
||||
// Returned value:
|
||||
// if the packet is removed (true) or no such lost packet is found (false).
|
||||
|
||||
bool remove(int32_t seqno1, int32_t seqno2);
|
||||
|
||||
// Functionality:
|
||||
// Find if there is any lost packets whose sequence number falling seqno1 and seqno2.
|
||||
// Parameters:
|
||||
// 0) [in] seqno1: start sequence number.
|
||||
// 1) [in] seqno2: end sequence number.
|
||||
// Returned value:
|
||||
// True if found; otherwise false.
|
||||
|
||||
bool find(int32_t seqno1, int32_t seqno2) const;
|
||||
|
||||
// Functionality:
|
||||
// Read the loss length.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// the length of the list.
|
||||
|
||||
int getLossLength() const;
|
||||
|
||||
// Functionality:
|
||||
// Read the first (smallest) seq. no. in the list.
|
||||
// Parameters:
|
||||
// None.
|
||||
// Returned value:
|
||||
// the sequence number or -1 if the list is empty.
|
||||
|
||||
int getFirstLostSeq() const;
|
||||
|
||||
// Functionality:
|
||||
// Get a encoded loss array for NAK report.
|
||||
// Parameters:
|
||||
// 0) [out] array: the result list of seq. no. to be included in NAK.
|
||||
// 1) [out] physical length of the result array.
|
||||
// 2) [in] limit: maximum length of the array.
|
||||
// Returned value:
|
||||
// None.
|
||||
|
||||
void getLossArray(int32_t* array, int& len, int limit);
|
||||
|
||||
private:
|
||||
int32_t* m_piData1; // sequence number starts
|
||||
int32_t* m_piData2; // sequence number ends
|
||||
int* m_piNext; // next node in the list
|
||||
int* m_piPrior; // prior node in the list;
|
||||
|
||||
int m_iHead; // first node in the list
|
||||
int m_iTail; // last node in the list;
|
||||
int m_iLength; // loss length
|
||||
int m_iSize; // size of the static array
|
||||
|
||||
private:
|
||||
CRcvLossList(const CRcvLossList&);
|
||||
CRcvLossList& operator=(const CRcvLossList&);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
381
vendor/udt4/src/md5.cpp
vendored
381
vendor/udt4/src/md5.cpp
vendored
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.cpp,v 1.3 2008/01/20 22:52:04 lilyco Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
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
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
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.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
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.
|
||||
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 <string.h>
|
||||
|
||||
#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)
|
||||
#else
|
||||
# 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 T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#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 T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#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 T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#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 T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
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 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;
|
||||
#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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* 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
|
||||
/* 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(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
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). */
|
||||
#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);
|
||||
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(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, 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). */
|
||||
#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);
|
||||
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(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(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
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). */
|
||||
#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);
|
||||
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(c, d, a, b, 10, 15, T55);
|
||||
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(b, c, d, a, 13, 21, T60);
|
||||
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);
|
||||
#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.) */
|
||||
pms->abcd[0] += a;
|
||||
pms->abcd[1] += b;
|
||||
pms->abcd[2] += c;
|
||||
pms->abcd[3] += d;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
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));
|
||||
}
|
||||
91
vendor/udt4/src/md5.h
vendored
91
vendor/udt4/src/md5.h
vendored
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id: md5.h,v 1.2 2007/12/24 05:58:37 lilyco Exp $ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
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
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
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.
|
||||
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>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
#ifndef md5_INCLUDED
|
||||
# define md5_INCLUDED
|
||||
|
||||
/*
|
||||
* This package supports both compile-time and run-time determination of CPU
|
||||
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
|
||||
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
|
||||
* defined as non-zero, the code will be compiled to run only on big-endian
|
||||
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
|
||||
* run on either big- or little-endian CPUs, but will run slightly less
|
||||
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
|
||||
*/
|
||||
|
||||
typedef unsigned char md5_byte_t; /* 8-bit byte */
|
||||
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 */
|
||||
} md5_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialize the algorithm. */
|
||||
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);
|
||||
|
||||
/* Finish the message and return the digest. */
|
||||
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* md5_INCLUDED */
|
||||
411
vendor/udt4/src/packet.cpp
vendored
411
vendor/udt4/src/packet.cpp
vendored
|
|
@ -1,411 +0,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 02/12/2011
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Packet Header |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// ~ Data / Control Information Field ~
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |0| Sequence Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |ff |o| Message Number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Time Stamp |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Destination Socket ID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// bit 0:
|
||||
// 0: Data Packet
|
||||
// 1: Control Packet
|
||||
// bit ff:
|
||||
// 11: solo message packet
|
||||
// 10: first packet of a message
|
||||
// 01: last packet of a message
|
||||
// bit o:
|
||||
// 0: in order delivery not required
|
||||
// 1: in order delivery required
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |1| Type | Reserved |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Additional Info |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Time Stamp |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Destination Socket ID |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// bit 1-15:
|
||||
// 0: Protocol Connection Handshake
|
||||
// Add. Info: Undefined
|
||||
// Control Info: Handshake information (see CHandShake)
|
||||
// 1: Keep-alive
|
||||
// Add. Info: Undefined
|
||||
// Control Info: None
|
||||
// 2: Acknowledgement (ACK)
|
||||
// Add. Info: The ACK sequence number
|
||||
// Control Info: The sequence number to which (but not include) all the previous packets have beed received
|
||||
// Optional: RTT
|
||||
// RTT Variance
|
||||
// available receiver buffer size (in bytes)
|
||||
// advertised flow window size (number of packets)
|
||||
// estimated bandwidth (number of packets per second)
|
||||
// 3: Negative Acknowledgement (NAK)
|
||||
// Add. Info: Undefined
|
||||
// Control Info: Loss list (see loss list coding below)
|
||||
// 4: Congestion/Delay Warning
|
||||
// Add. Info: Undefined
|
||||
// Control Info: None
|
||||
// 5: Shutdown
|
||||
// Add. Info: Undefined
|
||||
// Control Info: None
|
||||
// 6: Acknowledgement of Acknowledement (ACK-square)
|
||||
// Add. Info: The ACK sequence number
|
||||
// Control Info: None
|
||||
// 7: Message Drop Request
|
||||
// Add. Info: Message ID
|
||||
// Control Info: first sequence number of the message
|
||||
// last seqeunce number of the message
|
||||
// 8: Error Signal from the Peer Side
|
||||
// Add. Info: Error code
|
||||
// Control Info: None
|
||||
// 0x7FFF: Explained by bits 16 - 31
|
||||
//
|
||||
// bit 16 - 31:
|
||||
// This space is used for future expansion or user defined control packets.
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |1| Sequence Number a (first) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |0| Sequence Number b (last) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |0| Sequence Number (single) |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
//
|
||||
// Loss List Field Coding:
|
||||
// For any consectutive 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
|
||||
// the original sequence numbers in the field.
|
||||
|
||||
|
||||
#include <cstring>
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
const int CPacket::m_iPktHdrSize = 16;
|
||||
const int CHandShake::m_iContentSize = 48;
|
||||
|
||||
|
||||
// Set up the aliases in the constructure
|
||||
CPacket::CPacket():
|
||||
m_iSeqNo((int32_t&)(m_nHeader[0])),
|
||||
m_iMsgNo((int32_t&)(m_nHeader[1])),
|
||||
m_iTimeStamp((int32_t&)(m_nHeader[2])),
|
||||
m_iID((int32_t&)(m_nHeader[3])),
|
||||
m_pcData((char*&)(m_PacketVector[1].iov_base)),
|
||||
__pad()
|
||||
{
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
m_nHeader[i] = 0;
|
||||
m_PacketVector[0].iov_base = (char *)m_nHeader;
|
||||
m_PacketVector[0].iov_len = CPacket::m_iPktHdrSize;
|
||||
m_PacketVector[1].iov_base = NULL;
|
||||
m_PacketVector[1].iov_len = 0;
|
||||
}
|
||||
|
||||
CPacket::~CPacket()
|
||||
{
|
||||
}
|
||||
|
||||
int CPacket::getLength() const
|
||||
{
|
||||
return m_PacketVector[1].iov_len;
|
||||
}
|
||||
|
||||
void CPacket::setLength(int len)
|
||||
{
|
||||
m_PacketVector[1].iov_len = len;
|
||||
}
|
||||
|
||||
void CPacket::pack(int pkttype, void* lparam, void* rparam, int size)
|
||||
{
|
||||
// Set (bit-0 = 1) and (bit-1~15 = type)
|
||||
m_nHeader[0] = 0x80000000 | (pkttype << 16);
|
||||
|
||||
// Set additional information and control information field
|
||||
switch (pkttype)
|
||||
{
|
||||
case 2: //0010 - Acknowledgement (ACK)
|
||||
// ACK packet seq. no.
|
||||
if (NULL != lparam)
|
||||
m_nHeader[1] = *(int32_t *)lparam;
|
||||
|
||||
// data ACK seq. no.
|
||||
// optional: RTT (microsends), RTT variance (microseconds) advertised flow window size (packets), and estimated link capacity (packets per second)
|
||||
m_PacketVector[1].iov_base = (char *)rparam;
|
||||
m_PacketVector[1].iov_len = size;
|
||||
|
||||
break;
|
||||
|
||||
case 6: //0110 - Acknowledgement of Acknowledgement (ACK-2)
|
||||
// ACK packet seq. no.
|
||||
m_nHeader[1] = *(int32_t *)lparam;
|
||||
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
|
||||
m_PacketVector[1].iov_len = 4; //0;
|
||||
|
||||
break;
|
||||
|
||||
case 3: //0011 - Loss Report (NAK)
|
||||
// loss list
|
||||
m_PacketVector[1].iov_base = (char *)rparam;
|
||||
m_PacketVector[1].iov_len = size;
|
||||
|
||||
break;
|
||||
|
||||
case 4: //0100 - Congestion Warning
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
|
||||
m_PacketVector[1].iov_len = 4; //0;
|
||||
|
||||
break;
|
||||
|
||||
case 1: //0001 - Keep-alive
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
|
||||
m_PacketVector[1].iov_len = 4; //0;
|
||||
|
||||
break;
|
||||
|
||||
case 0: //0000 - Handshake
|
||||
// control info filed is handshake info
|
||||
m_PacketVector[1].iov_base = (char *)rparam;
|
||||
m_PacketVector[1].iov_len = size; //sizeof(CHandShake);
|
||||
|
||||
break;
|
||||
|
||||
case 5: //0101 - Shutdown
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
|
||||
m_PacketVector[1].iov_len = 4; //0;
|
||||
|
||||
break;
|
||||
|
||||
case 7: //0111 - Message Drop Request
|
||||
// msg id
|
||||
m_nHeader[1] = *(int32_t *)lparam;
|
||||
|
||||
//first seq no, last seq no
|
||||
m_PacketVector[1].iov_base = (char *)rparam;
|
||||
m_PacketVector[1].iov_len = size;
|
||||
|
||||
break;
|
||||
|
||||
case 8: //1000 - Error Signal from the Peer Side
|
||||
// Error type
|
||||
m_nHeader[1] = *(int32_t *)lparam;
|
||||
|
||||
// control info field should be none
|
||||
// but "writev" does not allow this
|
||||
m_PacketVector[1].iov_base = (char *)&__pad; //NULL;
|
||||
m_PacketVector[1].iov_len = 4; //0;
|
||||
|
||||
break;
|
||||
|
||||
case 32767: //0x7FFF - Reserved for user defined control packets
|
||||
// for extended control packet
|
||||
// "lparam" contains the extended type information for bit 16 - 31
|
||||
// "rparam" is the control information
|
||||
m_nHeader[0] |= *(int32_t *)lparam;
|
||||
|
||||
if (NULL != rparam)
|
||||
{
|
||||
m_PacketVector[1].iov_base = (char *)rparam;
|
||||
m_PacketVector[1].iov_len = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PacketVector[1].iov_base = (char *)&__pad;
|
||||
m_PacketVector[1].iov_len = 4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iovec* CPacket::getPacketVector()
|
||||
{
|
||||
return m_PacketVector;
|
||||
}
|
||||
|
||||
int CPacket::getFlag() const
|
||||
{
|
||||
// read bit 0
|
||||
return m_nHeader[0] >> 31;
|
||||
}
|
||||
|
||||
int CPacket::getType() const
|
||||
{
|
||||
// read bit 1~15
|
||||
return (m_nHeader[0] >> 16) & 0x00007FFF;
|
||||
}
|
||||
|
||||
int CPacket::getExtendedType() const
|
||||
{
|
||||
// read bit 16~31
|
||||
return m_nHeader[0] & 0x0000FFFF;
|
||||
}
|
||||
|
||||
int32_t CPacket::getAckSeqNo() const
|
||||
{
|
||||
// read additional information field
|
||||
return m_nHeader[1];
|
||||
}
|
||||
|
||||
int CPacket::getMsgBoundary() const
|
||||
{
|
||||
// read [1] bit 0~1
|
||||
return m_nHeader[1] >> 30;
|
||||
}
|
||||
|
||||
bool CPacket::getMsgOrderFlag() const
|
||||
{
|
||||
// read [1] bit 2
|
||||
return (1 == ((m_nHeader[1] >> 29) & 1));
|
||||
}
|
||||
|
||||
int32_t CPacket::getMsgSeq() const
|
||||
{
|
||||
// read [1] bit 3~31
|
||||
return m_nHeader[1] & 0x1FFFFFFF;
|
||||
}
|
||||
|
||||
CPacket* CPacket::clone() const
|
||||
{
|
||||
CPacket* pkt = new CPacket;
|
||||
memcpy(pkt->m_nHeader, m_nHeader, m_iPktHdrSize);
|
||||
pkt->m_pcData = new char[m_PacketVector[1].iov_len];
|
||||
memcpy(pkt->m_pcData, m_pcData, m_PacketVector[1].iov_len);
|
||||
pkt->m_PacketVector[1].iov_len = m_PacketVector[1].iov_len;
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
CHandShake::CHandShake():
|
||||
m_iVersion(0),
|
||||
m_iType(0),
|
||||
m_iISN(0),
|
||||
m_iMSS(0),
|
||||
m_iFlightFlagSize(0),
|
||||
m_iReqType(0),
|
||||
m_iID(0),
|
||||
m_iCookie(0)
|
||||
{
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
m_piPeerIP[i] = 0;
|
||||
}
|
||||
|
||||
int CHandShake::serialize(char* buf, int& size)
|
||||
{
|
||||
if (size < m_iContentSize)
|
||||
return -1;
|
||||
|
||||
int32_t* p = (int32_t*)buf;
|
||||
*p++ = m_iVersion;
|
||||
*p++ = m_iType;
|
||||
*p++ = m_iISN;
|
||||
*p++ = m_iMSS;
|
||||
*p++ = m_iFlightFlagSize;
|
||||
*p++ = m_iReqType;
|
||||
*p++ = m_iID;
|
||||
*p++ = m_iCookie;
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
*p++ = m_piPeerIP[i];
|
||||
|
||||
size = m_iContentSize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CHandShake::deserialize(const char* buf, int size)
|
||||
{
|
||||
if (size < m_iContentSize)
|
||||
return -1;
|
||||
|
||||
int32_t* p = (int32_t*)buf;
|
||||
m_iVersion = *p++;
|
||||
m_iType = *p++;
|
||||
m_iISN = *p++;
|
||||
m_iMSS = *p++;
|
||||
m_iFlightFlagSize = *p++;
|
||||
m_iReqType = *p++;
|
||||
m_iID = *p++;
|
||||
m_iCookie = *p++;
|
||||
for (int i = 0; i < 4; ++ i)
|
||||
m_piPeerIP[i] = *p++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue