diff --git a/CMakeLists.txt b/CMakeLists.txt index 23f984f81..98d643b29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,8 +44,6 @@ message(STATUS "CMake version ${CMAKE_VERSION}") project(graftnetwork) -set(DISABLE_SUPERNODE ${APPLE}) - function (die msg) if (NOT WIN32) string(ASCII 27 Esc) @@ -104,6 +102,38 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}") endif() + +if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + message("==> The configuration is ${CMAKE_BUILD_TYPE}. Debug info will be extracted into separate files.") + + function (add_executable _name) + _add_executable(${ARGV}) + + if (TARGET ${_name}) + add_custom_command(TARGET ${_name} POST_BUILD + COMMAND echo "$: extracting debug info" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" + COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" + ) + endif() + endfunction() + + function (add_library _name _type) + _add_library(${ARGV}) + + if (TARGET ${_name} AND ${_type} STREQUAL SHARED) + add_custom_command(TARGET ${_name} POST_BUILD + COMMAND echo "$: extracting debug info" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --only-keep-debug "$" "$.debug" + COMMAND ${CMAKE_COMMAND} -E chdir $ strip --strip-debug --strip-unneeded "$" + COMMAND ${CMAKE_COMMAND} -E chdir $ objcopy --add-gnu-debuglink="$.debug" "$" + ) + endif() + endfunction() + +endif(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) # ARCH defines the target architecture, either by an explicit identifier or @@ -196,6 +226,21 @@ endif() set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}") +if(NOT DEFINED CMAKE_ROOT_SOURCE_DIR) +# CMAKE_ROOT_SOURCE_DIR variable is required, because CMAKE_SOURCE_DIR works well for include like commands and does not for external projects + set(CMAKE_ROOT_SOURCE_DIR "${CMAKE_SOURCE_DIR}") +endif() + +add_definitions(-DMONERO_DEFAULT_LOG_CATEGORY="cryptonode" -DCMAKE_ROOT_SOURCE_DIR="${CMAKE_ROOT_SOURCE_DIR}") + +if(NOT DEFINED ENABLE_SYSLOG) + option(ENABLE_SYSLOG "SYSLOG support. It can be compiled for UNIX-like platforms only." OFF) +endif() + +if(ENABLE_SYSLOG) + add_definitions(-DELPP_SYSLOG) +endif() + # set this to 0 if per-block checkpoint needs to be disabled set(PER_BLOCK_CHECKPOINT 1) @@ -437,6 +482,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads") endif () +# Handle OpenSSL, used for sha256sum on binary updates if (APPLE AND NOT IOS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default") if (NOT OpenSSL_DIR) @@ -523,6 +569,9 @@ else() set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all") endif() message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}") + if(APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lz") + endif() if(ARCH STREQUAL "default") set(ARCH_FLAG "") elseif(PPC64LE) @@ -882,7 +931,7 @@ endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj") - set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32) + set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt) if(DEPENDS) set(ICU_LIBRARIES ${Boost_LOCALE_LIBRARY} sicuio sicuin sicuuc sicudt sicutu iconv) else() diff --git a/CMakeLists_IOS.txt b/CMakeLists_IOS.txt index 9273af19f..d2e567ade 100644 --- a/CMakeLists_IOS.txt +++ b/CMakeLists_IOS.txt @@ -60,9 +60,23 @@ set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") +set(IOS_BITCODE 1) +set(IOS_BITCODE_MARKER 0) +set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE ${IOS_BITCODE}) +if(IOS_BITCODE) + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") # Without this, Xcode adds -fembed-bitcode-marker compile options instead of -fembed-bitcode set(CMAKE_C_FLAGS "-fembed-bitcode ${CMAKE_C_FLAGS}") +endif() +# ld: '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a(arclite.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture x86_64 + +if(IOS_BITCODE) + set(BITCODE_FLAGS "-fembed-bitcode") +elseif(IOS_BITCODE_MARKER) + set(BITCODE_FLAGS "-fembed-bitcode-marker") +endif() + # Hidden visibilty is required for cxx on iOS -set (CMAKE_C_FLAGS_INIT "") -set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden") +set (CMAKE_C_FLAGS_INIT "${BITCODE_FLAGS}") +set (CMAKE_CXX_FLAGS_INIT "${BITCODE_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") diff --git a/Makefile b/Makefile index 40b8839cc..01db6092e 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,10 @@ debug-static-all: mkdir -p $(builddir)/debug cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE) +debug-static-test: + mkdir -p $(builddir)/debug + cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test + debug-static-win64: mkdir -p $(builddir)/debug cd $(builddir)/debug && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 $(topdir) && $(MAKE) @@ -74,9 +78,23 @@ cmake-release: mkdir -p $(builddir)/release cd $(builddir)/release && cmake -D CMAKE_BUILD_TYPE=Release $(topdir) +cmake-release-syslog: + mkdir -p build/release + cd build/release && cmake -D CMAKE_BUILD_TYPE=Release -D ENABLE_SYSLOG=ON ../.. + +cmake-release-syslog-static: + mkdir -p build/release + cd build/release && cmake -D CMAKE_BUILD_TYPE=Release -D ENABLE_SYSLOG=ON -D STATIC=ON ../.. + release: cmake-release cd $(builddir)/release && $(MAKE) +release-syslog: cmake-release-syslog + cd build/release && $(MAKE) + +release-syslog-static: cmake-release-syslog-static + cd build/release && $(MAKE) + release-test: mkdir -p $(builddir)/release cd $(builddir)/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE) && $(MAKE) test @@ -89,6 +107,10 @@ release-static: mkdir -p $(builddir)/release cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE) +release-static-locking: + mkdir -p build/release + cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) CXX_FLAGS=-DLOCK_RTA_SENDING + coverage: mkdir -p $(builddir)/debug cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON $(topdir) && $(MAKE) && $(MAKE) test @@ -121,6 +143,10 @@ release-static-linux-x86_64: mkdir -p $(builddir)/release cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" $(topdir) && $(MAKE) +release-static-linux-x86_64-debug-info: + mkdir -p build/release + cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=RelWithDebInfo -D BUILD_TAG="linux-x64" ../.. && $(MAKE) + release-static-freebsd-x86_64: mkdir -p $(builddir)/release cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" $(topdir) && $(MAKE) diff --git a/README.md b/README.md index 11d1126d9..1dc44e810 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Graft Network +<<<<<<< HEAD <<<<<<< HEAD Copyright (c) 2017-2018, The Graft Project ||||||| merged common ancestors @@ -7,6 +8,9 @@ Copyright (c) 2017, The Graft Project ======= Copyright (c) 2018, The Graft Project >>>>>>> master +======= +Copyright (c) 2019, The Graft Project +>>>>>>> origin/master ## Monero Fork (Monero version 0.12) @@ -65,11 +69,11 @@ These builds are of the master branch, which is used for active development and ## Introduction -Graft Network is a private, secure, untraceable, decentralised digital currency. You are your bank, you control your funds, and nobody can trace your transfers unless you allow them to do so. +Graft Network is a private, secure, untraceable, decentralized digital cryptocurrency. You are your bank. You control your funds and nobody can trace your transactions unless you allow them to do so. -**Privacy:** Graft Network uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain absolutely private by default. +**Privacy:** Graft Network uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has access to). This ensures that your purchases, receipts, and all transfers remain absolutely private by default. -**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25 word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen. +**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25-word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen. **Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Graft Network is able to ensure that transactions are not only untraceable, but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer. @@ -77,9 +81,9 @@ Graft Network is a private, secure, untraceable, decentralised digital currency. This is the core implementation of Graft Network. It is open source and completely free to use without restrictions, except for those specified in the license agreement below. There are no restrictions on anyone creating an alternative implementation of Graft Network that uses the protocol and network in a compatible manner. -As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability. +As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. Having said that, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability. -**Anyone is welcome to contribute to Graft Network's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request. +**Anyone is welcome to contribute to Graft Network's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase, it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request. ## Supporting the Project @@ -139,10 +143,20 @@ See [Vulnerability Response Process](VULNERABILITY_RESPONSE_PROCESS.md). Graft Network uses a fixed-schedule hard fork mechanism to implement new features. This means that users of Graft Network (end users and service providers) need to run current versions and update their software on a regular schedule. Here is the current schedule, versions, and compatibility. Dates are provided in the format YYYY-MM-DD. +<<<<<<< HEAD | Fork Date | Consensus version | Minimum Graft Network Version | Recommended Graft Network Version | Details | +======= + +| Fork Date | Consensus version | Minimum Graft Network Version | Recommended Graft Network Version | Details | +>>>>>>> origin/master | ----------------- | ----------------- | ---------------------- | -------------------------- | ------------------ | | 2018-01-18 | v7 | 1.0.0 | 1.0.1 | First release | | 2018-04-10 | v8 | 1.1.0 | 1.1.2 | Anti-ASIC change from Monero (Cryptonight variant 1), Improved Difficulty Adjustment Algorithm (new algorithm based on the LWMA difficulty algorithm) | +| 2018-04-23 | v9 | 1.2.0 | 1.2.3 | Fix for Difficulty Adjustment Algorithm | +| 2018-09-17 | v10 | 1.4.4 | 1.4.5 | Block reward halved | +| 2018-10-31 | v11 | 1.5.0 | 1.5.1 | PoW algorithm from Monero v8 (CN v2), enabled checkpoints for mainnet | +| 2019-03-07 | v12 | 1.6.0 | 1.6.0 | Own PoW algorithm - CryptoNight V8 ReverseWaltz - tweaked from CryptoNight Monero v8 (CN v2) | +| 2019-03-20 | v13 | 1.7.4 | 1.7.4 | RTA Mining | <<<<<<< HEAD ## Installing Graft Network from a Package @@ -230,7 +244,13 @@ Approximately three months prior to a scheduled software upgrade, a branch from ### Dependencies +<<<<<<< HEAD The following table summarizes the tools and libraries required to build. A +======= +**Due to gcc 7.3.0 being a hard requirement right now, we strongly recomend to use Ubuntu 18.04 as a build platform** + +The following table summarizes the tools and libraries required to build. A +>>>>>>> origin/master few of the libraries are also included in this repository (marked as "Vendored"). By default, the build uses the library installed on the system, and ignores the vendored sources. However, if no library is found installed on @@ -239,6 +259,7 @@ sources are also used for statically-linked builds because distribution packages often include only shared library binaries (`.so`) but not static library archives (`.a`). +<<<<<<< HEAD | Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Fedora | Optional | Purpose | | ------------ | ------------- | -------- | ------------------ | ------------ | ----------------- | -------- | -------------- | | GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `gcc` | NO | | @@ -259,10 +280,29 @@ library archives (`.a`). | Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation | | Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation | +======= +| Dep | Min. Version | Vendored | Debian/Ubuntu Pkg | Arch Pkg | Optional | Purpose | +| -------------- | ------------- | ---------| ------------------ | -------------- | -------- | -------------- | +| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | NO | | +| CMake | 3.0.0 | NO | `cmake` | `cmake` | NO | | +| pkg-config | any | NO | `pkg-config` | `base-devel` | NO | | +| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | NO | C++ libraries | +| OpenSSL | 1.0.2 | NO | `libssl-dev` | `openssl` | NO | sha256 sum | +| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | NO | DNS resolver | +| libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | YES | NAT punching | +| libunwind | any | NO | `libunwind8-dev` | `libunwind` | YES | Stack traces | +| liblzma | any | NO | `liblzma-dev` | `xz` | YES | For libunwind | +| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | YES | SSL toolkit | +| expat | 1.1 | NO | `libexpat1-dev` | `expat` | YES | XML parsing | +| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | YES | Test suite | +| Doxygen | any | NO | `doxygen` | `doxygen` | YES | Documentation | +| Graphviz | any | NO | `graphviz` | `graphviz` | YES | Documentation | +>>>>>>> origin/master [^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ``` +<<<<<<< HEAD <<<<<<< HEAD ||||||| merged common ancestors ### Cloning the repository @@ -290,6 +330,19 @@ If you already have a repo cloned, initialize and update: `$ cd monero && git submodule init && git submodule update` >>>>>>> 74902419f5946dc01e9b00ad7afad2397eb2efa3 +======= + +### Cloning the repository +Clone recursively to pull-in needed submodule(s): + + git clone --recurse-submodules https://github.com/graft-project/GraftNetwork + +If you already have a repo cloned, initialize and update: + + cd GraftNetwork + + +>>>>>>> origin/master ### Build instructions Graft Network uses the CMake build system and a top-level [Makefile](Makefile) that @@ -300,6 +353,7 @@ invokes cmake commands as needed. * Install the dependencies * Change to the root of the source code directory, change to the most recent release branch, and build: +<<<<<<< HEAD <<<<<<< HEAD cd GraftNetwork ||||||| merged common ancestors @@ -309,6 +363,10 @@ invokes cmake commands as needed. git checkout v0.13.0.4 >>>>>>> 74902419f5946dc01e9b00ad7afad2397eb2efa3 make +======= + cd GraftNetwork + make +>>>>>>> origin/master *Optional*: If your machine has several cores and enough memory, enable parallel build by running `make -j` instead of `make`. For diff --git a/contrib/epee/include/async_state_machine.h b/contrib/epee/include/async_state_machine.h new file mode 100644 index 000000000..4cb6d2ada --- /dev/null +++ b/contrib/epee/include/async_state_machine.h @@ -0,0 +1,151 @@ +#ifndef ASYNC_STATE_MACHINE_H +#define ASYNC_STATE_MACHINE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cblp { + +struct async_callback_state_machine : public boost::enable_shared_from_this +{ + enum call_result_type { + succesed, + failed, + aborted, + timeouted + }; + + typedef boost::function callback_type; + + struct i_task : public boost::enable_shared_from_this + { + virtual void exec() = 0; + virtual ~i_task() {} + + boost::weak_ptr timer; + }; + + virtual bool start() = 0; + + /// \brief creates state machine, it should be shared_ptr + static boost::shared_ptr create(boost::asio::io_service& io_service, + int64_t timeout, + async_callback_state_machine::callback_type finalizer); + + virtual ~async_callback_state_machine(); + +protected: + async_callback_state_machine(boost::asio::io_service& io_service + , int64_t timeout + , async_callback_state_machine::callback_type finalizer); + + static void deadline_handler(const boost::system::error_code& ec, + boost::shared_ptr& machine); + + + boost::asio::io_service& io_service; + boost::asio::io_service::strand strand; + int64_t timeout_msec; + + boost::shared_ptr deadline_timer; + std::set > scheduled_tasks; + std::set> active_timers; + callback_type final_callback; + std::chrono::high_resolution_clock::time_point timestamp; + +public: + /// \brief schedule task to be executed (immediatelly) + /// \param task to execute + void schedule_task(boost::shared_ptr task); + + /// \brief schedule task to be executed in "timeout" milliseconds + /// \param task to execute + /// \param time interval + void schedule_task(boost::shared_ptr task, int timeout); + + /// \brief deactivate already scheduled task + /// \param task to deactivate, could be outside the list + /// of allready scheduled tasks + void unschedule_task(boost::weak_ptr task); + + /// \brief stop machine, deactivate all tasks, stops all timers + void stop(call_result_type result = call_result_type::aborted); + +private: + struct weak_binder final + { + weak_binder(boost::shared_ptr& task + , boost::shared_ptr machine + = boost::shared_ptr() ) + : data(task) + , machine(machine) + {} + + void operator ()() { + if ( boost::shared_ptr ptr = data.lock() ) { + ptr->exec(); + if (boost::shared_ptr tmp = machine.lock()) + tmp->remove_scheduled_task(ptr); + } + } + boost::weak_ptr data; + boost::weak_ptr machine; + }; + + struct timer_binder final + { + timer_binder(boost::shared_ptr& task, + boost::shared_ptr machine, + int64_t timeout_msec) + : data(task) + , machine(machine) + , timer(new boost::asio::deadline_timer(machine->io_service, + boost::posix_time::milliseconds(timeout_msec))) + { + boost::shared_ptr tmp = this->data.lock(); + if (tmp) + tmp->timer = timer; + } + + void operator ()() { + if ( boost::shared_ptr ptr = data.lock() ) { + ptr->exec(); + if (boost::shared_ptr tmp = machine.lock()) + tmp->remove_scheduled_task(ptr); + } + } + + static void timeout_handler(const boost::system::error_code& ec, + boost::shared_ptr& binder) + { + if ( ec == boost::asio::error::operation_aborted ) + return; + (*binder)(); + } + + boost::weak_ptr data; + boost::weak_ptr machine; + boost::shared_ptr timer; + }; + + friend struct weak_binder; + friend struct timer_binder; + + void remove_scheduled_task(boost::shared_ptr& ptr); + + boost::recursive_mutex _mutex; +}; + + +} // namespace cblp + +#endif // ASYNC_STATE_MACHINE_H diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 530f8e636..9087d6837 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -32,20 +32,57 @@ #include "easylogging++.h" +#ifndef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "default" +#endif #define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes #define MAX_LOG_FILES 50 -#define MCFATAL(cat,x) CLOG(FATAL,cat) << x -#define MCERROR(cat,x) CLOG(ERROR,cat) << x -#define MCWARNING(cat,x) CLOG(WARNING,cat) << x -#define MCINFO(cat,x) CLOG(INFO,cat) << x -#define MCDEBUG(cat,x) CLOG(DEBUG,cat) << x -#define MCTRACE(cat,x) CLOG(TRACE,cat) << x +#ifdef __cplusplus +#if __cplusplus >= 201103L + +#define MONERO_LOG_CATEGORY mlog_current_log_category.empty()? MONERO_DEFAULT_LOG_CATEGORY : std::string(mlog_current_log_category.c_str()).c_str() + +// Define MONERO_DEFAULT_LOG_CATEGORY in your unit code to direct logging to +// a category for whole unit. Set mlog_current_log_category to direct logging +// to a particular category, then clear it to switch back to the category that +// is set for the unit. + +extern thread_local std::string mlog_current_log_category; + +#endif //__cplusplus >= 201103L +#endif //__cplusplus + +#ifndef MONERO_LOG_CATEGORY +#define MONERO_LOG_CATEGORY MONERO_DEFAULT_LOG_CATEGORY +#endif + +extern bool mlog_syslog; +#ifdef ELPP_SYSLOG +#define INITIALIZE_SYSLOG(id) ELPP_INITIALIZE_SYSLOG(id, LOG_PID, LOG_USER) + +#define CLOGX(LEVEL,cat) ((mlog_syslog)? CSYSLOG(LEVEL,cat) : CLOG(LEVEL,cat)) +#define MCLOG(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, \ + (mlog_syslog)? el::base::DispatchAction::SysLog : el::base::DispatchAction::NormalLog \ + , cat) << x +#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat, ((mlog_syslog)? "" : "\033[1;" color "m") << x << ((mlog_syslog)? "" : "\033[0m")) +#else //ELPP_SYSLOG +#define INITIALIZE_SYSLOG(id) + +#define CLOGX(LEVEL,cat) CLOG(LEVEL,cat) #define MCLOG(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::NormalLog, cat) << x +#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m") +#endif //ELPP_SYSLOG + +#define MCFATAL(cat,x) CLOGX(FATAL,cat) << x +#define MCERROR(cat,x) CLOGX(ERROR,cat) << x +#define MCWARNING(cat,x) CLOGX(WARNING,cat) << x +#define MCINFO(cat,x) CLOGX(INFO,cat) << x +#define MCDEBUG(cat,x) CLOGX(DEBUG,cat) << x +#define MCTRACE(cat,x) CLOGX(TRACE,cat) << x + #define MCLOG_FILE(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::FileOnlyLog, cat) << x -#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m") #define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x) #define MCLOG_GREEN(level,cat,x) MCLOG_COLOR(level,cat,"32",x) #define MCLOG_YELLOW(level,cat,x) MCLOG_COLOR(level,cat,"33",x) @@ -53,20 +90,20 @@ #define MCLOG_MAGENTA(level,cat,x) MCLOG_COLOR(level,cat,"35",x) #define MCLOG_CYAN(level,cat,x) MCLOG_COLOR(level,cat,"36",x) -#define MLOG_RED(level,x) MCLOG_RED(level,MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG_GREEN(level,x) MCLOG_GREEN(level,MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG_YELLOW(level,x) MCLOG_YELLOW(level,MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG_BLUE(level,x) MCLOG_BLUE(level,MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG_MAGENTA(level,x) MCLOG_MAGENTA(level,MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG_CYAN(level,x) MCLOG_CYAN(level,MONERO_DEFAULT_LOG_CATEGORY,x) - -#define MFATAL(x) MCFATAL(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MERROR(x) MCERROR(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MWARNING(x) MCWARNING(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MINFO(x) MCINFO(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MDEBUG(x) MCDEBUG(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MTRACE(x) MCTRACE(MONERO_DEFAULT_LOG_CATEGORY,x) -#define MLOG(level,x) MCLOG(level,MONERO_DEFAULT_LOG_CATEGORY,x) +#define MLOG_RED(level,x) MCLOG_RED(level,MONERO_LOG_CATEGORY,x) +#define MLOG_GREEN(level,x) MCLOG_GREEN(level,MONERO_LOG_CATEGORY,x) +#define MLOG_YELLOW(level,x) MCLOG_YELLOW(level,MONERO_LOG_CATEGORY,x) +#define MLOG_BLUE(level,x) MCLOG_BLUE(level,MONERO_LOG_CATEGORY,x) +#define MLOG_MAGENTA(level,x) MCLOG_MAGENTA(level,MONERO_LOG_CATEGORY,x) +#define MLOG_CYAN(level,x) MCLOG_CYAN(level,MONERO_LOG_CATEGORY,x) + +#define MFATAL(x) MCFATAL(MONERO_LOG_CATEGORY,x) +#define MERROR(x) MCERROR(MONERO_LOG_CATEGORY,x) +#define MWARNING(x) MCWARNING(MONERO_LOG_CATEGORY,x) +#define MINFO(x) MCINFO(MONERO_LOG_CATEGORY,x) +#define MDEBUG(x) MCDEBUG(MONERO_LOG_CATEGORY,x) +#define MTRACE(x) MCTRACE(MONERO_LOG_CATEGORY,x) +#define MLOG(level,x) MCLOG(level,MONERO_LOG_CATEGORY,x) #define MGINFO(x) MCINFO("global",x) #define MGINFO_RED(x) MCLOG_RED(el::Level::Info, "global",x) @@ -106,7 +143,9 @@ #endif std::string mlog_get_default_log_path(const char *default_filename); -void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE, const std::size_t max_log_files = MAX_LOG_FILES); +// %rfile custom specifier can be used in addition to the Logging Format Specifiers of the Easylogging++ +// %rfile similar to %file but the path is relative to topmost CMakeLists.txt +void mlog_configure(const std::string &filename_base, bool console, const char* format = nullptr, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE, const std::size_t max_log_files = MAX_LOG_FILES); void mlog_set_categories(const char *categories); std::string mlog_get_categories(); void mlog_set_log_level(int level); diff --git a/contrib/epee/include/net/abstract_tcp_server.h b/contrib/epee/include/net/abstract_tcp_server.h deleted file mode 100644 index cbad1717c..000000000 --- a/contrib/epee/include/net/abstract_tcp_server.h +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _ABSTRACT_TCP_SERVER_H_ -#define _ABSTRACT_TCP_SERVER_H_ - -#include -#include -#include -#include "winobj.h" -//#include "threads_helper.h" -#include "net_utils_base.h" - -#pragma comment(lib, "Ws2_32.lib") - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net" - -namespace epee -{ -namespace net_utils -{ - /************************************************************************/ - /* */ - /************************************************************************/ - class soket_sender: public i_service_endpoint - { - public: - soket_sender(SOCKET sock):m_sock(sock){} - private: - virtual bool handle_send(const void* ptr, size_t cb) - { - if(cb != send(m_sock, (char*)ptr, (int)cb, 0)) - { - int sock_err = WSAGetLastError(); - LOG_ERROR("soket_sender: Failed to send " << cb << " bytes, Error=" << sock_err); - return false; - } - return true; - - } - - SOCKET m_sock; - }; - - - - /************************************************************************/ - /* */ - /************************************************************************/ - template - class abstract_tcp_server - { - public: - abstract_tcp_server(); - - bool init_server(int port_no); - bool deinit_server(); - bool run_server(); - bool send_stop_signal(); - - typename THandler::config_type& get_config_object(){return m_config;} - - private: - bool invoke_connection(SOCKET hnew_sock, long ip_from, int post_from); - static unsigned __stdcall ConnectionHandlerProc(void* lpParameter); - - class thread_context; - typedef std::list connections_container; - typedef typename connections_container::iterator connections_iterator; - - struct thread_context - { - HANDLE m_htread; - SOCKET m_socket; - abstract_tcp_server* powner; - connection_context m_context; - typename connections_iterator m_self_it; - }; - - SOCKET m_listen_socket; - int m_port; - bool m_initialized; - volatile LONG m_stop_server; - volatile LONG m_threads_count; - typename THandler::config_type m_config; - connections_container m_connections; - critical_section m_connections_lock; - }; - - template - unsigned __stdcall abstract_tcp_server::ConnectionHandlerProc(void* lpParameter) - { - - thread_context* pthread_context = (thread_context*)lpParameter; - if(!pthread_context) - return 0; - abstract_tcp_server* pthis = pthread_context->powner; - - ::InterlockedIncrement(&pthis->m_threads_count); - - ::CoInitialize(NULL); - - - LOG_PRINT("Handler thread STARTED with socket=" << pthread_context->m_socket, LOG_LEVEL_2); - int res = 0; - - soket_sender sndr(pthread_context->m_socket); - THandler srv(&sndr, pthread_context->powner->m_config, pthread_context->m_context); - - - srv.after_init_connection(); - - char buff[1000] = {0}; - std::string ansver; - while ( (res = recv(pthread_context->m_socket, (char*)buff, 1000, 0)) > 0) - { - LOG_PRINT("Data in, " << res << " bytes", LOG_LEVEL_3); - if(!srv.handle_recv(buff, res)) - break; - } - shutdown(pthread_context->m_socket, SD_BOTH); - closesocket(pthread_context->m_socket); - - abstract_tcp_server* powner = pthread_context->powner; - LOG_PRINT("Handler thread with socket=" << pthread_context->m_socket << " STOPPED", LOG_LEVEL_2); - powner->m_connections_lock.lock(); - ::CloseHandle(pthread_context->m_htread); - pthread_context->powner->m_connections.erase(pthread_context->m_self_it); - powner->m_connections_lock.unlock(); - CoUninitialize(); - ::InterlockedDecrement(&pthis->m_threads_count); - return 1; - } - //---------------------------------------------------------------------------------------- - template - abstract_tcp_server::abstract_tcp_server():m_listen_socket(INVALID_SOCKET), - m_initialized(false), - m_stop_server(0), m_port(0), m_threads_count(0) - { - - } - - //---------------------------------------------------------------------------------------- - template - bool abstract_tcp_server::init_server(int port_no) - { - m_port = port_no; - WSADATA wsad = {0}; - int err = ::WSAStartup(MAKEWORD(2,2), &wsad); - if ( err != 0 || LOBYTE( wsad.wVersion ) != 2 || HIBYTE( wsad.wVersion ) != 2 ) - { - LOG_ERROR("Could not find a usable WinSock DLL, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - m_initialized = true; - - m_listen_socket = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); - if(INVALID_SOCKET == m_listen_socket) - { - err = ::WSAGetLastError(); - LOG_ERROR("Failed to create socket, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - int opt = 1; - setsockopt (m_listen_socket, SOL_SOCKET,SO_REUSEADDR, reinterpret_cast(&opt), sizeof(int)); - - sockaddr_in adr = {0}; - adr.sin_family = AF_INET; - adr.sin_addr.s_addr = htonl(INADDR_ANY); - adr.sin_port = (u_short)htons(port_no); - - err = bind(m_listen_socket, (const sockaddr*)&adr, sizeof(adr )); - if(SOCKET_ERROR == err ) - { - err = ::WSAGetLastError(); - LOG_PRINT("Failed to Bind, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_2); - deinit_server(); - return false; - } - - ::InterlockedExchange(&m_stop_server, 0); - - return true; - } - //---------------------------------------------------------------------------------------- - template - bool abstract_tcp_server::deinit_server() - { - - if(!m_initialized) - return true; - - if(INVALID_SOCKET != m_listen_socket) - { - shutdown(m_listen_socket, SD_BOTH); - int res = closesocket(m_listen_socket); - if(SOCKET_ERROR == res) - { - int err = ::WSAGetLastError(); - LOG_ERROR("Failed to closesocket(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - } - m_listen_socket = INVALID_SOCKET; - } - - int res = ::WSACleanup(); - if(SOCKET_ERROR == res) - { - int err = ::WSAGetLastError(); - LOG_ERROR("Failed to WSACleanup(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - } - m_initialized = false; - - return true; - } - //---------------------------------------------------------------------------------------- - template - bool abstract_tcp_server::send_stop_signal() - { - InterlockedExchange(&m_stop_server, 1); - return true; - } - //---------------------------------------------------------------------------------------- - template - bool abstract_tcp_server::run_server() - { - int err = listen(m_listen_socket, 10000); - if(SOCKET_ERROR == err ) - { - err = ::WSAGetLastError(); - LOG_ERROR("Failed to listen, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - LOG_PRINT("Listening port "<< m_port << "...." , LOG_LEVEL_2); - - while(!m_stop_server) - { - sockaddr_in adr_from = {0}; - int adr_len = sizeof(adr_from); - fd_set read_fs = {0}; - read_fs.fd_count = 1; - read_fs.fd_array[0] = m_listen_socket; - TIMEVAL tv = {0}; - tv.tv_usec = 100; - int select_res = select(0, &read_fs, NULL, NULL, &tv); - if(!select_res) - continue; - SOCKET new_sock = WSAAccept(m_listen_socket, (sockaddr *)&adr_from, &adr_len, NULL, NULL); - LOG_PRINT("Accepted connection on socket=" << new_sock, LOG_LEVEL_2); - invoke_connection(new_sock, adr_from.sin_addr.s_addr, adr_from.sin_port); - } - - deinit_server(); - -#define ABSTR_TCP_SRV_WAIT_COUNT_MAX 5000 -#define ABSTR_TCP_SRV_WAIT_COUNT_INTERVAL 1000 - - int wait_count = 0; - - while(m_threads_count && wait_count*1000 < ABSTR_TCP_SRV_WAIT_COUNT_MAX) - { - ::Sleep(ABSTR_TCP_SRV_WAIT_COUNT_INTERVAL); - wait_count++; - } - LOG_PRINT("abstract_tcp_server exit with wait count=" << wait_count*ABSTR_TCP_SRV_WAIT_COUNT_INTERVAL << "(max=" << ABSTR_TCP_SRV_WAIT_COUNT_MAX <<")", LOG_LEVEL_0); - - return true; - } - //---------------------------------------------------------------------------------------- - template - bool abstract_tcp_server::invoke_connection(SOCKET hnew_sock, const network_address &remote_address) - { - m_connections_lock.lock(); - m_connections.push_back(thread_context()); - m_connections_lock.unlock(); - m_connections.back().m_socket = hnew_sock; - m_connections.back().powner = this; - m_connections.back().m_self_it = --m_connections.end(); - m_connections.back().m_context.m_remote_address = remote_address; - m_connections.back().m_htread = threads_helper::create_thread(ConnectionHandlerProc, &m_connections.back()); // ugh, seems very risky - - return true; - } - //---------------------------------------------------------------------------------------- - - //---------------------------------------------------------------------------------------- - //---------------------------------------------------------------------------------------- -} -} -#endif //_ABSTRACT_TCP_SERVER_H_ diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index b2c05ebb0..b2a7b1700 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -35,6 +35,7 @@ #ifndef _ABSTRACT_TCP_SERVER2_H_ #define _ABSTRACT_TCP_SERVER2_H_ +#include "async_state_machine.h" #include #include @@ -49,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -60,13 +62,15 @@ #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net" -#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000 +#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT (1024) namespace epee { namespace net_utils { + using async_state_machine=cblp::async_callback_state_machine; + struct i_connection_filter { virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address)=0; @@ -79,6 +83,13 @@ namespace net_utils /* */ /************************************************************************/ /// Represents a single connection from a client. +// template +// struct do_send_state_machine; +// template +// struct do_send_chunk_state_machine; + template struct do_send_chunk_state_machine; + + template class connection : public boost::enable_shared_from_this >, @@ -86,6 +97,12 @@ namespace net_utils public i_service_endpoint, public connection_basic { + template friend struct do_send_chunk_state_machine; + +// typedef boost::function Type1; +// typedef boost::shared_ptr callback_type; + typedef boost::shared_ptr> callback_type; + public: typedef typename t_protocol_handler::connection_context t_connection_context; /// Construct a connection with the given io_service. @@ -135,6 +152,9 @@ namespace net_utils /// Handle completion of a write operation. void handle_write(const boost::system::error_code& e, size_t cb); + void handle_write_after_delay1(const boost::system::error_code& e, size_t bytes_sent); + void handle_write_after_delay2(const boost::system::error_code& e, size_t bytes_sent); + /// reset connection timeout timer and callback void reset_timer(boost::posix_time::milliseconds ms, bool add); @@ -146,7 +166,6 @@ namespace net_utils /// Buffer for incoming data. boost::array buffer_; - //boost::array buffer_; t_connection_context context; i_connection_filter* &m_pfilter; @@ -172,9 +191,34 @@ namespace net_utils bool m_local; bool m_ready_to_close; std::string m_host; + std::list> on_write_callback_list; + + public: + void setRpcStation(); + bool add_on_write_callback(std::pair &callback) + { + if (!m_send_que_lock.tryLock()) + return false; + int64_t bytes_in_que = 0; + for (auto entry : m_send_que) + bytes_in_que += entry.size(); + + int64_t bytes_to_wait = bytes_in_que + callback.first; + + for (auto entry : on_write_callback_list) + bytes_to_wait -= entry.first; + + if (bytes_to_wait <= 0) { + m_send_que_lock.unlock(); + return false; + } - public: - void setRpcStation(); + callback.first = bytes_to_wait; + on_write_callback_list.push_back(callback); + m_send_que_lock.unlock(); + return true; + + } }; @@ -266,13 +310,13 @@ namespace net_utils template bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms) - { - boost::shared_ptr ptr(new idle_callback_conext(io_service_, t_callback, timeout_ms)); - //needed call handler here ?... - ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period)); - ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server::global_timer_handler, this, ptr)); - return true; - } + { + boost::shared_ptr ptr(new idle_callback_conext(io_service_, t_callback, timeout_ms)); + //needed call handler here ?... + ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period)); + ptr->m_timer.async_wait(m_strand.wrap(boost::bind(&boosted_tcp_server::global_timer_handler, this, ptr))); + return true; + } bool global_timer_handler(/*const boost::system::error_code& err, */boost::shared_ptr ptr) { @@ -328,11 +372,148 @@ namespace net_utils connection_ptr new_connection_; boost::mutex connections_mutex; - std::set connections_; - + std::deque> connections_; + boost::asio::io_service::strand m_strand; }; // class <>boosted_tcp_server + template + struct do_send_chunk_state_machine : protected async_state_machine + { + static boost::shared_ptr create(boost::asio::io_service &io_service + , int64_t timeout + , async_state_machine::callback_type finalizer + , boost::weak_ptr>& conn + , const void* message + , size_t msg_len + ) + { + boost::shared_ptr ret( + new do_send_chunk_state_machine(io_service, timeout, finalizer, conn, message, msg_len) + ); + + return ret; + } + + void send_result(const boost::system::error_code& ec) + { + if (ec) { + stop(call_result_type::failed); + } + else { + stop(call_result_type::succesed); + } + } + + private: + template friend struct connection_write_task; + + struct connection_write_task : public i_task + { + connection_write_task(boost::shared_ptr machine) + : machine(machine) + {} + + template + /*virtual*/ void exec() + { + boost::shared_ptr mach + = boost::dynamic_pointer_cast>(machine); + boost::shared_ptr> con_ = mach->conn; + con_->m_send_que_lock.lock(); // *** critical *** + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){con_->m_send_que_lock.unlock();}); + + con_->m_send_que.resize(con_->m_send_que.size()+1); + con_->m_send_que.back().assign((const char*)mach->message, mach->length); + typename connection::callback_type callback = boost::bind(&do_send_chunk_state_machine::send_result,mach,_1); + con_->add_on_write_callback(std::pair::callback_type> { mach->length, callback } ); + + if(con_->m_send_que.size() == 1) { + // no active operation + auto size_now = con_->m_send_que.front().size(); + boost::asio::async_write(con_->socket_, boost::asio::buffer(con_->m_send_que.front().data(), size_now ) , + boost::bind(&connection::handle_write, con_, _1, _2) + ); + } + } + + boost::shared_ptr machine; + }; + + + do_send_chunk_state_machine(boost::asio::io_service &io_service + , int64_t timeout + , async_state_machine::callback_type caller + , boost::weak_ptr>& conn + , const void* message + , size_t msg_len + ) + : async_state_machine(io_service, timeout, caller) + , conn(conn) + , message(const_cast(message)) + , length(msg_len) + { + } + + /*virtual*/ bool start() + { + try { + boost::shared_ptr self; + try { + self = async_state_machine::shared_from_this(); + } + catch (boost::bad_weak_ptr& ex) { + return false; + } + catch (...) { + return false; + } + + if(conn->m_was_shutdown) + return false; + + do { + CRITICAL_REGION_LOCAL(conn->m_throttle_speed_out_mutex); + conn->m_throttle_speed_out.handle_trafic_exact(length); + conn->context.m_current_speed_up = conn->m_throttle_speed_out.get_current_speed(); + } while(0); + + conn->context.m_last_send = time(NULL); + conn->context.m_send_cnt += length; + + + boost::shared_ptr send_task(self); + + if (conn->speed_limit_is_enabled()) { + int64_t delay = conn->sleep_before_packet(length); + schedule_task(send_task, delay); + } + else { + schedule_task(send_task); + } + + return true; + } + catch (std::exception& ex) { + (void) ex; + return false; + } + catch (...) { + return false; + } + } + + + boost::shared_ptr> conn; + void * message; + size_t length; + }; // do_send_chunk_state_machine + + + template + using do_send_state_machine = do_send_chunk_state_machine; + + } // namespace } // namespace diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 3a5c83017..c5811012d 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -308,6 +308,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) if (speed_limit_is_enabled()) { +#if 0 do // keep sleeping if we should sleep { { //_scope_dbg1("CRITICAL_REGION_LOCAL"); @@ -322,6 +323,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) boost::this_thread::sleep_for(boost::chrono::milliseconds(ms)); } } while(delay > 0); +#endif } // any form of sleeping //_info("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred); @@ -412,18 +414,29 @@ PRAGMA_WARNING_DISABLE_VS(4355) if (m_was_shutdown) return false; // TODO avoid copy + // I think that author of this was a little drunk, or something else | const double factor = 32; // TODO config typedef long long signed int t_safe; // my t_size to avoid any overunderflow in arithmetic const t_safe chunksize_good = (t_safe)( 1024 * std::max(1.0,factor) ); const t_safe chunksize_max = chunksize_good * 2 ; - const bool allow_split = (m_connection_type == e_connection_type_RPC) ? false : true; // do not split RPC data + /*const */bool allow_split = (m_connection_type == e_connection_type_RPC) ? false : true; // do not split RPC data + CHECK_AND_ASSERT_MES(! (chunksize_max<0), false, "Negative chunksize_max" ); // make sure it is unsigned before removin sign with cast: long long unsigned int chunksize_max_unsigned = static_cast( chunksize_max ) ; + // may be it's better to use "long long long long long long unsigned int" or use multiprecision arithmetics?no? really? + + allow_split = false; // splitting for upload speed control... + // But it's allowed for non RPC connections + // and + // upload speed control turned on ONLY for RPC connections + // So, splitting is meaningless + // * Actually I had turned off RPC connection speed controls, because it hangs io_service threads. if (allow_split && (cb > chunksize_max_unsigned)) { { // LOCK: chunking epee::critical_region_t send_guard(m_chunking_lock); // *** critical *** + // Here we should also lock m_send_que_lock but we've forgotten, haven't we? MDEBUG("do_send() will SPLIT into small chunks, from packet="< ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) - { - retry++; - - /* if ( ::cryptonote::core::get_is_stopping() ) { // TODO re-add fast stop - _fact("ABORT queue wait due to stopping"); - return false; // aborted - }*/ - - long int ms = 250 + (rand()%50); - MDEBUG("Sleeping because QUEUE is FULL, in " << __FUNCTION__ << " for " << ms << " ms before packet_size="< retry_limit) { - MWARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); - shutdown(); - return false; - } + while (m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT) {// Than means that connection too slow, + // 1024 packs maxsize of 64K should be enough + MWARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection"); + self->shutdown(); + return false; } m_send_que.resize(m_send_que.size()+1); @@ -551,27 +546,22 @@ PRAGMA_WARNING_DISABLE_VS(4355) else { // no active operation - if(m_send_que.size()!=1) - { + if(m_send_que.size()!=1) {// It means that we've forgotten protect m_send_que + // by m_send_que_lock somewhere in the code _erro("Looks like no active operations, but send que size != 1!!"); return false; } auto size_now = m_send_que.front().size(); MDEBUG("do_send_chunk() NOW SENSD: packet="<::handle_write, self, _1, _2) - //) +// ) ); - //_dbg3("(chunk): " << size_now); - //logger_handle_net_write(size_now); - //_info("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size()); } //do_send_handler_stop( ptr , cb ); // empty function @@ -706,32 +696,61 @@ PRAGMA_WARNING_DISABLE_VS(4355) } //--------------------------------------------------------------------------------- template - void connection::handle_write(const boost::system::error_code& e, size_t cb) + void connection::handle_write(const boost::system::error_code& e, size_t bytes_sent) { TRY_ENTRY(); - LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << cb); + LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << bytes_sent); + + if (e) { // my crutch + for (auto entry : on_write_callback_list) { // my "crutch" + m_send_que_lock.lock(); + connection::callback_type callback = entry.second; + m_send_que_lock.unlock(); + if (callback) { + (*callback.get())(e); + } + + } + m_send_que_lock.lock(); + on_write_callback_list.clear(); + m_send_que_lock.unlock(); + - if (e) - { _dbg1("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value()); shutdown(); return; } - logger_handle_net_write(cb); +#if 0 // The single sleeping that is needed for correctly handling "out" speed throttling if (speed_limit_is_enabled()) { sleep_before_packet(cb, 1, 1); } +#endif bool do_shutdown = false; + connection::callback_type callback; // my "crutch" CRITICAL_REGION_BEGIN(m_send_que_lock); - if(m_send_que.empty()) + if(m_send_que.empty()) // we've forgotten protect m_send_que by m_send_mutex_lock { _erro("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!"); return; } + if (on_write_callback_list.size()) { // my crutch + std::pair& next_callback = on_write_callback_list.front(); + next_callback.first -= bytes_sent; + int64_t tmp = next_callback.first; + if (tmp <= 0) { + callback = next_callback.second; + on_write_callback_list.pop_front(); + if (on_write_callback_list.size() && tmp < 0) { + std::pair& next_callback = on_write_callback_list.front(); + next_callback.first += tmp; + } + } + } + m_send_que.pop_front(); if(m_send_que.empty()) { @@ -745,25 +764,57 @@ PRAGMA_WARNING_DISABLE_VS(4355) reset_timer(get_default_timeout(), false); auto size_now = m_send_que.front().size(); MDEBUG("handle_write() NOW SENDS: packet="<::handle_write, connection::shared_from_this(), _1, _2) - // ) + ) ); - //_dbg3("(normal)" << size_now); } CRITICAL_REGION_END(); + if (callback) + (*callback.get())(e); + if(do_shutdown) { + boost::system::error_code ec = + boost::system::errc::make_error_code(boost::system::errc::operation_canceled); + for (auto entry : on_write_callback_list) { // my "crutch" + m_send_que_lock.lock(); + connection::callback_type callback = entry.second; + m_send_que_lock.unlock(); + if (callback) + (*callback.get())(ec); + } + m_send_que_lock.lock(); + on_write_callback_list.clear(); + m_send_que_lock.unlock(); + shutdown(); } CATCH_ENTRY_L0("connection::handle_write", void()); } + template + void connection::handle_write_after_delay1(const boost::system::error_code& e, size_t bytes_sent) + { + } + + template + void connection::handle_write_after_delay2(const boost::system::error_code& e, size_t bytes_sent) + { + } + + + //--------------------------------------------------------------------------------- template void connection::setRpcStation() @@ -775,7 +826,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) template bool connection::speed_limit_is_enabled() const { - return m_connection_type != e_connection_type_RPC ; + return m_connection_type != e_connection_type_RPC ; } /************************************************************************/ @@ -792,6 +843,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_pfilter(NULL), m_thread_index(0), m_connection_type( connection_type ), new_connection_() + , m_strand(io_service_) { create_server_type_map(); m_thread_name_prefix = "NET"; @@ -806,6 +858,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_pfilter(NULL), m_thread_index(0), m_connection_type(connection_type), new_connection_() + , m_strand(io_service_) { create_server_type_map(); m_thread_name_prefix = "NET"; @@ -1019,7 +1072,7 @@ POP_WARNINGS connections_mutex.lock(); for (auto &c: connections_) { - c->cancel(); + c.second->cancel(); } connections_.clear(); connections_mutex.unlock(); @@ -1084,10 +1137,18 @@ POP_WARNINGS connection_ptr new_connection_l(new connection(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) ); connections_mutex.lock(); - connections_.insert(new_connection_l); + connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l)); + auto remove_connection = [](std::deque>& connections, const connection_ptr& c) { + for (auto it=connections.begin(); it!=connections.end(); ++it) + if (it->second == c) + { + connections.erase(it); + return; + } + }; MDEBUG("connections_ size now " << connections_.size()); connections_mutex.unlock(); - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); remove_connection(connections_, new_connection_l); }); boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); ////////////////////////////////////////////////////////////////////////// @@ -1175,7 +1236,7 @@ POP_WARNINGS // start adds the connection to the config object's list, so we don't need to have it locally anymore connections_mutex.lock(); - connections_.erase(new_connection_l); + remove_connection(connections_, new_connection_l); connections_mutex.unlock(); bool r = new_connection_l->start(false, 1 < m_threads_count); if (r) @@ -1201,10 +1262,18 @@ POP_WARNINGS TRY_ENTRY(); connection_ptr new_connection_l(new connection(io_service_, m_config, m_sock_count, m_sock_number, m_pfilter, m_connection_type) ); connections_mutex.lock(); - connections_.insert(new_connection_l); + connections_.push_back(std::make_pair(boost::get_system_time(), new_connection_l)); + auto remove_connection = [](std::deque>& connections, const connection_ptr& c) { + for (auto it=connections.begin(); it!=connections.end(); ++it) + if (it->second == c) + { + connections.erase(it); + return; + } + }; MDEBUG("connections_ size now " << connections_.size()); connections_mutex.unlock(); - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); remove_connection(connections_, new_connection_l); }); boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); ////////////////////////////////////////////////////////////////////////// @@ -1264,7 +1333,7 @@ POP_WARNINGS // start adds the connection to the config object's list, so we don't need to have it locally anymore connections_mutex.lock(); - connections_.erase(new_connection_l); + remove_connection(connections_, new_connection_l); connections_mutex.unlock(); bool r = new_connection_l->start(false, 1 < m_threads_count); if (r) diff --git a/contrib/epee/include/net/abstract_tcp_server_cp.h b/contrib/epee/include/net/abstract_tcp_server_cp.h deleted file mode 100644 index f10f4203f..000000000 --- a/contrib/epee/include/net/abstract_tcp_server_cp.h +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _LEVIN_CP_SERVER_H_ -#define _LEVIN_CP_SERVER_H_ - -#include -#include -#include -#include -#include - -#include "misc_log_ex.h" -//#include "threads_helper.h" -#include "syncobj.h" -#define ENABLE_PROFILING -#include "profile_tools.h" -#include "net_utils_base.h" -#include "pragma_comp_defs.h" - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net" - -#define LEVIN_DEFAULT_DATA_BUFF_SIZE 2000 - -namespace epee -{ -namespace net_utils -{ - - template - class cp_server_impl//: public abstract_handler - { - public: - cp_server_impl(/*abstract_handler* phandler = NULL*/); - virtual ~cp_server_impl(); - - bool init_server(int port_no); - bool deinit_server(); - bool run_server(int threads_count = 0); - bool send_stop_signal(); - bool is_stop_signal(); - virtual bool on_net_idle(){return true;} - size_t get_active_connections_num(); - typename TProtocol::config_type& get_config_object(){return m_config;} - private: - enum overlapped_operation_type - { - op_type_recv, - op_type_send, - op_type_stop - }; - - struct io_data_base - { - OVERLAPPED m_overlapped; - WSABUF DataBuf; - overlapped_operation_type m_op_type; - DWORD TotalBuffBytes; - volatile LONG m_is_in_use; - char Buffer[1]; - }; - -PRAGMA_WARNING_PUSH -PRAGMA_WARNING_DISABLE_VS(4355) - template - struct connection: public net_utils::i_service_endpoint - { - connection(typename TProtocol::config_type& ref_config):m_sock(INVALID_SOCKET), m_tprotocol_handler(this, ref_config, context), m_psend_data(NULL), m_precv_data(NULL), m_asked_to_shutdown(0), m_connection_shutwoned(0) - { - } - - //connection():m_sock(INVALID_SOCKET), m_tprotocol_handler(this, m_dummy_config, context), m_psend_data(NULL), m_precv_data(NULL), m_asked_to_shutdown(0), m_connection_shutwoned(0) - //{ - //} - - connection& operator=(const connection& obj) - { - return *this; - } - - bool init_buffers() - { - m_psend_data = (io_data_base*)new char[sizeof(io_data_base) + LEVIN_DEFAULT_DATA_BUFF_SIZE-1]; - m_psend_data->TotalBuffBytes = LEVIN_DEFAULT_DATA_BUFF_SIZE; - m_precv_data = (io_data_base*)new char[sizeof(io_data_base) + LEVIN_DEFAULT_DATA_BUFF_SIZE-1]; - m_precv_data->TotalBuffBytes = LEVIN_DEFAULT_DATA_BUFF_SIZE; - return true; - } - - bool query_shutdown() - { - if(!::InterlockedCompareExchange(&m_asked_to_shutdown, 1, 0)) - { - m_psend_data->m_op_type = op_type_stop; - ::PostQueuedCompletionStatus(m_completion_port, 0, (ULONG_PTR)this, &m_psend_data->m_overlapped); - } - return true; - } - - //bool set_config(typename TProtocol::config_type& config) - //{ - // this->~connection(); - // new(this) connection(config); - // return true; - //} - ~connection() - { - if(m_psend_data) - delete m_psend_data; - - if(m_precv_data) - delete m_precv_data; - } - virtual bool handle_send(const void* ptr, size_t cb) - { - PROFILE_FUNC("[handle_send]"); - if(m_psend_data->TotalBuffBytes < cb) - resize_send_buff((DWORD)cb); - - ZeroMemory(&m_psend_data->m_overlapped, sizeof(OVERLAPPED)); - m_psend_data->DataBuf.len = (u_long)cb;//m_psend_data->TotalBuffBytes; - m_psend_data->DataBuf.buf = m_psend_data->Buffer; - memcpy(m_psend_data->DataBuf.buf, ptr, cb); - m_psend_data->m_op_type = op_type_send; - InterlockedExchange(&m_psend_data->m_is_in_use, 1); - DWORD bytes_sent = 0; - DWORD flags = 0; - int res = 0; - { - PROFILE_FUNC("[handle_send] ::WSASend"); - res = ::WSASend(m_sock, &(m_psend_data->DataBuf), 1, &bytes_sent, flags, &(m_psend_data->m_overlapped), NULL); - } - - if(res == SOCKET_ERROR ) - { - int err = ::WSAGetLastError(); - if(WSA_IO_PENDING == err ) - return true; - } - LOG_ERROR("BIG FAIL: WSASend error code not correct, res=" << res << " last_err=" << err); - ::InterlockedExchange(&m_psend_data->m_is_in_use, 0); - query_shutdown(); - //closesocket(m_psend_data); - return false; - }else if(0 == res) - { - ::InterlockedExchange(&m_psend_data->m_is_in_use, 0); - if(!bytes_sent || bytes_sent != cb) - { - int err = ::WSAGetLastError(); - LOG_ERROR("BIG FAIL: WSASend immediatly complete? but bad results, res=" << res << " last_err=" << err); - query_shutdown(); - return false; - }else - { - return true; - } - } - - return true; - } - bool resize_send_buff(DWORD new_size) - { - if(m_psend_data->TotalBuffBytes >= new_size) - return true; - - delete m_psend_data; - m_psend_data = (io_data_base*)new char[sizeof(io_data_base) + new_size-1]; - m_psend_data->TotalBuffBytes = new_size; - LOG_PRINT("Connection buffer resized up to " << new_size, LOG_LEVEL_3); - return true; - } - - - SOCKET m_sock; - net_utils::connection_context_base context; - TProtocol m_tprotocol_handler; - typename TProtocol::config_type m_dummy_config; - io_data_base* m_precv_data; - io_data_base* m_psend_data; - HANDLE m_completion_port; - volatile LONG m_asked_to_shutdown; - volatile LONG m_connection_shutwoned; - }; -PRAGMA_WARNING_POP - - bool worker_thread_member(); - static unsigned CALLBACK worker_thread(void* param); - - bool add_new_connection(SOCKET new_sock, long ip_from, int port_from); - bool shutdown_connection(connection* pconn); - - - typedef std::map > > connections_container; - SOCKET m_listen_socket; - HANDLE m_completion_port; - connections_container m_connections; - critical_section m_connections_lock; - int m_port; - volatile LONG m_stop; - //abstract_handler* m_phandler; - bool m_initialized; - volatile LONG m_worker_thread_counter; - typename TProtocol::config_type m_config; - }; -} -} -#include "abstract_tcp_server_cp.inl" - - -#endif //_LEVIN_SERVER_H_ diff --git a/contrib/epee/include/net/abstract_tcp_server_cp.inl b/contrib/epee/include/net/abstract_tcp_server_cp.inl deleted file mode 100644 index e0ef6470e..000000000 --- a/contrib/epee/include/net/abstract_tcp_server_cp.inl +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. -// - - -#pragma comment(lib, "Ws2_32.lib") - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net" - -namespace epee -{ -namespace net_utils -{ -template -cp_server_impl::cp_server_impl(): - m_port(0), m_stop(false), - m_worker_thread_counter(0), m_listen_socket(INVALID_SOCKET) -{ -} -//------------------------------------------------------------- -template -cp_server_impl::~cp_server_impl() -{ - deinit_server(); -} -//------------------------------------------------------------- -template -bool cp_server_impl::init_server(int port_no) -{ - m_port = port_no; - - WSADATA wsad = {0}; - int err = ::WSAStartup(MAKEWORD(2,2), &wsad); - if ( err != 0 || LOBYTE( wsad.wVersion ) != 2 || HIBYTE( wsad.wVersion ) != 2 ) - { - LOG_ERROR("Could not find a usable WinSock DLL, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - m_initialized = true; - - m_listen_socket = ::WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); - if(INVALID_SOCKET == m_listen_socket) - { - err = ::WSAGetLastError(); - LOG_ERROR("Failed to create socket, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - - int opt = 1; - err = setsockopt (m_listen_socket, SOL_SOCKET,SO_REUSEADDR, reinterpret_cast(&opt), sizeof(int)); - if(SOCKET_ERROR == err ) - { - err = ::WSAGetLastError(); - LOG_PRINT("Failed to setsockopt(SO_REUSEADDR), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_1); - deinit_server(); - return false; - } - - - sockaddr_in adr = {0}; - adr.sin_family = AF_INET; - adr.sin_addr.s_addr = htonl(INADDR_ANY); - adr.sin_port = (u_short)htons(m_port); - - //binding - err = bind(m_listen_socket, (const sockaddr*)&adr, sizeof(adr )); - if(SOCKET_ERROR == err ) - { - err = ::WSAGetLastError(); - LOG_PRINT("Failed to Bind, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_1); - deinit_server(); - return false; - } - - - m_completion_port = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); - if(INVALID_HANDLE_VALUE == m_completion_port) - { - err = ::WSAGetLastError(); - LOG_PRINT("Failed to CreateIoCompletionPort, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_1); - deinit_server(); - return false; - } - - - return true; -} -//------------------------------------------------------------- - -//------------------------------------------------------------- -static int CALLBACK CPConditionFunc( - IN LPWSABUF lpCallerId, - IN LPWSABUF lpCallerData, - IN OUT LPQOS lpSQOS, - IN OUT LPQOS lpGQOS, - IN LPWSABUF lpCalleeId, - OUT LPWSABUF lpCalleeData, - OUT GROUP FAR *g, - IN DWORD_PTR dwCallbackData - ) -{ - - /*cp_server_impl* pthis = (cp_server_impl*)dwCallbackData; - if(!pthis) - return CF_REJECT;*/ - /*if(pthis->get_active_connections_num()>=FD_SETSIZE-1) - { - LOG_PRINT("Maximum connections count overfull.", LOG_LEVEL_2); - return CF_REJECT; - }*/ - - return CF_ACCEPT; -} -//------------------------------------------------------------- -template -size_t cp_server_impl::get_active_connections_num() -{ - return m_connections.size(); -} -//------------------------------------------------------------- -template -unsigned CALLBACK cp_server_impl::worker_thread(void* param) -{ - if(!param) - return 0; - - cp_server_impl* pthis = (cp_server_impl*)param; - pthis->worker_thread_member(); - return 1; -} -//------------------------------------------------------------- -template -bool cp_server_impl::worker_thread_member() -{ - LOG_PRINT("Worker thread STARTED", LOG_LEVEL_1); - bool stop_handling = false; - while(!stop_handling) - { - PROFILE_FUNC("[worker_thread]Worker Loop"); - DWORD bytes_transfered = 0; - connection* pconnection = 0; - io_data_base* pio_data = 0; - - { - PROFILE_FUNC("[worker_thread]GetQueuedCompletionStatus"); - BOOL res = ::GetQueuedCompletionStatus (m_completion_port, &bytes_transfered , (PULONG_PTR)&pconnection, (LPOVERLAPPED *)&pio_data, INFINITE); - if (res == 0) - { - // check return code for error - int err = GetLastError(); - LOG_PRINT("GetQueuedCompletionStatus failed with error " << err << " " << log_space::get_win32_err_descr(err), LOG_LEVEL_1); - - if(pio_data) - ::InterlockedExchange(&pio_data->m_is_in_use, 0); - - - continue; - } - } - - if(pio_data) - ::InterlockedExchange(&pio_data->m_is_in_use, 0); - - - - if(!bytes_transfered && !pconnection && !pio_data) - { - //signal to stop - break; - } - if(!pconnection || !pio_data) - { - LOG_PRINT("BIG FAIL: pconnection or pio_data is empty: pconnection=" << pconnection << " pio_data=" << pio_data, LOG_LEVEL_0); - break; - } - - - - if(::InterlockedCompareExchange(&pconnection->m_connection_shutwoned, 0, 0)) - { - LOG_ERROR("InterlockedCompareExchange(&pconnection->m_connection_shutwoned, 0, 0)"); - //DebugBreak(); - } - - if(pio_data->m_op_type == op_type_stop) - { - if(!pconnection) - { - LOG_ERROR("op_type=op_type_stop, but pconnection is empty!!!"); - continue; - } - shutdown_connection(pconnection); - continue;// - } - else if(pio_data->m_op_type == op_type_send) - { - continue; - //do nothing, just queuing request - }else if(pio_data->m_op_type == op_type_recv) - { - PROFILE_FUNC("[worker_thread]m_tprotocol_handler.handle_recv"); - if(bytes_transfered) - { - bool res = pconnection->m_tprotocol_handler.handle_recv(pio_data->Buffer, bytes_transfered); - if(!res) - pconnection->query_shutdown(); - } - else - { - pconnection->query_shutdown(); - continue; - } - - } - - //preparing new request, - - { - PROFILE_FUNC("[worker_thread]RECV Request small loop"); - int res = 0; - while(true) - { - LOG_PRINT("Prepearing data for WSARecv....", LOG_LEVEL_3); - ZeroMemory(&pio_data->m_overlapped, sizeof(OVERLAPPED)); - pio_data->DataBuf.len = pio_data->TotalBuffBytes; - pio_data->DataBuf.buf = pio_data->Buffer; - pio_data->m_op_type = op_type_recv; - //calling WSARecv() and go to completion waiting - DWORD bytes_recvd = 0; - DWORD flags = 0; - - LOG_PRINT("Calling WSARecv....", LOG_LEVEL_3); - ::InterlockedExchange(&pio_data->m_is_in_use, 1); - res = WSARecv(pconnection->m_sock, &(pio_data->DataBuf), 1, &bytes_recvd , &flags, &(pio_data->m_overlapped), NULL); - if(res == SOCKET_ERROR ) - { - int err = ::WSAGetLastError(); - if(WSA_IO_PENDING == err ) - {//go pending, ok - LOG_PRINT("WSARecv return WSA_IO_PENDING", LOG_LEVEL_3); - break; - } - LOG_ERROR("BIG FAIL: WSARecv error code not correct, res=" << res << " last_err=" << err); - ::InterlockedExchange(&pio_data->m_is_in_use, 0); - pconnection->query_shutdown(); - break; - } - break; - /*else if(0 == res) - { - if(!bytes_recvd) - { - ::InterlockedExchange(&pio_data->m_is_in_use, 0); - LOG_PRINT("WSARecv return 0, bytes_recvd=0, graceful close.", LOG_LEVEL_3); - int err = ::WSAGetLastError(); - //LOG_ERROR("BIG FAIL: WSARecv error code not correct, res=" << res << " last_err=" << err); - //pconnection->query_shutdown(); - break; - }else - { - LOG_PRINT("WSARecv return immediatily 0, bytes_recvd=" << bytes_recvd, LOG_LEVEL_3); - //pconnection->m_tprotocol_handler.handle_recv(pio_data->Buffer, bytes_recvd); - } - }*/ - } - } - } - - - LOG_PRINT("Worker thread STOPED", LOG_LEVEL_1); - ::InterlockedDecrement(&m_worker_thread_counter); - return true; -} -//------------------------------------------------------------- -template -bool cp_server_impl::shutdown_connection(connection* pconn) -{ - PROFILE_FUNC("[shutdown_connection]"); - - if(!pconn) - { - LOG_ERROR("Attempt to remove null pptr connection!"); - return false; - } - else - { - LOG_PRINT("Shutting down connection ("<< pconn << ")", LOG_LEVEL_3); - } - m_connections_lock.lock(); - connections_container::iterator it = m_connections.find(pconn->m_sock); - m_connections_lock.unlock(); - if(it == m_connections.end()) - { - LOG_ERROR("Failed to find closing socket=" << pconn->m_sock); - return false; - } - SOCKET sock = it->second->m_sock; - { - PROFILE_FUNC("[shutdown_connection] shutdown, close"); - ::shutdown(it->second->m_sock, SD_SEND ); - } - size_t close_sock_wait_count = 0; - { - LOG_PRINT("Entered to 'in_use wait zone'", LOG_LEVEL_3); - PROFILE_FUNC("[shutdown_connection] wait for in_use"); - while(::InterlockedCompareExchange(&it->second->m_precv_data->m_is_in_use, 1, 1)) - { - - Sleep(100); - close_sock_wait_count++; - } - LOG_PRINT("First step to 'in_use wait zone'", LOG_LEVEL_3); - - - while(::InterlockedCompareExchange(&it->second->m_psend_data->m_is_in_use, 1, 1)) - { - Sleep(100); - close_sock_wait_count++; - } - LOG_PRINT("Leaved 'in_use wait zone'", LOG_LEVEL_3); - } - - ::closesocket(it->second->m_sock); - - ::InterlockedExchange(&it->second->m_connection_shutwoned, 1); - m_connections_lock.lock(); - m_connections.erase(it); - m_connections_lock.unlock(); - LOG_PRINT("Socked " << sock << " closed, wait_count=" << close_sock_wait_count, LOG_LEVEL_2); - return true; -} -//------------------------------------------------------------- -template -bool cp_server_impl::run_server(int threads_count = 0) -{ - int err = listen(m_listen_socket, 100); - if(SOCKET_ERROR == err ) - { - err = ::WSAGetLastError(); - LOG_ERROR("Failed to listen, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - - if(!threads_count) - { - SYSTEM_INFO si = {0}; - ::GetSystemInfo(&si); - threads_count = si.dwNumberOfProcessors + 2; - } - for(int i = 0; i != threads_count; i++) - { - boost::thread(boost::bind(&cp_server_impl::worker_thread_member, this)); - //HANDLE h_thread = threads_helper::create_thread(worker_thread, this); - InterlockedIncrement(&m_worker_thread_counter); - //::CloseHandle(h_thread); - } - - LOG_PRINT("Numbers of worker threads started: " << threads_count, LOG_LEVEL_1); - - m_stop = false; - while(!m_stop) - { - PROFILE_FUNC("[run_server] main_loop"); - TIMEVAL tv = {0}; - tv.tv_sec = 0; - tv.tv_usec = 100; - fd_set sock_set; - sock_set.fd_count = 1; - sock_set.fd_array[0] = m_listen_socket; - int select_res = 0; - { - PROFILE_FUNC("[run_server] select"); - select_res = select(0, &sock_set, &sock_set, NULL, &tv); - } - - if(SOCKET_ERROR == select_res) - { - err = ::WSAGetLastError(); - LOG_ERROR("Failed to select, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - return false; - } - if(!select_res) - { - on_net_idle(); - continue; - } - else - { - sockaddr_in adr_from = {0}; - int adr_len = sizeof(adr_from); - SOCKET new_sock = INVALID_SOCKET; - { - PROFILE_FUNC("[run_server] WSAAccept"); - new_sock = ::WSAAccept(m_listen_socket, (sockaddr *)&adr_from, &adr_len, CPConditionFunc, (DWORD_PTR)this); - } - - if(INVALID_SOCKET == new_sock) - { - if(m_stop) - break; - int err = ::WSAGetLastError(); - LOG_PRINT("Failed to WSAAccept, err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_2); - continue; - } - LOG_PRINT("Accepted connection (new socket=" << new_sock << ")", LOG_LEVEL_2); - { - PROFILE_FUNC("[run_server] Add new connection"); - add_new_connection(new_sock, adr_from.sin_addr.s_addr, adr_from.sin_port); - } - - } - - } - LOG_PRINT("Closing connections("<< m_connections.size() << ") and waiting...", LOG_LEVEL_2); - m_connections_lock.lock(); - for(connections_container::iterator it = m_connections.begin(); it != m_connections.end(); it++) - { - ::shutdown(it->second->m_sock, SD_BOTH); - ::closesocket(it->second->m_sock); - } - m_connections_lock.unlock(); - size_t wait_count = 0; - while(m_connections.size() && wait_count < 100) - { - ::Sleep(100); - wait_count++; - } - LOG_PRINT("Connections closed OK (wait_count=" << wait_count << ")", LOG_LEVEL_2); - - - LOG_PRINT("Stopping worker threads("<< m_worker_thread_counter << ").", LOG_LEVEL_2); - for(int i = 0; i > ptr; - ptr.reset(new connection(m_config)); - - connection& conn = *ptr.get(); - m_connections[new_sock] = ptr; - LOG_PRINT("Add new connection zone: leaving lock", LOG_LEVEL_3); - m_connections_lock.unlock(); - conn.init_buffers(); - conn.m_sock = new_sock; - conn.context.m_remote_address = address_from; - conn.m_completion_port = m_completion_port; - { - PROFILE_FUNC("[add_new_connection] CreateIoCompletionPort"); - ::CreateIoCompletionPort((HANDLE)new_sock, m_completion_port, (ULONG_PTR)&conn, 0); - } - - //if(NULL == ::CreateIoCompletionPort((HANDLE)new_sock, m_completion_port, (ULONG_PTR)&conn, 0)) - //{ - // int err = ::GetLastError(); - // LOG_PRINT("Failed to CreateIoCompletionPort(associate socket and completion port), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"", LOG_LEVEL_2); - // return false; - //} - - conn.m_tprotocol_handler.after_init_connection(); - { - PROFILE_FUNC("[add_new_connection] starting loop"); - int res = 0; - while(true)//res!=SOCKET_ERROR) - { - PROFILE_FUNC("[add_new_connection] in loop time"); - conn.m_precv_data->TotalBuffBytes = LEVIN_DEFAULT_DATA_BUFF_SIZE; - ZeroMemory(&conn.m_precv_data->m_overlapped, sizeof(OVERLAPPED)); - conn.m_precv_data->DataBuf.len = conn.m_precv_data->TotalBuffBytes; - conn.m_precv_data->DataBuf.buf = conn.m_precv_data->Buffer; - conn.m_precv_data->m_op_type = op_type_recv; - InterlockedExchange(&conn.m_precv_data->m_is_in_use, 1); - DWORD bytes_recvd = 0; - DWORD flags = 0; - - ::InterlockedExchange(&conn.m_precv_data->m_is_in_use, 1); - { - PROFILE_FUNC("[add_new_connection] ::WSARecv"); - res = ::WSARecv(conn.m_sock, &(conn.m_precv_data->DataBuf), 1, &bytes_recvd , &flags, &(conn.m_precv_data->m_overlapped), NULL); - } - if(res == SOCKET_ERROR ) - { - int err = ::WSAGetLastError(); - if(WSA_IO_PENDING == err ) - { - break; - } - LOG_ERROR("BIG FAIL: WSARecv error code not correct, res=" << res << " last_err=" << err << " " << log_space::get_win32_err_descr(err)); - ::InterlockedExchange(&conn.m_precv_data->m_is_in_use, 0); - conn.query_shutdown(); - //shutdown_connection(&conn); - break; - } - - - break; - /*else if(0 == res) - { - if(!bytes_recvd) - { - PROFILE_FUNC("[add_new_connection] shutdown_connection"); - ::InterlockedExchange(&conn.m_precv_data->m_is_in_use, 0); - conn.query_shutdown(); - //shutdown_connection(&conn); - break; - }else - { - PROFILE_FUNC("[add_new_connection] handle_recv"); - } - }*/ - } - } - - - - return true; -} -//------------------------------------------------------------- -template -bool cp_server_impl::deinit_server() -{ - if(!m_initialized) - return true; - - if(INVALID_SOCKET != m_listen_socket) - { - shutdown(m_listen_socket, SD_BOTH); - int res = closesocket(m_listen_socket); - if(SOCKET_ERROR == res) - { - int err = ::WSAGetLastError(); - LOG_ERROR("Failed to closesocket(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - } - m_listen_socket = INVALID_SOCKET; - } - - int res = ::WSACleanup(); - if(SOCKET_ERROR == res) - { - int err = ::WSAGetLastError(); - LOG_ERROR("Failed to WSACleanup(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\""); - } - m_initialized = false; - - return true; -} - -//------------------------------------------------------------- -template -bool cp_server_impl::send_stop_signal() -{ - ::InterlockedExchange(&m_stop, 1); - return true; -} -//------------------------------------------------------------- -template -bool cp_server_impl::is_stop_signal() -{ - return m_stop?true:false; -} -//------------------------------------------------------------- -} -} diff --git a/contrib/epee/include/net/connection_basic.hpp b/contrib/epee/include/net/connection_basic.hpp index 095e747a5..1a4054abc 100644 --- a/contrib/epee/include/net/connection_basic.hpp +++ b/contrib/epee/include/net/connection_basic.hpp @@ -126,8 +126,10 @@ class connection_basic { // not-templated base class for rapid developmet of som static int get_tos_flag(); // handlers and sleep - void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) - static void save_limit_to_file(int limit); ///< for dr-monero + void sleep_before_packet(size_t packet_size, int phase, int q_len); // execute a sleep ; phase is not really used now(?) + int64_t sleep_before_packet(size_t packet_size); // returns delay to limit traffic + void update_traffic_limits(size_t packet_size); // updates current traffic measurements? + static void save_limit_to_file(int limit); ///< for dr-monero static double get_sleep_time(size_t cb); static void set_save_graph(bool save_graph); diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index 35c68a7a5..60e3a2543 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -234,8 +234,521 @@ namespace net_utils - namespace http - { + namespace http + { + +// class http_recved_data_handler : public boost::enable_shared_from_this, public i_target_handler +// { +// enum reciev_machine_state { +// reciev_machine_state_header, +// reciev_machine_state_body_content_len, +// reciev_machine_state_body_connection_close, +// reciev_machine_state_body_chunked, +// reciev_machine_state_done, +// reciev_machine_state_error +// }; + +// enum chunked_state{ +// http_chunked_state_chunk_head, +// http_chunked_state_chunk_body, +// http_chunked_state_done, +// http_chunked_state_undefined +// }; + +// public: +// static boost::shared_ptr create() { +// return boost::shared_ptr(new http_recved_data_handler); +// } + +// bool operator ()(void * data, size_t len, std::string outbuff) +// { +// std::string recv_buffer; +// recv_buffer.append(static_cast(data), len); +// while(keep_handling) +// { +// switch(m_state) +// { +// case reciev_machine_state_header: +// keep_handling = handle_header(recv_buffer, need_more_data); +// break; +// case reciev_machine_state_body_content_len: +// keep_handling = handle_body_content_len(recv_buffer, need_more_data); +// break; +// case reciev_machine_state_body_connection_close: +// keep_handling = handle_body_connection_close(recv_buffer, need_more_data); +// break; +// case reciev_machine_state_body_chunked: +// keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); +// break; +// case reciev_machine_state_done: +// keep_handling = false; +// break; +// case reciev_machine_state_error: +// keep_handling = false; +// break; +// } +// } + +// if (m_state == reciev_machine_state_done) { +// return true; +// } +// else if (m_state == reciev_machine_state_error) { +// throw std::exception(); +// } +// else { +// return false; +// } +// } + +// private: +// http_recved_data_handler() +// : keep_handling(true) +// , need_more_data(true) +// , m_state(reciev_machine_state_header) +// {} + +// //--------------------------------------------------------------------------- +// bool handle_header(std::string& recv_buff, bool& need_more_data) +// { +// m_header_cache += recv_buff; +// recv_buff.clear(); +// std::string::size_type pos = m_header_cache.find("\r\n\r\n"); +// if(pos != std::string::npos) +// { +// recv_buff.assign(m_header_cache.begin()+pos+4, m_header_cache.end()); +// m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end()); + +// analize_cached_header_and_invoke_state(); +// m_header_cache.clear(); +// if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) +// need_more_data = true; + +// return true; +// } +// else +// need_more_data = true; +// return true; +// } +// //--------------------------------------------------------------------------- +// bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) +// { +// if(!recv_buff.size()) +// { +// MERROR("Warning: Content-Len mode, but connection unexpectedly closed"); +// m_state = reciev_machine_state_done; +// return true; +// } +// CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); +// m_len_in_remain -= recv_buff.size(); +// if (!m_pcontent_encoding_handler->update_in(recv_buff)) +// { +// m_state = reciev_machine_state_done; +// return false; +// } + +// if(m_len_in_remain == 0) +// m_state = reciev_machine_state_done; +// else +// need_more_data = true; + +// return true; +// } +// //--------------------------------------------------------------------------- +// bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) +// { +// if(!recv_buff.size()) +// { +// m_state = reciev_machine_state_done; +// return true; +// } +// need_more_data = true; +// m_pcontent_encoding_handler->update_in(recv_buff); + + +// return true; +// } +// //--------------------------------------------------------------------------- +// bool is_hex_symbol(char ch) +// { +// if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f')) +// return true; +// else +// return false; +// } +// //--------------------------------------------------------------------------- +// bool get_len_from_chunk_head(const std::string &chunk_head, size_t& result_size) +// { +// std::stringstream str_stream; +// str_stream << std::hex; +// if(!(str_stream << chunk_head && str_stream >> result_size)) +// return false; + +// return true; +// } +// //--------------------------------------------------------------------------- +// bool get_chunk_head(std::string& buff, size_t& chunk_size, bool& is_matched) +// { +// is_matched = false; +// size_t offset = 0; +// for(std::string::iterator it = buff.begin(); it!= buff.end(); it++, offset++) +// { +// if(!is_hex_symbol(*it)) +// { +// if(*it == '\r' || *it == ' ' ) +// { +// offset--; +// continue; +// } +// else if(*it == '\n') +// { +// std::string chunk_head = buff.substr(0, offset); +// if(!get_len_from_chunk_head(chunk_head, chunk_size)) +// return false; + +// if(0 == chunk_size) +// { +// //Here is a small confusion +// //In brief - if the chunk is the last one we need to get terminating sequence +// //along with the cipher, generally in the "ddd\r\n\r\n" form + +// for(it++;it != buff.end(); it++) +// { +// if('\r' == *it) +// continue; +// else if('\n' == *it) +// break; +// else +// { +// LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); +// return false; +// } +// } + +// if(it == buff.end()) +// return true; +// } + +// buff.erase(buff.begin(), ++it); + +// is_matched = true; +// return true; +// } +// else +// return false; +// } +// } + +// return true; +// } +// //--------------------------------------------------------------------------- +// bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) +// { +// if(!recv_buff.size()) +// { +// MERROR("Warning: CHUNKED mode, but connection unexpectedly closed"); +// m_state = reciev_machine_state_done; +// return true; +// } +// m_chunked_cache += recv_buff; +// recv_buff.clear(); +// bool is_matched = false; + +// while(true) +// { +// if(!m_chunked_cache.size()) +// { +// need_more_data = true; +// break; +// } + +// switch(m_chunked_state) +// { +// case http_chunked_state_chunk_head: +// if(m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') +// { +// //optimize a bit +// if(m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') +// m_chunked_cache.erase(0, 2); +// else +// m_chunked_cache.erase(0, 1); +// break; +// } +// if(!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) +// { +// LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); +// m_state = reciev_machine_state_error; +// return false; +// } + +// if(!is_matched) +// { +// need_more_data = true; +// return true; +// }else +// { +// m_chunked_state = http_chunked_state_chunk_body; +// if(m_len_in_remain == 0) +// {//last chunk, let stop the stream and fix the chunk queue. +// m_state = reciev_machine_state_done; +// return true; +// } +// m_chunked_state = http_chunked_state_chunk_body; +// break; +// } +// break; +// case http_chunked_state_chunk_body: +// { +// std::string chunk_body; +// if(m_len_in_remain >= m_chunked_cache.size()) +// { +// m_len_in_remain -= m_chunked_cache.size(); +// chunk_body.swap(m_chunked_cache); +// }else +// { +// chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); +// m_chunked_cache.erase(0, m_len_in_remain); +// m_len_in_remain = 0; +// } + +// if (!m_pcontent_encoding_handler->update_in(chunk_body)) +// { +// m_state = reciev_machine_state_error; +// return false; +// } + +// if(!m_len_in_remain) +// m_chunked_state = http_chunked_state_chunk_head; +// } +// break; +// case http_chunked_state_done: +// m_state = reciev_machine_state_done; +// return true; +// case http_chunked_state_undefined: +// default: +// LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); +// return false; +// } +// } + +// return true; +// } +// //--------------------------------------------------------------------------- + +// bool analize_cached_header_and_invoke_state() +// { +// m_response_info.clear(); +// analize_first_response_line(); +// std::string fake_str; //gcc error workaround + +// bool res = parse_header(m_response_info.m_header_info, m_header_cache); +// CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); + +// set_reply_content_encoder(); + +// m_len_in_summary = 0; +// bool content_len_valid = false; +// if(m_response_info.m_header_info.m_content_length.size()) +// content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); + +// if(!m_len_in_summary && ((m_response_info.m_response_code>=100&&m_response_info.m_response_code<200) +// || 204 == m_response_info.m_response_code +// || 304 == m_response_info.m_response_code) ) {//There will be no response body, server will display the local page with error +// m_state = reciev_machine_state_done; +// return true; +// } +// else if(m_response_info.m_header_info.m_transfer_encoding.size()) { +// string_tools::trim(m_response_info.m_header_info.m_transfer_encoding); +// if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked")) { +// LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding); +// m_state = reciev_machine_state_error; +// return false; +// } +// m_state = reciev_machine_state_body_chunked; +// m_chunked_state = http_chunked_state_chunk_head; +// return true; +// } +// else if(!m_response_info.m_header_info.m_content_length.empty()) { +// //In the response header the length was specified +// if(!content_len_valid) { +// LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<(result[1]); +// m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); +// m_response_info.m_response_code = boost::lexical_cast(result[3]); + +// m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); +// return true; +// } +// else { +// LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); +// return false; +// } +// } + +// bool set_reply_content_encoder() +// { +// STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); +// boost::smatch result; // 12 3 +// if(boost::regex_search( m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) { +// m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); +// LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); +// return false; +// } +// else { +// m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); +// } + +// return true; +// } + +// bool is_multipart_body(const http_header_info& head_info, OUT std::string& boundary) +// { +// //Check whether this is multi part - if yes, capture boundary immediately +// STATIC_REGEXP_EXPR_1(rexp_match_multipart_type, "^\\s*multipart/([\\w\\-]+); boundary=((\"(.*?)\")|(\\\\\"(.*?)\\\\\")|([^\\s;]*))", boost::regex::icase | boost::regex::normal); +// boost::smatch result; +// if(boost::regex_search(head_info.m_content_type, result, rexp_match_multipart_type, boost::match_default) && result[0].matched) +// { +// if(result[4].matched) +// boundary = result[4]; +// else if(result[6].matched) +// boundary = result[6]; +// else if(result[7].matched) +// boundary = result[7]; +// else +// { +// LOG_ERROR("Failed to match boundary in content-type=" << head_info.m_content_type); +// return false; +// } +// return true; +// } +// else +// return false; + +// return true; +// } + +// /*virtual*/ bool handle_target_data(std::string& piece_of_transfer) +// { +// m_response_info.m_body += piece_of_transfer; +// piece_of_transfer.clear(); +// return true; +// } + + +// bool keep_handling; +// bool need_more_data; +// std::string m_header_cache; +// http_response_info m_response_info; +// size_t m_len_in_summary; +// size_t m_len_in_remain; +// boost::shared_ptr m_pcontent_encoding_handler; +// reciev_machine_state m_state; +// chunked_state m_chunked_state; +// std::string m_chunked_cache; +// }; // class http_recved_data_handler + template class http_simple_client_template: public i_target_handler @@ -278,9 +791,9 @@ namespace net_utils bool m_ssl; public: - explicit http_simple_client_template() + explicit http_simple_client_template(boost::shared_ptr ios = boost::shared_ptr(new boost::asio::io_service())) : i_target_handler() - , m_net_client() + , m_net_client(ios) , m_host_buff() , m_port() , m_auth() @@ -451,60 +964,60 @@ namespace net_utils std::string recv_buffer; while(keep_handling) { - if(need_more_data) + if(need_more_data) + { + if(!m_net_client.recv(recv_buffer, timeout)) + { + MERROR("Unexpected recv fail"); + m_state = reciev_machine_state_error; + } + if(!recv_buffer.size()) + { + //connection is going to be closed + if(reciev_machine_state_body_connection_close != m_state) { - if(!m_net_client.recv(recv_buffer, timeout)) - { - MERROR("Unexpected recv fail"); - m_state = reciev_machine_state_error; - } - if(!recv_buffer.size()) - { - //connection is going to be closed - if(reciev_machine_state_body_connection_close != m_state) - { - m_state = reciev_machine_state_error; - } - } - need_more_data = false; + m_state = reciev_machine_state_error; } - switch(m_state) - { - case reciev_machine_state_header: - keep_handling = handle_header(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_content_len: - keep_handling = handle_body_content_len(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_connection_close: - keep_handling = handle_body_connection_close(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_chunked: - keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); - break; - case reciev_machine_state_done: - keep_handling = false; - break; - case reciev_machine_state_error: - keep_handling = false; - break; - } - + } + need_more_data = false; } - m_header_cache.clear(); - if(m_state != reciev_machine_state_error) + switch(m_state) { - if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) - disconnect(); - - return true; + case reciev_machine_state_header: + keep_handling = handle_header(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_content_len: + keep_handling = handle_body_content_len(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_connection_close: + keep_handling = handle_body_connection_close(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_chunked: + keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); + break; + case reciev_machine_state_done: + keep_handling = false; + break; + case reciev_machine_state_error: + keep_handling = false; + break; } - else + + } + m_header_cache.clear(); + if(m_state != reciev_machine_state_error) + { + if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) + disconnect(); + + return true; + } + else { - LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); - return false; + LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); + return false; } - } + } //--------------------------------------------------------------------------- inline bool handle_header(std::string& recv_buff, bool& need_more_data) diff --git a/contrib/epee/include/net/http_client_via_api_helper.h b/contrib/epee/include/net/http_client_via_api_helper.h deleted file mode 100644 index 3242e4162..000000000 --- a/contrib/epee/include/net/http_client_via_api_helper.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. -// - - - - -#pragma once -#include -#include -#pragma comment(lib, "Wininet.lib") - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net.http" - -namespace epee -{ -namespace net_utils -{ - inline - bool http_ssl_invoke(const std::string& url, const std::string usr, const std::string psw, std::string& http_response_body, bool use_post = false) - { - bool final_res = false; - - ATL::CUrl url_obj; - BOOL crack_rss = url_obj.CrackUrl(string_encoding::convert_to_t >(url).c_str()); - - HINTERNET hinet = ::InternetOpenA(SHARED_JOBSCOMMON_HTTP_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - if(!hinet) - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetOpenA, \nError: " << err << " " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - return false; - } - - DWORD dwFlags = 0; - DWORD dwBuffLen = sizeof(dwFlags); - - if(usr.size()) - { - dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID| - INTERNET_FLAG_PRAGMA_NOCACHE | SECURITY_FLAG_IGNORE_UNKNOWN_CA|INTERNET_FLAG_SECURE; - }else - { - dwFlags |= INTERNET_FLAG_PRAGMA_NOCACHE; - } - - - int port = url_obj.GetPortNumber(); - BOOL res = FALSE; - - HINTERNET hsession = ::InternetConnectA(hinet, string_encoding::convert_to_ansii(url_obj.GetHostName()).c_str(), port/*INTERNET_DEFAULT_HTTPS_PORT*/, usr.c_str(), psw.c_str(), INTERNET_SERVICE_HTTP, dwFlags, NULL); - if(hsession) - { - const std::string uri = string_encoding::convert_to_ansii(url_obj.GetUrlPath()) + string_encoding::convert_to_ansii(url_obj.GetExtraInfo()); - - HINTERNET hrequest = ::HttpOpenRequestA(hsession, use_post?"POST":NULL, uri.c_str(), NULL, NULL,NULL, dwFlags, NULL); - if(hrequest) - { - while(true) - { - res = ::HttpSendRequestA(hrequest, NULL, 0, NULL, 0); - if(!res) - { - //ERROR_INTERNET_INVALID_CA 45 - //ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5) - int err = ::GetLastError(); - LOG_PRINT("Failed to call HttpSendRequestA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - break; - } - - DWORD code = 0; - DWORD buf_len = sizeof(code); - DWORD index = 0; - res = ::HttpQueryInfo(hrequest, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &code, &buf_len, &index); - if(!res) - { - //ERROR_INTERNET_INVALID_CA 45 - //ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5) - int err = ::GetLastError(); - LOG_PRINT("Failed to call HttpQueryInfo, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - break; - } - if(code < 200 || code > 299) - { - LOG_PRINT("Wrong server response, HttpQueryInfo returned statuse code" << code , LOG_LEVEL_0); - break; - } - - - char buff[100000] = {0}; - DWORD readed = 0; - while(true) - { - res = ::InternetReadFile(hrequest, buff, sizeof(buff), &readed); - if(!res) - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetReadFile, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - break; - } - if(readed) - { - http_response_body.append(buff, readed); - } - else - break; - } - - if(!res) - break; - - - //we success - final_res = true; - - res = ::InternetCloseHandle(hrequest); - if(!res) - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - } - - break; - } - } - else - { - //ERROR_INTERNET_INVALID_CA - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetOpenUrlA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - return false; - } - - res = ::InternetCloseHandle(hsession); - if(!res) - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - } - }else - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetConnectA(" << string_encoding::convert_to_ansii(url_obj.GetHostName()) << ", port " << port << " \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - } - - - - res = ::InternetCloseHandle(hinet); - if(!res) - { - int err = ::GetLastError(); - LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0); - } - return final_res; - } -} -} diff --git a/contrib/epee/include/net/http_server_cp.h b/contrib/epee/include/net/http_server_cp.h deleted file mode 100644 index 1ac2223c7..000000000 --- a/contrib/epee/include/net/http_server_cp.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _HTTP_SERVER_CP_H_ -#define _HTTP_SERVER_CP_H_ - -#include "abstract_tcp_server_cp.h" -#include "http_server.h" - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net.http" - -namespace epee -{ -namespace net_utils -{ - typedef cp_server_impl cp_http_server_file_system; - typedef cp_server_impl cp_http_server_custum_handling; -} -} - - - -#endif - - diff --git a/contrib/epee/include/net/http_server_thread_per_connect.h b/contrib/epee/include/net/http_server_thread_per_connect.h deleted file mode 100644 index bec43b726..000000000 --- a/contrib/epee/include/net/http_server_thread_per_connect.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _HTTP_SERVER_CP_H_ -#define _HTTP_SERVER_CP_H_ - -#include "abstract_tcp_server.h" -#include "http_server.h" - -namespace epee -{ -namespace net_utils -{ - typedef abstract_tcp_server mt_http_server_file_system; - typedef abstract_tcp_server mt_http_server_custum_handling; - -} -} - - -#endif - - diff --git a/contrib/epee/include/net/levin_helper.h b/contrib/epee/include/net/levin_helper.h deleted file mode 100644 index 05560dd90..000000000 --- a/contrib/epee/include/net/levin_helper.h +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. -// - - - -#pragma once - -#include "levin_base.h" -#include "serializeble_struct_helper.h" - -#undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net" - -namespace epee -{ -namespace levin -{ - template - bool pack_struct_to_levin_message(const t_struct& t, std::string& buff, int command_id) - { - buff.resize(sizeof(levin::bucket_head)); - levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); - head.m_signature = LEVIN_SIGNATURE; - head.m_cb = 0; - head.m_have_to_return_data = true; - head.m_command = command_id; - head.m_return_code = 1; - head.m_reservedA = rand(); //probably some flags in future - head.m_reservedB = rand(); //probably some check summ in future - - std::string buff_strg; - if(!StorageNamed::save_struct_as_storage_to_buff_t(t, buff_strg)) - return false; - - head.m_cb = buff_strg.size(); - buff.append(buff_strg); - return true; - } - - - bool pack_data_to_levin_message(const std::string& data, std::string& buff, int command_id) - { - buff.resize(sizeof(levin::bucket_head)); - levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); - head.m_signature = LEVIN_SIGNATURE; - head.m_cb = 0; - head.m_have_to_return_data = true; - head.m_command = command_id; - head.m_return_code = 1; - head.m_reservedA = rand(); //probably some flags in future - head.m_reservedB = rand(); //probably some check summ in future - - head.m_cb = data.size(); - buff.append(data); - return true; - } - - bool load_levin_data_from_levin_message(std::string& levin_data, const std::string& buff, int& command) - { - if(buff.size() < sizeof(levin::bucket_head) ) - { - LOG_PRINT_L3("size of buff(" << buff.size() << ") is too small, at load_struct_from_levin_message"); - return false; - } - - levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); - if(head.m_signature != LEVIN_SIGNATURE) - { - LOG_PRINT_L3("Failed to read signature in levin message, at load_struct_from_levin_message"); - return false; - } - if(head.m_cb != buff.size()-sizeof(levin::bucket_head)) - { - LOG_PRINT_L3("sizes mismatch, at load_struct_from_levin_message"); - return false; - } - - //std::string buff_strg; - levin_data.assign(&buff[sizeof(levin::bucket_head)], buff.size()-sizeof(levin::bucket_head)); - command = head.m_command; - return true; - } - - template - bool load_struct_from_levin_message(t_struct& t, const std::string& buff, int& command) - { - if(buff.size() < sizeof(levin::bucket_head) ) - { - LOG_ERROR("size of buff(" << buff.size() << ") is too small, at load_struct_from_levin_message"); - return false; - } - - levin::bucket_head& head = *(levin::bucket_head*)(&buff[0]); - if(head.m_signature != LEVIN_SIGNATURE) - { - LOG_ERROR("Failed to read signature in levin message, at load_struct_from_levin_message"); - return false; - } - if(head.m_cb != buff.size()-sizeof(levin::bucket_head)) - { - LOG_ERROR("sizes mismatch, at load_struct_from_levin_message"); - return false; - } - - std::string buff_strg; - buff_strg.assign(&buff[sizeof(levin::bucket_head)], buff.size()-sizeof(levin::bucket_head)); - - if(!StorageNamed::load_struct_from_storage_buff_t(t, buff_strg)) - { - LOG_ERROR("Failed to read storage, at load_struct_from_levin_message"); - return false; - } - command = head.m_command; - return true; - } -} -} diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index e9853ee26..8529f144e 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -37,6 +37,7 @@ #include "misc_language.h" #include "syncobj.h" #include "misc_os_dependent.h" +#include "async_state_machine.h" #include #include @@ -53,12 +54,18 @@ namespace epee namespace levin { +using async_state_machine=cblp::async_callback_state_machine; + + /************************************************************************/ /* */ /************************************************************************/ template class async_protocol_handler; +template + struct invoke_remote_command2_state_machine; + template class async_protocol_handler_config { @@ -70,9 +77,13 @@ class async_protocol_handler_config void del_connection(async_protocol_handler* pc); async_protocol_handler* find_connection(boost::uuids::uuid connection_id) const; +public: int find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler*& aph); friend class async_protocol_handler; +// friend template +// struct invoke_remote_command2_state_machine* m_pcommands_handler; void (*m_pcommands_handler_destroy)(levin_commands_handler*); @@ -157,15 +168,15 @@ class async_protocol_handler virtual void reset_timer()=0; }; template - struct anvoke_handler: invoke_response_handler_base + struct invoke_handler: invoke_response_handler_base { - anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command) + invoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command) :m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false), m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command) { if(m_con.start_outer_call()) { - MDEBUG(con.get_context_ref() << "anvoke_handler, timeout: " << timeout); + MDEBUG(con.get_context_ref() << "invoke_handler, timeout: " << timeout); m_timer.expires_from_now(boost::posix_time::milliseconds(timeout)); m_timer.async_wait([&con, command, cb, timeout](const boost::system::error_code& ec) { @@ -180,7 +191,7 @@ class async_protocol_handler m_timer_started = true; } } - virtual ~anvoke_handler() + virtual ~invoke_handler() {} callback_t m_cb; async_protocol_handler& m_con; @@ -251,7 +262,7 @@ class async_protocol_handler bool add_invoke_response_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler& con, int command) { CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock); - boost::shared_ptr handler(boost::make_shared>(cb, timeout, con, command)); + boost::shared_ptr handler(boost::make_shared>(cb, timeout, con, command)); m_invoke_response_handlers.push_back(handler); return handler->is_timer_started(); } @@ -582,18 +593,19 @@ class async_protocol_handler break; } - if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size())) + if(!add_invoke_response_handler(cb, timeout, *this, command)) { - LOG_ERROR_CC(m_connection_context, "Failed to do_send"); - err_code = LEVIN_ERROR_CONNECTION; + err_code = LEVIN_ERROR_CONNECTION_DESTROYED; break; } - if(!add_invoke_response_handler(cb, timeout, *this, command)) + if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size())) { - err_code = LEVIN_ERROR_CONNECTION_DESTROYED; + LOG_ERROR_CC(m_connection_context, "Failed to do_send"); + err_code = LEVIN_ERROR_CONNECTION; break; } + CRITICAL_REGION_END(); } while (false); @@ -913,5 +925,9 @@ bool async_protocol_handler_config::request_callback(boost return false; } } + + + + } } diff --git a/contrib/epee/include/net/levin_server_cp.h b/contrib/epee/include/net/levin_server_cp.h deleted file mode 100644 index 8ece35059..000000000 --- a/contrib/epee/include/net/levin_server_cp.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _HTTP_SERVER_CP_H_ -#define _HTTP_SERVER_CP_H_ - -#include "abstract_tcp_server_cp.h" -#include "levin_protocol_handler.h" -namespace epee -{ -namespace net_utils -{ - typedef cp_server_impl cp_levin_server; -} -} - - - -#endif - - diff --git a/contrib/epee/include/net/multiprotocols_server.h b/contrib/epee/include/net/multiprotocols_server.h deleted file mode 100644 index 4807a4421..000000000 --- a/contrib/epee/include/net/multiprotocols_server.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _MULTIPROTOCOLS_SERVER_H_ -#define _MULTIPROTOCOLS_SERVER_H_ - -//#include "abstract_tcp_server_cp.h" -#include "protocol_switcher.h" -#include "abstract_tcp_server2.h" - -namespace epee -{ -namespace net_utils -{ - //typedef cp_server_impl multiprotocol_server; - typedef boosted_tcp_server boosted_multiprotocol_server; -} -} - - -#endif //_MULTIPROTOCOLS_SERVER_H_ - diff --git a/contrib/epee/include/net/munin_connection_handler.h b/contrib/epee/include/net/munin_connection_handler.h deleted file mode 100644 index 62856bec5..000000000 --- a/contrib/epee/include/net/munin_connection_handler.h +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _MUNIN_CONNECTION_HANDLER_H_ -#define _MUNIN_CONNECTION_HANDLER_H_ - -#include -#include "net_utils_base.h" -#include "to_nonconst_iterator.h" -#include "http_base.h" -#include "reg_exp_definer.h" - -#define MUNIN_ARGS_DEFAULT(vertial_lable_str) "graph_args --base 1000 -l 0 --vertical-label " vertial_lable_str " \n" -#define MUNIN_ARGS_FORCE_AUPPER_LIMIT(vertial_lable_str, limit) "graph_args --base 1000 -l 0 --vertical-label " vertial_lable_str " --rigid --upper-limit " limit " \n" -#define MUNIN_TITLE(title_str) "graph_title " title_str "\n" -#define MUNIN_CATEGORY(category_str) "graph_category " category_str "\n" -#define MUNIN_INFO(info_str) "graph_info " info_str "\n" -#define MUNIN_ENTRY(var_name) #var_name".label " #var_name "\n" #var_name".info "#var_name".\n" -#define MUNIN_ENTRY_AREA(var_name) #var_name".label " #var_name "\n" #var_name".info "#var_name".\n" #var_name".draw AREASTACK\n" -#define MUNIN_ENTRY_ALIAS(var_name, alias) #var_name".label " #alias"\n" #var_name".info "#alias".\n" -#define BEGIN_MUNIN_SERVICE(servivece_name_str) if(servivece_name_str == pservice->m_service_name) { -#define END_MUNIN_SERVICE() } -#define MUNIN_SERVICE_PARAM(munin_var_name_str, variable) paramters_text += std::string() + munin_var_name_str ".value " + boost::lexical_cast(variable) + "\n" - - - - -namespace epee -{ -namespace net_utils -{ - namespace munin - { - - - /************************************************************************/ - /* */ - /************************************************************************/ - struct munin_service; - - struct munin_service_data_provider - { - virtual bool update_service_data(munin_service* pservice, std::string& paramters_text)=0; - }; - - struct munin_service - { - std::string m_service_name; - std::string m_service_config_string; - munin_service_data_provider* m_pdata_provider; - }; - - struct node_server_config - { - std::list m_services; - //TODO: - }; - - struct fake_send_handler: public i_service_endpoint - { - virtual bool do_send(const void* ptr, size_t cb) - { - m_cache += std::string((const char*)ptr, cb); - return true; - } - public: - - std::string m_cache; - }; - - /************************************************************************/ - /* */ - /************************************************************************/ - class munin_node_server_connection_handler - { - public: - typedef node_server_config config_type; - typedef connection_context_base connection_context; - - munin_node_server_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, const connection_context_base& context):m_psnd_hndlr(psnd_hndlr), - m_machine_state(http_state_retriving_comand_line), - m_config(config) - { - init(); - } - virtual ~munin_node_server_connection_handler() - { - - } - - bool release_protocol() - { - return true; - } - bool after_init_connection() - { - std::string hello_str = "# munin node at "; - hello_str += m_host_name + "\n"; - send_hook(hello_str); - return true; - } - - virtual bool thread_init() - { - return true; - } - - virtual bool thread_deinit() - { - return true; - } - - void handle_qued_callback() - { - - } - - virtual bool handle_recv(const void* ptr, size_t cb) - { - - const char* pbuff = (const char*)ptr; - std::string recvd_buff(pbuff, cb); - LOG_PRINT("munin_recv: \n" << recvd_buff, LOG_LEVEL_3); - - m_cache += recvd_buff; - - bool stop_handling = false; - while(!stop_handling) - { - switch(m_machine_state) - { - case http_state_retriving_comand_line: - { - - std::string::size_type fpos = m_cache.find('\n'); - if(std::string::npos != fpos ) - { - bool res = handle_command(m_cache); - if(!res) - return false; - m_cache.erase(0, fpos+1); - continue; - } - stop_handling = true; - } - break; - case http_state_error: - stop_handling = true; - return false; - default: - LOG_ERROR("Error in munin state machine! Unknown state=" << m_machine_state); - stop_handling = true; - m_machine_state = http_state_error; - return false; - } - - } - - return true; - } - - private: - - - bool init() - { - char hostname[64] = {0}; - int res = gethostname(hostname, 64); - hostname[63] = 0;//be happy - m_host_name = hostname; - return true; - } - bool handle_command(const std::string& command) - { - // list, nodes, config, fetch, version or quit - STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^((list)|(nodes)|(config)|(fetch)|(version)|(quit))(\\s+(\\S+))?", boost::regex::icase | boost::regex::normal); - // 12 3 4 5 6 7 8 9 - size_t match_len = 0; - boost::smatch result; - if(boost::regex_search(command, result, rexp_match_command_line, boost::match_default) && result[0].matched) - { - if(result[2].matched) - {//list command - return handle_list_command(); - }else if(result[3].matched) - {//nodes command - return handle_nodes_command(); - }else if(result[4].matched) - {//config command - if(result[9].matched) - return handle_config_command(result[9]); - else - { - send_hook("Unknown service\n"); - } - }else if(result[5].matched) - {//fetch command - if(result[9].matched) - return handle_fetch_command(result[9]); - else - { - send_hook("Unknown service\n"); - } - }else if(result[6].matched) - {//version command - return handle_version_command(); - }else if(result[7].matched) - {//quit command - return handle_quit_command(); - } - else - return send_hook("Unknown command. Try list, nodes, config, fetch, version or quit\n"); - } - - return send_hook("Unknown command. Try list, nodes, config, fetch, version or quit\n");; - } - - bool handle_list_command() - { - std::string buff_to_send; - for(std::list::const_iterator it = m_config.m_services.begin(); it!=m_config.m_services.end();it++) - { - buff_to_send += it->m_service_name + " "; - } - buff_to_send+='\n'; - return send_hook(buff_to_send); - } - bool handle_nodes_command() - { - //supports only one node - host name - send_hook(m_host_name + "\n.\n"); - return true; - } - bool handle_config_command(const std::string& service_name) - { - munin_service* psrv = get_service_by_name(service_name); - if(!psrv) - return send_hook(std::string() + "Unknown service\n"); - - - return send_hook(psrv->m_service_config_string + ".\n"); - } - - bool handle_fetch_command(const std::string& service_name) - { - munin_service* psrv = get_service_by_name(service_name); - if(!psrv) - return send_hook(std::string() + "Unknown service\n"); - - std::string buff; - psrv->m_pdata_provider->update_service_data(psrv, buff); - - buff += ".\n"; - return send_hook(buff); - } - bool handle_version_command() - { - return send_hook("Munin node component by Andrey Sabelnikov\n"); - } - bool handle_quit_command() - { - return false; - } - - bool send_hook(const std::string& buff) - { - LOG_PRINT("munin_send: \n" << buff, LOG_LEVEL_3); - - if(m_psnd_hndlr) - return m_psnd_hndlr->do_send(buff.data(), buff.size()); - else - return false; - } - - - munin_service* get_service_by_name(const std::string& srv_name) - { - std::list::iterator it = m_config.m_services.begin(); - for(; it!=m_config.m_services.end(); it++) - if(it->m_service_name == srv_name) - break; - - if(it==m_config.m_services.end()) - return NULL; - - return &(*it); - } - - enum machine_state{ - http_state_retriving_comand_line, - http_state_error - }; - - - config_type& m_config; - machine_state m_machine_state; - std::string m_cache; - std::string m_host_name; - protected: - i_service_endpoint* m_psnd_hndlr; - }; - - - inline bool test_self() - { - /*WSADATA w; - ::WSAStartup(MAKEWORD(1, 1), &w); - node_server_config sc; - sc.m_services.push_back(munin_service()); - sc.m_services.back().m_service_name = "test_service"; - - sc.m_services.back().m_service_config_string = - "graph_args --base 1000 -l 0 --vertical-label N --upper-limit 329342976\n" - "graph_title REPORTS STATICTICS\n" - "graph_category bind\n" - "graph_info This graph shows how many reports came in fixed time period.\n" - "graph_order apps free swap\n" - "apps.label apps\n" - "apps.draw AREA\n" - "apps.info Memory used by user-space applications.\n" - "swap.label swap\n" - "swap.draw STACK\n" - "swap.info Swap space used.\n" - "free.label unused\n" - "free.draw STACK\n" - "free.info Wasted memory. Memory that is not used for anything at all.\n" - "committed.label committed\n" - "committed.draw LINE2\n" - "committed.warn 625410048\n" - "committed.info The amount of memory that would be used if all the memory that's been allocated were to be used.\n"; - - - sc.m_services.push_back(munin_service()); - sc.m_services.back().m_service_name = "test_service1"; - fake_send_handler fh; - munin_node_server_connection_handler mh(&fh, sc); - - std::string buff = "list\n"; - mh.handle_recv(buff.data(), buff.size()); - - - buff = "nodes\n"; - mh.handle_recv(buff.data(), buff.size()); -*/ - return true; - } - - } -} -} -#endif//!_MUNIN_CONNECTION_HANDLER_H_ diff --git a/contrib/epee/include/net/munin_node_server.h b/contrib/epee/include/net/munin_node_server.h deleted file mode 100644 index e6df390cb..000000000 --- a/contrib/epee/include/net/munin_node_server.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _MUNIN_NODE_SERVER_H_ -#define _MUNIN_NODE_SERVER_H_ - -#include -//#include "net_utils_base.h" -#include "munin_connection_handler.h" -//#include "abstract_tcp_server.h" -//#include "abstract_tcp_server_cp.h" -#include "abstract_tcp_server2.h" -namespace epee -{ -namespace net_utils -{ - namespace munin - { - typedef boosted_tcp_server munin_node_server; - //typedef cp_server_impl munin_node_cp_server; - } -} -} -#endif//!_MUNIN_NODE_SERVER_H_ diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 94744ac21..fec7cbe0c 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -41,6 +41,12 @@ #include #include "net/net_utils_base.h" #include "misc_language.h" +//#include "profile_tools.h" +#include "../string_tools.h" +#include +#include +#include +#include #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net" @@ -55,10 +61,193 @@ namespace epee namespace net_utils { + + class async_client : public boost::enable_shared_from_this + { + public: + enum result_type { + suceed + , timeouted + , resolve_error + , connect_error + , send_error + , recv_error + }; + + typedef boost::function recv_data_handler_type; + typedef boost::function final_callback_type; + + struct ignore_call_result : public boost::enable_shared_from_this + { + static boost::shared_ptr create() { + return boost::shared_ptr(new ignore_call_result); + } + void operator() (result_type, const std::string&) {} + protected: + ignore_call_result() = default; + }; + + + static boost::shared_ptr create(boost::asio::io_service& io_service + , recv_data_handler_type on_recv_callback/* = boost::bind(&http_recved_data_handler::operator() + , http_recved_data_handler::create() + , _1, _2, _3)*/ + , final_callback_type callback = boost::bind(&ignore_call_result::operator() + , ignore_call_result::create + , _1, _2) + , const std::string& bind_ip = "0.0.0.0") + { + boost::shared_ptr ret(new async_client(io_service, on_recv_callback, callback, bind_ip)); + return ret; + } + + void connect_send_wait_answer_and_disconnect(const std::string& addr + , const std::string& port + , const std::string& data_to_send + , int64_t timeout + ) + { + if (timeout < 0) + timeout = 1; + + boost::asio::ip::tcp::resolver::query query(addr,port); + boost::asio::ip::tcp::resolver r(m_io_service); + + r.async_resolve(query, boost::bind(&async_client::on_resolve, shared_from_this(), _1, _2)); + + m_request = data_to_send; + m_deadline.expires_from_now(std::chrono::milliseconds(timeout)); + m_deadline.async_wait(boost::bind(&async_client::on_timeout, shared_from_this(), _1)); + } + + protected: + async_client(boost::asio::io_service& io_service + , recv_data_handler_type& on_recv_callback + , final_callback_type callback + , const std::string& bind_ip = "0.0.0.0") + : m_io_service(io_service) + , m_socket(io_service) + , m_initialized(false) + , m_connected(false) + , m_deadline(m_io_service) + , m_on_receive_callback(on_recv_callback) + , m_inbuff(8192) + , m_finalizer(callback) + , m_bind_ip(bind_ip) + , m_strand(io_service) + { + m_initialized = true; + } + + void on_resolve(const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator _epIt) + { + if (ec) { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::resolve_error, std::string())); + return; + } + + m_socket.async_connect(*_epIt,boost::bind(&async_client::on_connect, shared_from_this(),_1)); + } + + void on_connect(const boost::system::error_code& ec) + { + if (ec) { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::resolve_error, std::string())); + return; + } + + boost::asio::async_read(m_socket, boost::asio::buffer(m_inbuff.data(), m_inbuff.size()) + , m_strand.wrap(boost::bind(&async_client::on_read, shared_from_this(), _1, _2))); + + boost::asio::async_write(m_socket,boost::asio::buffer(m_request.data(), m_request.size()) + , boost::bind(&async_client::on_write, shared_from_this(), _1, _2)); + } + + void on_read(const boost::system::error_code& ec, + std::size_t bytes_read) + { + if (!ec) { + if ( m_on_receive_callback(m_inbuff.data(), bytes_read, m_responce) ) { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::suceed, m_responce)); + } + else { + boost::asio::async_read(m_socket, boost::asio::buffer(m_inbuff.data(), m_inbuff.size()) + , m_strand.wrap(boost::bind(&async_client::on_read, shared_from_this(), _1, _2))); + } + } + else if (ec == boost::asio::error::eof) { + if ( m_on_receive_callback(m_inbuff.data(), bytes_read, m_responce) ) { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::suceed, m_responce)); + } + else { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::recv_error, std::string())); + } + } + else { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::recv_error, std::string())); + } + } + + void on_write(const boost::system::error_code& ec, + size_t bytes_sent) + { + if (ec || bytes_sent != m_request.size() ) { + shutdown(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::send_error, std::string())); + return; + } + } + + void on_timeout(const boost::system::error_code& ec) + { + if (ec == boost::asio::error::operation_aborted) + return; + + m_socket.close(); + m_io_service.post(boost::bind(&async_client::on_final, shared_from_this(), result_type::timeouted, std::string())); + } + + void on_final(result_type r, const std::string& resp) + { + m_finalizer(r, resp); + } + + + void shutdown() + { + m_socket.close(); + m_deadline.cancel(); + } + + + boost::asio::io_service& m_io_service; + boost::asio::ip::tcp::socket m_socket; + bool m_initialized; + bool m_connected; + boost::asio::steady_timer m_deadline; + volatile uint32_t m_shutdowned; + recv_data_handler_type m_on_receive_callback; + + std::vector m_inbuff; + std::string m_request; + std::string m_responce; + + final_callback_type m_finalizer; + + const std::string m_bind_ip; + boost::asio::io_service::strand m_strand; + }; + + class blocked_mode_client { - struct handler_obj { handler_obj(boost::system::error_code& error, size_t& bytes_transferred):ref_error(error), ref_bytes_transferred(bytes_transferred) @@ -77,16 +266,19 @@ namespace net_utils ref_bytes_transferred = bytes_transferred; } }; - + public: inline - blocked_mode_client():m_initialized(false), + blocked_mode_client(boost::shared_ptr ios + = boost::shared_ptr{new boost::asio::io_service()}) + :m_io_service{ios}, + m_initialized(false), m_connected(false), - m_deadline(m_io_service), + m_deadline(*m_io_service), m_shutdowned(0), m_ssl(false), m_ctx(boost::asio::ssl::context::sslv23), - m_ssl_socket(m_io_service,m_ctx) + m_ssl_socket(*m_io_service,m_ctx) { @@ -135,7 +327,7 @@ namespace net_utils ////////////////////////////////////////////////////////////////////////// - boost::asio::ip::tcp::resolver resolver(m_io_service); + boost::asio::ip::tcp::resolver resolver(*m_io_service); boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); boost::asio::ip::tcp::resolver::iterator end; @@ -168,7 +360,7 @@ namespace net_utils m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); while (ec == boost::asio::error::would_block) { - m_io_service.run_one(); + m_io_service->run_one(); } if (!ec && m_ssl_socket.next_layer().is_open()) @@ -257,7 +449,7 @@ namespace net_utils // Block until the asynchronous operation has completed. while (ec == boost::asio::error::would_block) { - m_io_service.run_one(); + m_io_service->run_one(); } if (ec) @@ -382,7 +574,7 @@ namespace net_utils // Block until the asynchronous operation has completed. while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) { - m_io_service.run_one(); + m_io_service->run_one(); } @@ -463,7 +655,7 @@ namespace net_utils // Block until the asynchronous operation has completed. while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) { - m_io_service.run_one(); + m_io_service->run_one(); } if (ec) @@ -528,7 +720,7 @@ namespace net_utils } boost::asio::io_service& get_io_service() { - return m_io_service; + return *m_io_service; } boost::asio::ip::tcp::socket& get_socket() @@ -568,7 +760,7 @@ namespace net_utils m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1); while (ec == boost::asio::error::would_block) { - m_io_service.run_one(); + m_io_service->run_one(); } // Ignore "short read" error if (ec.category() == boost::asio::error::get_ssl_category() && @@ -611,7 +803,7 @@ namespace net_utils } protected: - boost::asio::io_service m_io_service; + boost::shared_ptr m_io_service; boost::asio::ssl::context m_ctx; boost::asio::ssl::stream m_ssl_socket; bool m_ssl; @@ -628,7 +820,7 @@ namespace net_utils class async_blocked_mode_client: public blocked_mode_client { public: - async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service) + async_blocked_mode_client():m_send_deadline(this->get_io_service()) { // No deadline is required until the first socket operation is started. We @@ -732,6 +924,6 @@ namespace net_utils // Put the actor back to sleep. m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); } - }; + }; } } diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index a133942fb..230935843 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -159,7 +159,8 @@ namespace net_utils bool is_loopback() const { return self ? self->is_loopback() : false; } bool is_local() const { return self ? self->is_local() : false; } uint8_t get_type_id() const { return self ? self->get_type_id() : 0; } - template const Type &as() const { return as_mutable(); } + template Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)self.get(); } + template const Type &as() const { return as_mutable(); } BEGIN_KV_SERIALIZE_MAP() uint8_t type = is_store ? this_ref.get_type_id() : 0; diff --git a/contrib/epee/include/net/protocol_switcher.h b/contrib/epee/include/net/protocol_switcher.h deleted file mode 100644 index 3b153d19c..000000000 --- a/contrib/epee/include/net/protocol_switcher.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _PROTOCOL_SWITCHER_H_ -#define _PROTOCOL_SWITCHER_H_ - -#include "levin_base.h" -#include "http_server.h" -#include "levin_protocol_handler.h" -//#include "abstract_tcp_server.h" - -namespace epee -{ -namespace net_utils -{ - struct protocl_switcher_config - { - http::http_custom_handler::config_type m_http_config; - levin::protocol_handler::config_type m_levin_config; - }; - - - struct i_protocol_handler - { - virtual bool handle_recv(const void* ptr, size_t cb)=0; - }; - - template - class t_protocol_handler: public i_protocol_handler - { - public: - typedef t t_type; - t_protocol_handler(i_service_endpoint* psnd_hndlr, typename t_type::config_type& config, const connection_context& conn_context):m_hadler(psnd_hndlr, config, conn_context) - {} - private: - bool handle_recv(const void* ptr, size_t cb) - { - return m_hadler.handle_recv(ptr, cb); - } - t_type m_hadler; - }; - - - class protocol_switcher - { - public: - typedef protocl_switcher_config config_type; - - protocol_switcher(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context); - virtual ~protocol_switcher(){} - - virtual bool handle_recv(const void* ptr, size_t cb); - - bool after_init_connection(){return true;} - private: - t_protocol_handler m_http_handler; - t_protocol_handler m_levin_handler; - i_protocol_handler* pcurrent_handler; - - std::string m_cached_buff; - }; - - protocol_switcher::protocol_switcher(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context):m_http_handler(psnd_hndlr, config.m_http_config, conn_context), m_levin_handler(psnd_hndlr, config.m_levin_config, conn_context), pcurrent_handler(NULL) - {} - - bool protocol_switcher::handle_recv(const void* ptr, size_t cb) - { - if(pcurrent_handler) - return pcurrent_handler->handle_recv(ptr, cb); - else - { - m_cached_buff.append((const char*)ptr, cb); - if(m_cached_buff.size() < sizeof(uint64_t)) - return true; - - if(*((uint64_t*)&m_cached_buff[0]) == LEVIN_SIGNATURE) - { - pcurrent_handler = &m_levin_handler; - return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); - } - if(m_cached_buff.substr(0, 4) == "GET " || m_cached_buff.substr(0, 4) == "POST") - { - pcurrent_handler = &m_http_handler; - return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size()); - }else - { - LOG_ERROR("Wrong protocol accepted on port..."); - return false; - } - } - - return true; - } -} -} -#endif //_PROTOCOL_SWITCHER_H_ diff --git a/contrib/epee/include/net/rpc_method_name.h b/contrib/epee/include/net/rpc_method_name.h deleted file mode 100644 index 1c327bc31..000000000 --- a/contrib/epee/include/net/rpc_method_name.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. -// - - -#pragma once - - -#define RPC_METHOD_NAME(name) static inline const char* methodname(){return name;} diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h index fc5a21851..a596f4cc4 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -96,6 +96,10 @@ public: \ #define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \ epee::serialization::selector::serialize_stl_container_pod_val_as_blob(this_ref.varialble, stg, hparent_section, val_name); +#define KV_SERIALIZE_SPECIAL_TYPE_N(varialble, val_name, serializer) \ + auto v = this_ref.serializer(this_ref.varialble); \ + epee::serialization::selector::serialize(v, stg, hparent_section, val_name); + #define END_KV_SERIALIZE_MAP() return true;} #define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble) @@ -104,6 +108,7 @@ public: \ #define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check #define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble) #define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value) +#define KV_SERIALIZE_SPECIAL_TYPE(varialble, serializer) KV_SERIALIZE_SPECIAL_TYPE_N(varialble, #varialble, serializer) } diff --git a/contrib/epee/include/storages/gzipped_inmemstorage.h b/contrib/epee/include/storages/gzipped_inmemstorage.h deleted file mode 100644 index 229a56da6..000000000 --- a/contrib/epee/include/storages/gzipped_inmemstorage.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 _GZIPPED_INMEMSTORAGE_H_ -#define _GZIPPED_INMEMSTORAGE_H_ - -#include "zlib_helper.h" -namespace epee -{ -namespace StorageNamed -{ - - template - class gziped_storage: public t_base_storage - { - public: - size_t PackToSolidBuffer(std::string& targetObj) - { - size_t res = t_base_storage::PackToSolidBuffer(targetObj); - if(res <= 0) - return res; - - if(!zlib_helper::pack(targetObj)) - return 0; - - return targetObj.size(); - } - - size_t LoadFromSolidBuffer(const std::string& pTargetObj) - { - std::string buff_to_ungzip = pTargetObj; - if(zlib_helper::unpack(buff_to_ungzip)) - return t_base_storage::LoadFromSolidBuffer(buff_to_ungzip); - - return 0; - } - - private: - }; - -} -} - -#endif diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index d93084ab0..ee9723b52 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -69,6 +69,36 @@ namespace epee return serialization::load_t_from_json(result_struct, pri->m_body); } + template + bool invoke_http_json_async(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, t_callback callback, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET") + { + std::string req_param; + if(!serialization::store_t_to_json(out_struct, req_param)) + return false; + + const http::http_response_info* pri = NULL; + if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri))) + { + LOG_PRINT_L1("Failed to invoke http request to " << uri); + return false; + } + + if(!pri) + { + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", internal error (null response ptr)"); + return false; + } + + if(pri->m_response_code != 200) + { + LOG_PRINT_L1("Failed to invoke http request to " << uri << ", wrong response code: " << pri->m_response_code); + return false; + } + + return serialization::load_t_from_json(result_struct, pri->m_body); + } + + template diff --git a/contrib/epee/include/zlib_helper.h b/contrib/epee/include/zlib_helper.h deleted file mode 100644 index 46c7f48e6..000000000 --- a/contrib/epee/include/zlib_helper.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the Andrey N. Sabelnikov nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. -// - - -#pragma once -extern "C" { -#include "zlib/zlib.h" -} -#pragma comment(lib, "zlibstat.lib") - -namespace epee -{ -namespace zlib_helper -{ - inline - bool pack(std::string& target){ - std::string result_packed_buff; - - z_stream zstream = {0}; - int ret = deflateInit(&zstream, Z_DEFAULT_COMPRESSION); - if(target.size()) - { - - - result_packed_buff.resize(target.size()*2, 'X'); - - zstream.next_in = (Bytef*)target.data(); - zstream.avail_in = (uInt)target.size(); - zstream.next_out = (Bytef*)result_packed_buff.data(); - zstream.avail_out = (uInt)result_packed_buff.size(); - - ret = deflate(&zstream, Z_FINISH); - CHECK_AND_ASSERT_MES(ret>=0, false, "Failed to deflate. err = " << ret); - - if(result_packed_buff.size() != zstream.avail_out) - result_packed_buff.resize(result_packed_buff.size()-zstream.avail_out); - - - result_packed_buff.erase(0, 2); - target.swap(result_packed_buff); - } - - deflateEnd(& zstream ); - return true; - } - - inline bool unpack(std::string& target) - { - z_stream zstream = {0}; - int ret = inflateInit(&zstream);// - - std::string decode_summary_buff; - size_t ungzip_buff_size = target.size() * 0x30; - std::string current_decode_buff(ungzip_buff_size, 'X'); - - while(target.size()) - { - - - zstream.next_out = (Bytef*)current_decode_buff.data(); - zstream.avail_out = (uInt)ungzip_buff_size; - - int flag = Z_SYNC_FLUSH; - - static char dummy_head[2] = - { - 0x8 + 0x7 * 0x10, - (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF, - }; - zstream.next_in = (Bytef*) dummy_head; - zstream.avail_in = sizeof(dummy_head); - ret = inflate(&zstream, Z_NO_FLUSH); - if (ret != Z_OK) - { - LOCAL_ASSERT(0); - return false; - } - - zstream.next_in = (Bytef*)target.data(); - zstream.avail_in = (uInt)target.size(); - - ret = inflate(&zstream, Z_SYNC_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - LOCAL_ASSERT(0); - return false; - } - - - target.erase(0, target.size()-zstream.avail_in); - - - if(ungzip_buff_size == zstream.avail_out) - { - LOG_ERROR("Can't unpack buffer"); - return false; - } - - - current_decode_buff.resize(ungzip_buff_size - zstream.avail_out); - if(decode_summary_buff.size()) - decode_summary_buff += current_decode_buff; - else - current_decode_buff.swap(decode_summary_buff); - - current_decode_buff.resize(ungzip_buff_size); - } - - inflateEnd(&zstream ); - - decode_summary_buff.swap(target); - return 1; - } - -}; -}//namespace epee diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt index bc437deb9..706305b1d 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -26,10 +26,13 @@ # 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. -add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c - connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp) if (USE_READLINE AND GNU_READLINE_FOUND) add_library(epee_readline STATIC readline_buffer.cpp) + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c + connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp async_state_machine.cpp readline_buffer.cpp) +else() + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c + connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp async_state_machine.cpp) endif() if(HAVE_C11) diff --git a/contrib/epee/src/async_state_machine.cpp b/contrib/epee/src/async_state_machine.cpp new file mode 100644 index 000000000..38a458dd2 --- /dev/null +++ b/contrib/epee/src/async_state_machine.cpp @@ -0,0 +1,119 @@ +#include "async_state_machine.h" + +namespace cblp { + + +/*virtual*/ async_callback_state_machine::~async_callback_state_machine() +{ +#if 0 + if (deadline_timer ) { + deadline_timer->cancel(); + deadline_timer.reset(); + } +#endif +} + + +async_callback_state_machine::async_callback_state_machine(boost::asio::io_service& io_service + , int64_t timeout + , async_callback_state_machine::callback_type finalizer) + : io_service(io_service) + , timeout_msec(timeout) + , deadline_timer( timeout_msec > 0 + ? new boost::asio::deadline_timer(io_service, + boost::posix_time::milliseconds(timeout)) + : nullptr) + , final_callback(finalizer) + , strand(io_service) + , timestamp(std::chrono::high_resolution_clock::now()) +{} + + +void async_callback_state_machine::deadline_handler(const boost::system::error_code& ec, + boost::shared_ptr& machine) +{ + if ( ec == boost::asio::error::operation_aborted ) + return; + machine->final_callback(call_result_type::timeouted); +} + + +void async_callback_state_machine::remove_scheduled_task(boost::shared_ptr& ptr) +{ + // TODO: add mutex + _mutex.lock(); + scheduled_tasks.erase(ptr); + _mutex.unlock(); +} + + +void async_callback_state_machine::schedule_task(boost::shared_ptr task) +{ + boost::shared_ptr wrapper(new weak_binder(task, shared_from_this())); + _mutex.lock(); + scheduled_tasks.insert(task); + _mutex.unlock(); + io_service.post(strand.wrap(boost::bind(&weak_binder::operator(), wrapper))); +} + +void async_callback_state_machine::schedule_task(boost::shared_ptr task, int timeout) +{ + boost::shared_ptr wrapper(new timer_binder(task, shared_from_this(), timeout)); + _mutex.lock(); + scheduled_tasks.insert(task); + active_timers.insert(wrapper->timer); + _mutex.unlock(); + wrapper->timer->async_wait(boost::bind(&timer_binder::timeout_handler, _1, wrapper)); +} + + +void async_callback_state_machine::unschedule_task(boost::weak_ptr task) +{ + boost::shared_ptr t = task.lock(); + if (!t) + return; + _mutex.lock(); + scheduled_tasks.erase(t); + _mutex.unlock(); + boost::shared_ptr timer = t->timer.lock(); + if (timer) { + timer->cancel(); + _mutex.lock(); + active_timers.erase(timer); + _mutex.unlock(); + } +} + + +void async_callback_state_machine::stop(call_result_type result /*= call_result_type::aborted*/) +{ + std::vector> timers; + deadline_timer->cancel(); + deadline_timer.reset(); + + do { + boost::recursive_mutex::scoped_lock guard(_mutex); + if (scheduled_tasks.empty()) + break; + + auto task = *(scheduled_tasks.begin()); + guard.unlock(); + unschedule_task(task); + guard.lock(); + + } while(1); + + _mutex.lock(); + for (auto entry : active_timers) + timers.push_back(entry); + active_timers.clear(); + _mutex.unlock(); + + for (auto timer : timers) + timer->cancel(); + + final_callback(result); +} + + +} // namespace cblp diff --git a/contrib/epee/src/connection_basic.cpp b/contrib/epee/src/connection_basic.cpp index dea1928a7..704d417ae 100644 --- a/contrib/epee/src/connection_basic.cpp +++ b/contrib/epee/src/connection_basic.cpp @@ -250,6 +250,21 @@ void connection_basic::sleep_before_packet(size_t packet_size, int phase, int q } } + +int64_t connection_basic::sleep_before_packet(size_t packet_size) +{ + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + double delay = network_throttle_manager::get_global_throttle_out().get_sleep_time_after_tick( packet_size ); // decission from global + return (delay * 1000); +} + +void connection_basic::update_traffic_limits(size_t packet_size) +{ + CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); + network_throttle_manager::get_global_throttle_out().handle_trafic_exact( packet_size * 700); // increase counter - global +} + + void connection_basic::set_start_time() { CRITICAL_REGION_LOCAL( network_throttle_manager::m_lock_get_global_throttle_out ); m_start_time = network_throttle_manager::get_global_throttle_out().get_time_seconds(); diff --git a/contrib/epee/src/mlog.cpp b/contrib/epee/src/mlog.cpp index 8486777b6..0ac765a1c 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -50,6 +50,10 @@ #define MLOG_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x +thread_local std::string mlog_current_log_category; + +bool mlog_syslog = false; + using namespace epee; static std::string generate_log_filename(const char *base) @@ -150,14 +154,34 @@ bool EnableVTMode() } #endif -void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size, const std::size_t max_log_files) +// %rfile custom specifier can be used in addition to the Logging Format Specifiers of the Easylogging++ +// %rfile similar to %file but the path is relative to topmost CMakeLists.txt +void mlog_configure(const std::string &filename_base, bool console, const char* format, const std::size_t max_log_file_size, const std::size_t max_log_files) { + //support %rlog + static bool once = false; + if(!once) + { + once = true; + auto rfile = [](const el::LogMessage* lm)-> std::string + { + assert(sizeof(CMAKE_ROOT_SOURCE_DIR) < lm->file().size()); + return lm->file().substr(sizeof(CMAKE_ROOT_SOURCE_DIR)); + }; + el::Helpers::installCustomFormatSpecifier(el::CustomFormatSpecifier("%rfile", rfile)); + } + el::Configurations c; c.setGlobally(el::ConfigurationType::Filename, filename_base); c.setGlobally(el::ConfigurationType::ToFile, "true"); - const char *log_format = getenv("MONERO_LOG_FORMAT"); - if (!log_format) - log_format = MLOG_BASE_FORMAT; + + const char *log_format = format; + if(!log_format) + { + log_format = getenv("MONERO_LOG_FORMAT"); + if (!log_format) + log_format = MLOG_BASE_FORMAT; + } c.setGlobally(el::ConfigurationType::Format, log_format); c.setGlobally(el::ConfigurationType::ToStandardOutput, console ? "true" : "false"); c.setGlobally(el::ConfigurationType::MaxLogFileSize, std::to_string(max_log_file_size)); diff --git a/install_dependencies.sh b/install_dependencies.sh index 063372f9d..caf83413e 100755 --- a/install_dependencies.sh +++ b/install_dependencies.sh @@ -17,7 +17,8 @@ sudo apt-get install -y \ libldns-dev \ libexpat1-dev \ doxygen \ - graphviz + graphviz \ + libssl-dev if [ ${VER[1]} == "18.04" ]; then sudo apt-get install -y libssl1.0-dev diff --git a/ios_get_libwallet.api.sh b/ios_get_libwallet.api.sh new file mode 100755 index 000000000..07ab3a559 --- /dev/null +++ b/ios_get_libwallet.api.sh @@ -0,0 +1,50 @@ +#!/bin/bash -e + +# 3 header files required by monero are missing from the IOS SDK. I copied them from iphoneSimulator SDK +# cd /Applications/XCode.app +# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/sys/vmmeter.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/sys/ +# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/netinet/udp_var.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/netinet/ +# sudo cp ./Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/netinet/ip_var.h ./Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/netinet/ + + +if [ -z $BUILD_TYPE ]; then + BUILD_TYPE=release +fi + +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [ -z $BOOST_LIBRARYDIR ]; then + BOOST_LIBRARYDIR=${ROOT_DIR}/../ofxiOSBoost/libs/boost/ios +fi +if [ -z $BOOST_INCLUDEDIR ]; then + BOOST_INCLUDEDIR=${ROOT_DIR}/../ofxiOSBoost/libs/boost/include +fi +if [ -z $OPENSSL_INCLUDE_DIR ]; then + OPENSSL_INCLUDE_DIR=${ROOT_DIR}/../OpenSSL-for-iPhone/include +fi +if [ -z $OPENSSL_ROOT_DIR ]; then + OPENSSL_ROOT_DIR=${ROOT_DIR}/../OpenSSL-for-iPhone +fi + +echo "Building IOS armv7" +rm -r build > /dev/null +mkdir -p build/release +pushd build/release +cmake -D IOS=ON -D ARCH=armv7 -D BOOST_LIBRARYDIR=${BOOST_INCLUDEDIR} -D BOOST_INCLUDEDIR=${BOOST_INCLUDEDIR} -D OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR} -D OPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} -D CMAKE_BUILD_TYPE=release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="${ROOT_DIR}" ../.. +make -j4 && make install +popd +echo "Building IOS arm64" +rm -r build > /dev/null +mkdir -p build/release +pushd build/release +cmake -D IOS=ON -D ARCH=arm64 -D BOOST_LIBRARYDIR=${BOOST_INCLUDEDIR} -D BOOST_INCLUDEDIR=${BOOST_INCLUDEDIR} -D OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR} -D OPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR} -D CMAKE_BUILD_TYPE=release -D STATIC=ON -D BUILD_GUI_DEPS=ON -D INSTALL_VENDORED_LIBUNBOUND=ON -D CMAKE_INSTALL_PREFIX="${ROOT_DIR}" ../.. +make -j4 && make install +popd + +echo "Creating fat library for armv7 and arm64" +pushd . +mkdir -p lib-ios +lipo -create lib-armv7/libwallet_merged.a lib-arm64/libwallet_merged.a -output lib-ios/libwallet_merged.a +lipo -create lib-armv7/libunbound.a lib-armv8-a/libunbound.a -output lib-ios/libunbound.a +lipo -create lib-armv7/libeasylogging.a lib-armv8-a/libeasylogging.a -output lib-ios/libeasylogging.a +lipo -create lib-armv7/libepee.a lib-arm64/libepee.a -output lib-ios/libepee.a +popd diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index baa21affd..7328d0a70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,7 @@ if(NOT IOS) add_subdirectory(daemonizer) add_subdirectory(daemon) add_subdirectory(blockchain_utilities) + add_subdirectory(utils) endif() if(CMAKE_BUILD_TYPE STREQUAL Debug) diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index 00804f3b1..05160da42 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -185,6 +185,7 @@ namespace cryptonote // TODO return true; } + return true; } @@ -229,10 +230,10 @@ namespace cryptonote std::vector records; // All four MoneroPulse domains have DNSSEC on and valid - static const std::vector dns_urls = { "checkpoints.moneropulse.se" + static const std::vector dns_urls = { }; - static const std::vector testnet_dns_urls = { "testpoints.moneropulse.se" + static const std::vector testnet_dns_urls = { }; static const std::vector stagenet_dns_urls = { "stagenetpoints.moneropulse.se" diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h index 33d85fa4d..c3d2c2a92 100644 --- a/src/crypto/chacha.h +++ b/src/crypto/chacha.h @@ -73,18 +73,18 @@ namespace crypto { inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); epee::mlocked> pwd_hash; - crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); + crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/, 0/*modifier*/); for (uint64_t n = 1; n < kdf_rounds; ++n) - crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); + crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/, 0/*modifier*/); memcpy(&unwrap(unwrap(key)), pwd_hash.data(), sizeof(key)); } inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); epee::mlocked> pwd_hash; - crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/); + crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/, 0/*modifier*/); for (uint64_t n = 1; n < kdf_rounds; ++n) - crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); + crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/, 0/*modifier*/); memcpy(&unwrap(unwrap(key)), pwd_hash.data(), sizeof(key)); } diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index d77d55cf3..f9f76c2f5 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -78,8 +78,13 @@ enum { HASH_DATA_AREA = 136 }; +#define CN_MODIFIER_NONE 0x0 +#define CN_MODIFIER_WALTZ 0x1 +#define CN_MODIFIER_REVERSE 0x2 +#define CN_MODIFIER_REVERSE_WALTZ CN_MODIFIER_WALTZ | CN_MODIFIER_REVERSE + void cn_fast_hash(const void *data, size_t length, char *hash); -void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed); +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, int modifier); void hash_extra_blake(const void *data, size_t length, char *hash); void hash_extra_groestl(const void *data, size_t length, char *hash); diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 995e2294e..e06f91603 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -71,12 +71,12 @@ namespace crypto { return h; } - inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0) { - cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 0/*prehashed*/); + inline void cn_slow_hash(const void *data, std::size_t length, hash &hash, int variant = 0, int modifier = 0) { + cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 0/*prehashed*/, modifier); } - inline void cn_slow_hash_prehashed(const void *data, std::size_t length, hash &hash, int variant = 0) { - cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 1/*prehashed*/); + inline void cn_slow_hash_prehashed(const void *data, std::size_t length, hash &hash, int variant = 0, int modifier = 0) { + cn_slow_hash(data, length, reinterpret_cast(&hash), variant, 1/*prehashed*/, modifier); } inline void tree_hash(const hash *hashes, std::size_t count, hash &root_hash) { diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 359904ded..c66f93df2 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -113,34 +113,34 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp sqrt_result = state.hs.w[13]; \ } while (0) -#define VARIANT2_SHUFFLE_ADD_SSE2(base_ptr, offset) \ +#define VARIANT2_SHUFFLE_ADD_SSE2(base_ptr, offset, reverse) \ do if (variant >= 2) \ { \ - const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10))); \ + const __m128i chunk1 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ (reverse ? 0x30 : 0x10)))); \ const __m128i chunk2 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20))); \ - const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30))); \ + const __m128i chunk3 = _mm_load_si128((__m128i *)((base_ptr) + ((offset) ^ (reverse ? 0x10 : 0x30)))); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x10)), _mm_add_epi64(chunk3, _b1)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x20)), _mm_add_epi64(chunk1, _b)); \ _mm_store_si128((__m128i *)((base_ptr) + ((offset) ^ 0x30)), _mm_add_epi64(chunk2, _a)); \ } while (0) -#define VARIANT2_SHUFFLE_ADD_NEON(base_ptr, offset) \ +#define VARIANT2_SHUFFLE_ADD_NEON(base_ptr, offset, reverse) \ do if (variant >= 2) \ { \ - const uint64x2_t chunk1 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x10))); \ + const uint64x2_t chunk1 = vld1q_u64(U64((base_ptr) + ((offset) ^ (reverse ? 0x30 : 0x10)))); \ const uint64x2_t chunk2 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x20))); \ - const uint64x2_t chunk3 = vld1q_u64(U64((base_ptr) + ((offset) ^ 0x30))); \ + const uint64x2_t chunk3 = vld1q_u64(U64((base_ptr) + ((offset) ^ (reverse ? 0x10 : 0x30)))); \ vst1q_u64(U64((base_ptr) + ((offset) ^ 0x10)), vaddq_u64(chunk3, vreinterpretq_u64_u8(_b1))); \ vst1q_u64(U64((base_ptr) + ((offset) ^ 0x20)), vaddq_u64(chunk1, vreinterpretq_u64_u8(_b))); \ vst1q_u64(U64((base_ptr) + ((offset) ^ 0x30)), vaddq_u64(chunk2, vreinterpretq_u64_u8(_a))); \ } while (0) -#define VARIANT2_PORTABLE_SHUFFLE_ADD(base_ptr, offset) \ +#define VARIANT2_PORTABLE_SHUFFLE_ADD(base_ptr, offset, reverse) \ do if (variant >= 2) \ { \ - uint64_t* chunk1 = U64((base_ptr) + ((offset) ^ 0x10)); \ + uint64_t* chunk1 = U64((base_ptr) + ((offset) ^ (reverse ? 0x30 : 0x10))); \ uint64_t* chunk2 = U64((base_ptr) + ((offset) ^ 0x20)); \ - uint64_t* chunk3 = U64((base_ptr) + ((offset) ^ 0x30)); \ + uint64_t* chunk3 = U64((base_ptr) + ((offset) ^ (reverse ? 0x10 : 0x30))); \ \ const uint64_t chunk1_old[2] = { chunk1[0], chunk1[1] }; \ \ @@ -288,8 +288,8 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp * bit multiply. * This code is based upon an optimized implementation by dga. */ -#define post_aes() \ - VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j); \ +#define post_aes(reverse) \ + VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j, reverse); \ _mm_store_si128(R128(c), _c); \ _mm_store_si128(R128(&hp_state[j]), _mm_xor_si128(_b, _c)); \ VARIANT1_1(&hp_state[j]); \ @@ -299,7 +299,7 @@ extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *exp VARIANT2_INTEGER_MATH_SSE2(b, c); \ __mul(); \ VARIANT2_2(); \ - VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j); \ + VARIANT2_SHUFFLE_ADD_SSE2(hp_state, j, reverse); \ a[0] += hi; a[1] += lo; \ p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ @@ -693,7 +693,7 @@ void slow_hash_free_state(void) * @param length the length in bytes of the data * @param hash a pointer to a buffer in which the final 256 bit hash will be stored */ -void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, int modifier) { RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */ @@ -762,9 +762,10 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1]; /* CryptoNight Step 3: Bounce randomly 1,048,576 times (1<<20) through the mixing buffer, - * using 524,288 iterations of the following mixing function. Each execution - * performs two reads and writes from the mixing buffer. + * using 524,288 (CryptoNight) or 393,216 (CryptoNight Waltz) iterations of the following + * mixing function. Each execution performs two reads and writes from the mixing buffer. */ + uint64_t iters = (modifier & CN_MODIFIER_WALTZ) ? (3 * ITER) / 8 : ITER / 2; _b = _mm_load_si128(R128(b)); _b1 = _mm_load_si128(R128(b) + 1); @@ -772,20 +773,44 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int // the useAes test is only performed once, not every iteration. if(useAes) { - for(i = 0; i < ITER / 2; i++) + if(modifier & CN_MODIFIER_REVERSE) { - pre_aes(); - _c = _mm_aesenc_si128(_c, _a); - post_aes(); + for(i = 0; i < iters; i++) + { + pre_aes(); + _c = _mm_aesenc_si128(_c, _a); + post_aes(1); + } + } + else + { + for(i = 0; i < iters; i++) + { + pre_aes(); + _c = _mm_aesenc_si128(_c, _a); + post_aes(0); + } } } else { - for(i = 0; i < ITER / 2; i++) + if(modifier & CN_MODIFIER_REVERSE) { - pre_aes(); - aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a); - post_aes(); + for(i = 0; i < iters; i++) + { + pre_aes(); + aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a); + post_aes(1); + } + } + else + { + for(i = 0; i < iters; i++) + { + pre_aes(); + aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a); + post_aes(0); + } } } @@ -891,8 +916,8 @@ union cn_slow_hash_state _c = vld1q_u8(&hp_state[j]); \ _a = vld1q_u8((const uint8_t *)a); \ -#define post_aes() \ - VARIANT2_SHUFFLE_ADD_NEON(hp_state, j); \ +#define post_aes(reverse) \ + VARIANT2_SHUFFLE_ADD_NEON(hp_state, j, reverse); \ vst1q_u8((uint8_t *)c, _c); \ vst1q_u8(&hp_state[j], veorq_u8(_b, _c)); \ VARIANT1_1(&hp_state[j]); \ @@ -902,7 +927,7 @@ union cn_slow_hash_state VARIANT2_PORTABLE_INTEGER_MATH(b, c); \ __mul(); \ VARIANT2_2(); \ - VARIANT2_SHUFFLE_ADD_NEON(hp_state, j); \ + VARIANT2_SHUFFLE_ADD_NEON(hp_state, j, reverse); \ a[0] += hi; a[1] += lo; \ p = U64(&hp_state[j]); \ p[0] = a[0]; p[1] = a[1]; \ @@ -1062,7 +1087,7 @@ STATIC INLINE void aligned_free(void *ptr) } #endif /* FORCE_USE_HEAP */ -void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, int modifier) { RDATA_ALIGN16 uint8_t expandedKey[240]; @@ -1117,20 +1142,36 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1]; /* CryptoNight Step 3: Bounce randomly 1,048,576 times (1<<20) through the mixing buffer, - * using 524,288 iterations of the following mixing function. Each execution - * performs two reads and writes from the mixing buffer. + * using 524,288 (CryptoNight) or 393,216 (CryptoNight Waltz) iterations of the following + * mixing function. Each execution performs two reads and writes from the mixing buffer. */ _b = vld1q_u8((const uint8_t *)b); _b1 = vld1q_u8(((const uint8_t *)b) + AES_BLOCK_SIZE); - for(i = 0; i < ITER / 2; i++) + uint64_t iters = (modifier & CN_MODIFIER_WALTZ) ? (3 * ITER) / 8 : ITER / 2; + + if(modifier & CN_MODIFIER_REVERSE) { - pre_aes(); - _c = vaeseq_u8(_c, zero); - _c = vaesmcq_u8(_c); - _c = veorq_u8(_c, _a); - post_aes(); + for(i = 0; i < iters; i++) + { + pre_aes(); + _c = vaeseq_u8(_c, zero); + _c = vaesmcq_u8(_c); + _c = veorq_u8(_c, _a); + post_aes(1); + } + } + else + { + for(i = 0; i < iters; i++) + { + pre_aes(); + _c = vaeseq_u8(_c, zero); + _c = vaesmcq_u8(_c); + _c = veorq_u8(_c, _a); + post_aes(0); + } } /* CryptoNight Step 4: Sequentially pass through the mixing buffer and use 10 rounds @@ -1277,7 +1318,7 @@ STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b) U64(a)[1] ^= U64(b)[1]; } -void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, int modifier) { uint8_t text[INIT_SIZE_BYTE]; uint8_t a[AES_BLOCK_SIZE]; @@ -1331,7 +1372,10 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0]; U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1]; - for(i = 0; i < ITER / 2; i++) + uint64_t iters = (modifier & CN_MODIFIER_WALTZ) ? (3 * ITER) / 8 : ITER / 2; + uint8_t isReverse = (modifier & CN_MODIFIER_REVERSE) ? 1 : 0; + + for(i = 0; i < iters; i++) { #define MASK ((uint32_t)(((MEMORY / AES_BLOCK_SIZE) - 1) << 4)) #define state_index(x) ((*(uint32_t *) x) & MASK) @@ -1342,7 +1386,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int aesb_single_round(p, p, a); copy_block(c1, p); - VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j); + VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j, isReverse); xor_blocks(p, b); VARIANT1_1(p); @@ -1354,7 +1398,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int VARIANT2_PORTABLE_INTEGER_MATH(c, c1); mul(c1, c, d); VARIANT2_2_PORTABLE(); - VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j); + VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j, isReverse); sum_half_blocks(a, d); swap_blocks(a, c); xor_blocks(a, c); @@ -1478,7 +1522,7 @@ union cn_slow_hash_state { }; #pragma pack(pop) -void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed) { +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed, int modifier) { #ifndef FORCE_USE_HEAP uint8_t long_state[MEMORY]; #else @@ -1521,7 +1565,10 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int b[i] = state.k[AES_BLOCK_SIZE + i] ^ state.k[AES_BLOCK_SIZE * 3 + i]; } - for (i = 0; i < ITER / 2; i++) { + uint64_t iters = (modifier & CN_MODIFIER_WALTZ) ? (3 * ITER) / 8 : ITER / 2; + uint8_t isReverse = (modifier & CN_MODIFIER_REVERSE) ? 1 : 0; + + for (i = 0; i < iters; i++) { /* Dependency chain: address -> read value ------+ * written value <-+ hard function (AES or MUL) <+ * next address <-+ @@ -1530,7 +1577,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int j = e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; copy_block(c1, &long_state[j]); aesb_single_round(c1, c1, a); - VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j); + VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j, isReverse); copy_block(&long_state[j], c1); xor_blocks(&long_state[j], b); assert(j == e2i(a, MEMORY / AES_BLOCK_SIZE) * AES_BLOCK_SIZE); @@ -1541,7 +1588,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int VARIANT2_PORTABLE_INTEGER_MATH(c2, c1); mul(c1, c2, d); VARIANT2_2_PORTABLE(); - VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j); + VARIANT2_PORTABLE_SHUFFLE_ADD(long_state, j, isReverse); swap_blocks(a, c1); sum_half_blocks(c1, d); swap_blocks(c1, c2); diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index d4558ef7b..8af60ccc5 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -37,6 +37,7 @@ #include #include #include "serialization/variant.h" +#include "serialization/list.h" #include "serialization/vector.h" #include "serialization/binary_archive.h" #include "serialization/json_archive.h" @@ -134,9 +135,7 @@ namespace cryptonote END_SERIALIZE() }; - typedef boost::variant txin_v; - typedef boost::variant txout_target_v; //typedef std::pair out_t; @@ -153,6 +152,9 @@ namespace cryptonote }; + + + class transaction_prefix { @@ -168,15 +170,86 @@ namespace cryptonote BEGIN_SERIALIZE() VARINT_FIELD(version) - if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; + if (version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; VARINT_FIELD(unlock_time) FIELD(vin) FIELD(vout) FIELD(extra) END_SERIALIZE() - public: - transaction_prefix(){} + + }; + + /************************************************************************/ + /* */ + /************************************************************************/ + struct account_public_address + { + crypto::public_key m_spend_public_key; + crypto::public_key m_view_public_key; + + BEGIN_SERIALIZE_OBJECT() + FIELD(m_spend_public_key) + FIELD(m_view_public_key) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) + KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) + END_KV_SERIALIZE_MAP() + + bool operator==(const account_public_address& rhs) const + { + return m_spend_public_key == rhs.m_spend_public_key && + m_view_public_key == rhs.m_view_public_key; + } + + bool operator!=(const account_public_address& rhs) const + { + return !(*this == rhs); + } + }; + + // container for RTA identities (public keys) + // stores RTA payment ID, PoS public one-time identification key (used to identify PoS in the network and protect data for it), + // auth sample supernode public identification keys (graftnode will need it to validate auth sample signatures), + // PoS and Wallet Proxy Supernode identification keys to transaction_header.extra. + // TODO: better name? + struct rta_header + { + std::string payment_id; + // pre-defined key indexes for POS, POS Proxy and Wallet Proxy + static constexpr size_t POS_KEY_INDEX = 0; + static constexpr size_t POS_PROXY_KEY_INDEX = 1; + static constexpr size_t WALLET_PROXY_KEY_INDEX = 2; + uint64_t auth_sample_height = 0; // block height for auth sample generation + + std::vector keys; + BEGIN_SERIALIZE_OBJECT() + FIELD(payment_id) + FIELD(auth_sample_height) + FIELD(keys) + END_SERIALIZE() + bool operator== (const rta_header &other) const + { + return this->payment_id == other.payment_id + && this->keys == other.keys + && this->auth_sample_height == other.auth_sample_height; + } + }; + + struct rta_signature + { + size_t key_index; // reference to the corresponding pubkey. alternatively we can just iterate by matching signatures and keys + crypto::signature signature; + BEGIN_SERIALIZE_OBJECT() + FIELD(key_index) + FIELD(signature) + END_SERIALIZE() + bool operator== (const rta_signature &other) const + { + return this->signature == other.signature; + } }; class transaction: public transaction_prefix @@ -194,9 +267,26 @@ namespace cryptonote mutable crypto::hash hash; mutable size_t blob_size; + // graft: introducing transaction type. currently this field is not used to calculate tx hash + // TODO: probably move it to transaction_prefix.extra + enum tx_type { + // generic monero transaction; + tx_type_generic = 0, + // supernode 'zero-fee' transaction + tx_type_rta = 1, + tx_type_invalid = 255 + }; + // graft: tx type field + // TODO: consider to removed 'type' field. we can check if transaction is rta either by + // 1. checking if 'tx_extra_graft_rta_header' is present in tx_extra + // 2. simply checking tx version, so 'type' only needed for 'alpha' compatibilty. + size_t type = tx_type_generic; + + std::vector extra2; + transaction(); - transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } } - transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } return *this; } + transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), type(t.type), extra2(t.extra2) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } } + transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; type = t.type; extra2 = t.extra2; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } return *this; } virtual ~transaction(); void set_null(); void invalidate_hashes(); @@ -245,7 +335,7 @@ namespace cryptonote } ar.end_array(); } - else + else if (version >= 2) { ar.tag("rct_signatures"); if (!vin.empty()) @@ -265,6 +355,12 @@ namespace cryptonote } } } + // version >= 3 is rta transaction: allowed 0 fee and auth sample signatures + if (version >= 3) + { + FIELD(type) + FIELD(extra2) + } END_SERIALIZE() template class Archive> @@ -289,6 +385,7 @@ namespace cryptonote return true; } + private: static size_t get_signature_size(const txin_v& tx_in); }; @@ -318,6 +415,7 @@ namespace cryptonote rct_signatures.type = rct::RCTTypeNull; set_hash_valid(false); set_blob_size_valid(false); + type = tx_type_generic; } inline @@ -393,37 +491,6 @@ namespace cryptonote END_SERIALIZE() }; - - /************************************************************************/ - /* */ - /************************************************************************/ - struct account_public_address - { - crypto::public_key m_spend_public_key; - crypto::public_key m_view_public_key; - - BEGIN_SERIALIZE_OBJECT() - FIELD(m_spend_public_key) - FIELD(m_view_public_key) - END_SERIALIZE() - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key) - KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key) - END_KV_SERIALIZE_MAP() - - bool operator==(const account_public_address& rhs) const - { - return m_spend_public_key == rhs.m_spend_public_key && - m_view_public_key == rhs.m_view_public_key; - } - - bool operator!=(const account_public_address& rhs) const - { - return !(*this == rhs); - } - }; - struct keypair { crypto::public_key pub; diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index f113fbb09..3264fb432 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -114,9 +114,9 @@ namespace cryptonote { if (current_block_weight <= median_weight) { reward = base_reward; - if (version >= 10) { - // halving reward since version 10 - reward /= 2; + if (version >= 12) { // XXX Be careful when merging back to master, in master "halving" version is 10; LK: use version 12 instead of 10 during the merge + // halving reward since version 12 + reward /= 2; } return true; } @@ -144,8 +144,8 @@ namespace cryptonote { assert(reward_lo < base_reward); reward = reward_lo; - if (version >= 10) { - // halving reward since version 10 + if (version >= 12) { // XXX Be careful when merging back to master, in master "halving" version is 10; LK: use version 12 instead of 10 during merge + // halving reward since version 12 reward /= 2; } return true; diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 7d89a1693..97f34f214 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -621,7 +621,8 @@ namespace cryptonote << ", in transaction id=" << get_transaction_hash(tx)); } - return true; + return true; //TODO: validate tx + } //----------------------------------------------------------------------------------------------- bool check_outs_valid(const transaction& tx) @@ -1036,7 +1037,8 @@ namespace cryptonote // variant = 1 for versions between 8 and 11 // variant = 2 for versions 11 and greater const int cn_variant = b.major_version < 8 ? 0 : b.major_version >= 11 ? 2 : 1; - crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant); + const int cn_modifier = b.major_version < 12 ? CN_MODIFIER_NONE : CN_MODIFIER_REVERSE_WALTZ; + crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant, cn_modifier); return true; } //--------------------------------------------------------------- @@ -1182,4 +1184,145 @@ namespace cryptonote return ::serialization::parse_binary(graft_extra.data, graft_tx_extra); } + namespace + { + struct GraftStakeTxExtra + { + std::string supernode_public_id; + cryptonote::account_public_address supernode_public_address; + crypto::signature supernode_signature; + + GraftStakeTxExtra() = default; + + GraftStakeTxExtra(const std::string &supernode_public_id, + const cryptonote::account_public_address& supernode_public_address, + const crypto::signature &supernode_signature) : + supernode_public_id(supernode_public_id), + supernode_public_address(supernode_public_address), + supernode_signature(supernode_signature) + {} + + bool operator ==(const GraftStakeTxExtra &rhs) const { + return supernode_public_id == rhs.supernode_public_id && + !memcmp(&supernode_public_address.m_view_public_key.data[0], &rhs.supernode_public_address.m_view_public_key.data[0], + sizeof(supernode_public_address.m_view_public_key.data)) && + !memcmp(&supernode_signature.c.data[0], &rhs.supernode_signature.c.data[0], sizeof(supernode_signature.c.data)) && + !memcmp(&supernode_signature.r.data[0], &rhs.supernode_signature.r.data[0], sizeof(supernode_signature.r.data)); + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(supernode_public_id) + FIELD(supernode_public_address) + FIELD(supernode_signature) + END_SERIALIZE() + }; + } + + bool add_graft_stake_tx_extra_to_extra + (std::vector &extra, + const std::string &supernode_public_id, + const cryptonote::account_public_address &supernode_public_address, + const crypto::signature &supernode_signature) + { + GraftStakeTxExtra tx_extra(supernode_public_id, supernode_public_address, supernode_signature); + std::string blob; + ::serialization::dump_binary(tx_extra, blob); + tx_extra_graft_stake_tx container; + container.data = blob; + blob.clear(); + ::serialization::dump_binary(container, blob); + extra.push_back(TX_EXTRA_GRAFT_STAKE_TX_TAG); + std::copy(blob.begin(), blob.end(), std::back_inserter(extra)); + return true; + } + + bool add_graft_rta_header_to_extra(std::vector &extra, const rta_header &rta_header) + { + std::string blob; + ::serialization::dump_binary(const_cast(rta_header), blob); + tx_extra_graft_rta_header container; + container.data = blob; + blob.clear(); + ::serialization::dump_binary(container, blob); + extra.push_back(TX_EXTRA_GRAFT_RTA_HEADER_TAG); + std::copy(blob.begin(), blob.end(), std::back_inserter(extra)); + return true; + } + + bool get_graft_rta_header_from_extra(const transaction &tx, rta_header &rta_header) + { + std::vector tx_extra_fields; + parse_tx_extra(tx.extra, tx_extra_fields); + tx_extra_graft_rta_header rta_header_data; + if(!find_tx_extra_field_by_type(tx_extra_fields, rta_header_data)) + return false; + return ::serialization::parse_binary(rta_header_data.data, rta_header); + } + + bool add_graft_tx_secret_key_to_extra(std::vector &extra, const crypto::secret_key& secret_key) + { + tx_extra_graft_tx_secret_key container; + container.secret_key = secret_key; + std::string blob; + ::serialization::dump_binary(container, blob); + extra.push_back(TX_EXTRA_GRAFT_TX_SECRET_KEY_TAG); + std::copy(blob.begin(), blob.end(), std::back_inserter(extra)); + return true; + } + + bool get_graft_stake_tx_extra_from_extra + (const transaction &tx, + std::string &supernode_public_id, + cryptonote::account_public_address &supernode_public_address, + crypto::signature &supernode_signature, + crypto::secret_key &tx_secret_key) + { + std::vector tx_extra_fields; + parse_tx_extra(tx.extra, tx_extra_fields); + + tx_extra_graft_stake_tx stake_tx_extra; + + if(!find_tx_extra_field_by_type(tx_extra_fields, stake_tx_extra)) + return false; + + GraftStakeTxExtra stake_tx; + + if (!::serialization::parse_binary(stake_tx_extra.data, stake_tx)) + return false; + + tx_extra_graft_tx_secret_key stake_tx_secret_key_extra; + + if(!find_tx_extra_field_by_type(tx_extra_fields, stake_tx_secret_key_extra)) + return false; + + supernode_public_id = stake_tx.supernode_public_id; + supernode_public_address = stake_tx.supernode_public_address; + supernode_signature = stake_tx.supernode_signature; + tx_secret_key = stake_tx_secret_key_extra.secret_key; + + return true; + } + + bool add_graft_rta_signatures_to_extra2(std::vector &extra, const std::vector &rta_signatures) + { + std::string blob; + ::serialization::dump_binary(const_cast &>(rta_signatures), blob); + tx_extra_graft_rta_signatures container; + container.data = blob; + blob.clear(); + ::serialization::dump_binary(container, blob); + extra.push_back(TX_EXTRA_GRAFT_RTA_SIGNATURES_TAG); + std::copy(blob.begin(), blob.end(), std::back_inserter(extra)); + return true; + } + + bool get_graft_rta_signatures_from_extra2(const transaction &tx, std::vector &rta_signatures) + { + std::vector tx_extra_fields; + parse_tx_extra(tx.extra2, tx_extra_fields); + tx_extra_graft_rta_signatures rta_signatures_data; + if(!find_tx_extra_field_by_type(tx_extra_fields, rta_signatures_data)) + return false; + return ::serialization::parse_binary(rta_signatures_data.data, rta_signatures); + } } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 5898f24e0..67dcb208c 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -75,6 +75,97 @@ namespace cryptonote std::vector get_additional_tx_pub_keys_from_extra(const std::vector& tx_extra); std::vector get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx); bool add_additional_tx_pub_keys_to_extra(std::vector& tx_extra, const std::vector& additional_pub_keys); + + /*! + * \brief add_graft_tx_extra_to_extra - adds graft extra fields to tx + * \param tx - transaction fields to be added to + * \param graft_extra - graft fields to add + * \return - true on success + */ + // TODO: probably we will remove "..graft_tx_extra.." methods + bool add_graft_tx_extra_to_extra(transaction &tx, const supernode::GraftTxExtra &graft_extra); + + /*! + * @brief add_graft_tx_extra_to_extra - overloaded function to add graft extra directly to tx extra + * @param extra - extra to add fields to + * @param graft_extra - graft fields to add + * @return - true on success + */ + bool add_graft_tx_extra_to_extra(std::vector& extra, const supernode::GraftTxExtra &graft_extra); + + /*! + * \brief get_graft_tx_extra_from_extra - read graft extra fields from tx extra + * \param tx - source transaction + * \param graft_tx_extra - destination graft extra fields + * \return - true on success + */ + bool get_graft_tx_extra_from_extra(const transaction &tx, supernode::GraftTxExtra &graft_tx_extra); + + /*! + * \brief add_graft_stake_tx_extra_to_extra - adds graft stake transaction fields to extra + * \param extra - extra to add fields to + * \param supernode_public_id - public identifier of supernode + * \param supernode_wallet_id - supernode public wallet address + * \return - true on success + */ + bool add_graft_stake_tx_extra_to_extra(std::vector &extra, const std::string &supernode_public_id, + const cryptonote::account_public_address &supernode_public_address, const crypto::signature& supernode_signature); + + /*! + * \brief add_graft_tx_secret_key_to_extra - adds graft transaction secret key to extra + * \param extra - extra to add fields to + * \param secret_key - secret key + * \return - true on success + */ + bool add_graft_tx_secret_key_to_extra(std::vector &extra, const crypto::secret_key& secret_key); + + /*! + * \brief get_graft_stake_tx_extra_from_extra - gets graft stake transaction fields from extra + * \param tx - source transaction + * \param supernode_public_id - public identifier of supernode + * \param supernode_wallet_id - supernode public wallet address + * \param tx_secret_key - transaction secret key + * \return - true on success + */ + bool get_graft_stake_tx_extra_from_extra + (const transaction &tx, + std::string &supernode_public_id, + cryptonote::account_public_address &supernode_public_address, + crypto::signature &supernode_signature, + crypto::secret_key &tx_secret_key); + + /*! + * \brief add_graft_rta_header_to_extra - add rta_header to the extra + * \param extra - extra to add fields to + * \param rta_header - source rta_header + * \return - true on success + */ + bool add_graft_rta_header_to_extra(std::vector &extra, const rta_header &rta_header); + + /*! + * \brief get_graft_rta_header_from_extra - read rta_header from tx extra + * \param tx - input transaction + * \param rta_header - output rta_header + * \return - true on success + */ + bool get_graft_rta_header_from_extra(const transaction& tx, rta_header &rta_header); + + /*! + * \brief add_graft_rta_signatures_to_extra - add rta_signatures to the 'extra' container + * \param extra - 'extra' container + * \param rta_signatures - rta signatures to add + * \return - true on success + */ + bool add_graft_rta_signatures_to_extra2(std::vector &extra, const std::vector &rta_signatures); + + /*! + * \brief get_graft_rta_signatures_from_extra2 - read rta signatures from tx extra2 field + * \param tx - input transaction + * \param rta_signatures - output rta signatures + * \return - true on success + */ + bool get_graft_rta_signatures_from_extra2(const transaction& tx, std::vector &rta_signatures); + bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); bool remove_field_from_tx_extra(std::vector& tx_extra, const std::type_info &type); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 4f861eb4e..38e6af4ef 100644 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -30,6 +30,8 @@ #pragma once +#include "cryptonote_basic.h" // only need rta_header so it probably make sense to move it to separate file + #define TX_EXTRA_PADDING_MAX_COUNT 255 #define TX_EXTRA_NONCE_MAX_COUNT 255 @@ -39,6 +41,12 @@ #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04 + +#define TX_EXTRA_GRAFT_STAKE_TX_TAG 0x80 +#define TX_EXTRA_GRAFT_TX_SECRET_KEY_TAG 0x81 +#define TX_EXTRA_GRAFT_RTA_HEADER_TAG 0x83 +#define TX_EXTRA_GRAFT_RTA_SIGNATURES_TAG 0x84 + #define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 #define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01 @@ -79,7 +87,7 @@ namespace cryptonote template