diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ff1e3a0a..33dff274d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,6 @@ cmake_minimum_required(VERSION 2.8.7) project(graftnetwork) -set(DISABLE_SUPERNODE ${APPLE}) - function (die msg) if (NOT WIN32) string(ASCII 27 Esc) @@ -54,6 +52,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 @@ -109,6 +139,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 0) diff --git a/CMakeLists_IOS.txt b/CMakeLists_IOS.txt index 4dab94cb3..acaf33435 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 4f6e6465f..bc3fcce6a 100644 --- a/Makefile +++ b/Makefile @@ -51,9 +51,23 @@ cmake-release: mkdir -p build/release cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../.. +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 build/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 build/release cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) && $(MAKE) test @@ -66,6 +80,10 @@ release-static: 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) +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 build/debug cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test @@ -92,6 +110,10 @@ release-static-linux-x86_64: mkdir -p build/release cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" ../.. && $(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 build/release cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" ../.. && $(MAKE) diff --git a/README.md b/README.md index ead9dc5c9..a508969a7 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Dates are provided in the format YYYY-MM-DD. | 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-18 | v13 | 1.7.0 | 1.7.0 | RTA Mining | ## Installing Graft Network from a Package @@ -121,6 +122,8 @@ If you already have a repo cloned, initialize and update: cd GraftNetwork && git submodule init && git submodule update + + ### Build instructions Graft Network uses the CMake build system and a top-level [Makefile](Makefile) that 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 0c52d9273..8cc2239b2 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -55,16 +55,51 @@ #define MONERO_DEFAULT_LOG_CATEGORY "default" #endif -#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) @@ -72,20 +107,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) @@ -125,7 +160,10 @@ #endif std::string mlog_get_default_log_path(const char *default_filename); -void mlog_configure(const std::string &filename_base, bool console); + +// %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); void mlog_set_categories(const char *categories); void mlog_set_log_level(int level); void mlog_set_log(const char *log); 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 000305cfa..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()); - - 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 ca58d5467..09368580b 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. @@ -134,10 +151,12 @@ 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); + /// Buffer for incoming data. boost::array buffer_; - //boost::array buffer_; t_connection_context context; i_connection_filter* &m_pfilter; @@ -149,6 +168,7 @@ namespace net_utils std::list > > m_self_refs; // add_ref/release support critical_section m_self_refs_lock; critical_section m_chunking_lock; // held while we add small chunks of the big do_send() to small do_send_chunk() + critical_section m_shutdown_lock; // held while shutting down t_connection_type m_connection_type; @@ -158,8 +178,34 @@ namespace net_utils boost::mutex m_throttle_speed_in_mutex; boost::mutex m_throttle_speed_out_mutex; - public: - void setRpcStation(); + 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; + } + + callback.first = bytes_to_wait; + on_write_callback_list.push_back(callback); + m_send_que_lock.unlock(); + return true; + + } }; @@ -245,13 +291,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) { @@ -310,10 +356,148 @@ namespace net_utils boost::mutex connections_mutex; 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 698d267b3..3d3b288d5 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -81,7 +81,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_pfilter( pfilter ), m_connection_type( connection_type ), m_throttle_speed_in("speed_in", "throttle_speed_in"), - m_throttle_speed_out("speed_out", "throttle_speed_out") + m_throttle_speed_out("speed_out", "throttle_speed_out") { MINFO("test, connection constructor set m_connection_type="< 0) { - long int ms = (long int)(delay * 100); - boost::this_thread::sleep_for(boost::chrono::milliseconds(ms)); - } - } while(delay > 0); +// delay *= 0.5; +// if (delay > 0) { +// long int ms = (long int)(delay * 100); +// boost::this_thread::sleep_for(boost::chrono::milliseconds(ms)); +// } +// } while(delay > 0); } // any form of sleeping //_info("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred); @@ -390,18 +390,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="< 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); @@ -531,26 +525,25 @@ 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() 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 @@ -563,10 +556,14 @@ PRAGMA_WARNING_DISABLE_VS(4355) template bool connection::shutdown() { + CRITICAL_REGION_BEGIN(m_shutdown_lock); + if (m_was_shutdown) + return true; + m_was_shutdown = true; // Initiate graceful connection closure. boost::system::error_code ignored_ec; socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - m_was_shutdown = true; + CRITICAL_REGION_END(); m_protocol_handler.release_protocol(); return true; } @@ -575,6 +572,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) bool connection::close() { TRY_ENTRY(); + auto self = safe_shared_from_this(); + if(!self) + return false; //_info("[sock " << socket_.native_handle() << "] Que Shutdown called."); size_t send_que_size = 0; CRITICAL_REGION_BEGIN(m_send_que_lock); @@ -597,31 +597,60 @@ 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 (speed_limit_is_enabled()) { - sleep_before_packet(cb, 1, 1); - } +#if 0 // Hang io thread for any time by sleep instruction is a bad idea + if (speed_limit_is_enabled()) { + sleep_before_packet(cb, 1, 1); + } +#endif // Comment thread sleep instructions 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()) { @@ -634,25 +663,57 @@ PRAGMA_WARNING_DISABLE_VS(4355) //have more data to send 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() @@ -664,7 +725,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 ; } /************************************************************************/ @@ -681,6 +742,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"; @@ -695,6 +757,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"; 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/http_client.h b/contrib/epee/include/net/http_client.h index 8e099e2bc..5231cbd15 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -234,8 +234,521 @@ using namespace std; - 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 + class http_simple_client: public i_target_handler { @@ -260,7 +773,7 @@ using namespace std; }; - blocked_mode_client m_net_client; + blocked_mode_client m_net_client; std::string m_host_buff; std::string m_port; http_client_auth m_auth; @@ -276,9 +789,9 @@ using namespace std; critical_section m_lock; public: - explicit http_simple_client() + explicit http_simple_client(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() @@ -437,60 +950,60 @@ using namespace std; 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 60a667690..f007ccc76 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -35,6 +35,7 @@ #include "levin_base.h" #include "misc_language.h" +#include "async_state_machine.h" #include #include @@ -51,12 +52,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 { @@ -68,9 +75,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 - 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) { @@ -171,7 +182,7 @@ class async_protocol_handler m_timer_started = true; } } - virtual ~anvoke_handler() + virtual ~invoke_handler() {} callback_t m_cb; async_protocol_handler& m_con; @@ -242,7 +253,7 @@ class async_protocol_handler bool add_invoke_response_handler(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(); } @@ -563,18 +574,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); @@ -867,5 +879,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 1d808cc4c..3fa517507 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -46,6 +46,10 @@ #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" @@ -60,10 +64,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) @@ -82,14 +269,17 @@ namespace net_utils ref_bytes_transferred = bytes_transferred; } }; - + public: inline - blocked_mode_client():m_socket(m_io_service), - m_initialized(false), - m_connected(false), - m_deadline(m_io_service), - m_shutdowned(0) + blocked_mode_client(boost::shared_ptr ios + = boost::shared_ptr{new boost::asio::io_service()}) + : m_io_service{ios}, + m_socket(*m_io_service), + m_initialized(false), + m_connected(false), + m_deadline(*m_io_service), + m_shutdowned(0) { @@ -130,7 +320,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; @@ -164,7 +354,7 @@ namespace net_utils m_socket.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_socket.is_open()) @@ -245,7 +435,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) @@ -375,7 +565,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(); } @@ -458,7 +648,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) @@ -515,7 +705,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() @@ -551,7 +741,7 @@ namespace net_utils protected: - boost::asio::io_service m_io_service; + boost::shared_ptr m_io_service; boost::asio::ip::tcp::socket m_socket; bool m_initialized; bool m_connected; @@ -566,7 +756,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 @@ -670,6 +860,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 ef3a1d146..733757a53 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -116,8 +116,8 @@ namespace net_utils bool is_loopback() const { return (*this)->is_loopback(); } bool is_local() const { return (*this)->is_local(); } uint8_t get_type_id() const { return (*this)->get_type_id(); } - template Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); } - template const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); } + template Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); } + template const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); } BEGIN_KV_SERIALIZE_MAP() uint8_t type = is_store ? this_ref.get_type_id() : 0; @@ -192,6 +192,10 @@ namespace net_utils connection_context_base& operator=(const connection_context_base& a) { + if(&a == this) { + MWARNING("self assignment for " << m_connection_id << "(" << this << ")"); + return *this; + } set_details(a.m_connection_id, a.m_remote_address, a.m_is_income); return *this; } 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/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 823ce6731..433038647 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -66,6 +66,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 f5dd4842c..3ec022b65 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -27,9 +27,9 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. if (USE_READLINE AND GNU_READLINE_FOUND) - add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp memwipe.c readline_buffer.cpp) + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp memwipe.c async_state_machine.cpp readline_buffer.cpp) else() - add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp memwipe.c) + add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp memwipe.c 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/mlog.cpp b/contrib/epee/src/mlog.cpp index 0d6e48ee6..1af90cd34 100644 --- a/contrib/epee/src/mlog.cpp +++ b/contrib/epee/src/mlog.cpp @@ -39,6 +39,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) @@ -112,14 +116,34 @@ static const char *get_default_categories(int level) return categories; } -void mlog_configure(const std::string &filename_base, bool console) +// %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) { + //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, "104850000"); // 100 MB - 7600 bytes diff --git a/install_dependencies.sh b/install_dependencies.sh index 063372f9d..001389286 100755 --- a/install_dependencies.sh +++ b/install_dependencies.sh @@ -17,12 +17,7 @@ sudo apt-get install -y \ libldns-dev \ libexpat1-dev \ doxygen \ - graphviz - -if [ ${VER[1]} == "18.04" ]; then - sudo apt-get install -y libssl1.0-dev -else - sudo apt-get install -y libssl-dev -fi + graphviz \ + libssl-dev sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ 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 8c3d0b0aa..ad49f3ba1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,9 +109,7 @@ if(NOT IOS) add_subdirectory(rpc) endif() add_subdirectory(wallet) -if (NOT DISABLE_SUPERNODE) add_subdirectory(supernode) -endif() if(NOT IOS) add_subdirectory(p2p) endif() @@ -121,6 +119,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/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index c4adf1fcb..213a05283 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -139,9 +139,7 @@ namespace cryptonote END_SERIALIZE() }; - typedef boost::variant txin_v; - typedef boost::variant txout_target_v; //typedef std::pair out_t; @@ -158,6 +156,9 @@ namespace cryptonote }; + + + class transaction_prefix { @@ -173,15 +174,75 @@ 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() + }; + + // 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 @@ -199,9 +260,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 = 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(); @@ -250,7 +328,7 @@ namespace cryptonote } ar.end_array(); } - else + else if (version >= 2) { ar.tag("rct_signatures"); if (!vin.empty()) @@ -270,6 +348,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> @@ -294,6 +378,7 @@ namespace cryptonote return true; } + private: static size_t get_signature_size(const txin_v& tx_in); }; @@ -323,6 +408,7 @@ namespace cryptonote rct_signatures.type = rct::RCTTypeNull; set_hash_valid(false); set_blob_size_valid(false); + type = tx_type_generic; } inline @@ -399,24 +485,7 @@ namespace cryptonote }; - /************************************************************************/ - /* */ - /************************************************************************/ - 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() - }; struct keypair { diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index f046e769d..81af83d2f 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -114,8 +114,8 @@ namespace cryptonote { if (current_block_size <= median_size) { reward = base_reward; - 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 + // 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 + // 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 2286e7056..c9e9f5bf5 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -413,7 +413,8 @@ namespace cryptonote << ", in transaction id=" << get_transaction_hash(tx)); } - return true; + return true; //TODO: validate tx + } //----------------------------------------------------------------------------------------------- bool check_outs_valid(const transaction& tx) @@ -882,5 +883,146 @@ 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 56899ba7e..1de517e8c 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -72,6 +72,7 @@ namespace cryptonote * \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); /*! @@ -89,6 +90,72 @@ namespace cryptonote * \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 4bc81121e..1c040c7ce 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 @@ -38,7 +40,14 @@ #define TX_EXTRA_TAG_PUBKEY 0x01 #define TX_EXTRA_NONCE 0x02 #define TX_EXTRA_MERGE_MINING_TAG 0x03 +// TODO: suggested to remove #define TX_EXTRA_GRAFT_EXTRA_TAG 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 @@ -79,7 +88,7 @@ namespace cryptonote template