commit
c8c05254b1
130 changed files with 2497 additions and 19690 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -48,7 +48,4 @@ fc_automoc.cpp
|
|||
git_revision.cpp
|
||||
GitSHA3.cpp
|
||||
|
||||
ntp_test
|
||||
task_cancel_test
|
||||
udt_client
|
||||
udt_server
|
||||
|
|
|
|||
5
.gitmodules
vendored
5
.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
|
||||
url = https://github.com/bitshares/secp256k1-zkp.git
|
||||
[submodule "vendor/websocketpp"]
|
||||
path = vendor/websocketpp
|
||||
url = https://github.com/zaphoyd/websocketpp.git
|
||||
|
|
|
|||
196
CMakeLists.txt
196
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)
|
||||
|
|
@ -182,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
|
||||
|
|
@ -199,7 +213,6 @@ set( fc_sources
|
|||
src/crypto/aes.cpp
|
||||
src/crypto/crc.cpp
|
||||
src/crypto/city.cpp
|
||||
src/crypto/base32.cpp
|
||||
src/crypto/base36.cpp
|
||||
src/crypto/base58.cpp
|
||||
src/crypto/base64.cpp
|
||||
|
|
@ -219,20 +232,16 @@ set( fc_sources
|
|||
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
|
||||
src/network/ntp.cpp
|
||||
src/network/ip.cpp
|
||||
src/network/ntp.cpp
|
||||
src/network/rate_limiting.cpp
|
||||
src/network/resolve.cpp
|
||||
src/network/url.cpp
|
||||
src/network/gntp.cpp
|
||||
src/compress/smaz.cpp
|
||||
src/compress/zlib.cpp
|
||||
vendor/cyoencode-1.0.2/src/CyoDecode.c
|
||||
vendor/cyoencode-1.0.2/src/CyoEncode.c
|
||||
)
|
||||
|
||||
file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h )
|
||||
|
|
@ -245,10 +254,10 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/git_revision.cpp.in" "${CMAKE_CU
|
|||
list(APPEND sources "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp")
|
||||
list(APPEND sources ${fc_headers})
|
||||
|
||||
add_subdirectory( vendor/websocketpp )
|
||||
add_subdirectory( vendor/udt4 )
|
||||
add_subdirectory( vendor/websocketpp EXCLUDE_FROM_ALL )
|
||||
|
||||
setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC DONT_INSTALL_LIBRARY )
|
||||
setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC )
|
||||
install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" DESTINATION include )
|
||||
|
||||
# begin readline stuff
|
||||
find_package(Curses)
|
||||
|
|
@ -269,6 +278,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
|
||||
|
|
@ -279,47 +292,96 @@ IF(WIN32)
|
|||
# autodetecting code to do the right thing.
|
||||
_WEBSOCKETPP_CPP11_CHRONO_
|
||||
)
|
||||
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} ${CPP_STANDARD} -Wall -fnon-call-exceptions")
|
||||
|
||||
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
|
||||
if( CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.0.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0.0 )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-partial-specialization" )
|
||||
endif()
|
||||
endif()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -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")
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ASIO_HAS_STD_CHRONO")
|
||||
|
||||
OPTION( LOG_LONG_API "Log long API calls over websocket (ON OR OFF)" ON )
|
||||
MESSAGE( STATUS "LOG_LONG_API: ${LOG_LONG_API}" )
|
||||
if( LOG_LONG_API )
|
||||
SET( LOG_LONG_API_MAX_MS 1000 CACHE STRING "Max API execution time in ms" )
|
||||
SET( LOG_LONG_API_WARN_MS 750 CACHE STRING "API execution time in ms at which to warn" )
|
||||
MESSAGE( STATUS " " )
|
||||
MESSAGE( STATUS " LOGGING LONG API CALLS" )
|
||||
MESSAGE( STATUS " MAX MS: ${LOG_LONG_API_MAX_MS}" )
|
||||
MESSAGE( STATUS " WARN MS: ${LOG_LONG_API_WARN_MS}" )
|
||||
MESSAGE( STATUS " " )
|
||||
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLOG_LONG_API -DLOG_LONG_API_MAX_MS=${LOG_LONG_API_MAX_MS} -DLOG_LONG_API_WARN_MS=${LOG_LONG_API_WARN_MS}" )
|
||||
SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLOG_LONG_API -DLOG_LONG_API_MAX_MS=${LOG_LONG_API_MAX_MS} -DLOG_LONG_API_WARN_MS=${LOG_LONG_API_WARN_MS}" )
|
||||
endif()
|
||||
|
||||
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_DIRS}
|
||||
)
|
||||
|
||||
#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} ${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" )
|
||||
|
|
@ -327,77 +389,16 @@ 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 )
|
||||
|
||||
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
|
||||
|
|
@ -481,14 +482,6 @@ if(WIN32)
|
|||
|
||||
endif(WIN32)
|
||||
|
||||
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 )
|
||||
ENDIF(APPLE)
|
||||
|
||||
SET(OPENSSL_CONF_TARGET )
|
||||
IF(DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||
SET (OPENSSL_CONF_TARGET ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
|
|
@ -497,8 +490,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,127 +0,0 @@
|
|||
# Find Wt includes and libraries
|
||||
#
|
||||
# This script sets the following variables:
|
||||
#
|
||||
# Wt_INCLUDE_DIR
|
||||
# Wt_LIBRARIES - Release libraries
|
||||
# Wt_FOUND - True if release libraries found
|
||||
# Wt_DEBUG_LIBRARIES - Debug libraries
|
||||
# Wt_DEBUG_FOUND - True if debug libraries found
|
||||
#
|
||||
# To direct the script to a particular Wt installation, use the
|
||||
# standard cmake variables CMAKE_INCLUDE_PATH and CMAKE_LIBRARY_PATH
|
||||
#
|
||||
# To use this script to find Wt, when using the new style for include files:
|
||||
# #include <Wt/WLineEdit>
|
||||
# #include <Wt/Ext/LineEdit>
|
||||
# #include <Wt/Chart/WPieChart>
|
||||
#
|
||||
# include the following CMake snippet in your project:
|
||||
#
|
||||
# FIND_PACKAGE( Wt REQUIRED )
|
||||
# INCLUDE_DIRECTORIES( ${Wt_INCLUDE_DIR} )
|
||||
# TARGET_LINK_LIBRARIES( yourexe
|
||||
# ${Wt_DEBUG_LIBRARY} # or {Wt_LIBRARY}
|
||||
# ${Wt_HTTP_DEBUG_LIBRARY} # or {Wt_HTTP_LIBRARY}
|
||||
# ${Wt_EXT_DEBUG_LIBRARY} # or {Wt_EXT_LIBRARY}
|
||||
# )
|
||||
#
|
||||
# To use this script to find Wt, when using the old include style:
|
||||
# #include <WLineEdit>
|
||||
# #include <Ext/LineEdit>
|
||||
# #include <Chart/WPieChart>
|
||||
# style of include files, change the INCLUDE_DIRECTORIES statement to:
|
||||
# INCLUDE_DIRECTORIES( ${Wt_INCLUDE_DIR} ${Wt_INCLUDE_DIR}/Wt )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# Copyright (c) 2007, Pau Garcia i Quiles, <pgquiles@elpauer.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
FIND_PATH( Wt_INCLUDE_DIR NAMES Wt/WObject PATHS ENV PATH PATH_SUFFIXES include wt )
|
||||
|
||||
SET( Wt_FIND_COMPONENTS Release Debug )
|
||||
|
||||
IF( Wt_INCLUDE_DIR )
|
||||
FIND_LIBRARY( Wt_LIBRARY NAMES wt PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_EXT_LIBRARY NAMES wtext PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_HTTP_LIBRARY NAMES wthttp PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_FCGI_LIBRARY NAMES wtfcgi PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_DBO_LIBRARY NAMES wtdbo PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_DBOSQLITE3_LIBRARY NAMES wtdbosqlite3 PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
FIND_LIBRARY( Wt_DBOPOSTGRES_LIBRARY NAMES wtdbopostgres PATHS PATH PATH_SUFFIXES lib lib-release lib_release )
|
||||
|
||||
FIND_LIBRARY( Wt_DEBUG_LIBRARY NAMES wtd wt PATHS PATH PATH_SUFFIXES lib libd lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_EXT_DEBUG_LIBRARY NAMES wtextd wtext PATHS PATH PATH_SUFFIXES lib libd lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_HTTP_DEBUG_LIBRARY NAMES wthttpd wthttp PATHS PATH PATH_SUFFIXES lib libd lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_FCGI_DEBUG_LIBRARY NAMES wtfcgid wtfcgi PATHS PATH PATH_SUFFIXES lib libd lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_DBO_DEBUG_LIBRARY NAMES wtdbod wtdbo PATHS PATH PATH_SUFFIXES lib lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_DBOSQLITE3_DEBUG_LIBRARY NAMES wtdbosqlite3d wtdbosqlite3 PATHS PATH PATH_SUFFIXES lib lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
FIND_LIBRARY( Wt_DBOPOSTGRES_DEBUG_LIBRARY NAMES wtdbopostgresd wtdbopostgres PATHS PATH PATH_SUFFIXES lib lib-debug lib_debug HINTS /usr/lib/debug/usr/lib)
|
||||
|
||||
IF( Wt_LIBRARY AND Wt_EXT_LIBRARY AND Wt_HTTP_LIBRARY)
|
||||
SET( Wt_FOUND TRUE )
|
||||
SET( Wt_FIND_REQUIRED_Release TRUE )
|
||||
SET( Wt_LIBRARIES ${Wt_HTTP_LIBRARY} ${Wt_EXT_LIBRARY} ${Wt_LIBRARY} )
|
||||
ENDIF( Wt_LIBRARY AND Wt_EXT_LIBRARY AND Wt_HTTP_LIBRARY)
|
||||
|
||||
IF( Wt_DBO_LIBRARY )
|
||||
SET( Wt_LIBRARIES ${Wt_LIBRARIES} ${Wt_DBO_LIBRARY} )
|
||||
IF( Wt_DBOSQLITE3_LIBRARY )
|
||||
SET( Wt_LIBRARIES ${Wt_LIBRARIES} ${Wt_DBOSQLITE3_LIBRARY} )
|
||||
ENDIF( Wt_DBOSQLITE3_LIBRARY )
|
||||
IF( Wt_DBOPOSTGRES_LIBRARY )
|
||||
SET( Wt_LIBRARIES ${Wt_LIBRARIES} ${Wt_DBOPOSTGRES_LIBRARY} )
|
||||
ENDIF( Wt_DBOPOSTGRES_LIBRARY )
|
||||
ENDIF( Wt_DBO_LIBRARY )
|
||||
|
||||
IF( Wt_FCGI_LIBRARY )
|
||||
SET( Wt_LIBRARIES ${Wt_LIBRARIES} ${Wt_FCGI_LIBRARY} )
|
||||
ENDIF( Wt_FCGI_LIBRARY )
|
||||
|
||||
IF( Wt_DEBUG_LIBRARY AND Wt_EXT_DEBUG_LIBRARY AND Wt_HTTP_DEBUG_LIBRARY)
|
||||
SET( Wt_DEBUG_FOUND TRUE )
|
||||
SET( Wt_FIND_REQUIRED_Debug TRUE )
|
||||
SET( Wt_DEBUG_LIBRARIES ${Wt_HTTP_DEBUG_LIBRARY} ${Wt_EXT_DEBUG_LIBRARY} ${Wt_DEBUG_LIBRARY} )
|
||||
ENDIF( Wt_DEBUG_LIBRARY AND Wt_EXT_DEBUG_LIBRARY AND Wt_HTTP_DEBUG_LIBRARY)
|
||||
|
||||
IF( Wt_DBO_DEBUG_LIBRARY )
|
||||
SET( Wt_DEBUG_LIBRARIES ${Wt_DEBUG_LIBRARIES} ${Wt_DBO_DEBUG_LIBRARY} )
|
||||
IF( Wt_DBOSQLITE3_DEBUG_LIBRARY )
|
||||
SET( Wt_DEBUG_LIBRARIES ${Wt_DEBUG_LIBRARIES} ${Wt_DBOSQLITE3_DEBUG_LIBRARY} )
|
||||
ENDIF( Wt_DBOSQLITE3_DEBUG_LIBRARY )
|
||||
IF( Wt_DBOPOSTGRES_DEBUG_LIBRARY )
|
||||
SET( Wt_DEBUG_LIBRARIES ${Wt_DEBUG_LIBRARIES} ${Wt_DBOPOSTGRES_DEBUG_LIBRARY} )
|
||||
ENDIF( Wt_DBOPOSTGRES_DEBUG_LIBRARY )
|
||||
ENDIF( Wt_DBO_DEBUG_LIBRARY )
|
||||
|
||||
IF( Wt_FCGI_DEBUG_LIBRARY )
|
||||
SET( Wt_DEBUG_LIBRARIES ${Wt_DEBUG_LIBRARIES} ${Wt_FCGI_DEBUG_LIBRARY} )
|
||||
ENDIF( Wt_FCGI_DEBUG_LIBRARY )
|
||||
|
||||
IF(Wt_FOUND)
|
||||
IF (NOT Wt_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found the Wt libraries at ${Wt_LIBRARIES}")
|
||||
MESSAGE(STATUS "Found the Wt headers at ${Wt_INCLUDE_DIR}")
|
||||
ENDIF (NOT Wt_FIND_QUIETLY)
|
||||
ELSE(Wt_FOUND)
|
||||
IF(Wt_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could NOT find Wt")
|
||||
ENDIF(Wt_FIND_REQUIRED)
|
||||
ENDIF(Wt_FOUND)
|
||||
|
||||
IF(Wt_DEBUG_FOUND)
|
||||
IF (NOT Wt_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found the Wt debug libraries at ${Wt_DEBUG_LIBRARIES}")
|
||||
MESSAGE(STATUS "Found the Wt debug headers at ${Wt_INCLUDE_DIR}")
|
||||
ENDIF (NOT Wt_FIND_QUIETLY)
|
||||
ELSE(Wt_DEBUG_FOUND)
|
||||
IF(Wt_FIND_REQUIRED_Debug)
|
||||
MESSAGE(FATAL_ERROR "Could NOT find Wt debug libraries")
|
||||
ENDIF(Wt_FIND_REQUIRED_Debug)
|
||||
ENDIF(Wt_DEBUG_FOUND)
|
||||
|
||||
ENDIF( Wt_INCLUDE_DIR )
|
||||
|
|
@ -58,7 +58,7 @@ function(get_git_head_revision _refspecvar _hashvar)
|
|||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
get_filename_component(GIT_DIR ${GIT_DIR_RELATIVE} ABSOLUTE BASE_DIR ${SUBMODULE_DIR})
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
|
|
|||
|
|
@ -21,10 +21,16 @@ namespace fc {
|
|||
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
T& operator[]( size_t pos ) { assert( pos < N); return data[pos]; }
|
||||
const T& operator[]( size_t pos )const { assert( pos < N); return data[pos]; }
|
||||
|
||||
|
||||
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, typename... A>
|
||||
void unpack(Stream& s, flat_map<K, V, A...>& 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
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base32( const fc::string& b32 );
|
||||
fc::string to_base32( const std::vector<char>& vec );
|
||||
fc::string to_base32( const char* data, size_t len );
|
||||
}
|
||||
|
|
@ -123,7 +123,7 @@ namespace fc {
|
|||
fc::sha512 get_shared_secret( const public_key& pub )const;
|
||||
|
||||
// signature sign( const fc::sha256& digest )const;
|
||||
compact_signature sign_compact( const fc::sha256& digest )const;
|
||||
compact_signature sign_compact( const fc::sha256& digest, bool require_canonical = true )const;
|
||||
// bool verify( const fc::sha256& digest, const signature& sig );
|
||||
|
||||
public_key get_public_key()const;
|
||||
|
|
@ -218,8 +218,8 @@ namespace fc {
|
|||
|
||||
struct range_proof_info
|
||||
{
|
||||
int exp;
|
||||
int mantissa;
|
||||
int64_t exp;
|
||||
int64_t mantissa;
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
};
|
||||
|
|
|
|||
107
include/fc/crypto/hash_ctr_rng.hpp
Normal file
107
include/fc/crypto/hash_ctr_rng.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/multiprecision/integer.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Always returns 0. Useful for testing.
|
||||
*/
|
||||
class nullary_rng
|
||||
{
|
||||
public:
|
||||
nullary_rng() {}
|
||||
virtual ~nullary_rng() {}
|
||||
|
||||
template< typename T > T operator()( T max )
|
||||
{ return T(0); }
|
||||
} ;
|
||||
|
||||
/**
|
||||
* The hash_ctr_rng generates bits using a hash function in counter (CTR)
|
||||
* mode.
|
||||
*/
|
||||
template<class HashClass, int SeedLength>
|
||||
class hash_ctr_rng
|
||||
{
|
||||
public:
|
||||
hash_ctr_rng( const char* seed, uint64_t counter = 0 )
|
||||
: _counter( counter ), _current_offset( 0 )
|
||||
{
|
||||
memcpy( _seed, seed, SeedLength );
|
||||
_reset_current_value();
|
||||
return;
|
||||
}
|
||||
|
||||
virtual ~hash_ctr_rng() {}
|
||||
|
||||
uint64_t get_bits( uint8_t count )
|
||||
{
|
||||
uint64_t result = 0;
|
||||
uint64_t mask = 1;
|
||||
// grab the requested number of bits
|
||||
while( count > 0 )
|
||||
{
|
||||
result |=
|
||||
(
|
||||
(
|
||||
(
|
||||
_current_value.data()[ (_current_offset >> 3) & 0x1F ]
|
||||
& ( 1 << (_current_offset & 0x07) )
|
||||
)
|
||||
!= 0
|
||||
) ? mask : 0
|
||||
);
|
||||
mask += mask;
|
||||
--count;
|
||||
++_current_offset;
|
||||
if( _current_offset == (_current_value.data_size() << 3) )
|
||||
{
|
||||
_counter++;
|
||||
_current_offset = 0;
|
||||
_reset_current_value();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t operator()( uint64_t bound )
|
||||
{
|
||||
if( bound <= 1 )
|
||||
return 0;
|
||||
uint8_t bitcount = boost::multiprecision::detail::find_msb( bound ) + 1;
|
||||
|
||||
// probability of loop exiting is >= 1/2, so probability of
|
||||
// running N times is bounded above by (1/2)^N
|
||||
while( true )
|
||||
{
|
||||
uint64_t result = get_bits( bitcount );
|
||||
if( result < bound )
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// convenience method which does casting for types other than uint64_t
|
||||
template< typename T > T operator()( T bound )
|
||||
{ return (T) ( (*this)(uint64_t( bound )) ); }
|
||||
|
||||
void _reset_current_value()
|
||||
{
|
||||
// internal implementation detail, called to update
|
||||
// _current_value when _counter changes
|
||||
typename HashClass::encoder enc;
|
||||
enc.write( _seed , SeedLength );
|
||||
enc.write( (char *) &_counter, 8 );
|
||||
_current_value = enc.result();
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t _counter;
|
||||
char _seed[ SeedLength ];
|
||||
HashClass _current_value;
|
||||
uint16_t _current_offset;
|
||||
|
||||
static const int seed_length = SeedLength;
|
||||
};
|
||||
|
||||
} // end namespace fc
|
||||
|
|
@ -68,7 +68,7 @@ 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]) +
|
||||
|
|
@ -76,6 +76,25 @@ class sha256
|
|||
__builtin_popcountll(_hash[3]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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];
|
||||
};
|
||||
|
||||
|
|
@ -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 )
|
||||
{
|
||||
|
|
@ -324,13 +331,13 @@ namespace fc {
|
|||
struct if_enum<fc::true_type> {
|
||||
template<typename Stream, typename T>
|
||||
static inline void pack( Stream& s, const T& v ) {
|
||||
fc::raw::pack(s, (int64_t)v);
|
||||
fc::raw::pack(s, signed_int((int32_t)v));
|
||||
}
|
||||
template<typename Stream, typename T>
|
||||
static inline void unpack( Stream& s, T& v ) {
|
||||
int64_t temp;
|
||||
signed_int temp;
|
||||
fc::raw::unpack(s, temp);
|
||||
v = (T)temp;
|
||||
v = (T)temp.value;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -155,6 +155,15 @@ namespace fc
|
|||
#define FC_FORMAT_ARG_PARAMS( ... )\
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARGS, v, __VA_ARGS__ )
|
||||
|
||||
#define fc_ddump( LOGGER, SEQ ) \
|
||||
fc_dlog( LOGGER, FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define fc_idump( LOGGER, SEQ ) \
|
||||
fc_ilog( LOGGER, FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define fc_wdump( LOGGER, SEQ ) \
|
||||
fc_wlog( LOGGER, FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define fc_edump( LOGGER, SEQ ) \
|
||||
fc_elog( LOGGER, FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
|
||||
#define ddump( SEQ ) \
|
||||
dlog( FC_FORMAT(SEQ), FC_FORMAT_ARG_PARAMS(SEQ) )
|
||||
#define idump( SEQ ) \
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
#pragma once
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
#include <fc/crypto/rand.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
#include <fc/network/ip.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
namespace detail {
|
||||
class gntp_icon_impl;
|
||||
}
|
||||
class gntp_notifier;
|
||||
|
||||
class gntp_icon {
|
||||
public:
|
||||
gntp_icon(const char* buffer, size_t length);
|
||||
~gntp_icon();
|
||||
private:
|
||||
std::unique_ptr<detail::gntp_icon_impl> my;
|
||||
friend class gntp_notifier;
|
||||
};
|
||||
typedef std::shared_ptr<gntp_icon> gntp_icon_ptr;
|
||||
|
||||
class gntp_notification_type {
|
||||
public:
|
||||
std::string name;
|
||||
std::string display_name;
|
||||
bool enabled;
|
||||
gntp_icon_ptr icon;
|
||||
};
|
||||
typedef std::vector<gntp_notification_type> gntp_notification_type_list;
|
||||
|
||||
namespace detail {
|
||||
class gntp_notifier_impl;
|
||||
}
|
||||
|
||||
typedef uint160_t gntp_guid;
|
||||
|
||||
class gntp_notifier {
|
||||
public:
|
||||
gntp_notifier(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053,
|
||||
const optional<std::string>& password = optional<std::string>());
|
||||
~gntp_notifier();
|
||||
void set_application_name(std::string application_name);
|
||||
void set_application_icon(const gntp_icon_ptr& icon);
|
||||
void register_notifications();
|
||||
gntp_guid send_notification(std::string name, std::string title, std::string text, const gntp_icon_ptr& icon = gntp_icon_ptr(), optional<gntp_guid> coalescingId = optional<gntp_guid>());
|
||||
void add_notification_type(const gntp_notification_type& notificationType);
|
||||
private:
|
||||
std::unique_ptr<detail::gntp_notifier_impl> my;
|
||||
};
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
|
@ -40,6 +40,7 @@ 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;
|
||||
|
|
|
|||
|
|
@ -29,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;
|
||||
|
|
@ -76,7 +78,7 @@ namespace fc { namespace http {
|
|||
class websocket_client
|
||||
{
|
||||
public:
|
||||
websocket_client();
|
||||
websocket_client( const std::string& ca_filename = "_default" );
|
||||
~websocket_client();
|
||||
|
||||
websocket_connection_ptr connect( const std::string& uri );
|
||||
|
|
@ -88,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
|
||||
|
|
@ -21,6 +21,8 @@ namespace fc {
|
|||
class optional
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
optional():_valid(false){}
|
||||
~optional(){ reset(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ 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());
|
||||
o = fc::reflector<T>::from_int( v.as_int64() );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
namespace fc {
|
||||
class api_connection;
|
||||
|
||||
typedef uint32_t api_id_type;
|
||||
|
||||
namespace detail {
|
||||
template<typename Signature>
|
||||
class callback_functor
|
||||
|
|
@ -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) )
|
||||
|
||||
|
|
@ -23,7 +23,10 @@ namespace fc { namespace rpc {
|
|||
response(){}
|
||||
response( int64_t i, fc::variant r ):id(i),result(r){}
|
||||
response( int64_t i, error_object r ):id(i),error(r){}
|
||||
response( int64_t i, fc::variant r, string j ):id(i),jsonrpc(j),result(r){}
|
||||
response( int64_t i, error_object r, string j ):id(i),jsonrpc(j),error(r){}
|
||||
int64_t id = 0;
|
||||
optional<fc::string> jsonrpc;
|
||||
optional<fc::variant> result;
|
||||
optional<error_object> error;
|
||||
};
|
||||
|
|
@ -57,4 +60,4 @@ namespace fc { namespace rpc {
|
|||
|
||||
FC_REFLECT( fc::rpc::request, (id)(method)(params) );
|
||||
FC_REFLECT( fc::rpc::error_object, (code)(message)(data) )
|
||||
FC_REFLECT( fc::rpc::response, (id)(result)(error) )
|
||||
FC_REFLECT( fc::rpc::response, (id)(jsonrpc)(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.
|
||||
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);
|
||||
*/
|
||||
void decodeUtf8(const std::string& input, std::wstring* storage);
|
||||
|
||||
/** Encodes given wide (unicode) string into UTF-8 representation.
|
||||
/** 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);
|
||||
*/
|
||||
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, typename... A>
|
||||
void from_variant(const variant& var, flat_map<K, T, A...>& 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 );
|
||||
|
||||
|
|
|
|||
22
src/asio.cpp
22
src/asio.cpp
|
|
@ -92,14 +92,15 @@ 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( [=]()
|
||||
for( int i = 0; i < 8; ++i ) {
|
||||
asio_threads.push_back( new boost::thread( [=]()
|
||||
{
|
||||
fc::thread::current().set_name("asio");
|
||||
while (!io->stopped())
|
||||
|
|
@ -121,17 +122,22 @@ namespace fc {
|
|||
elog("Caught unhandled exception in asio service loop");
|
||||
}
|
||||
}
|
||||
});
|
||||
}) );
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
delete the_work;
|
||||
io->stop();
|
||||
for( auto asio_thread : asio_threads ) {
|
||||
asio_thread->join();
|
||||
}
|
||||
delete io;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
#include <fc/crypto/base32.hpp>
|
||||
#include <CyoDecode.h>
|
||||
#include <CyoEncode.h>
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base32( const std::string& b32 )
|
||||
{
|
||||
auto len = cyoBase32DecodeGetLength( b32.size() );
|
||||
std::vector<char> v(len);
|
||||
len = cyoBase32Decode( v.data(), b32.c_str(), b32.size() );
|
||||
v.resize( len );
|
||||
return v;
|
||||
}
|
||||
|
||||
std::string to_base32( const char* data, size_t len )
|
||||
{
|
||||
auto s = cyoBase32EncodeGetLength(len);
|
||||
std::vector<char> b32;
|
||||
b32.resize(s);
|
||||
cyoBase32Encode( b32.data(), data, len );
|
||||
b32.resize( b32.size()-1); // strip the nullterm
|
||||
return std::string(b32.begin(),b32.end());
|
||||
}
|
||||
|
||||
std::string to_base32( const std::vector<char>& vec )
|
||||
{
|
||||
return to_base32( vec.data(), vec.size() );
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ namespace fc { namespace ecc {
|
|||
return secp256k1_nonce_function_default( nonce32, msg32, key32, *extra, nullptr );
|
||||
}
|
||||
|
||||
compact_signature private_key::sign_compact( const fc::sha256& digest )const
|
||||
compact_signature private_key::sign_compact( const fc::sha256& digest, bool require_canonical )const
|
||||
{
|
||||
FC_ASSERT( my->_key != empty_priv );
|
||||
compact_signature result;
|
||||
|
|
@ -94,7 +94,7 @@ namespace fc { namespace ecc {
|
|||
do
|
||||
{
|
||||
FC_ASSERT( secp256k1_ecdsa_sign_compact( detail::_get_context(), (unsigned char*) digest.data(), (unsigned char*) result.begin() + 1, (unsigned char*) my->_key.data(), extended_nonce_function, &counter, &recid ));
|
||||
} while( !public_key::is_canonical( result ) );
|
||||
} while( require_canonical && !public_key::is_canonical( result ) );
|
||||
result.begin()[0] = 27 + 4 + recid;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <assert.h>
|
||||
#include <secp256k1.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _WIN32
|
||||
# include <malloc.h>
|
||||
#else
|
||||
# include <alloca.h>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -98,6 +99,101 @@ namespace fc {
|
|||
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)
|
||||
|
|
@ -177,10 +176,11 @@ namespace fc
|
|||
string exception::to_string( log_level ll )const
|
||||
{
|
||||
fc::stringstream ss;
|
||||
ss << what() << " (" << variant(my->_code).as_string() <<")\n";
|
||||
ss << what() << ":";
|
||||
for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ++itr )
|
||||
{
|
||||
ss << fc::format_string( itr->get_format(), itr->get_data() ) <<"\n";
|
||||
if( itr->get_format().size() )
|
||||
ss << " " << fc::format_string( itr->get_format(), itr->get_data() );
|
||||
// ss << " " << itr->get_context().to_string() <<"\n";
|
||||
}
|
||||
return ss.str();
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <fc/exception/exception.hpp>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
namespace fc {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ namespace fc {
|
|||
void logger::add_appender( const fc::shared_ptr<appender>& a )
|
||||
{ my->_appenders.push_back(a); }
|
||||
|
||||
// void logger::remove_appender( const fc::shared_ptr<appender>& a )
|
||||
// { my->_appenders.erase(a); }
|
||||
void logger::remove_appender( const fc::shared_ptr<appender>& a )
|
||||
{ my->_appenders.erase(std::remove(my->_appenders.begin(), my->_appenders.end(), a), my->_appenders.end()); }
|
||||
|
||||
std::vector<fc::shared_ptr<appender> > logger::get_appenders()const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,291 +0,0 @@
|
|||
#include <fc/network/gntp.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/asio.hpp>
|
||||
#include <fc/network/tcp_socket.hpp>
|
||||
#include <fc/crypto/sha1.hpp>
|
||||
#include <fc/crypto/base32.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/rand.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
static std::string calc_sha1_base32_of_buffer(const std::string& buffer)
|
||||
{
|
||||
sha1::encoder sha1_encoder;
|
||||
sha1_encoder.write(buffer.c_str(), buffer.size());
|
||||
sha1 sha1_result = sha1_encoder.result();
|
||||
string sha1_result_base32 = to_base32((char*)&sha1_result, sizeof(sha1_result));
|
||||
return sha1_result_base32.c_str();
|
||||
}
|
||||
|
||||
|
||||
class gntp_icon_impl
|
||||
{
|
||||
public:
|
||||
std::string _icon_bytes;
|
||||
std::string _sha1_hash;
|
||||
|
||||
gntp_icon_impl(const char* buffer, size_t length) :
|
||||
_icon_bytes(buffer, length),
|
||||
_sha1_hash(calc_sha1_base32_of_buffer(_icon_bytes))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class gntp_notifier_impl
|
||||
{
|
||||
public:
|
||||
gntp_notifier_impl(const std::string& host_to_notify = "127.0.0.1", uint16_t port = 23053, const optional<std::string>& password = optional<std::string>());
|
||||
|
||||
// there's no API to change these right now, it will always notify localhost at the default GNTP port
|
||||
std::string hostname;
|
||||
uint16_t port;
|
||||
optional<std::string> password;
|
||||
|
||||
std::string application_name;
|
||||
gntp_icon_ptr application_icon;
|
||||
|
||||
gntp_notification_type_list notification_types; // list of all notification types we're registered to send
|
||||
|
||||
optional<boost::asio::ip::tcp::endpoint> endpoint; // cache the last endpoint we've connected to
|
||||
|
||||
bool connection_failed; // true after we've tried to connect and failed
|
||||
bool is_registered; // true after we've registered
|
||||
|
||||
void send_gntp_message(const std::string& message);
|
||||
};
|
||||
|
||||
gntp_notifier_impl::gntp_notifier_impl(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */,
|
||||
const optional<std::string>& password /* = optional<std::string>() */) :
|
||||
hostname(host_to_notify),
|
||||
port(port),
|
||||
password(password),
|
||||
connection_failed(false),
|
||||
is_registered(false)
|
||||
{
|
||||
}
|
||||
|
||||
void gntp_notifier_impl::send_gntp_message(const std::string& message)
|
||||
{
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> sock(new boost::asio::ip::tcp::socket(asio::default_io_service()));
|
||||
|
||||
bool connected = false;
|
||||
if (endpoint)
|
||||
{
|
||||
// we've successfully connected before, connect to the same endpoint that worked last time
|
||||
try
|
||||
{
|
||||
asio::tcp::connect(*sock, *endpoint);
|
||||
connected = true;
|
||||
}
|
||||
catch (exception& er)
|
||||
{
|
||||
ilog("Failed to connect to GNTP service using an endpoint that previously worked: ${error_report}",
|
||||
("error_report", er.to_detail_string()));
|
||||
sock->close();
|
||||
// clear the cached endpoint and fall through to the full connection procedure
|
||||
endpoint = optional<boost::asio::ip::tcp::endpoint>();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ilog("Failed to connect to GNTP service using an endpoint that previously worked");
|
||||
sock->close();
|
||||
// clear the cached endpoint and fall through to the full connection procedure
|
||||
endpoint = optional<boost::asio::ip::tcp::endpoint>();
|
||||
}
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
// do the full connection procedure
|
||||
auto eps = asio::tcp::resolve(hostname, boost::lexical_cast<std::string>(port));
|
||||
if (eps.size() == 0)
|
||||
FC_THROW("Unable to resolve host '${host}'", ("host", hostname));
|
||||
|
||||
for (uint32_t i = 0; i < eps.size(); ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
ilog("Attempting to connect to GNTP srvice");
|
||||
asio::tcp::connect(*sock, eps[i]);
|
||||
endpoint = eps[i];
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
catch (const exception& er)
|
||||
{
|
||||
ilog("Failed to connect to GNTP service: ${error_reprot}",
|
||||
("error_report", er.to_detail_string()) );
|
||||
sock->close();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
ilog("Failed to connect to GNTP service");
|
||||
sock->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!connected)
|
||||
FC_THROW("Unable to connect to any resolved endpoint for ${host}:${port}",
|
||||
("host", hostname)("port", port));
|
||||
try
|
||||
{
|
||||
asio::ostream<boost::asio::ip::tcp::socket> write_stream(sock);
|
||||
write_stream.write(message.c_str(), message.size());
|
||||
write_stream.flush();
|
||||
write_stream.close();
|
||||
}
|
||||
catch (exception& er)
|
||||
{
|
||||
FC_RETHROW_EXCEPTION(er, warn, "Caught an exception while sending data to GNTP service");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
FC_THROW("Caught an exception while sending data to GNTP service");
|
||||
}
|
||||
}
|
||||
} // end namespace detail
|
||||
|
||||
gntp_icon::gntp_icon(const char* buffer, size_t length) :
|
||||
my(new detail::gntp_icon_impl(buffer, length))
|
||||
{
|
||||
}
|
||||
gntp_icon::~gntp_icon()
|
||||
{
|
||||
}
|
||||
|
||||
gntp_notifier::gntp_notifier(const std::string& host_to_notify /* = "127.0.0.1" */, uint16_t port /* = 23053 */,
|
||||
const optional<std::string>& password /* = optional<std::string>() */) :
|
||||
my(new detail::gntp_notifier_impl(host_to_notify, port, password))
|
||||
{
|
||||
}
|
||||
|
||||
gntp_notifier::~gntp_notifier()
|
||||
{
|
||||
}
|
||||
|
||||
void gntp_notifier::set_application_name(std::string appName)
|
||||
{
|
||||
my->application_name = appName;
|
||||
}
|
||||
void gntp_notifier::set_application_icon(const gntp_icon_ptr& icon)
|
||||
{
|
||||
my->application_icon = icon;
|
||||
}
|
||||
void gntp_notifier::add_notification_type(const gntp_notification_type& notification_type)
|
||||
{
|
||||
my->notification_types.push_back(notification_type);
|
||||
}
|
||||
|
||||
void gntp_notifier::register_notifications()
|
||||
{
|
||||
// this call will reset any errors
|
||||
my->connection_failed = false;
|
||||
my->is_registered = false;
|
||||
|
||||
std::ostringstream message;
|
||||
std::set<gntp_icon_ptr> icons_used;
|
||||
|
||||
message << "GNTP/1.0 REGISTER NONE\r\n";
|
||||
message << "Application-Name: " << my->application_name << "\r\n";
|
||||
if (my->application_icon)
|
||||
{
|
||||
message << "Application-Icon: x-growl-resource://" << my->application_icon->my->_sha1_hash << "\r\n";
|
||||
icons_used.insert(my->application_icon);
|
||||
}
|
||||
|
||||
message << "Notifications-Count: " << my->notification_types.size() << "\r\n";
|
||||
for (const gntp_notification_type& notification_type : my->notification_types)
|
||||
{
|
||||
message << "\r\n";
|
||||
message << "Notification-Name: " << notification_type.name << "\r\n";
|
||||
if (!notification_type.display_name.empty())
|
||||
message << "Notification-Display-Name: " << notification_type.display_name << "\r\n";
|
||||
if (notification_type.icon)
|
||||
{
|
||||
message << "Notification-Icon: x-growl-resource://" << notification_type.icon->my->_sha1_hash << "\r\n";
|
||||
icons_used.insert(notification_type.icon);
|
||||
}
|
||||
message << "Notification-Enabled: " << (notification_type.enabled ? "True" : "False") << "\r\n";
|
||||
}
|
||||
if (!icons_used.empty())
|
||||
{
|
||||
message << "\r\n";
|
||||
for (const gntp_icon_ptr& icon : icons_used)
|
||||
{
|
||||
message << "Identifier: " << icon->my->_sha1_hash << "\r\n";
|
||||
message << "Length: " << icon->my->_icon_bytes.size() << "\r\n";
|
||||
message << "\r\n";
|
||||
message << icon->my->_icon_bytes;
|
||||
message << "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
message << "\r\n\r\n";
|
||||
try
|
||||
{
|
||||
my->send_gntp_message(message.str());
|
||||
my->is_registered = true;
|
||||
}
|
||||
catch (const exception&)
|
||||
{
|
||||
my->connection_failed = true;
|
||||
}
|
||||
}
|
||||
gntp_guid gntp_notifier::send_notification(std::string name, std::string title, std::string text,
|
||||
const gntp_icon_ptr& icon, optional<gntp_guid> coalescingId /* = optional<gntp_guid>() */)
|
||||
{
|
||||
if (my->connection_failed)
|
||||
return gntp_guid();
|
||||
if (!my->is_registered)
|
||||
return gntp_guid();
|
||||
|
||||
gntp_guid notification_id;
|
||||
rand_pseudo_bytes(notification_id.data(), 20);
|
||||
|
||||
std::ostringstream message;
|
||||
message << "GNTP/1.0 NOTIFY NONE";
|
||||
if (my->password)
|
||||
{
|
||||
char salt[16];
|
||||
rand_pseudo_bytes(salt, sizeof(salt));
|
||||
std::string salted_password = *my->password + std::string(salt, 16);
|
||||
sha256 key = sha256::hash(salted_password);
|
||||
sha256 keyhash = sha256::hash(key.data(), 32);
|
||||
message << " SHA256:" << boost::to_upper_copy(to_hex(keyhash.data(), 32)) << "." << boost::to_upper_copy(to_hex(salt, sizeof(salt)));
|
||||
}
|
||||
message << "\r\n";
|
||||
message << "Application-Name: " << my->application_name << "\r\n";
|
||||
message << "Notification-Name: " << name << "\r\n";
|
||||
message << "Notification-ID: " << notification_id.str() << "\r\n";
|
||||
message << "Notification-Coalescing-ID: " << (coalescingId ? coalescingId->str() : notification_id.str()) << "\r\n";
|
||||
message << "Notification-Title: " << title << "\r\n";
|
||||
message << "Notification-Text: " << text << "\r\n";
|
||||
if (icon)
|
||||
message << "Notification-Icon: x-growl-resource://" << icon->my->_sha1_hash << "\r\n";
|
||||
|
||||
if (icon)
|
||||
{
|
||||
message << "\r\n";
|
||||
message << "Identifier: " << icon->my->_sha1_hash << "\r\n";
|
||||
message << "Length: " << icon->my->_icon_bytes.size() << "\r\n";
|
||||
message << "\r\n";
|
||||
message << icon->my->_icon_bytes;
|
||||
message << "\r\n";
|
||||
}
|
||||
message << "\r\n\r\n";
|
||||
my->send_gntp_message(message.str());
|
||||
return notification_id;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
|
@ -168,6 +168,11 @@ 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;
|
||||
};
|
||||
|
||||
|
|
@ -193,7 +198,7 @@ namespace fc { namespace http {
|
|||
_server_thread.async( [&](){
|
||||
auto current_con = _connections.find(hdl);
|
||||
assert( current_con != _connections.end() );
|
||||
idump(("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;
|
||||
|
|
@ -204,6 +209,11 @@ 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<websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
|
|
@ -336,7 +346,7 @@ namespace fc { namespace http {
|
|||
_on_connection( current_con );
|
||||
|
||||
auto con = _server.get_con_from_hdl(hdl);
|
||||
idump(("server")(con->get_request_body()));
|
||||
wdump(("server")(con->get_request_body()));
|
||||
auto response = current_con->on_http( con->get_request_body() );
|
||||
|
||||
con->set_body( response );
|
||||
|
|
@ -457,6 +467,7 @@ namespace fc { namespace http {
|
|||
fc::thread& _client_thread;
|
||||
websocket_client_type _client;
|
||||
websocket_connection_ptr _connection;
|
||||
std::string _uri;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -466,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( [&](){
|
||||
|
|
@ -505,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 {
|
||||
|
|
@ -512,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;
|
||||
|
|
@ -531,12 +564,32 @@ 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_connection_ptr _connection;
|
||||
std::string _uri;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -588,12 +641,12 @@ namespace fc { namespace http {
|
|||
}
|
||||
|
||||
|
||||
websocket_tls_client::websocket_tls_client():my( 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():my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl()) {}
|
||||
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 )
|
||||
|
|
@ -605,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 ){
|
||||
|
|
@ -631,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 {
|
||||
|
|
@ -159,7 +159,7 @@ namespace fc {
|
|||
}
|
||||
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() );
|
||||
} );
|
||||
|
|
@ -83,12 +94,16 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht
|
|||
if( var_obj.contains( "method" ) )
|
||||
{
|
||||
auto call = var.as<fc::rpc::request>();
|
||||
try
|
||||
{
|
||||
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 )
|
||||
{
|
||||
resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(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() );
|
||||
} );
|
||||
|
|
@ -78,21 +87,40 @@ std::string websocket_api_connection::on_message(
|
|||
{
|
||||
auto var = fc::json::from_string(message);
|
||||
const auto& var_obj = var.get_object();
|
||||
|
||||
if( var_obj.contains( "method" ) )
|
||||
{
|
||||
auto call = var.as<fc::rpc::request>();
|
||||
exception_ptr optexcept;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
#ifdef LOG_LONG_API
|
||||
auto start = time_point::now();
|
||||
#endif
|
||||
|
||||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
|
||||
#ifdef LOG_LONG_API
|
||||
auto end = time_point::now();
|
||||
|
||||
if( end - start > fc::milliseconds( LOG_LONG_API_MAX_MS ) )
|
||||
elog( "API call execution time limit exceeded. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) );
|
||||
else if( end - start > fc::milliseconds( LOG_LONG_API_WARN_MS ) )
|
||||
wlog( "API call execution time nearing limit. method: ${m} params: ${p} time: ${t}", ("m",call.method)("p",call.params)("t", end - start) );
|
||||
#endif
|
||||
|
||||
if( call.id )
|
||||
{
|
||||
auto reply = fc::json::to_string( response( *call.id, result ) );
|
||||
auto reply = fc::json::to_string( response( *call.id, result, "2.0" ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) )
|
||||
}
|
||||
catch ( const fc::exception& e )
|
||||
{
|
||||
if( call.id )
|
||||
|
|
@ -102,7 +130,7 @@ std::string websocket_api_connection::on_message(
|
|||
}
|
||||
if( optexcept ) {
|
||||
|
||||
auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_detail_string(), fc::variant(*optexcept)} ) );
|
||||
auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept)}, "2.0" ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
|
|
|
|||
58
tests/CMakeLists.txt
Normal file
58
tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
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( 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/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;
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/base32.hpp>
|
||||
#include <fc/crypto/base36.hpp>
|
||||
#include <fc/crypto/base58.hpp>
|
||||
#include <fc/crypto/base64.hpp>
|
||||
|
|
@ -44,29 +43,6 @@ BOOST_AUTO_TEST_CASE(hex_test)
|
|||
}
|
||||
|
||||
|
||||
static void test_32( const std::string& test, const std::string& expected )
|
||||
{
|
||||
std::vector<char> vec( test.begin(), test.end() );
|
||||
fc::string enc1 = fc::to_base32( vec );
|
||||
fc::string enc2 = fc::to_base32( test.c_str(), test.size() );
|
||||
BOOST_CHECK_EQUAL( enc1, enc2 );
|
||||
BOOST_CHECK_EQUAL( expected, enc2 );
|
||||
|
||||
std::vector<char> dec = fc::from_base32( enc1 );
|
||||
BOOST_CHECK_EQUAL( vec.size(), dec.size() );
|
||||
BOOST_CHECK( !memcmp( vec.data(), dec.data(), vec.size() ) );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(base32_test)
|
||||
{
|
||||
test_32( TEST1, "" );
|
||||
test_32( TEST2, "AAATAMI=" );
|
||||
test_32( TEST3, "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======" );
|
||||
test_32( TEST4, "777AB7IB7Q======" );
|
||||
test_32( TEST5, "AAAAA===" );
|
||||
}
|
||||
|
||||
|
||||
static void test_36( const std::string& test, const std::string& expected )
|
||||
{
|
||||
std::vector<char> vec( test.begin(), test.end() );
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <fc/network/ntp.hpp>
|
||||
#include <fc/log/logger.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(fc_network)
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ntp_test )
|
||||
{
|
||||
fc::ntp ntp_service;
|
||||
ntp_service.set_request_interval(5);
|
||||
fc::usleep(fc::seconds(4) );
|
||||
auto time = ntp_service.get_time();
|
||||
BOOST_CHECK( time );
|
||||
auto ntp_time = *time;
|
||||
auto delta = ntp_time - fc::time_point::now();
|
||||
// auto minutes = delta.count() / 1000000 / 60;
|
||||
// auto hours = delta.count() / 1000000 / 60 / 60;
|
||||
// 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;
|
||||
}
|
||||
27
vendor/cyoencode-1.0.2/LICENSE.TXT
vendored
27
vendor/cyoencode-1.0.2/LICENSE.TXT
vendored
|
|
@ -1,27 +0,0 @@
|
|||
All the files in this library are covered under the terms of the Berkeley
|
||||
Software Distribution (BSD) License:
|
||||
|
||||
Copyright (c) 2009-2012, Graham Bull.
|
||||
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.
|
||||
|
||||
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 HOLDER 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.
|
||||
|
||||
50
vendor/cyoencode-1.0.2/README.TXT
vendored
50
vendor/cyoencode-1.0.2/README.TXT
vendored
|
|
@ -1,50 +0,0 @@
|
|||
===============================================================================
|
||||
CyoEncode
|
||||
http://cyoencode.sourceforge.net/
|
||||
|
||||
Copyright (c) 2009-2012, Graham Bull. All rights reserved.
|
||||
===============================================================================
|
||||
|
||||
Version 1.0.2
|
||||
Release Date 5th January 2012
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
1. License
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
CyoEncode is made available under the terms of the Berkeley Software
|
||||
Distribution (BSD) licence, as detailed in LICENSE.TXT. This allows you
|
||||
complete freedom to use and distribute the code in source and/or binary form,
|
||||
as long as you respect the original copyright.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
2. Instructions
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Simply copy the required source files (CyoEncode.h/cpp and CyoDecode.h/cpp)
|
||||
into your C/C++ project.
|
||||
|
||||
Examples of usage can be found in the test.c file.
|
||||
|
||||
For Unix/Linux developers, there's a shell script that will build the test
|
||||
using GCC.
|
||||
|
||||
For Windows developers, Visual Studio projects are included.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
3. Release Notes
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
1.0.2 - 5th January 2012
|
||||
- A little refactoring, added some shared functions.
|
||||
- Added VS42010 project file.
|
||||
- Added x64 build configurations.
|
||||
|
||||
1.0.1 - 25th September 2009
|
||||
- Added the cyoBase??Validate() functions.
|
||||
- Added detection of invalid encodings in the cyoBase??Decode() functions,
|
||||
rather than relying on assertions.
|
||||
|
||||
1.0.0 - 19th August 2009
|
||||
- First release.
|
||||
|
||||
398
vendor/cyoencode-1.0.2/src/CyoDecode.c
vendored
398
vendor/cyoencode-1.0.2/src/CyoDecode.c
vendored
|
|
@ -1,398 +0,0 @@
|
|||
/*
|
||||
* CyoDecode.c - part of the CyoEncode library
|
||||
*
|
||||
* Copyright (c) 2009-2012, Graham Bull.
|
||||
* 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.
|
||||
*
|
||||
* 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 HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "CyoDecode.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdio.h> //TEMP
|
||||
|
||||
/********************************** Shared ***********************************/
|
||||
|
||||
static int cyoBaseXXValidate( const char* src, size_t size, size_t inputBytes, size_t maxPadding,
|
||||
unsigned char maxValue, const unsigned char table[] )
|
||||
{
|
||||
/*
|
||||
* returns 0 if the source is a valid baseXX encoding
|
||||
*/
|
||||
|
||||
if (!src)
|
||||
return -1; /*ERROR - NULL pointer*/
|
||||
|
||||
if (size % inputBytes != 0)
|
||||
return -1; /*ERROR - extra characters*/
|
||||
|
||||
/* check the bytes */
|
||||
for (; size >= 1; --size, ++src)
|
||||
{
|
||||
unsigned char ch = *src;
|
||||
if ((ch >= 0x80) || (table[ ch ] > maxValue))
|
||||
break;
|
||||
}
|
||||
|
||||
/* check any padding */
|
||||
for (; 1 <= size && size <= maxPadding; --size, ++src)
|
||||
{
|
||||
unsigned char ch = *src;
|
||||
if ((ch >= 0x80) || (table[ ch ] != maxValue + 1))
|
||||
break;
|
||||
}
|
||||
|
||||
/* if size isn't zero then the encoded string isn't valid */
|
||||
if (size != 0)
|
||||
return -2; /*ERROR - invalid baseXX character*/
|
||||
|
||||
/* OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t cyoBaseXXDecodeGetLength( size_t size, size_t inputBytes, size_t outputBytes )
|
||||
{
|
||||
if (size % inputBytes != 0)
|
||||
return 0; /*ERROR - extra characters*/
|
||||
|
||||
/* OK */
|
||||
return (((size + inputBytes - 1) / inputBytes) * outputBytes) + 1; /*plus terminator*/
|
||||
}
|
||||
|
||||
/****************************** Base16 Decoding ******************************/
|
||||
|
||||
static const size_t BASE16_INPUT = 2;
|
||||
static const size_t BASE16_OUTPUT = 1;
|
||||
static const size_t BASE16_MAX_PADDING = 0;
|
||||
static const unsigned char BASE16_MAX_VALUE = 15;
|
||||
static const unsigned char BASE16_TABLE[ 0x80 ] = {
|
||||
/*00-07*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*08-0f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*10-17*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*18-1f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*20-27*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*28-2f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*30-37*/ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /*8 = '0'-'7'*/
|
||||
/*38-3f*/ 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*2 = '8'-'9'*/
|
||||
/*40-47*/ 0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, /*6 = 'A'-'F'*/
|
||||
/*48-4f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*50-57*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*58-5f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*60-67*/ 0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xFF, /*6 = 'a'-'f' (same as 'A'-'F')*/
|
||||
/*68-6f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*70-77*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*78-7f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
int cyoBase16Validate( const char* src, size_t size )
|
||||
{
|
||||
return cyoBaseXXValidate( src, size, BASE16_INPUT, BASE16_MAX_PADDING, BASE16_MAX_VALUE, BASE16_TABLE );
|
||||
}
|
||||
|
||||
size_t cyoBase16DecodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXDecodeGetLength( size, BASE16_INPUT, BASE16_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase16Decode( void* dest, const char* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 1 byte for every 2 input:
|
||||
*
|
||||
* outputs: 1
|
||||
* inputs: 1 = ----1111 = 1111----
|
||||
* 2 = ----2222 = ----2222
|
||||
*/
|
||||
|
||||
if (dest && src && (size % BASE16_INPUT == 0))
|
||||
{
|
||||
unsigned char* pDest = (unsigned char*)dest;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
unsigned char in1, in2;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* 2 inputs */
|
||||
in1 = *src++;
|
||||
in2 = *src++;
|
||||
dwSrcSize -= BASE16_INPUT;
|
||||
|
||||
/* Validate ascii */
|
||||
if (in1 >= 0x80 || in2 >= 0x80)
|
||||
return 0; /*ERROR - invalid base16 character*/
|
||||
|
||||
/* Convert ascii to base16 */
|
||||
in1 = BASE16_TABLE[ in1 ];
|
||||
in2 = BASE16_TABLE[ in2 ];
|
||||
|
||||
/* Validate base16 */
|
||||
if (in1 > BASE16_MAX_VALUE || in2 > BASE16_MAX_VALUE)
|
||||
return 0; /*ERROR - invalid base16 character*/
|
||||
|
||||
/* 1 output */
|
||||
*pDest++ = ((in1 << 4) | in2);
|
||||
dwDestSize += BASE16_OUTPUT;
|
||||
}
|
||||
*pDest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer, or size isn't a multiple of 2*/
|
||||
}
|
||||
|
||||
/****************************** Base32 Decoding ******************************/
|
||||
|
||||
static const size_t BASE32_INPUT = 8;
|
||||
static const size_t BASE32_OUTPUT = 5;
|
||||
static const size_t BASE32_MAX_PADDING = 6;
|
||||
static const unsigned char BASE32_MAX_VALUE = 31;
|
||||
static const unsigned char BASE32_TABLE[ 0x80 ] = {
|
||||
/*00-07*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*08-0f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*10-17*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*18-1f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*20-27*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*28-2f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*30-37*/ 0xFF, 0xFF, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /*6 = '2'-'7'*/
|
||||
/*38-3f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0xFF, 0xFF, /*1 = '='*/
|
||||
/*40-47*/ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*7 = 'A'-'G'*/
|
||||
/*48-4f*/ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /*8 = 'H'-'O'*/
|
||||
/*50-57*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /*8 = 'P'-'W'*/
|
||||
/*58-5f*/ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*3 = 'X'-'Z'*/
|
||||
/*60-67*/ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*7 = 'a'-'g' (same as 'A'-'G')*/
|
||||
/*68-6f*/ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /*8 = 'h'-'o' (same as 'H'-'O')*/
|
||||
/*70-77*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /*8 = 'p'-'w' (same as 'P'-'W')*/
|
||||
/*78-7f*/ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /*3 = 'x'-'z' (same as 'X'-'Z')*/
|
||||
};
|
||||
|
||||
int cyoBase32Validate( const char* src, size_t size )
|
||||
{
|
||||
return cyoBaseXXValidate( src, size, BASE32_INPUT, BASE32_MAX_PADDING, BASE32_MAX_VALUE, BASE32_TABLE );
|
||||
}
|
||||
|
||||
size_t cyoBase32DecodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXDecodeGetLength( size, BASE32_INPUT, BASE32_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase32Decode( void* dest, const char* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 5 bytes for every 8 input:
|
||||
*
|
||||
* outputs: 1 2 3 4 5
|
||||
* inputs: 1 = ---11111 = 11111---
|
||||
* 2 = ---222XX = -----222 XX------
|
||||
* 3 = ---33333 = --33333-
|
||||
* 4 = ---4XXXX = -------4 XXXX----
|
||||
* 5 = ---5555X = ----5555 X-------
|
||||
* 6 = ---66666 = -66666--
|
||||
* 7 = ---77XXX = ------77 XXX-----
|
||||
* 8 = ---88888 = ---88888
|
||||
*/
|
||||
|
||||
if (dest && src && (size % BASE32_INPUT == 0))
|
||||
{
|
||||
unsigned char* pDest = (unsigned char*)dest;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
unsigned char in1, in2, in3, in4, in5, in6, in7, in8;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* 8 inputs */
|
||||
in1 = *src++;
|
||||
in2 = *src++;
|
||||
in3 = *src++;
|
||||
in4 = *src++;
|
||||
in5 = *src++;
|
||||
in6 = *src++;
|
||||
in7 = *src++;
|
||||
in8 = *src++;
|
||||
dwSrcSize -= BASE32_INPUT;
|
||||
|
||||
/* Validate ascii */
|
||||
if ( in1 >= 0x80 || in2 >= 0x80 || in3 >= 0x80 || in4 >= 0x80
|
||||
|| in5 >= 0x80 || in6 >= 0x80 || in7 >= 0x80 || in8 >= 0x80)
|
||||
return 0; /*ERROR - invalid base32 character*/
|
||||
|
||||
/* Convert ascii to base16 */
|
||||
in1 = BASE32_TABLE[ in1 ];
|
||||
in2 = BASE32_TABLE[ in2 ];
|
||||
in3 = BASE32_TABLE[ in3 ];
|
||||
in4 = BASE32_TABLE[ in4 ];
|
||||
in5 = BASE32_TABLE[ in5 ];
|
||||
in6 = BASE32_TABLE[ in6 ];
|
||||
in7 = BASE32_TABLE[ in7 ];
|
||||
in8 = BASE32_TABLE[ in8 ];
|
||||
|
||||
/* Validate base32 */
|
||||
if (in1 > BASE32_MAX_VALUE || in2 > BASE32_MAX_VALUE)
|
||||
return 0; /*ERROR - invalid base32 character*/
|
||||
/*the following can be padding*/
|
||||
if ( in3 > BASE32_MAX_VALUE + 1 || in4 > BASE32_MAX_VALUE + 1 || in5 > BASE32_MAX_VALUE + 1
|
||||
|| in6 > BASE32_MAX_VALUE + 1 || in7 > BASE32_MAX_VALUE + 1 || in8 > BASE32_MAX_VALUE + 1)
|
||||
return 0; /*ERROR - invalid base32 character*/
|
||||
|
||||
/* 5 outputs */
|
||||
*pDest++ = ((in1 & 0x1f) << 3) | ((in2 & 0x1c) >> 2);
|
||||
*pDest++ = ((in2 & 0x03) << 6) | ((in3 & 0x1f) << 1) | ((in4 & 0x10) >> 4);
|
||||
*pDest++ = ((in4 & 0x0f) << 4) | ((in5 & 0x1e) >> 1);
|
||||
*pDest++ = ((in5 & 0x01) << 7) | ((in6 & 0x1f) << 2) | ((in7 & 0x18) >> 3);
|
||||
*pDest++ = ((in7 & 0x07) << 5) | (in8 & 0x1f);
|
||||
dwDestSize += BASE32_OUTPUT;
|
||||
|
||||
/* Padding */
|
||||
if (in8 == BASE32_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
assert( (in7 == BASE32_MAX_VALUE + 1 && in6 == BASE32_MAX_VALUE + 1) || (in7 != BASE32_MAX_VALUE + 1) );
|
||||
if (in6 == BASE32_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
if (in5 == BASE32_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
assert( (in4 == BASE32_MAX_VALUE + 1 && in3 == BASE32_MAX_VALUE + 1) || (in4 != BASE32_MAX_VALUE + 1) );
|
||||
if (in3 == BASE32_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*pDest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer, or size isn't a multiple of 8*/
|
||||
}
|
||||
|
||||
/****************************** Base64 Decoding ******************************/
|
||||
|
||||
static const size_t BASE64_INPUT = 4;
|
||||
static const size_t BASE64_OUTPUT = 3;
|
||||
static const size_t BASE64_MAX_PADDING = 2;
|
||||
static const unsigned char BASE64_MAX_VALUE = 63;
|
||||
static const unsigned char BASE64_TABLE[ 0x80 ] = {
|
||||
/*00-07*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*08-0f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*10-17*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*18-1f*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*20-27*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
/*28-2f*/ 0xFF, 0xFF, 0xFF, 0x3e, 0xFF, 0xFF, 0xFF, 0x3f, /*2 = '+' and '/'*/
|
||||
/*30-37*/ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /*8 = '0'-'7'*/
|
||||
/*38-3f*/ 0x3c, 0x3d, 0xFF, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, /*2 = '8'-'9' and '='*/
|
||||
/*40-47*/ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /*7 = 'A'-'G'*/
|
||||
/*48-4f*/ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /*8 = 'H'-'O'*/
|
||||
/*50-57*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /*8 = 'P'-'W'*/
|
||||
/*58-5f*/ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*3 = 'X'-'Z'*/
|
||||
/*60-67*/ 0xFF, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /*7 = 'a'-'g'*/
|
||||
/*68-6f*/ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /*8 = 'h'-'o'*/
|
||||
/*70-77*/ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /*8 = 'p'-'w'*/
|
||||
/*78-7f*/ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /*3 = 'x'-'z'*/
|
||||
};
|
||||
|
||||
int cyoBase64Validate( const char* src, size_t size )
|
||||
{
|
||||
return cyoBaseXXValidate( src, size, BASE64_INPUT, BASE64_MAX_PADDING, BASE64_MAX_VALUE, BASE64_TABLE );
|
||||
}
|
||||
|
||||
size_t cyoBase64DecodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXDecodeGetLength( size, BASE64_INPUT, BASE64_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase64Decode( void* dest, const char* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 3 bytes for every 4 input:
|
||||
*
|
||||
* outputs: 1 2 3
|
||||
* inputs: 1 = --111111 = 111111--
|
||||
* 2 = --22XXXX = ------22 XXXX----
|
||||
* 3 = --3333XX = ----3333 XX------
|
||||
* 4 = --444444 = --444444
|
||||
*/
|
||||
|
||||
if (dest && src && (size % BASE64_INPUT == 0))
|
||||
{
|
||||
unsigned char* pDest = (unsigned char*)dest;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
unsigned char in1, in2, in3, in4;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* 4 inputs */
|
||||
in1 = *src++;
|
||||
in2 = *src++;
|
||||
in3 = *src++;
|
||||
in4 = *src++;
|
||||
dwSrcSize -= BASE64_INPUT;
|
||||
|
||||
/* Validate ascii */
|
||||
if (in1 >= 0x80 || in2 >= 0x80 || in3 >= 0x80 || in4 >= 0x80)
|
||||
return 0; /*ERROR - invalid base64 character*/
|
||||
|
||||
/* Convert ascii to base64 */
|
||||
in1 = BASE64_TABLE[ in1 ];
|
||||
in2 = BASE64_TABLE[ in2 ];
|
||||
in3 = BASE64_TABLE[ in3 ];
|
||||
in4 = BASE64_TABLE[ in4 ];
|
||||
|
||||
/* Validate base64 */
|
||||
if (in1 > BASE64_MAX_VALUE || in2 > BASE64_MAX_VALUE)
|
||||
return 0; /*ERROR - invalid base64 character*/
|
||||
/*the following can be padding*/
|
||||
if (in3 > BASE64_MAX_VALUE + 1 || in4 > BASE64_MAX_VALUE + 1)
|
||||
return 0; /*ERROR - invalid base64 character*/
|
||||
|
||||
/* 3 outputs */
|
||||
*pDest++ = ((in1 & 0x3f) << 2) | ((in2 & 0x30) >> 4);
|
||||
*pDest++ = ((in2 & 0x0f) << 4) | ((in3 & 0x3c) >> 2);
|
||||
*pDest++ = ((in3 & 0x03) << 6) | (in4 & 0x3f);
|
||||
dwDestSize += BASE64_OUTPUT;
|
||||
|
||||
/* Padding */
|
||||
if (in4 == BASE64_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
if (in3 == BASE64_MAX_VALUE + 1)
|
||||
{
|
||||
--dwDestSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pDest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer, or size isn't a multiple of 4*/
|
||||
}
|
||||
58
vendor/cyoencode-1.0.2/src/CyoDecode.h
vendored
58
vendor/cyoencode-1.0.2/src/CyoDecode.h
vendored
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* CyoDecode.h - part of the CyoEncode library
|
||||
*
|
||||
* Copyright (c) 2009-2012, Graham Bull.
|
||||
* 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.
|
||||
*
|
||||
* 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 HOLDER 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.
|
||||
*/
|
||||
|
||||
#ifndef __CYODECODE_H
|
||||
#define __CYODECODE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Base16 Decoding */
|
||||
int cyoBase16Validate( const char* src, size_t size );
|
||||
size_t cyoBase16DecodeGetLength( size_t size );
|
||||
size_t cyoBase16Decode( void* dest, const char* src, size_t size );
|
||||
|
||||
/* Base32 Decoding */
|
||||
int cyoBase32Validate( const char* src, size_t size );
|
||||
size_t cyoBase32DecodeGetLength( size_t size );
|
||||
size_t cyoBase32Decode( void* dest, const char* src, size_t size );
|
||||
|
||||
/* Base64 Decoding */
|
||||
int cyoBase64Validate( const char* src, size_t size );
|
||||
size_t cyoBase64DecodeGetLength( size_t size );
|
||||
size_t cyoBase64Decode( void* dest, const char* src, size_t size );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__CYODECODE_H*/
|
||||
|
||||
283
vendor/cyoencode-1.0.2/src/CyoEncode.c
vendored
283
vendor/cyoencode-1.0.2/src/CyoEncode.c
vendored
|
|
@ -1,283 +0,0 @@
|
|||
/*
|
||||
* CyoEncode.c - part of the CyoEncode library
|
||||
*
|
||||
* Copyright (c) 2009-2012, Graham Bull.
|
||||
* 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.
|
||||
*
|
||||
* 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 HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "CyoEncode.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/********************************** Shared ***********************************/
|
||||
|
||||
static size_t cyoBaseXXEncodeGetLength( size_t size, size_t inputBytes, size_t outputBytes )
|
||||
{
|
||||
return (((size + inputBytes - 1) / inputBytes) * outputBytes) + 1; /*plus terminator*/
|
||||
}
|
||||
|
||||
/****************************** Base16 Encoding ******************************/
|
||||
|
||||
static const size_t BASE16_INPUT = 1;
|
||||
static const size_t BASE16_OUTPUT = 2;
|
||||
static const char* const BASE16_TABLE = "0123456789ABCDEF";
|
||||
|
||||
size_t cyoBase16EncodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXEncodeGetLength( size, BASE16_INPUT, BASE16_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase16Encode( char* dest, const void* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 2 bytes for every 1 input:
|
||||
*
|
||||
* inputs: 1
|
||||
* outputs: 1 = ----1111 = 1111----
|
||||
* 2 = ----2222 = ----2222
|
||||
*/
|
||||
|
||||
if (dest && src)
|
||||
{
|
||||
unsigned char* pSrc = (unsigned char*)src;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
unsigned char ch;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* 1 input */
|
||||
ch = *pSrc++;
|
||||
dwSrcSize -= BASE16_INPUT;
|
||||
|
||||
/* 2 outputs */
|
||||
*dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ];
|
||||
*dest++ = BASE16_TABLE[ (ch & 0x0f) ];
|
||||
dwDestSize += BASE16_OUTPUT;
|
||||
}
|
||||
*dest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer*/
|
||||
}
|
||||
|
||||
/****************************** Base32 Encoding ******************************/
|
||||
|
||||
static const size_t BASE32_INPUT = 5;
|
||||
static const size_t BASE32_OUTPUT = 8;
|
||||
static const char* const BASE32_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
|
||||
|
||||
size_t cyoBase32EncodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXEncodeGetLength( size, BASE32_INPUT, BASE32_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase32Encode( char* dest, const void* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 8 bytes for every 5 input:
|
||||
*
|
||||
* inputs: 1 2 3 4 5
|
||||
* outputs: 1 = ---11111 = 11111---
|
||||
* 2 = ---222XX = -----222 XX------
|
||||
* 3 = ---33333 = --33333-
|
||||
* 4 = ---4XXXX = -------4 XXXX----
|
||||
* 5 = ---5555X = ----5555 X-------
|
||||
* 6 = ---66666 = -66666--
|
||||
* 7 = ---77XXX = ------77 XXX-----
|
||||
* 8 = ---88888 = ---88888
|
||||
*/
|
||||
|
||||
if (dest && src)
|
||||
{
|
||||
unsigned char* pSrc = (unsigned char*)src;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
size_t dwBlockSize;
|
||||
unsigned char n1, n2, n3, n4, n5, n6, n7, n8;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* Encode inputs */
|
||||
dwBlockSize = (dwSrcSize < BASE32_INPUT ? dwSrcSize : BASE32_INPUT);
|
||||
n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = 0;
|
||||
switch (dwBlockSize)
|
||||
{
|
||||
case 5:
|
||||
n8 = (pSrc[ 4 ] & 0x1f);
|
||||
n7 = ((pSrc[ 4 ] & 0xe0) >> 5);
|
||||
case 4:
|
||||
n7 |= ((pSrc[ 3 ] & 0x03) << 3);
|
||||
n6 = ((pSrc[ 3 ] & 0x7c) >> 2);
|
||||
n5 = ((pSrc[ 3 ] & 0x80) >> 7);
|
||||
case 3:
|
||||
n5 |= ((pSrc[ 2 ] & 0x0f) << 1);
|
||||
n4 = ((pSrc[ 2 ] & 0xf0) >> 4);
|
||||
case 2:
|
||||
n4 |= ((pSrc[ 1 ] & 0x01) << 4);
|
||||
n3 = ((pSrc[ 1 ] & 0x3e) >> 1);
|
||||
n2 = ((pSrc[ 1 ] & 0xc0) >> 6);
|
||||
case 1:
|
||||
n2 |= ((pSrc[ 0 ] & 0x07) << 2);
|
||||
n1 = ((pSrc[ 0 ] & 0xf8) >> 3);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
pSrc += dwBlockSize;
|
||||
dwSrcSize -= dwBlockSize;
|
||||
|
||||
/* Validate */
|
||||
assert( n1 <= 31 );
|
||||
assert( n2 <= 31 );
|
||||
assert( n3 <= 31 );
|
||||
assert( n4 <= 31 );
|
||||
assert( n5 <= 31 );
|
||||
assert( n6 <= 31 );
|
||||
assert( n7 <= 31 );
|
||||
assert( n8 <= 31 );
|
||||
|
||||
/* Padding */
|
||||
switch (dwBlockSize)
|
||||
{
|
||||
case 1: n3 = n4 = 32;
|
||||
case 2: n5 = 32;
|
||||
case 3: n6 = n7 = 32;
|
||||
case 4: n8 = 32;
|
||||
case 5:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
/* 8 outputs */
|
||||
*dest++ = BASE32_TABLE[ n1 ];
|
||||
*dest++ = BASE32_TABLE[ n2 ];
|
||||
*dest++ = BASE32_TABLE[ n3 ];
|
||||
*dest++ = BASE32_TABLE[ n4 ];
|
||||
*dest++ = BASE32_TABLE[ n5 ];
|
||||
*dest++ = BASE32_TABLE[ n6 ];
|
||||
*dest++ = BASE32_TABLE[ n7 ];
|
||||
*dest++ = BASE32_TABLE[ n8 ];
|
||||
dwDestSize += BASE32_OUTPUT;
|
||||
}
|
||||
*dest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer*/
|
||||
}
|
||||
|
||||
/****************************** Base64 Encoding ******************************/
|
||||
|
||||
static const size_t BASE64_INPUT = 3;
|
||||
static const size_t BASE64_OUTPUT = 4;
|
||||
static const char* const BASE64_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
size_t cyoBase64EncodeGetLength( size_t size )
|
||||
{
|
||||
return cyoBaseXXEncodeGetLength( size, BASE64_INPUT, BASE64_OUTPUT );
|
||||
}
|
||||
|
||||
size_t cyoBase64Encode( char* dest, const void* src, size_t size )
|
||||
{
|
||||
/*
|
||||
* output 4 bytes for every 3 input:
|
||||
*
|
||||
* inputs: 1 2 3
|
||||
* outputs: 1 = --111111 = 111111--
|
||||
* 2 = --22XXXX = ------22 XXXX----
|
||||
* 3 = --3333XX = ----3333 XX------
|
||||
* 4 = --444444 = --444444
|
||||
*/
|
||||
|
||||
if (dest && src)
|
||||
{
|
||||
unsigned char* pSrc = (unsigned char*)src;
|
||||
size_t dwSrcSize = size;
|
||||
size_t dwDestSize = 0;
|
||||
size_t dwBlockSize = 0;
|
||||
unsigned char n1, n2, n3, n4;
|
||||
|
||||
while (dwSrcSize >= 1)
|
||||
{
|
||||
/* Encode inputs */
|
||||
dwBlockSize = (dwSrcSize < BASE64_INPUT ? dwSrcSize : BASE64_INPUT);
|
||||
n1 = n2 = n3 = n4 = 0;
|
||||
switch (dwBlockSize)
|
||||
{
|
||||
case 3:
|
||||
n4 = (pSrc[ 2 ] & 0x3f);
|
||||
n3 = ((pSrc[ 2 ] & 0xc0) >> 6);
|
||||
case 2:
|
||||
n3 |= ((pSrc[ 1 ] & 0x0f) << 2);
|
||||
n2 = ((pSrc[ 1 ] & 0xf0) >> 4);
|
||||
case 1:
|
||||
n2 |= ((pSrc[ 0 ] & 0x03) << 4);
|
||||
n1 = ((pSrc[ 0 ] & 0xfc) >> 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
pSrc += dwBlockSize;
|
||||
dwSrcSize -= dwBlockSize;
|
||||
|
||||
/* Validate */
|
||||
assert( n1 <= 63 );
|
||||
assert( n2 <= 63 );
|
||||
assert( n3 <= 63 );
|
||||
assert( n4 <= 63 );
|
||||
|
||||
/* Padding */
|
||||
switch (dwBlockSize)
|
||||
{
|
||||
case 1: n3 = 64;
|
||||
case 2: n4 = 64;
|
||||
case 3:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
/* 4 outputs */
|
||||
*dest++ = BASE64_TABLE[ n1 ];
|
||||
*dest++ = BASE64_TABLE[ n2 ];
|
||||
*dest++ = BASE64_TABLE[ n3 ];
|
||||
*dest++ = BASE64_TABLE[ n4 ];
|
||||
dwDestSize += BASE64_OUTPUT;
|
||||
}
|
||||
*dest++ = '\x0'; /*append terminator*/
|
||||
|
||||
return dwDestSize;
|
||||
}
|
||||
else
|
||||
return 0; /*ERROR - null pointer*/
|
||||
}
|
||||
55
vendor/cyoencode-1.0.2/src/CyoEncode.h
vendored
55
vendor/cyoencode-1.0.2/src/CyoEncode.h
vendored
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* CyoEncode.h - part of the CyoEncode library
|
||||
*
|
||||
* Copyright (c) 2009-2012, Graham Bull.
|
||||
* 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.
|
||||
*
|
||||
* 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 HOLDER 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.
|
||||
*/
|
||||
|
||||
#ifndef __CYOENCODE_H
|
||||
#define __CYOENCODE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Base16 Encoding */
|
||||
size_t cyoBase16EncodeGetLength( size_t size );
|
||||
size_t cyoBase16Encode( char* dest, const void* src, size_t size );
|
||||
|
||||
/* Base32 Encoding */
|
||||
size_t cyoBase32EncodeGetLength( size_t size );
|
||||
size_t cyoBase32Encode( char* dest, const void* src, size_t size );
|
||||
|
||||
/* Base64 Encoding */
|
||||
size_t cyoBase64EncodeGetLength( size_t size );
|
||||
size_t cyoBase64Encode( char* dest, const void* src, size_t size );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__CYOENCODE_H*/
|
||||
|
||||
2
vendor/cyoencode-1.0.2/src/build.sh
vendored
2
vendor/cyoencode-1.0.2/src/build.sh
vendored
|
|
@ -1,2 +0,0 @@
|
|||
gcc test.c CyoEncode.c CyoDecode.c -o test
|
||||
|
||||
162
vendor/cyoencode-1.0.2/src/cyoencode-vc100.vcxproj
vendored
162
vendor/cyoencode-1.0.2/src/cyoencode-vc100.vcxproj
vendored
|
|
@ -1,162 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>cyoencode-vc100</ProjectName>
|
||||
<ProjectGuid>{C773C1E9-CAC6-40AF-A400-567F73AB0178}</ProjectGuid>
|
||||
<RootNamespace>cyoencodevc100</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Configuration)\</IntDir>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
|
||||
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CyoDecode.c" />
|
||||
<ClCompile Include="CyoEncode.c" />
|
||||
<ClCompile Include="test.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CyoDecode.h" />
|
||||
<ClInclude Include="CyoEncode.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
129
vendor/cyoencode-1.0.2/src/cyoencode-vc71.vcproj
vendored
129
vendor/cyoencode-1.0.2/src/cyoencode-vc71.vcproj
vendored
|
|
@ -1,129 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="cyoencode-vc71"
|
||||
ProjectGUID="{E658BBCC-49D8-4B45-B374-EF43427EB66B}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/cyoencode-vc71.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/cyoencode-vc71.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/cyoencode-vc71.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\test.c">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
195
vendor/cyoencode-1.0.2/src/cyoencode-vc80.vcproj
vendored
195
vendor/cyoencode-1.0.2/src/cyoencode-vc80.vcproj
vendored
|
|
@ -1,195 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="cyoencode-vc80"
|
||||
ProjectGUID="{F0A6E47E-F480-4F4A-8730-F655144E2D7F}"
|
||||
RootNamespace="cyoencodevc80"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\test.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
341
vendor/cyoencode-1.0.2/src/cyoencode-vc90.vcproj
vendored
341
vendor/cyoencode-1.0.2/src/cyoencode-vc90.vcproj
vendored
|
|
@ -1,341 +0,0 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="cyoencode-vc90"
|
||||
ProjectGUID="{C773C1E9-CAC6-40AF-A400-567F73AB0178}"
|
||||
RootNamespace="cyoencodevc90"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoDecode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CyoEncode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\test.c"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
191
vendor/cyoencode-1.0.2/src/test.c
vendored
191
vendor/cyoencode-1.0.2/src/test.c
vendored
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* test.c - part of the CyoEncode library
|
||||
*
|
||||
* Copyright (c) 2009-2012, Graham Bull.
|
||||
* 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.
|
||||
*
|
||||
* 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 HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "CyoEncode.h"
|
||||
#include "CyoDecode.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TEST_BASExx(base,str,expected) \
|
||||
printf( "TEST_BASE%s('%s')='%s'", #base, str, expected ); \
|
||||
required = cyoBase##base##EncodeGetLength( strlen( str )); \
|
||||
encoded = (char*)malloc( required ); \
|
||||
if (encoded == NULL) { \
|
||||
printf( "\n*** ERROR: Unable to allocate buffer for encoding ***\n" ); \
|
||||
goto exit; \
|
||||
} \
|
||||
cyoBase##base##Encode( encoded, str, strlen( str )); \
|
||||
if (strcmp( encoded, expected ) != 0) { \
|
||||
printf( "\n*** ERROR: Encoding failure ***\n" ); \
|
||||
goto exit; \
|
||||
} \
|
||||
valid = cyoBase##base##Validate( encoded, strlen( encoded )); \
|
||||
if (valid < 0) \
|
||||
{ \
|
||||
printf( "\n*** ERROR: Unable to validate encoding (error %d) ***\n", valid ); \
|
||||
goto exit; \
|
||||
} \
|
||||
printf( " [passed]\n" ); \
|
||||
free( encoded ); encoded = NULL;
|
||||
|
||||
#define TEST_BASE64(str,expected) TEST_BASExx(64,str,expected)
|
||||
#define TEST_BASE32(str,expected) TEST_BASExx(32,str,expected)
|
||||
#define TEST_BASE16(str,expected) TEST_BASExx(16,str,expected)
|
||||
|
||||
#define CHECK_INVALID_BASExx(base,str,res) \
|
||||
printf( "CHECK_INVALID_BASE%s('%s')=%d", #base, str, res ); \
|
||||
valid = cyoBase##base##Validate( str, strlen( str )); \
|
||||
if (valid == 0) \
|
||||
{ \
|
||||
printf( "\n*** ERROR: This is a valid encoding! ***\n" ); \
|
||||
goto exit; \
|
||||
} \
|
||||
if (valid != res) \
|
||||
{ \
|
||||
printf( "\n*** ERROR: Expected a different return code! (%d) ***\n", valid ); \
|
||||
goto exit; \
|
||||
} \
|
||||
printf( " [passed]\n", #base, str ); \
|
||||
|
||||
#define CHECK_INVALID_BASE16(enc,res) CHECK_INVALID_BASExx(16,enc,res)
|
||||
#define CHECK_INVALID_BASE32(enc,res) CHECK_INVALID_BASExx(32,enc,res)
|
||||
#define CHECK_INVALID_BASE64(enc,res) CHECK_INVALID_BASExx(64,enc,res)
|
||||
|
||||
int main( void )
|
||||
{
|
||||
const char* const original = "A wise man speaks when he has something to say";
|
||||
size_t required = 0;
|
||||
char* encoded = NULL;
|
||||
char* decoded = NULL;
|
||||
int valid = 0;
|
||||
int retcode = 1;
|
||||
|
||||
printf( "Running CyoEncode tests...\n" );
|
||||
|
||||
/* Encode using Base64 */
|
||||
|
||||
printf( "Original = '%s'\n", original );
|
||||
required = cyoBase64EncodeGetLength( strlen( original ));
|
||||
encoded = (char*)malloc( required );
|
||||
if (encoded == NULL)
|
||||
{
|
||||
printf( "*** ERROR: Unable to allocate buffer for encoding ***\n" );
|
||||
goto exit;
|
||||
}
|
||||
cyoBase64Encode( encoded, original, strlen( original ));
|
||||
printf( "Encoded = '%s'\n", encoded );
|
||||
|
||||
/* Validate encoding */
|
||||
|
||||
valid = cyoBase64Validate( encoded, strlen( encoded ));
|
||||
if (valid < 0)
|
||||
{
|
||||
printf( "*** ERROR: Encoding failure (error %d) ***\n", valid );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Decode using Base64 */
|
||||
|
||||
required = cyoBase64DecodeGetLength( strlen( encoded ));
|
||||
decoded = (char*)malloc( required );
|
||||
if (decoded == NULL)
|
||||
{
|
||||
printf( "*** ERROR: Unable to allocate buffer for decoding ***\n" );
|
||||
goto exit;
|
||||
}
|
||||
cyoBase64Decode( decoded, encoded, strlen( encoded ));
|
||||
printf( "Decoded = '%s'\n", decoded );
|
||||
|
||||
/* Validate */
|
||||
|
||||
if (strcmp( original, decoded ) != 0)
|
||||
{
|
||||
printf( "*** ERROR: Encoding/decoding failure ***\n" );
|
||||
goto exit;
|
||||
}
|
||||
|
||||
free( encoded );
|
||||
encoded = NULL;
|
||||
free( decoded );
|
||||
decoded = NULL;
|
||||
|
||||
/* Test vectors from RFC 4648 */
|
||||
|
||||
TEST_BASE16( "", "" );
|
||||
TEST_BASE16( "f", "66" );
|
||||
TEST_BASE16( "fo", "666F" );
|
||||
TEST_BASE16( "foo", "666F6F" );
|
||||
TEST_BASE16( "foob", "666F6F62" );
|
||||
TEST_BASE16( "fooba", "666F6F6261" );
|
||||
TEST_BASE16( "foobar", "666F6F626172" );
|
||||
|
||||
TEST_BASE32( "", "" );
|
||||
TEST_BASE32( "f", "MY======" );
|
||||
TEST_BASE32( "fo", "MZXQ====" );
|
||||
TEST_BASE32( "foo", "MZXW6===" );
|
||||
TEST_BASE32( "foob", "MZXW6YQ=" );
|
||||
TEST_BASE32( "fooba", "MZXW6YTB" );
|
||||
TEST_BASE32( "foobar", "MZXW6YTBOI======" );
|
||||
|
||||
TEST_BASE64( "", "" );
|
||||
TEST_BASE64( "f", "Zg==" );
|
||||
TEST_BASE64( "fo", "Zm8=" );
|
||||
TEST_BASE64( "foo", "Zm9v" );
|
||||
TEST_BASE64( "foob", "Zm9vYg==" );
|
||||
TEST_BASE64( "fooba", "Zm9vYmE=" );
|
||||
TEST_BASE64( "foobar", "Zm9vYmFy" );
|
||||
|
||||
/* Other tests */
|
||||
|
||||
CHECK_INVALID_BASE16( "1", -1 );
|
||||
CHECK_INVALID_BASE16( "123", -1 );
|
||||
CHECK_INVALID_BASE16( "1G", -2 );
|
||||
|
||||
CHECK_INVALID_BASE32( "A", -1 );
|
||||
CHECK_INVALID_BASE32( "ABCDEFG", -1 );
|
||||
CHECK_INVALID_BASE32( "ABCDEFG1", -2 );
|
||||
CHECK_INVALID_BASE32( "A=======", -2 );
|
||||
|
||||
CHECK_INVALID_BASE64( "A", -1 );
|
||||
CHECK_INVALID_BASE64( "ABCDE", -1 );
|
||||
CHECK_INVALID_BASE64( "A&B=", -2 );
|
||||
CHECK_INVALID_BASE64( "A===", -2 );
|
||||
|
||||
printf( "*** All tests passed ***\n" );
|
||||
retcode = 0;
|
||||
|
||||
exit:
|
||||
if (encoded != NULL)
|
||||
free( encoded );
|
||||
if (decoded != NULL)
|
||||
free( decoded );
|
||||
|
||||
return retcode;
|
||||
}
|
||||
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
1
vendor/diff-match-patch-cpp-stl
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7f95b37e554453262e2bcda830724fc362614103
|
||||
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} )
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue