diff --git a/.gitignore b/.gitignore index 25103bf..bbccfeb 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ libfc_debug.a fc_automoc.cpp *.swp +GitSHA3.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df294ed..c44aab8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,6 @@ IF( WIN32 ) FIND_PACKAGE(Boost 1.54 REQUIRED COMPONENTS coroutine) SET(Boost_LIBRARIES ${BOOST_LIBRARIES_TEMP} ${Boost_LIBRARIES}) ENDIF() - ELSE(WIN32) MESSAGE(STATUS "Configuring fc to build on Unix/Apple") @@ -57,10 +56,6 @@ ELSE(WIN32) SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so") - include_directories( ${Boost_INCLUDE_DIR} ) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/vendor/salsa20 ) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include ) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/vendor/easylzma/src ) IF(NOT APPLE ) # then unix # Unix build: SET(SALSA_SRC vendor/salsa20/salsa20.s) @@ -69,10 +64,9 @@ ELSE(WIN32) ENDIF(NOT APPLE) ENDIF(WIN32) +find_package( OpenSSL ) -FIND_PACKAGE( OpenSSL ) - -SET (CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_LIB_SUFFIXES}) +set( CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_LIB_SUFFIXES} ) option( UNITY_BUILD OFF ) @@ -166,7 +160,7 @@ list(APPEND sources ${fc_headers}) add_subdirectory( vendor/easylzma ) -setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC ) +setup_library( fc SOURCES ${sources} LIBRARY_TYPE STATIC DONT_INSTALL_LIBRARY ) IF(WIN32) target_compile_definitions(fc PUBLIC WIN32 NOMINMAX _WIN32_WINNT=0x0501 _CRT_SECURE_NO_WARNINGS @@ -174,8 +168,8 @@ IF(WIN32) # Needed to disable MSVC autolinking feature (#pragma comment) BOOST_ALL_NO_LIB ) - # Activate C++ exception handling inc. SEH to catch GPFs - target_compile_options(fc PUBLIC /EHa) + # Activate C++ exception handling, assume extern C calls don't throw + target_compile_options(fc PUBLIC /EHsc) ELSE() SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall" ) @@ -200,7 +194,7 @@ target_include_directories(fc ${CMAKE_CURRENT_SOURCE_DIR}/vendor/easylzma/src ) -target_link_libraries( fc easylzma_static ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ) +target_link_libraries( fc easylzma_static ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_DL_LIBS}) #add_executable( test_compress tests/compress.cpp ) #target_link_libraries( test_compress fc ) @@ -209,5 +203,48 @@ target_link_libraries( fc easylzma_static ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES #add_executable( test_sleep tests/sleep.cpp ) #target_link_libraries( test_sleep fc ) +if(WIN32) + # now generate a list of the DLLs we're using to use during the install process + include (ParseLibraryList) + PARSE_LIBRARY_LIST(${Boost_LIBRARIES} + FOUND parseOk + DEBUG Boost_LIBRARIES_DEBUG + OPT Boost_LIBRARIES_RELEASE + GENERAL Boost_LIBRARIES_GENERAL) + + set(SHARED_LIBRARIES_RELEASE) + foreach(boost_import_lib ${Boost_LIBRARIES_RELEASE}) + get_filename_component(import_lib_name_root ${boost_import_lib} NAME_WE) + get_filename_component(import_lib_path ${boost_import_lib} PATH) + set(boost_dll "${import_lib_path}/${import_lib_name_root}${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(SHARED_LIBRARIES_RELEASE ${SHARED_LIBRARIES_RELEASE} ${boost_dll}) + endforeach() + + + set(SHARED_LIBRARIES_DEBUG) + foreach(boost_import_lib ${Boost_LIBRARIES_DEBUG}) + get_filename_component(import_lib_name_root ${boost_import_lib} NAME_WE) + get_filename_component(import_lib_path ${boost_import_lib} PATH) + set(boost_dll "${import_lib_path}/${import_lib_name_root}${CMAKE_SHARED_LIBRARY_SUFFIX}") + set(SHARED_LIBRARIES_DEBUG ${SHARED_LIBRARIES_DEBUG} ${boost_dll}) + endforeach() + + message("openssl_libraries=${OPENSSL_LIBRARIES}") + foreach(lib ${OPENSSL_LIBRARIES}) + get_filename_component(lib_name ${lib} NAME_WE) + if (${lib_name} STREQUAL "libeay32") + get_filename_component(lib_dir ${lib} DIRECTORY) + get_filename_component(openssl_dir "${lib_dir}/.." REALPATH) + set( eaydll "${openssl_dir}/bin/${lib_name}${CMAKE_SHARED_LIBRARY_SUFFIX}") + message( "eay=${eaydll}") + set(SHARED_LIBRARIES_DEBUG ${SHARED_LIBRARIES_DEBUG} "${eaydll}") + set(SHARED_LIBRARIES_RELEASE ${SHARED_LIBRARIES_RELEASE} "${eaydll}") + endif() + endforeach() + + set_property(TARGET fc PROPERTY SHARED_LIBRARIES_DEBUG ${SHARED_LIBRARIES_DEBUG}) + set_property(TARGET fc PROPERTY SHARED_LIBRARIES_RELEASE ${SHARED_LIBRARIES_RELEASE}) +endif(WIN32) + MESSAGE(STATUS "Finished fc module configuration...") diff --git a/CMakeModules/ParseLibraryList.cmake b/CMakeModules/ParseLibraryList.cmake new file mode 100644 index 0000000..e559b9d --- /dev/null +++ b/CMakeModules/ParseLibraryList.cmake @@ -0,0 +1,79 @@ +# -*- mode: cmake -*- + +# +# Shamelessly stolen from MSTK who shamelessly stole from Amanzi open source code https://software.lanl.gov/ascem/trac) +# +# PARSE_LIBRARY_LIST( +# DEBUG +# OPT +# GENERAL ) + +# CMake module +include(CMakeParseArguments) + +function(PARSE_LIBRARY_LIST) + + # Macro: _print_usage + macro(_print_usage) + message("PARSE_LIBRARY_LIST \n" + " FOUND \n" + " DEBUG \n" + " OPT \n" + " GENERAL \n" + "lib_list string to parse\n" + "FOUND flag to indicate if keywords were found\n" + "DEBUG variable containing debug libraries\n" + "OPT variable containing optimized libraries\n" + "GENERAL variable containing debug libraries\n") + + endmacro() + + # Read in args + cmake_parse_arguments(PARSE_ARGS "" "FOUND;DEBUG;OPT;GENERAL" "" ${ARGN}) + set(_parse_list "${PARSE_ARGS_UNPARSED_ARGUMENTS}") + if ( (NOT PARSE_ARGS_FOUND) OR + (NOT PARSE_ARGS_DEBUG) OR + (NOT PARSE_ARGS_OPT) OR + (NOT PARSE_ARGS_GENERAL) OR + (NOT _parse_list ) + ) + _print_usage() + message(FATAL_ERROR "Invalid arguments") + endif() + + # Now split the list + set(_debug_libs "") + set(_opt_libs "") + set(_gen_libs "") + foreach( item ${_parse_list} ) + if( ${item} MATCHES debug OR + ${item} MATCHES optimized OR + ${item} MATCHES general ) + + if( ${item} STREQUAL "debug" ) + set( mylist "_debug_libs" ) + elseif( ${item} STREQUAL "optimized" ) + set( mylist "_opt_libs" ) + elseif( ${item} STREQUAL "general" ) + set( mylist "_gen_libs" ) + endif() + else() + list( APPEND ${mylist} ${item} ) + endif() + endforeach() + + + # Now set output vairables + set(${PARSE_ARGS_DEBUG} "${_debug_libs}" PARENT_SCOPE) + set(${PARSE_ARGS_OPT} "${_opt_libs}" PARENT_SCOPE) + set(${PARSE_ARGS_GENERAL} "${_gen_libs}" PARENT_SCOPE) + + # If any of the lib lists are defined set flag to TRUE + if ( (_debug_libs) OR (_opt_libs) OR (_gen_libs) ) + set(${PARSE_ARGS_FOUND} TRUE PARENT_SCOPE) + else() + set(${PARSE_ARGS_FOUND} FALSE PARENT_SCOPE) + endif() + +endfunction(PARSE_LIBRARY_LIST) + diff --git a/include/fc/crypto/elliptic.hpp b/include/fc/crypto/elliptic.hpp index d507051..ac411a0 100644 --- a/include/fc/crypto/elliptic.hpp +++ b/include/fc/crypto/elliptic.hpp @@ -57,6 +57,10 @@ namespace fc { { return a.serialize() != b.serialize(); } + + /// Allows to convert current public key object into base58 number. + std::string to_base58() const; + private: friend class private_key; fc::fwd my; diff --git a/include/fc/io/varint.hpp b/include/fc/io/varint.hpp index f3c49ad..ddc1c73 100644 --- a/include/fc/io/varint.hpp +++ b/include/fc/io/varint.hpp @@ -21,6 +21,10 @@ struct unsigned_int { friend bool operator==( const unsigned_int& i, const uint32_t& v ) { return v == i.value; } friend bool operator!=( const unsigned_int& i, const uint32_t& v ) { return v != i.value; } + friend bool operator<( const unsigned_int& i, const uint32_t& v ) { return v < i.value; } + friend bool operator>=( const unsigned_int& i, const uint32_t& v ) { return v >= i.value; } + friend bool operator<( const unsigned_int& i, const unsigned_int& v ) { return v < i.value; } + friend bool operator>=( const unsigned_int& i, const unsigned_int& v ) { return v >= i.value; } }; struct signed_int { diff --git a/include/fc/signals.hpp b/include/fc/signals.hpp index 82f8a04..a322c1e 100644 --- a/include/fc/signals.hpp +++ b/include/fc/signals.hpp @@ -8,6 +8,17 @@ namespace fc { template using signal = boost::signals2::signal; #else + /** Workaround for missing Template Aliases feature in the VS 2012. + \warning Class defined below cannot have defined constructor (even base class has it) + since it is impossible to reference directly template class arguments outside this class. + This code will work until someone will use non-default constructor as it is defined in + boost::signals2::signal. + */ + template + class signal : public boost::signals2::signal + { + public: + }; #endif template diff --git a/include/fc/string.hpp b/include/fc/string.hpp index 5afeb9f..df2cac8 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -15,6 +15,7 @@ namespace fc fc::string to_string( double ); fc::string to_string( uint64_t ); fc::string to_string( int64_t ); + fc::string to_string( uint16_t ); typedef fc::optional ostring; class variant_object; diff --git a/include/fc/thread/task.hpp b/include/fc/thread/task.hpp index 664a5db..5c1b30e 100644 --- a/include/fc/thread/task.hpp +++ b/include/fc/thread/task.hpp @@ -33,6 +33,8 @@ namespace fc { void* _functor; void (*_destroy_functor)(void*); void (*_run_functor)(void*, void* ); + + void run_impl(); }; namespace detail { diff --git a/include/fc/thread/thread.hpp b/include/fc/thread/thread.hpp index eec4f72..e95a7d1 100644 --- a/include/fc/thread/thread.hpp +++ b/include/fc/thread/thread.hpp @@ -175,5 +175,29 @@ namespace fc { auto async( Functor&& f, const char* desc ="", priority prio = priority()) -> fc::future { return fc::thread::current().async( fc::forward(f), desc, prio ); } -} + +} // end namespace fc + +#ifdef _MSC_VER +struct _EXCEPTION_POINTERS; + +namespace fc { + /* There's something about the setup of the stacks created for fc::async tasks + * that screws up the global structured exception filters installed by + * SetUnhandledExceptionFilter(). The only way I've found to catch an + * unhaldned structured exception thrown in an async task is to put a + * __try/__except block inside the async task. + * We do just that, and if a SEH escapes outside the function running + * in the async task, fc will call an exception filter privided by + * set_unhandled_structured_exception_filter(), passing as arguments + * the result of GetExceptionCode() and GetExceptionInformation(). + * + * Right now there is only one global exception filter, used for any + * async task. + */ + typedef int (*unhandled_exception_filter_type)(unsigned, _EXCEPTION_POINTERS*); + void set_unhandled_structured_exception_filter(unhandled_exception_filter_type new_filter); + unhandled_exception_filter_type get_unhandled_structured_exception_filter(); +} +#endif diff --git a/src/crypto/elliptic.cpp b/src/crypto/elliptic.cpp index 9654096..dda84f2 100644 --- a/src/crypto/elliptic.cpp +++ b/src/crypto/elliptic.cpp @@ -1,8 +1,12 @@ #include + +#include +#include + #include #include #include -#include + #include namespace fc { namespace ecc { @@ -257,6 +261,17 @@ namespace fc { namespace ecc { } FC_RETHROW_EXCEPTIONS( debug, "digest: ${digest}", ("digest",digest) ); } + std::string public_key::to_base58() const + { + public_key_data key = serialize(); + uint32_t check = uint32_t(city_hash64(key.data, sizeof(key))); + assert(key.size() + sizeof(check) == 37); + array data; + memcpy(data.data, key.begin(), key.size()); + memcpy(data.begin() + key.size(), (const char*)&check, sizeof(check)); + return fc::to_base58(data.begin(), data.size()); + } + private_key::private_key() {} diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 537706f..a95aae7 100644 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -234,8 +234,13 @@ namespace fc { try { boost::filesystem::rename( boost::filesystem::path(f), boost::filesystem::path(t) ); } catch ( boost::system::system_error& e ) { - FC_THROW( "Rename from ${srcfile} to ${dstfile} failed because ${reason}", - ("srcfile",f)("dstfile",t)("reason",e.what() ) ); + try{ + boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t) ); + boost::filesystem::remove( boost::filesystem::path(f)); + } catch ( boost::system::system_error& e ) { + FC_THROW( "Rename from ${srcfile} to ${dstfile} failed because ${reason}", + ("srcfile",f)("dstfile",t)("reason",e.what() ) ); + } } catch ( ... ) { FC_THROW( "Rename from ${srcfile} to ${dstfile} failed", ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); diff --git a/src/string.cpp b/src/string.cpp index ce79a9c..d09ab2f 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -98,6 +98,10 @@ namespace fc { { return boost::lexical_cast(d); } + fc::string to_string( uint16_t d) + { + return boost::lexical_cast(d); + } std::string trim( const std::string& s ) { std::string cpy(s); diff --git a/src/thread/task.cpp b/src/thread/task.cpp index b963f2c..98edbd3 100644 --- a/src/thread/task.cpp +++ b/src/thread/task.cpp @@ -7,6 +7,11 @@ #include #include +#ifdef _MSC_VER +# include +# include +#endif + namespace fc { task_base::task_base(void* func) : @@ -18,6 +23,17 @@ namespace fc { } void task_base::run() { +#ifdef _MSC_VER + __try { +#endif + run_impl(); +#ifdef _MSC_VER + } __except (get_unhandled_structured_exception_filter() ? get_unhandled_structured_exception_filter()(GetExceptionCode(), GetExceptionInformation()) : EXCEPTION_CONTINUE_SEARCH) { + ExitProcess(1); + } +#endif + } + void task_base::run_impl() { try { _run_functor( _functor, _promise_impl ); } diff --git a/src/thread/thread.cpp b/src/thread/thread.cpp index 0a929eb..3ab54f6 100644 --- a/src/thread/thread.cpp +++ b/src/thread/thread.cpp @@ -381,5 +381,19 @@ namespace fc { return this == ¤t(); } - -} +#ifdef _MSC_VER + /* support for providing a structured exception handler for async tasks */ + namespace detail + { + unhandled_exception_filter_type unhandled_structured_exception_filter = nullptr; + } + void set_unhandled_structured_exception_filter(unhandled_exception_filter_type new_filter) + { + detail::unhandled_structured_exception_filter = new_filter; + } + unhandled_exception_filter_type get_unhandled_structured_exception_filter() + { + return detail::unhandled_structured_exception_filter; + } +#endif // _MSC_VER +} // end namespace fc diff --git a/src/thread/thread_d.hpp b/src/thread/thread_d.hpp index 9a93867..a23d922 100644 --- a/src/thread/thread_d.hpp +++ b/src/thread/thread_d.hpp @@ -430,9 +430,9 @@ namespace fc { else { //ilog( "..." ); - FC_ASSERT( c != current ) //ilog( "ready_push_front" ); - ready_push_front( c ); + if (c != current) + ready_push_front( c ); } } return time_point::min();