Ubuntu 18.04 Upgrade #3
114 changed files with 4616 additions and 17395 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -50,5 +50,3 @@ GitSHA3.cpp
|
|||
|
||||
ntp_test
|
||||
task_cancel_test
|
||||
udt_client
|
||||
udt_server
|
||||
|
|
|
|||
7
.gitmodules
vendored
7
.gitmodules
vendored
|
|
@ -1,6 +1,9 @@
|
|||
[submodule "vendor/diff-match-patch-cpp-stl"]
|
||||
path = vendor/diff-match-patch-cpp-stl
|
||||
url = https://github.com/leutloff/diff-match-patch-cpp-stl
|
||||
[submodule "vendor/secp256k1-zkp"]
|
||||
path = vendor/secp256k1-zkp
|
||||
url = https://github.com/cryptonomex/secp256k1-zkp.git
|
||||
path = vendor/secp256k1-zkp
|
||||
url = https://github.com/bitshares/secp256k1-zkp.git
|
||||
[submodule "vendor/websocketpp"]
|
||||
path = vendor/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
|
|
|
|||
177
CMakeLists.txt
177
CMakeLists.txt
|
|
@ -55,7 +55,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" )
|
||||
|
||||
|
|
@ -71,8 +71,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
|
||||
|
|
@ -81,6 +91,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
|
||||
|
|
@ -93,13 +104,14 @@ 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 )
|
||||
install( FILES ${binary_dir}/.libs/libsecp256k1${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION lib/cryptonomex )
|
||||
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})
|
||||
|
|
@ -116,7 +128,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)
|
||||
|
|
@ -148,17 +160,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
|
||||
|
|
@ -193,10 +194,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
|
||||
|
|
@ -225,12 +228,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
|
||||
|
|
@ -257,7 +260,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 )
|
||||
|
|
@ -281,6 +284,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
|
||||
|
|
@ -291,22 +298,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")
|
||||
|
||||
|
|
@ -316,22 +354,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
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${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" )
|
||||
|
|
@ -339,77 +377,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
|
||||
|
|
@ -501,8 +479,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}" )
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
fc
|
||||
==
|
||||
|
||||
**NOTE:** This fork reverts upstream commit a421e280488385cab26a42153f7ce3c8d5b6281f to avoid changing the BitShares API.
|
||||
|
||||
FC stands for fast-compiling c++ library and provides a set of utility libraries useful
|
||||
for the development of asynchronous libraries. Some of the highlights include:
|
||||
|
||||
|
|
|
|||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ namespace fc
|
|||
invalid_operation_exception_code = 14,
|
||||
unknown_host_exception_code = 15,
|
||||
null_optional_code = 16,
|
||||
udt_error_code = 17,
|
||||
aes_error_code = 18,
|
||||
overflow_code = 19,
|
||||
underflow_code = 20,
|
||||
|
|
@ -76,7 +75,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();
|
||||
|
|
@ -294,7 +293,6 @@ namespace fc
|
|||
FC_DECLARE_EXCEPTION( assert_exception, assert_exception_code, "Assert Exception" );
|
||||
FC_DECLARE_EXCEPTION( eof_exception, eof_exception_code, "End Of File" );
|
||||
FC_DECLARE_EXCEPTION( null_optional, null_optional_code, "null optional" );
|
||||
FC_DECLARE_EXCEPTION( udt_exception, udt_error_code, "UDT error" );
|
||||
FC_DECLARE_EXCEPTION( aes_exception, aes_error_code, "AES error" );
|
||||
FC_DECLARE_EXCEPTION( overflow_exception, overflow_code, "Integer Overflow" );
|
||||
FC_DECLARE_EXCEPTION( underflow_exception, underflow_code, "Integer Underflow" );
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -28,6 +29,8 @@ namespace fc { namespace http {
|
|||
void set_session_data( fc::any d ){ _session_data = std::move(d); }
|
||||
fc::any& get_session_data() { return _session_data; }
|
||||
|
||||
virtual std::string get_request_header(const std::string& key) = 0;
|
||||
|
||||
fc::signal<void()> closed;
|
||||
private:
|
||||
fc::any _session_data;
|
||||
|
|
@ -41,7 +44,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 +53,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 +71,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 +90,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) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <fc/filesystem.hpp>
|
||||
|
||||
namespace fc {
|
||||
class path;
|
||||
class logger;
|
||||
namespace ssh {
|
||||
namespace detail {
|
||||
class client_impl;
|
||||
class process_impl;
|
||||
};
|
||||
|
||||
enum sftp_file_type {
|
||||
named_pipe = 0010000,
|
||||
directory = 0040000,
|
||||
regular = 0100000,
|
||||
symlink = 0120000
|
||||
};
|
||||
|
||||
|
||||
enum sftp_file_mode {
|
||||
owner_mask = 0000700, /* RWX mask for owner */
|
||||
owner_read = 0000400, /* R for owner */
|
||||
owner_write = 0000200, /* W for owner */
|
||||
owner_exec = 0000100, /* X for owner */
|
||||
group_mask = 0000070, /* RWX mask for group */
|
||||
group_read = 0000040, /* R for group */
|
||||
group_write = 0000020, /* W for group */
|
||||
group_exec = 0000010, /* X for group */
|
||||
other_mask = 0000007, /* RWX mask for other */
|
||||
other_read = 0000004, /* R for other */
|
||||
other_write = 0000002, /* W for other */
|
||||
other_exec = 0000001 /* X for other */
|
||||
};
|
||||
|
||||
struct file_attrib {
|
||||
file_attrib();
|
||||
|
||||
uint64_t size;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t permissions;
|
||||
uint32_t atime;
|
||||
uint32_t mtime;
|
||||
|
||||
bool exists();
|
||||
bool is_file();
|
||||
bool is_directory();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enables communication over ssh using libssh2.
|
||||
*
|
||||
* Because the client creates other resources that depend upon
|
||||
* it, it can only be created as a std::shared_ptr<client> (aka client::ptr)
|
||||
* via client::create();
|
||||
*
|
||||
*/
|
||||
class client
|
||||
{
|
||||
public:
|
||||
enum trace_level {
|
||||
TRACE_NONE = 0,
|
||||
TRACE_TRANS = (1<<1),
|
||||
TRACE_KEX = (1<<2),
|
||||
TRACE_AUTH = (1<<3),
|
||||
TRACE_CONN = (1<<4),
|
||||
TRACE_SCP = (1<<5),
|
||||
TRACE_SFTP = (1<<6),
|
||||
TRACE_ERROR = (1<<7),
|
||||
TRACE_PUBLICKEY = (1<<8),
|
||||
TRACE_SOCKET = (1<<9)
|
||||
};
|
||||
/**
|
||||
* Everything but TRACE_ERROR will be logged at fc::log_level::debug, while
|
||||
* TRACE_ERROR will be logged at fc::log_level::error
|
||||
*
|
||||
* @param bitmask comprised of values from trace_level
|
||||
**/
|
||||
void set_trace_level( int bitmask );
|
||||
int get_trace_level()const;
|
||||
|
||||
/**
|
||||
* Override the default logger used by fc::ssh::client
|
||||
*/
|
||||
void set_logger( const logger& lgr );
|
||||
const logger& get_logger()const;
|
||||
|
||||
/**
|
||||
* Connect, with no password specified. Authentication will try public key,
|
||||
* (via agent or explicitly-set key), empty password, then keyboard-interactive
|
||||
*/
|
||||
void connect( const fc::string& user, const fc::string& host, uint16_t port = 22);
|
||||
|
||||
/**
|
||||
* Connect, specifying a password to be used for password authentication
|
||||
*/
|
||||
void connect( const fc::string& user, const fc::string& pass, const fc::string& host, uint16_t port = 22);
|
||||
|
||||
/**
|
||||
* @note THIS METHOD IS DEPRECATED and should be replace with:
|
||||
*
|
||||
* ssh::client_ptr sshc = std::make_shared<ssh::client>();
|
||||
* sshc->connect( ... )
|
||||
* ssh::process_ptr proc = std::make_shared<ssh::process>( sshc );
|
||||
* proc->exec( ... )
|
||||
*
|
||||
*
|
||||
* @brief execute command on remote machine
|
||||
* @param pty_type - whether or not to request a PTY when executing this process, this is necessary
|
||||
* for interactive (non-buffered) IO with the remote process, if left empty no pty will be
|
||||
* requested
|
||||
*
|
||||
* @note Processes launched in this manner will fully buffer stdin and stdout regardless of whether
|
||||
* the process calls flush(). If you need unbuffered (streaming, realtime) access to standard
|
||||
* out then you must launch the process via a shell.
|
||||
ssh::process exec( const fc::string& cmd, const fc::string& pty_type = "" );
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief upload a file to remote host
|
||||
* @param progress a callback to report / cancel upload.
|
||||
* The callback takes two parameters, bytes sent and file size. To continue the
|
||||
* transfer, the callback should return true. To cancel the callback should return false.
|
||||
*/
|
||||
void scp_send( const fc::path& local_path, const fc::path& remote_path,
|
||||
std::function<bool(uint64_t,uint64_t)> progress = [](uint64_t,uint64_t){return true;} );
|
||||
|
||||
/**
|
||||
* @brief recursively sends the contents of local_dir to the remote_path
|
||||
*
|
||||
* If remote_path ends in '/' then a new directory at <code>remote_path/local_dir.filename()</code> will
|
||||
* be created, otherwise <code>local_dir / *</code> will be copied to <code>remote_path / *</code>
|
||||
*
|
||||
* Progress will be reported as total bytes transferred for all files.
|
||||
*/
|
||||
void scp_send_dir( const fc::path& local_dir, const fc::path& remote_path,
|
||||
std::function<bool(uint64_t,uint64_t)> progress = [](uint64_t,uint64_t){return true;} );
|
||||
|
||||
/**
|
||||
* @pre remote_path is not a directory
|
||||
* @post remote file is removed from the remote filesystem
|
||||
*/
|
||||
void rm( const fc::path& remote_path );
|
||||
|
||||
/**
|
||||
* @pre remote_path is a directory
|
||||
* @post remote directory is removed from the remote filesystem
|
||||
*/
|
||||
void rmdir( const fc::path& remote_path );
|
||||
|
||||
void rmdir_recursive( const fc::path& remote_path );
|
||||
|
||||
file_attrib stat( const fc::path& remote_path );
|
||||
|
||||
/**
|
||||
* @pre all parent directories already exist.
|
||||
* @pre remote_dir is not exist or is already a directory
|
||||
* @post remote_dir exists.
|
||||
*/
|
||||
void mkdir( const fc::path& remote_dir, int mode = owner_read|owner_write|owner_exec );
|
||||
|
||||
/**
|
||||
* Create all parent directories for remote_dir if they do not exist.
|
||||
*
|
||||
* @post remote_dir exists.
|
||||
*/
|
||||
void create_directories( const fc::path& remote_dir, int mode = owner_read|owner_write|owner_exec );
|
||||
|
||||
/**
|
||||
* Sets whether the remote system is believed to be a Windows box (by default, it's
|
||||
* assumed to be running UNIX. This alters how command-line arguments are quoted
|
||||
* and possibly how filenames are altered when copying files
|
||||
*/
|
||||
void set_remote_system_is_windows(bool is_windows = true);
|
||||
|
||||
void close();
|
||||
|
||||
client();
|
||||
~client();
|
||||
|
||||
private:
|
||||
friend class process;
|
||||
friend class detail::process_impl;
|
||||
std::unique_ptr<detail::client_impl> my;
|
||||
};
|
||||
typedef std::shared_ptr<client> client_ptr;
|
||||
|
||||
} } // namespace fc::ssh
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef MACE_SSH_ERROR_HPP
|
||||
#define MACE_SSH_ERROR_HPP
|
||||
#include <boost/exception/all.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace mace { namespace ssh {
|
||||
typedef boost::error_info<struct err_msg_,std::string> err_msg;
|
||||
|
||||
struct exception : public virtual boost::exception, public virtual std::exception {
|
||||
const char* what()const throw() { return "exception"; }
|
||||
virtual void rethrow()const { BOOST_THROW_EXCEPTION(*this); }
|
||||
const std::string& message()const { return *boost::get_error_info<mace::ssh::err_msg>(*this); }
|
||||
};
|
||||
|
||||
} } // mace::ssh
|
||||
|
||||
/**
|
||||
* Helper macro for throwing exceptions with a message: THROW( "Hello World %1%, %2%", %"Hello" %"World" )
|
||||
*/
|
||||
#define MACE_SSH_THROW( MSG, ... ) \
|
||||
do { \
|
||||
BOOST_THROW_EXCEPTION( mace::ssh::exception() << mace::ssh::err_msg( (boost::format( MSG ) __VA_ARGS__ ).str() ) );\
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
#pragma once
|
||||
#include <fc/interprocess/iprocess.hpp>
|
||||
|
||||
namespace fc { namespace ssh
|
||||
{
|
||||
|
||||
class client;
|
||||
|
||||
namespace detail {
|
||||
class process_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables communication with a process executed via
|
||||
* client::exec().
|
||||
*
|
||||
* Process can only be created by mace::ssh::client.
|
||||
*/
|
||||
class process : public iprocess
|
||||
{
|
||||
public:
|
||||
virtual iprocess& exec( const fc::path& exe, std::vector<std::string> args,
|
||||
const fc::path& work_dir = fc::path(), exec_opts opts = open_all );
|
||||
|
||||
/**
|
||||
* Blocks until the result code of the process has been returned.
|
||||
*/
|
||||
virtual int result();
|
||||
|
||||
|
||||
/**
|
||||
* Not supported. libssh2 does not support sending signals to remote processes.
|
||||
* closing in_stream() is the best you can do
|
||||
*/
|
||||
virtual void kill();
|
||||
|
||||
|
||||
/**
|
||||
* @brief returns a stream that writes to the process' stdin
|
||||
*/
|
||||
virtual fc::buffered_ostream_ptr in_stream();
|
||||
|
||||
/**
|
||||
* @brief returns a stream that reads from the process' stdout
|
||||
*/
|
||||
virtual fc::buffered_istream_ptr out_stream();
|
||||
/**
|
||||
* @brief returns a stream that reads from the process' stderr
|
||||
*/
|
||||
virtual fc::buffered_istream_ptr err_stream();
|
||||
|
||||
process( fc::ssh::client_ptr c );
|
||||
~process();
|
||||
private:
|
||||
std::unique_ptr<detail::process_impl> my;
|
||||
};
|
||||
|
||||
} } // fc::ssh
|
||||
|
|
@ -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,10 +88,10 @@ 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 K, typename T, typename C>
|
||||
void to_variant( const std::map<K,T, C>& var, variant& vo );
|
||||
|
|
@ -307,6 +307,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 );
|
||||
|
||||
|
|
|
|||
68
src/asio.cpp
68
src/asio.cpp
|
|
@ -92,45 +92,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()
|
||||
|
|
@ -139,10 +145,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) );
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ namespace fc
|
|||
(eof_exception)
|
||||
(unknown_host_exception)
|
||||
(null_optional)
|
||||
(udt_exception)
|
||||
(aes_exception)
|
||||
(overflow_exception)
|
||||
(underflow_exception)
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -1,19 +1,8 @@
|
|||
#include <fc/network/http/websocket.hpp>
|
||||
|
||||
#ifndef WIN32
|
||||
// websocket++ currently does not build correctly with permessage deflate enabled
|
||||
// since chrome does not work with websocketpp's implementation of permessage-deflate
|
||||
// yet, I'm just disabling it on windows instead of trying to fix the build error.
|
||||
# define ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
#endif
|
||||
|
||||
#include <websocketpp/config/asio_client.hpp>
|
||||
#include <websocketpp/config/asio.hpp>
|
||||
#include <websocketpp/server.hpp>
|
||||
#include <websocketpp/config/asio_client.hpp>
|
||||
#ifdef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
# include <websocketpp/extensions/permessage_deflate/enabled.hpp>
|
||||
#endif
|
||||
#include <websocketpp/client.hpp>
|
||||
#include <websocketpp/logger/stub.hpp>
|
||||
|
||||
|
|
@ -30,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;
|
||||
|
|
@ -43,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;
|
||||
|
||||
|
|
@ -63,16 +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_tls_with_stub_log : public websocketpp::config::asio_tls {
|
||||
|
||||
#ifdef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
struct asio_with_stub_log_and_deflate : public websocketpp::config::asio {
|
||||
typedef asio_with_stub_log_and_deflate type;
|
||||
typedef asio base;
|
||||
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;
|
||||
|
|
@ -82,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;
|
||||
|
||||
|
|
@ -94,97 +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;
|
||||
};
|
||||
#endif ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
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;
|
||||
};
|
||||
#endif
|
||||
|
||||
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
|
||||
|
|
@ -210,24 +168,17 @@ namespace fc { namespace http {
|
|||
_ws_connection->close(code,reason);
|
||||
}
|
||||
|
||||
virtual std::string get_request_header(const std::string& key)override
|
||||
{
|
||||
return _ws_connection->get_request_header(key);
|
||||
}
|
||||
|
||||
T _ws_connection;
|
||||
};
|
||||
|
||||
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()
|
||||
|
|
@ -239,15 +190,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;
|
||||
|
|
@ -258,15 +209,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);
|
||||
|
|
@ -328,62 +284,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;
|
||||
|
||||
|
|
@ -441,6 +467,7 @@ namespace fc { namespace http {
|
|||
fc::thread& _client_thread;
|
||||
websocket_client_type _client;
|
||||
websocket_connection_ptr _connection;
|
||||
std::string _uri;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -450,9 +477,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( [&](){
|
||||
|
|
@ -489,6 +520,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 {
|
||||
|
|
@ -496,6 +543,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;
|
||||
|
|
@ -515,91 +564,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(
|
||||
#ifdef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
enable_permessage_deflate ?
|
||||
(detail::abstract_websocket_server*)new detail::websocket_server_impl<detail::asio_with_stub_log_and_deflate> :
|
||||
#endif
|
||||
(detail::abstract_websocket_server*)new detail::websocket_server_impl<detail::asio_with_stub_log> )
|
||||
{
|
||||
#ifndef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
if (enable_permessage_deflate)
|
||||
elog("Websocket permessage-deflate requested but not enabled during compile");
|
||||
#endif
|
||||
}
|
||||
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(
|
||||
#ifdef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
enable_permessage_deflate ?
|
||||
(detail::abstract_websocket_server*)new detail::websocket_tls_server_impl<detail::asio_tls_stub_log_and_deflate>(server_pem, ssl_password) :
|
||||
#endif
|
||||
(detail::abstract_websocket_server*)new detail::websocket_tls_server_impl<detail::asio_tls_stub_log>(server_pem, ssl_password) )
|
||||
{
|
||||
#ifndef ENABLE_WEBSOCKET_PERMESSAGE_DEFLATE
|
||||
if (enable_permessage_deflate)
|
||||
elog("Websocket permessage-deflate requested but not enabled during compile");
|
||||
#endif
|
||||
}
|
||||
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 )
|
||||
|
|
@ -611,6 +658,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 ){
|
||||
|
|
@ -637,6 +685,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,20 @@ 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() )
|
||||
{
|
||||
variant subresult = this->receive_call( 1, args[0].as_string() );
|
||||
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 +96,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,17 @@ 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() )
|
||||
{
|
||||
variant subresult = this->receive_call( 1, args[0].as_string() );
|
||||
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() );
|
||||
} );
|
||||
|
|
@ -84,14 +93,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 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,717 +0,0 @@
|
|||
#define NOMINMAX // prevent windows from defining min and max macros
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fc/filesystem.hpp>
|
||||
#include <fc/ssh/client.hpp>
|
||||
#include <fc/ssh/process.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <fc/io/iostream.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/interprocess/file_mapping.hpp>
|
||||
#include <fc/thread/unique_lock.hpp>
|
||||
#include <fc/asio.hpp>
|
||||
|
||||
#include "client_impl.hpp"
|
||||
|
||||
namespace fc { namespace ssh {
|
||||
|
||||
namespace detail {
|
||||
static int ssh_init = libssh2_init(0);
|
||||
}
|
||||
|
||||
client::client():my( new detail::client_impl() ){ (void)detail::ssh_init; /* fix unused warning...*/ }
|
||||
client::~client() { my->close(); }
|
||||
|
||||
void client::set_trace_level( int bitmask ) { my->_trace_level = bitmask; }
|
||||
int client::get_trace_level()const { return my->_trace_level; }
|
||||
const logger& client::get_logger()const { return my->logr; }
|
||||
void client::set_logger( const logger& l ) { my->logr = l; }
|
||||
|
||||
void client::connect( const fc::string& user, const fc::string& host, uint16_t port ) {
|
||||
my->hostname = host;
|
||||
my->uname = user;
|
||||
my->port = port;
|
||||
my->connect();
|
||||
}
|
||||
void client::connect( const fc::string& user, const fc::string& pass,
|
||||
const fc::string& host, uint16_t port ) {
|
||||
my->hostname = host;
|
||||
my->uname = user;
|
||||
my->upass = pass;
|
||||
my->port = port;
|
||||
|
||||
my->connect();
|
||||
}
|
||||
|
||||
void client::close() { my->close(); }
|
||||
|
||||
|
||||
// ssh::process client::exec( const fc::string& cmd, const fc::string& pty_type ) {
|
||||
// return ssh::process( *this, cmd, pty_type );
|
||||
// }
|
||||
|
||||
/**
|
||||
* @todo implement progress reporting.
|
||||
*/
|
||||
void client::scp_send_dir( const fc::path& local_dir, const fc::path& remote_path,
|
||||
std::function<bool(uint64_t,uint64_t)> progress )
|
||||
{
|
||||
fc::path remote_dir = remote_path;
|
||||
if( remote_dir.filename() == fc::path(".") )
|
||||
remote_dir /= local_dir.filename();
|
||||
|
||||
fc_dlog( my->logr, "scp -r ${local} ${remote}", ("local",local_dir)("remote",remote_dir) );
|
||||
create_directories( remote_dir );
|
||||
|
||||
directory_iterator ditr(local_dir);
|
||||
directory_iterator dend;
|
||||
|
||||
while( ditr != dend ) {
|
||||
if( (*ditr).filename() == "." ||
|
||||
(*ditr).filename() == ".." )
|
||||
{ }
|
||||
else if( fc::is_directory(*ditr) )
|
||||
{
|
||||
scp_send_dir( (*ditr), remote_dir / (*ditr).filename() );
|
||||
} else if( fc::is_regular_file(*ditr) ) {
|
||||
scp_send( *ditr, remote_dir / (*ditr).filename() );
|
||||
} else {
|
||||
fc_wlog( my->logr, "Skipping '${path}", ("path",fc::canonical(*ditr)) );
|
||||
}
|
||||
++ditr;
|
||||
}
|
||||
}
|
||||
|
||||
void client::scp_send( const fc::path& local_path, const fc::path& remote_path,
|
||||
std::function<bool(uint64_t,uint64_t)> progress ) {
|
||||
fc_wlog( my->logr, "scp ${local} ${remote}", ("local",local_path)("remote",remote_path ) );
|
||||
if( !fc::exists(local_path) ) {
|
||||
FC_THROW( "Source file '${file}' does not exist", ("file",local_path) ) ;
|
||||
}
|
||||
if( is_directory( local_path ) ) {
|
||||
FC_THROW( "Source file '${file}' is a directory, expected a file", ("file",local_path) ) ;
|
||||
}
|
||||
|
||||
// memory map the file
|
||||
uint64_t fsize = file_size(local_path);
|
||||
if( fsize == 0 ) {
|
||||
elog( "file size ${file_size}", ("file_size", fsize) );
|
||||
// TODO: handle empty file case
|
||||
if( progress ) progress(0,0);
|
||||
return;
|
||||
}
|
||||
file_mapping fmap( local_path.string().c_str(), read_only );
|
||||
|
||||
LIBSSH2_CHANNEL* chan = 0;
|
||||
time_t now;
|
||||
memset( &now, 0, sizeof(now) );
|
||||
|
||||
// TODO: preserve creation / modification date
|
||||
// TODO: perserve permissions / exec bit?
|
||||
try {
|
||||
// libssh2_scp_send64 stores state data in the session object, and it calls channel_open which
|
||||
// stores its own state data, so lock both.
|
||||
fc::scoped_lock<fc::mutex> channel_open_lock(my->channel_open_mutex);
|
||||
fc::scoped_lock<fc::mutex> scp_send_lock(my->scp_send_mutex);
|
||||
chan = my->call_ssh2_ptr_function_throw<LIBSSH2_CHANNEL*>(boost::bind(libssh2_scp_send64, my->session, remote_path.generic_string().c_str(), 0700, fsize, now, now ));
|
||||
} catch (fc::exception& er) {
|
||||
FC_RETHROW_EXCEPTION(er, error, "scp ${local_file} to ${remote_file} failed", ("local_file", local_path)("remote_file",remote_path));
|
||||
}
|
||||
uint64_t total_bytes_written = 0;
|
||||
try {
|
||||
const size_t max_mapping_size = 1024*1024*1024; // 1GB
|
||||
for (uint64_t current_offset = 0; current_offset < fsize; current_offset += max_mapping_size) {
|
||||
uint64_t total_bytes_left_to_send = fsize - current_offset;
|
||||
size_t bytes_to_send_this_iteration = (size_t)std::min<uint64_t>(total_bytes_left_to_send, max_mapping_size);
|
||||
mapped_region mr( fmap, fc::read_only, current_offset, bytes_to_send_this_iteration);
|
||||
size_t bytes_written_this_iteration = 0;
|
||||
char* pos = reinterpret_cast<char*>(mr.get_address());
|
||||
while( progress(total_bytes_written, fsize) && bytes_written_this_iteration < bytes_to_send_this_iteration) {
|
||||
int r = my->call_ssh2_function_throw(boost::bind(libssh2_channel_write_ex, chan, 0, pos,
|
||||
bytes_to_send_this_iteration - bytes_written_this_iteration),
|
||||
"scp failed ${code} - ${message}");
|
||||
bytes_written_this_iteration += r;
|
||||
total_bytes_written += r;
|
||||
pos += r;
|
||||
// fc_wlog( my->logr, "wrote ${bytes} bytes", ("bytes",r) );
|
||||
}
|
||||
}
|
||||
my->call_ssh2_function(boost::bind(libssh2_channel_send_eof, chan));
|
||||
my->call_ssh2_function(boost::bind(libssh2_channel_wait_eof, chan));
|
||||
my->call_ssh2_function(boost::bind(libssh2_channel_close, chan));
|
||||
} catch ( fc::exception& er ) {
|
||||
// clean up chan
|
||||
my->call_ssh2_function(boost::bind(libssh2_channel_free, chan));
|
||||
throw er;
|
||||
}
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_channel_free, chan),
|
||||
"scp failed ${code} - ${message}");
|
||||
}
|
||||
|
||||
|
||||
void client::rm( const fc::path& remote_path ) {
|
||||
try {
|
||||
auto s = stat(remote_path);
|
||||
if( s.is_directory() ) {
|
||||
FC_THROW( "sftp cannot remove directory ${path}", ("path",remote_path) );
|
||||
}
|
||||
else if( !s.exists() ) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_unlink_lock(my->scp_unlink_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_unlink_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()),
|
||||
"sftp rm failed ${code}");
|
||||
}
|
||||
} catch ( fc::exception& er ) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "sftp remove '${remote_path}' failed", ("remote_path",remote_path) );
|
||||
}
|
||||
}
|
||||
|
||||
void client::rmdir( const fc::path& remote_path ) {
|
||||
try {
|
||||
auto s = stat(remote_path);
|
||||
if( !s.is_directory() )
|
||||
FC_THROW( "sftp cannot rmdir non-directory ${path}", ("path",remote_path) );
|
||||
else if( !s.exists() )
|
||||
return; // nothing to do
|
||||
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_rmdir_lock(my->scp_rmdir_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_rmdir_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()),
|
||||
"sftp rmdir failed ${code}");
|
||||
}
|
||||
} catch ( fc::exception& er ) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "sftp rmdir '${remote_path}' failed", ("remote_path",remote_path) );
|
||||
}
|
||||
}
|
||||
|
||||
void client::rmdir_recursive( const fc::path& remote_path ) {
|
||||
try {
|
||||
auto s = stat(remote_path);
|
||||
if( !s.is_directory() )
|
||||
FC_THROW( "sftp cannot rmdir non-directory ${path}", ("path",remote_path) );
|
||||
else if( !s.exists() )
|
||||
return; // nothing to do
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *dir_handle;
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_open_lock(my->scp_open_mutex);
|
||||
dir_handle =
|
||||
my->call_ssh2_ptr_function_throw<LIBSSH2_SFTP_HANDLE*>(boost::bind(libssh2_sftp_open_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size(), 0, 0, LIBSSH2_SFTP_OPENDIR),
|
||||
"sftp libssh2_sftp_opendir failed ${code}");
|
||||
}
|
||||
do {
|
||||
char mem[512];
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||
|
||||
int rc;
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_readdir_lock(my->scp_readdir_mutex);
|
||||
rc = my->call_ssh2_function_throw(boost::bind(libssh2_sftp_readdir_ex, dir_handle, mem, sizeof(mem), (char*)NULL, 0, &attrs),
|
||||
"sftp readdir failed ${code}");
|
||||
}
|
||||
if (rc > 0) {
|
||||
fc::string file_or_dir_name(mem, rc);
|
||||
if (file_or_dir_name == "." || file_or_dir_name == "..")
|
||||
continue;
|
||||
fc::path full_remote_path = remote_path / file_or_dir_name;
|
||||
if (LIBSSH2_SFTP_S_ISDIR(attrs.permissions))
|
||||
rmdir_recursive(full_remote_path);
|
||||
else if (LIBSSH2_SFTP_S_ISREG(attrs.permissions)) {
|
||||
fc::scoped_lock<fc::mutex> scp_unlink_lock(my->scp_unlink_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_unlink_ex, my->sftp, full_remote_path.generic_string().c_str(), full_remote_path.generic_string().size()),
|
||||
"sftp rm failed ${code}");
|
||||
}
|
||||
} else
|
||||
break;
|
||||
} while (1);
|
||||
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_close_lock(my->scp_close_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_close_handle, dir_handle), "sftp libssh2_sftp_closedir failed ${code}");
|
||||
}
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_rmdir_lock(my->scp_rmdir_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_rmdir_ex, my->sftp, remote_path.generic_string().c_str(), remote_path.generic_string().size()),
|
||||
"sftp rmdir failed ${code}");
|
||||
}
|
||||
} catch ( fc::exception& er ) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "sftp rmdir recursive '${remote_path}' failed", ("remote_path",remote_path) );
|
||||
}
|
||||
}
|
||||
|
||||
file_attrib client::stat( const fc::path& remote_path ){
|
||||
my->init_sftp();
|
||||
LIBSSH2_SFTP_ATTRIBUTES att;
|
||||
int ec;
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_stat_lock(my->scp_stat_mutex);
|
||||
ec = my->call_ssh2_function(boost::bind(libssh2_sftp_stat_ex, my->sftp,
|
||||
remote_path.generic_string().c_str(), remote_path.generic_string().size(),
|
||||
LIBSSH2_SFTP_STAT, &att));
|
||||
}
|
||||
if( ec )
|
||||
return file_attrib();
|
||||
file_attrib ft;
|
||||
ft.size = att.filesize;
|
||||
ft.permissions = att.permissions;
|
||||
return ft;
|
||||
}
|
||||
void client::create_directories( const fc::path& rdir, int mode ) {
|
||||
boost::filesystem::path dir = rdir;
|
||||
boost::filesystem::path p;
|
||||
auto pitr = dir.begin();
|
||||
while( pitr != dir.end() ) {
|
||||
p /= *pitr;
|
||||
if( !stat( p ).exists() ) {
|
||||
mkdir(p,mode);
|
||||
}
|
||||
++pitr;
|
||||
}
|
||||
}
|
||||
|
||||
void client::mkdir( const fc::path& rdir, int mode ) {
|
||||
try {
|
||||
auto s = stat(rdir);
|
||||
if( s.is_directory() )
|
||||
return;
|
||||
else if( s.exists() )
|
||||
FC_THROW( "File already exists at path ${path}", ("path",rdir) );
|
||||
|
||||
{
|
||||
fc::scoped_lock<fc::mutex> scp_mkdir_lock(my->scp_mkdir_mutex);
|
||||
my->call_ssh2_function_throw(boost::bind(libssh2_sftp_mkdir_ex, my->sftp,
|
||||
rdir.generic_string().c_str(), rdir.generic_string().size(), mode),
|
||||
"sftp mkdir error");
|
||||
}
|
||||
} catch ( fc::exception& er ) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "sftp failed to create directory '${directory}'", ( "directory", rdir ) );
|
||||
}
|
||||
}
|
||||
|
||||
void client::set_remote_system_is_windows(bool is_windows /* = true */) {
|
||||
my->remote_system_is_windows = is_windows;
|
||||
}
|
||||
|
||||
|
||||
file_attrib::file_attrib()
|
||||
:size(0),uid(0),gid(0),permissions(0),atime(0),mtime(0)
|
||||
{ }
|
||||
|
||||
bool file_attrib::is_directory() {
|
||||
return LIBSSH2_SFTP_S_ISDIR(permissions);
|
||||
}
|
||||
bool file_attrib::is_file() {
|
||||
return LIBSSH2_SFTP_S_ISREG(permissions);
|
||||
}
|
||||
bool file_attrib::exists() {
|
||||
return 0 != permissions;
|
||||
}
|
||||
|
||||
detail::client_impl::client_impl() :
|
||||
session(nullptr),
|
||||
knownhosts(nullptr),
|
||||
sftp(nullptr),
|
||||
agent(nullptr),
|
||||
_trace_level(0), // was LIBSSH2_TRACE_ERROR
|
||||
logr(fc::logger::get( "fc::ssh::client" )),
|
||||
remote_system_is_windows(false) {
|
||||
logr.set_parent( fc::logger::get( "default" ) );
|
||||
}
|
||||
|
||||
detail::client_impl::~client_impl() {
|
||||
close();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void detail::client_impl::kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len, int num_prompts,
|
||||
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
|
||||
void **abstract) {
|
||||
detail::client_impl* self = (client_impl*)*abstract;
|
||||
|
||||
|
||||
for (int i = 0; i < num_prompts; i++) {
|
||||
fwrite(prompts[i].text, 1, prompts[i].length, stdout);
|
||||
|
||||
if( self->upass.size() == 0 ) {
|
||||
/** TODO: add keyboard callback here...
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
n = strlen(buf);
|
||||
while (n > 0 && strchr("\r\n", buf[n - 1]))
|
||||
n--;
|
||||
buf[n] = 0;
|
||||
|
||||
#ifdef WIN32 // fix warning
|
||||
# define strdup _strdup
|
||||
#endif
|
||||
responses[i].text = strdup(buf);
|
||||
responses[i].length = n;
|
||||
*/
|
||||
responses[i].text = nullptr;
|
||||
responses[i].length = 0;
|
||||
} else {
|
||||
responses[i].text = strdup(self->upass.c_str());
|
||||
responses[i].length = self->upass.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detail::client_impl::connect() {
|
||||
try {
|
||||
if( libssh2_init(0) < 0 )
|
||||
FC_THROW( "Unable to init libssh2" );
|
||||
|
||||
auto eps = fc::asio::tcp::resolve( hostname, boost::lexical_cast<std::string>(port) );
|
||||
if( eps.size() == 0 )
|
||||
FC_THROW( "Unable to resolve host '${host}'", ("host",hostname) );
|
||||
|
||||
sock.reset( new boost::asio::ip::tcp::socket( fc::asio::default_io_service() ) );
|
||||
|
||||
bool resolved = false;
|
||||
for( uint32_t i = 0; i < eps.size(); ++i ) {
|
||||
std::stringstream ss; ss << eps[i];
|
||||
try {
|
||||
boost::system::error_code ec;
|
||||
fc_ilog( logr, "Attempting to connect to ${endpoint}", ("endpoint",ss.str().c_str()) );
|
||||
fc::asio::tcp::connect( *sock, eps[i] );
|
||||
endpt = eps[i];
|
||||
resolved = true;
|
||||
break;
|
||||
} catch ( fc::exception& er ) {
|
||||
fc_ilog( logr, "Failed to connect to ${endpoint}\n${error_reprot}",
|
||||
("endpoint",ss.str().c_str())("error_report", er.to_detail_string()) );
|
||||
sock->close();
|
||||
}
|
||||
}
|
||||
if( !resolved )
|
||||
FC_THROW( "Unable to connect to any resolved endpoint for ${host}:${port}",
|
||||
("host", hostname).set("port",port) );
|
||||
|
||||
session = libssh2_session_init();
|
||||
libssh2_trace( session, _trace_level );
|
||||
libssh2_trace_sethandler( session, this, client_impl::handle_trace );
|
||||
|
||||
*libssh2_session_abstract(session) = this;
|
||||
|
||||
libssh2_session_set_blocking( session, 0 );
|
||||
try {
|
||||
call_ssh2_function_throw(boost::bind(libssh2_session_handshake, session, sock->native()),
|
||||
"SSH Handshake error: ${code} - ${message}");
|
||||
} catch (fc::exception& er) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "Error during SSH handshake" );;
|
||||
}
|
||||
//const char* fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
//slog( "fingerprint: %s", fingerprint );
|
||||
|
||||
// try to authenticate, throw on error.
|
||||
try {
|
||||
authenticate();
|
||||
} catch (fc::exception& er) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "Error during SSH authentication" );;
|
||||
}
|
||||
//slog(".");
|
||||
} catch ( fc::exception& er ) {
|
||||
elog( "Unable to connect to ssh server: ${detail}", ("detail", er.to_detail_string().c_str()) );
|
||||
close();
|
||||
FC_RETHROW_EXCEPTION( er, error, "Unable to connect to ssh server" );;
|
||||
} catch ( ... ) {
|
||||
close();
|
||||
FC_THROW( "Unable to connect to ssh server", ("exception", fc::except_str() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
void detail::client_impl::handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length ) {
|
||||
client_impl* my = (client_impl*)context;
|
||||
fc::string str(data,length);
|
||||
fc_wlog( my->logr, "${message}", ("message",str) );
|
||||
}
|
||||
|
||||
void detail::client_impl::close() {
|
||||
if( session ) {
|
||||
if( sftp ) {
|
||||
try {
|
||||
call_ssh2_function(boost::bind(libssh2_sftp_shutdown, sftp));
|
||||
}catch(...){
|
||||
fc_wlog( logr, "caught closing sftp session" );
|
||||
}
|
||||
sftp = 0;
|
||||
}
|
||||
|
||||
if (agent) {
|
||||
libssh2_agent_disconnect(agent);
|
||||
libssh2_agent_free(agent);
|
||||
agent = nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
call_ssh2_function(boost::bind(libssh2_session_disconnect_ex, session, SSH_DISCONNECT_BY_APPLICATION, "exit cleanly", ""));
|
||||
call_ssh2_function(boost::bind(libssh2_session_free, session), false);
|
||||
} catch ( ... ){
|
||||
fc_wlog( logr, "caught freeing session" );
|
||||
}
|
||||
session = 0;
|
||||
try {
|
||||
if( sock )
|
||||
sock->close();
|
||||
} catch ( ... ){
|
||||
fc_wlog( logr, "caught error closing socket" );
|
||||
}
|
||||
sock.reset(0);
|
||||
try {
|
||||
if( read_prom )
|
||||
read_prom->wait();
|
||||
} catch ( ... ){
|
||||
fc_wlog( logr, "caught error waiting on read" );
|
||||
}
|
||||
try {
|
||||
if( write_prom )
|
||||
write_prom->wait();
|
||||
} catch ( ... ){
|
||||
fc_wlog( logr, "caught error waiting on write" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detail::client_impl::authenticate() {
|
||||
try {
|
||||
char * alist = NULL;
|
||||
// libssh2_userauth_list has strange enough behavior that we can't use the
|
||||
// call_blocking_libssh2_function-type functions to wait and retry, so we must
|
||||
// explicitly lock around the libssh2_userauth_list calls.
|
||||
// hence, this anonymous scope:
|
||||
{
|
||||
fc::unique_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
|
||||
alist = libssh2_userauth_list(session, uname.c_str(),uname.size());
|
||||
|
||||
if(alist==NULL) {
|
||||
char * msg = 0;
|
||||
int ec = 0;
|
||||
if(libssh2_userauth_authenticated(session))
|
||||
return; // CONNECTED!
|
||||
ec = libssh2_session_last_error(session,&msg,NULL,0);
|
||||
|
||||
while( !alist && (ec == LIBSSH2_ERROR_EAGAIN) ) {
|
||||
wait_on_socket();
|
||||
alist = libssh2_userauth_list(session, uname.c_str(), uname.size());
|
||||
ec = libssh2_session_last_error(session,&msg,NULL,0);
|
||||
}
|
||||
if( !alist ) {
|
||||
FC_THROW( "Error getting authorization list: ${code} - ${message}",
|
||||
("code",ec).set("message",msg));
|
||||
}
|
||||
}
|
||||
} // end anonymous scope
|
||||
|
||||
std::vector<std::string> split_alist;
|
||||
bool pubkey = false;
|
||||
bool pass = false;
|
||||
bool keybd = false;
|
||||
boost::split( split_alist, alist, boost::is_any_of(",") );
|
||||
std::for_each( split_alist.begin(), split_alist.end(), [&](const std::string& s){
|
||||
if( s == "publickey" )
|
||||
pubkey = true;
|
||||
else if( s == "password" )
|
||||
pass = true;
|
||||
else if( s == "keyboard-interactive" )
|
||||
keybd = true;
|
||||
else
|
||||
fc_dlog( logr, "Unknown/unsupported authentication type '${auth_type}'", ("auth_type",s.c_str()));
|
||||
});
|
||||
|
||||
if( pubkey && try_pub_key() )
|
||||
return;
|
||||
if( pass && try_pass() )
|
||||
return;
|
||||
if( keybd && try_keyboard() )
|
||||
return;
|
||||
} catch ( fc::exception& er ) {
|
||||
FC_RETHROW_EXCEPTION( er, error, "Unable to authenticate ssh connection" );
|
||||
}
|
||||
FC_THROW( "Unable to authenticate ssh connection" );
|
||||
} // authenticate()
|
||||
|
||||
bool detail::client_impl::try_pass() {
|
||||
return !call_ssh2_function(boost::bind(libssh2_userauth_password_ex, session, uname.c_str(), uname.size(),
|
||||
upass.c_str(), upass.size(), (LIBSSH2_PASSWD_CHANGEREQ_FUNC((*)))NULL));
|
||||
}
|
||||
bool detail::client_impl::try_keyboard() {
|
||||
return !call_ssh2_function(boost::bind(libssh2_userauth_keyboard_interactive_ex, session,
|
||||
uname.c_str(), uname.size(), &client_impl::kbd_callback));
|
||||
}
|
||||
bool detail::client_impl::try_pub_key() {
|
||||
if (privkey.size()) {
|
||||
if (!call_ssh2_function(boost::bind(libssh2_userauth_publickey_fromfile_ex,
|
||||
session,
|
||||
uname.c_str(), uname.size(),
|
||||
pubkey.c_str(),
|
||||
privkey.c_str(),
|
||||
passphrase.c_str())))
|
||||
return true; // successful authentication from file
|
||||
fc_ilog( logr, "failed to authenticate with private key from file '${privkey_filename}'", ("privkey_filename",privkey));
|
||||
} else
|
||||
fc_ilog( logr, "no private key file set, skiping pubkey authorization from file");
|
||||
|
||||
agent = libssh2_agent_init(session);
|
||||
if (!agent) {
|
||||
fc_wlog( logr, "failed to initialize ssh-agent support");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (call_ssh2_function(boost::bind(libssh2_agent_connect, agent))) {
|
||||
fc_ilog( logr, "failed to connect to ssh-agent");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (call_ssh2_function(boost::bind(libssh2_agent_list_identities, agent))) {
|
||||
fc_ilog( logr, "failed requesting identities from ssh-agent");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct libssh2_agent_publickey *prev_identity = NULL;
|
||||
while (1) {
|
||||
struct libssh2_agent_publickey *identity;
|
||||
int ec = call_ssh2_function(boost::bind(libssh2_agent_get_identity, agent, &identity, prev_identity));
|
||||
if (ec == 1)
|
||||
break; // done iterating over keys
|
||||
if (ec < 0) {
|
||||
fc_ilog( logr, "failed obtaining identity from ssh-agent");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (call_ssh2_function(boost::bind(libssh2_agent_userauth, agent, uname.c_str(), identity)))
|
||||
fc_ilog( logr, "unable to authenticate with public key '${key_comment}'", ("key_comment",identity->comment));
|
||||
else {
|
||||
fc_ilog( logr, "authenticated with public key '${key_comment}'", ("key_comment",identity->comment));
|
||||
return true;
|
||||
}
|
||||
prev_identity = identity;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void detail::client_impl::wait_on_socket(int additionalDirections /* = 0 */) {
|
||||
int dir = libssh2_session_block_directions(session);
|
||||
dir |= additionalDirections;
|
||||
if( !dir )
|
||||
return;
|
||||
|
||||
fc::promise<boost::system::error_code>::ptr rprom, wprom;
|
||||
if( dir & LIBSSH2_SESSION_BLOCK_INBOUND ) {
|
||||
fc::scoped_lock<fc::spin_lock> lock(this->_spin_lock);
|
||||
if( !read_prom ) {
|
||||
read_prom.reset( new fc::promise<boost::system::error_code>("read_prom") );
|
||||
sock->async_read_some( boost::asio::null_buffers(),
|
||||
[=]( const boost::system::error_code& e, size_t ) {
|
||||
fc::scoped_lock<fc::spin_lock> lock(this->_spin_lock);
|
||||
this->read_prom->set_value(e);
|
||||
this->read_prom.reset(nullptr);
|
||||
} );
|
||||
}
|
||||
rprom = read_prom;
|
||||
}
|
||||
|
||||
if( dir & LIBSSH2_SESSION_BLOCK_OUTBOUND ) {
|
||||
fc::scoped_lock<fc::spin_lock> lock(this->_spin_lock);
|
||||
if( !write_prom ) {
|
||||
write_prom.reset( new fc::promise<boost::system::error_code>("write_prom") );
|
||||
sock->async_write_some( boost::asio::null_buffers(),
|
||||
[=]( const boost::system::error_code& e, size_t ) {
|
||||
fc::scoped_lock<fc::spin_lock> lock(this->_spin_lock);
|
||||
this->write_prom->set_value(e);
|
||||
this->write_prom.reset(0);
|
||||
} );
|
||||
}
|
||||
wprom = write_prom;
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
if( rprom.get() && wprom.get() ) {
|
||||
typedef fc::future<boost::system::error_code> fprom;
|
||||
fprom fw(wprom);
|
||||
fprom fr(rprom);
|
||||
#if 0
|
||||
// EMF: at present there are known bugs in fc::wait_any, and it will fail to wake up
|
||||
// when one of the futures is ready.
|
||||
int r = fc::wait_any( fw, fr, fc::seconds(1) );
|
||||
#else
|
||||
int r;
|
||||
while (1) {
|
||||
if (fw.ready()) {
|
||||
r = 0; break;
|
||||
}
|
||||
if (fr.ready()) {
|
||||
r = 1; break;
|
||||
}
|
||||
fc::usleep(fc::microseconds(5000));
|
||||
}
|
||||
#endif
|
||||
switch( r ) {
|
||||
case 0:
|
||||
if( wprom->wait() ) {
|
||||
FC_THROW( "Socket Error ${message}",
|
||||
( "message", boost::system::system_error(rprom->wait() ).what() ) );
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if( rprom->wait() ) {
|
||||
FC_THROW( "Socket Error ${message}",
|
||||
( "message", boost::system::system_error(rprom->wait() ).what() ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if( rprom ) {
|
||||
if( rprom->wait() ) {
|
||||
FC_THROW( "Socket Error ${message}",
|
||||
( "message", boost::system::system_error(rprom->wait() ).what() ) );
|
||||
}
|
||||
} else if( wprom ) {
|
||||
if( wprom->wait() ) {
|
||||
FC_THROW( "Socket Error ${message}",
|
||||
( "message", boost::system::system_error(wprom->wait() ).what() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
void detail::client_impl::init_sftp() {
|
||||
if( !sftp )
|
||||
sftp = call_ssh2_ptr_function_throw<LIBSSH2_SFTP*>(boost::bind(libssh2_sftp_init,session),
|
||||
"init sftp error ${code} - ${message}");
|
||||
}
|
||||
|
||||
|
||||
LIBSSH2_CHANNEL* detail::client_impl::open_channel( const fc::string& pty_type ) {
|
||||
LIBSSH2_CHANNEL* chan = 0;
|
||||
/* anonymous scope */ {
|
||||
fc::scoped_lock<fc::mutex> channel_open_lock(channel_open_mutex);
|
||||
|
||||
chan = call_ssh2_ptr_function_throw<LIBSSH2_CHANNEL*>(boost::bind(libssh2_channel_open_ex, session,
|
||||
"session", sizeof("session") - 1,
|
||||
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
|
||||
LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
||||
(const char*)NULL, 0),
|
||||
"libssh2_channel_open_session failed: ${message}");
|
||||
}
|
||||
|
||||
if( pty_type.size() )
|
||||
call_ssh2_function_throw(boost::bind(libssh2_channel_request_pty_ex, chan, pty_type.c_str(), pty_type.size(),
|
||||
(char *)NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT,
|
||||
LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX),
|
||||
"libssh2_channel_req_pty failed: ${message}");
|
||||
return chan;
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
#define NOMINMAX
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include <fc/ssh/client.hpp>
|
||||
#include <fc/ssh/process.hpp>
|
||||
#include <fc/thread/mutex.hpp>
|
||||
#include <fc/thread/spin_lock.hpp>
|
||||
#include <fc/thread/scoped_lock.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
|
||||
#include <fc/asio.hpp>
|
||||
|
||||
// include this to get acess to the details of the LIBSSH2_SESSION structure, so
|
||||
// we can verify that all data has really been sent when libssh2 says it has.
|
||||
#include <../src/libssh2_priv.h>
|
||||
|
||||
namespace fc { namespace ssh {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class client_impl {
|
||||
public:
|
||||
client_impl();
|
||||
~client_impl();
|
||||
|
||||
LIBSSH2_SESSION* session;
|
||||
LIBSSH2_KNOWNHOSTS* knownhosts;
|
||||
LIBSSH2_SFTP* sftp;
|
||||
LIBSSH2_AGENT* agent;
|
||||
|
||||
std::unique_ptr<boost::asio::ip::tcp::socket> sock;
|
||||
boost::asio::ip::tcp::endpoint endpt;
|
||||
|
||||
fc::mutex ssh_session_mutex;
|
||||
fc::mutex channel_open_mutex;
|
||||
fc::mutex process_startup_mutex;
|
||||
fc::mutex scp_send_mutex;
|
||||
fc::mutex scp_stat_mutex;
|
||||
fc::mutex scp_mkdir_mutex;
|
||||
fc::mutex scp_rmdir_mutex;
|
||||
fc::mutex scp_unlink_mutex;
|
||||
fc::mutex scp_close_mutex;
|
||||
fc::mutex scp_readdir_mutex;
|
||||
fc::mutex scp_open_mutex;
|
||||
|
||||
fc::string uname;
|
||||
fc::string upass;
|
||||
fc::string pubkey;
|
||||
fc::string privkey;
|
||||
fc::string passphrase;
|
||||
fc::string hostname;
|
||||
uint16_t port;
|
||||
bool session_connected;
|
||||
fc::promise<boost::system::error_code>::ptr read_prom;
|
||||
fc::promise<boost::system::error_code>::ptr write_prom;
|
||||
fc::spin_lock _spin_lock;
|
||||
int _trace_level;
|
||||
logger logr;
|
||||
|
||||
bool remote_system_is_windows; // true if windows, false if unix, used for command-line quoting and maybe filename translation
|
||||
|
||||
LIBSSH2_CHANNEL* open_channel( const fc::string& pty_type );
|
||||
static void kbd_callback(const char *name, int name_len,
|
||||
const char *instruction, int instruction_len, int num_prompts,
|
||||
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
|
||||
void **abstract);
|
||||
|
||||
void connect();
|
||||
|
||||
static void handle_trace( LIBSSH2_SESSION* session, void* context, const char* data, size_t length );
|
||||
|
||||
void close();
|
||||
void authenticate();
|
||||
|
||||
bool try_pass();
|
||||
bool try_keyboard();
|
||||
bool try_pub_key();
|
||||
|
||||
// don't call this "unlocked" version directly
|
||||
template <typename T>
|
||||
int call_ssh2_function_unlocked(const T& lambda, bool check_for_errors = true);
|
||||
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
template <typename T>
|
||||
int call_ssh2_function(const T& lambda, bool check_for_errors = true);
|
||||
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
// if libssh2 returns an error, get extended info and throw a message with ${code} and ${message}
|
||||
// set appropriately.
|
||||
template <typename T>
|
||||
int call_ssh2_function_throw(const T& lambda, const char* message = "libssh2 call failed ${code} - ${message}", bool check_for_errors = true);
|
||||
|
||||
// this version is a little different, it handles functions like libssh2_sftp_init which return
|
||||
// a pointer instead of an int. These retry automatically if the result is NULL and the error
|
||||
// is LIBSSH2_ERROR_EAGAIN
|
||||
template <typename return_type>
|
||||
return_type call_ssh2_ptr_function_throw(std::function<return_type()> lambda, const char* message = "libssh2 call failed ${code} - ${message}", bool check_for_errors = true);
|
||||
|
||||
void wait_on_socket(int additionalDirections = 0);
|
||||
|
||||
void init_sftp();
|
||||
};
|
||||
|
||||
|
||||
// #define OLD_BLOCKING,
|
||||
// the OLD_BLOCKING version of these functions will ensure that if a libssh2 function returns
|
||||
// LIBSSH2_ERROR_EAGAIN, no other libssh2 functions will be called until that function has been
|
||||
// called again and returned some other value.
|
||||
//
|
||||
// if you don't define this and use the new version of this, we will release the lock and let
|
||||
// other libssh2 functions be called *unless* it appears that there was unwritten data.
|
||||
//
|
||||
// the OLD_BLOCKING version is too conservative -- if you try to read on a channel that doesn't
|
||||
// have any data, you're likely to deadlock. The new version is not heavily tested and may be
|
||||
// too lax, time will tell.
|
||||
#ifdef OLD_BLOCKING
|
||||
// don't call this "unlocked" version directly
|
||||
template <typename T>
|
||||
int client_impl::call_ssh2_function_unlocked(const T& lambda, bool check_for_errors /* = true */) {
|
||||
int ec = lambda();
|
||||
while (ec == LIBSSH2_ERROR_EAGAIN ) {
|
||||
wait_on_socket();
|
||||
ec = lambda();
|
||||
}
|
||||
|
||||
// this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN
|
||||
// but the internal session data indicates a data write is still in progress
|
||||
// set check_for_errors to false when closing the connection
|
||||
assert(!check_for_errors || !session->packet.olen);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
template <typename T>
|
||||
int client_impl::call_ssh2_function(const T& lambda, bool check_for_errors /* = true */) {
|
||||
fc::scoped_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
return call_ssh2_function_unlocked(lambda, check_for_errors);
|
||||
}
|
||||
#else
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
template <typename T>
|
||||
int client_impl::call_ssh2_function(const T& lambda, bool check_for_errors /* = true */) {
|
||||
fc::unique_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
int ec = lambda();
|
||||
while (ec == LIBSSH2_ERROR_EAGAIN) {
|
||||
bool unlock_to_wait = !session->packet.olen;
|
||||
if (unlock_to_wait)
|
||||
lock.unlock();
|
||||
wait_on_socket();
|
||||
if (unlock_to_wait)
|
||||
lock.lock();
|
||||
ec = lambda();
|
||||
}
|
||||
// this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN
|
||||
// but the internal session data indicates a data write is still in progress
|
||||
// set check_for_errors to false when closing the connection
|
||||
assert(!check_for_errors || !session->packet.olen);
|
||||
return ec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OLD_BLOCKING
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
// if libssh2 returns an error, get extended info and throw a message with ${code} and ${message}
|
||||
// set appropriately.
|
||||
template <typename T>
|
||||
int client_impl::call_ssh2_function_throw(const T& lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) {
|
||||
fc::scoped_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
int ec = call_ssh2_function_unlocked(lambda, check_for_errors);
|
||||
|
||||
if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) {
|
||||
ec = libssh2_sftp_last_error(sftp);
|
||||
FC_THROW(message, ("code", ec).set("message", "SFTP protocol error"));
|
||||
} else if( ec < 0 ) {
|
||||
char* msg = 0;
|
||||
ec = libssh2_session_last_error( session, &msg, 0, 0 );
|
||||
FC_THROW(message, ("code",ec).set("message",msg));
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
#else
|
||||
// calls into libssh2, waits and retries the function if we get LIBSSH2_ERROR_EAGAIN
|
||||
// if libssh2 returns an error, get extended info and throw a message with ${code} and ${message}
|
||||
// set appropriately.
|
||||
template <typename T>
|
||||
int client_impl::call_ssh2_function_throw(const T& lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) {
|
||||
fc::unique_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
int ec = lambda();
|
||||
while (ec == LIBSSH2_ERROR_EAGAIN) {
|
||||
bool unlock_to_wait = !session->packet.olen;
|
||||
if (unlock_to_wait)
|
||||
lock.unlock();
|
||||
wait_on_socket();
|
||||
if (unlock_to_wait)
|
||||
lock.lock();
|
||||
ec = lambda();
|
||||
}
|
||||
// this assert catches bugs in libssh2 if libssh2 returns ec != LIBSSH2_ERROR_EAGAIN
|
||||
// but the internal session data indicates a data write is still in progress
|
||||
// set check_for_errors to false when closing the connection
|
||||
assert(!check_for_errors || !session->packet.olen);
|
||||
|
||||
if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) {
|
||||
ec = libssh2_sftp_last_error(sftp);
|
||||
FC_THROW(message, ("code", ec).set("message", "SFTP protocol error"));
|
||||
} else if( ec < 0 ) {
|
||||
char* msg = 0;
|
||||
ec = libssh2_session_last_error( session, &msg, 0, 0 );
|
||||
FC_THROW(message, ("code",ec).set("message",msg));
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OLD_BLOCKING
|
||||
// this version is a little different, it handles functions like libssh2_sftp_init which return
|
||||
// a pointer instead of an int. These retry automatically if the result is NULL and the error
|
||||
// is LIBSSH2_ERROR_EAGAIN
|
||||
template <typename return_type>
|
||||
return_type client_impl::call_ssh2_ptr_function_throw(std::function<return_type()> lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) {
|
||||
fc::scoped_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
return_type ret = lambda();
|
||||
while (!ret) {
|
||||
char* msg = 0;
|
||||
int ec = libssh2_session_last_error(session,&msg,NULL,0);
|
||||
if ( ec == LIBSSH2_ERROR_EAGAIN ) {
|
||||
wait_on_socket();
|
||||
ret = lambda();
|
||||
} else if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) {
|
||||
ec = libssh2_sftp_last_error(sftp);
|
||||
FC_THROW(message, ("code", ec).set("message", "SFTP protocol error"));
|
||||
} else {
|
||||
ec = libssh2_session_last_error( session, &msg, 0, 0 );
|
||||
FC_THROW(message, ("code",ec).set("message",msg));
|
||||
}
|
||||
}
|
||||
assert(!check_for_errors || !session->packet.olen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
// this version is a little different, it handles functions like libssh2_sftp_init which return
|
||||
// a pointer instead of an int. These retry automatically if the result is NULL and the error
|
||||
// is LIBSSH2_ERROR_EAGAIN
|
||||
template <typename return_type>
|
||||
return_type client_impl::call_ssh2_ptr_function_throw(std::function<return_type()> lambda, const char* message /* = "libssh2 call failed ${code} - ${message}" */, bool check_for_errors /* = true */) {
|
||||
fc::unique_lock<fc::mutex> lock(ssh_session_mutex);
|
||||
return_type ret = lambda();
|
||||
while (!ret) {
|
||||
char* msg = 0;
|
||||
int ec = libssh2_session_last_error(session,&msg,NULL,0);
|
||||
if ( ec == LIBSSH2_ERROR_EAGAIN ) {
|
||||
bool unlock_to_wait = !session->packet.olen;
|
||||
if (unlock_to_wait)
|
||||
lock.unlock();
|
||||
wait_on_socket();
|
||||
if (unlock_to_wait)
|
||||
lock.lock();
|
||||
ret = lambda();
|
||||
} else if (ec == LIBSSH2_ERROR_SFTP_PROTOCOL && sftp) {
|
||||
ec = libssh2_sftp_last_error(sftp);
|
||||
FC_THROW(message, ("code", ec).set("message", "SFTP protocol error"));
|
||||
} else {
|
||||
ec = libssh2_session_last_error( session, &msg, 0, 0 );
|
||||
FC_THROW(message, ("code",ec).set("message",msg));
|
||||
}
|
||||
}
|
||||
assert(!check_for_errors || !session->packet.olen);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
@ -1,334 +0,0 @@
|
|||
#define NOMINMAX // prevent windows from defining min and max macros
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fc/ssh/client.hpp>
|
||||
#include <fc/ssh/process.hpp>
|
||||
#include <fc/io/sstream.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/thread/unique_lock.hpp>
|
||||
|
||||
#include "client_impl.hpp"
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#pragma warning (disable : 4355)
|
||||
#endif
|
||||
|
||||
namespace fc { namespace ssh {
|
||||
|
||||
namespace detail {
|
||||
class process_impl;
|
||||
class process_istream : public fc::istream {
|
||||
public:
|
||||
process_istream( process_impl& p, int c )
|
||||
:proc(p),chan(c){}
|
||||
|
||||
virtual size_t readsome( char* buf, size_t len );
|
||||
|
||||
virtual bool eof() const;
|
||||
|
||||
process_impl& proc;
|
||||
int chan;
|
||||
};
|
||||
|
||||
class process_ostream : public fc::ostream {
|
||||
public:
|
||||
process_ostream( process_impl& p )
|
||||
:proc(p){}
|
||||
|
||||
virtual size_t writesome( const char* buf, size_t len );
|
||||
virtual void close();
|
||||
virtual void flush();
|
||||
|
||||
process_impl& proc;
|
||||
};
|
||||
|
||||
class process_impl {
|
||||
public:
|
||||
process_impl( client_ptr c );
|
||||
~process_impl();
|
||||
//process_impl( const client& c, const fc::string& cmd, const fc::string& pty_type );
|
||||
void exec(const fc::path& exe, vector<string> args,
|
||||
const fc::path& work_dir /* = fc::path() */, fc::iprocess::exec_opts opts /* = open_all */);
|
||||
|
||||
|
||||
int read_some( char* data, size_t len, int stream_id );
|
||||
int write_some( const char* data, size_t len, int stream_id );
|
||||
void flush();
|
||||
void send_eof();
|
||||
|
||||
LIBSSH2_CHANNEL* chan;
|
||||
client_ptr sshc;
|
||||
buffered_ostream_ptr buffered_std_in;
|
||||
buffered_istream_ptr buffered_std_out;
|
||||
buffered_istream_ptr buffered_std_err;
|
||||
|
||||
fc::string command;
|
||||
fc::promise<int>::ptr result;
|
||||
|
||||
fc::optional<int> return_code;
|
||||
fc::ostring return_signal;
|
||||
fc::ostring return_signal_message;
|
||||
private:
|
||||
static fc::string windows_shell_escape(const fc::string& str);
|
||||
static fc::string unix_shell_escape(const fc::string& str);
|
||||
static fc::string windows_shell_escape_command(const fc::path& exe, const vector<string>& args);
|
||||
static fc::string unix_shell_escape_command(const fc::path& exe, const vector<string>& args);
|
||||
};
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
|
||||
process::process(client_ptr c) :
|
||||
my(new detail::process_impl(c))
|
||||
{}
|
||||
|
||||
process::~process()
|
||||
{}
|
||||
|
||||
iprocess& process::exec( const fc::path& exe, vector<string> args,
|
||||
const fc::path& work_dir /* = fc::path() */, exec_opts opts /* = open_all */ ) {
|
||||
my->exec(exe, args, work_dir, opts);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks until the result code of the process has been returned.
|
||||
*/
|
||||
int process::result() {
|
||||
if (!my->return_code && !my->return_signal) {
|
||||
// we don't have any cached exit status, so wait and obtain the values now
|
||||
my->sshc->my->call_ssh2_function(boost::bind(libssh2_channel_wait_eof, my->chan));
|
||||
my->sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_wait_closed, my->chan),
|
||||
"Error waiting on socket to close: ${message}");
|
||||
|
||||
char* exit_signal;
|
||||
char* error_message;
|
||||
libssh2_channel_get_exit_signal(my->chan, &exit_signal, NULL, &error_message, NULL, NULL, NULL);
|
||||
if (exit_signal) {
|
||||
// process terminated with a signal
|
||||
my->return_signal = exit_signal;
|
||||
libssh2_free(my->chan->session, exit_signal);
|
||||
if (error_message) {
|
||||
my->return_signal_message = error_message;
|
||||
libssh2_free(my->chan->session, error_message);
|
||||
}
|
||||
} else
|
||||
my->return_code = libssh2_channel_get_exit_status(my->chan);
|
||||
}
|
||||
if (my->return_signal)
|
||||
FC_THROW("process terminated with signal ${signal}: ${signal_message}", ("signal", *my->return_signal)
|
||||
("signal_message", my->return_signal_message ? *my->return_signal_message : ""));
|
||||
else
|
||||
return *my->return_code;
|
||||
}
|
||||
|
||||
void process::kill() {
|
||||
elog("error: fc::ssh::process::kill() not supported");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief returns a stream that writes to the procss' stdin
|
||||
*/
|
||||
fc::buffered_ostream_ptr process::in_stream() {
|
||||
return my->buffered_std_in;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a stream that reads from the process' stdout
|
||||
*/
|
||||
fc::buffered_istream_ptr process::out_stream() {
|
||||
return my->buffered_std_out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns a stream that reads from the process' stderr
|
||||
*/
|
||||
fc::buffered_istream_ptr process::err_stream() {
|
||||
return my->buffered_std_err;
|
||||
}
|
||||
|
||||
void detail::process_impl::flush() {
|
||||
if( !chan ) return;
|
||||
/* channel_flush deleates input buffer, and does not ensure writes go out
|
||||
*
|
||||
int ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA);
|
||||
while( ec == LIBSSH2_ERROR_EAGAIN ) {
|
||||
sshc.my->wait_on_socket();
|
||||
ec = libssh2_channel_flush_ex( chan, LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA );
|
||||
}
|
||||
ec = libssh2_channel_flush( chan );
|
||||
while( ec == LIBSSH2_ERROR_EAGAIN ) {
|
||||
sshc.my->wait_on_socket();
|
||||
ec = libssh2_channel_flush( chan );
|
||||
}
|
||||
if( ec < 0 ) {
|
||||
FC_THROW( "ssh flush failed", ( "channel_error", ec) );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int detail::process_impl::read_some( char* data, size_t len, int stream_id ){
|
||||
if( !sshc->my->session ) { FC_THROW( "Session closed" ); }
|
||||
int rc;
|
||||
char* buf = data;
|
||||
size_t buflen = len;
|
||||
do {
|
||||
rc = sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_read_ex, chan, stream_id, buf, buflen),
|
||||
"read failed: ${message}");
|
||||
if( rc > 0 ) {
|
||||
buf += rc;
|
||||
buflen -= rc;
|
||||
return buf-data;
|
||||
} else if( rc == 0 ) {
|
||||
if( libssh2_channel_eof( chan ) )
|
||||
return -1; // eof
|
||||
sshc->my->wait_on_socket();
|
||||
}
|
||||
} while( rc >= 0 && buflen);
|
||||
return buf-data;
|
||||
}
|
||||
|
||||
int detail::process_impl::write_some( const char* data, size_t len, int stream_id ) {
|
||||
if( !sshc->my->session ) { FC_THROW( "Session closed" ); }
|
||||
|
||||
int rc;
|
||||
const char* buf = data;
|
||||
size_t buflen = len;
|
||||
do {
|
||||
rc = sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_write_ex, chan, stream_id, buf, buflen),
|
||||
"write failed: ${message}");
|
||||
if( rc > 0 ) {
|
||||
buf += rc;
|
||||
buflen -= rc;
|
||||
return buf-data;
|
||||
} else if( rc == 0 ) {
|
||||
if( libssh2_channel_eof( chan ) ) {
|
||||
FC_THROW( "EOF" );
|
||||
//return -1; // eof
|
||||
}
|
||||
}
|
||||
} while( rc >= 0 && buflen);
|
||||
return buf-data;
|
||||
}
|
||||
|
||||
void detail::process_impl::send_eof() {
|
||||
if( sshc->my->session )
|
||||
sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_send_eof, chan),
|
||||
"send eof failed: ${message}");
|
||||
}
|
||||
|
||||
size_t detail::process_istream::readsome( char* buf, size_t len ) {
|
||||
int bytesRead = proc.read_some(buf, len, chan);
|
||||
if (bytesRead < 0)
|
||||
FC_THROW("EOF");
|
||||
else
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool detail::process_istream::eof()const {
|
||||
return 0 != libssh2_channel_eof( proc.chan );
|
||||
}
|
||||
|
||||
size_t detail::process_ostream::writesome( const char* buf, size_t len ) {
|
||||
return proc.write_some(buf, len, 0);
|
||||
}
|
||||
|
||||
void detail::process_ostream::close(){
|
||||
proc.send_eof();
|
||||
}
|
||||
|
||||
void detail::process_ostream::flush(){
|
||||
proc.flush();
|
||||
}
|
||||
|
||||
detail::process_impl::process_impl( client_ptr c )
|
||||
:chan(nullptr),
|
||||
sshc(c),
|
||||
buffered_std_in(new buffered_ostream(ostream_ptr(new process_ostream(*this)))),
|
||||
buffered_std_out(new buffered_istream(istream_ptr(new process_istream(*this, 0)))),
|
||||
buffered_std_err(new buffered_istream(istream_ptr(new process_istream(*this, SSH_EXTENDED_DATA_STDERR))))
|
||||
{
|
||||
}
|
||||
|
||||
detail::process_impl::~process_impl() {
|
||||
if (chan) {
|
||||
sshc->my->call_ssh2_function(boost::bind(libssh2_channel_free, chan));
|
||||
chan = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// these rules work pretty well for a standard bash shell on unix
|
||||
fc::string detail::process_impl::unix_shell_escape(const fc::string& str) {
|
||||
if (str.find_first_of(" ;&|><*?`$(){}[]!#'\"") == fc::string::npos)
|
||||
return str;
|
||||
fc::string escaped_quotes(str);
|
||||
for (size_t start = escaped_quotes.find("'");
|
||||
start != fc::string::npos;
|
||||
start = escaped_quotes.find("'", start + 5))
|
||||
escaped_quotes.replace(start, 1, "'\"'\"'");
|
||||
fc::string escaped_str("\'");
|
||||
escaped_str += escaped_quotes;
|
||||
escaped_str += "\'";
|
||||
return escaped_str;
|
||||
}
|
||||
fc::string detail::process_impl::unix_shell_escape_command(const fc::path& exe, const vector<string>& args) {
|
||||
fc::stringstream command_line;
|
||||
command_line << unix_shell_escape(exe.string());
|
||||
for (unsigned i = 0; i < args.size(); ++i)
|
||||
command_line << " " << unix_shell_escape(args[i]);
|
||||
return command_line.str();
|
||||
}
|
||||
|
||||
// windows command-line escaping rules are a disaster, partly because how the command-line is
|
||||
// parsed depends on what program you're running. In windows, the command line is passed in
|
||||
// as a single string, and the process is left to interpret it as it sees fit. The standard
|
||||
// C runtime uses one set of rules, the function CommandLineToArgvW usually used by
|
||||
// GUI-mode programs uses a different set.
|
||||
// Here we try to find a common denominator that works well for simple cases
|
||||
// it's only minimally tested right now due to time constraints.
|
||||
fc::string detail::process_impl::windows_shell_escape(const fc::string& str) {
|
||||
if (str.find_first_of(" \"") == fc::string::npos)
|
||||
return str;
|
||||
fc::string escaped_quotes(str);
|
||||
for (size_t start = escaped_quotes.find("\"");
|
||||
start != fc::string::npos;
|
||||
start = escaped_quotes.find("\"", start + 2))
|
||||
escaped_quotes.replace(start, 1, "\\\"");
|
||||
fc::string escaped_str("\"");
|
||||
escaped_str += escaped_quotes;
|
||||
escaped_str += "\"";
|
||||
return escaped_str;
|
||||
}
|
||||
fc::string detail::process_impl::windows_shell_escape_command(const fc::path& exe, const vector<string>& args) {
|
||||
fc::stringstream command_line;
|
||||
command_line << windows_shell_escape(exe.string());
|
||||
for (unsigned i = 0; i < args.size(); ++i)
|
||||
command_line << " " << windows_shell_escape(args[i]);
|
||||
return command_line.str();
|
||||
}
|
||||
|
||||
void detail::process_impl::exec(const fc::path& exe, vector<string> args,
|
||||
const fc::path& work_dir /* = fc::path() */,
|
||||
fc::iprocess::exec_opts opts /* = open_all */) {
|
||||
chan = sshc->my->open_channel("");
|
||||
|
||||
sshc->my->call_ssh2_function(boost::bind(libssh2_channel_handle_extended_data2, chan, LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL));
|
||||
|
||||
try {
|
||||
fc::scoped_lock<fc::mutex> process_startup_lock(sshc->my->process_startup_mutex);
|
||||
fc::string command_line = sshc->my->remote_system_is_windows ? windows_shell_escape_command(exe, args) : unix_shell_escape_command(exe, args);
|
||||
sshc->my->call_ssh2_function_throw(boost::bind(libssh2_channel_process_startup, chan, "exec", sizeof("exec") - 1, command_line.c_str(), command_line.size()),
|
||||
"exec failed: ${message}"); // equiv to libssh2_channel_exec(chan, cmd) macro
|
||||
} catch (fc::exception& er) {
|
||||
elog( "error starting process" );
|
||||
FC_RETHROW_EXCEPTION(er, error, "error starting process");
|
||||
}
|
||||
}
|
||||
|
||||
} }
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
|
|
|
|||
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,36 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <udt.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace UDT;
|
||||
|
||||
int main()
|
||||
{
|
||||
UDTSOCKET client = UDT::socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
sockaddr_in serv_addr;
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(9000);
|
||||
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
|
||||
|
||||
memset(&(serv_addr.sin_zero), '\0', 8);
|
||||
|
||||
// connect to the server, implict bind
|
||||
if (UDT::ERROR == UDT::connect(client, (sockaddr*)&serv_addr, sizeof(serv_addr)))
|
||||
{
|
||||
cout << "connect: " << UDT::getlasterror().getErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* hello = "hello world! 3\n";
|
||||
if (UDT::ERROR == UDT::send(client, hello, strlen(hello) + 1, 0))
|
||||
{
|
||||
cout << "send: " << UDT::getlasterror().getErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
UDT::close(client);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <udt.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
UDTSOCKET serv = UDT::socket(AF_INET, SOCK_STREAM, 0);
|
||||
bool block = false;
|
||||
|
||||
sockaddr_in my_addr;
|
||||
my_addr.sin_family = AF_INET;
|
||||
my_addr.sin_port = htons(9000);
|
||||
my_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
memset(&(my_addr.sin_zero), '\0', 8);
|
||||
|
||||
if (UDT::ERROR == UDT::bind(serv, (sockaddr*)&my_addr, sizeof(my_addr)))
|
||||
{
|
||||
cout << "bind: " << UDT::getlasterror().getErrorMessage();
|
||||
return 0;
|
||||
}
|
||||
UDT::listen(serv, 10);
|
||||
|
||||
int namelen;
|
||||
sockaddr_in their_addr;
|
||||
|
||||
|
||||
UDT::setsockopt(serv, 0, UDT_SNDSYN, &block, sizeof(bool));
|
||||
UDT::setsockopt(serv, 0, UDT_RCVSYN, &block, sizeof(bool));
|
||||
UDTSOCKET recver = UDT::accept(serv, (sockaddr*)&their_addr, &namelen);
|
||||
if( recver == UDT::INVALID_SOCK )
|
||||
{
|
||||
if( UDT::getlasterror_code() == CUDTException::EASYNCRCV )
|
||||
{
|
||||
std::cout << "nothing yet... better luck next time\n";
|
||||
}
|
||||
}
|
||||
auto pollid = UDT::epoll_create();
|
||||
UDT::epoll_add_usock(pollid, serv, nullptr );// const int* events = NULL);
|
||||
std::set<UDTSOCKET> readready;
|
||||
std::set<UDTSOCKET> writeready;
|
||||
std::cout << "waiting for 5 seconds\n";
|
||||
UDT::epoll_wait( pollid, &readready, &writeready, 10000 );
|
||||
|
||||
|
||||
recver = UDT::accept(serv, (sockaddr*)&their_addr, &namelen);
|
||||
if( recver == UDT::INVALID_SOCK )
|
||||
{
|
||||
if( UDT::getlasterror_code() == CUDTException::EASYNCRCV )
|
||||
{
|
||||
std::cout << "nothing yet... better luck next time\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
UDT::setsockopt(recver, 0, UDT_SNDSYN, &block, sizeof(bool));
|
||||
UDT::setsockopt(recver, 0, UDT_RCVSYN, &block, sizeof(bool));
|
||||
UDT::epoll_remove_usock(pollid, serv );// const int* events = NULL);
|
||||
int events = UDT_EPOLL_IN;
|
||||
|
||||
UDT::epoll_add_usock(pollid, recver, &events );// const int* events = NULL);
|
||||
|
||||
readready.clear();
|
||||
UDT::epoll_wait( pollid, &readready, &writeready, 5000 );
|
||||
|
||||
char ip[16];
|
||||
cout << "new connection: " << inet_ntoa(their_addr.sin_addr) << ":" << ntohs(their_addr.sin_port) << endl;
|
||||
|
||||
char data[100];
|
||||
|
||||
while (UDT::ERROR == UDT::recv(recver, data, 100, 0))
|
||||
{
|
||||
cout << "recv:" << UDT::getlasterror().getErrorMessage() << endl;
|
||||
UDT::epoll_wait( pollid, &readready, &writeready, 5000 );
|
||||
}
|
||||
|
||||
cout << data << endl;
|
||||
|
||||
UDT::close(recver);
|
||||
UDT::close(serv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#include <fc/network/udt_socket.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace fc;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
try {
|
||||
udt_socket sock;
|
||||
sock.bind( fc::ip::endpoint::from_string( "127.0.0.1:6666" ) );
|
||||
ilog( "." );
|
||||
sock.connect_to( fc::ip::endpoint::from_string( "127.0.0.1:7777" ) );
|
||||
ilog( "after connect to..." );
|
||||
|
||||
std::cout << "local endpoint: " <<std::string( sock.local_endpoint() ) <<"\n";
|
||||
std::cout << "remote endpoint: " <<std::string( sock.remote_endpoint() ) <<"\n";
|
||||
|
||||
std::string hello = "hello world\n";
|
||||
for( uint32_t i = 0; i < 1000000; ++i )
|
||||
{
|
||||
sock.write( hello.c_str(), hello.size() );
|
||||
}
|
||||
ilog( "closing" );
|
||||
sock.close();
|
||||
usleep( fc::seconds(1) );
|
||||
/*
|
||||
std::vector<char> response;
|
||||
response.resize(1024);
|
||||
int r = sock.readsome( response.data(), response.size() );
|
||||
while( r )
|
||||
{
|
||||
std::cout.write( response.data(), r );
|
||||
r = sock.readsome( response.data(), response.size() );
|
||||
}
|
||||
*/
|
||||
// if we exit too quickly, UDT will not have a chance to
|
||||
// send the graceful close message.
|
||||
//fc::usleep( fc::seconds(1) );
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
elog( "${e}", ("e",e.to_detail_string() ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#include <fc/network/udt_socket.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace fc;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
try {
|
||||
udt_server serv;
|
||||
serv.listen( fc::ip::endpoint::from_string( "127.0.0.1:7777" ) );
|
||||
|
||||
while( true )
|
||||
{
|
||||
udt_socket sock;
|
||||
serv.accept( sock );
|
||||
|
||||
std::vector<char> response;
|
||||
response.resize(1024);
|
||||
int r = sock.readsome( response.data(), response.size() );
|
||||
while( r )
|
||||
{
|
||||
std::cout.write( response.data(), r );
|
||||
r = sock.readsome( response.data(), response.size() );
|
||||
//sock.write( response.data(), response.size() );
|
||||
}
|
||||
|
||||
std::string goodbye = "goodbye cruel world";
|
||||
sock.write( goodbye.c_str(), goodbye.size() );
|
||||
}
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
elog( "${e}", ("e",e.to_detail_string() ) );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7f95b37e554453262e2bcda830724fc362614103
|
||||
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
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue