Merged in betting-merge (pull request #1)

Betting merge
This commit is contained in:
Andrew Moore 2018-08-27 13:59:03 +00:00
commit c8c05254b1
130 changed files with 2497 additions and 19690 deletions

3
.gitignore vendored
View file

@ -48,7 +48,4 @@ fc_automoc.cpp
git_revision.cpp
GitSHA3.cpp
ntp_test
task_cancel_test
udt_client
udt_server

7
.gitmodules vendored
View file

@ -1,6 +1,9 @@
[submodule "vendor/diff-match-patch-cpp-stl"]
path = vendor/diff-match-patch-cpp-stl
url = https://github.com/leutloff/diff-match-patch-cpp-stl
[submodule "vendor/secp256k1-zkp"]
path = vendor/secp256k1-zkp
url = https://github.com/cryptonomex/secp256k1-zkp.git
path = vendor/secp256k1-zkp
url = https://github.com/bitshares/secp256k1-zkp.git
[submodule "vendor/websocketpp"]
path = vendor/websocketpp
url = https://github.com/zaphoyd/websocketpp.git

View file

@ -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_
)
# Activate C++ exception handling, assume extern C calls don't throw
# Add /U options to be sure settings specific to dynamic boost link are ineffective
target_compile_options(fc PUBLIC /EHsc /UBOOST_ALL_DYN_LINK /UBOOST_LINKING_PYTHON /UBOOST_DEBUG_PYTHON)
if( MSVC )
# Activate C++ exception handling, assume extern C calls don't throw
# Add /U options to be sure settings specific to dynamic boost link are ineffective
target_compile_options(fc PUBLIC /EHsc /UBOOST_ALL_DYN_LINK /UBOOST_LINKING_PYTHON /UBOOST_DEBUG_PYTHON)
elseif( MINGW )
# Put MinGW specific compiler settings here
endif()
ELSE()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall")
IF(APPLE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPP_STANDARD} -stdlib=libc++ -Wall")
ELSE()
if( NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
target_compile_options(fc PUBLIC -std=c++11 -Wall -fnon-call-exceptions)
target_compile_options(fc PUBLIC ${CPP_STANDARD} -Wall -fnon-call-exceptions)
endif()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${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}

View file

@ -45,3 +45,5 @@ mark_as_advanced(
Readline_INCLUDE_DIR
Readline_LIBRARY
)
MESSAGE( STATUS "Found Readline: ${Readline_LIBRARY}" )

View file

@ -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 )

View file

@ -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}")

View file

@ -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:

View file

@ -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(); }

View file

@ -20,11 +20,17 @@ namespace fc {
T& at( size_t pos ) { assert( pos < N); return data[pos]; }
const T& at( size_t pos )const { assert( pos < N); return data[pos]; }
///@}
T& operator[]( size_t pos ) { assert( pos < N); return data[pos]; }
const T& operator[]( size_t pos )const { assert( pos < N); return data[pos]; }
T* begin() { return &data[0]; }
const T* begin()const { return &data[0]; }
const T* end()const { return &data[N]; }
T* begin() { return &data[0]; }
T* end() { return &data[N]; }
size_t size()const { return N; }
T data[N];

View file

@ -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();

View file

@ -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

View file

@ -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 );
}

View file

@ -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;
};

View 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

View file

@ -68,15 +68,34 @@ class sha256
friend bool operator > ( const sha256& h1, const sha256& h2 );
friend bool operator < ( const sha256& h1, const sha256& h2 );
uint32_t pop_count()
uint32_t pop_count()const
{
return (uint32_t)(__builtin_popcountll(_hash[0]) +
__builtin_popcountll(_hash[1]) +
__builtin_popcountll(_hash[2]) +
__builtin_popcountll(_hash[3]));
}
uint64_t _hash[4];
/**
* Count leading zero bits
*/
uint16_t clz()const;
/**
* Approximate (log_2(x) + 1) * 2**24.
*
* Detailed specs:
* - Return 0 when x == 0.
* - High 8 bits of result simply counts nonzero bits.
* - Low 24 bits of result are the 24 bits of input immediately after the most significant 1 in the input.
* - If above would require reading beyond the end of the input, zeros are used instead.
*/
uint32_t approx_log_32()const;
void set_to_inverse_approx_log_32( uint32_t x );
static double inverse_approx_log_32_double( uint32_t x );
uint64_t _hash[4];
};
typedef sha256 uint256;
@ -99,5 +118,17 @@ namespace std
}
};
}
namespace boost
{
template<>
struct hash<fc::sha256>
{
size_t operator()( const fc::sha256& s )const
{
return s._hash[3];//*((size_t*)&s);
}
};
}
#include <fc/reflect/reflect.hpp>
FC_REFLECT_TYPENAME( fc::sha256 )

View file

@ -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" );

View file

@ -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
View 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();
}
}

View 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 );
}
}
}

View 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

View file

@ -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 )
{

View file

@ -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 {

View file

@ -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 );

View file

@ -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 ) \

View file

@ -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

View file

@ -40,11 +40,12 @@ namespace fc {
struct request
{
fc::string get_header( const fc::string& key )const;
fc::string remote_endpoint;
fc::string method;
fc::string domain;
fc::string path;
std::vector<header> headers;
std::vector<char> body;
std::vector<header> headers;
std::vector<char> body;
};
std::vector<header> parse_urlencoded_params( const fc::string& f );

View file

@ -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 );

View file

@ -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

View file

@ -18,9 +18,11 @@ namespace fc {
* fc::optional adds less than 400.
*/
template<typename T>
class optional
class optional
{
public:
typedef T value_type;
optional():_valid(false){}
~optional(){ reset(); }

View file

@ -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

View file

@ -88,8 +88,8 @@ namespace fc
{
if( v.is_string() )
o = fc::reflector<T>::from_string( v.get_string().c_str() );
else
o = static_cast<T>(v.as_int64());
else
o = fc::reflector<T>::from_int( v.as_int64() );
}
};

View file

@ -12,8 +12,6 @@
namespace fc {
class api_connection;
typedef uint32_t api_id_type;
namespace detail {
template<typename Signature>
@ -68,6 +66,33 @@ namespace fc {
};
}
/**
* If api<T> is returned from a remote method, the API is eagerly bound to api<T> of
* the correct type in api_visitor::from_variant(). This binding [1] needs a reference
* to the api_connection, which is made available to from_variant() as a parameter.
*
* However, in the case of a remote method which returns api_base which can subsequently
* be cast by the caller with as<T>, we need to keep track of the connection because
* the binding is done later (when the client code actually calls as<T>).
*
* [1] The binding actually happens in get_remote_api().
*/
class any_api : public api_base
{
public:
any_api( api_id_type api_id, const std::shared_ptr<fc::api_connection>& con )
: _api_id(api_id), _api_connection(con) {}
virtual uint64_t get_handle()const override
{ return _api_id; }
virtual api_id_type register_api( api_connection& conn )const override
{ FC_ASSERT( false ); return api_id_type(); }
api_id_type _api_id;
std::weak_ptr<fc::api_connection> _api_connection;
};
} // namespace detail
class generic_api
@ -143,7 +168,7 @@ namespace fc {
struct api_visitor
{
api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):api(a),_api_con(s){ }
api_visitor( generic_api& a, const std::weak_ptr<fc::api_connection>& s ):_api(a),_api_con(s){ }
template<typename Interface, typename Adaptor, typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<api<Interface,Adaptor>(Args...)>& f )const;
@ -151,6 +176,9 @@ namespace fc {
template<typename Interface, typename Adaptor, typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::optional<api<Interface,Adaptor>>(Args...)>& f )const;
template<typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<fc::api_ptr(Args...)>& f )const;
template<typename R, typename ... Args>
std::function<variant(const fc::variants&)> to_generic( const std::function<R(Args...)>& f )const;
@ -159,11 +187,11 @@ namespace fc {
template<typename Result, typename... Args>
void operator()( const char* name, std::function<Result(Args...)>& memb )const {
api._methods.emplace_back( to_generic( memb ) );
api._by_name[name] = api._methods.size() - 1;
_api._methods.emplace_back( to_generic( memb ) );
_api._by_name[name] = _api._methods.size() - 1;
}
generic_api& api;
generic_api& _api;
const std::weak_ptr<fc::api_connection>& _api_con;
};
@ -267,6 +295,17 @@ namespace fc {
return con->get_remote_api<ResultInterface>( v.as_uint64() );
}
static fc::api_ptr from_variant(
const variant& v,
fc::api_ptr* /* used for template deduction */,
const std::shared_ptr<fc::api_connection>& con
)
{
if( v.is_null() )
return fc::api_ptr();
return fc::api_ptr( new detail::any_api( v.as_uint64(), con ) );
}
template<typename T>
static fc::variant convert_callbacks( const std::shared_ptr<fc::api_connection>&, const T& v )
{
@ -345,7 +384,7 @@ namespace fc {
const std::function<fc::api<Interface,Adaptor>(Args...)>& f )const
{
auto api_con = _api_con;
auto gapi = &api;
auto gapi = &_api;
return [=]( const variants& args ) {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
@ -359,7 +398,7 @@ namespace fc {
const std::function<fc::optional<fc::api<Interface,Adaptor>>(Args...)>& f )const
{
auto api_con = _api_con;
auto gapi = &api;
auto gapi = &_api;
return [=]( const variants& args )-> fc::variant {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
@ -370,10 +409,28 @@ namespace fc {
return variant();
};
}
template<typename ... Args>
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic(
const std::function<fc::api_ptr(Args...)>& f )const
{
auto api_con = _api_con;
auto gapi = &_api;
return [=]( const variants& args ) -> fc::variant {
auto con = api_con.lock();
FC_ASSERT( con, "not connected" );
auto api_result = gapi->call_generic( f, args.begin(), args.end() );
if( !api_result )
return variant();
return api_result->register_api( *con );
};
}
template<typename R, typename ... Args>
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<R(Args...)>& f )const
{
generic_api* gapi = &api;
generic_api* gapi = &_api;
return [f,gapi]( const variants& args ) {
return variant( gapi->call_generic( f, args.begin(), args.end() ) );
};
@ -382,13 +439,47 @@ namespace fc {
template<typename ... Args>
std::function<variant(const fc::variants&)> generic_api::api_visitor::to_generic( const std::function<void(Args...)>& f )const
{
generic_api* gapi = &api;
generic_api* gapi = &_api;
return [f,gapi]( const variants& args ) {
gapi->call_generic( f, args.begin(), args.end() );
return variant();
};
}
/**
* It is slightly unclean tight coupling to have this method in the api class.
* It breaks encapsulation by requiring an api class method to have a pointer
* to an api_connection. The reason this is necessary is we have a goal of being
* able to call register_api() on an api<T> through its base class api_base. But
* register_api() must know the template parameters!
*
* The only reasonable way to achieve the goal is to implement register_api()
* as a method in api<T> (which obviously knows the template parameter T),
* then make the implementation accessible through the base class (by making
* it a pure virtual method in the base class which is overridden by the subclass's
* implementation).
*/
template< typename Interface, typename Transform >
api_id_type api< Interface, Transform >::register_api( api_connection& conn )const
{
return conn.register_api( *this );
}
template< typename T >
api<T> api_base::as()
{
// TODO: this method should probably be const (if it is not too hard)
api<T>* maybe_requested_type = dynamic_cast< api<T>* >(this);
if( maybe_requested_type != nullptr )
return *maybe_requested_type;
detail::any_api* maybe_any = dynamic_cast< detail::any_api* >(this);
FC_ASSERT( maybe_any != nullptr );
std::shared_ptr< api_connection > api_conn = maybe_any->_api_connection.lock();
FC_ASSERT( api_conn );
return api_conn->get_remote_api<T>( maybe_any->_api_id );
}
namespace detail {
template<typename Signature>
template<typename... Args>

View 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
View 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) )

View file

@ -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) )

View 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) );
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -8,19 +8,21 @@
namespace fc
{
bool is_utf8( const std::string& str );
std::string prune_invalid_utf8( const std::string& str );
/** Decodes utf 8 std::string into unicode string.
@param input - input string to be decoded and stored in 'storage'
@param storage - buffer for converted text. Cannot be nullptr.
*/
void decodeUtf8(const std::string& input, std::wstring* storage);
/** Encodes given wide (unicode) string into UTF-8 representation.
@param input - input string to be encoded and stored in 'storage'
@param storage - buffer for converted text. Cannot be nullptr.
*/
void encodeUtf8(const std::wstring& input, std::string* storage);
bool is_utf8( const std::string& str );
/** Decodes utf 8 std::string into unicode string.
@param input - input string to be decoded and stored in 'storage'
@param storage - buffer for converted text. Cannot be nullptr.
*/
void decodeUtf8(const std::string& input, std::wstring* storage);
/** Encodes given wide (unicode) string into UTF-8 representation.
@param input - input string to be encoded and stored in 'storage'
@param storage - buffer for converted text. Cannot be nullptr.
*/
void encodeUtf8(const std::wstring& input, std::string* storage);
} /// namespace fc

View file

@ -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 );

View file

@ -92,45 +92,51 @@ namespace fc {
struct default_io_service_scope
{
boost::asio::io_service* io;
boost::thread* asio_thread;
std::vector<boost::thread*> asio_threads;
boost::asio::io_service::work* the_work;
default_io_service_scope()
{
io = new boost::asio::io_service();
the_work = new boost::asio::io_service::work(*io);
asio_thread = new boost::thread( [=]()
{
fc::thread::current().set_name("asio");
while (!io->stopped())
{
try
{
io->run();
}
catch (const fc::exception& e)
{
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e));
}
catch (const std::exception& e)
{
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e.what()));
}
catch (...)
{
elog("Caught unhandled exception in asio service loop");
}
}
});
for( int i = 0; i < 8; ++i ) {
asio_threads.push_back( new boost::thread( [=]()
{
fc::thread::current().set_name("asio");
while (!io->stopped())
{
try
{
io->run();
}
catch (const fc::exception& e)
{
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e));
}
catch (const std::exception& e)
{
elog("Caught unhandled exception in asio service loop: ${e}", ("e", e.what()));
}
catch (...)
{
elog("Caught unhandled exception in asio service loop");
}
}
}) );
}
}
void cleanup()
{
delete the_work;
io->stop();
asio_thread->join();
for( auto asio_thread : asio_threads ) {
asio_thread->join();
}
delete io;
delete asio_thread;
for( auto asio_thread : asio_threads ) {
delete asio_thread;
}
}
~default_io_service_scope()
@ -139,10 +145,12 @@ namespace fc {
/// If cleanup is true, do not use the return value; it is a null reference
boost::asio::io_service& default_io_service(bool cleanup) {
static default_io_service_scope fc_asio_service;
if (cleanup)
fc_asio_service.cleanup();
return *fc_asio_service.io;
static default_io_service_scope fc_asio_service[1];
if (cleanup) {
for( int i = 0; i < 1; ++i )
fc_asio_service[i].cleanup();
}
return *fc_asio_service[0].io;
}
namespace tcp {

View file

@ -1,6 +1,6 @@
#pragma once
#ifdef _MSC_VER
#ifdef _WIN32
# include <stdlib.h>
# define bswap_64(x) _byteswap_uint64(x)
#elif defined(__APPLE__)

View file

@ -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;

View file

@ -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

View file

@ -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() );
}
}

View file

@ -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)

View file

@ -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>

View file

@ -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;
}

View file

@ -12,7 +12,7 @@
#include <assert.h>
#include <secp256k1.h>
#ifdef _MSC_VER
#if _WIN32
# include <malloc.h>
#else
# include <alloca.h>

View file

@ -3,6 +3,7 @@
#include <fc/fwd_impl.hpp>
#include <openssl/sha.h>
#include <string.h>
#include <cmath>
#include <fc/crypto/sha256.hpp>
#include <fc/variant.hpp>
#include <fc/exception/exception.hpp>
@ -97,7 +98,102 @@ namespace fc {
bool operator == ( const sha256& h1, const sha256& h2 ) {
return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0;
}
uint32_t sha256::approx_log_32()const
{
uint16_t lzbits = clz();
if( lzbits >= 0x100 )
return 0;
uint8_t nzbits = 0xFF-lzbits;
size_t offset = (size_t) (lzbits >> 3);
uint8_t* my_bytes = (uint8_t*) data();
size_t n = data_size();
uint32_t y = (uint32_t( my_bytes[offset ] ) << 0x18)
| (uint32_t(offset+1 < n ? my_bytes[offset+1] : 0) << 0x10)
| (uint32_t(offset+2 < n ? my_bytes[offset+2] : 0) << 0x08)
| (uint32_t(offset+3 < n ? my_bytes[offset+3] : 0) )
;
//
// lzbits&7 == 7 : 00000001 iff nzbits&7 == 0
// lzbits&7 == 6 : 0000001x iff nzbits&7 == 1
// lzbits&7 == 5 : 000001xx iff nzbits&7 == 2
//
y >>= (nzbits & 7);
y ^= 1 << 0x18;
y |= uint32_t( nzbits ) << 0x18;
return y;
}
void sha256::set_to_inverse_approx_log_32( uint32_t x )
{
uint8_t nzbits = uint8_t( x >> 0x18 );
_hash[0] = 0;
_hash[1] = 0;
_hash[2] = 0;
_hash[3] = 0;
if( nzbits == 0 )
return;
uint8_t x0 = uint8_t((x ) & 0xFF);
uint8_t x1 = uint8_t((x >> 0x08) & 0xFF);
uint8_t x2 = uint8_t((x >> 0x10) & 0xFF);
uint8_t* my_bytes = (uint8_t*) data();
my_bytes[0x1F] = x0;
my_bytes[0x1E] = x1;
my_bytes[0x1D] = x2;
my_bytes[0x1C] = 1;
if( nzbits <= 0x18 )
{
(*this) = (*this) >> (0x18 - nzbits);
}
else
(*this) = (*this) << (nzbits - 0x18);
return;
}
double sha256::inverse_approx_log_32_double( uint32_t x )
{
uint8_t nzbits = uint8_t( x >> 0x18 );
if( nzbits == 0 )
return 0.0;
uint32_t b = 1 << 0x18;
uint32_t y = (x & (b-1)) | b;
return std::ldexp( y, int( nzbits ) - 0x18 );
}
uint16_t sha256::clz()const
{
const uint8_t* my_bytes = (uint8_t*) data();
size_t size = data_size();
size_t lzbits = 0;
static const uint8_t char2lzbits[] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
size_t i = 0;
while( true )
{
uint8_t c = my_bytes[i];
lzbits += char2lzbits[c];
if( c != 0 )
break;
++i;
if( i >= size )
return 0x100;
}
return lzbits;
}
void to_variant( const sha256& bi, variant& v )
{
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );

View file

@ -21,7 +21,6 @@ namespace fc
(eof_exception)
(unknown_host_exception)
(null_optional)
(udt_exception)
(aes_exception)
(overflow_exception)
(underflow_exception)
@ -156,7 +155,7 @@ namespace fc
* and other information that is generally only useful for
* developers.
*/
string exception::to_detail_string( log_level ll )const
string exception::to_detail_string( log_level ll )const
{
fc::stringstream ss;
ss << variant(my->_code).as_string() <<" " << my->_name << ": " <<my->_what<<"\n";
@ -174,13 +173,14 @@ namespace fc
/**
* Generates a user-friendly error report.
*/
string exception::to_string( log_level ll )const
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();

View file

@ -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>

View 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

View file

@ -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 );

View file

@ -14,6 +14,7 @@
#include <fc/exception/exception.hpp>
#include <iomanip>
#include <sstream>
#include <mutex>
namespace fc {
@ -27,7 +28,7 @@ namespace fc {
#endif
};
console_appender::console_appender( const variant& args )
console_appender::console_appender( const variant& args )
:my(new impl)
{
configure( args.as<config>() );
@ -66,7 +67,7 @@ namespace fc {
#ifdef WIN32
static WORD
#else
static const char*
static const char*
#endif
get_console_color(console_appender::color::type t ) {
switch( t ) {
@ -140,7 +141,7 @@ namespace fc {
#endif
if( text.size() )
fprintf( out, "%s", text.c_str() ); //fmt_str.c_str() );
fprintf( out, "%s", text.c_str() ); //fmt_str.c_str() );
#ifdef WIN32
if (my->console_handle != INVALID_HANDLE_VALUE)

View file

@ -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
{

View file

@ -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

View file

@ -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_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 ){

View file

@ -8,7 +8,7 @@
#include <fc/exception/exception.hpp>
#if defined _WIN32 || defined WIN32 || defined OS_WIN64 || defined _WIN64 || defined WIN64 || defined WINNT
# include <MSTcpIP.h>
# include <mstcpip.h>
#endif
namespace fc {
@ -154,12 +154,12 @@ namespace fc {
{
try
{
my->_sock.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(local_endpoint.get_address()),
my->_sock.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(local_endpoint.get_address()),
local_endpoint.port()));
}
catch (const std::exception& except)
{
elog("Exception binding outgoing connection to desired local endpoint: ${what}", ("what", except.what()));
elog("Exception binding outgoing connection to desired local endpoint ${endpoint}: ${what}", ("endpoint", local_endpoint)("what", except.what()));
FC_THROW("error binding to ${endpoint}: ${what}", ("endpoint", local_endpoint)("what", except.what()));
}
}
@ -309,7 +309,7 @@ namespace fc {
try
{
my->_accept.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), port));
my->_accept.listen();
my->_accept.listen(256);
}
FC_RETHROW_EXCEPTIONS(warn, "error listening on socket");
}

View file

@ -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
View 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

View file

@ -11,9 +11,20 @@ http_api_connection::http_api_connection()
{
_rpc_state.add_method( "call", [this]( const variants& args ) -> variant
{
// TODO: This logic is duplicated between http_api_connection and websocket_api_connection
// it should be consolidated into one place instead of copy-pasted
FC_ASSERT( args.size() == 3 && args[2].is_array() );
api_id_type api_id;
if( args[0].is_string() )
{
variant subresult = this->receive_call( 1, args[0].as_string() );
api_id = subresult.as_uint64();
}
else
api_id = args[0].as_uint64();
return this->receive_call(
args[0].as_uint64(),
api_id,
args[1].as_string(),
args[2].get_array() );
} );
@ -85,9 +96,13 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht
auto call = var.as<fc::rpc::request>();
try
{
auto result = _rpc_state.local_call( call.method, call.params );
resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) );
resp_status = http::reply::OK;
try
{
auto result = _rpc_state.local_call( call.method, call.params );
resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) );
resp_status = http::reply::OK;
}
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) );
}
catch ( const fc::exception& e )
{

View file

@ -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,20 +87,39 @@ 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
{
auto result = _rpc_state.local_call( call.method, call.params );
if( call.id )
try
{
auto reply = fc::json::to_string( response( *call.id, result ) );
if( send_message )
_connection.send_message( reply );
return reply;
#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, "2.0" ) );
if( send_message )
_connection.send_message( reply );
return reply;
}
}
FC_CAPTURE_AND_RETHROW( (call.method)(call.params) )
}
catch ( const fc::exception& e )
{
@ -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 );

View file

@ -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;
}
} }

View file

@ -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
}
} }

View file

@ -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");
}
}
} }

View file

@ -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

View file

@ -5,7 +5,7 @@
#include "thread_d.hpp"
#if defined(_MSC_VER) && !defined(NDEBUG)
# include <Windows.h>
# include <windows.h>
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
@ -92,7 +92,7 @@ namespace fc {
p->wait();
my->boost_thread = t;
my->name = name;
wlog("name:${n} tid:${tid}", ("n", name)("tid", (uintptr_t)my->boost_thread->native_handle()) );
//wlog("name:${n} tid:${tid}", ("n", name)("tid", (uintptr_t)my->boost_thread->native_handle()) );
}
thread::thread( thread_d* ) {
my = new thread_d(*this);
@ -118,24 +118,24 @@ namespace fc {
}
thread& thread::current() {
if( !current_thread() )
if( !current_thread() )
current_thread() = new thread((thread_d*)0);
return *current_thread();
}
const string& thread::name()const
{
return my->name;
const string& thread::name()const
{
return my->name;
}
void thread::set_name( const fc::string& n )
{
{
if (!is_current())
{
async([=](){ set_name(n); }, "set_name").wait();
return;
}
my->name = n;
my->name = n;
set_thread_name(my->name.c_str()); // set thread's name for the debugger to display
}
@ -145,17 +145,17 @@ namespace fc {
return my->current->cur_task->get_desc();
return NULL;
}
void thread::debug( const fc::string& d ) { /*my->debug(d);*/ }
void thread::quit()
void thread::quit()
{
//if quitting from a different thread, start quit task on thread.
//If we have and know our attached boost thread, wait for it to finish, then return.
if( &current() != this )
if( &current() != this )
{
async( [=](){quit();}, "thread::quit" );//.wait();
if( my->boost_thread )
if( my->boost_thread )
{
//wlog("destroying boost thread ${tid}",("tid",(uintptr_t)my->boost_thread->native_handle()));
my->boost_thread->join();
@ -170,23 +170,23 @@ namespace fc {
// We are quiting from our own thread...
// break all promises, thread quit!
while( my->blocked )
while( my->blocked )
{
fc::context* cur = my->blocked;
while( cur )
while( cur )
{
fc::context* n = cur->next;
// this will move the context into the ready list.
//cur->prom->set_exception( boost::copy_exception( error::thread_quit() ) );
//cur->set_exception_on_blocking_promises( thread_quit() );
cur->set_exception_on_blocking_promises( std::make_shared<canceled_exception>(FC_LOG_MESSAGE(error, "cancellation reason: thread quitting")) );
cur = n;
}
if( my->blocked )
{
if( my->blocked )
{
//wlog( "still blocking... whats up with that?");
debug( "on quit" );
debug( "on quit" );
}
}
BOOST_ASSERT( my->blocked == 0 );
@ -200,7 +200,7 @@ namespace fc {
scheduled_task->set_exception(std::make_shared<canceled_exception>(FC_LOG_MESSAGE(error, "cancellation reason: thread quitting")));
my->task_sch_queue.clear();
// move all sleep tasks to ready
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
@ -209,7 +209,7 @@ namespace fc {
// move all idle tasks to ready
fc::context* cur = my->pt_head;
while( cur )
while( cur )
{
fc::context* n = cur->next;
cur->next = 0;
@ -217,7 +217,7 @@ namespace fc {
cur = n;
}
// mark all ready tasks (should be everyone)... as canceled
// mark all ready tasks (should be everyone)... as canceled
for (fc::context* ready_context : my->ready_heap)
ready_context->canceled = true;
@ -225,22 +225,22 @@ namespace fc {
// let them all quit.
while (!my->ready_heap.empty())
{
my->start_next_fiber(true);
my->start_next_fiber(true);
my->check_for_timeouts();
}
my->clear_free_list();
my->cleanup_thread_specific_data();
}
void thread::exec()
void thread::exec()
{
if( !my->current )
if( !my->current )
my->current = new fc::context(&fc::thread::current());
try
try
{
my->process_tasks();
}
my->process_tasks();
}
catch( canceled_exception& e )
{
dlog( "thread canceled: ${e}", ("e", e.to_detail_string()) );
@ -248,40 +248,40 @@ namespace fc {
delete my->current;
my->current = 0;
}
bool thread::is_running()const
bool thread::is_running()const
{
return !my->done;
}
priority thread::current_priority()const
priority thread::current_priority()const
{
BOOST_ASSERT(my);
if( my->current )
if( my->current )
return my->current->prio;
return priority();
}
void thread::yield(bool reschedule)
void thread::yield(bool reschedule)
{
my->check_fiber_exceptions();
my->start_next_fiber(reschedule);
my->check_fiber_exceptions();
}
void thread::sleep_until( const time_point& tp )
void thread::sleep_until( const time_point& tp )
{
if( tp <= (time_point::now()+fc::microseconds(10000)) )
if( tp <= (time_point::now()+fc::microseconds(10000)) )
yield(true);
my->yield_until( tp, false );
}
int thread::wait_any_until( std::vector<promise_base::ptr>&& p, const time_point& timeout) {
for( size_t i = 0; i < p.size(); ++i )
if( p[i]->ready() )
if( p[i]->ready() )
return i;
if( timeout < time_point::now() )
if( timeout < time_point::now() )
{
fc::stringstream ss;
for( auto i = p.begin(); i != p.end(); ++i )
@ -289,20 +289,20 @@ namespace fc {
FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task",ss.str()) );
}
if( !my->current )
my->current = new fc::context(&fc::thread::current());
my->current = new fc::context(&fc::thread::current());
for( uint32_t i = 0; i < p.size(); ++i )
my->current->add_blocking_promise(p[i].get(),false);
// if not max timeout, added to sleep pqueue
if( timeout != time_point::maximum() )
if( timeout != time_point::maximum() )
{
my->current->resume_time = timeout;
my->sleep_pqueue.push_back(my->current);
std::push_heap( my->sleep_pqueue.begin(),
my->sleep_pqueue.end(),
my->sleep_pqueue.end(),
sleep_priority_less() );
}
@ -311,11 +311,11 @@ namespace fc {
for( auto i = p.begin(); i != p.end(); ++i )
my->current->remove_blocking_promise(i->get());
my->check_fiber_exceptions();
for( uint32_t i = 0; i < p.size(); ++i )
if( p[i]->ready() )
if( p[i]->ready() )
return i;
//BOOST_THROW_EXCEPTION( wait_any_error() );
@ -342,8 +342,8 @@ namespace fc {
// Because only one thread can post the 'first task', only that thread will attempt
// to aquire the lock and therefore there should be no contention on this lock except
// when *this thread is about to block on a wait condition.
if( this != &current() && !stale_head ) {
// when *this thread is about to block on a wait condition.
if( this != &current() && !stale_head ) {
boost::unique_lock<boost::mutex> lock(my->task_ready_mutex);
my->task_ready.notify_one();
}
@ -359,42 +359,42 @@ namespace fc {
thread::current().sleep_until(tp);
}
void exec()
void exec()
{
return thread::current().exec();
}
int wait_any( std::vector<promise_base::ptr>&& v, const microseconds& timeout_us )
int wait_any( std::vector<promise_base::ptr>&& v, const microseconds& timeout_us )
{
return thread::current().wait_any_until( fc::move(v), time_point::now() + timeout_us );
}
int wait_any_until( std::vector<promise_base::ptr>&& v, const time_point& tp )
int wait_any_until( std::vector<promise_base::ptr>&& v, const time_point& tp )
{
return thread::current().wait_any_until( fc::move(v), tp );
}
void thread::wait_until( promise_base::ptr&& p, const time_point& timeout )
void thread::wait_until( promise_base::ptr&& p, const time_point& timeout )
{
if( p->ready() )
if( p->ready() )
return;
if( timeout < time_point::now() )
if( timeout < time_point::now() )
FC_THROW_EXCEPTION( timeout_exception, "${task}", ("task", p->get_desc()) );
if( !my->current )
my->current = new fc::context(&fc::thread::current());
if( !my->current )
my->current = new fc::context(&fc::thread::current());
//slog( " %1% blocking on %2%", my->current, p.get() );
my->current->add_blocking_promise(p.get(), true);
// if not max timeout, added to sleep pqueue
if( timeout != time_point::maximum() )
if( timeout != time_point::maximum() )
{
my->current->resume_time = timeout;
my->sleep_pqueue.push_back(my->current);
std::push_heap( my->sleep_pqueue.begin(),
my->sleep_pqueue.end(),
my->sleep_pqueue.end(),
sleep_priority_less() );
}
@ -412,34 +412,34 @@ namespace fc {
my->check_fiber_exceptions();
}
void thread::notify( const promise_base::ptr& p )
void thread::notify( const promise_base::ptr& p )
{
//slog( "this %p my %p", this, my );
BOOST_ASSERT(p->ready());
if( !is_current() )
if( !is_current() )
{
this->async( [=](){ notify(p); }, "notify", priority::max() );
return;
}
// TODO: store a list of blocked contexts with the promise
// TODO: store a list of blocked contexts with the promise
// to accelerate the lookup.... unless it introduces contention...
// iterate over all blocked contexts
fc::context* cur_blocked = my->blocked;
fc::context* prev_blocked = 0;
while( cur_blocked )
while( cur_blocked )
{
// if the blocked context is waiting on this promise
if( cur_blocked->try_unblock( p.get() ) )
// if the blocked context is waiting on this promise
if( cur_blocked->try_unblock( p.get() ) )
{
// remove it from the blocked list.
// remove this context from the sleep queue...
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
for( uint32_t i = 0; i < my->sleep_pqueue.size(); ++i )
{
if( my->sleep_pqueue[i] == cur_blocked )
if( my->sleep_pqueue[i] == cur_blocked )
{
my->sleep_pqueue[i]->blocking_prom.clear();
my->sleep_pqueue[i] = my->sleep_pqueue.back();
@ -449,28 +449,28 @@ namespace fc {
}
}
auto cur = cur_blocked;
if( prev_blocked )
{
prev_blocked->next_blocked = cur_blocked->next_blocked;
if( prev_blocked )
{
prev_blocked->next_blocked = cur_blocked->next_blocked;
cur_blocked = prev_blocked->next_blocked;
}
else
{
my->blocked = cur_blocked->next_blocked;
}
else
{
my->blocked = cur_blocked->next_blocked;
cur_blocked = my->blocked;
}
cur->next_blocked = 0;
my->add_context_to_ready_list( cur );
}
else
}
else
{ // goto the next blocked task
prev_blocked = cur_blocked;
cur_blocked = cur_blocked->next_blocked;
}
}
}
bool thread::is_current()const
bool thread::is_current()const
{
return this == &current();
}

View file

@ -22,7 +22,7 @@ namespace fc
{
if (slot + 1 > specific_data->size())
specific_data->resize(slot + 1);
(*specific_data)[slot] = std::move(detail::specific_data_info(new_value, cleanup));
(*specific_data)[slot] = detail::specific_data_info(new_value, cleanup);
}
void* get_thread_specific_data(unsigned slot)
@ -62,4 +62,4 @@ namespace fc
}
}
}
} // end namespace fc
} // end namespace fc

View file

@ -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 &quotient, 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;
}

View file

@ -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);

View file

@ -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
View 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
View 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;
}

View file

@ -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() );

View file

@ -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
View 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
View 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)))

View file

@ -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()

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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.

View file

@ -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*/
}

View file

@ -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*/

View file

@ -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*/
}

View file

@ -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*/

View file

@ -1,2 +0,0 @@
gcc test.c CyoEncode.c CyoDecode.c -o test

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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

@ -0,0 +1 @@
Subproject commit 7f95b37e554453262e2bcda830724fc362614103

View file

@ -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