aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/epee/LICENSE.txt25
-rw-r--r--contrib/epee/README.md1
-rw-r--r--contrib/epee/demo/.gitignore1
-rw-r--r--contrib/epee/demo/CMakeLists.txt49
-rw-r--r--contrib/epee/demo/README.txt0
-rw-r--r--contrib/epee/demo/demo_http_server/demo_http_server.cpp217
-rw-r--r--contrib/epee/demo/demo_http_server/demo_http_server.h101
-rw-r--r--contrib/epee/demo/demo_http_server/stdafx.cpp8
-rw-r--r--contrib/epee/demo/demo_http_server/stdafx.h40
-rw-r--r--contrib/epee/demo/demo_http_server/targetver.h13
-rw-r--r--contrib/epee/demo/demo_levin_server/demo_levin_server.cpp200
-rw-r--r--contrib/epee/demo/demo_levin_server/demo_levin_server.h76
-rw-r--r--contrib/epee/demo/demo_levin_server/stdafx.cpp30
-rw-r--r--contrib/epee/demo/demo_levin_server/stdafx.h41
-rw-r--r--contrib/epee/demo/demo_levin_server/targetver.h13
-rw-r--r--contrib/epee/demo/generate_gcc.sh4
-rw-r--r--contrib/epee/demo/generate_vc_proj.bat7
-rw-r--r--contrib/epee/demo/iface/transport_defs.h213
-rw-r--r--contrib/epee/include/ado_db_helper.h1095
-rw-r--r--contrib/epee/include/console_handler.h310
-rw-r--r--contrib/epee/include/file_io_utils.h455
-rw-r--r--contrib/epee/include/global_stream_operators.h35
-rw-r--r--contrib/epee/include/gzip_encoding.h227
-rw-r--r--contrib/epee/include/hmac-md5.h93
-rw-r--r--contrib/epee/include/include_base_utils.h34
-rw-r--r--contrib/epee/include/math_helper.h272
-rw-r--r--contrib/epee/include/md5_l.h97
-rw-r--r--contrib/epee/include/md5_l.inl563
-rw-r--r--contrib/epee/include/md5global.h77
-rw-r--r--contrib/epee/include/misc_language.h162
-rw-r--r--contrib/epee/include/misc_log_ex.h1426
-rw-r--r--contrib/epee/include/misc_os_dependent.h108
-rw-r--r--contrib/epee/include/net/abstract_tcp_server.h316
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h276
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl811
-rw-r--r--contrib/epee/include/net/abstract_tcp_server_cp.h233
-rw-r--r--contrib/epee/include/net/abstract_tcp_server_cp.inl605
-rw-r--r--contrib/epee/include/net/http_base.h184
-rw-r--r--contrib/epee/include/net/http_client.h875
-rw-r--r--contrib/epee/include/net/http_client_abstract_invoke.h98
-rw-r--r--contrib/epee/include/net/http_client_base.h73
-rw-r--r--contrib/epee/include/net/http_client_via_api_helper.h177
-rw-r--r--contrib/epee/include/net/http_protocol_handler.h209
-rw-r--r--contrib/epee/include/net/http_protocol_handler.inl664
-rw-r--r--contrib/epee/include/net/http_server_cp.h48
-rw-r--r--contrib/epee/include/net/http_server_cp2.h47
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h260
-rw-r--r--contrib/epee/include/net/http_server_impl_base.h112
-rw-r--r--contrib/epee/include/net/http_server_thread_per_connect.h48
-rw-r--r--contrib/epee/include/net/levin_base.h125
-rw-r--r--contrib/epee/include/net/levin_client.h89
-rw-r--r--contrib/epee/include/net/levin_client.inl194
-rw-r--r--contrib/epee/include/net/levin_client_async.h577
-rw-r--r--contrib/epee/include/net/levin_client_async.inl0
-rw-r--r--contrib/epee/include/net/levin_helper.h137
-rw-r--r--contrib/epee/include/net/levin_protocol_handler.h178
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h778
-rw-r--r--contrib/epee/include/net/levin_server_cp.h47
-rw-r--r--contrib/epee/include/net/levin_server_cp2.h49
-rw-r--r--contrib/epee/include/net/local_ip.h72
-rw-r--r--contrib/epee/include/net/multiprotocols_server.h47
-rw-r--r--contrib/epee/include/net/munin_connection_handler.h376
-rw-r--r--contrib/epee/include/net/munin_node_server.h49
-rw-r--r--contrib/epee/include/net/net_helper.h683
-rw-r--r--contrib/epee/include/net/net_parse_helpers.h168
-rw-r--r--contrib/epee/include/net/net_utils_base.h150
-rw-r--r--contrib/epee/include/net/protocol_switcher.h121
-rw-r--r--contrib/epee/include/net/rpc_method_name.h31
-rw-r--r--contrib/epee/include/net/smtp.h181
-rw-r--r--contrib/epee/include/net/smtp.inl1569
-rw-r--r--contrib/epee/include/net/smtp_helper.h88
-rw-r--r--contrib/epee/include/pragma_comp_defs.h14
-rw-r--r--contrib/epee/include/profile_tools.h111
-rw-r--r--contrib/epee/include/reg_exp_definer.h84
-rw-r--r--contrib/epee/include/reg_utils.h249
-rw-r--r--contrib/epee/include/serialization/enableable.h53
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization.h92
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization_overloads.h366
-rw-r--r--contrib/epee/include/serialization/serialize_base.h2
-rw-r--r--contrib/epee/include/service_impl_base.h323
-rw-r--r--contrib/epee/include/sha1.h51
-rw-r--r--contrib/epee/include/sha1.inl179
-rw-r--r--contrib/epee/include/soci_helper.h142
-rw-r--r--contrib/epee/include/static_initializer.h82
-rw-r--r--contrib/epee/include/storages/activity_notifier.h132
-rw-r--r--contrib/epee/include/storages/crypted_storage.h62
-rw-r--r--contrib/epee/include/storages/gzipped_inmemstorage.h68
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h126
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h289
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h260
-rw-r--r--contrib/epee/include/storages/portable_storage.h463
-rw-r--r--contrib/epee/include/storages/portable_storage_base.h160
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h281
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h379
-rw-r--r--contrib/epee/include/storages/portable_storage_template_helper.h120
-rw-r--r--contrib/epee/include/storages/portable_storage_to_bin.h212
-rw-r--r--contrib/epee/include/storages/portable_storage_to_json.h172
-rw-r--r--contrib/epee/include/storages/portable_storage_val_converters.h169
-rw-r--r--contrib/epee/include/string_coding.h295
-rw-r--r--contrib/epee/include/string_tools.h736
-rw-r--r--contrib/epee/include/syncobj.h241
-rw-r--r--contrib/epee/include/time_helper.h159
-rw-r--r--contrib/epee/include/tiny_ini.h75
-rw-r--r--contrib/epee/include/to_nonconst_iterator.h52
-rw-r--r--contrib/epee/include/warnings.h30
-rw-r--r--contrib/epee/include/winobj.h227
-rw-r--r--contrib/epee/include/zlib_helper.h139
-rw-r--r--contrib/epee/tests/.gitignore1
-rw-r--r--contrib/epee/tests/data/storages/invalid_storage_1.binbin0 -> 109577 bytes
-rw-r--r--contrib/epee/tests/data/storages/invalid_storage_2.binbin0 -> 20 bytes
-rw-r--r--contrib/epee/tests/data/storages/invalid_storage_3.bin1
-rw-r--r--contrib/epee/tests/data/storages/invalid_storage_4.binbin0 -> 18 bytes
-rw-r--r--contrib/epee/tests/data/storages/valid_storage.binbin0 -> 180345 bytes
-rw-r--r--contrib/epee/tests/generate_vc_proj.bat5
-rw-r--r--contrib/epee/tests/src/CMakeLists.txt33
-rw-r--r--contrib/epee/tests/src/misc/test_math.h82
-rw-r--r--contrib/epee/tests/src/net/test_net.h403
-rw-r--r--contrib/epee/tests/src/storages/portable_storages_test.h232
-rw-r--r--contrib/epee/tests/src/storages/storage_tests.h142
-rw-r--r--contrib/epee/tests/src/tests.cpp59
120 files changed, 24291 insertions, 0 deletions
diff --git a/contrib/epee/LICENSE.txt b/contrib/epee/LICENSE.txt
new file mode 100644
index 000000000..4a6b529e5
--- /dev/null
+++ b/contrib/epee/LICENSE.txt
@@ -0,0 +1,25 @@
+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 Andrey N. Sabelnikov 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. \ No newline at end of file
diff --git a/contrib/epee/README.md b/contrib/epee/README.md
new file mode 100644
index 000000000..a69884f57
--- /dev/null
+++ b/contrib/epee/README.md
@@ -0,0 +1 @@
+epee - is a small library of helpers, wrappers, tools and and so on, used to make my life easier. \ No newline at end of file
diff --git a/contrib/epee/demo/.gitignore b/contrib/epee/demo/.gitignore
new file mode 100644
index 000000000..d9b4f015d
--- /dev/null
+++ b/contrib/epee/demo/.gitignore
@@ -0,0 +1 @@
+/build/*
diff --git a/contrib/epee/demo/CMakeLists.txt b/contrib/epee/demo/CMakeLists.txt
new file mode 100644
index 000000000..b4ac2cc8b
--- /dev/null
+++ b/contrib/epee/demo/CMakeLists.txt
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 2.8)
+set(Boost_USE_MULTITHREADED ON)
+#set(Boost_DEBUG 1)
+find_package(Boost COMPONENTS system filesystem thread date_time chrono regex )
+
+include_directories( ${Boost_INCLUDE_DIRS} )
+
+
+IF (MSVC)
+ add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /nologo /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /bigobj" )
+ELSE()
+ # set stuff for other systems
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder -D_GNU_SOURCE")
+ENDIF()
+
+
+include_directories(.)
+include_directories(../include)
+include_directories(iface)
+
+
+# Add folders to filters
+file(GLOB_RECURSE LEVIN_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.inl
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.cpp)
+
+file(GLOB_RECURSE HTTP_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.inl
+ ${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.cpp)
+
+
+
+source_group(general FILES ${LEVIN_GENERAL_SECTION} FILES ${HTTP_GENERAL_SECTION})
+#source_group(general FILES ${HTTP_GENERAL_SECTION})
+
+add_executable(demo_http_server ${HTTP_GENERAL_SECTION} )
+add_executable(demo_levin_server ${LEVIN_GENERAL_SECTION} )
+
+target_link_libraries( demo_http_server ${Boost_LIBRARIES} )
+target_link_libraries( demo_levin_server ${Boost_LIBRARIES} )
+
+IF (NOT WIN32)
+ target_link_libraries (demo_http_server rt)
+ target_link_libraries (demo_levin_server rt)
+ENDIF()
+
+
diff --git a/contrib/epee/demo/README.txt b/contrib/epee/demo/README.txt
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/contrib/epee/demo/README.txt
diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.cpp b/contrib/epee/demo/demo_http_server/demo_http_server.cpp
new file mode 100644
index 000000000..f614da6c5
--- /dev/null
+++ b/contrib/epee/demo/demo_http_server/demo_http_server.cpp
@@ -0,0 +1,217 @@
+// 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.
+//
+
+#include "stdafx.h"
+#include "console_handler.h"
+#include "demo_http_server.h"
+#include "net/http_client.h"
+#include "storages/http_abstract_invoke.h"
+
+
+template<class t_request, class t_response>
+bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false)
+{
+ epee::net_utils::http::http_simple_client http_client;
+ bool r = http_client.connect(ip, port, 1000);
+ CHECK_AND_ASSERT_MES(r, false, "failed to connect");
+ if(use_json)
+ {
+ if(use_jrpc)
+ {
+ epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
+ req_t.params = req;
+ req_t.id = "10";
+ req_t.method = "command_example_1";
+ req_t.version = "1.1";
+ epee::json_rpc::response<t_response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+ if(!epee::net_utils::invoke_http_json_remote_command2("/request_json_rpc", req_t, resp_t, http_client))
+ {
+ return false;
+ }
+ rsp = resp_t.result;
+ return true;
+ }else
+ return epee::net_utils::invoke_http_json_remote_command2(url, req, rsp, http_client);
+ }
+ else
+ return epee::net_utils::invoke_http_bin_remote_command2(url, req, rsp, http_client);
+}
+
+
+int main(int argc, char* argv[])
+{
+ TRY_ENTRY();
+ string_tools::set_module_name_and_folder(argv[0]);
+
+ //set up logging options
+ log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
+ log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
+ log_space::log_singletone::add_logger(LOGGER_FILE,
+ log_space::log_singletone::get_default_log_file().c_str(),
+ log_space::log_singletone::get_default_log_folder().c_str());
+
+
+
+ LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
+
+
+ demo::demo_http_server srv;
+
+ start_default_console(&srv);
+
+ std::string bind_param = "0.0.0.0";
+ std::string port = "83";
+
+ if(!srv.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ //log loop
+ srv.run();
+ size_t count = 0;
+ while (!srv.is_stop())
+ {
+
+ demo::COMMAND_EXAMPLE_1::request req;
+ req.sub = demo::get_test_data();
+ demo::COMMAND_EXAMPLE_1::response rsp;
+ bool r = false;
+ if(count%2)
+ {//invoke json
+ r = communicate("/request_api_json_1", req, rsp, "127.0.0.1", port, true, true);
+ }else{
+ r = communicate("/request_api_bin_1", req, rsp, "127.0.0.1", port, false);
+ }
+ CHECK_AND_ASSERT_MES(r, false, "failed to invoke http request");
+ CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
+ //misc_utils::sleep_no_w(1000);
+ ++count;
+ }
+ bool r = srv.wait_stop();
+ CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
+ srv.deinit();
+
+ LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
+ return 1;
+
+ CATCH_ENTRY_L0("main", 1);
+}
+
+/************************************************************************/
+/* */
+/************************************************************************/
+namespace demo
+{
+ bool demo_http_server::init(const std::string& bind_port, const std::string& bind_ip)
+ {
+
+
+ //set self as callback handler
+ m_net_server.get_config_object().m_phandler = this;
+
+ //here set folder for hosting reqests
+ m_net_server.get_config_object().m_folder = "";
+
+ LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
+ return m_net_server.init_server(bind_port, bind_ip);
+ }
+
+ bool demo_http_server::run()
+ {
+ m_stop = false;
+ //here you can set worker threads count
+ int thrds_count = 4;
+
+ //go to loop
+ LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
+ if(!m_net_server.run_server(thrds_count, false))
+ {
+ LOG_ERROR("Failed to run net tcp server!");
+ }
+
+ return true;
+ }
+
+ bool demo_http_server::deinit()
+ {
+ return m_net_server.deinit_server();
+ }
+
+ bool demo_http_server::send_stop_signal()
+ {
+ m_stop = true;
+ m_net_server.send_stop_signal();
+ return true;
+ }
+
+ bool demo_http_server::on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context)
+ {
+ return true;
+ }
+
+
+ bool demo_http_server::on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context)
+ {
+ return true;
+ }
+
+
+ bool demo_http_server::on_hosting_request( const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context)
+ {
+ //read file from filesystem here
+ return true;
+ }
+
+ bool demo_http_server::on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res)
+ {
+ CHECK_AND_ASSERT_MES(req.sub == demo::get_test_data(), false, "wrong request");
+ res.m_success = true;
+ res.subs.push_back(req.sub);
+ return true;
+ }
+
+ bool demo_http_server::on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp)
+ {
+ error_resp.code = 232432;
+ error_resp.message = "bla bla bla";
+ return false;
+ }
+
+ bool demo_http_server::on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res)
+ {
+ return true;
+ }
+}
diff --git a/contrib/epee/demo/demo_http_server/demo_http_server.h b/contrib/epee/demo/demo_http_server/demo_http_server.h
new file mode 100644
index 000000000..bb8f9bffa
--- /dev/null
+++ b/contrib/epee/demo/demo_http_server/demo_http_server.h
@@ -0,0 +1,101 @@
+// 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 <boost/thread.hpp>
+#include <boost/bind.hpp>
+
+#include "net/http_server_cp2.h"
+#include "transport_defs.h"
+#include "net/http_server_handlers_map2.h"
+
+using namespace epee;
+
+namespace demo
+{
+
+ class demo_http_server: public net_utils::http::i_http_server_handler
+ {
+ public:
+ demo_http_server():m_stop(false){}
+ bool run();
+ bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
+ bool deinit();
+ bool send_stop_signal();
+ bool is_stop(){return m_stop;}
+ bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
+ private:
+
+
+ CHAIN_HTTP_TO_MAP2(); //forward http requests to uri map
+
+ BEGIN_URI_MAP2()
+ MAP_URI2("/requestr_uri_1", on_requestr_uri_1)
+ MAP_URI2("/requestr_uri_2", on_requestr_uri_1)
+ //MAP_URI_AUTO_XML2("/request_api_xml_1", on_request_api_1, COMMAND_EXAMPLE_1)
+ //MAP_URI_AUTO_XML2("/request_api_xml_2", on_request_api_2, COMMAND_EXAMPLE_2)
+ MAP_URI_AUTO_JON2("/request_api_json_1", on_request_api_1, COMMAND_EXAMPLE_1)
+ MAP_URI_AUTO_JON2("/request_api_json_2", on_request_api_2, COMMAND_EXAMPLE_2)
+ MAP_URI_AUTO_BIN2("/request_api_bin_1", on_request_api_1, COMMAND_EXAMPLE_1)
+ MAP_URI_AUTO_BIN2("/request_api_bin_2", on_request_api_2, COMMAND_EXAMPLE_2)
+ BEGIN_JSON_RPC_MAP("/request_json_rpc")
+ MAP_JON_RPC("command_example_1", on_request_api_1, COMMAND_EXAMPLE_1)
+ MAP_JON_RPC("command_example_2", on_request_api_2, COMMAND_EXAMPLE_2)
+ MAP_JON_RPC_WE("command_example_1_we", on_request_api_1_with_error, COMMAND_EXAMPLE_1)
+ END_JSON_RPC_MAP()
+ CHAIN_URI_MAP2(on_hosting_request)
+ END_URI_MAP2()
+
+
+
+ bool on_requestr_uri_1(const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context);
+
+
+ bool on_requestr_uri_2(const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context);
+
+
+
+
+ bool on_hosting_request( const net_utils::http::http_request_info& query_info,
+ net_utils::http::http_response_info& response,
+ const net_utils::connection_context_base& m_conn_context);
+
+ bool on_request_api_1(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res);
+ bool on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res);
+
+ bool on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp);
+
+ net_utils::boosted_http_server_custum_handling m_net_server;
+ std::atomic<bool> m_stop;
+ };
+}
+
diff --git a/contrib/epee/demo/demo_http_server/stdafx.cpp b/contrib/epee/demo/demo_http_server/stdafx.cpp
new file mode 100644
index 000000000..ecec24657
--- /dev/null
+++ b/contrib/epee/demo/demo_http_server/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// demo_http_server.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/contrib/epee/demo/demo_http_server/stdafx.h b/contrib/epee/demo/demo_http_server/stdafx.h
new file mode 100644
index 000000000..e28883202
--- /dev/null
+++ b/contrib/epee/demo/demo_http_server/stdafx.h
@@ -0,0 +1,40 @@
+// 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 "targetver.h"
+
+
+#include <stdio.h>
+
+
+#define BOOST_FILESYSTEM_VERSION 3
+#define ENABLE_RELEASE_LOGGING
+#include "misc_log_ex.h"
+
+
diff --git a/contrib/epee/demo/demo_http_server/targetver.h b/contrib/epee/demo/demo_http_server/targetver.h
new file mode 100644
index 000000000..6fe8eb79e
--- /dev/null
+++ b/contrib/epee/demo/demo_http_server/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp b/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
new file mode 100644
index 000000000..215b1dd48
--- /dev/null
+++ b/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
@@ -0,0 +1,200 @@
+// 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.
+//
+
+
+
+#include "stdafx.h"
+#include "demo_levin_server.h"
+#include "console_handler.h"
+
+
+template<class t_request>
+bool communicate(net_utils::boosted_levin_async_server& transport, int id, t_request& req, const std::string& ip, const std::string& port, bool use_async)
+{
+ if(use_async)
+ {
+ //IMPORTANT: do not pass local parameters from stack by reference! connect_async returns immediately, and callback will call in any thread later
+ transport.connect_async(ip, port, 10000, [&transport, id, req, ip, port](net_utils::connection_context_base& ctx, const boost::system::error_code& ec_)
+ {
+ if(!!ec_)
+ {
+ LOG_ERROR("Failed to connect to " << ip << ":" << port);
+ }else
+ {//connected ok!
+
+ epee::net_utils::async_invoke_remote_command2<demo::COMMAND_EXAMPLE_1::response>(ctx.m_connection_id, id, req, transport.get_config_object(), [&transport, ip, port](int res_code, demo::COMMAND_EXAMPLE_1::response& rsp, net_utils::connection_context_base& ctx)
+ {
+ if(res_code < 0)
+ {
+ LOG_ERROR("Failed to invoke to " << ip << ":" << port);
+ }else
+ {//invoked ok
+ CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
+ LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoked ok", LOG_LEVEL_0);
+ }
+ transport.get_config_object().close(ctx.m_connection_id);
+ return true;
+ });
+ LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoke requested", LOG_LEVEL_0);
+ }
+ });
+ }else
+ {
+ net_utils::connection_context_base ctx = AUTO_VAL_INIT(ctx);
+ bool r = transport.connect(ip, port, 10000, ctx);
+ CHECK_AND_ASSERT_MES(r, false, "failed to connect to " << ip << ":" << port);
+ demo::COMMAND_EXAMPLE_1::response rsp = AUTO_VAL_INIT(rsp);
+ LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoke requested", LOG_LEVEL_0);
+ r = epee::net_utils::invoke_remote_command2(ctx.m_connection_id, id, req, rsp, transport.get_config_object());
+ CHECK_AND_ASSERT_MES(r, false, "failed to invoke levin request");
+ CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
+ CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
+ transport.get_config_object().close(ctx.m_connection_id);
+ LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoked ok", LOG_LEVEL_0);
+ }
+ return true;
+}
+
+
+int main(int argc, char* argv[])
+{
+ TRY_ENTRY();
+ string_tools::set_module_name_and_folder(argv[0]);
+
+ //set up logging options
+ log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
+ log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
+ log_space::log_singletone::add_logger(LOGGER_FILE,
+ log_space::log_singletone::get_default_log_file().c_str(),
+ log_space::log_singletone::get_default_log_folder().c_str());
+
+
+
+ LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
+
+
+ demo::demo_levin_server srv;
+
+ start_default_console(&srv);
+
+ std::string bind_param = "0.0.0.0";
+ std::string port = "12345";
+
+ if(!srv.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ srv.run();
+
+ size_t c = 1;
+ while (!srv.is_stop())
+ {
+
+ demo::COMMAND_EXAMPLE_1::request req;
+ req.sub = demo::get_test_data();
+ bool r = communicate(srv.get_server(), demo::COMMAND_EXAMPLE_1::ID, req, "127.0.0.1", port, (c%2 == 0));
+ misc_utils::sleep_no_w(1000);
+ ++c;
+ }
+ bool r = srv.wait_stop();
+ CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
+
+
+ srv.deinit();
+
+ LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
+ return 1;
+
+ CATCH_ENTRY_L0("main", 1);
+}
+
+/************************************************************************/
+/* */
+/************************************************************************/
+namespace demo
+{
+ bool demo_levin_server::init(const std::string& bind_port, const std::string& bind_ip)
+ {
+ m_net_server.get_config_object().m_pcommands_handler = this;
+ LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
+ return m_net_server.init_server(bind_port, bind_ip);
+ }
+
+ bool demo_levin_server::run()
+ {
+ m_stop = false;
+ //here you can set worker threads count
+ int thrds_count = 4;
+ m_net_server.get_config_object().m_invoke_timeout = 10000;
+ m_net_server.get_config_object().m_pcommands_handler = this;
+
+ //go to loop
+ LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
+ if(!m_net_server.run_server(thrds_count, false))
+ {
+ LOG_ERROR("Failed to run net tcp server!");
+ }
+
+ LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
+ return true;
+ }
+
+ bool demo_levin_server::deinit()
+ {
+ return m_net_server.deinit_server();
+ }
+
+ bool demo_levin_server::send_stop_signal()
+ {
+ m_net_server.send_stop_signal();
+ return true;
+ }
+ int demo_levin_server::handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context)
+ {
+ CHECK_AND_ASSERT_MES(arg.sub == demo::get_test_data(), false, "wrong request");
+ rsp.m_success = true;
+ rsp.subs.push_back(arg.sub);
+ LOG_PRINT_GREEN("Server COMMAND_EXAMPLE_1 ok", LOG_LEVEL_0);
+ return 1;
+ }
+ int demo_levin_server::handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
+ {
+ return 1;
+ }
+ int demo_levin_server::handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context)
+ {
+ return 1;
+ }
+ int demo_levin_server::handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context)
+ {
+ return 1;
+ }
+}
diff --git a/contrib/epee/demo/demo_levin_server/demo_levin_server.h b/contrib/epee/demo/demo_levin_server/demo_levin_server.h
new file mode 100644
index 000000000..5a6f68f2d
--- /dev/null
+++ b/contrib/epee/demo/demo_levin_server/demo_levin_server.h
@@ -0,0 +1,76 @@
+// 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 <boost/thread.hpp>
+#include <boost/bind.hpp>
+
+#include "net/levin_server_cp2.h"
+#include "transport_defs.h"
+#include "storages/levin_abstract_invoke2.h"
+
+using namespace epee;
+
+namespace demo
+{
+
+ class demo_levin_server: public levin::levin_commands_handler<>
+ {
+ public:
+ bool run();
+ bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
+ bool deinit();
+ bool send_stop_signal();
+ bool is_stop(){return m_stop;}
+ bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
+ net_utils::boosted_levin_async_server& get_server(){return m_net_server;}
+ private:
+
+
+ CHAIN_LEVIN_INVOKE_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map
+ CHAIN_LEVIN_NOTIFY_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing
+
+ BEGIN_INVOKE_MAP2(demo_levin_server)
+ HANDLE_INVOKE_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_command_1)
+ HANDLE_INVOKE_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_command_2)
+ HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_notify_1)
+ HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_notify_2)
+ END_INVOKE_MAP2()
+
+ //----------------- commands handlers ----------------------------------------------
+ int handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context);
+ int handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context);
+ int handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context);
+ int handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context);
+ //----------------------------------------------------------------------------------
+ net_utils::boosted_levin_async_server m_net_server;
+ std::atomic<bool> m_stop;
+
+ };
+}
+
diff --git a/contrib/epee/demo/demo_levin_server/stdafx.cpp b/contrib/epee/demo/demo_levin_server/stdafx.cpp
new file mode 100644
index 000000000..d6ea1c6f2
--- /dev/null
+++ b/contrib/epee/demo/demo_levin_server/stdafx.cpp
@@ -0,0 +1,30 @@
+// 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.
+//
+
+
+
+#include "stdafx.h"
+
diff --git a/contrib/epee/demo/demo_levin_server/stdafx.h b/contrib/epee/demo/demo_levin_server/stdafx.h
new file mode 100644
index 000000000..f69d5922b
--- /dev/null
+++ b/contrib/epee/demo/demo_levin_server/stdafx.h
@@ -0,0 +1,41 @@
+// 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 "targetver.h"
+
+
+#include <stdio.h>
+
+
+#define BOOST_FILESYSTEM_VERSION 3
+#define ENABLE_RELEASE_LOGGING
+#include "log_opt_defs.h"
+#include "misc_log_ex.h"
+
+
diff --git a/contrib/epee/demo/demo_levin_server/targetver.h b/contrib/epee/demo/demo_levin_server/targetver.h
new file mode 100644
index 000000000..6fe8eb79e
--- /dev/null
+++ b/contrib/epee/demo/demo_levin_server/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
diff --git a/contrib/epee/demo/generate_gcc.sh b/contrib/epee/demo/generate_gcc.sh
new file mode 100644
index 000000000..fcd0a8a7e
--- /dev/null
+++ b/contrib/epee/demo/generate_gcc.sh
@@ -0,0 +1,4 @@
+mkdir build
+cd build
+cmake ..
+#cmake -DBOOST_ROOT=/usr/local/proj/boost_1_49_0 -DBOOST_LIBRARYDIR=/usr/local/proj/boost_1_49_0/stage/lib ..
diff --git a/contrib/epee/demo/generate_vc_proj.bat b/contrib/epee/demo/generate_vc_proj.bat
new file mode 100644
index 000000000..111405981
--- /dev/null
+++ b/contrib/epee/demo/generate_vc_proj.bat
@@ -0,0 +1,7 @@
+mkdir build
+
+cd build
+
+cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" ..
+cd ..
+pause \ No newline at end of file
diff --git a/contrib/epee/demo/iface/transport_defs.h b/contrib/epee/demo/iface/transport_defs.h
new file mode 100644
index 000000000..97f6caadd
--- /dev/null
+++ b/contrib/epee/demo/iface/transport_defs.h
@@ -0,0 +1,213 @@
+#pragma once
+
+#include "serialization/keyvalue_serialization.h"
+
+
+namespace demo
+{
+
+ struct some_test_subdata
+ {
+ std::string m_str;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_str)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct some_test_data
+ {
+ std::string m_str;
+ uint64_t m_uint64;
+ uint32_t m_uint32;
+ uint16_t m_uint16;
+ uint8_t m_uint8;
+ int64_t m_int64;
+ int32_t m_int32;
+ int16_t m_int16;
+ int8_t m_int8;
+ double m_double;
+ bool m_bool;
+ std::list<std::string> m_list_of_str;
+ std::list<uint64_t> m_list_of_uint64_t;
+ std::list<uint32_t> m_list_of_uint32_t;
+ std::list<uint16_t> m_list_of_uint16_t;
+ std::list<uint8_t> m_list_of_uint8_t;
+ std::list<int64_t> m_list_of_int64_t;
+ std::list<int32_t> m_list_of_int32_t;
+ std::list<int16_t> m_list_of_int16_t;
+ std::list<int8_t> m_list_of_int8_t;
+ std::list<double> m_list_of_double;
+ std::list<bool> m_list_of_bool;
+ some_test_subdata m_subobj;
+ std::list<some_test_data> m_list_of_self;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_str)
+ KV_SERIALIZE(m_uint64)
+ KV_SERIALIZE(m_uint32)
+ KV_SERIALIZE(m_uint16)
+ KV_SERIALIZE(m_uint8)
+ KV_SERIALIZE(m_int64)
+ KV_SERIALIZE(m_int32)
+ KV_SERIALIZE(m_int16)
+ KV_SERIALIZE(m_int8)
+ KV_SERIALIZE(m_double)
+ KV_SERIALIZE(m_bool)
+ KV_SERIALIZE(m_subobj)
+ KV_SERIALIZE(m_list_of_str)
+ KV_SERIALIZE(m_list_of_uint64_t)
+ KV_SERIALIZE(m_list_of_uint32_t)
+ KV_SERIALIZE(m_list_of_uint16_t)
+ KV_SERIALIZE(m_list_of_uint8_t)
+ KV_SERIALIZE(m_list_of_int64_t)
+ KV_SERIALIZE(m_list_of_int32_t)
+ KV_SERIALIZE(m_list_of_int16_t)
+ KV_SERIALIZE(m_list_of_int8_t)
+ KV_SERIALIZE(m_list_of_double)
+ KV_SERIALIZE(m_list_of_bool)
+ KV_SERIALIZE(m_list_of_self)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct COMMAND_EXAMPLE_1
+ {
+ const static int ID = 1000;
+
+ struct request
+ {
+ std::string example_string_data;
+ some_test_data sub;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(example_string_data)
+ KV_SERIALIZE(sub)
+ END_KV_SERIALIZE_MAP()
+ };
+
+
+ struct response
+ {
+ bool m_success;
+ std::list<some_test_data> subs;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_success)
+ KV_SERIALIZE(subs)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+
+ struct COMMAND_EXAMPLE_2
+ {
+ const static int ID = 1001;
+
+ struct request
+ {
+ std::string example_string_data2;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(example_string_data2)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ bool m_success;
+
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_success)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+
+ //-------------------------------------------------------------------------------------
+ //-------------------------------------------------------------------------------------
+ //in debug purpose
+ bool operator != (const some_test_subdata& a, const some_test_subdata& b)
+ {
+ return b.m_str != a.m_str;
+ }
+
+ bool operator == (const some_test_data& a, const some_test_data& b)
+ {
+ if( b.m_str != a.m_str
+ || b.m_uint64 != a.m_uint64
+ || b.m_uint32 != a.m_uint32
+ || b.m_uint16 != a.m_uint16
+ || b.m_uint8 != a.m_uint8
+ || b.m_int64 != a.m_int64
+ || b.m_int32 != a.m_int32
+ || b.m_int16 != a.m_int16
+ || b.m_int8 != a.m_int8
+ || b.m_double != a.m_double
+ || b.m_bool != a.m_bool
+ || b.m_list_of_str != a.m_list_of_str
+ || b.m_list_of_uint64_t != a.m_list_of_uint64_t
+ || b.m_list_of_uint32_t != a.m_list_of_uint32_t
+ || b.m_list_of_uint16_t != a.m_list_of_uint16_t
+ || b.m_list_of_uint8_t != a.m_list_of_uint8_t
+ || b.m_list_of_int64_t != a.m_list_of_int64_t
+ || b.m_list_of_int32_t != a.m_list_of_int32_t
+ || b.m_list_of_int16_t != a.m_list_of_int16_t
+ || b.m_list_of_int8_t != a.m_list_of_int8_t
+ || b.m_list_of_double != a.m_list_of_double
+ || b.m_list_of_bool != a.m_list_of_bool
+ || b.m_subobj != a.m_subobj
+ || b.m_list_of_self != a.m_list_of_self
+ )
+ return false;
+ return true;
+ }
+
+ inline some_test_data get_test_data()
+ {
+ some_test_data s;
+ s.m_str = "zuzuzuzuzuz";
+ s.m_uint64 = 111111111111111;
+ s.m_uint32 = 2222222;
+ s.m_uint16 = 2222;
+ s.m_uint8 = 22;
+ s.m_int64 = -111111111111111;
+ s.m_int32 = -2222222;
+ s.m_int16 = -2222;
+ s.m_int8 = -24;
+ s.m_double = 0.11111;
+ s.m_bool = true;
+ s.m_list_of_str.push_back("1112121");
+ s.m_list_of_uint64_t.push_back(1111111111);
+ s.m_list_of_uint64_t.push_back(2222222222);
+ s.m_list_of_uint32_t.push_back(1111111);
+ s.m_list_of_uint32_t.push_back(2222222);
+ s.m_list_of_uint16_t.push_back(1111);
+ s.m_list_of_uint16_t.push_back(2222);
+ s.m_list_of_uint8_t.push_back(11);
+ s.m_list_of_uint8_t.push_back(22);
+
+
+ s.m_list_of_int64_t.push_back(-1111111111);
+ s.m_list_of_int64_t.push_back(-222222222);
+ s.m_list_of_int32_t.push_back(-1111111);
+ s.m_list_of_int32_t.push_back(-2222222);
+ s.m_list_of_int16_t.push_back(-1111);
+ s.m_list_of_int16_t.push_back(-2222);
+ s.m_list_of_int8_t.push_back(-11);
+ s.m_list_of_int8_t.push_back(-22);
+
+ s.m_list_of_double.push_back(0.11111);
+ s.m_list_of_double.push_back(0.22222);
+ s.m_list_of_bool.push_back(true);
+ s.m_list_of_bool.push_back(false);
+
+ s.m_subobj.m_str = "subszzzzzzzz";
+ s.m_list_of_self.push_back(s);
+ return s;
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/ado_db_helper.h b/contrib/epee/include/ado_db_helper.h
new file mode 100644
index 000000000..ed4e5b30f
--- /dev/null
+++ b/contrib/epee/include/ado_db_helper.h
@@ -0,0 +1,1095 @@
+// 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 _DB_ADO_HELPER_H_
+#define _DB_ADO_HELPER_H_
+
+#include <vector>
+#include <comutil.h>
+#include "string_coding.h"
+#include "math_helper.h"
+#include "file_io_utils.h"
+#include "global_stream_operators.h"
+
+
+
+#define BEGIN_TRY_SECTION() try {
+
+#define CATCH_TRY_SECTION(ret_val) CATCH_TRY_SECTION_MESS(ret_val, "")
+
+#define CATCH_TRY_SECTION_MESS(ret_val, mess_where) }\
+ catch(const std::exception&ex)\
+ {\
+ LOG_PRINT_J("DB_ERROR: " << ex.what(), LOG_LEVEL_0);\
+ return ret_val;\
+ }\
+ catch(const _com_error& comm_err)\
+ {\
+ const TCHAR* pstr = comm_err.Description();\
+ std::string descr = string_encoding::convert_to_ansii(pstr?pstr:TEXT(""));\
+ const TCHAR* pmessage = comm_err.ErrorMessage();\
+ pstr = comm_err.Source();\
+ std::string source = string_encoding::convert_to_ansii(pstr?pstr:TEXT(""));\
+ LOG_PRINT_J("COM_ERROR " << mess_where << ":\n\tDescriprion:" << descr << ", \n\t Message: " << string_encoding::convert_to_ansii(pmessage) << "\n\t Source: " << source, LOG_LEVEL_0);\
+ return ret_val;\
+ }\
+ catch(...)\
+ {\
+ LOG_PRINT_J("..._ERROR: Unknown error.", LOG_LEVEL_0);\
+ return ret_val;\
+ }\
+
+namespace epee
+{
+namespace ado_db_helper
+{
+
+ struct profile_entry
+ {
+ profile_entry():m_call_count(0), m_max_time(0), m_min_time(0)
+ {}
+ //std::string m_sql;
+ math_helper::average<DWORD, 10> m_avrg;
+ size_t m_call_count;
+ DWORD m_max_time;
+ DWORD m_min_time;
+ };
+
+ class profiler_manager
+ {
+ public:
+ typedef std::map<std::string, profile_entry> sqls_map;
+ profiler_manager(){}
+
+ static bool sort_by_timing(const sqls_map::iterator& a, const sqls_map::iterator& b)
+ {
+ return a->second.m_avrg.get_avg() > b->second.m_avrg.get_avg();
+ }
+
+ bool flush_log(const std::string& path)
+ {
+ CRITICAL_REGION_BEGIN(m_sqls_lock);
+ std::stringstream strm;
+ strm << "SQL PROFILE:\r\nStatements: " << m_sqls.size() << "\r\n";
+ std::list<sqls_map::iterator> m_sorted_by_time_sqls;
+ for(std::map<std::string, profile_entry>::iterator it = m_sqls.begin();it!=m_sqls.end();it++)
+ m_sorted_by_time_sqls.push_back(it);
+
+ m_sorted_by_time_sqls.sort(sort_by_timing);
+
+ for(std::list<sqls_map::iterator>::iterator it = m_sorted_by_time_sqls.begin();it!=m_sorted_by_time_sqls.end();it++)
+ {
+ strm << "---------------------------------------------------------------------------------------------------------\r\nSQL: " << (*it)->first << "\r\n";
+ strm << "\tavrg: " << (*it)->second.m_avrg.get_avg() << "\r\n\tmax: " << (*it)->second.m_max_time << "\r\n\tmin: " << (*it)->second.m_min_time << "\r\n\tcount: " << (*it)->second.m_call_count << "\r\n";
+ }
+
+ return file_io_utils::save_string_to_file(path.c_str(), strm.str());
+ CRITICAL_REGION_END();
+ }
+
+ bool push_entry(const std::string sql, DWORD time)
+ {
+ CRITICAL_REGION_BEGIN(m_sqls_lock);
+ profile_entry& entry_ref = m_sqls[sql];
+ entry_ref.m_avrg.push(time);
+ entry_ref.m_call_count++;
+ if(time > entry_ref.m_max_time) entry_ref.m_max_time = time;
+ if(time < entry_ref.m_min_time || entry_ref.m_min_time == 0) entry_ref.m_min_time = time;
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ bool get_entry_avarege(const std::string sql, DWORD& time)
+ {
+ CRITICAL_REGION_BEGIN(m_sqls_lock);
+ sqls_map::iterator it = m_sqls.find(sql);
+ if(it==m_sqls.end())
+ return false;
+
+ time = static_cast<DWORD>(it->second.m_avrg.get_avg());
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ private:
+
+ sqls_map m_sqls;
+ critical_section m_sqls_lock;
+ };
+inline
+ profiler_manager* get_set_profiler(bool need_to_set = false, profiler_manager** pprofiler = NULL)
+ {
+ static profiler_manager* pmanager = NULL;
+ if(need_to_set)
+ pmanager = *pprofiler;
+ //else
+ // *pprofiler = pmanager;
+
+ return pmanager;
+ }
+inline
+ bool init() // INIT and DEINIT are NOT THREAD SAFE operations, CALL it BEFOR u start using this wrapper.
+ {
+ profiler_manager* pmanager = new profiler_manager();
+ get_set_profiler(true, &pmanager);
+ return true;
+ }
+inline
+ bool deinit()
+ {
+ profiler_manager* pmanager = get_set_profiler();
+ //get_set_profiler(false, &pmanager);
+ if(pmanager)
+ delete pmanager;
+ return true;
+ }
+ inline bool push_timing(const std::string sql, DWORD time)
+ {
+ profiler_manager* pmanager = get_set_profiler();
+ //get_set_profiler(false, &pmanager);
+ if(pmanager)
+ return pmanager->push_entry(sql, time);
+ return true;
+ }
+
+ inline bool flush_profiler(const std::string path)
+ {
+ profiler_manager* pmanager = get_set_profiler();
+ //get_set_profiler(false, &pmanager);
+ if(pmanager)
+ return pmanager->flush_log(path);
+ return true;
+ }
+
+ class timing_guard
+ {
+ DWORD m_start_time;
+ std::string m_sql;
+
+ public:
+ timing_guard(const std::string& sql)
+ {
+ m_start_time = ::GetTickCount();
+ m_sql = sql;
+ }
+
+ ~timing_guard()
+ {
+ DWORD timing = ::GetTickCount() - m_start_time;
+ push_timing(m_sql, timing);
+ }
+ };
+#define PROFILE_SQL(sql) timing_guard local_timing(sql)
+
+
+ typedef std::vector<std::vector<_variant_t> > table;
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const std::string& parametr)
+ {
+ _variant_t param(parametr.c_str());
+ ADODB::ADO_LONGPTR size = sizeof(parametr);
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("", ADODB::adVarChar, ADODB::adParamInput, static_cast<long>(parametr.size()+1), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const std::wstring& parametr)
+ {
+ _variant_t param(parametr.c_str());
+ ADODB::ADO_LONGPTR size = sizeof(parametr);
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("", ADODB::adVarWChar, ADODB::adParamInput, static_cast<long>(parametr.size()+2), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const __int64 parametr)
+ {
+ _variant_t param(parametr);
+ ADODB::ADO_LONGPTR size = static_cast<long>(sizeof(parametr));
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adBigInt, ADODB::adParamInput, static_cast<long>(size), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const unsigned __int64 parametr)
+ {
+ _variant_t param(parametr);
+ ADODB::ADO_LONGPTR size = static_cast<long>(sizeof(parametr));
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adUnsignedBigInt, ADODB::adParamInput, static_cast<long>(size), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const int parametr)
+ {
+ _variant_t param(parametr);
+ ADODB::ADO_LONGPTR size = static_cast<long>(sizeof(parametr));
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adInteger, ADODB::adParamInput, static_cast<long>(size), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const unsigned int parametr)
+ {
+ _variant_t param(parametr);
+ ADODB::ADO_LONGPTR size = static_cast<long>(sizeof(parametr));
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adUnsignedInt, ADODB::adParamInput, static_cast<long>(size), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, float parametr)
+ {
+ _variant_t param;
+ param.ChangeType(VT_R4);
+ param.fltVal = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adSingle, ADODB::adParamInput, static_cast<long>(sizeof(float)), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, bool parametr)
+ {
+ _variant_t param;
+ param = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adBoolean, ADODB::adParamInput, sizeof(parametr), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, _variant_t parametr)
+ {
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adDBTimeStamp, ADODB::adParamInput, sizeof(parametr), parametr);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+
+ inline bool add_parametr_as_double(ADODB::_CommandPtr cmd, const DATE parametr)
+ {
+ _variant_t param;
+ param.ChangeType(VT_R8);
+ param.dblVal = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adDouble, ADODB::adParamInput, sizeof(float), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }
+
+ template<typename TParam>
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const std::list<TParam> params)
+ {
+ for(std::list<TParam>::const_iterator it = params.begin(); it!=params.end(); it++)
+ if(!add_parametr(cmd, *it))
+ return false;
+ return true;
+ }
+
+ /*
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const size_t parametr)
+ {
+ _variant_t param;
+ param.ChangeType(VT_I4);
+ param.intVal = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adInteger, ADODB::adParamInput, sizeof(parametr), param);
+ cmd->Parameters->Append(param_obj);
+ return true;
+ }*/
+
+
+ inline bool add_parametr(ADODB::_CommandPtr cmd, const DATE parametr)
+ {
+ /*_variant_t param;
+ param.ChangeType(VT_R8);
+ param.dblVal = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adDouble, ADODB::adParamInput, sizeof(float), param);
+ cmd->Parameters->Append(param_obj);*/
+
+ _variant_t param;
+ param.ChangeType(VT_DATE);
+ param.date = parametr;
+ ADODB::_ParameterPtr param_obj = cmd->CreateParameter("parametr", ADODB::adDBDate, ADODB::adParamInput, sizeof(parametr), param);
+ cmd->Parameters->Append(param_obj);
+
+ return true;
+ }
+
+
+ inline bool execute_helper(ADODB::_CommandPtr cmd, _variant_t* pcount_processed = NULL)
+ {
+ //BEGIN_TRY_SECTION();
+
+ cmd->Execute(pcount_processed, NULL, ADODB::adExecuteNoRecords);
+
+
+ //CATCH_TRY_SECTION(false);
+
+ return true;
+ }
+
+
+ inline bool select_helper(ADODB::_CommandPtr cmd, table& result_vector)
+ {
+ result_vector.clear();
+ //BEGIN_TRY_SECTION();
+
+ ADODB::_RecordsetPtr precordset = cmd->Execute(NULL, NULL, NULL);
+ if(!precordset)
+ {
+ LOG_ERROR("DB_ERROR: cmd->Execute returned NULL!!!");
+ return false;
+ }
+
+ //if(precordset->EndOfFile == EOF)
+ //{
+ // return true;
+ //}
+ /*try
+ {
+ if(precordset->MoveFirst()!= S_OK)
+ {
+ LOG_ERROR("DB_ERROR: Filed to move first!!!");
+ return false;
+ }
+ }
+ catch (...)
+ {
+ return true;
+ }*/
+
+ size_t current_record_index = 0;
+ while(precordset->EndOfFile != EOF)
+ {
+ result_vector.push_back(table::value_type());
+ size_t fields_count = precordset->Fields->Count;
+ result_vector[current_record_index].resize(fields_count);
+ for(size_t current_field_index = 0; current_field_index < fields_count; current_field_index++)
+ {
+ _variant_t var;
+ var.ChangeType(VT_I2);
+ var.intVal = static_cast<INT>(current_field_index);
+ result_vector[current_record_index][current_field_index] = precordset->Fields->GetItem(var)->Value;
+ }
+ precordset->MoveNext();
+ current_record_index++;
+ }
+ //CATCH_TRY_SECTION(false);
+ return true;
+ }
+
+
+ template<typename TParam1>
+ struct adapter_zero
+ {
+
+ };
+
+ template<typename TParam1>
+ struct adapter_single
+ {
+ TParam1 tparam1;
+ };
+ template<typename TParam1, typename TParam2>
+ struct adapter_double
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ };
+
+
+ template<typename TParam1, typename TParam2, typename TParam3>
+ struct adapter_triple
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ };
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4>
+ struct adapter_quad
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ TParam4 tparam4;
+ };
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5>
+ struct adapter_quanto
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ TParam4 tparam4;
+ TParam5 tparam5;
+ };
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6>
+ struct adapter_sixto
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ TParam4 tparam4;
+ TParam5 tparam5;
+ TParam6 tparam6;
+ };
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7>
+ struct adapter_sevento
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ TParam4 tparam4;
+ TParam5 tparam5;
+ TParam6 tparam6;
+ TParam7 tparam7;
+ };
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7, typename TParam8, typename TParam9>
+ struct adapter_nine
+ {
+ TParam1 tparam1;
+ TParam2 tparam2;
+ TParam3 tparam3;
+ TParam4 tparam4;
+ TParam5 tparam5;
+ TParam6 tparam6;
+ TParam7 tparam7;
+ TParam8 tparam8;
+ TParam9 tparam9;
+ };
+
+ template<typename TParam1>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_zero<TParam1>& params)
+ {
+ return true;
+ }
+
+ template<typename TParam1>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_single<TParam1>& params)
+ {
+ return add_parametr(cmd, params.tparam1);
+ }
+
+ template<typename TParam1, typename TParam2>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_double<TParam1, TParam2>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ return add_parametr(cmd, params.tparam2);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_triple<TParam1, TParam2, TParam3>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ return add_parametr(cmd, params.tparam3);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_quad<TParam1, TParam2, TParam3, TParam4>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ if(!add_parametr(cmd, params.tparam3)) return false;
+ return add_parametr(cmd, params.tparam4);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_quanto<TParam1, TParam2, TParam3, TParam4, TParam5>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ if(!add_parametr(cmd, params.tparam3)) return false;
+ if(!add_parametr(cmd, params.tparam4)) return false;
+ return add_parametr(cmd, params.tparam5);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_sixto<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ if(!add_parametr(cmd, params.tparam3)) return false;
+ if(!add_parametr(cmd, params.tparam4)) return false;
+ if(!add_parametr(cmd, params.tparam5)) return false;
+ return add_parametr(cmd, params.tparam6);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_sevento<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ if(!add_parametr(cmd, params.tparam3)) return false;
+ if(!add_parametr(cmd, params.tparam4)) return false;
+ if(!add_parametr(cmd, params.tparam5)) return false;
+ if(!add_parametr(cmd, params.tparam6)) return false;
+ return add_parametr(cmd, params.tparam7);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7, typename TParam8, typename TParam9>
+ bool add_parametrs_multi(ADODB::_CommandPtr cmd, const adapter_nine<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7, TParam8, TParam9>& params)
+ {
+ if(!add_parametr(cmd, params.tparam1)) return false;
+ if(!add_parametr(cmd, params.tparam2)) return false;
+ if(!add_parametr(cmd, params.tparam3)) return false;
+ if(!add_parametr(cmd, params.tparam4)) return false;
+ if(!add_parametr(cmd, params.tparam5)) return false;
+ if(!add_parametr(cmd, params.tparam6)) return false;
+ if(!add_parametr(cmd, params.tparam7)) return false;
+ if(!add_parametr(cmd, params.tparam8)) return false;
+ return add_parametr(cmd, params.tparam9);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7>
+ std::string print_parameters_multi(const adapter_sevento<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3 << ", " << params.tparam4 << ", " << params.tparam5 << ", " << params.tparam6 << ", " << params.tparam7;
+ return strm.str();
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7, typename TParam8, typename TParam9>
+ std::string print_parameters_multi(const adapter_nine<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7, TParam8, TParam9>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3 << ", " << params.tparam4 << ", " << params.tparam5 << ", " << params.tparam6 << ", " << params.tparam7 << ", " << params.tparam8 << ", " << params.tparam9;
+ return strm.str();
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6>
+ std::string print_parameters_multi(const adapter_sixto<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3 << ", " << params.tparam4 << ", " << params.tparam5 << ", " << params.tparam6;
+ return strm.str();
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5>
+ std::string print_parameters_multi(const adapter_quanto<TParam1, TParam2, TParam3, TParam4, TParam5>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3 << ", " << params.tparam4 << ", " << params.tparam5;
+ return strm.str();
+ }
+
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4>
+ std::string print_parameters_multi(const adapter_quad<TParam1, TParam2, TParam3, TParam4>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3 << ", " << params.tparam4;
+ return strm.str();
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3>
+ std::string print_parameters_multi(const adapter_triple<TParam1, TParam2, TParam3>& params)
+ {
+ std::stringstream strm;
+ strm << params.tparam1 << ", " << params.tparam2 << ", " << params.tparam3;
+ return strm.str();
+ }
+
+ template<typename TParam>
+ std::string get_str_param(const TParam& prm)
+ {
+ std::stringstream strm;
+ strm << prm;
+ return strm.str();
+ }
+
+ template<typename TParam>
+ std::string get_str_param(const std::list<TParam>& prm_lst)
+ {
+ std::stringstream strm;
+ for(std::list<TParam>::const_iterator it = prm_lst.begin();it!=prm_lst.end();it++)
+ strm << get_str_param(*it) << ", ";
+ return strm.str();
+ }
+
+
+ template<typename TParam1, typename TParam2>
+ std::string print_parameters_multi(const adapter_double<TParam1, TParam2>& params)
+ {
+ std::stringstream strm;
+ strm << get_str_param(params.tparam1) << ", " << get_str_param(params.tparam2);
+ return strm.str();
+ }
+
+ template<typename TParam1>
+ std::string print_parameters_multi(const adapter_single<TParam1>& params)
+ {
+ std::stringstream strm;
+ strm << get_str_param(params.tparam1);
+ return strm.str();
+ }
+
+ template<typename TParam1>
+ std::string print_parameters_multi(const adapter_zero<TParam1>& params)
+ {
+ std::stringstream strm;
+ strm << "(no parametrs)";
+ return strm.str();
+ }
+
+
+ template<typename TParams>
+ bool execute_helper_multiparam(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParams& parametrs, _variant_t* pcount_processed = NULL)
+ {
+ PROFILE_SQL(sql_statment);
+ bool res = false;
+ BEGIN_TRY_SECTION();
+
+ ADODB::_CommandPtr cmd;
+ cmd.CreateInstance(__uuidof(ADODB::Command));
+ cmd->CommandText = _bstr_t(sql_statment.c_str());
+
+ if(!add_parametrs_multi(cmd, parametrs))
+ return false;
+
+ cmd->ActiveConnection = pconnection;
+ res = execute_helper(cmd, pcount_processed);
+
+ CATCH_TRY_SECTION_MESS(false, "while statment: " << sql_statment << " [params]: " << print_parameters_multi(parametrs));
+ return res;
+ }
+
+
+ template<typename TParams>
+ inline
+ bool select_helper_multiparam(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParams& parametrs, table& result_vector)
+ {
+ PROFILE_SQL(sql_statment);
+ bool res = false;
+ BEGIN_TRY_SECTION();
+ ADODB::_CommandPtr cmd;
+ cmd.CreateInstance(__uuidof(ADODB::Command));
+ cmd->CommandText = _bstr_t(sql_statment.c_str());
+
+
+ if(!add_parametrs_multi(cmd, parametrs))
+ return false;
+
+ cmd->ActiveConnection = pconnection;
+ res = select_helper(cmd, result_vector);
+ CATCH_TRY_SECTION_MESS(false, "while statment: " << sql_statment << " [params]: " << print_parameters_multi(parametrs));
+ return res;
+ }
+
+
+ template<typename TParams>
+ inline
+ bool select_helper_param_container(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParams& parametrs, table& result_vector)
+ {
+ PROFILE_SQL(sql_statment);
+ bool res = false;
+ BEGIN_TRY_SECTION();
+ ADODB::_CommandPtr cmd;
+ cmd.CreateInstance(__uuidof(ADODB::Command));
+ cmd->CommandText = _bstr_t(sql_statment.c_str());
+
+
+ for(TParams::const_iterator it = parametrs.begin(); it!=parametrs.end(); it++)
+ {
+ add_parametr(cmd, *it);
+ }
+
+ cmd->ActiveConnection = pconnection;
+ res = select_helper(cmd, result_vector);
+
+ CATCH_TRY_SECTION(false);
+ return res;
+ }
+
+
+ inline
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, _variant_t* pvt = NULL)
+ {
+ adapter_zero<int> params;
+ return execute_helper_multiparam(pconnection, sql_statment, params, pvt);
+ }
+
+ template<typename TParam>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam& parametr)
+ {
+ adapter_single<TParam> params;
+ params.tparam1 = parametr;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+
+ template<typename TParam1, typename TParam2>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2)
+ {
+ adapter_double<TParam1, TParam2> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2, const TParam3& parametr3)
+ {
+ adapter_triple<TParam1, TParam2, typename TParam3> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2, const TParam3& parametr3, const TParam4& parametr4)
+ {
+ adapter_quad<TParam1, TParam2, TParam3, TParam4> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2, const TParam3& parametr3, const TParam4& parametr4, const TParam5& parametr5)
+ {
+ adapter_quanto<TParam1, TParam2, TParam3, TParam4, TParam5> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2, const TParam3& parametr3, const TParam4& parametr4, const TParam5& parametr5, const TParam6& parametr6)
+ {
+ adapter_sixto<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ params.tparam6 = parametr6;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7>
+ bool execute_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1& parametr1, const TParam2& parametr2, const TParam3& parametr3, const TParam4& parametr4, const TParam5& parametr5, const TParam6& parametr6, const TParam7& parametr7)
+ {
+ adapter_sevento<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ params.tparam6 = parametr6;
+ params.tparam7 = parametr7;
+ return execute_helper_multiparam(pconnection, sql_statment, params);
+ }
+
+ inline
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, table& result_vector)
+ {
+ adapter_zero<int> params;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+
+ template<typename TParam>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam& parametr, table& result_vector)
+ {
+ adapter_single<TParam> params;
+ params.tparam1 = parametr;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+ template<typename TParam1, typename TParam2>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, table& result_vector)
+ {
+ adapter_double<TParam1, TParam2> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, table& result_vector)
+ {
+ adapter_triple<TParam1, TParam2, typename TParam3> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, const TParam4 parametr4, table& result_vector)
+ {
+ adapter_quad<TParam1, TParam2, TParam3, TParam4> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, const TParam4 parametr4, const TParam5 parametr5, table& result_vector)
+ {
+ adapter_quanto<TParam1, TParam2, TParam3, TParam4, TParam5> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, const TParam4 parametr4, const TParam5 parametr5, const TParam6 parametr6, table& result_vector)
+ {
+ adapter_sixto<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ params.tparam6 = parametr6;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, const TParam4 parametr4, const TParam5 parametr5, const TParam6 parametr6, const TParam7 parametr7, table& result_vector)
+ {
+ adapter_sevento<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ params.tparam6 = parametr6;
+ params.tparam7 = parametr7;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename TParam5, typename TParam6, typename TParam7, typename TParam8, typename TParam9>
+ bool select_helper(ADODB::_ConnectionPtr pconnection, const std::string& sql_statment, const TParam1 parametr1, const TParam2 parametr2, const TParam3 parametr3, const TParam4 parametr4, const TParam5 parametr5, const TParam6 parametr6, const TParam7 parametr7,const TParam8 parametr8,const TParam9 parametr9, table& result_vector)
+ {
+ adapter_nine<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7, TParam8, TParam9> params;
+ params.tparam1 = parametr1;
+ params.tparam2 = parametr2;
+ params.tparam3 = parametr3;
+ params.tparam4 = parametr4;
+ params.tparam5 = parametr5;
+ params.tparam6 = parametr6;
+ params.tparam7 = parametr7;
+ params.tparam8 = parametr8;
+ params.tparam9 = parametr9;
+ return select_helper_multiparam(pconnection, sql_statment, params, result_vector);
+ }
+
+
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+
+ class per_thread_connection_pool
+ {
+ public:
+ bool init(const std::string& connection_string, const std::string& login, const std::string& pass)
+ {
+ m_connection_string = connection_string;
+ m_login = login;
+ m_password = pass;
+ if(!get_db_connection().GetInterfacePtr())
+ return false;
+
+ return true;
+ }
+
+ ADODB::_ConnectionPtr& get_db_connection()
+ {
+
+ //soci::session
+
+ m_db_connections_lock.lock();
+ boost::shared_ptr<ADODB::_ConnectionPtr>& conn_ptr = m_db_connections[::GetCurrentThreadId()];
+ m_db_connections_lock.unlock();
+ if(!conn_ptr.get())
+ {
+ conn_ptr.reset(new ADODB::_ConnectionPtr());
+ ADODB::_ConnectionPtr& conn = *conn_ptr.get();
+ //init new connection
+
+ BEGIN_TRY_SECTION();
+ //_bstr_t str = _bstr_t("Provider=SQLOLEDB;Data Source=SRV1;Integrated Security=SSPI;Initial Catalog=dispatcher;");
+
+ if(S_OK != conn.CreateInstance(__uuidof(ADODB::Connection)))
+ {
+ LOG_ERROR("Failed to Create, instance, was CoInitialize called ???!");
+ return conn;
+ }
+
+ HRESULT res = conn->Open(_bstr_t(m_connection_string.c_str()), _bstr_t(m_login.c_str()), _bstr_t(m_password.c_str()), NULL);
+ if(res != S_OK)
+ {
+ LOG_ERROR("Failed to connect do DB, connection str:" << m_connection_string);
+ return conn;
+ }
+ CATCH_TRY_SECTION_MESS(conn, "while creating another connection");
+ LOG_PRINT("New DB Connection added for threadid=" << ::GetCurrentThreadId(), LOG_LEVEL_0);
+ ado_db_helper::execute_helper(conn, "set enable_seqscan=false;");
+ return conn;
+ }
+
+ return *conn_ptr.get();
+ }
+
+ //----------------------------------------------------------------------------------------------
+ bool check_status()
+ {
+ ADODB::_ConnectionPtr& rconn = get_db_connection();
+ if(!ado_db_helper::execute_helper(rconn, "SET CLIENT_ENCODING TO 'SQL_ASCII'"))
+ {
+
+ try{
+ HRESULT res = rconn->Close();
+ }
+ catch(...)
+ {
+
+ };
+ BEGIN_TRY_SECTION();
+
+ HRESULT res = rconn->Open(_bstr_t(m_connection_string.c_str()), _bstr_t(m_login.c_str()), _bstr_t(m_password.c_str()), NULL);
+ if(res != S_OK)
+ {
+ LOG_PRINT("Failed to restore connection to local AI DB", LOG_LEVEL_1);
+ return false;
+ }
+ CATCH_TRY_SECTION(false);
+ }
+
+ return true;
+ }
+
+ protected:
+ private:
+ std::map<DWORD, boost::shared_ptr<ADODB::_ConnectionPtr> > m_db_connections;
+ critical_section m_db_connections_lock;
+ std::string m_connection_string;
+ std::string m_login;
+ std::string m_password;
+ };
+
+
+ template<typename TParam1, typename default_id_type, typename t_conn>
+ bool find_or_add_t(const std::string& sql_select_statment, const std::string& sql_insert_statment, OUT default_id_type& id, OUT bool& new_object_added, TParam1 parametr_1, t_conn& c)
+ {
+ ado_db_helper::adapter_single<TParam1> params;
+ params.tparam1 = parametr_1;
+ return find_or_add_t_multiparametred(sql_select_statment, sql_insert_statment, id, new_object_added, params, c);
+ }
+
+
+ template<typename TParam1, typename TParam2, typename default_id_type, typename t_conn>
+ bool find_or_add_t(const std::string& sql_select_statment, const std::string& sql_insert_statment, OUT default_id_type& id, OUT bool& new_object_added, TParam1 parametr_1, TParam2 parametr_2, t_conn& c)
+ {
+ ado_db_helper::adapter_double<TParam1, TParam2> params;
+ params.tparam1 = parametr_1;
+ params.tparam2 = parametr_2;
+ return find_or_add_t_multiparametred(sql_select_statment, sql_insert_statment, id, new_object_added, params, c);
+ }
+
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename default_id_type, typename t_conn>
+ bool find_or_add_t(const std::string& sql_select_statment, const std::string& sql_insert_statment, OUT default_id_type& id, OUT bool& new_object_added, TParam1 parametr_1, TParam2 parametr_2, TParam3 parametr_3, t_conn& c)
+ {
+ ado_db_helper::adapter_triple<TParam1, TParam2, TParam3> params;
+ params.tparam1 = parametr_1;
+ params.tparam2 = parametr_2;
+ params.tparam3 = parametr_3;
+ return find_or_add_t_multiparametred(sql_select_statment, sql_insert_statment, id, new_object_added, params, c);
+ }
+
+ template<typename TParam1, typename TParam2, typename TParam3, typename TParam4, typename default_id_type, typename t_conn>
+ bool find_or_add_t(const std::string& sql_select_statment, const std::string& sql_insert_statment, OUT default_id_type& id, OUT bool& new_object_added, TParam1 parametr_1, TParam2 parametr_2, TParam3 parametr_3, TParam4 parametr_4, t_conn& c)
+ {
+ ado_db_helper::adapter_quad<TParam1, TParam2, TParam3, TParam4> params;
+ params.tparam1 = parametr_1;
+ params.tparam2 = parametr_2;
+ params.tparam3 = parametr_3;
+ params.tparam4 = parametr_4;
+ return find_or_add_t_multiparametred(sql_select_statment, sql_insert_statment, id, new_object_added, params, c);
+ }
+
+ template<typename TParams, typename default_id_type, typename t_conn>
+ bool find_or_add_t_multiparametred(const std::string& sql_select_statment, const std::string& sql_insert_statment, OUT default_id_type& id, OUT bool& new_object_added, TParams params, t_conn& c)
+ {
+
+ //CHECK_CONNECTION(false);
+
+ new_object_added = false;
+ ado_db_helper::table result_table;
+
+ bool res = select_helper_multiparam(c.get_db_connection(), sql_select_statment, params, result_table);
+ if(!result_table.size())
+ {
+ res = select_helper_multiparam(c.get_db_connection(), sql_insert_statment, params, result_table);
+ if(!res || !result_table.size())
+ {
+ //last time try to select
+ res = select_helper_multiparam(c.get_db_connection(), sql_select_statment, params, result_table);
+ CHECK_AND_ASSERT_MES(res, false, "Failed to execute statment: " << sql_select_statment);
+ CHECK_AND_ASSERT_MES(result_table.size(), false, "No records returned from statment: " << sql_select_statment);
+ }else
+ {
+ new_object_added = true;
+ }
+ }
+
+ BEGIN_TRY_SECTION()
+ id = result_table[0][0];
+ CATCH_TRY_SECTION_MESS(false, "while converting returned value [find_or_add_t_multiparametred()]");
+
+ return true;
+ }
+
+}
+}
+#endif //!_DB_HELPER_H_
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
new file mode 100644
index 000000000..238abc80c
--- /dev/null
+++ b/contrib/epee/include/console_handler.h
@@ -0,0 +1,310 @@
+// 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
+
+namespace epee
+{
+
+
+
+
+ template<class t_server>
+ bool empty_commands_handler(t_server* psrv, const std::string& command)
+ {
+ return true;
+ }
+
+
+ template<class t_server, class chain_handler>
+ bool default_console_handler(t_server* psrv, chain_handler ch_handler, const std::string usage = "")
+ {
+ TRY_ENTRY();
+ bool continue_handle = true;
+ while(continue_handle)
+ {
+ char command_buff[400] = {0};
+ std::string command;
+ std::cin.getline(command_buff, 399);
+ if(std::cin.eof() || std::cin.fail())
+ {
+ LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
+ continue_handle = false;
+ break;
+ }
+ command = command_buff;
+
+ if(!command.compare("exit") || !command.compare("q") )
+ {
+ psrv->send_stop_signal();
+ continue_handle = false;
+ }else if ( !command.compare(0, 7, "set_log"))
+ {
+ //parse set_log command
+ if(command.size() != 9)
+ {
+ std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
+ continue;
+ }
+ int n = 0;
+ if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
+ {
+ std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
+ continue;
+ }
+ log_space::get_set_log_detalisation_level(true, n);
+ LOG_PRINT_L0("New log level set " << n);
+ }
+ else if(ch_handler(psrv, command))
+ continue;
+ else
+ {
+ std::cout << "unknown command: " << command << std::endl;
+ std::cout << usage;
+ }
+ }
+ return true;
+ CATCH_ENTRY_L0("console_handler", false);
+ }
+
+ template<class chain_handler>
+ bool default_console_handler2(chain_handler ch_handler, const std::string usage)
+ {
+ TRY_ENTRY();
+ bool continue_handle = true;
+ while(continue_handle)
+ {
+ char command_buff[400] = {0};
+ std::string command;
+ std::cin.getline(command_buff, 399);
+ if(std::cin.eof() || std::cin.fail())
+ {
+
+ LOG_PRINT("std::cin.eof() or std::cin.fail(), stopping...", LOG_LEVEL_0);
+ continue_handle = false;
+ break;
+ }
+ command = command_buff;
+
+ if(!command.compare("exit") || !command.compare("q") )
+ {
+ continue_handle = false;
+ }else if ( !command.compare(0, 7, "set_log"))
+ {
+ //parse set_log command
+ if(command.size() != 9)
+ {
+ std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
+ continue;
+ }
+ int n = 0;
+ if(!string_tools::get_xtype_from_string(n, command.substr(8, 1)))
+ {
+ std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
+ continue;
+ }
+ log_space::get_set_log_detalisation_level(true, n);
+ LOG_PRINT_L0("New log level set " << n);
+ }
+ else if(ch_handler(command))
+ continue;
+ else
+ {
+ std::cout << "unknown command: " << command << std::endl;
+ std::cout << usage;
+ }
+ }
+ return true;
+ CATCH_ENTRY_L0("console_handler", false);
+ }
+
+
+
+
+ template<class t_server, class t_handler>
+ bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
+ {
+ boost::thread( boost::bind(default_console_handler<t_server, t_handler>, ptsrv, handlr, usage) );
+ return true;
+ }
+
+ template<class t_server>
+ bool start_default_console(t_server* ptsrv, const std::string& usage = "")
+ {
+ return start_default_console(ptsrv, empty_commands_handler<t_server>, usage);
+ }
+
+ template<class t_server, class t_handler>
+ bool no_srv_param_adapter(t_server* ptsrv, const std::string& cmd, t_handler handlr)
+ {
+ return handlr(cmd);
+ }
+
+ template<class t_server, class t_handler>
+ bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
+ {
+ return default_console_handler(ptsrv, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _2, handlr), usage);
+ }
+
+ template<class t_server, class t_handler>
+ bool start_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& usage = "")
+ {
+ boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, usage) );
+ return true;
+ }
+
+ /*template<class a>
+ bool f(int i, a l)
+ {
+ return true;
+ }*/
+ /*
+ template<class chain_handler>
+ bool default_console_handler2(chain_handler ch_handler, const std::string usage)
+ */
+
+
+ /*template<class t_handler>
+ bool start_default_console2(t_handler handlr, const std::string& usage = "")
+ {
+ //std::string usage_local = usage;
+ boost::thread( boost::bind(default_console_handler2<t_handler>, handlr, usage) );
+ //boost::function<bool ()> p__ = boost::bind(f<t_handler>, 1, handlr);
+ //boost::function<bool ()> p__ = boost::bind(default_console_handler2<t_handler>, handlr, usage);
+ //boost::thread tr(p__);
+ return true;
+ }*/
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class console_handlers_binder
+ {
+ typedef boost::function<bool (const std::vector<std::string> &)> console_command_handler;
+ typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
+ std::unique_ptr<boost::thread> m_console_thread;
+ command_handlers_map m_command_handlers;
+ public:
+ std::string get_usage()
+ {
+ std::stringstream ss;
+ size_t max_command_len = 0;
+ for(auto& x:m_command_handlers)
+ if(x.first.size() > max_command_len)
+ max_command_len = x.first.size();
+
+ for(auto& x:m_command_handlers)
+ {
+ ss.width(max_command_len + 3);
+ ss << std::left << x.first << x.second.second << ENDL;
+ }
+ return ss.str();
+ }
+ void set_handler(const std::string& cmd, const console_command_handler& hndlr, const std::string& usage = "")
+ {
+ command_handlers_map::mapped_type & vt = m_command_handlers[cmd];
+ vt.first = hndlr;
+ vt.second = usage;
+ }
+ bool process_command_vec(const std::vector<std::string>& cmd)
+ {
+ if(!cmd.size())
+ return false;
+ auto it = m_command_handlers.find(cmd.front());
+ if(it == m_command_handlers.end())
+ return false;
+ std::vector<std::string> cmd_local(cmd.begin()+1, cmd.end());
+ return it->second.first(cmd_local);
+ }
+
+ bool process_command_str(const std::string& cmd)
+ {
+ std::vector<std::string> cmd_v;
+ boost::split(cmd_v,cmd,boost::is_any_of(" "), boost::token_compress_on);
+ return process_command_vec(cmd_v);
+ }
+
+ /*template<class t_srv>
+ bool start_handling(t_srv& srv, const std::string& usage_string = "")
+ {
+ start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
+ return true;
+ }*/
+
+ bool start_handling(const std::string& usage_string = "")
+ {
+ m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, usage_string) ));
+ return true;
+ }
+
+ bool stop_handling()
+ {
+ if(m_console_thread.get())
+ m_console_thread->interrupt();
+ return true;
+ }
+
+
+ bool run_handling(const std::string usage_string)
+ {
+ return default_console_handler2(boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string);
+ }
+
+ /*template<class t_srv>
+ bool run_handling(t_srv& srv, const std::string& usage_string)
+ {
+ return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
+ }*/
+
+ };
+
+ /* work around because of broken boost bind */
+ template<class t_server>
+ class srv_console_handlers_binder: public console_handlers_binder
+ {
+ bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
+ {
+ return console_handlers_binder::process_command_str(cmd);
+ }
+ public:
+ bool start_handling(t_server* psrv, const std::string& usage_string = "")
+ {
+ boost::thread(boost::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, usage_string) );
+ return true;
+ }
+
+ bool run_handling(t_server* psrv, const std::string usage_string)
+ {
+ return default_console_handler(psrv, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), usage_string);
+ }
+ };
+
+
+}
+
+
diff --git a/contrib/epee/include/file_io_utils.h b/contrib/epee/include/file_io_utils.h
new file mode 100644
index 000000000..7e8521838
--- /dev/null
+++ b/contrib/epee/include/file_io_utils.h
@@ -0,0 +1,455 @@
+// 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 _FILE_IO_UTILS_H_
+#define _FILE_IO_UTILS_H_
+
+
+//#include <sys/types.h>
+//#include <sys/stat.h>
+
+#include <iostream>
+#include <boost/filesystem.hpp>
+
+
+#ifndef MAKE64
+ #define MAKE64(low,high) ((__int64)(((DWORD)(low)) | ((__int64)((DWORD)(high))) << 32))
+#endif
+
+#ifdef WINDOWS_PLATFORM
+#include <psapi.h>
+#include <strsafe.h>
+#include <string.h>
+#include <mbstring.h>
+
+#endif
+
+
+
+namespace epee
+{
+namespace file_io_utils
+{
+#ifdef WINDOWS_PLATFORM
+
+ inline
+ std::string get_temp_file_name_a()
+ {
+ std::string str_result;
+ char sz_temp[MAX_PATH*2] = {0};
+ if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
+ return str_result;
+
+ char sz_temp_file[MAX_PATH*2] = {0};
+ if(!::GetTempFileNameA( sz_temp, "mail", 0, sz_temp_file))
+ return str_result;
+ sz_temp_file[sizeof(sz_temp_file)-1] = 0; //be happy!
+ str_result = sz_temp_file;
+ return str_result;
+ }
+
+
+#ifdef BOOST_LEXICAL_CAST_INCLUDED
+ inline
+ bool get_not_used_filename(const std::string& folder, OUT std::string& result_name)
+ {
+ DWORD folder_attr = ::GetFileAttributesA(folder.c_str());
+ if(folder_attr == INVALID_FILE_ATTRIBUTES)
+ return false;
+ if(!(folder_attr&FILE_ATTRIBUTE_DIRECTORY))
+ return false;
+
+
+ std::string base_name = folder + "\\tmp";
+ std::string tmp_name;
+ bool name_found = false;
+ int current_index = 0;
+ tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
+ while(!name_found)
+ {
+ if(INVALID_FILE_ATTRIBUTES == ::GetFileAttributesA(tmp_name.c_str()))
+ name_found = true;
+ else
+ {
+ current_index++;
+ tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
+ }
+ }
+ result_name = tmp_name;
+ return true;
+ }
+#endif
+
+ inline
+ std::string get_temp_folder_a()
+ {
+ std::string str_result;
+ char sz_temp[MAX_PATH*2] = {0};
+ if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
+ return str_result;
+ sz_temp[(sizeof(sz_temp)/sizeof(sz_temp[0])) -1] = 0;
+ str_result = sz_temp;
+ return str_result;
+ }
+
+ std::string convert_from_device_path_to_standart(const std::string& path)
+ {
+
+
+ STRSAFE_LPSTR pszFilename = (STRSAFE_LPSTR)path.c_str();
+
+ // Translate path with device name to drive letters.
+ char szTemp[4000] = {0};
+
+ if (::GetLogicalDriveStringsA(sizeof(szTemp)-1, szTemp))
+ {
+ char szName[MAX_PATH];
+ char szDrive[3] = " :";
+ BOOL bFound = FALSE;
+ char* p = szTemp;
+
+ do
+ {
+ // Copy the drive letter to the template string
+ *szDrive = *p;
+
+ // Look up each device name
+ if (::QueryDosDeviceA(szDrive, szName, sizeof(szName)))
+ {
+ UINT uNameLen = strlen(szName);
+
+ if (uNameLen < MAX_PATH)
+ {
+ bFound = _mbsnbicmp((const unsigned char*)pszFilename, (const unsigned char*)szName,
+ uNameLen) == 0;
+
+ if (bFound)
+ {
+ // Reconstruct pszFilename using szTempFile
+ // Replace device path with DOS path
+ char szTempFile[MAX_PATH] = {0};
+ StringCchPrintfA(szTempFile,
+ MAX_PATH,
+ "%s%s",
+ szDrive,
+ pszFilename+uNameLen);
+ return szTempFile;
+ //::StringCchCopyNA(pszFilename, MAX_PATH+1, szTempFile, strlen(szTempFile));
+ }
+ }
+ }
+
+ // Go to the next NULL character.
+ while (*p++);
+ } while (!bFound && *p); // end of string
+ }
+
+ return "";
+ }
+
+ inline
+ std::string get_process_path_by_pid(DWORD pid)
+ {
+ std::string res;
+
+ HANDLE hprocess = 0;
+ if( hprocess = ::OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pid) )
+ {
+ char buff[MAX_PATH]= {0};
+ if(!::GetModuleFileNameExA( hprocess, 0, buff, MAX_PATH - 1 ))
+ res = "Unknown_b";
+ else
+ {
+ buff[MAX_PATH - 1]=0; //be happy!
+ res = buff;
+ std::string::size_type a = res.rfind( '\\' );
+ if ( a != std::string::npos )
+ res.erase( 0, a+1);
+
+ }
+ ::CloseHandle( hprocess );
+ }else
+ res = "Unknown_a";
+
+ return res;
+ }
+
+
+
+
+
+ inline
+ std::wstring get_temp_file_name_w()
+ {
+ std::wstring str_result;
+ wchar_t sz_temp[MAX_PATH*2] = {0};
+ if(!::GetTempPathW( sizeof(sz_temp)/sizeof(sz_temp[0]), sz_temp ))
+ return str_result;
+
+ wchar_t sz_temp_file[MAX_PATH+1] = {0};
+ if(!::GetTempFileNameW( sz_temp, L"mail", 0, sz_temp_file))
+ return str_result;
+
+ sz_temp_file[(sizeof(sz_temp_file)/sizeof(sz_temp_file[0]))-1] = 0; //be happy!
+ str_result = sz_temp_file;
+ return str_result;
+ }
+#endif
+ inline
+ bool is_file_exist(const std::string& path)
+ {
+ boost::filesystem::path p(path);
+ return boost::filesystem::exists(p);
+ }
+
+ /*
+ inline
+ bool save_string_to_handle(HANDLE hfile, const std::string& str)
+ {
+
+
+
+ if( INVALID_HANDLE_VALUE != hfile )
+ {
+ DWORD dw;
+ if( !::WriteFile( hfile, str.data(), (DWORD) str.size(), &dw, NULL) )
+ {
+ int err_code = GetLastError();
+ //LOG_PRINT("Failed to write to file handle: " << hfile<< " Last error code:" << err_code << " : " << log_space::get_win32_err_descr(err_code), LOG_LEVEL_2);
+ return false;
+ }
+ ::CloseHandle(hfile);
+ return true;
+ }else
+ {
+ //LOG_WIN32_ERROR(::GetLastError());
+ return false;
+ }
+
+ return false;
+ }*/
+
+
+
+ inline
+ bool save_string_to_file(const std::string& path_to_file, const std::string& str)
+ {
+
+ try
+ {
+ std::ofstream fstream;
+ fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ fstream.open(path_to_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
+ fstream << str;
+ fstream.close();
+ return true;
+ }
+
+ catch(...)
+ {
+ return false;
+ }
+ }
+
+ /*
+ inline
+ bool load_form_handle(HANDLE hfile, std::string& str)
+ {
+ if( INVALID_HANDLE_VALUE != hfile )
+ {
+ bool res = true;
+ DWORD dw = 0;
+ DWORD fsize = ::GetFileSize(hfile, &dw);
+ if(fsize > 300000000)
+ {
+ ::CloseHandle(hfile);
+ return false;
+ }
+ if(fsize)
+ {
+ str.resize(fsize);
+ if(!::ReadFile( hfile, (LPVOID)str.data(), (DWORD)str.size(), &dw, NULL))
+ res = false;
+ }
+ ::CloseHandle(hfile);
+ return res;
+ }
+ return false;
+ }
+ */
+ inline
+ bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
+ {
+ boost::system::error_code ec;
+ ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
+ if(!ec)
+ return true;
+ else
+ return false;
+ }
+
+ inline
+ bool set_file_time(const std::string& path_to_file, const time_t& ft)
+ {
+ boost::system::error_code ec;
+ boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ft, ec);
+ if(!ec)
+ return true;
+ else
+ return false;
+ }
+
+
+ inline
+ bool load_file_to_string(const std::string& path_to_file, std::string& target_str)
+ {
+ try
+ {
+ std::ifstream fstream;
+ fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
+
+ std::ifstream::pos_type file_size = fstream.tellg();
+
+ if(file_size > 1000000000)
+ return false;//don't go crazy
+ size_t file_size_t = static_cast<size_t>(file_size);
+
+ target_str.resize(file_size_t);
+
+ fstream.seekg (0, std::ios::beg);
+ fstream.read((char*)target_str.data(), target_str.size());
+ fstream.close();
+ return true;
+ }
+
+ catch(...)
+ {
+ return false;
+ }
+ }
+
+ inline
+ bool append_string_to_file(const std::string& path_to_file, const std::string& str)
+ {
+ try
+ {
+ std::ofstream fstream;
+ fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+ fstream.open(path_to_file.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::app);
+ fstream << str;
+ fstream.close();
+ return true;
+ }
+
+ catch(...)
+ {
+ return false;
+ }
+ }
+
+ /*
+ bool remove_dir_and_subirs(const char* path_to_dir);
+
+ inline
+ bool clean_dir(const char* path_to_dir)
+ {
+ if(!path_to_dir)
+ return false;
+
+ std::string folder = path_to_dir;
+ WIN32_FIND_DATAA find_data = {0};
+ HANDLE hfind = ::FindFirstFileA((folder + "\\*.*").c_str(), &find_data);
+ if(INVALID_HANDLE_VALUE == hfind)
+ return false;
+ do{
+ if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
+ continue;
+
+ if(find_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if(!remove_dir_and_subirs((folder + "\\" + find_data.cFileName).c_str()))
+ return false;
+ }else
+ {
+ if(!::DeleteFileA((folder + "\\" + find_data.cFileName).c_str()))
+ return false;
+ }
+
+
+ }while(::FindNextFileA(hfind, &find_data));
+ ::FindClose(hfind);
+
+ return true;
+ }
+ */
+#ifdef WINDOWS_PLATFORM
+ inline bool get_folder_content(const std::string& path, std::list<WIN32_FIND_DATAA>& OUT target_list)
+ {
+ WIN32_FIND_DATAA find_data = {0};
+ HANDLE hfind = ::FindFirstFileA((path + "\\*.*").c_str(), &find_data);
+ if(INVALID_HANDLE_VALUE == hfind)
+ return false;
+ do{
+ if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
+ continue;
+
+ target_list.push_back(find_data);
+
+ }while(::FindNextFileA(hfind, &find_data));
+ ::FindClose(hfind);
+
+ return true;
+ }
+#endif
+ inline bool get_folder_content(const std::string& path, std::list<std::string>& OUT target_list, bool only_files = false)
+ {
+ try
+ {
+
+ boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
+ for ( boost::filesystem::directory_iterator itr( path ); itr != end_itr; ++itr )
+ {
+ if ( only_files && boost::filesystem::is_directory(itr->status()) )
+ {
+ continue;
+ }
+ target_list.push_back(itr->path().filename().string());
+ }
+
+ }
+
+ catch(...)
+ {
+ return false;
+ }
+ return true;
+ }
+}
+}
+
+#endif //_FILE_IO_UTILS_H_
diff --git a/contrib/epee/include/global_stream_operators.h b/contrib/epee/include/global_stream_operators.h
new file mode 100644
index 000000000..6fbdbc2ed
--- /dev/null
+++ b/contrib/epee/include/global_stream_operators.h
@@ -0,0 +1,35 @@
+// 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
+
+std::stringstream& operator<<(std::stringstream& out, const std::wstring& ws)
+{
+ std::string as = string_encoding::convert_to_ansii(ws);
+ out << as;
+ return out;
+}
diff --git a/contrib/epee/include/gzip_encoding.h b/contrib/epee/include/gzip_encoding.h
new file mode 100644
index 000000000..2be51e77d
--- /dev/null
+++ b/contrib/epee/include/gzip_encoding.h
@@ -0,0 +1,227 @@
+// 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 _GZIP_ENCODING_H_
+#define _GZIP_ENCODING_H_
+#include "net/http_client_base.h"
+#include "zlib/zlib.h"
+//#include "http.h"
+
+
+namespace epee
+{
+namespace net_utils
+{
+
+
+
+ class content_encoding_gzip: public i_sub_handler
+ {
+ public:
+ /*! \brief
+ * Function content_encoding_gzip : Constructor
+ *
+ */
+ inline
+ content_encoding_gzip(i_target_handler* powner_filter, bool is_deflate_mode = false):m_powner_filter(powner_filter),
+ m_is_stream_ended(false),
+ m_is_deflate_mode(is_deflate_mode),
+ m_is_first_update_in(true)
+ {
+ memset(&m_zstream_in, 0, sizeof(m_zstream_in));
+ memset(&m_zstream_out, 0, sizeof(m_zstream_out));
+ int ret = 0;
+ if(is_deflate_mode)
+ {
+ ret = inflateInit(&m_zstream_in);
+ ret = deflateInit(&m_zstream_out, Z_DEFAULT_COMPRESSION);
+ }else
+ {
+ ret = inflateInit2(&m_zstream_in, 0x1F);
+ ret = deflateInit2(&m_zstream_out, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8, Z_DEFAULT_STRATEGY);
+ }
+ }
+ /*! \brief
+ * Function content_encoding_gzip : Destructor
+ *
+ */
+ inline
+ ~content_encoding_gzip()
+ {
+ inflateEnd(& m_zstream_in );
+ deflateEnd(& m_zstream_out );
+ }
+ /*! \brief
+ * Function update_in : Entry point for income data
+ *
+ */
+ inline
+ virtual bool update_in( std::string& piece_of_transfer)
+ {
+
+ bool is_first_time_here = m_is_first_update_in;
+ m_is_first_update_in = false;
+
+ if(m_pre_decode.size())
+ m_pre_decode += piece_of_transfer;
+ else
+ m_pre_decode.swap(piece_of_transfer);
+ piece_of_transfer.clear();
+
+ std::string decode_summary_buff;
+
+ size_t ungzip_size = m_pre_decode.size() * 0x30;
+ std::string current_decode_buff(ungzip_size, 'X');
+
+ //Here the cycle is introduced where we unpack the buffer, the cycle is required
+ //because of the case where if after unpacking the data will exceed the awaited size, we will not halt with error
+ bool continue_unpacking = true;
+ bool first_step = true;
+ while(m_pre_decode.size() && continue_unpacking)
+ {
+
+ //fill buffers
+ m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
+ m_zstream_in.avail_in = (uInt)m_pre_decode.size();
+ m_zstream_in.next_out = (Bytef*)current_decode_buff.data();
+ m_zstream_in.avail_out = (uInt)ungzip_size;
+
+ int flag = Z_SYNC_FLUSH;
+ int ret = inflate(&m_zstream_in, flag);
+ CHECK_AND_ASSERT_MES(ret>=0 || m_zstream_in.avail_out ||m_is_deflate_mode, false, "content_encoding_gzip::update_in() Failed to inflate. err = " << ret);
+
+ if(Z_STREAM_END == ret)
+ m_is_stream_ended = true;
+ else if(Z_DATA_ERROR == ret && is_first_time_here && m_is_deflate_mode&& first_step)
+ {
+ // some servers (notably Apache with mod_deflate) don't generate zlib headers
+ // insert a dummy header and try again
+ static char dummy_head[2] =
+ {
+ 0x8 + 0x7 * 0x10,
+ (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
+ };
+ inflateReset(&m_zstream_in);
+ m_zstream_in.next_in = (Bytef*) dummy_head;
+ m_zstream_in.avail_in = sizeof(dummy_head);
+
+ ret = inflate(&m_zstream_in, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ LOCAL_ASSERT(0);
+ m_pre_decode.swap(piece_of_transfer);
+ return false;
+ }
+ m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
+ m_zstream_in.avail_in = (uInt)m_pre_decode.size();
+
+ ret = inflate(&m_zstream_in, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ LOCAL_ASSERT(0);
+ m_pre_decode.swap(piece_of_transfer);
+ return false;
+ }
+ }
+
+
+ //leave only unpacked part in the output buffer to start with it the next time
+ m_pre_decode.erase(0, m_pre_decode.size()-m_zstream_in.avail_in);
+ //if decoder gave nothing to return, then everything is ahead, now simply break
+ if(ungzip_size == m_zstream_in.avail_out)
+ break;
+
+ //decode_buff currently stores data parts that were unpacked, fix this size
+ current_decode_buff.resize(ungzip_size - m_zstream_in.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_size);
+ first_step = false;
+ }
+
+ //Process these data if required
+ bool res = true;
+
+ res = m_powner_filter->handle_target_data(decode_summary_buff);
+
+ return true;
+
+ }
+ /*! \brief
+ * Function stop : Entry point for stop signal and flushing cached data buffer.
+ *
+ */
+ inline
+ virtual void stop(std::string& OUT collect_remains)
+ {
+ }
+ protected:
+ private:
+ /*! \brief
+ * Pointer to parent HTTP-parser
+ */
+ i_target_handler* m_powner_filter;
+ /*! \brief
+ * ZLIB object for income stream
+ */
+ z_stream m_zstream_in;
+ /*! \brief
+ * ZLIB object for outcome stream
+ */
+ z_stream m_zstream_out;
+ /*! \brief
+ * Data that could not be unpacked immediately, left to wait for the next packet of data
+ */
+ std::string m_pre_decode;
+ /*! \brief
+ * The data are accumulated for a package in the buffer to send the web client
+ */
+ std::string m_pre_encode;
+ /*! \brief
+ * Signals that stream looks like ended
+ */
+ bool m_is_stream_ended;
+ /*! \brief
+ * If this flag is set, income data is in HTTP-deflate mode
+ */
+ bool m_is_deflate_mode;
+ /*! \brief
+ * Marks that it is a first data packet
+ */
+ bool m_is_first_update_in;
+ };
+}
+}
+
+
+
+#endif //_GZIP_ENCODING_H_
diff --git a/contrib/epee/include/hmac-md5.h b/contrib/epee/include/hmac-md5.h
new file mode 100644
index 000000000..2a4e0d401
--- /dev/null
+++ b/contrib/epee/include/hmac-md5.h
@@ -0,0 +1,93 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the libEtPan! project 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* hmac-md5.h -- HMAC_MD5 functions
+ */
+
+/*
+ * $Id: hmac-md5.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
+ */
+
+#ifndef HMAC_MD5_H
+#define HMAC_MD5_H 1
+
+namespace md5
+{
+
+
+
+#define HMAC_MD5_SIZE 16
+
+ /* intermediate MD5 context */
+ typedef struct HMAC_MD5_CTX_s {
+ MD5_CTX ictx, octx;
+ } HMAC_MD5_CTX;
+
+ /* intermediate HMAC state
+ * values stored in network byte order (Big Endian)
+ */
+ typedef struct HMAC_MD5_STATE_s {
+ UINT4 istate[4];
+ UINT4 ostate[4];
+ } HMAC_MD5_STATE;
+
+ /* One step hmac computation
+ *
+ * digest may be same as text or key
+ */
+ void hmac_md5(const unsigned char *text, int text_len,
+ const unsigned char *key, int key_len,
+ unsigned char digest[HMAC_MD5_SIZE]);
+
+ /* create context from key
+ */
+ void hmac_md5_init(HMAC_MD5_CTX *hmac,
+ const unsigned char *key, int key_len);
+
+ /* precalculate intermediate state from key
+ */
+ void hmac_md5_precalc(HMAC_MD5_STATE *hmac,
+ const unsigned char *key, int key_len);
+
+ /* initialize context from intermediate state
+ */
+ void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);
+
+#define hmac_md5_update(hmac, text, text_len) MD5Update(&(hmac)->ictx, (text), (text_len))
+
+ /* finish hmac from intermediate result. Intermediate result is zeroed.
+ */
+ void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+ HMAC_MD5_CTX *hmac);
+
+}
+
+#endif /* HMAC_MD5_H */
diff --git a/contrib/epee/include/include_base_utils.h b/contrib/epee/include/include_base_utils.h
new file mode 100644
index 000000000..8412a0083
--- /dev/null
+++ b/contrib/epee/include/include_base_utils.h
@@ -0,0 +1,34 @@
+// 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 BOOST_FILESYSTEM_VERSION 3
+#define ENABLE_RELEASE_LOGGING
+
+#include "misc_log_ex.h"
+
+
diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h
new file mode 100644
index 000000000..44efd4682
--- /dev/null
+++ b/contrib/epee/include/math_helper.h
@@ -0,0 +1,272 @@
+// 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 <list>
+#include <numeric>
+#include <boost/timer.hpp>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/random_generator.hpp>
+
+#include "misc_os_dependent.h"
+
+namespace epee
+{
+namespace math_helper
+{
+
+ template<typename val, int default_base>
+ class average
+ {
+ public:
+
+ average()
+ {
+ m_base = default_base;
+ m_last_avg_val = 0;
+ }
+
+ bool set_base()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+
+ m_base = default_base;
+ if(m_list.size() > m_base)
+ m_list.resize(m_base);
+
+ return true;
+ }
+
+ typedef val value_type;
+
+ void push(const value_type& vl)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+
+//#ifndef DEBUG_STUB
+ m_list.push_back(vl);
+ if(m_list.size() > m_base )
+ m_list.pop_front();
+//#endif
+ }
+
+ double update(const value_type& vl)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+//#ifndef DEBUG_STUB
+ push(vl);
+//#endif
+
+ return get_avg();
+ }
+
+ double get_avg()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+
+ value_type vl = std::accumulate(m_list.begin(), m_list.end(), value_type(0));
+ if(m_list.size())
+ return m_last_avg_val = (double)(vl/m_list.size());
+
+ return m_last_avg_val = (double)vl;
+ }
+
+ value_type get_last_val()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ if(m_list.size())
+ return m_list.back();
+
+ return 0;
+ }
+
+ private:
+ unsigned int m_base;
+ double m_last_avg_val;
+ std::list<value_type> m_list;
+ critical_section m_lock;
+ };
+
+
+#ifdef WINDOWS_PLATFORM
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class timing_guard_base
+ {
+ public:
+ virtual ~timing_guard_base(){};
+ };
+
+ template<class T>
+ class timing_guard: public timing_guard_base
+ {
+ public:
+ timing_guard(T& avrg):m_avrg(avrg)
+ {
+ m_start_ticks = ::GetTickCount();
+ }
+
+ ~timing_guard()
+ {
+ m_avrg.push(::GetTickCount()-m_start_ticks);
+ }
+
+ private:
+ T& m_avrg;
+ DWORD m_start_ticks;
+ };
+
+ template<class t_timing>
+ timing_guard_base* create_timing_guard(t_timing& timing){return new timing_guard<t_timing>(timing);}
+
+#define BEGIN_TIMING_ZONE(timing_var) { boost::shared_ptr<math_helper::timing_guard_base> local_timing_guard_ptr(math_helper::create_timing_guard(timing_var));
+#define END_TIMING_ZONE() }
+#endif
+
+//#ifdef WINDOWS_PLATFORM_EX
+ template<boost::uint64_t default_time_window>
+ class speed
+ {
+ public:
+
+ speed()
+ {
+ m_time_window = default_time_window;
+ m_last_speed_value = 0;
+ }
+ bool chick()
+ {
+#ifndef DEBUG_STUB
+ boost::uint64_t ticks = misc_utils::get_tick_count();
+ CRITICAL_REGION_BEGIN(m_lock);
+ m_chicks.push_back(ticks);
+ CRITICAL_REGION_END();
+ //flush(ticks);
+#endif
+ return true;
+ }
+
+ bool chick(size_t count)
+ {
+ for(size_t s = 0; s != count; s++)
+ chick();
+
+ return true;
+ }
+
+
+ size_t get_speed()
+ {
+ flush(misc_utils::get_tick_count());
+ return m_last_speed_value = m_chicks.size();
+ }
+ private:
+
+ bool flush(boost::uint64_t ticks)
+ {
+ CRITICAL_REGION_BEGIN(m_lock);
+ std::list<boost::uint64_t>::iterator it = m_chicks.begin();
+ while(it != m_chicks.end())
+ {
+ if(*it + m_time_window < ticks)
+ m_chicks.erase(it++);
+ else
+ break;
+ }
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ std::list<boost::uint64_t> m_chicks;
+ boost::uint64_t m_time_window;
+ size_t m_last_speed_value;
+ critical_section m_lock;
+ };
+//#endif
+
+ template<class tlist>
+ void randomize_list(tlist& t_list)
+ {
+ for(typename tlist::iterator it = t_list.begin();it!=t_list.end();it++)
+ {
+ size_t offset = rand()%t_list.size();
+ typename tlist::iterator it_2 = t_list.begin();
+ for(size_t local_offset = 0;local_offset!=offset;local_offset++)
+ it_2++;
+ if(it_2 == it)
+ continue;
+ std::swap(*it_2, *it);
+ }
+
+ }
+PRAGMA_WARNING_PUSH
+PRAGMA_GCC("GCC diagnostic ignored \"-Wstrict-aliasing\"")
+ inline
+ uint64_t generated_random_uint64()
+ {
+ boost::uuids::uuid id___ = boost::uuids::random_generator()();
+ return *reinterpret_cast<uint64_t*>(&id___.data[0]); //(*reinterpret_cast<uint64_t*>(&id___.data[0]) ^ *reinterpret_cast<uint64_t*>(&id___.data[8]));
+ }
+PRAGMA_WARNING_POP
+ template<int default_interval, bool start_immediate = true>
+ class once_a_time_seconds
+ {
+ public:
+ once_a_time_seconds():m_interval(default_interval)
+ {
+ m_last_worked_time = 0;
+ if(!start_immediate)
+ time(&m_last_worked_time);
+ }
+
+ template<class functor_t>
+ bool do_call(functor_t functr)
+ {
+ time_t current_time = 0;
+ time(&current_time);
+
+ if(current_time - m_last_worked_time > m_interval)
+ {
+ bool res = functr();
+ time(&m_last_worked_time);
+ return res;
+ }
+ return true;
+ }
+
+ private:
+ time_t m_last_worked_time;
+ time_t m_interval;
+ };
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/md5_l.h b/contrib/epee/include/md5_l.h
new file mode 100644
index 000000000..fe4c67db6
--- /dev/null
+++ b/contrib/epee/include/md5_l.h
@@ -0,0 +1,97 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the libEtPan! project 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id: md5.h,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
+ */
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+#ifndef MD5_H
+#define MD5_H
+
+
+#include "md5global.h"
+
+namespace md5
+{
+ /* MD5 context. */
+ typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+ } MD5_CTX;
+
+ static void MD5Init(MD5_CTX * context);
+ static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen );
+ static void MD5Final ( unsigned char digest[16], MD5_CTX *context );
+ static void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest);
+
+
+ inline bool md5( unsigned char *input, int ilen, unsigned char output[16] )
+ {
+ MD5_CTX ctx;
+
+ MD5Init( &ctx );
+ MD5Update( &ctx, input, ilen );
+ MD5Final( output, &ctx);
+
+ memset( &ctx, 0, sizeof( MD5_CTX) );
+ return true;
+ }
+
+
+}
+
+#include "md5_l.inl"
+
+#endif
diff --git a/contrib/epee/include/md5_l.inl b/contrib/epee/include/md5_l.inl
new file mode 100644
index 000000000..c3da1a3b0
--- /dev/null
+++ b/contrib/epee/include/md5_l.inl
@@ -0,0 +1,563 @@
+/*
+* libEtPan! -- a mail stuff library
+*
+* Copyright (C) 2001, 2005 - DINH Viet Hoa
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. 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.
+* 3. Neither the name of the libEtPan! project 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
+* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+* SUCH DAMAGE.
+*/
+
+/*
+* $Id: md5.c,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
+*/
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+*/
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+/* do i need all of this just for htonl()? damn. */
+//#include <sys/types.h>
+//#include <sys/param.h>
+//#include <sys/socket.h>
+//#include <netinet/in.h>
+
+
+
+#include "md5global.h"
+#include "md5_l.h"
+#include "hmac-md5.h"
+
+namespace md5
+{
+ /* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+ /*
+ static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+ static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+ static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+ static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+ static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+ */
+
+ static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
+ {
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+ }
+
+ /* Note: Replace "for loop" with standard memset if possible.
+ */
+
+ static void MD5_memset (POINTER output, int value, unsigned int len)
+ {
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+ }
+
+ static void MD5Transform (UINT4 state[4], unsigned char block[64]);
+
+ static unsigned char* PADDING()
+ {
+ static unsigned char local_PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ return local_PADDING;
+
+ }
+
+
+
+ /* F, G, H and I are basic MD5 functions.
+
+ */
+#ifdef I
+ /* This might be defined via NANA */
+#undef I
+#endif
+
+#define MD5_M_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define MD5_M_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define MD5_M_H(x, y, z) ((x) ^ (y) ^ (z))
+#define MD5_M_I(x, y, z) ((y) ^ ((x) | (~z)))
+
+ /* ROTATE_LEFT rotates x left n bits.
+
+ */
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+ /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ Rotation is separate from addition to prevent recomputation.
+ */
+
+#define FF(a, b, c, d, x, s, ac) { (a) += MD5_M_F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define GG(a, b, c, d, x, s, ac) { (a) += MD5_M_G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define HH(a, b, c, d, x, s, ac) { (a) += MD5_M_H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define II(a, b, c, d, x, s, ac) { (a) += MD5_M_I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+
+ /* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+
+ static void MD5Init(MD5_CTX * context)
+ {
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+ }
+
+ /* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the context.
+ */
+
+ static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen )
+ {
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+
+ */
+ if (inputLen >= partLen)
+ {
+ MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)input, partLen );
+ MD5Transform( context->state, context->buffer );
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, (unsigned char*)&input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i );
+
+ }
+
+ /* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+
+ */
+
+ static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+ {
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+ }
+
+ /* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+
+ */
+
+ static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+ {
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16)
+ | (((UINT4)input[j+3]) << 24);
+ }
+
+ /* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+
+ */
+
+ static void MD5Final ( unsigned char digest[16], MD5_CTX *context )
+ {
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+
+ */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING(), padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+
+ /* MD5 basic transformation. Transforms state based on block.
+
+ */
+
+ static void MD5Transform (UINT4 state[4], unsigned char block[64])
+ {
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+ }
+
+ /* Note: Replace "for loop" with standard memcpy if possible.
+
+ */
+ inline
+ void hmac_md5_init(HMAC_MD5_CTX *hmac,
+ const unsigned char *key,
+ int key_len)
+ {
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset(k_ipad, '\0', sizeof k_ipad);
+ MD5_memset(k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ MD5Init(&hmac->ictx); /* init inner context */
+ MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
+
+ MD5Init(&hmac->octx); /* init outer context */
+ MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
+
+ /* scrub the pads and key context (if used) */
+ MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
+ MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
+ MD5_memset( (POINTER)&tk, 0, sizeof(tk));
+
+ /* and we're done. */
+ }
+
+ /* The precalc and import routines here rely on the fact that we pad
+ * the key out to 64 bytes and use that to initialize the md5
+ * contexts, and that updating an md5 context with 64 bytes of data
+ * leaves nothing left over; all of the interesting state is contained
+ * in the state field, and none of it is left over in the count and
+ * buffer fields. So all we have to do is save the state field; we
+ * can zero the others when we reload it. Which is why the decision
+ * was made to pad the key out to 64 bytes in the first place. */
+ inline
+ void hmac_md5_precalc(HMAC_MD5_STATE *state,
+ const unsigned char *key,
+ int key_len)
+ {
+ HMAC_MD5_CTX hmac;
+ unsigned lupe;
+
+ hmac_md5_init(&hmac, key, key_len);
+ for (lupe = 0; lupe < 4; lupe++) {
+ state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
+ state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
+ }
+ MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
+ }
+
+
+ inline
+ void hmac_md5_import(HMAC_MD5_CTX *hmac,
+ HMAC_MD5_STATE *state)
+ {
+ unsigned lupe;
+ MD5_memset( (POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
+ for (lupe = 0; lupe < 4; lupe++) {
+ hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
+ hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
+ }
+ /* Init the counts to account for our having applied
+ * 64 bytes of key; this works out to 0x200 (64 << 3; see
+ * MD5Update above...) */
+ hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
+ }
+
+ inline
+ void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+ HMAC_MD5_CTX *hmac)
+ {
+ MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
+ MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
+ MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
+ }
+
+
+ void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest)
+ {
+ MD5_CTX context;
+
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset(k_ipad, '\0', sizeof k_ipad);
+ MD5_memset(k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+
+ MD5Init(&context); /* init context for 1st
+ * pass */
+ MD5Update(&context, k_ipad, 64); /* start with inner pad */
+ MD5Update(&context, text, text_len); /* then text of datagram */
+ MD5Final(digest, &context); /* finish up 1st pass */
+
+ /*
+ * perform outer MD5
+ */
+ MD5Init(&context); /* init context for 2nd
+ * pass */
+ MD5Update(&context, k_opad, 64); /* start with outer pad */
+ MD5Update(&context, digest, 16); /* then results of 1st
+ * hash */
+ MD5Final(digest, &context); /* finish up 2nd pass */
+
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/md5global.h b/contrib/epee/include/md5global.h
new file mode 100644
index 000000000..afc229019
--- /dev/null
+++ b/contrib/epee/include/md5global.h
@@ -0,0 +1,77 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the name of the libEtPan! project 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id: md5global.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
+ */
+
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+#ifndef MD5GLOBAL_H
+#define MD5GLOBAL_H
+
+namespace md5
+{
+
+
+ /* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+ /* POINTER defines a generic pointer type */
+ typedef unsigned char *POINTER;
+
+ /* UINT2 defines a two byte word */
+ typedef unsigned short int UINT2;
+
+ /* UINT4 defines a four byte word */
+ //typedef unsigned long int UINT4;
+ typedef unsigned int UINT4;
+
+ /* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+}
+
+#endif
diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h
new file mode 100644
index 000000000..d5157365c
--- /dev/null
+++ b/contrib/epee/include/misc_language.h
@@ -0,0 +1,162 @@
+// 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 <limits>
+#include <boost/thread.hpp>
+#include <boost/utility/value_init.hpp>
+namespace epee
+{
+#define STD_TRY_BEGIN() try {
+
+#define STD_TRY_CATCH(where_, ret_val) \
+ } \
+ catch (const std::exception &e) \
+ { \
+ LOG_ERROR("EXCEPTION: " << where_ << ", mes: "<< e.what()); \
+ return ret_val; \
+ } \
+ catch (...) \
+ { \
+ LOG_ERROR("EXCEPTION: " << where_ ); \
+ return ret_val; \
+ }
+
+
+
+#define AUTO_VAL_INIT(v) boost::value_initialized<decltype(v)>()
+
+namespace misc_utils
+{
+ template<typename t_type>
+ t_type get_max_t_val(t_type t)
+ {
+ return (std::numeric_limits<t_type>::max)();
+ }
+
+
+ template<typename t_iterator>
+ t_iterator move_it_forward(t_iterator it, size_t count)
+ {
+ while(count--)
+ it++;
+ return it;
+ }
+
+ template<typename t_iterator>
+ t_iterator move_it_backward(t_iterator it, size_t count)
+ {
+ while(count--)
+ it--;
+ return it;
+ }
+
+
+ // TEMPLATE STRUCT less
+ template<class _Ty>
+ struct less_as_pod
+ : public std::binary_function<_Ty, _Ty, bool>
+ { // functor for operator<
+ bool operator()(const _Ty& _Left, const _Ty& _Right) const
+ { // apply operator< to operands
+ return memcmp(&_Left, &_Right, sizeof(_Left)) < 0;
+ }
+ };
+
+ template<class _Ty>
+ bool is_less_as_pod(const _Ty& _Left, const _Ty& _Right)
+ { // apply operator< to operands
+ return memcmp(&_Left, &_Right, sizeof(_Left)) < 0;
+ }
+
+
+ inline
+ bool sleep_no_w(long ms )
+ {
+ boost::this_thread::sleep(
+ boost::get_system_time() +
+ boost::posix_time::milliseconds( std::max<long>(ms,0) ) );
+
+ return true;
+ }
+
+ template<class type_vec_type>
+ type_vec_type median(std::vector<type_vec_type> &v)
+ {
+ if(v.empty())
+ return boost::value_initialized<type_vec_type>();
+ if(v.size() == 1)
+ return v[0];
+
+ size_t n = (v.size()) / 2;
+ std::sort(v.begin(), v.end());
+ //nth_element(v.begin(), v.begin()+n-1, v.end());
+ if(v.size()%2)
+ {//1, 3, 5...
+ return v[n];
+ }else
+ {//2, 4, 6...
+ return (v[n-1] + v[n])/2;
+ }
+
+ }
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+
+ struct call_befor_die_base
+ {
+ virtual ~call_befor_die_base(){}
+ };
+
+ typedef boost::shared_ptr<call_befor_die_base> auto_scope_leave_caller;
+
+
+ template<class t_scope_leave_handler>
+ struct call_befor_die: public call_befor_die_base
+ {
+ t_scope_leave_handler m_func;
+ call_befor_die(t_scope_leave_handler f):m_func(f)
+ {}
+ ~call_befor_die()
+ {
+ m_func();
+ }
+ };
+
+ template<class t_scope_leave_handler>
+ auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
+ {
+ auto_scope_leave_caller slc(new call_befor_die<t_scope_leave_handler>(f));
+ return slc;
+ }
+
+}
+}
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
new file mode 100644
index 000000000..446d4bd3b
--- /dev/null
+++ b/contrib/epee/include/misc_log_ex.h
@@ -0,0 +1,1426 @@
+// 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 _MISC_LOG_EX_H_
+#define _MISC_LOG_EX_H_
+
+//#include <windows.h>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <fstream>
+#include <algorithm>
+#include <list>
+#include <map>
+#include <time.h>
+#include <boost/cstdint.hpp>
+#include <boost/thread.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include "static_initializer.h"
+#include "string_tools.h"
+#include "time_helper.h"
+#include "misc_os_dependent.h"
+
+
+#include "syncobj.h"
+
+
+
+
+#define LOG_LEVEL_SILENT -1
+#define LOG_LEVEL_0 0
+#define LOG_LEVEL_1 1
+#define LOG_LEVEL_2 2
+#define LOG_LEVEL_3 3
+#define LOG_LEVEL_4 4
+#define LOG_LEVEL_MIN LOG_LEVEL_SILENT
+#define LOG_LEVEL_MAX LOG_LEVEL_4
+
+
+
+
+#define LOGGER_NULL 0
+#define LOGGER_FILE 1
+#define LOGGER_DEBUGGER 2
+#define LOGGER_CONSOLE 3
+#define LOGGER_DUMP 4
+
+
+#ifndef LOCAL_ASSERT
+#include <assert.h>
+#if (defined _MSC_VER)
+#define LOCAL_ASSERT(expr) {if(epee::debug::get_set_enable_assert()){_ASSERTE(expr);}}
+#else
+#define LOCAL_ASSERT(expr)
+#endif
+
+#endif
+
+namespace epee
+{
+namespace debug
+{
+ inline bool get_set_enable_assert(bool set = false, bool v = false)
+ {
+ static bool e = true;
+ if(set)
+ e = v;
+ return e;
+ }
+}
+namespace log_space
+{
+ class logger;
+ class log_message;
+ class log_singletone;
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ enum console_colors
+ {
+ console_color_default,
+ console_color_white,
+ console_color_red,
+ console_color_green,
+ console_color_blue,
+ console_color_cyan,
+ console_color_magenta,
+ console_color_yellow
+ };
+
+
+ struct ibase_log_stream
+ {
+ ibase_log_stream(){}
+ virtual ~ibase_log_stream(){}
+ virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)=0;
+ virtual int get_type(){return 0;}
+
+ virtual bool set_max_logfile_size(boost::uint64_t max_size){return true;};
+ virtual bool set_log_rotate_cmd(const std::string& cmd){return true;};
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ /*struct ibase_log_value
+ {
+ public:
+ virtual void debug_out( std::stringstream* p_stream)const = 0;
+ };*/
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ /*class log_message: public std::stringstream
+ {
+ public:
+ log_message(const log_message& lm): std::stringstream(), std::stringstream::basic_ios()
+ {}
+ log_message(){}
+
+ template<class T>
+ log_message& operator<< (T t)
+ {
+ std::stringstream* pstrstr = this;
+ (*pstrstr) << t;
+
+ return *this;
+ }
+ };
+ inline
+ log_space::log_message& operator<<(log_space::log_message& sstream, const ibase_log_value& log_val)
+ {
+ log_val.debug_out(&sstream);
+ return sstream;
+ }
+ */
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct delete_ptr
+ {
+ template <class P>
+ void operator() (P p)
+ {
+ delete p.first;
+ }
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ //------------------------------------------------------------------------
+#define max_dbg_str_len 80
+#ifdef _MSC_VER
+ class debug_output_stream: public ibase_log_stream
+ {
+ virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)
+ {
+ for ( int i = 0; i < buffer_len; i = i + max_dbg_str_len )
+ {
+ std::string s( buffer + i, buffer_len- i < max_dbg_str_len ?
+ buffer_len - i : max_dbg_str_len );
+
+ ::OutputDebugStringA( s.c_str() );
+ }
+ return true;
+ }
+
+ };
+#endif
+
+ inline void set_console_color(int color, bool bright)
+ {
+ switch(color)
+ {
+ case console_color_default:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE| (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;37m";
+ else
+ std::cout << "\033[0m";
+#endif
+ }
+ break;
+ case console_color_white:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;37m";
+ else
+ std::cout << "\033[0;37m";
+#endif
+ }
+ break;
+ case console_color_red:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;31m";
+ else
+ std::cout << "\033[0;31m";
+#endif
+ }
+ break;
+ case console_color_green:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;32m";
+ else
+ std::cout << "\033[0;32m";
+#endif
+ }
+ break;
+
+ case console_color_blue:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_INTENSITY);//(bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;34m";
+ else
+ std::cout << "\033[0;34m";
+#endif
+ }
+ break;
+
+ case console_color_cyan:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_GREEN | FOREGROUND_BLUE | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;36m";
+ else
+ std::cout << "\033[0;36m";
+#endif
+ }
+ break;
+
+ case console_color_magenta:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_BLUE | FOREGROUND_RED | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;35m";
+ else
+ std::cout << "\033[0;35m";
+#endif
+ }
+ break;
+
+ case console_color_yellow:
+ {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | (bright ? FOREGROUND_INTENSITY:0));
+#else
+ if(bright)
+ std::cout << "\033[1;33m";
+ else
+ std::cout << "\033[0;33m";
+#endif
+ }
+ break;
+
+ }
+ }
+
+ inline void reset_console_color() {
+#ifdef WIN32
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+#else
+ std::cout << "\033[0m";
+#endif
+ }
+
+ class console_output_stream: public ibase_log_stream
+ {
+#ifdef _MSC_VER
+ bool m_have_to_kill_console;
+#endif
+
+ public:
+ console_output_stream()
+ {
+#ifdef _MSC_VER
+
+ if(!::GetStdHandle(STD_OUTPUT_HANDLE))
+ m_have_to_kill_console = true;
+ else
+ m_have_to_kill_console = false;
+
+ ::AllocConsole();
+#endif
+ }
+
+ ~console_output_stream()
+ {
+#ifdef _MSC_VER
+ if(m_have_to_kill_console)
+ ::FreeConsole();
+#endif
+ }
+ int get_type(){return LOGGER_CONSOLE;}
+
+
+
+ virtual bool out_buffer( const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL)
+ {
+ if(plog_name)
+ return true; //skip alternative logs from console
+
+ set_console_color(color, log_level < 1);
+
+#ifdef _MSC_VER
+ const char* ptarget_buf = NULL;
+ char* pallocated_buf = NULL;
+
+ //
+ int i = 0;
+ for(; i < buffer_len; i++)
+ if(buffer[i] == '\a') break;
+ if(i == buffer_len)
+ ptarget_buf = buffer;
+ else
+ {
+ pallocated_buf = new char[buffer_len];
+ ptarget_buf = pallocated_buf;
+ for(i = 0; i < buffer_len; i++)
+ {
+ if(buffer[i] == '\a')
+ pallocated_buf[i] = '^';
+ else
+ pallocated_buf[i] = buffer[i];
+ }
+ }
+
+ //boost::uint32_t b = 0;
+ //::WriteConsoleA(::GetStdHandle(STD_OUTPUT_HANDLE), ptarget_buf, buffer_len, (DWORD*)&b, 0);
+ std::cout << ptarget_buf;
+ if(pallocated_buf) delete [] pallocated_buf;
+#else
+ std::string buf(buffer, buffer_len);
+ for(size_t i = 0; i!= buf.size(); i++)
+ {
+ if(buf[i] == 7 || buf[i] == -107)
+ buf[i] = '^';
+ }
+
+ std::cout << buf;
+#endif
+ reset_console_color();
+ return true;
+ }
+
+
+ };
+
+ inline bool rotate_log_file(const char* pfile_path)
+ {
+#ifdef _MSC_VER
+ if(!pfile_path)
+ return false;
+
+ std::string file_path = pfile_path;
+ std::string::size_type a = file_path .rfind('.');
+ if ( a != std::string::npos )
+ file_path .erase( a, file_path .size());
+
+ ::DeleteFileA( (file_path + ".0").c_str() );
+ ::MoveFileA( (file_path + ".log").c_str(), (file_path + ".0").c_str() );
+#else
+ return false;//not implemented yet
+#endif
+ return true;
+ }
+
+
+
+
+ //--------------------------------------------------------------------------//
+ class file_output_stream : public ibase_log_stream
+ {
+ public:
+ typedef std::map<std::string, std::ofstream*> named_log_streams;
+
+ file_output_stream( std::string default_log_file_name, std::string log_path )
+ {
+ m_default_log_filename = default_log_file_name;
+ m_max_logfile_size = 0;
+ m_default_log_path = log_path;
+ m_pdefault_file_stream = add_new_stream_and_open(default_log_file_name.c_str());
+ }
+
+ ~file_output_stream()
+ {
+ for(named_log_streams::iterator it = m_log_file_names.begin(); it!=m_log_file_names.end(); it++)
+ {
+ if ( it->second->is_open() )
+ {
+ it->second->flush();
+ it->second->close();
+ }
+ delete it->second;
+ }
+ }
+ private:
+ named_log_streams m_log_file_names;
+ std::string m_default_log_path;
+ std::ofstream* m_pdefault_file_stream;
+ std::string m_log_rotate_cmd;
+ std::string m_default_log_filename;
+ boost::uint64_t m_max_logfile_size;
+
+
+ std::ofstream* add_new_stream_and_open(const char* pstream_name)
+ {
+ //log_space::rotate_log_file((m_default_log_path + "\\" + pstream_name).c_str());
+
+ std::ofstream* pstream = (m_log_file_names[pstream_name] = new std::ofstream);
+ std::string target_path = m_default_log_path + "/" + pstream_name;
+ pstream->open( target_path.c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */);
+ if(pstream->fail())
+ return NULL;
+ return pstream;
+ }
+
+ bool set_max_logfile_size(boost::uint64_t max_size)
+ {
+ m_max_logfile_size = max_size;
+ return true;
+ }
+
+ bool set_log_rotate_cmd(const std::string& cmd)
+ {
+ m_log_rotate_cmd = cmd;
+ return true;
+ }
+
+
+
+ virtual bool out_buffer( const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL )
+ {
+ std::ofstream* m_target_file_stream = m_pdefault_file_stream;
+ if(plog_name)
+ { //find named stream
+ named_log_streams::iterator it = m_log_file_names.find(plog_name);
+ if(it == m_log_file_names.end())
+ m_target_file_stream = add_new_stream_and_open(plog_name);
+ else
+ m_target_file_stream = it->second;
+ }
+ if(!m_target_file_stream || !m_target_file_stream->is_open())
+ return false;//TODO: add assert here
+
+ m_target_file_stream->write(buffer, buffer_len );
+ m_target_file_stream->flush();
+
+ if(m_max_logfile_size)
+ {
+ std::ofstream::pos_type pt = m_target_file_stream->tellp();
+ boost::uint64_t current_sz = pt;
+ if(current_sz > m_max_logfile_size)
+ {
+ std::cout << "current_sz= " << current_sz << " m_max_logfile_size= " << m_max_logfile_size << std::endl;
+ std::string log_file_name;
+ if(!plog_name)
+ log_file_name = m_default_log_filename;
+ else
+ log_file_name = plog_name;
+
+ m_target_file_stream->close();
+ std::string new_log_file_name = log_file_name;
+
+ time_t tm = 0;
+ time(&tm);
+
+ int err_count = 0;
+ boost::system::error_code ec;
+ do
+ {
+ new_log_file_name = string_tools::cut_off_extension(log_file_name);
+ if(err_count)
+ new_log_file_name += misc_utils::get_time_str_v2(tm) + "(" + boost::lexical_cast<std::string>(err_count) + ")" + ".log";
+ else
+ new_log_file_name += misc_utils::get_time_str_v2(tm) + ".log";
+
+ err_count++;
+ }while(boost::filesystem::exists(m_default_log_path + "/" + new_log_file_name, ec));
+
+ std::string new_log_file_path = m_default_log_path + "/" + new_log_file_name;
+ boost::filesystem::rename(m_default_log_path + "/" + log_file_name, new_log_file_path, ec);
+ if(ec)
+ {
+ std::cout << "Filed to rename, ec = " << ec.message() << std::endl;
+ }
+
+ if(m_log_rotate_cmd.size())
+ {
+
+ std::string m_log_rotate_cmd_local_copy = m_log_rotate_cmd;
+ //boost::replace_all(m_log_rotate_cmd, "[*SOURCE*]", new_log_file_path);
+ boost::replace_all(m_log_rotate_cmd_local_copy, "[*TARGET*]", new_log_file_path);
+
+ misc_utils::call_sys_cmd(m_log_rotate_cmd_local_copy);
+ }
+
+ m_target_file_stream->open( (m_default_log_path + "/" + log_file_name).c_str(), std::ios_base::out | std::ios::app /*ios_base::trunc */);
+ if(m_target_file_stream->fail())
+ return false;
+ }
+ }
+
+ return true;
+ }
+ int get_type(){return LOGGER_FILE;}
+ };
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class log_stream_splitter
+ {
+ public:
+ typedef std::list<std::pair<ibase_log_stream*, int> > streams_container;
+
+ log_stream_splitter(){}
+ ~log_stream_splitter()
+ {
+ //free pointers
+ std::for_each(m_log_streams.begin(), m_log_streams.end(), delete_ptr());
+ }
+
+ bool set_max_logfile_size(boost::uint64_t max_size)
+ {
+ for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++)
+ it->first->set_max_logfile_size(max_size);
+ return true;
+ }
+
+ bool set_log_rotate_cmd(const std::string& cmd)
+ {
+ for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++)
+ it->first->set_log_rotate_cmd(cmd);
+ return true;
+ }
+
+ bool do_log_message(const std::string& rlog_mes, int log_level, int color, const char* plog_name = NULL)
+ {
+ std::string str_mess = rlog_mes;
+ size_t str_len = str_mess.size();
+ const char* pstr = str_mess.c_str();
+ for(streams_container::iterator it = m_log_streams.begin(); it!=m_log_streams.end();it++)
+ if(it->second >= log_level)
+ it->first->out_buffer(pstr, (int)str_len, log_level, color, plog_name);
+ return true;
+ }
+
+ bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4 )
+ {
+ ibase_log_stream* ls = NULL;
+
+ switch( type )
+ {
+ case LOGGER_FILE:
+ ls = new file_output_stream( pdefault_file_name, pdefault_log_folder );
+ break;
+
+ case LOGGER_DEBUGGER:
+#ifdef _MSC_VER
+ ls = new debug_output_stream( );
+#else
+ return false;//not implemented yet
+#endif
+ break;
+ case LOGGER_CONSOLE:
+ ls = new console_output_stream( );
+ break;
+ }
+
+ if ( ls ) {
+ m_log_streams.push_back(streams_container::value_type(ls, log_level_limit));
+ return true;
+ }
+ return ls ? true:false;
+ }
+ bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 )
+ {
+ m_log_streams.push_back(streams_container::value_type(pstream, log_level_limit) );
+ return true;
+ }
+
+ bool remove_logger(int type)
+ {
+ streams_container::iterator it = m_log_streams.begin();
+ for(;it!=m_log_streams.end(); it++)
+ {
+ if(it->first->get_type() == type)
+ {
+ delete it->first;
+ m_log_streams.erase(it);
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ protected:
+ private:
+
+ streams_container m_log_streams;
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ inline int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1);
+ inline int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0);
+ inline bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false);
+ inline bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false);
+
+
+ inline std::string get_daytime_string2()
+ {
+ boost::posix_time::ptime p = boost::posix_time::microsec_clock::local_time();
+ return misc_utils::get_time_str_v3(p);
+ }
+ inline std::string get_day_time_string()
+ {
+ return get_daytime_string2();
+ //time_t tm = 0;
+ //time(&tm);
+ //return misc_utils::get_time_str(tm);
+ }
+
+ inline std::string get_time_string()
+ {
+ return get_daytime_string2();
+
+ }
+#ifdef _MSC_VER
+ inline std::string get_time_string_adv(SYSTEMTIME* pst = NULL)
+ {
+ SYSTEMTIME st = {0};
+ if(!pst)
+ {
+ pst = &st;
+ GetSystemTime(&st);
+ }
+ std::stringstream str_str;
+ str_str.fill('0');
+ str_str << std::setw(2) << pst->wHour << "_"
+ << std::setw(2) << pst->wMinute << "_"
+ << std::setw(2) << pst->wSecond << "_"
+ << std::setw(3) << pst->wMilliseconds;
+ return str_str.str();
+ }
+#endif
+
+
+
+
+
+ class logger
+ {
+ public:
+ friend class log_singletone;
+
+ logger()
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ init();
+ CRITICAL_REGION_END();
+ }
+ ~logger()
+ {
+ }
+
+ bool set_max_logfile_size(boost::uint64_t max_size)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ m_log_target.set_max_logfile_size(max_size);
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ bool set_log_rotate_cmd(const std::string& cmd)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ m_log_target.set_log_rotate_cmd(cmd);
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ bool take_away_journal(std::list<std::string>& journal)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ m_journal.swap(journal);
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+ bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool add_to_journal = false, const char* plog_name = NULL)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ m_log_target.do_log_message(rlog_mes, log_level, color, plog_name);
+ if(add_to_journal)
+ m_journal.push_back(rlog_mes);
+
+ return true;
+ CRITICAL_REGION_END();
+ }
+
+ bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder , int log_level_limit = LOG_LEVEL_4)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ return m_log_target.add_logger( type, pdefault_file_name, pdefault_log_folder, log_level_limit);
+ CRITICAL_REGION_END();
+ }
+ bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ return m_log_target.add_logger(pstream, log_level_limit);
+ CRITICAL_REGION_END();
+ }
+
+ bool remove_logger(int type)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ return m_log_target.remove_logger(type);
+ CRITICAL_REGION_END();
+ }
+
+
+ bool set_thread_prefix(const std::string& prefix)
+ {
+ CRITICAL_REGION_BEGIN(m_critical_sec);
+ m_thr_prefix_strings[misc_utils::get_thread_string_id()] = prefix;
+ CRITICAL_REGION_END();
+ return true;
+ }
+
+
+ std::string get_default_log_file()
+ {
+ return m_default_log_file;
+ }
+
+ std::string get_default_log_folder()
+ {
+ return m_default_log_folder;
+ }
+
+ protected:
+ private:
+ bool init()
+ {
+ //
+
+ m_process_name = string_tools::get_current_module_name();
+
+ init_log_path_by_default();
+
+ //init default set of loggers
+ init_default_loggers();
+
+ std::stringstream ss;
+ ss << get_time_string() << " Init logging. Level=" << get_set_log_detalisation_level()
+ << " Log path=" << m_default_log_folder << std::endl;
+ this->do_log_message(ss.str(), console_color_white, LOG_LEVEL_0);
+ return true;
+ }
+ bool init_default_loggers()
+ {
+ //TODO:
+ return true;
+ }
+
+ bool init_log_path_by_default()
+ {
+ //load process name
+ m_default_log_folder = string_tools::get_current_module_folder();
+
+ m_default_log_file = m_process_name;
+ std::string::size_type a = m_default_log_file.rfind('.');
+ if ( a != std::string::npos )
+ m_default_log_file.erase( a, m_default_log_file.size());
+ m_default_log_file += ".log";
+
+ return true;
+ }
+
+ log_stream_splitter m_log_target;
+
+ std::string m_default_log_folder;
+ std::string m_default_log_file;
+ std::string m_process_name;
+ std::map<std::string, std::string> m_thr_prefix_strings;
+ std::list<std::string> m_journal;
+ critical_section m_critical_sec;
+ };
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class log_singletone
+ {
+ public:
+ friend class initializer<log_singletone>;
+ friend class logger;
+ static int get_log_detalisation_level()
+ {
+ get_or_create_instance();//to initialize logger, if it not initialized
+ return get_set_log_detalisation_level();
+ }
+
+ static bool is_filter_error(int error_code)
+ {
+ return false;
+ }
+
+
+ static bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool keep_in_journal, const char* plog_name = NULL)
+ {
+ logger* plogger = get_or_create_instance();
+ bool res = false;
+ if(plogger)
+ res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name);
+ else
+ { //globally uninitialized, create new logger for each call of do_log_message() and then delete it
+ plogger = new logger();
+ //TODO: some extra initialization
+ res = plogger->do_log_message(rlog_mes, log_level, color, keep_in_journal, plog_name);
+ delete plogger;
+ plogger = NULL;
+ }
+ return res;
+ }
+
+ static bool take_away_journal(std::list<std::string>& journal)
+ {
+ logger* plogger = get_or_create_instance();
+ bool res = false;
+ if(plogger)
+ res = plogger->take_away_journal(journal);
+
+ return res;
+ }
+
+ static bool set_max_logfile_size(boost::uint64_t file_size)
+ {
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->set_max_logfile_size(file_size);
+ }
+
+
+ static bool set_log_rotate_cmd(const std::string& cmd)
+ {
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->set_log_rotate_cmd(cmd);
+ }
+
+
+ static bool add_logger( int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4)
+ {
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->add_logger(type, pdefault_file_name, pdefault_log_folder, log_level_limit);
+ }
+
+ static std::string get_default_log_file()
+ {
+ logger* plogger = get_or_create_instance();
+ if(plogger)
+ return plogger->get_default_log_file();
+
+ return "";
+ }
+
+ static std::string get_default_log_folder()
+ {
+ logger* plogger = get_or_create_instance();
+ if(plogger)
+ return plogger->get_default_log_folder();
+
+ return "";
+ }
+
+ static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 )
+ {
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->add_logger(pstream, log_level_limit);
+ }
+
+
+ static bool remove_logger( int type )
+ {
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->remove_logger(type);
+ }
+PUSH_WARNINGS
+DISABLE_GCC_WARNING(maybe-uninitialized)
+ static int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1)
+ {
+ static int log_detalisation_level = LOG_LEVEL_1;
+ if(is_need_set)
+ log_detalisation_level = log_level_to_set;
+ return log_detalisation_level;
+ }
+POP_WARNINGS
+ static int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0)
+ {
+ static int val_time_log_level = LOG_LEVEL_0;
+ if(is_need_set)
+ val_time_log_level = time_log_level;
+
+ return val_time_log_level;
+ }
+
+ static int get_set_process_level(bool is_need_set = false, int process_log_level = LOG_LEVEL_0)
+ {
+ static int val_process_log_level = LOG_LEVEL_0;
+ if(is_need_set)
+ val_process_log_level = process_log_level;
+
+ return val_process_log_level;
+ }
+
+ /*static int get_set_tid_level(bool is_need_set = false, int tid_log_level = LOG_LEVEL_0)
+ {
+ static int val_tid_log_level = LOG_LEVEL_0;
+ if(is_need_set)
+ val_tid_log_level = tid_log_level;
+
+ return val_tid_log_level;
+ }*/
+
+ static bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false)
+ {
+ static bool is_need = false;
+ if(is_need_set)
+ is_need = is_need_val;
+
+ return is_need;
+ }
+
+ static bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false)
+ {
+ static bool is_need = true;
+ if(is_need_set)
+ is_need = is_need_val;
+
+ return is_need;
+ }
+ static boost::uint64_t get_set_err_count(bool is_need_set = false, boost::uint64_t err_val = false)
+ {
+ static boost::uint64_t err_count = 0;
+ if(is_need_set)
+ err_count = err_val;
+
+ return err_count;
+ }
+
+
+#ifdef _MSC_VER
+
+
+ static void SetThreadName( DWORD dwThreadID, const char* threadName)
+ {
+#define MS_VC_EXCEPTION 0x406D1388
+
+#pragma pack(push,8)
+ typedef struct tagTHREADNAME_INFO
+ {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+ } THREADNAME_INFO;
+#pragma pack(pop)
+
+
+
+ Sleep(10);
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = (char*)threadName;
+ info.dwThreadID = dwThreadID;
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+ }
+#endif
+
+ static bool set_thread_log_prefix(const std::string& prefix)
+ {
+#ifdef _MSC_VER
+ SetThreadName(-1, prefix.c_str());
+#endif
+
+
+ logger* plogger = get_or_create_instance();
+ if(!plogger) return false;
+ return plogger->set_thread_prefix(prefix);
+ }
+
+
+ static std::string get_prefix_entry()
+ {
+ std::stringstream str_prefix;
+ //write time entry
+ if ( get_set_time_level() <= get_set_log_detalisation_level() )
+ str_prefix << get_day_time_string() << " ";
+
+ //write process info
+ logger* plogger = get_or_create_instance();
+ //bool res = false;
+ if(!plogger)
+ { //globally uninitialized, create new logger for each call of get_prefix_entry() and then delete it
+ plogger = new logger();
+ }
+
+ //if ( get_set_need_proc_name() && get_set_process_level() <= get_set_log_detalisation_level() )
+ // str_prefix << "[" << plogger->m_process_name << " (id=" << GetCurrentProcessId() << ")] ";
+//#ifdef _MSC_VER_EX
+ if ( get_set_need_thread_id() /*&& get_set_tid_level() <= get_set_log_detalisation_level()*/ )
+ str_prefix << "tid:" << misc_utils::get_thread_string_id() << " ";
+//#endif
+
+ if(plogger->m_thr_prefix_strings.size())
+ {
+ CRITICAL_REGION_LOCAL(plogger->m_critical_sec);
+ std::string thr_str = misc_utils::get_thread_string_id();
+ std::map<std::string, std::string>::iterator it = plogger->m_thr_prefix_strings.find(thr_str);
+ if(it!=plogger->m_thr_prefix_strings.end())
+ {
+ str_prefix << it->second;
+ }
+ }
+
+
+ if(get_set_is_uninitialized())
+ delete plogger;
+
+ return str_prefix.str();
+ }
+
+ private:
+ log_singletone(){}//restric to create an instance
+ //static initializer<log_singletone> m_log_initializer;//must be in one .cpp file (for example main.cpp) via DEFINE_LOGGING macro
+
+ static bool init()
+ {
+ return true;/*do nothing here*/
+ }
+ static bool un_init()
+ {
+ //delete object
+ logger* plogger = get_set_instance_internal();
+ if(plogger) delete plogger;
+ //set uninitialized
+ get_set_is_uninitialized(true, true);
+ get_set_instance_internal(true, NULL);
+ return true;
+ }
+
+ static logger* get_or_create_instance()
+ {
+ logger* plogger = get_set_instance_internal();
+ if(!plogger)
+ if(!get_set_is_uninitialized())
+ get_set_instance_internal(true, plogger = new logger);
+
+ return plogger;
+ }
+
+ static logger* get_set_instance_internal(bool is_need_set = false, logger* pnew_logger_val = NULL)
+ {
+ static logger* val_plogger = NULL;
+
+ if(is_need_set)
+ val_plogger = pnew_logger_val;
+
+ return val_plogger;
+ }
+
+ static bool get_set_is_uninitialized(bool is_need_set = false, bool is_uninitialized = false)
+ {
+ static bool val_is_uninitialized = false;
+
+ if(is_need_set)
+ val_is_uninitialized = is_uninitialized;
+
+ return val_is_uninitialized;
+ }
+ //static int get_set_error_filter(bool is_need_set = false)
+ };
+
+ const static initializer<log_singletone> log_initializer;
+ /************************************************************************/
+ /* */
+// /************************************************************************/
+// class log_array_value
+// {
+// int num;
+// log_message& m_ref_log_mes;
+//
+// public:
+//
+// log_array_value( log_message& log_mes ) : num(0), m_ref_log_mes(log_mes) {}
+//
+// void operator ( )( ibase_log_value *val ) {
+// m_ref_log_mes << "\n[" << num++ << "] "/* << val*/; }
+//
+//
+// template<class T>
+// void operator ()(T &value )
+// {
+// m_ref_log_mes << "\n[" << num++ << "] " << value;
+// }
+// };
+
+ class log_frame
+ {
+ std::string m_name;
+ int m_level;
+ const char* m_plog_name;
+ public:
+
+ log_frame(const std::string& name, int dlevel = LOG_LEVEL_2 , const char* plog_name = NULL)
+ {
+#ifdef _MSC_VER
+ int lasterr=::GetLastError();
+#endif
+ m_plog_name = plog_name;
+ if ( dlevel <= log_singletone::get_log_detalisation_level() )
+ {
+ m_name = name;
+ std::stringstream ss;
+ ss << log_space::log_singletone::get_prefix_entry() << "-->>" << m_name << std::endl;
+ log_singletone::do_log_message(ss.str(), dlevel, console_color_default, false, m_plog_name);
+ }
+ m_level = dlevel;
+#ifdef _MSC_VER
+ ::SetLastError(lasterr);
+#endif
+ }
+ ~log_frame()
+ {
+#ifdef _MSC_VER
+ int lasterr=::GetLastError();
+#endif
+
+ if (m_level <= log_singletone::get_log_detalisation_level() )
+ {
+ std::stringstream ss;
+ ss << log_space::log_singletone::get_prefix_entry() << "<<--" << m_name << std::endl;
+ log_singletone::do_log_message(ss.str(), m_level, console_color_default, false,m_plog_name);
+ }
+#ifdef _MSC_VER
+ ::SetLastError(lasterr);
+#endif
+ }
+ };
+
+ inline int get_set_time_level(bool is_need_set, int time_log_level)
+ {
+ return log_singletone::get_set_time_level(is_need_set, time_log_level);
+ }
+ inline int get_set_log_detalisation_level(bool is_need_set, int log_level_to_set)
+ {
+ return log_singletone::get_set_log_detalisation_level(is_need_set, log_level_to_set);
+ }
+ inline std::string get_prefix_entry()
+ {
+ return log_singletone::get_prefix_entry();
+ }
+ inline bool get_set_need_thread_id(bool is_need_set, bool is_need_val)
+ {
+ return log_singletone::get_set_need_thread_id(is_need_set, is_need_val);
+ }
+ inline bool get_set_need_proc_name(bool is_need_set, bool is_need_val )
+ {
+ return log_singletone::get_set_need_proc_name(is_need_set, is_need_val);
+ }
+
+ inline std::string get_win32_err_descr(int err_no)
+ {
+#ifdef _MSC_VER
+ LPVOID lpMsgBuf;
+
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err_no,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (char*) &lpMsgBuf,
+ 0, NULL );
+
+ std::string fix_sys_message = "(null)";
+ if(lpMsgBuf) fix_sys_message = (char*)lpMsgBuf;
+ std::string::size_type a;
+ if ( (a = fix_sys_message.rfind( '\n' )) != std::string::npos )
+ fix_sys_message.erase(a);
+ if ( (a = fix_sys_message.rfind( '\r' )) != std::string::npos )
+ fix_sys_message.erase(a);
+
+ LocalFree(lpMsgBuf);
+ return fix_sys_message;
+#else
+ return "Not implemented yet";
+#endif
+ }
+
+ inline bool getwin32_err_text(std::stringstream& ref_message, int error_no)
+ {
+ ref_message << "win32 error:" << get_win32_err_descr(error_no);
+ return true;
+ }
+}
+#if defined(_DEBUG) || defined(__GNUC__)
+ #define ENABLE_LOGGING_INTERNAL
+#endif
+
+#if defined(ENABLE_RELEASE_LOGGING)
+ #define ENABLE_LOGGING_INTERNAL
+#endif
+
+
+#if defined(ENABLE_LOGGING_INTERNAL)
+
+#define LOG_PRINT_NO_PREFIX2(log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);}}
+
+#define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
+
+
+#define LOG_PRINT_NO_POSTFIX2(log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
+
+
+#define LOG_PRINT2(log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
+
+#define LOG_PRINT_COLOR2(log_name, x, y, color) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name);}}
+
+
+#define LOG_PRINT2_JORNAL(log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() )\
+ {std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);}}
+
+
+#define LOG_ERROR2(log_name, x) { \
+ std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << "ERROR " << __FILE__ << ":" << __LINE__ << " " << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), LOG_LEVEL_0, epee::log_space::console_color_red, true, log_name);LOCAL_ASSERT(0); epee::log_space::log_singletone::get_set_err_count(true, epee::log_space::log_singletone::get_set_err_count()+1);}
+
+#define LOG_FRAME2(log_name, x, y) epee::log_space::log_frame frame(x, y, log_name)
+
+#else
+
+
+#define LOG_PRINT_NO_PREFIX2(log_name, x, y)
+
+#define LOG_PRINT_NO_PREFIX_NO_POSTFIX2(log_name, x, y)
+
+#define LOG_PRINT_NO_POSTFIX2(log_name, x, y)
+
+#define LOG_PRINT_COLOR2(log_name, x, y, color)
+
+#define LOG_PRINT2_JORNAL(log_name, x, y)
+
+#define LOG_PRINT2(log_name, x, y)
+
+#define LOG_ERROR2(log_name, x)
+
+
+#define LOG_FRAME2(log_name, x, y)
+
+
+#endif
+
+
+#ifndef LOG_DEFAULT_TARGET
+ #define LOG_DEFAULT_TARGET NULL
+#endif
+
+
+#define LOG_PRINT_NO_POSTFIX(mess, level) LOG_PRINT_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
+#define LOG_PRINT_NO_PREFIX(mess, level) LOG_PRINT_NO_PREFIX2(LOG_DEFAULT_TARGET, mess, level)
+#define LOG_PRINT_NO_PREFIX_NO_POSTFIX(mess, level) LOG_PRINT_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
+#define LOG_PRINT(mess, level) LOG_PRINT2(LOG_DEFAULT_TARGET, mess, level)
+
+#define LOG_PRINT_COLOR(mess, level, color) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, color)
+#define LOG_PRINT_RED(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_red)
+#define LOG_PRINT_GREEN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_green)
+#define LOG_PRINT_BLUE(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_blue)
+
+#define LOG_PRINT_RED_L0(mess) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, LOG_LEVEL_0, epee::log_space::console_color_red)
+
+#define LOG_PRINT_L0(mess) LOG_PRINT(mess, LOG_LEVEL_0)
+#define LOG_PRINT_L1(mess) LOG_PRINT(mess, LOG_LEVEL_1)
+#define LOG_PRINT_L2(mess) LOG_PRINT(mess, LOG_LEVEL_2)
+#define LOG_PRINT_L3(mess) LOG_PRINT(mess, LOG_LEVEL_3)
+#define LOG_PRINT_L4(mess) LOG_PRINT(mess, LOG_LEVEL_4)
+#define LOG_PRINT_J(mess, level) LOG_PRINT2_JORNAL(LOG_DEFAULT_TARGET, mess, level)
+
+#define LOG_ERROR(mess) LOG_ERROR2(LOG_DEFAULT_TARGET, mess)
+#define LOG_FRAME(mess, level) LOG_FRAME2(LOG_DEFAULT_TARGET, mess, level)
+#define LOG_VALUE(mess, level) LOG_VALUE2(LOG_DEFAULT_TARGET, mess, level)
+#define LOG_ARRAY(mess, level) LOG_ARRAY2(LOG_DEFAULT_TARGET, mess, level)
+//#define LOGWIN_PLATFORM_ERROR(err_no) LOGWINDWOS_PLATFORM_ERROR2(LOG_DEFAULT_TARGET, err_no)
+#define LOG_SOCKET_ERROR(err_no) LOG_SOCKET_ERROR2(LOG_DEFAULT_TARGET, err_no)
+//#define LOGWIN_PLATFORM_ERROR_UNCRITICAL(mess) LOGWINDWOS_PLATFORM_ERROR_UNCRITICAL2(LOG_DEFAULT_TARGET, mess)
+
+#define ENDL std::endl
+
+#define TRY_ENTRY() try {
+#define CATCH_ENTRY(location, return_val) } \
+ catch(const std::exception& ex) \
+{ \
+ (void)(ex); \
+ LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
+ return return_val; \
+}\
+ catch(...)\
+{\
+ LOG_ERROR("Exception at [" << location << "], generic exception \"...\"");\
+ return return_val; \
+}
+
+#define CATCH_ENTRY_L0(lacation, return_val) CATCH_ENTRY(lacation, return_val)
+#define CATCH_ENTRY_L1(lacation, return_val) CATCH_ENTRY(lacation, return_val)
+#define CATCH_ENTRY_L2(lacation, return_val) CATCH_ENTRY(lacation, return_val)
+#define CATCH_ENTRY_L3(lacation, return_val) CATCH_ENTRY(lacation, return_val)
+#define CATCH_ENTRY_L4(lacation, return_val) CATCH_ENTRY(lacation, return_val)
+
+
+#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());}
+#define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);}
+
+
+#ifndef CHECK_AND_ASSERT
+#define CHECK_AND_ASSERT(expr, fail_ret_val) do{if(!(expr)){LOCAL_ASSERT(expr); return fail_ret_val;};}while(0)
+#endif
+
+#define NOTHING
+
+#ifndef CHECK_AND_ASSERT_MES
+#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_ERROR(message); return fail_ret_val;};}while(0)
+#endif
+
+#ifndef CHECK_AND_NO_ASSERT_MES
+#define CHECK_AND_NO_ASSERT_MES(expr, fail_ret_val, message) do{if(!(expr)) {LOG_PRINT_L0(message); /*LOCAL_ASSERT(expr);*/ return fail_ret_val;};}while(0)
+#endif
+
+
+#ifndef CHECK_AND_ASSERT_MES_NO_RET
+#define CHECK_AND_ASSERT_MES_NO_RET(expr, message) do{if(!(expr)) {LOG_ERROR(message); return;};}while(0)
+#endif
+
+
+#ifndef CHECK_AND_ASSERT_MES2
+#define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0)
+#endif
+
+}
+#endif //_MISC_LOG_EX_H_
diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h
new file mode 100644
index 000000000..0850c7c07
--- /dev/null
+++ b/contrib/epee/include/misc_os_dependent.h
@@ -0,0 +1,108 @@
+// 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.
+//
+#ifdef WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+
+ //#ifdef _WIN32_WINNT
+ // #undef _WIN32_WINNT
+ // #define _WIN32_WINNT 0x0600
+ //#endif
+
+
+#include <windows.h>
+#endif
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
+#pragma once
+namespace epee
+{
+namespace misc_utils
+{
+
+ inline boost::uint64_t get_tick_count()
+ {
+#if defined(_MSC_VER)
+ return ::GetTickCount64();
+#elif defined(__MACH__)
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+
+ return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
+#else
+ struct timespec ts;
+ if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+ return 0;
+ }
+ return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
+#endif
+ }
+
+
+ inline int call_sys_cmd(const std::string& cmd)
+ {
+ std::cout << "# " << cmd << std::endl;
+
+ FILE * fp ;
+ //char tstCommand[] ="ls *";
+ char path[1000] = {0};
+#if !defined(__GNUC__)
+ fp = _popen(cmd.c_str(), "r");
+#else
+ fp = popen(cmd.c_str(), "r");
+#endif
+ while ( fgets( path, 1000, fp ) != NULL )
+ std::cout << path;
+
+#if !defined(__GNUC__)
+ _pclose(fp);
+#else
+ pclose(fp);
+#endif
+ return 0;
+
+ }
+
+
+ inline std::string get_thread_string_id()
+ {
+#if defined(_MSC_VER)
+ return boost::lexical_cast<std::string>(GetCurrentThreadId());
+#elif defined(__GNUC__)
+ return boost::lexical_cast<std::string>(pthread_self());
+#endif
+ }
+}
+}
diff --git a/contrib/epee/include/net/abstract_tcp_server.h b/contrib/epee/include/net/abstract_tcp_server.h
new file mode 100644
index 000000000..c74444c8e
--- /dev/null
+++ b/contrib/epee/include/net/abstract_tcp_server.h
@@ -0,0 +1,316 @@
+// 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 <process.h>
+#include <list>
+#include <winsock2.h>
+#include "winobj.h"
+//#include "threads_helper.h"
+#include "net_utils_base.h"
+
+#pragma comment(lib, "Ws2_32.lib")
+
+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 THandler>
+ 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<thread_context> 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<class THandler>
+ unsigned __stdcall abstract_tcp_server<THandler>::ConnectionHandlerProc(void* lpParameter)
+ {
+
+ thread_context* pthread_context = (thread_context*)lpParameter;
+ if(!pthread_context)
+ return 0;
+ abstract_tcp_server<THandler>* 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<class THandler>
+ abstract_tcp_server<THandler>::abstract_tcp_server():m_listen_socket(INVALID_SOCKET),
+ m_initialized(false),
+ m_stop_server(0), m_port(0), m_threads_count(0)
+ {
+
+ }
+
+ //----------------------------------------------------------------------------------------
+ template<class THandler>
+ bool abstract_tcp_server<THandler>::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<char*>(&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<class THandler>
+ bool abstract_tcp_server<THandler>::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<class THandler>
+ bool abstract_tcp_server<THandler>::send_stop_signal()
+ {
+ InterlockedExchange(&m_stop_server, 1);
+ return true;
+ }
+ //----------------------------------------------------------------------------------------
+ template<class THandler>
+ bool abstract_tcp_server<THandler>::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<class THandler>
+ bool abstract_tcp_server<THandler>::invoke_connection(SOCKET hnew_sock, long ip_from, int post_from)
+ {
+ 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_ip = ip_from;
+ m_connections.back().m_context.m_remote_port = post_from;
+ 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
new file mode 100644
index 000000000..d49b8f864
--- /dev/null
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -0,0 +1,276 @@
+// 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_SERVER2_H_
+#define _ABSTRACT_TCP_SERVER2_H_
+
+
+#include <boost/asio.hpp>
+#include <string>
+#include <vector>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <atomic>
+
+#include <boost/asio.hpp>
+#include <boost/array.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/thread/thread.hpp>
+#include "net_utils_base.h"
+#include "syncobj.h"
+
+
+#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 100
+
+namespace epee
+{
+namespace net_utils
+{
+
+ struct i_connection_filter
+ {
+ virtual bool is_remote_ip_allowed(boost::uint32_t adress)=0;
+ protected:
+ virtual ~i_connection_filter(){}
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ /// Represents a single connection from a client.
+ template<class t_protocol_handler>
+ class connection
+ : public boost::enable_shared_from_this<connection<t_protocol_handler> >,
+ private boost::noncopyable,
+ public i_service_endpoint
+ {
+ public:
+ typedef typename t_protocol_handler::connection_context t_connection_context;
+ /// Construct a connection with the given io_service.
+ explicit connection(boost::asio::io_service& io_service,
+ typename t_protocol_handler::config_type& config, volatile boost::uint32_t& sock_count, i_connection_filter * &pfilter);
+
+ virtual ~connection();
+ /// Get the socket associated with the connection.
+ boost::asio::ip::tcp::socket& socket();
+
+ /// Start the first asynchronous operation for the connection.
+ bool start(bool is_income, bool is_multithreaded);
+
+ void get_context(t_connection_context& context_){context_ = context;}
+
+ void call_back_starter();
+ private:
+ //----------------- i_service_endpoint ---------------------
+ virtual bool do_send(const void* ptr, size_t cb);
+ virtual bool close();
+ virtual bool call_run_once_service_io();
+ virtual bool request_callback();
+ virtual boost::asio::io_service& get_io_service();
+ virtual bool add_ref();
+ virtual bool release();
+ //------------------------------------------------------
+ boost::shared_ptr<connection<t_protocol_handler> > safe_shared_from_this();
+ bool shutdown();
+ /// Handle completion of a read operation.
+ void handle_read(const boost::system::error_code& e,
+ std::size_t bytes_transferred);
+
+ /// Handle completion of a write operation.
+ void handle_write(const boost::system::error_code& e, size_t cb);
+
+ /// Strand to ensure the connection's handlers are not called concurrently.
+ boost::asio::io_service::strand strand_;
+
+ /// Socket for the connection.
+ boost::asio::ip::tcp::socket socket_;
+
+ /// Buffer for incoming data.
+ boost::array<char, 8192> buffer_;
+
+ t_connection_context context;
+ volatile boost::uint32_t m_want_close_connection;
+ std::atomic<bool> m_was_shutdown;
+ critical_section m_send_que_lock;
+ std::list<std::string> m_send_que;
+ volatile boost::uint32_t& m_ref_sockets_count;
+ i_connection_filter* &m_pfilter;
+ volatile bool m_is_multithreaded;
+
+ //this should be the last one, because it could be wait on destructor, while other activities possible on other threads
+ t_protocol_handler m_protocol_handler;
+ //typename t_protocol_handler::config_type m_dummy_config;
+ std::list<boost::shared_ptr<connection<t_protocol_handler> > > m_self_refs; // add_ref/release support
+ critical_section m_self_refs_lock;
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_protocol_handler>
+ class boosted_tcp_server
+ : private boost::noncopyable
+ {
+ public:
+ typedef boost::shared_ptr<connection<t_protocol_handler> > connection_ptr;
+ typedef typename t_protocol_handler::connection_context t_connection_context;
+ /// Construct the server to listen on the specified TCP address and port, and
+ /// serve up files from the given directory.
+ boosted_tcp_server();
+ explicit boosted_tcp_server(boost::asio::io_service& external_io_service);
+ ~boosted_tcp_server();
+
+ bool init_server(uint32_t port, const std::string address = "0.0.0.0");
+ bool init_server(const std::string port, const std::string& address = "0.0.0.0");
+
+ /// Run the server's io_service loop.
+ bool run_server(size_t threads_count, bool wait = true);
+
+ /// wait for service workers stop
+ bool timed_wait_server_stop(boost::uint64_t wait_mseconds);
+
+ /// Stop the server.
+ void send_stop_signal();
+
+ bool is_stop_signal_sent();
+
+ void set_threads_prefix(const std::string& prefix_name);
+
+ bool deinit_server(){return true;}
+
+ size_t get_threads_count(){return m_threads_count;}
+
+ void set_connection_filter(i_connection_filter* pfilter);
+
+ bool connect(const std::string& adr, const std::string& port, boost::uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0");
+ template<class t_callback>
+ bool connect_async(const std::string& adr, const std::string& port, boost::uint32_t conn_timeot, t_callback cb, const std::string& bind_ip = "0.0.0.0");
+
+ typename t_protocol_handler::config_type& get_config_object(){return m_config;}
+
+ int get_binded_port(){return m_port;}
+
+ boost::asio::io_service& get_io_service(){return io_service_;}
+
+ struct idle_callback_conext_base
+ {
+ virtual ~idle_callback_conext_base(){}
+
+ virtual bool call_handler(){return true;}
+
+ idle_callback_conext_base(boost::asio::io_service& io_serice):
+ m_timer(io_serice)
+ {}
+ boost::asio::deadline_timer m_timer;
+ boost::uint64_t m_period;
+ };
+
+ template <class t_handler>
+ struct idle_callback_conext: public idle_callback_conext_base
+ {
+ idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, boost::uint64_t period):
+ idle_callback_conext_base(io_serice),
+ m_handler(h)
+ {this->m_period = period;}
+
+ t_handler m_handler;
+ virtual bool call_handler()
+ {
+ return m_handler();
+ }
+ };
+
+ template<class t_handler>
+ bool add_idle_handler(t_handler t_callback, boost::uint64_t timeout_ms)
+ {
+ boost::shared_ptr<idle_callback_conext_base> ptr(new idle_callback_conext<t_handler>(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<t_protocol_handler>::global_timer_handler, this, ptr));
+ return true;
+ }
+
+ bool global_timer_handler(/*const boost::system::error_code& err, */boost::shared_ptr<idle_callback_conext_base> ptr)
+ {
+ //if handler return false - he don't want to be called anymore
+ if(!ptr->call_handler())
+ return true;
+ ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period));
+ ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server<t_protocol_handler>::global_timer_handler, this, ptr));
+ return true;
+ }
+
+ template<class t_handler>
+ bool async_call(t_handler t_callback)
+ {
+ io_service_.post(t_callback);
+ return true;
+ }
+
+ protected:
+ typename t_protocol_handler::config_type m_config;
+
+ private:
+ /// Run the server's io_service loop.
+ bool worker_thread();
+ /// Handle completion of an asynchronous accept operation.
+ void handle_accept(const boost::system::error_code& e);
+
+ bool is_thread_worker();
+
+ /// The io_service used to perform asynchronous operations.
+ std::unique_ptr<boost::asio::io_service> m_io_service_local_instance;
+ boost::asio::io_service& io_service_;
+
+ /// Acceptor used to listen for incoming connections.
+ boost::asio::ip::tcp::acceptor acceptor_;
+
+ /// The next connection to be accepted.
+ connection_ptr new_connection_;
+ std::atomic<bool> m_stop_signal_sent;
+ uint32_t m_port;
+ volatile boost::uint32_t m_sockets_count;
+ std::string m_address;
+ std::string m_thread_name_prefix;
+ size_t m_threads_count;
+ i_connection_filter* m_pfilter;
+ std::vector<boost::shared_ptr<boost::thread> > m_threads;
+ boost::thread::id m_main_thread_id;
+ critical_section m_threads_lock;
+ volatile uint32_t m_thread_index;
+ };
+}
+}
+
+#include "abstract_tcp_server2.inl"
+
+#endif \ No newline at end of file
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
new file mode 100644
index 000000000..1d6a1662f
--- /dev/null
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -0,0 +1,811 @@
+// 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.
+//
+
+
+
+#include "net_utils_base.h"
+#include <boost/lambda/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/uuid/random_generator.hpp>
+#include <boost/chrono.hpp>
+#include <boost/utility/value_init.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include "misc_language.h"
+#include "pragma_comp_defs.h"
+
+PRAGMA_WARNING_PUSH
+namespace epee
+{
+namespace net_utils
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+PRAGMA_WARNING_DISABLE_VS(4355)
+
+ template<class t_protocol_handler>
+ connection<t_protocol_handler>::connection(boost::asio::io_service& io_service,
+ typename t_protocol_handler::config_type& config, volatile boost::uint32_t& sock_count, i_connection_filter* &pfilter)
+ : strand_(io_service),
+ socket_(io_service),
+ //context(typename boost::value_initialized<t_connection_context>())
+ m_protocol_handler(this, config, context),
+ m_want_close_connection(0),
+ m_was_shutdown(0),
+ m_ref_sockets_count(sock_count),
+ m_pfilter(pfilter)
+ {
+ boost::interprocess::ipcdetail::atomic_inc32(&m_ref_sockets_count);
+ }
+PRAGMA_WARNING_DISABLE_VS(4355)
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ connection<t_protocol_handler>::~connection()
+ {
+ if(!m_was_shutdown)
+ {
+ LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown.");
+ shutdown();
+ }
+
+ LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Socket destroyed");
+ boost::interprocess::ipcdetail::atomic_dec32(&m_ref_sockets_count);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ boost::asio::ip::tcp::socket& connection<t_protocol_handler>::socket()
+ {
+ return socket_;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ boost::shared_ptr<connection<t_protocol_handler> > connection<t_protocol_handler>::safe_shared_from_this()
+ {
+ try
+ {
+ return connection<t_protocol_handler>::shared_from_this();
+ }
+ catch (const boost::bad_weak_ptr&)
+ {
+ // It happens when the connection is being deleted
+ return boost::shared_ptr<connection<t_protocol_handler> >();
+ }
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::start(bool is_income, bool is_multithreaded)
+ {
+ TRY_ENTRY();
+
+ // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted
+ auto self = safe_shared_from_this();
+ if(!self)
+ return false;
+
+ m_is_multithreaded = is_multithreaded;
+
+ boost::system::error_code ec;
+ auto remote_ep = socket_.remote_endpoint(ec);
+ CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value());
+
+ auto local_ep = socket_.local_endpoint(ec);
+ CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
+
+ context = boost::value_initialized<t_connection_context>();
+ long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong());
+
+ context.set_details(boost::uuids::random_generator()(), ip_, remote_ep.port(), is_income);
+ LOG_PRINT_L3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
+ " to " << local_ep.address().to_string() << ':' << local_ep.port() <<
+ ", total sockets objects " << m_ref_sockets_count);
+
+ if(m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip))
+ {
+ LOG_PRINT_L2("[sock " << socket_.native_handle() << "] ip denied " << string_tools::get_ip_string_from_int32(context.m_remote_ip) << ", shutdowning connection");
+ close();
+ return false;
+ }
+
+ m_protocol_handler.after_init_connection();
+
+ socket_.async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_read, self,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+
+ return true;
+
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::start()", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::request_callback()
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L2("[" << print_connection_context_short(context) << "] request_callback");
+ // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted
+ auto self = safe_shared_from_this();
+ if(!self)
+ return false;
+
+ strand_.post(boost::bind(&connection<t_protocol_handler>::call_back_starter, self));
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::request_callback()", false);
+ return true;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ boost::asio::io_service& connection<t_protocol_handler>::get_io_service()
+ {
+ return socket_.get_io_service();
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::add_ref()
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] add_ref");
+ CRITICAL_REGION_LOCAL(m_self_refs_lock);
+
+ // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted
+ auto self = safe_shared_from_this();
+ if(!self)
+ return false;
+ if(m_was_shutdown)
+ return false;
+ m_self_refs.push_back(self);
+ return true;
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::add_ref()", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::release()
+ {
+ TRY_ENTRY();
+ boost::shared_ptr<connection<t_protocol_handler> > back_connection_copy;
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] release");
+ CRITICAL_REGION_BEGIN(m_self_refs_lock);
+ CHECK_AND_ASSERT_MES(m_self_refs.size(), false, "[sock " << socket_.native_handle() << "] m_self_refs empty at connection<t_protocol_handler>::release() call");
+ //erasing from container without additional copy can cause start deleting object, including m_self_refs
+ back_connection_copy = m_self_refs.back();
+ m_self_refs.pop_back();
+ CRITICAL_REGION_END();
+ return true;
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::release()", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void connection<t_protocol_handler>::call_back_starter()
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L2("[" << print_connection_context_short(context) << "] fired_callback");
+ m_protocol_handler.handle_qued_callback();
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::call_back_starter()", void());
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void connection<t_protocol_handler>::handle_read(const boost::system::error_code& e,
+ std::size_t bytes_transferred)
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Async read calledback.");
+
+ if (!e)
+ {
+ LOG_PRINT("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred, LOG_LEVEL_4);
+ bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred);
+ if(!recv_res)
+ {
+ LOG_PRINT("[sock " << socket_.native_handle() << "] protocol_want_close", LOG_LEVEL_4);
+
+ //some error in protocol, protocol handler ask to close connection
+ boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
+ bool do_shutdown = false;
+ CRITICAL_REGION_BEGIN(m_send_que_lock);
+ if(!m_send_que.size())
+ do_shutdown = true;
+ CRITICAL_REGION_END();
+ if(do_shutdown)
+ shutdown();
+ }else
+ {
+ socket_.async_read_some(boost::asio::buffer(buffer_),
+ strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "]Async read requested.");
+ }
+ }else
+ {
+ LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Some not success at read: " << e.message() << ':' << e.value());
+ if(e.value() != 2)
+ {
+ LOG_PRINT_L3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value());
+ shutdown();
+ }
+ }
+ // If an error occurs then no new asynchronous operations are started. This
+ // means that all shared_ptr references to the connection object will
+ // disappear and the object will be destroyed automatically after this
+ // handler returns. The connection class's destructor closes the socket.
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::handle_read", void());
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::call_run_once_service_io()
+ {
+ TRY_ENTRY();
+ if(!m_is_multithreaded)
+ {
+ //single thread model, we can wait in blocked call
+ size_t cnt = socket_.get_io_service().run_one();
+ if(!cnt)//service is going to quit
+ return false;
+ }else
+ {
+ //multi thread model, we can't(!) wait in blocked call
+ //so we make non blocking call and releasing CPU by calling sleep(0);
+ //if no handlers were called
+ //TODO: Maybe we need to have have critical section + event + callback to upper protocol to
+ //ask it inside(!) critical region if we still able to go in event wait...
+ size_t cnt = socket_.get_io_service().poll_one();
+ if(!cnt)
+ misc_utils::sleep_no_w(0);
+ }
+
+ return true;
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::call_run_once_service_io", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::do_send(const void* ptr, size_t cb)
+ {
+ TRY_ENTRY();
+ // Use safe_shared_from_this, because of this is public method and it can be called on the object being deleted
+ auto self = safe_shared_from_this();
+ if(!self)
+ return false;
+ if(m_was_shutdown)
+ return false;
+
+ LOG_PRINT("[sock " << socket_.native_handle() << "] SEND " << cb, LOG_LEVEL_4);
+ //some data should be wrote to stream
+ //request complete
+
+ epee::critical_region_t<decltype(m_send_que_lock)> send_guard(m_send_que_lock);
+ if(m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
+ {
+ send_guard.unlock();
+ LOG_ERROR("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
+ close();
+ return false;
+ }
+
+ m_send_que.resize(m_send_que.size()+1);
+ m_send_que.back().assign((const char*)ptr, cb);
+
+ if(m_send_que.size() > 1)
+ {
+ //active operation should be in progress, nothing to do, just wait last operation callback
+ }else
+ {
+ //no active operation
+ if(m_send_que.size()!=1)
+ {
+ LOG_ERROR("Looks like no active operations, but send que size != 1!!");
+ return false;
+ }
+
+ boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), m_send_que.front().size()),
+ //strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
+ //)
+ );
+
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size());
+ }
+
+ return true;
+
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::do_send", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::shutdown()
+ {
+ // 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;
+ m_protocol_handler.release_protocol();
+ return true;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool connection<t_protocol_handler>::close()
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Que Shutdown called.");
+ size_t send_que_size = 0;
+ CRITICAL_REGION_BEGIN(m_send_que_lock);
+ send_que_size = m_send_que.size();
+ CRITICAL_REGION_END();
+ boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
+ if(!send_que_size)
+ {
+ shutdown();
+ }
+
+ return true;
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::close", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb)
+ {
+ TRY_ENTRY();
+ LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Async send calledback " << cb);
+
+ if (e)
+ {
+ LOG_PRINT_L0("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value());
+ shutdown();
+ return;
+ }
+
+ bool do_shutdown = false;
+ CRITICAL_REGION_BEGIN(m_send_que_lock);
+ if(m_send_que.empty())
+ {
+ LOG_ERROR("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!");
+ return;
+ }
+
+ m_send_que.pop_front();
+ if(m_send_que.empty())
+ {
+ if(boost::interprocess::ipcdetail::atomic_read32(&m_want_close_connection))
+ {
+ do_shutdown = true;
+ }
+ }else
+ {
+ //have more data to send
+ boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), m_send_que.front().size()),
+ //strand_.wrap(
+ boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2));
+ //);
+ }
+ CRITICAL_REGION_END();
+
+ if(do_shutdown)
+ {
+ shutdown();
+ }
+ CATCH_ENTRY_L0("connection<t_protocol_handler>::handle_write", void());
+ }
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_protocol_handler>
+ boosted_tcp_server<t_protocol_handler>::boosted_tcp_server():
+ m_io_service_local_instance(new boost::asio::io_service()),
+ io_service_(*m_io_service_local_instance.get()),
+ acceptor_(io_service_),
+ new_connection_(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter)),
+ m_stop_signal_sent(false), m_port(0), m_sockets_count(0), m_threads_count(0), m_pfilter(NULL), m_thread_index(0)
+ {
+ m_thread_name_prefix = "NET";
+ }
+
+ template<class t_protocol_handler>
+ boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_service& extarnal_io_service):
+ io_service_(extarnal_io_service),
+ acceptor_(io_service_),
+ new_connection_(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter)),
+ m_stop_signal_sent(false), m_port(0), m_sockets_count(0), m_threads_count(0), m_pfilter(NULL), m_thread_index(0)
+ {
+ m_thread_name_prefix = "NET";
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ boosted_tcp_server<t_protocol_handler>::~boosted_tcp_server()
+ {
+ this->send_stop_signal();
+ timed_wait_server_stop(10000);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address)
+ {
+ TRY_ENTRY();
+ m_stop_signal_sent = false;
+ m_port = port;
+ m_address = address;
+ // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
+ boost::asio::ip::tcp::resolver resolver(io_service_);
+ boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port));
+ boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
+ acceptor_.open(endpoint.protocol());
+ acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor_.bind(endpoint);
+ acceptor_.listen();
+ boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
+ m_port = binded_endpoint.port();
+ acceptor_.async_accept(new_connection_->socket(),
+ boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
+ boost::asio::placeholders::error));
+
+ return true;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::init_server", false);
+ }
+ //-----------------------------------------------------------------------------
+PUSH_WARNINGS
+DISABLE_GCC_WARNING(maybe-uninitialized)
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address)
+ {
+ uint32_t p = 0;
+
+ if (port.size() && !string_tools::get_xtype_from_string(p, port)) {
+ return false;
+ LOG_ERROR("Failed to convert port no = port");
+ }
+ return this->init_server(p, address);
+ }
+POP_WARNINGS
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::worker_thread()
+ {
+ TRY_ENTRY();
+ uint32_t local_thr_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
+ std::string thread_name = std::string("[") + m_thread_name_prefix;
+ thread_name += boost::to_string(local_thr_index) + "]";
+ log_space::log_singletone::set_thread_log_prefix(thread_name);
+ while(!m_stop_signal_sent)
+ {
+ try
+ {
+ io_service_.run();
+ }
+ catch(const std::exception& ex)
+ {
+ LOG_ERROR("Exception at server worker thread, what=" << ex.what());
+ }
+ catch(...)
+ {
+ LOG_ERROR("Exception at server worker thread, unknown execption");
+ }
+ }
+ LOG_PRINT_L4("Worker thread finished");
+ return true;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::worker_thread", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::set_threads_prefix(const std::string& prefix_name)
+ {
+ m_thread_name_prefix = prefix_name;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::set_connection_filter(i_connection_filter* pfilter)
+ {
+ m_pfilter = pfilter;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait)
+ {
+ TRY_ENTRY();
+ m_threads_count = threads_count;
+ m_main_thread_id = boost::this_thread::get_id();
+ log_space::log_singletone::set_thread_log_prefix("[SRV_MAIN]");
+ while(!m_stop_signal_sent)
+ {
+
+ // Create a pool of threads to run all of the io_services.
+ CRITICAL_REGION_BEGIN(m_threads_lock);
+ for (std::size_t i = 0; i < threads_count; ++i)
+ {
+ boost::shared_ptr<boost::thread> thread(new boost::thread(
+ boost::bind(&boosted_tcp_server<t_protocol_handler>::worker_thread, this)));
+ m_threads.push_back(thread);
+ }
+ CRITICAL_REGION_END();
+ // Wait for all threads in the pool to exit.
+ if(wait)
+ {
+ for (std::size_t i = 0; i < m_threads.size(); ++i)
+ m_threads[i]->join();
+ m_threads.clear();
+
+ }else
+ {
+ return true;
+ }
+
+ if(wait && !m_stop_signal_sent)
+ {
+ //some problems with the listening socket ?..
+ LOG_PRINT_L0("Net service stopped without stop request, restarting...");
+ if(!this->init_server(m_port, m_address))
+ {
+ LOG_PRINT_L0("Reiniting service failed, exit.");
+ return false;
+ }else
+ {
+ LOG_PRINT_L0("Reiniting OK.");
+ }
+ }
+ }
+ return true;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::run_server", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::is_thread_worker()
+ {
+ TRY_ENTRY();
+ CRITICAL_REGION_LOCAL(m_threads_lock);
+ BOOST_FOREACH(boost::shared_ptr<boost::thread>& thp, m_threads)
+ {
+ if(thp->get_id() == boost::this_thread::get_id())
+ return true;
+ }
+ if(m_threads_count == 1 && boost::this_thread::get_id() == m_main_thread_id)
+ return true;
+ return false;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::is_thread_worker", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop(boost::uint64_t wait_mseconds)
+ {
+ TRY_ENTRY();
+ boost::chrono::milliseconds ms(wait_mseconds);
+ for (std::size_t i = 0; i < m_threads.size(); ++i)
+ {
+ if(m_threads[i]->joinable() && !m_threads[i]->try_join_for(ms))
+ {
+ LOG_PRINT_L0("Interrupting thread " << m_threads[i]->native_handle());
+ m_threads[i]->interrupt();
+ }
+ }
+ return true;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::send_stop_signal()
+ {
+ m_stop_signal_sent = true;
+ TRY_ENTRY();
+ io_service_.stop();
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::is_stop_signal_sent()
+ {
+ return m_stop_signal_sent;
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ void boosted_tcp_server<t_protocol_handler>::handle_accept(const boost::system::error_code& e)
+ {
+ TRY_ENTRY();
+ if (!e)
+ {
+ connection_ptr conn(std::move(new_connection_));
+
+ new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter));
+ acceptor_.async_accept(new_connection_->socket(),
+ boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this,
+ boost::asio::placeholders::error));
+
+ bool r = conn->start(true, 1 < m_threads_count);
+ if (!r)
+ LOG_ERROR("[sock " << conn->socket().native_handle() << "] Failed to start connection, connections_count = " << m_sockets_count);
+ }else
+ {
+ LOG_ERROR("Some problems at accept: " << e.message() << ", connections_count = " << m_sockets_count);
+ }
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::handle_accept", void());
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler>
+ bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, boost::uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip)
+ {
+ TRY_ENTRY();
+
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter) );
+ boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
+
+ //////////////////////////////////////////////////////////////////////////
+ boost::asio::ip::tcp::resolver resolver(io_service_);
+ boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port);
+ boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+ if(iterator == end)
+ {
+ LOG_ERROR("Failed to resolve " << adr);
+ return false;
+ }
+ //////////////////////////////////////////////////////////////////////////
+
+
+ //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
+ boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
+
+ sock_.open(remote_endpoint.protocol());
+ if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
+ {
+ boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0);
+ sock_.bind(local_endpoint);
+ }
+
+ /*
+ NOTICE: be careful to make sync connection from event handler: in case if all threads suddenly do sync connect, there will be no thread to dispatch events from io service.
+ */
+
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ //have another free thread(s), work in wait mode, without event handling
+ struct local_async_context
+ {
+ boost::system::error_code ec;
+ boost::mutex connect_mut;
+ boost::condition_variable cond;
+ };
+
+ boost::shared_ptr<local_async_context> local_shared_context(new local_async_context());
+ local_shared_context->ec = boost::asio::error::would_block;
+ boost::unique_lock<boost::mutex> lock(local_shared_context->connect_mut);
+ auto connect_callback = [](boost::system::error_code ec_, boost::shared_ptr<local_async_context> shared_context)
+ {
+ shared_context->connect_mut.lock(); shared_context->ec = ec_; shared_context->connect_mut.unlock(); shared_context->cond.notify_one();
+ };
+
+ sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, _1, local_shared_context));
+ while(local_shared_context->ec == boost::asio::error::would_block)
+ {
+ bool r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));
+ if(local_shared_context->ec == boost::asio::error::would_block && !r)
+ {
+ //timeout
+ sock_.close();
+ LOG_PRINT_L3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")");
+ return false;
+ }
+ }
+ ec = local_shared_context->ec;
+
+ if (ec || !sock_.is_open())
+ {
+ LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3);
+ return false;
+ }
+
+ LOG_PRINT_L3("Connected success to " << adr << ':' << port);
+
+ bool r = new_connection_l->start(false, 1 < m_threads_count);
+ if (r)
+ {
+ new_connection_l->get_context(conn_context);
+ //new_connection_l.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter));
+ }
+ else
+ {
+ LOG_ERROR("[sock " << new_connection_->socket().native_handle() << "] Failed to start connection, connections_count = " << m_sockets_count);
+ }
+
+ return r;
+
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::connect", false);
+ }
+ //---------------------------------------------------------------------------------
+ template<class t_protocol_handler> template<class t_callback>
+ bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, boost::uint32_t conn_timeout, t_callback cb, const std::string& bind_ip)
+ {
+ TRY_ENTRY();
+ connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_config, m_sockets_count, m_pfilter) );
+ boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
+
+ //////////////////////////////////////////////////////////////////////////
+ boost::asio::ip::tcp::resolver resolver(io_service_);
+ boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port);
+ boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+ if(iterator == end)
+ {
+ LOG_ERROR("Failed to resolve " << adr);
+ return false;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
+
+ sock_.open(remote_endpoint.protocol());
+ if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
+ {
+ boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0);
+ sock_.bind(local_endpoint);
+ }
+
+ boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_service_));
+ //start deadline
+ sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
+ sh_deadline->async_wait([=](const boost::system::error_code& error)
+ {
+ if(error != boost::asio::error::operation_aborted)
+ {
+ LOG_PRINT_L3("Failed to connect to " << adr << ':' << port << ", because of timeout (" << conn_timeout << ")");
+ new_connection_l->socket().close();
+ }
+ });
+ //start async connect
+ sock_.async_connect(remote_endpoint, [=](const boost::system::error_code& ec_)
+ {
+ t_connection_context conn_context = AUTO_VAL_INIT(conn_context);
+ boost::system::error_code ignored_ec;
+ boost::asio::ip::tcp::socket::endpoint_type lep = new_connection_l->socket().local_endpoint(ignored_ec);
+ if(!ec_)
+ {//success
+ if(!sh_deadline->cancel())
+ {
+ cb(conn_context, boost::asio::error::operation_aborted);//this mean that deadline timer already queued callback with cancel operation, rare situation
+ }else
+ {
+ LOG_PRINT_L3("[sock " << new_connection_l->socket().native_handle() << "] Connected success to " << adr << ':' << port <<
+ " from " << lep.address().to_string() << ':' << lep.port());
+ bool r = new_connection_l->start(false, 1 < m_threads_count);
+ if (r)
+ {
+ new_connection_l->get_context(conn_context);
+ cb(conn_context, ec_);
+ }
+ else
+ {
+ LOG_PRINT_L3("[sock " << new_connection_l->socket().native_handle() << "] Failed to start connection to " << adr << ':' << port);
+ cb(conn_context, boost::asio::error::fault);
+ }
+ }
+ }else
+ {
+ LOG_PRINT_L3("[sock " << new_connection_l->socket().native_handle() << "] Failed to connect to " << adr << ':' << port <<
+ " from " << lep.address().to_string() << ':' << lep.port() << ": " << ec_.message() << ':' << ec_.value());
+ cb(conn_context, ec_);
+ }
+ });
+ return true;
+ CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::connect_async", false);
+ }
+}
+}
+PRAGMA_WARNING_POP
diff --git a/contrib/epee/include/net/abstract_tcp_server_cp.h b/contrib/epee/include/net/abstract_tcp_server_cp.h
new file mode 100644
index 000000000..b6410e120
--- /dev/null
+++ b/contrib/epee/include/net/abstract_tcp_server_cp.h
@@ -0,0 +1,233 @@
+// 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 <winsock2.h>
+#include <rpc.h>
+#include <string>
+#include <map>
+#include <boost/shared_ptr.hpp>
+
+#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"
+
+#define LEVIN_DEFAULT_DATA_BUFF_SIZE 2000
+
+namespace epee
+{
+namespace net_utils
+{
+
+ template<class TProtocol>
+ 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<class TProtocol>
+ 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<TProtocol>& operator=(const connection<TProtocol>& 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<TProtocol>(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<TProtocol>* pconn);
+
+
+ typedef std::map<SOCKET, boost::shared_ptr<connection<TProtocol> > > 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
new file mode 100644
index 000000000..5673c50be
--- /dev/null
+++ b/contrib/epee/include/net/abstract_tcp_server_cp.inl
@@ -0,0 +1,605 @@
+// 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")
+
+namespace epee
+{
+namespace net_utils
+{
+template<class TProtocol>
+cp_server_impl<TProtocol>::cp_server_impl():
+ m_port(0), m_stop(false),
+ m_worker_thread_counter(0), m_listen_socket(INVALID_SOCKET)
+{
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+cp_server_impl<TProtocol>::~cp_server_impl()
+{
+ deinit_server();
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+bool cp_server_impl<TProtocol>::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<char*>(&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<class TProtocol>
+size_t cp_server_impl<TProtocol>::get_active_connections_num()
+{
+ return m_connections.size();
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+unsigned CALLBACK cp_server_impl<TProtocol>::worker_thread(void* param)
+{
+ if(!param)
+ return 0;
+
+ cp_server_impl<TProtocol>* pthis = (cp_server_impl<TProtocol>*)param;
+ pthis->worker_thread_member();
+ return 1;
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+bool cp_server_impl<TProtocol>::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<TProtocol>* 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<class TProtocol>
+bool cp_server_impl<TProtocol>::shutdown_connection(connection<TProtocol>* 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<class TProtocol>
+bool cp_server_impl<TProtocol>::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<m_worker_thread_counter; i++)
+ {
+ ::PostQueuedCompletionStatus(m_completion_port, 0, 0, 0);
+ }
+
+ wait_count = 0;
+ while(InterlockedCompareExchange(&m_worker_thread_counter, 0, 0) && wait_count < 100)
+ {
+ Sleep(100);
+ wait_count++;
+ }
+
+ LOG_PRINT("Net Server STOPPED, wait_count = " << wait_count, LOG_LEVEL_1);
+ return true;
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+bool cp_server_impl<TProtocol>::add_new_connection(SOCKET new_sock, long ip_from, int port_from)
+{
+ PROFILE_FUNC("[add_new_connection]");
+
+ LOG_PRINT("Add new connection zone: entering lock", LOG_LEVEL_3);
+ m_connections_lock.lock();
+
+ boost::shared_ptr<connection<TProtocol> > ptr;
+ ptr.reset(new connection<TProtocol>(m_config));
+
+ connection<TProtocol>& 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_ip = ip_from;
+ conn.context.m_remote_port = port_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<class TProtocol>
+bool cp_server_impl<TProtocol>::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<class TProtocol>
+bool cp_server_impl<TProtocol>::send_stop_signal()
+{
+ ::InterlockedExchange(&m_stop, 1);
+ return true;
+}
+//-------------------------------------------------------------
+template<class TProtocol>
+bool cp_server_impl<TProtocol>::is_stop_signal()
+{
+ return m_stop?true:false;
+}
+//-------------------------------------------------------------
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h
new file mode 100644
index 000000000..6de537a4c
--- /dev/null
+++ b/contrib/epee/include/net/http_base.h
@@ -0,0 +1,184 @@
+// 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 <boost/lexical_cast.hpp>
+#include <boost/regex.hpp>
+
+#include "string_tools.h"
+namespace epee
+{
+namespace net_utils
+{
+ namespace http
+ {
+
+ enum http_method{
+ http_method_get,
+ http_method_post,
+ http_method_put,
+ http_method_head,
+ http_method_etc,
+ http_method_unknown
+ };
+
+ enum http_content_type
+ {
+ http_content_type_text_html,
+ http_content_type_image_gif,
+ http_content_type_other,
+ http_content_type_not_set
+ };
+
+ typedef std::list<std::pair<std::string, std::string> > fields_list;
+
+ inline
+ std::string get_value_from_fields_list(const std::string& param_name, const net_utils::http::fields_list& fields)
+ {
+ fields_list::const_iterator it = fields.begin();
+ for(; it != fields.end(); it++)
+ if(!string_tools::compare_no_case(param_name, it->first))
+ break;
+
+ if(it==fields.end())
+ return std::string();
+
+ return it->second;
+ }
+
+
+ inline
+ std::string get_value_from_uri_line(const std::string& param_name, const std::string& uri)
+ {
+ std::string buff = "([\\?|&])";
+ buff += param_name + "=([^&]*)";
+ boost::regex match_param(buff.c_str(), boost::regex::icase | boost::regex::normal);
+ boost::smatch result;
+ if(boost::regex_search(uri, result, match_param, boost::match_default) && result[0].matched)
+ {
+ return result[2];
+ }
+ return std::string();
+ }
+
+
+
+ struct http_header_info
+ {
+ std::string m_connection; //"Connection:"
+ std::string m_referer; //"Referer:"
+ std::string m_content_length; //"Content-Length:"
+ std::string m_content_type; //"Content-Type:"
+ std::string m_transfer_encoding;//"Transfer-Encoding:"
+ std::string m_content_encoding; //"Content-Encoding:"
+ std::string m_host; //"Host:"
+ std::string m_cookie; //"Cookie:"
+ fields_list m_etc_fields;
+
+ void clear()
+ {
+ m_connection.clear();
+ m_referer.clear();
+ m_content_length.clear();
+ m_content_type.clear();
+ m_transfer_encoding.clear();
+ m_content_encoding.clear();
+ m_host.clear();
+ m_cookie.clear();
+ m_etc_fields.clear();
+ }
+ };
+
+ struct uri_content
+ {
+ std::string m_path;
+ std::string m_query;
+ std::string m_fragment;
+ std::list<std::pair<std::string, std::string> > m_query_params;
+ };
+
+ struct url_content
+ {
+ std::string schema;
+ std::string host;
+ std::string uri;
+ boost::uint64_t port;
+ uri_content m_uri_content;
+ };
+
+
+ struct http_request_info
+ {
+ http_request_info():m_http_method(http_method_unknown),
+ m_http_ver_hi(0),
+ m_http_ver_lo(0),
+ m_have_to_block(false)
+ {}
+
+ http_method m_http_method;
+ std::string m_URI;
+ std::string m_http_method_str;
+ std::string m_full_request_str;
+ std::string m_replace_html;
+ std::string m_request_head;
+ int m_http_ver_hi;
+ int m_http_ver_lo;
+ bool m_have_to_block;
+ http_header_info m_header_info;
+ uri_content m_uri_content;
+ size_t m_full_request_buf_size;
+ std::string m_body;
+
+ void clear()
+ {
+ this->~http_request_info();
+ new(this) http_request_info();
+ }
+ };
+
+
+ struct http_response_info
+ {
+ int m_response_code;
+ std::string m_response_comment;
+ fields_list m_additional_fields;
+ std::string m_body;
+ std::string m_mime_tipe;
+ http_header_info m_header_info;
+ int m_http_ver_hi;// OUT paramter only
+ int m_http_ver_lo;// OUT paramter only
+
+ void clear()
+ {
+ this->~http_response_info();
+ new(this) http_response_info();
+ }
+ };
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
new file mode 100644
index 000000000..4a88c06ef
--- /dev/null
+++ b/contrib/epee/include/net/http_client.h
@@ -0,0 +1,875 @@
+// 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 <boost/shared_ptr.hpp>
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+//#include <mbstring.h>
+#include <algorithm>
+#include <cctype>
+#include <functional>
+
+#include "net_helper.h"
+#include "http_client_base.h"
+
+#ifdef HTTP_ENABLE_GZIP
+#include "gzip_encoding.h"
+#endif
+
+#include "string_tools.h"
+#include "reg_exp_definer.h"
+#include "http_base.h"
+#include "to_nonconst_iterator.h"
+#include "net_parse_helpers.h"
+
+//#include "shlwapi.h"
+
+//#pragma comment(lib, "shlwapi.lib")
+
+extern epee::critical_section gregexp_lock;
+
+
+namespace epee
+{
+namespace net_utils
+{
+
+using namespace std;
+
+ /*struct url
+ {
+ public:
+ void parse(const std::string& url_s)
+ {
+ const string prot_end("://");
+ string::const_iterator prot_i = search(url_s.begin(), url_s.end(),
+ prot_end.begin(), prot_end.end());
+ protocol_.reserve(distance(url_s.begin(), prot_i));
+ transform(url_s.begin(), prot_i,
+ back_inserter(protocol_),
+ ptr_fun<int,int>(tolower)); // protocol is icase
+ if( prot_i == url_s.end() )
+ return;
+ advance(prot_i, prot_end.length());
+ string::const_iterator path_i = find(prot_i, url_s.end(), '/');
+ host_.reserve(distance(prot_i, path_i));
+ transform(prot_i, path_i,
+ back_inserter(host_),
+ ptr_fun<int,int>(tolower)); // host is icase
+ string::const_iterator query_i = find(path_i, url_s.end(), '?');
+ path_.assign(path_i, query_i);
+ if( query_i != url_s.end() )
+ ++query_i;
+ query_.assign(query_i, url_s.end());
+ }
+
+ std::string protocol_;
+ std::string host_;
+ std::string path_;
+ std::string query_;
+ };*/
+
+
+
+
+ //---------------------------------------------------------------------------
+ static inline const char* get_hex_vals()
+ {
+ static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ return hexVals;
+ }
+
+ static inline const char* get_unsave_chars()
+ {
+ //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
+ static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
+ return unsave_chars;
+ }
+
+ static inline bool is_unsafe(unsigned char compare_char)
+ {
+ if(compare_char <= 32 || compare_char >= 123)
+ return true;
+
+ const char* punsave = get_unsave_chars();
+
+ for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
+ if(compare_char == punsave[ichar_pos])
+ return true;
+
+ return false;
+ }
+
+ static inline
+ std::string dec_to_hex(char num, int radix)
+ {
+ int temp=0;
+ std::string csTmp;
+ int num_char;
+
+ num_char = (int) num;
+ if (num_char < 0)
+ num_char = 256 + num_char;
+
+ while (num_char >= radix)
+ {
+ temp = num_char % radix;
+ num_char = (int)floor((float)num_char / (float)radix);
+ csTmp = get_hex_vals()[temp];
+ }
+
+ csTmp += get_hex_vals()[num_char];
+
+ if(csTmp.size() < 2)
+ {
+ csTmp += '0';
+ }
+
+ std::reverse(csTmp.begin(), csTmp.end());
+ //_mbsrev((unsigned char*)csTmp.data());
+
+ return csTmp;
+ }
+
+ static inline std::string convert(char val)
+ {
+ std::string csRet;
+ csRet += "%";
+ csRet += dec_to_hex(val, 16);
+ return csRet;
+ }
+ static inline std::string conver_to_url_format(const std::string& uri)
+ {
+
+ std::string result;
+
+ for(size_t i = 0; i!= uri.size(); i++)
+ {
+ if(is_unsafe(uri[i]))
+ result += convert(uri[i]);
+ else
+ result += uri[i];
+
+ }
+
+ return result;
+ }
+
+ static inline std::string convert_to_url_format_force_all(const std::string& uri)
+ {
+
+ std::string result;
+
+ for(size_t i = 0; i!= uri.size(); i++)
+ {
+ result += convert(uri[i]);
+ }
+
+ return result;
+ }
+
+
+
+
+
+ namespace http
+ {
+
+ class http_simple_client: public i_target_handler
+ {
+ public:
+
+
+ private:
+ 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
+ };
+
+
+ blocked_mode_client m_net_client;
+ std::string m_host_buff;
+ std::string m_port;
+ unsigned int m_timeout;
+ std::string m_header_cache;
+ http_response_info m_response_info;
+ size_t m_len_in_summary;
+ size_t m_len_in_remain;
+ //std::string* m_ptarget_buffer;
+ boost::shared_ptr<i_sub_handler> m_pcontent_encoding_handler;
+ reciev_machine_state m_state;
+ chunked_state m_chunked_state;
+ std::string m_chunked_cache;
+ critical_section m_lock;
+
+ public:
+ void set_host_name(const std::string& name)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ m_host_buff = name;
+ }
+ bool connect(const std::string& host, int port, unsigned int timeout)
+ {
+ return connect(host, std::to_string(port), timeout);
+ }
+ bool connect(const std::string& host, const std::string& port, unsigned int timeout)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ m_host_buff = host;
+ m_port = port;
+ m_timeout = timeout;
+
+ return m_net_client.connect(host, port, timeout, timeout);
+ }
+ //---------------------------------------------------------------------------
+ bool disconnect()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ return m_net_client.disconnect();
+ }
+ //---------------------------------------------------------------------------
+ bool is_connected()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ return m_net_client.is_connected();
+ }
+ //---------------------------------------------------------------------------
+ virtual bool handle_target_data(std::string& piece_of_transfer)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ m_response_info.m_body += piece_of_transfer;
+ piece_of_transfer.clear();
+ return true;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ return invoke(uri, "GET", body, ppresponse_info, additional_params);
+ }
+
+ //---------------------------------------------------------------------------
+ inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ if(!is_connected())
+ {
+ LOG_PRINT("Reconnecting...", LOG_LEVEL_3);
+ if(!connect(m_host_buff, m_port, m_timeout))
+ {
+ LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3);
+ return false;
+ }
+ }
+ m_response_info.clear();
+ std::string req_buff = method + " ";
+ req_buff += uri + " HTTP/1.1\r\n" +
+ "Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n";
+
+
+ //handle "additional_params"
+ for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++)
+ req_buff += it->first + ": " + it->second + "\r\n";
+ req_buff += "\r\n";
+ //--
+
+ bool res = m_net_client.send(req_buff);
+ CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
+ if(body.size())
+ res = m_net_client.send(body);
+ CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
+
+ if(ppresponse_info)
+ *ppresponse_info = &m_response_info;
+
+ m_state = reciev_machine_state_header;
+ return handle_reciev();
+ }
+ //---------------------------------------------------------------------------
+ inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ return invoke(uri, "POST", body, ppresponse_info, additional_params);
+ }
+ private:
+ //---------------------------------------------------------------------------
+ inline bool handle_reciev()
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ bool keep_handling = true;
+ bool need_more_data = true;
+ std::string recv_buffer;
+ while(keep_handling)
+ {
+ if(need_more_data)
+ {
+ if(!m_net_client.recv(recv_buffer))
+ {
+ LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3);
+ 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;
+ }
+ 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;
+ }
+
+ }
+ 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;
+ }
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool handle_header(std::string& recv_buff, bool& need_more_data)
+ {
+
+ CRITICAL_REGION_LOCAL(m_lock);
+ if(!recv_buff.size())
+ {
+ LOG_ERROR("Connection closed at handle_header");
+ m_state = reciev_machine_state_error;
+ return false;
+ }
+
+ 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;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool handle_body_content_len(std::string& recv_buff, bool& need_more_data)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ if(!recv_buff.size())
+ {
+ LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3);
+ 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();
+ m_pcontent_encoding_handler->update_in(recv_buff);
+
+ if(m_len_in_remain == 0)
+ m_state = reciev_machine_state_done;
+ else
+ need_more_data = true;
+
+ return true;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ 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;
+ }
+ //---------------------------------------------------------------------------
+ inline bool is_hex_symbol(char ch)
+ {
+
+ if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f'))
+ return true;
+ else
+ return false;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ 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;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ 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 breif - 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;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data)
+ {
+ CRITICAL_REGION_LOCAL(m_lock);
+ if(!recv_buff.size())
+ {
+ LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3);
+ 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;
+ }
+
+ m_pcontent_encoding_handler->update_in(chunk_body);
+
+ 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;
+ }
+ //---------------------------------------------------------------------------
+ inline
+ bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process)
+ {
+ LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4);
+
+ STATIC_REGEXP_EXPR_1(rexp_mach_field,
+ "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)"
+ // 12 3 4 5 6 7 8 9
+ "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
+ //10 1112 13
+ boost::regex::icase | boost::regex::normal);
+
+ boost::smatch result;
+ std::string::const_iterator it_current_bound = m_cache_to_process.begin();
+ std::string::const_iterator it_end_bound = m_cache_to_process.end();
+
+
+
+ //lookup all fields and fill well-known fields
+ while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
+ {
+ const size_t field_val = 12;
+ //const size_t field_etc_name = 10;
+
+ int i = 2; //start position = 2
+ if(result[i++].matched)//"Connection"
+ body_info.m_connection = result[field_val];
+ else if(result[i++].matched)//"Referrer"
+ body_info.m_referer = result[field_val];
+ else if(result[i++].matched)//"Content-Length"
+ body_info.m_content_length = result[field_val];
+ else if(result[i++].matched)//"Content-Type"
+ body_info.m_content_type = result[field_val];
+ else if(result[i++].matched)//"Transfer-Encoding"
+ body_info.m_transfer_encoding = result[field_val];
+ else if(result[i++].matched)//"Content-Encoding"
+ body_info.m_content_encoding = result[field_val];
+ else if(result[i++].matched)//"Host"
+ { body_info.m_host = result[field_val];
+ string_tools::trim(body_info.m_host);
+ }
+ else if(result[i++].matched)//"Cookie"
+ body_info.m_cookie = result[field_val];
+ else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
+ {;}
+ else
+ {CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<<m_cache_to_process);}
+
+ it_current_bound = result[(int)result.size()-1]. first;
+ }
+ return true;
+
+ }
+ inline
+ bool analize_first_response_line()
+ {
+
+ //First line response, look like this: "HTTP/1.1 200 OK"
+ STATIC_REGEXP_EXPR_1(rexp_match_first_response_line, "^HTTP/(\\d+).(\\d+) ((\\d)\\d{2})( [^\n]*)?\r?\n", boost::regex::icase | boost::regex::normal);
+ // 1 2 34 5
+ //size_t match_len = 0;
+ boost::smatch result;
+ if(boost::regex_search( m_header_cache, result, rexp_match_first_response_line, boost::match_default) && result[0].matched)
+ {
+ CHECK_AND_ASSERT_MES(result[1].matched&&result[2].matched, false, "http_stream_filter::handle_invoke_reply_line() assert failed...");
+ m_response_info.m_http_ver_hi = boost::lexical_cast<int>(result[1]);
+ m_response_info.m_http_ver_lo = boost::lexical_cast<int>(result[2]);
+ m_response_info.m_response_code = boost::lexical_cast<int>(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;
+ }
+
+ }
+ inline
+ 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)
+ {
+#ifdef HTTP_ENABLE_GZIP
+ m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched));
+#else
+ 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;
+#endif
+ }
+ else
+ {
+ m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this));
+ }
+
+ return true;
+ }
+ inline
+ 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="<<m_response_info.m_header_info.m_content_length);
+ m_state = reciev_machine_state_error;
+ return false;
+ }
+ if(!m_len_in_summary)
+ {
+ m_state = reciev_machine_state_done;
+ return true;
+ }
+ else
+ {
+ m_len_in_remain = m_len_in_summary;
+ m_state = reciev_machine_state_body_content_len;
+ return true;
+ }
+ }else if(!m_response_info.m_header_info.m_connection.empty() && is_connection_close_field(m_response_info.m_header_info.m_connection))
+ { //By indirect signs we suspect that data transfer will end with a connection break
+ m_state = reciev_machine_state_body_connection_close;
+ }else if(is_multipart_body(m_response_info.m_header_info, fake_str))
+ {
+ m_state = reciev_machine_state_error;
+ LOG_ERROR("Unsupported MULTIPART BODY.");
+ return false;
+ }else
+ { //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
+ m_state = reciev_machine_state_error;
+ LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method.", LOG_LEVEL_2);
+ return false;
+ }
+ return false;
+ }
+ inline
+ bool is_connection_close_field(const std::string& str)
+ {
+ STATIC_REGEXP_EXPR_1(rexp_match_close, "^\\s*close", boost::regex::icase | boost::regex::normal);
+ boost::smatch result;
+ if(boost::regex_search( str, result, rexp_match_close, boost::match_default) && result[0].matched)
+ return true;
+ else
+ return false;
+ }
+ inline
+ 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;
+ }
+ };
+
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ //inline
+ template<class t_transport>
+ bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list())
+ {
+ http::url_content u_c;
+ bool res = parse_url(url, u_c);
+
+ if(!tr.is_connected())
+ {
+ CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url);
+
+ if(!u_c.port)
+ u_c.port = 80;//default for http
+
+ res = tr.connect(u_c.host, static_cast<int>(u_c.port), timeout);
+ CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port);
+ }
+
+ return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params);
+ }
+
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_client_abstract_invoke.h b/contrib/epee/include/net/http_client_abstract_invoke.h
new file mode 100644
index 000000000..425a355ee
--- /dev/null
+++ b/contrib/epee/include/net/http_client_abstract_invoke.h
@@ -0,0 +1,98 @@
+
+// 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 "storages/serializeble_struct_helper.h"
+
+namespace epee
+{
+ namespace net_utils
+ {
+ namespace http
+ {
+ template<class TArg, class TResult, class TTransport>
+ bool invoke_http_json_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
+ {
+ std::string req_param;
+ StorageNamed::InMemStorageSpace::json::store_t_to_json(out_struct, req_param);
+
+ const http_response_info* pri = NULL;
+ if(!invoke_request(url, transport, timeout, &pri, method, req_param))
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url);
+ return false;
+ }
+
+ if(!pri->m_response_code)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
+ return false;
+ }
+
+ if(pri->m_response_code != 200)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
+ return false;
+ }
+
+ return StorageNamed::InMemStorageSpace::json::load_t_from_json(result_struct, pri->m_body);
+ }
+
+
+
+ template<class TArg, class TResult, class TTransport>
+ bool invoke_http_bin_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
+ {
+ std::string req_param;
+ epee::StorageNamed::save_struct_as_storage_to_buff(out_struct, req_param);
+
+ const http_response_info* pri = NULL;
+ if(!invoke_request(url, transport, timeout, &pri, method, req_param))
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url);
+ return false;
+ }
+
+ if(!pri->m_response_code)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
+ return false;
+ }
+
+ if(pri->m_response_code != 200)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
+ return false;
+ }
+
+ return epee::StorageNamed::load_struct_from_storage_buff(result_struct, pri->m_body);
+ }
+
+
+ }
+ }
+}
diff --git a/contrib/epee/include/net/http_client_base.h b/contrib/epee/include/net/http_client_base.h
new file mode 100644
index 000000000..571e27f73
--- /dev/null
+++ b/contrib/epee/include/net/http_client_base.h
@@ -0,0 +1,73 @@
+// 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
+
+namespace epee
+{
+ namespace net_utils
+ {
+ struct i_sub_handler
+ {
+ virtual ~i_sub_handler(){}
+
+ virtual bool update_in( std::string& piece_of_transfer)=0;
+ virtual void stop(std::string& OUT collect_remains)=0;
+ virtual bool update_and_stop(std::string& OUT collect_remains, bool& is_changed)
+ {
+ is_changed = true;
+ bool res = this->update_in(collect_remains);
+ if(res)
+ this->stop(collect_remains);
+ return res;
+ }
+ };
+
+
+ struct i_target_handler
+ {
+ virtual ~i_target_handler(){}
+ virtual bool handle_target_data( std::string& piece_of_transfer)=0;
+ };
+
+
+ class do_nothing_sub_handler: public i_sub_handler
+ {
+ public:
+ do_nothing_sub_handler(i_target_handler* powner_filter):m_powner_filter(powner_filter)
+ {}
+ virtual bool update_in( std::string& piece_of_transfer)
+ {
+ return m_powner_filter->handle_target_data(piece_of_transfer);
+ }
+ virtual void stop(std::string& OUT collect_remains)
+ {
+
+ }
+ i_target_handler* m_powner_filter;
+ };
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_client_via_api_helper.h b/contrib/epee/include/net/http_client_via_api_helper.h
new file mode 100644
index 000000000..45a70993b
--- /dev/null
+++ b/contrib/epee/include/net/http_client_via_api_helper.h
@@ -0,0 +1,177 @@
+// 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 <wininet.h>
+#include <atlutil.h>
+#pragma comment(lib, "Wininet.lib")
+
+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<std::basic_string<TCHAR> >(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;
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h
new file mode 100644
index 000000000..4aebcf2aa
--- /dev/null
+++ b/contrib/epee/include/net/http_protocol_handler.h
@@ -0,0 +1,209 @@
+// 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_H_
+#define _HTTP_SERVER_H_
+
+#include <string>
+#include "net_utils_base.h"
+#include "to_nonconst_iterator.h"
+#include "http_base.h"
+
+namespace epee
+{
+namespace net_utils
+{
+ namespace http
+ {
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct http_server_config
+ {
+ std::string m_folder;
+ critical_section m_lock;
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class simple_http_connection_handler
+ {
+ public:
+ typedef net_utils::connection_context_base connection_context;
+ typedef http_server_config config_type;
+
+ simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config);
+ virtual ~simple_http_connection_handler(){}
+
+ bool release_protocol()
+ {
+ return true;
+ }
+
+ virtual bool thread_init()
+ {
+ return true;
+ }
+
+ virtual bool thread_deinit()
+ {
+ return true;
+ }
+ bool after_init_connection()
+ {
+ return true;
+ }
+ virtual bool handle_recv(const void* ptr, size_t cb);
+ virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response);
+
+
+ //temporary here
+ //bool parse_uri(const std::string uri, uri_content& content);
+
+ private:
+ enum machine_state{
+ http_state_retriving_comand_line,
+ http_state_retriving_header,
+ http_state_retriving_body,
+ http_state_connection_close,
+ http_state_error
+ };
+
+ enum body_transfer_type{
+ http_body_transfer_chunked,
+ http_body_transfer_measure,//mean "Content-Length" valid
+ http_body_transfer_chunked_instead_measure,
+ http_body_transfer_connection_close,
+ http_body_transfer_multipart,
+ http_body_transfer_undefined
+ };
+
+ bool handle_buff_in(std::string& buf);
+
+ bool analize_cached_request_header_and_invoke_state(size_t pos);
+
+ bool handle_invoke_query_line();
+ bool parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos);
+ std::string::size_type match_end_of_header(const std::string& buf);
+ bool get_len_from_content_lenght(const std::string& str, size_t& len);
+ bool handle_retriving_query_body();
+ bool handle_query_measure();
+ bool set_ready_state();
+ bool slash_to_back_slash(std::string& str);
+ std::string get_file_mime_tipe(const std::string& path);
+ std::string get_response_header(const http_response_info& response);
+
+ //major function
+ inline bool handle_request_and_send_response(const http::http_request_info& query_info);
+
+
+ std::string get_not_found_response_body(const std::string& URI);
+
+ std::string m_root_path;
+ std::string m_cache;
+ machine_state m_state;
+ body_transfer_type m_body_transfer_type;
+ bool m_is_stop_handling;
+ http::http_request_info m_query_info;
+ size_t m_len_summary, m_len_remain;
+ config_type& m_config;
+ bool m_want_close;
+ protected:
+ i_service_endpoint* m_psnd_hndlr;
+ };
+
+
+ struct i_http_server_handler
+ {
+ virtual ~i_http_server_handler(){}
+ virtual bool handle_http_request(const http_request_info& query_info, http_response_info& response, const net_utils::connection_context_base& m_conn_context)=0;
+ virtual bool init_server_thread(){return true;}
+ virtual bool deinit_server_thread(){return true;}
+ };
+
+
+ struct custum_handler_config: public http_server_config
+ {
+ i_http_server_handler* m_phandler;
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class http_custom_handler: public simple_http_connection_handler
+ {
+ public:
+ typedef custum_handler_config config_type;
+
+ http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, const net_utils::connection_context_base& conn_context):simple_http_connection_handler(psnd_hndlr, config),
+ m_config(config),
+ m_conn_context(conn_context)
+ {}
+ inline bool handle_request(const http_request_info& query_info, http_response_info& response)
+ {
+ CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!");
+ //fill with default values
+ response.m_mime_tipe = "text/plain";
+ response.m_response_code = 200;
+ response.m_response_comment = "OK";
+ response.m_body.clear();
+ return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context);
+ }
+
+ virtual bool thread_init()
+ {
+ return m_config.m_phandler->init_server_thread();;
+ }
+
+ virtual bool thread_deinit()
+ {
+ return m_config.m_phandler->deinit_server_thread();
+ }
+ void handle_qued_callback()
+ {}
+ bool after_init_connection()
+ {
+ return true;
+ }
+
+ private:
+ //simple_http_connection_handler::config_type m_stub_config;
+ config_type& m_config;
+ const net_utils::connection_context_base& m_conn_context;
+ };
+ }
+}
+}
+
+#include "http_protocol_handler.inl"
+
+#endif //_HTTP_SERVER_H_
diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl
new file mode 100644
index 000000000..810c46db9
--- /dev/null
+++ b/contrib/epee/include/net/http_protocol_handler.inl
@@ -0,0 +1,664 @@
+// 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.
+//
+
+
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+#include "http_protocol_handler.h"
+#include "reg_exp_definer.h"
+#include "string_tools.h"
+#include "file_io_utils.h"
+#include "net_parse_helpers.h"
+
+#define HTTP_MAX_URI_LEN 9000
+#define HTTP_MAX_HEADER_LEN 100000
+
+namespace epee
+{
+namespace net_utils
+{
+ namespace http
+ {
+
+ struct multipart_entry
+ {
+ std::list<std::pair<std::string, std::string> > m_etc_header_fields;
+ std::string m_content_disposition;
+ std::string m_content_type;
+ std::string m_body;
+ };
+
+ inline
+ bool match_boundary(const std::string& content_type, std::string& boundary)
+ {
+ STATIC_REGEXP_EXPR_1(rexp_match_boundary, "boundary=(.*?)(($)|([;\\s,]))", boost::regex::icase | boost::regex::normal);
+ // 1
+ boost::smatch result;
+ if(boost::regex_search(content_type, result, rexp_match_boundary, boost::match_default) && result[0].matched)
+ {
+ boundary = result[1];
+ return true;
+ }
+
+ return false;
+ }
+
+ inline
+ bool parse_header(std::string::const_iterator it_begin, std::string::const_iterator it_end, multipart_entry& entry)
+ {
+ STATIC_REGEXP_EXPR_1(rexp_mach_field,
+ "\n?((Content-Disposition)|(Content-Type)"
+ // 12 3
+ "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
+ //4 56 7
+ boost::regex::icase | boost::regex::normal);
+
+ boost::smatch result;
+ std::string::const_iterator it_current_bound = it_begin;
+ std::string::const_iterator it_end_bound = it_end;
+
+ //lookup all fields and fill well-known fields
+ while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
+ {
+ const size_t field_val = 6;
+ const size_t field_etc_name = 4;
+
+ int i = 2; //start position = 2
+ if(result[i++].matched)//"Content-Disposition"
+ entry.m_content_disposition = result[field_val];
+ else if(result[i++].matched)//"Content-Type"
+ entry.m_content_type = result[field_val];
+ else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
+ entry.m_etc_header_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
+ else
+ {
+ LOG_ERROR("simple_http_connection_handler::parse_header() not matched last entry in:"<<std::string(it_current_bound, it_end));
+ }
+
+ it_current_bound = result[(int)result.size()-1].first;
+ }
+ return true;
+ }
+
+ inline
+ bool handle_part_of_multipart(std::string::const_iterator it_begin, std::string::const_iterator it_end, multipart_entry& entry)
+ {
+ std::string end_str = "\r\n\r\n";
+ std::string::const_iterator end_header_it = std::search(it_begin, it_end, end_str.begin(), end_str.end());
+ if(end_header_it == it_end)
+ {
+ //header not matched
+ return false;
+ }
+
+ if(!parse_header(it_begin, end_header_it+4, entry))
+ {
+ LOG_ERROR("Failed to parse header:" << std::string(it_begin, end_header_it+2));
+ return false;
+ }
+
+ entry.m_body.assign(end_header_it+4, it_end);
+
+ return true;
+ }
+
+ inline
+ bool parse_multipart_body(const std::string& content_type, const std::string& body, std::list<multipart_entry>& out_values)
+ {
+ //bool res = file_io_utils::load_file_to_string("C:\\public\\multupart_data", body);
+
+ std::string boundary;
+ if(!match_boundary(content_type, boundary))
+ {
+ LOG_PRINT("Failed to match boundary in content type: " << content_type, LOG_LEVEL_0);
+ return false;
+ }
+
+ boundary+="\r\n";
+ bool is_stop = false;
+ bool first_step = true;
+
+ std::string::const_iterator it_begin = body.begin();
+ std::string::const_iterator it_end;
+ while(!is_stop)
+ {
+ std::string::size_type pos = body.find(boundary, std::distance(body.begin(), it_begin));
+
+ if(std::string::npos == pos)
+ {
+ is_stop = true;
+ boundary.erase(boundary.size()-2, 2);
+ boundary+= "--";
+ pos = body.find(boundary, std::distance(body.begin(), it_begin));
+ if(std::string::npos == pos)
+ {
+ LOG_PRINT("Error: Filed to match closing multipart tag", LOG_LEVEL_0);
+ it_end = body.end();
+ }else
+ {
+ it_end = body.begin() + pos;
+ }
+ }else
+ it_end = body.begin() + pos;
+
+
+ if(first_step && !is_stop)
+ {
+ first_step = false;
+ it_begin = it_end + boundary.size();
+ std::string temp = "\r\n--";
+ boundary = temp + boundary;
+ continue;
+ }
+
+ out_values.push_back(multipart_entry());
+ if(!handle_part_of_multipart(it_begin, it_end, out_values.back()))
+ {
+ LOG_PRINT("Failed to handle_part_of_multipart", LOG_LEVEL_0);
+ return false;
+ }
+
+ it_begin = it_end + boundary.size();
+ }
+
+ return true;
+ }
+
+
+
+
+ //--------------------------------------------------------------------------------------------
+ inline
+ simple_http_connection_handler::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config):
+ m_state(http_state_retriving_comand_line),
+ m_body_transfer_type(http_body_transfer_undefined),
+ m_is_stop_handling(false),
+ m_len_summary(0),
+ m_len_remain(0),
+ m_config(config),
+ m_want_close(false),
+ m_psnd_hndlr(psnd_hndlr)
+ {
+
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::set_ready_state()
+ {
+ m_is_stop_handling = false;
+ m_state = http_state_retriving_comand_line;
+ m_body_transfer_type = http_body_transfer_undefined;
+ m_query_info.clear();
+ m_len_summary = 0;
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_recv(const void* ptr, size_t cb)
+ {
+ std::string buf((const char*)ptr, cb);
+ //LOG_PRINT_L0("HTTP_RECV: " << ptr << "\r\n" << buf);
+ //file_io_utils::save_string_to_file(string_tools::get_current_module_folder() + "/" + boost::lexical_cast<std::string>(ptr), std::string((const char*)ptr, cb));
+
+ bool res = handle_buff_in(buf);
+ if(m_want_close/*m_state == http_state_connection_close || m_state == http_state_error*/)
+ return false;
+ return res;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_buff_in(std::string& buf)
+ {
+
+ if(m_cache.size())
+ m_cache += buf;
+ else
+ m_cache.swap(buf);
+
+ m_is_stop_handling = false;
+ while(!m_is_stop_handling)
+ {
+ switch(m_state)
+ {
+ case http_state_retriving_comand_line:
+ //The HTTP protocol does not place any a priori limit on the length of a URI. (c)RFC2616
+ //but we forebly restirct it len to HTTP_MAX_URI_LEN to make it more safely
+ if(!m_cache.size())
+ break;
+
+ //check_and_handle_fake_response();
+ if((m_cache[0] == '\r' || m_cache[0] == '\n'))
+ {
+ //some times it could be that before query line cold be few line breaks
+ //so we have to be calm without panic with assers
+ m_cache.erase(0, 1);
+ break;
+ }
+
+ if(std::string::npos != m_cache.find('\n', 0))
+ handle_invoke_query_line();
+ else
+ {
+ m_is_stop_handling = true;
+ if(m_cache.size() > HTTP_MAX_URI_LEN)
+ {
+ LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line");
+ m_state = http_state_error;
+ return false;
+ }
+ }
+ break;
+ case http_state_retriving_header:
+ {
+ std::string::size_type pos = match_end_of_header(m_cache);
+ if(std::string::npos == pos)
+ {
+ m_is_stop_handling = true;
+ if(m_cache.size() > HTTP_MAX_HEADER_LEN)
+ {
+ LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long header area");
+ m_state = http_state_error;
+ return false;
+ }
+ break;
+ }
+ analize_cached_request_header_and_invoke_state(pos);
+ break;
+ }
+ case http_state_retriving_body:
+ return handle_retriving_query_body();
+ case http_state_connection_close:
+ return false;
+ default:
+ LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
+ return false;
+ case http_state_error:
+ LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!");
+ return false;
+ }
+
+ if(!m_cache.size())
+ m_is_stop_handling = true;
+ }
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool analize_http_method(const boost::smatch& result, http::http_method& method, int& http_ver_major, int& http_ver_minor)
+ {
+ CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed...");
+ http_ver_major = boost::lexical_cast<int>(result[11]);
+ http_ver_minor = boost::lexical_cast<int>(result[12]);
+ if(result[4].matched)
+ method = http::http_method_get;
+ else if(result[5].matched)
+ method = http::http_method_head;
+ else if(result[6].matched)
+ method = http::http_method_post;
+ else if(result[7].matched)
+ method = http::http_method_put;
+ else
+ method = http::http_method_etc;
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_invoke_query_line()
+ {
+ LOG_FRAME("simple_http_connection_handler::handle_recognize_protocol_out(*)", LOG_LEVEL_3);
+
+ STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
+ // 123 4 5 6 7 8 9 10 11 12
+ //size_t match_len = 0;
+ boost::smatch result;
+ if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched)
+ {
+ analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi);
+ m_query_info.m_URI = result[10];
+ parse_uri(m_query_info.m_URI, m_query_info.m_uri_content);
+ m_query_info.m_http_method_str = result[2];
+ m_query_info.m_full_request_str = result[0];
+
+ m_cache.erase(m_cache.begin(), to_nonsonst_iterator(m_cache, result[0].second));
+
+ m_state = http_state_retriving_header;
+
+ return true;
+ }else
+ {
+ m_state = http_state_error;
+ LOG_ERROR("simple_http_connection_handler::handle_invoke_query_line(): Failed to match first line: " << m_cache);
+ return false;
+ }
+
+ return false;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline std::string::size_type simple_http_connection_handler::match_end_of_header(const std::string& buf)
+ {
+
+ //Here we returning head size, including terminating sequence (\r\n\r\n or \n\n)
+ std::string::size_type res = buf.find("\r\n\r\n");
+ if(std::string::npos != res)
+ return res+4;
+ res = buf.find("\n\n");
+ if(std::string::npos != res)
+ return res+2;
+ return res;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::analize_cached_request_header_and_invoke_state(size_t pos)
+ {
+ //LOG_PRINT_L4("HTTP HEAD:\r\n" << m_cache.substr(0, pos));
+
+ LOG_FRAME("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(*)", LOG_LEVEL_3);
+
+ m_query_info.m_full_request_buf_size = pos;
+ m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
+
+ if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos))
+ {
+ LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
+ m_state = http_state_error;
+ }
+
+ m_cache.erase(0, pos);
+
+ std::string req_command_str = m_query_info.m_full_request_str;
+ //if we have POST or PUT command, it is very possible tha we will get body
+ //but now, we suppose than we have body only in case of we have "ContentLength"
+ if(m_query_info.m_header_info.m_content_length.size())
+ {
+ m_state = http_state_retriving_body;
+ m_body_transfer_type = http_body_transfer_measure;
+ if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary))
+ {
+ LOG_ERROR("simple_http_connection_handler::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
+ m_state = http_state_error;
+ return false;
+ }
+ if(0 == m_len_summary)
+ { //current query finished, next will be next query
+ if(handle_request_and_send_response(m_query_info))
+ set_ready_state();
+ else
+ m_state = http_state_error;
+ }
+ m_len_remain = m_len_summary;
+ }else
+ {//current query finished, next will be next query
+ handle_request_and_send_response(m_query_info);
+ set_ready_state();
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_retriving_query_body()
+ {
+ switch(m_body_transfer_type)
+ {
+ case http_body_transfer_measure:
+ return handle_query_measure();
+ case http_body_transfer_chunked:
+ case http_body_transfer_connection_close:
+ case http_body_transfer_multipart:
+ case http_body_transfer_undefined:
+ default:
+ LOG_ERROR("simple_http_connection_handler::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
+ m_state = http_state_error;
+ return false;
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_query_measure()
+ {
+
+ if(m_len_remain >= m_cache.size())
+ {
+ m_len_remain -= m_cache.size();
+ m_query_info.m_body += m_cache;
+ m_cache.clear();
+ }else
+ {
+ m_query_info.m_body.append(m_cache.begin(), m_cache.begin() + m_len_remain);
+ m_cache.erase(0, m_len_remain);
+ m_len_remain = 0;
+ }
+
+ if(!m_len_remain)
+ {
+ if(handle_request_and_send_response(m_query_info))
+ set_ready_state();
+ else
+ m_state = http_state_error;
+ }
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos)
+ {
+ LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_3);
+
+ STATIC_REGEXP_EXPR_1(rexp_mach_field,
+ "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)"
+ // 12 3 4 5 6 7 8 9
+ "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
+ //10 1112 13
+ boost::regex::icase | boost::regex::normal);
+
+ boost::smatch result;
+ std::string::const_iterator it_current_bound = m_cache_to_process.begin();
+ std::string::const_iterator it_end_bound = m_cache_to_process.begin()+pos;
+
+ body_info.clear();
+
+ //lookup all fields and fill well-known fields
+ while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
+ {
+ const size_t field_val = 12;
+ const size_t field_etc_name = 10;
+
+ int i = 2; //start position = 2
+ if(result[i++].matched)//"Connection"
+ body_info.m_connection = result[field_val];
+ else if(result[i++].matched)//"Referer"
+ body_info.m_referer = result[field_val];
+ else if(result[i++].matched)//"Content-Length"
+ body_info.m_content_length = result[field_val];
+ else if(result[i++].matched)//"Content-Type"
+ body_info.m_content_type = result[field_val];
+ else if(result[i++].matched)//"Transfer-Encoding"
+ body_info.m_transfer_encoding = result[field_val];
+ else if(result[i++].matched)//"Content-Encoding"
+ body_info.m_content_encoding = result[field_val];
+ else if(result[i++].matched)//"Host"
+ body_info.m_host = result[field_val];
+ else if(result[i++].matched)//"Cookie"
+ body_info.m_cookie = result[field_val];
+ else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
+ body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
+ else
+ {
+ LOG_ERROR("simple_http_connection_handler::parse_cached_header() not matched last entry in:"<<m_cache_to_process);
+ }
+
+ it_current_bound = result[(int)result.size()-1]. first;
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::get_len_from_content_lenght(const std::string& str, size_t& OUT len)
+ {
+ STATIC_REGEXP_EXPR_1(rexp_mach_field, "\\d+", boost::regex::normal);
+ std::string res;
+ boost::smatch result;
+ if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched))
+ return false;
+
+ len = boost::lexical_cast<size_t>(result[0]);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_request_and_send_response(const http::http_request_info& query_info)
+ {
+ http_response_info response;
+ bool res = handle_request(query_info, response);
+ //CHECK_AND_ASSERT_MES(res, res, "handle_request(query_info, response) returned false" );
+
+ std::string response_data = get_response_header(response);
+
+ //LOG_PRINT_L0("HTTP_SEND: << \r\n" << response_data + response.m_body);
+ LOG_PRINT_L3("HTTP_RESPONSE_HEAD: << \r\n" << response_data);
+
+ m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
+ if(response.m_body.size())
+ m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
+ return res;
+ }
+ //-----------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::handle_request(const http::http_request_info& query_info, http_response_info& response)
+ {
+
+ std::string uri_to_path = query_info.m_uri_content.m_path;
+ if("/" == uri_to_path)
+ uri_to_path = "/index.html";
+
+ //slash_to_back_slash(uri_to_path);
+ m_config.m_lock.lock();
+ std::string destination_file_path = m_config.m_folder + uri_to_path;
+ m_config.m_lock.unlock();
+ if(!file_io_utils::load_file_to_string(destination_file_path.c_str(), response.m_body))
+ {
+ LOG_PRINT("URI \""<< query_info.m_full_request_str.substr(0, query_info.m_full_request_str.size()-2) << "\" [" << destination_file_path << "] Not Found (404 )" , LOG_LEVEL_1);
+ response.m_body = get_not_found_response_body(query_info.m_URI);
+ response.m_response_code = 404;
+ response.m_response_comment = "Not found";
+ response.m_mime_tipe = "text/html";
+ return true;
+ }
+
+ LOG_PRINT(" -->> " << query_info.m_full_request_str << "\r\n<<--OK" , LOG_LEVEL_3);
+ response.m_response_code = 200;
+ response.m_response_comment = "OK";
+ response.m_mime_tipe = get_file_mime_tipe(uri_to_path);
+
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------
+ inline std::string simple_http_connection_handler::get_response_header(const http_response_info& response)
+ {
+ std::string buf = "HTTP/1.1 ";
+ buf += boost::lexical_cast<std::string>(response.m_response_code) + " " + response.m_response_comment + "\r\n" +
+ "Server: Siski v0.1\r\n"
+ "Content-Length: ";
+ buf += boost::lexical_cast<std::string>(response.m_body.size()) + "\r\n";
+ buf += "Content-Type: ";
+ buf += response.m_mime_tipe + "\r\n";
+
+ buf += "Last-Modified: ";
+ time_t tm;
+ time(&tm);
+ buf += misc_utils::get_internet_time_str(tm) + "\r\n";
+ buf += "Accept-Ranges: bytes\r\n";
+ //Wed, 01 Dec 2010 03:27:41 GMT"
+
+ string_tools::trim(m_query_info.m_header_info.m_connection);
+ if(m_query_info.m_header_info.m_connection.size())
+ {
+ if(!string_tools::compare_no_case("close", m_query_info.m_header_info.m_connection))
+ {
+ //closing connection after sending
+ buf += "Connection: close\r\n";
+ m_state = http_state_connection_close;
+ m_want_close = true;
+ }
+ }
+ //add additional fields, if it is
+ for(fields_list::const_iterator it = response.m_additional_fields.begin(); it!=response.m_additional_fields.end(); it++)
+ buf += it->first + ":" + it->second + "\r\n";
+
+ buf+="\r\n";
+
+ return buf;
+ }
+ //-----------------------------------------------------------------------------------
+ inline std::string simple_http_connection_handler::get_file_mime_tipe(const std::string& path)
+ {
+ std::string result;
+ std::string ext = string_tools::get_extension(path);
+ if(!string_tools::compare_no_case(ext, "gif"))
+ result = "image/gif";
+ else if(!string_tools::compare_no_case(ext, "jpg"))
+ result = "image/jpeg";
+ else if(!string_tools::compare_no_case(ext, "html"))
+ result = "text/html";
+ else if(!string_tools::compare_no_case(ext, "htm"))
+ result = "text/html";
+ else if(!string_tools::compare_no_case(ext, "js"))
+ result = "application/x-javascript";
+ else if(!string_tools::compare_no_case(ext, "css"))
+ result = "text/css";
+ else if(!string_tools::compare_no_case(ext, "xml"))
+ result = "application/xml";
+ else if(!string_tools::compare_no_case(ext, "svg"))
+ result = "image/svg+xml";
+
+
+ return result;
+ }
+ //-----------------------------------------------------------------------------------
+ inline std::string simple_http_connection_handler::get_not_found_response_body(const std::string& URI)
+ {
+ std::string body =
+ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+ "<html><head>\r\n"
+ "<title>404 Not Found</title>\r\n"
+ "</head><body>\r\n"
+ "<h1>Not Found</h1>\r\n"
+ "<p>The requested URL \r\n";
+ body += URI;
+ body += "was not found on this server.</p>\r\n"
+ "</body></html>\r\n";
+
+ return body;
+ }
+ //--------------------------------------------------------------------------------------------
+ inline bool simple_http_connection_handler::slash_to_back_slash(std::string& str)
+ {
+ for(std::string::iterator it = str.begin(); it!=str.end(); it++)
+ if('/' == *it)
+ *it = '\\';
+ return true;
+ }
+ }
+}
+}
+
+//--------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------- \ No newline at end of file
diff --git a/contrib/epee/include/net/http_server_cp.h b/contrib/epee/include/net/http_server_cp.h
new file mode 100644
index 000000000..bbb167f9f
--- /dev/null
+++ b/contrib/epee/include/net/http_server_cp.h
@@ -0,0 +1,48 @@
+// 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"
+namespace epee
+{
+namespace net_utils
+{
+ typedef cp_server_impl<http::simple_http_connection_handler> cp_http_server_file_system;
+ typedef cp_server_impl<http::http_custom_handler> cp_http_server_custum_handling;
+}
+}
+
+
+
+#endif
+
+
diff --git a/contrib/epee/include/net/http_server_cp2.h b/contrib/epee/include/net/http_server_cp2.h
new file mode 100644
index 000000000..dd76d06f8
--- /dev/null
+++ b/contrib/epee/include/net/http_server_cp2.h
@@ -0,0 +1,47 @@
+// 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_CP2_H_
+#define _HTTP_SERVER_CP2_H_
+
+#include "abstract_tcp_server2.h"
+#include "http_protocol_handler.h"
+namespace epee
+{
+namespace net_utils
+{
+ typedef boosted_tcp_server<http::simple_http_connection_handler> boosted_http_server_file_system;
+ typedef boosted_tcp_server<http::http_custom_handler> boosted_http_server_custum_handling;
+}
+}
+
+
+#endif
+
+
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
new file mode 100644
index 000000000..7a8bdd4ad
--- /dev/null
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -0,0 +1,260 @@
+// 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 "serialization/keyvalue_serialization.h"
+#include "storages/portable_storage_template_helper.h"
+#include "http_base.h"
+
+
+#define CHAIN_HTTP_TO_MAP2() bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
+ epee::net_utils::http::http_response_info& response, \
+ const epee::net_utils::connection_context_base& m_conn_context) \
+{\
+ LOG_PRINT_L2("HTTP [" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "] " << query_info.m_http_method_str << " " << query_info.m_URI); \
+ response.m_response_code = 200; \
+ response.m_response_comment = "Ok"; \
+ if(!handle_http_request_map(query_info, response, m_conn_context)) \
+ {response.m_response_code = 404;response.m_response_comment = "Not found";} \
+ return true; \
+}
+
+
+#define BEGIN_URI_MAP2() bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
+ epee::net_utils::http::http_response_info& response_info, \
+ const epee::net_utils::connection_context_base& m_conn_context) { \
+ bool handled = false; \
+ if(false) return true; //just a stub to have "else if"
+
+#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context);
+
+#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
+
+#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \
+ else if(query_info.m_URI == s_pattern) \
+ { \
+ handled = true; \
+ boost::uint64_t ticks = misc_utils::get_tick_count(); \
+ boost::value_initialized<command_type::request> req; \
+ bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
+ CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse json: \r\n" << query_info.m_body); \
+ boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
+ boost::value_initialized<command_type::response> resp;\
+ if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp))) \
+ { \
+ LOG_ERROR("Failed to " << #callback_f << "()"); \
+ response_info.m_response_code = 500; \
+ response_info.m_response_comment = "Internal Server Error"; \
+ return true; \
+ } \
+ boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
+ epee::serialization::store_t_to_json(static_cast<command_type::response&>(resp), response_info.m_body); \
+ boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
+ response_info.m_mime_tipe = "application/json"; \
+ response_info.m_header_info.m_content_type = " application/json"; \
+ LOG_PRINT( s_pattern << " processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
+ }
+
+#define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \
+ else if(query_info.m_URI == s_pattern) \
+ { \
+ handled = true; \
+ boost::uint64_t ticks = misc_utils::get_tick_count(); \
+ boost::value_initialized<command_type::request> req; \
+ bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
+ CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
+ boost::uint64_t ticks1 = misc_utils::get_tick_count(); \
+ boost::value_initialized<command_type::response> resp;\
+ if(!callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp))) \
+ { \
+ LOG_ERROR("Failed to " << #callback_f << "()"); \
+ response_info.m_response_code = 500; \
+ response_info.m_response_comment = "Internal Server Error"; \
+ return true; \
+ } \
+ boost::uint64_t ticks2 = misc_utils::get_tick_count(); \
+ epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \
+ boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
+ response_info.m_mime_tipe = " application/octet-stream"; \
+ response_info.m_header_info.m_content_type = " application/octet-stream"; \
+ LOG_PRINT( s_pattern << "() processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
+ }
+
+#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);handled = true;}
+
+#define END_URI_MAP2() return handled;}
+
+
+
+
+namespace epee
+{
+ namespace json_rpc
+ {
+ template<typename t_param>
+ struct request
+ {
+ std::string version;
+ std::string method;
+ std::string id;
+ t_param params;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(version)
+ KV_SERIALIZE(method)
+ KV_SERIALIZE(id)
+ KV_SERIALIZE(params)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct error
+ {
+ int64_t code;
+ std::string message;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(code)
+ KV_SERIALIZE(message)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct dummy_error
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ template<typename t_param, typename t_error>
+ struct response
+ {
+ t_param result;
+ t_error error;
+ std::string id;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(result)
+ KV_SERIALIZE(error)
+ KV_SERIALIZE(id)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ typedef response<std::string, error> error_response;
+ }
+}
+
+
+
+
+#define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == uri) \
+ { \
+ boost::uint64_t ticks = epee::misc_utils::get_tick_count(); \
+ epee::serialization::portable_storage ps; \
+ if(!ps.load_from_json(query_info.m_body)) \
+ { \
+ boost::value_initialized<epee::json_rpc::error_response> rsp; \
+ static_cast<epee::json_rpc::error_response&>(rsp).error.code = -32700; \
+ static_cast<epee::json_rpc::error_response&>(rsp).error.message = "Parse error"; \
+ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
+ return true; \
+ } \
+ std::string callback_name; \
+ if(!ps.get_value("method", callback_name, nullptr)) \
+ { \
+ epee::json_rpc::error_response rsp; \
+ rsp.error.code = -32600; \
+ rsp.error.message = "Invalid Request"; \
+ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
+ return true; \
+ } \
+ if(false) return true; //just a stub to have "else if"
+
+#define MAP_JON_RPC_WE(method_name, callback_f, command_type) \
+ else if(callback_name == method_name) \
+{ \
+ handled = true; \
+ boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
+ epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
+ req.load(ps); \
+ boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
+ boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
+ epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
+ resp.id = req.id; \
+ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
+ fail_resp.id = req.id; \
+ if(!callback_f(req.params, resp.result, fail_resp.error)) \
+{ \
+ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
+ return true; \
+} \
+ boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
+ epee::serialization::store_t_to_json(resp, response_info.m_body); \
+ boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
+ response_info.m_mime_tipe = "application/json"; \
+ response_info.m_header_info.m_content_type = " application/json"; \
+ LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
+ return true;\
+}
+
+
+#define MAP_JON_RPC(method_name, callback_f, command_type) \
+ else if(callback_name == method_name) \
+{ \
+ handled = true; \
+ boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
+ epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
+ req.load(ps); \
+ boost::uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
+ boost::value_initialized<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> > resp_; \
+ epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error>& resp = static_cast<epee::json_rpc::response<command_type::response, epee::json_rpc::dummy_error> &>(resp_); \
+ resp.id = req.id; \
+ if(!callback_f(req.params, resp.result)) \
+{ \
+ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
+ fail_resp.id = req.id; \
+ fail_resp.error.code = -32603; \
+ fail_resp.error.message = "Internal error"; \
+ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
+ return true; \
+} \
+ boost::uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
+ epee::serialization::store_t_to_json(resp, response_info.m_body); \
+ boost::uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
+ response_info.m_mime_tipe = "application/json"; \
+ response_info.m_header_info.m_content_type = " application/json"; \
+ LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
+ return true;\
+}
+
+
+#define END_JSON_RPC_MAP() \
+ epee::json_rpc::error_response rsp; \
+ rsp.error.code = -32601; \
+ rsp.error.message = "Method not found"; \
+ epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
+ return true; \
+ }
+
+
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
new file mode 100644
index 000000000..f81b4f601
--- /dev/null
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -0,0 +1,112 @@
+// 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 <boost/thread.hpp>
+#include <boost/bind.hpp>
+
+#include "net/http_server_cp2.h"
+#include "net/http_server_handlers_map2.h"
+
+namespace epee
+{
+
+ template<class t_child_class>
+ class http_server_impl_base: public net_utils::http::i_http_server_handler
+ {
+
+ public:
+ http_server_impl_base()
+ : m_net_server()
+ {}
+
+ explicit http_server_impl_base(boost::asio::io_service& external_io_service)
+ : m_net_server(external_io_service)
+ {}
+
+ bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0")
+ {
+
+ //set self as callback handler
+ m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
+
+ //here set folder for hosting reqests
+ m_net_server.get_config_object().m_folder = "";
+
+ LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
+ bool res = m_net_server.init_server(bind_port, bind_ip);
+ if(!res)
+ {
+ LOG_ERROR("Failed to bind server");
+ return false;
+ }
+ return true;
+ }
+
+ bool run(size_t threads_count, bool wait = true)
+ {
+ //go to loop
+ LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0);
+ if(!m_net_server.run_server(threads_count, wait))
+ {
+ LOG_ERROR("Failed to run net tcp server!");
+ }
+
+ if(wait)
+ LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
+ return true;
+ }
+
+ bool deinit()
+ {
+ return m_net_server.deinit_server();
+ }
+
+ bool timed_wait_server_stop(uint64_t ms)
+ {
+ return m_net_server.timed_wait_server_stop(ms);
+ }
+
+ bool send_stop_signal()
+ {
+ m_net_server.send_stop_signal();
+ return true;
+ }
+
+ int get_binded_port()
+ {
+ return m_net_server.get_binded_port();
+ }
+
+ protected:
+ net_utils::boosted_http_server_custum_handling m_net_server;
+ };
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/http_server_thread_per_connect.h b/contrib/epee/include/net/http_server_thread_per_connect.h
new file mode 100644
index 000000000..bec43b726
--- /dev/null
+++ b/contrib/epee/include/net/http_server_thread_per_connect.h
@@ -0,0 +1,48 @@
+// 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<http::simple_http_connection_handler> mt_http_server_file_system;
+ typedef abstract_tcp_server<http::http_custom_handler> mt_http_server_custum_handling;
+
+}
+}
+
+
+#endif
+
+
diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h
new file mode 100644
index 000000000..503a9e5df
--- /dev/null
+++ b/contrib/epee/include/net/levin_base.h
@@ -0,0 +1,125 @@
+// 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_BASE_H_
+#define _LEVIN_BASE_H_
+
+#include "net_utils_base.h"
+
+#define LEVIN_SIGNATURE 0x0101010101012101LL //Bender's nightmare
+
+namespace epee
+{
+namespace levin
+{
+#pragma pack(push)
+#pragma pack(1)
+ struct bucket_head
+ {
+ boost::uint64_t m_signature;
+ boost::uint64_t m_cb;
+ bool m_have_to_return_data;
+ boost::uint32_t m_command;
+ boost::int32_t m_return_code;
+ boost::uint32_t m_reservedA; //probably some flags in future
+ boost::uint32_t m_reservedB; //probably some check sum in future
+ };
+#pragma pack(pop)
+
+
+#pragma pack(push)
+#pragma pack(1)
+ struct bucket_head2
+ {
+ boost::uint64_t m_signature;
+ boost::uint64_t m_cb;
+ bool m_have_to_return_data;
+ boost::uint32_t m_command;
+ boost::int32_t m_return_code;
+ boost::uint32_t m_flags;
+ boost::uint32_t m_protocol_version;
+ };
+#pragma pack(pop)
+
+
+#define LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED 0
+#define LEVIN_DEFAULT_MAX_PACKET_SIZE 100000000 //100MB by default
+
+#define LEVIN_PACKET_REQUEST 0x00000001
+#define LEVIN_PACKET_RESPONSE 0x00000002
+
+
+#define LEVIN_PROTOCOL_VER_0 0
+#define LEVIN_PROTOCOL_VER_1 1
+
+ template<class t_connection_context = net_utils::connection_context_base>
+ struct levin_commands_handler
+ {
+ virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, t_connection_context& context)=0;
+ virtual int notify(int command, const std::string& in_buff, t_connection_context& context)=0;
+ virtual void callback(t_connection_context& context){};
+
+ virtual void on_connection_new(t_connection_context& context){};
+ virtual void on_connection_close(t_connection_context& context){};
+
+ };
+
+#define LEVIN_OK 0
+#define LEVIN_ERROR_CONNECTION -1
+#define LEVIN_ERROR_CONNECTION_NOT_FOUND -2
+#define LEVIN_ERROR_CONNECTION_DESTROYED -3
+#define LEVIN_ERROR_CONNECTION_TIMEDOUT -4
+#define LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL -5
+#define LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED -6
+#define LEVIN_ERROR_FORMAT -7
+
+#define DESCRIBE_RET_CODE(code) case code: return #code;
+ inline
+ const char* get_err_descr(int err)
+ {
+ switch(err)
+ {
+ DESCRIBE_RET_CODE(LEVIN_OK);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_NOT_FOUND);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_DESTROYED);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_TIMEDOUT);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_NO_DUPLEX_PROTOCOL);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED);
+ DESCRIBE_RET_CODE(LEVIN_ERROR_FORMAT);
+ default:
+ return "unknown code";
+ }
+ }
+
+
+}
+}
+
+
+#endif //_LEVIN_BASE_H_
diff --git a/contrib/epee/include/net/levin_client.h b/contrib/epee/include/net/levin_client.h
new file mode 100644
index 000000000..335f6ba02
--- /dev/null
+++ b/contrib/epee/include/net/levin_client.h
@@ -0,0 +1,89 @@
+// 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_CLIENT_H_
+#define _LEVIN_CLIENT_H_
+
+#include "net_helper.h"
+#include "levin_base.h"
+
+
+#ifndef MAKE_IP
+#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
+#endif
+
+namespace epee
+{
+namespace levin
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class levin_client_impl
+ {
+ public:
+ levin_client_impl();
+ virtual ~levin_client_impl();
+
+ bool connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0");
+ bool connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0");
+ bool is_connected();
+ bool disconnect();
+
+ virtual int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ virtual int notify(int command, const std::string& in_buff);
+
+ protected:
+ net_utils::blocked_mode_client m_transport;
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class levin_client_impl2: public levin_client_impl
+ {
+ public:
+
+ int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ int notify(int command, const std::string& in_buff);
+ };
+
+}
+namespace net_utils
+{
+ typedef levin::levin_client_impl levin_client;
+ typedef levin::levin_client_impl2 levin_client2;
+}
+}
+
+#include "levin_client.inl"
+
+#endif //_LEVIN_CLIENT_H_
diff --git a/contrib/epee/include/net/levin_client.inl b/contrib/epee/include/net/levin_client.inl
new file mode 100644
index 000000000..ae159da6e
--- /dev/null
+++ b/contrib/epee/include/net/levin_client.inl
@@ -0,0 +1,194 @@
+// 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.
+//
+
+
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+#include "string_tools.h"
+namespace epee
+{
+namespace levin
+{
+inline
+bool levin_client_impl::connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip)
+{
+ return m_transport.connect(string_tools::get_ip_string_from_int32(ip), port, timeout, timeout, bind_ip);
+}
+//------------------------------------------------------------------------------
+inline
+ bool levin_client_impl::connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip)
+{
+ return m_transport.connect(addr, port, timeout, timeout, bind_ip);
+}
+//------------------------------------------------------------------------------
+inline
+bool levin_client_impl::is_connected()
+{
+ return m_transport.is_connected();
+}
+//------------------------------------------------------------------------------
+inline
+bool levin_client_impl::disconnect()
+{
+ return m_transport.disconnect();
+}
+//------------------------------------------------------------------------------
+inline
+levin_client_impl::levin_client_impl()
+{
+}
+//------------------------------------------------------------------------------
+inline
+levin_client_impl::~levin_client_impl()
+{
+ disconnect();
+}
+//------------------------------------------------------------------------------
+inline
+int levin_client_impl::invoke(int command, const std::string& in_buff, std::string& buff_out)
+{
+ if(!is_connected())
+ return -1;
+
+ bucket_head head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = true;
+ head.m_command = command;
+ if(!m_transport.send(&head, sizeof(head)))
+ return -1;
+
+ if(!m_transport.send(in_buff))
+ return -1;
+
+ std::string local_buff;
+ if(!m_transport.recv_n(local_buff, sizeof(bucket_head)))
+ return -1;
+
+ head = *(bucket_head*)local_buff.data();
+
+
+ if(head.m_signature!=LEVIN_SIGNATURE)
+ {
+ LOG_PRINT_L0("Signature missmatch in response");
+ return -1;
+ }
+
+ if(!m_transport.recv_n(buff_out, head.m_cb))
+ return -1;
+
+ return head.m_return_code;
+}
+//------------------------------------------------------------------------------
+inline
+int levin_client_impl::notify(int command, const std::string& in_buff)
+{
+ if(!is_connected())
+ return -1;
+
+ bucket_head head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = false;
+ head.m_command = command;
+
+ if(!m_transport.send((const char*)&head, sizeof(head)))
+ return -1;
+
+ if(!m_transport.send(in_buff))
+ return -1;
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+inline
+ int levin_client_impl2::invoke(int command, const std::string& in_buff, std::string& buff_out)
+{
+ if(!is_connected())
+ return -1;
+
+ bucket_head2 head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = true;
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ if(!m_transport.send(&head, sizeof(head)))
+ return -1;
+
+ if(!m_transport.send(in_buff))
+ return -1;
+
+ std::string local_buff;
+ if(!m_transport.recv_n(local_buff, sizeof(bucket_head2)))
+ return -1;
+
+ head = *(bucket_head2*)local_buff.data();
+
+
+ if(head.m_signature!=LEVIN_SIGNATURE)
+ {
+ LOG_PRINT_L0("Signature missmatch in response");
+ return -1;
+ }
+
+ if(!m_transport.recv_n(buff_out, head.m_cb))
+ return -1;
+
+ return head.m_return_code;
+}
+//------------------------------------------------------------------------------
+inline
+ int levin_client_impl2::notify(int command, const std::string& in_buff)
+{
+ if(!is_connected())
+ return -1;
+
+ bucket_head2 head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = false;
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_REQUEST;
+
+ if(!m_transport.send((const char*)&head, sizeof(head)))
+ return -1;
+
+ if(!m_transport.send(in_buff))
+ return -1;
+
+ return 1;
+}
+
+}
+}
+//------------------------------------------------------------------------------ \ No newline at end of file
diff --git a/contrib/epee/include/net/levin_client_async.h b/contrib/epee/include/net/levin_client_async.h
new file mode 100644
index 000000000..b02fa7ee7
--- /dev/null
+++ b/contrib/epee/include/net/levin_client_async.h
@@ -0,0 +1,577 @@
+// 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 "net_helper.h"
+#include "levin_base.h"
+
+
+namespace epee
+{
+namespace levin
+{
+
+ /************************************************************************
+ * levin_client_async - probably it is not really fast implementation,
+ * each handler thread could make up to 30 ms latency.
+ * But, handling events in reader thread will cause dead locks in
+ * case of recursive call (call invoke() to the same connection
+ * on reader thread on remote invoke() handler)
+ ***********************************************************************/
+
+
+ class levin_client_async
+ {
+ levin_commands_handler* m_pcommands_handler;
+ volatile boost::uint32_t m_is_stop;
+ volatile boost::uint32_t m_threads_count;
+ ::critical_section m_send_lock;
+
+ std::string m_local_invoke_buff;
+ ::critical_section m_local_invoke_buff_lock;
+ volatile int m_invoke_res;
+
+ volatile boost::uint32_t m_invoke_data_ready;
+ volatile boost::uint32_t m_invoke_is_active;
+
+ boost::mutex m_invoke_event;
+ boost::condition_variable m_invoke_cond;
+ size_t m_timeout;
+
+ ::critical_section m_recieved_packets_lock;
+ struct packet_entry
+ {
+ bucket_head m_hd;
+ std::string m_body;
+ boost::uint32_t m_connection_index;
+ };
+ std::list<packet_entry> m_recieved_packets;
+ /*
+ m_current_connection_index needed when some connection was broken and reconnected - in this
+ case we could have some received packets in que, which shoud not be handled
+ */
+ volatile boost::uint32_t m_current_connection_index;
+ ::critical_section m_invoke_lock;
+ ::critical_section m_reciev_packet_lock;
+ ::critical_section m_connection_lock;
+ net_utils::blocked_mode_client m_transport;
+ public:
+ levin_client_async():m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
+ {}
+ levin_client_async(const levin_client_async& /*v*/):m_pcommands_handler(NULL), m_is_stop(0), m_threads_count(0), m_invoke_data_ready(0), m_invoke_is_active(0)
+ {}
+ ~levin_client_async()
+ {
+ boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 1);
+ disconnect();
+
+
+ while(boost::interprocess::ipcdetail::atomic_read32(&m_threads_count))
+ ::Sleep(100);
+ }
+
+ void set_handler(levin_commands_handler* phandler)
+ {
+ m_pcommands_handler = phandler;
+ }
+
+ bool connect(boost::uint32_t ip, boost::uint32_t port, boost::uint32_t timeout)
+ {
+ loop_call_guard();
+ critical_region cr(m_connection_lock);
+
+ m_timeout = timeout;
+ bool res = false;
+ CRITICAL_REGION_BEGIN(m_reciev_packet_lock);
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ res = levin_client_impl::connect(ip, port, timeout);
+ boost::interprocess::ipcdetail::atomic_inc32(&m_current_connection_index);
+ CRITICAL_REGION_END();
+ CRITICAL_REGION_END();
+ if(res && !boost::interprocess::ipcdetail::atomic_read32(&m_threads_count) )
+ {
+ //boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 0);//m_is_stop = false;
+ boost::thread( boost::bind(&levin_duplex_client::reciever_thread, this) );
+ boost::thread( boost::bind(&levin_duplex_client::handler_thread, this) );
+ boost::thread( boost::bind(&levin_duplex_client::handler_thread, this) );
+ }
+
+ return res;
+ }
+ bool is_connected()
+ {
+ loop_call_guard();
+ critical_region cr(m_cs);
+ return levin_client_impl::is_connected();
+ }
+
+ inline
+ bool check_connection()
+ {
+ loop_call_guard();
+ critical_region cr(m_cs);
+
+ if(!is_connected())
+ {
+ if( !reconnect() )
+ {
+ LOG_ERROR("Reconnect Failed. Failed to invoke() becouse not connected!");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ //------------------------------------------------------------------------------
+ inline
+ bool recv_n(SOCKET s, char* pbuff, size_t cb)
+ {
+ while(cb)
+ {
+ int res = ::recv(m_socket, pbuff, (int)cb, 0);
+
+ if(SOCKET_ERROR == res)
+ {
+ if(!m_connected)
+ return false;
+
+ int err = ::WSAGetLastError();
+ LOG_ERROR("Failed to recv(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"");
+ disconnect();
+ //reconnect();
+ return false;
+ }else if(res == 0)
+ {
+ disconnect();
+ //reconnect();
+ return false;
+ }
+ LOG_PRINT_L4("[" << m_socket <<"] RECV " << res);
+ cb -= res;
+ pbuff += res;
+ }
+
+ return true;
+ }
+
+ //------------------------------------------------------------------------------
+ inline
+ bool recv_n(SOCKET s, std::string& buff)
+ {
+ size_t cb_remain = buff.size();
+ char* m_current_ptr = (char*)buff.data();
+ return recv_n(s, m_current_ptr, cb_remain);
+ }
+
+ bool disconnect()
+ {
+ //boost::interprocess::ipcdetail::atomic_write32(&m_is_stop, 1);//m_is_stop = true;
+ loop_call_guard();
+ critical_region cr(m_cs);
+ levin_client_impl::disconnect();
+
+ CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock);
+ m_local_invoke_buff.clear();
+ m_invoke_res = LEVIN_ERROR_CONNECTION_DESTROYED;
+ CRITICAL_REGION_END();
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 1); //m_invoke_data_ready = true;
+ m_invoke_cond.notify_all();
+ return true;
+ }
+
+ void loop_call_guard()
+ {
+
+ }
+
+ void on_leave_invoke()
+ {
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_is_active, 0);
+ }
+
+ int invoke(const GUID& target, int command, const std::string& in_buff, std::string& buff_out)
+ {
+
+ critical_region cr_invoke(m_invoke_lock);
+
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_is_active, 1);
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 0);
+ misc_utils::destr_ptr hdlr = misc_utils::add_exit_scope_handler(boost::bind(&levin_duplex_client::on_leave_invoke, this));
+
+ loop_call_guard();
+
+ if(!check_connection())
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+
+ bucket_head head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = true;
+ head.m_id = target;
+#ifdef TRACE_LEVIN_PACKETS_BY_GUIDS
+ ::UuidCreate(&head.m_id);
+#endif
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ LOG_PRINT("[" << m_socket <<"] Sending invoke data", LOG_LEVEL_4);
+
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ LOG_PRINT_L4("[" << m_socket <<"] SEND " << sizeof(head));
+ int res = ::send(m_socket, (const char*)&head, sizeof(head), 0);
+ if(SOCKET_ERROR == res)
+ {
+ int err = ::WSAGetLastError();
+ LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"");
+ disconnect();
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ }
+ LOG_PRINT_L4("[" << m_socket <<"] SEND " << (int)in_buff.size());
+ res = ::send(m_socket, in_buff.data(), (int)in_buff.size(), 0);
+ if(SOCKET_ERROR == res)
+ {
+ int err = ::WSAGetLastError();
+ LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"");
+ disconnect();
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
+
+ //hard coded timeout in 10 minutes for maximum invoke period. if it happens, it could mean only some real troubles.
+ boost::system_time timeout = boost::get_system_time()+ boost::posix_time::milliseconds(100);
+ size_t timeout_count = 0;
+ boost::unique_lock<boost::mutex> lock(m_invoke_event);
+
+ while(!boost::interprocess::ipcdetail::atomic_read32(&m_invoke_data_ready))
+ {
+ if(!m_invoke_cond.timed_wait(lock, timeout))
+ {
+ if(timeout_count < 10)
+ {
+ //workaround to avoid freezing at timed_wait called after notify_all.
+ timeout = boost::get_system_time()+ boost::posix_time::milliseconds(100);
+ ++timeout_count;
+ continue;
+ }else if(timeout_count == 10)
+ {
+ //workaround to avoid freezing at timed_wait called after notify_all.
+ timeout = boost::get_system_time()+ boost::posix_time::minutes(10);
+ ++timeout_count;
+ continue;
+ }else
+ {
+ LOG_PRINT("[" << m_socket <<"] Timeout on waiting invoke result. ", LOG_LEVEL_0);
+ //disconnect();
+ return LEVIN_ERROR_CONNECTION_TIMEDOUT;
+ }
+ }
+ }
+
+
+ CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock);
+ buff_out.swap(m_local_invoke_buff);
+ m_local_invoke_buff.clear();
+ CRITICAL_REGION_END();
+ return m_invoke_res;
+ }
+
+ int notify(const GUID& target, int command, const std::string& in_buff)
+ {
+ if(!check_connection())
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ bucket_head head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = false;
+ head.m_id = target;
+#ifdef TRACE_LEVIN_PACKETS_BY_GUIDS
+ ::UuidCreate(&head.m_id);
+#endif
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ LOG_PRINT_L4("[" << m_socket <<"] SEND " << sizeof(head));
+ int res = ::send(m_socket, (const char*)&head, sizeof(head), 0);
+ if(SOCKET_ERROR == res)
+ {
+ int err = ::WSAGetLastError();
+ LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"");
+ disconnect();
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ }
+ LOG_PRINT_L4("[" << m_socket <<"] SEND " << (int)in_buff.size());
+ res = ::send(m_socket, in_buff.data(), (int)in_buff.size(), 0);
+ if(SOCKET_ERROR == res)
+ {
+ int err = ::WSAGetLastError();
+ LOG_ERROR("Failed to send(), err = " << err << " \"" << socket_errors::get_socket_error_text(err) <<"\"");
+ disconnect();
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
+
+ return 1;
+ }
+
+
+ private:
+ bool have_some_data(SOCKET sock, int interval = 1)
+ {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+
+ fd_set fdse;
+ FD_ZERO(&fdse);
+ FD_SET(sock, &fdse);
+
+
+ timeval tv;
+ tv.tv_sec = interval;
+ tv.tv_usec = 0;
+
+ int sel_res = select(0, &fds, 0, &fdse, &tv);
+ if(0 == sel_res)
+ return false;
+ else if(sel_res == SOCKET_ERROR)
+ {
+ if(m_is_stop)
+ return false;
+ int err_code = ::WSAGetLastError();
+ LOG_ERROR("Filed to call select, err code = " << err_code);
+ disconnect();
+ }else
+ {
+ if(fds.fd_array[0])
+ {//some read operations was performed
+ return true;
+ }else if(fdse.fd_array[0])
+ {//some error was at the socket
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ bool reciev_and_process_incoming_data()
+ {
+ bucket_head head = {0};
+ boost::uint32_t conn_index = 0;
+ bool is_request = false;
+ std::string local_buff;
+ CRITICAL_REGION_BEGIN(m_reciev_packet_lock);//to protect from socket reconnect between head and body
+
+ if(!recv_n(m_socket, (char*)&head, sizeof(head)))
+ {
+ if(m_is_stop)
+ return false;
+ LOG_ERROR("Failed to recv_n");
+ return false;
+ }
+
+ conn_index = boost::interprocess::ipcdetail::atomic_read32(&m_current_connection_index);
+
+ if(head.m_signature!=LEVIN_SIGNATURE)
+ {
+ LOG_ERROR("Signature missmatch in response");
+ return false;
+ }
+
+ is_request = (head.m_protocol_version == LEVIN_PROTOCOL_VER_1 && head.m_flags&LEVIN_PACKET_REQUEST);
+
+
+ local_buff.resize((size_t)head.m_cb);
+ if(!recv_n(m_socket, local_buff))
+ {
+ if(m_is_stop)
+ return false;
+ LOG_ERROR("Filed to reciev");
+ return false;
+ }
+ CRITICAL_REGION_END();
+
+ LOG_PRINT_L4("LEVIN_PACKET_RECIEVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
+
+ if(is_request)
+ {
+ CRITICAL_REGION_BEGIN(m_recieved_packets_lock);
+ m_recieved_packets.resize(m_recieved_packets.size() + 1);
+ m_recieved_packets.back().m_hd = head;
+ m_recieved_packets.back().m_body.swap(local_buff);
+ m_recieved_packets.back().m_connection_index = conn_index;
+ CRITICAL_REGION_END();
+ /*
+
+ */
+ }else
+ {//this is some response
+
+ CRITICAL_REGION_BEGIN(m_local_invoke_buff_lock);
+ m_local_invoke_buff.swap(local_buff);
+ m_invoke_res = head.m_return_code;
+ CRITICAL_REGION_END();
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_data_ready, 1); //m_invoke_data_ready = true;
+ m_invoke_cond.notify_all();
+
+ }
+ return true;
+ }
+
+ bool reciever_thread()
+ {
+ LOG_PRINT_L3("[" << m_socket <<"] Socket reciever thread started.[m_threads_count=" << m_threads_count << "]");
+ log_space::log_singletone::set_thread_log_prefix("RECIEVER_WORKER");
+ boost::interprocess::ipcdetail::atomic_inc32(&m_threads_count);
+
+ while(!m_is_stop)
+ {
+ if(!m_connected)
+ {
+ Sleep(100);
+ continue;
+ }
+
+ if(have_some_data(m_socket, 1))
+ {
+ if(!reciev_and_process_incoming_data())
+ {
+ if(m_is_stop)
+ {
+ break;//boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count);
+ //return true;
+ }
+ LOG_ERROR("Failed to reciev_and_process_incoming_data. shutting down");
+ //boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count);
+ //disconnect_no_wait();
+ //break;
+ }
+ }
+ }
+
+ boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count);
+ LOG_PRINT_L3("[" << m_socket <<"] Socket reciever thread stopped.[m_threads_count=" << m_threads_count << "]");
+ return true;
+ }
+
+ bool process_recieved_packet(bucket_head& head, const std::string& local_buff, boost::uint32_t conn_index)
+ {
+
+ net_utils::connection_context_base conn_context;
+ conn_context.m_remote_ip = m_ip;
+ conn_context.m_remote_port = m_port;
+ if(head.m_have_to_return_data)
+ {
+ std::string return_buff;
+ if(m_pcommands_handler)
+ head.m_return_code = m_pcommands_handler->invoke(head.m_id, head.m_command, local_buff, return_buff, conn_context);
+ else
+ head.m_return_code = LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED;
+
+
+
+ head.m_cb = return_buff.size();
+ head.m_have_to_return_data = false;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_RESPONSE;
+
+ std::string send_buff((const char*)&head, sizeof(head));
+ send_buff += return_buff;
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ if(conn_index != boost::interprocess::ipcdetail::atomic_read32(&m_current_connection_index))
+ {//there was reconnect, send response back is not allowed
+ return true;
+ }
+ int res = ::send(m_socket, (const char*)send_buff.data(), send_buff.size(), 0);
+ if(res == SOCKET_ERROR)
+ {
+ int err_code = ::WSAGetLastError();
+ LOG_ERROR("Failed to send, err = " << err_code);
+ return false;
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_L4("LEVIN_PACKET_SENT. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
+
+ }
+ else
+ {
+ if(m_pcommands_handler)
+ m_pcommands_handler->notify(head.m_id, head.m_command, local_buff, conn_context);
+ }
+
+ return true;
+ }
+
+ bool handler_thread()
+ {
+ LOG_PRINT_L3("[" << m_socket <<"] Socket handler thread started.[m_threads_count=" << m_threads_count << "]");
+ log_space::log_singletone::set_thread_log_prefix("HANDLER_WORKER");
+ boost::interprocess::ipcdetail::atomic_inc32(&m_threads_count);
+
+ while(!m_is_stop)
+ {
+ bool have_some_work = false;
+ std::string local_buff;
+ bucket_head bh = {0};
+ boost::uint32_t conn_index = 0;
+
+ CRITICAL_REGION_BEGIN(m_recieved_packets_lock);
+ if(m_recieved_packets.size())
+ {
+ bh = m_recieved_packets.begin()->m_hd;
+ conn_index = m_recieved_packets.begin()->m_connection_index;
+ local_buff.swap(m_recieved_packets.begin()->m_body);
+ have_some_work = true;
+ m_recieved_packets.pop_front();
+ }
+ CRITICAL_REGION_END();
+
+ if(have_some_work)
+ {
+ process_recieved_packet(bh, local_buff, conn_index);
+ }else
+ {
+ //Idle when no work
+ Sleep(30);
+ }
+ }
+
+ boost::interprocess::ipcdetail::atomic_dec32(&m_threads_count);
+ LOG_PRINT_L3("[" << m_socket <<"] Socket handler thread stopped.[m_threads_count=" << m_threads_count << "]");
+ return true;
+ }
+ };
+
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/levin_client_async.inl b/contrib/epee/include/net/levin_client_async.inl
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/contrib/epee/include/net/levin_client_async.inl
diff --git a/contrib/epee/include/net/levin_helper.h b/contrib/epee/include/net/levin_helper.h
new file mode 100644
index 000000000..a8406103c
--- /dev/null
+++ b/contrib/epee/include/net/levin_helper.h
@@ -0,0 +1,137 @@
+// 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"
+
+namespace epee
+{
+namespace levin
+{
+ template<class t_struct>
+ 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_struct, StorageNamed::DefaultStorageType>(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 missmatch, 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<class t_struct>
+ 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 missmatch, 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_struct, StorageNamed::DefaultStorageType>(t, buff_strg))
+ {
+ LOG_ERROR("Failed to read storage, at load_struct_from_levin_message");
+ return false;
+ }
+ command = head.m_command;
+ return true;
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/levin_protocol_handler.h b/contrib/epee/include/net/levin_protocol_handler.h
new file mode 100644
index 000000000..adc6e95d5
--- /dev/null
+++ b/contrib/epee/include/net/levin_protocol_handler.h
@@ -0,0 +1,178 @@
+// 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_PROTOCOL_HANDLER_H_
+#define _LEVIN_PROTOCOL_HANDLER_H_
+
+#include <boost/uuid/uuid_generators.hpp>
+#include "levin_base.h"
+
+namespace epee
+{
+namespace levin
+{
+ template<class t_connection_context = net_utils::connection_context_base>
+ struct protocl_handler_config
+ {
+ levin_commands_handler<t_connection_context>* m_pcommands_handler;
+ };
+
+ template<class t_connection_context = net_utils::connection_context_base>
+ class protocol_handler
+ {
+ public:
+ typedef t_connection_context connection_context;
+ typedef protocl_handler_config<t_connection_context> config_type;
+
+ protocol_handler(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
+ virtual ~protocol_handler(){}
+
+ virtual bool handle_recv(const void* ptr, size_t cb);
+
+ bool after_init_connection(){return true;}
+ private:
+ enum connection_data_state
+ {
+ conn_state_reading_head,
+ conn_state_reading_body
+ };
+
+
+ config_type& m_config;
+ t_connection_context& m_conn_context;
+ net_utils::i_service_endpoint* m_psnd_hndlr;
+ std::string m_cach_in_buffer;
+ connection_data_state m_state;
+ bucket_head m_current_head;
+ };
+
+ template<class t_connection_context>
+ protocol_handler<t_connection_context>::protocol_handler(net_utils::i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context):
+ m_config(config),
+ m_conn_context(conn_context),
+ m_psnd_hndlr(psnd_hndlr),
+ m_state(conn_state_reading_head),
+ m_current_head(bucket_head())
+ {}
+
+ template<class t_connection_context>
+ bool protocol_handler<t_connection_context>::handle_recv(const void* ptr, size_t cb)
+ {
+ if(!m_config.m_pcommands_handler)
+ {
+ LOG_ERROR("Command handler not set!");
+ return false;
+ }
+ m_cach_in_buffer.append((const char*)ptr, cb);
+
+ bool is_continue = true;
+ while(is_continue)
+ {
+ switch(m_state)
+ {
+ case conn_state_reading_head:
+ if(m_cach_in_buffer.size() < sizeof(bucket_head))
+ {
+ if(m_cach_in_buffer.size() >= sizeof(boost::uint64_t) && *((boost::uint64_t*)m_cach_in_buffer.data()) != LEVIN_SIGNATURE)
+ {
+ LOG_ERROR("Signature missmatch on accepted connection");
+ return false;
+ }
+ is_continue = false;
+ break;
+ }
+ {
+ bucket_head* phead = (bucket_head*)m_cach_in_buffer.data();
+ if(LEVIN_SIGNATURE != phead->m_signature)
+ {
+ LOG_ERROR("Signature missmatch on accepted connection");
+ return false;
+ }
+ m_current_head = *phead;
+ }
+ m_cach_in_buffer.erase(0, sizeof(bucket_head));
+ m_state = conn_state_reading_body;
+ break;
+ case conn_state_reading_body:
+ if(m_cach_in_buffer.size() < m_current_head.m_cb)
+ {
+ is_continue = false;
+ break;
+ }
+ {
+ std::string buff_to_invoke;
+ if(m_cach_in_buffer.size() == m_current_head.m_cb)
+ buff_to_invoke.swap(m_cach_in_buffer);
+ else
+ {
+ buff_to_invoke.assign(m_cach_in_buffer, 0, (std::string::size_type)m_current_head.m_cb);
+ m_cach_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb);
+ }
+
+
+ if(m_current_head.m_have_to_return_data)
+ {
+ std::string return_buff;
+ m_current_head.m_return_code = m_config.m_pcommands_handler->invoke(m_current_head.m_command, buff_to_invoke, return_buff, m_conn_context);
+ m_current_head.m_cb = return_buff.size();
+ m_current_head.m_have_to_return_data = false;
+ std::string send_buff((const char*)&m_current_head, sizeof(m_current_head));
+ send_buff += return_buff;
+
+ if(!m_psnd_hndlr->do_send(send_buff.data(), send_buff.size()))
+ return false;
+
+ }
+ else
+ m_config.m_pcommands_handler->notify(m_current_head.m_command, buff_to_invoke, m_conn_context);
+ }
+ m_state = conn_state_reading_head;
+ break;
+ default:
+ LOG_ERROR("Undefined state in levin_server_impl::connection_handler, m_state=" << m_state);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+
+
+
+
+
+}
+}
+
+
+
+
+#endif //_LEVIN_PROTOCOL_HANDLER_H_
+
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
new file mode 100644
index 000000000..dc4f41146
--- /dev/null
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -0,0 +1,778 @@
+// 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 <boost/uuid/uuid_generators.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <atomic>
+
+#include "levin_base.h"
+#include "misc_language.h"
+
+
+namespace epee
+{
+namespace levin
+{
+
+/************************************************************************/
+/* */
+/************************************************************************/
+template<class t_connection_context>
+class async_protocol_handler;
+
+template<class t_connection_context>
+class async_protocol_handler_config
+{
+ typedef std::map<boost::uuids::uuid, async_protocol_handler<t_connection_context>* > connections_map;
+ critical_section m_connects_lock;
+ connections_map m_connects;
+
+ void add_connection(async_protocol_handler<t_connection_context>* pc);
+ void del_connection(async_protocol_handler<t_connection_context>* pc);
+
+ async_protocol_handler<t_connection_context>* find_connection(boost::uuids::uuid connection_id) const;
+ int find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler<t_connection_context>*& aph);
+
+ friend class async_protocol_handler<t_connection_context>;
+
+public:
+ typedef t_connection_context connection_context;
+ levin_commands_handler<t_connection_context>* m_pcommands_handler;
+ boost::uint64_t m_max_packet_size;
+ boost::uint64_t m_invoke_timeout;
+
+ int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
+ template<class callback_t>
+ int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
+
+ int notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id);
+ bool close(boost::uuids::uuid connection_id);
+ bool update_connection_context(const t_connection_context& contxt);
+ bool request_callback(boost::uuids::uuid connection_id);
+ template<class callback_t>
+ bool foreach_connection(callback_t cb);
+ size_t get_connections_count();
+
+ async_protocol_handler_config():m_pcommands_handler(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE)
+ {}
+};
+
+
+/************************************************************************/
+/* */
+/************************************************************************/
+template<class t_connection_context = net_utils::connection_context_base>
+class async_protocol_handler
+{
+public:
+ typedef t_connection_context connection_context;
+ typedef async_protocol_handler_config<t_connection_context> config_type;
+
+ enum stream_state
+ {
+ stream_state_head,
+ stream_state_body
+ };
+
+ std::atomic<bool> m_deletion_initiated;
+ std::atomic<bool> m_protocol_released;
+ volatile uint32_t m_invoke_buf_ready;
+
+ volatile int m_invoke_result_code;
+
+ critical_section m_local_inv_buff_lock;
+ std::string m_local_inv_buff;
+
+ critical_section m_send_lock;
+ critical_section m_call_lock;
+
+ volatile uint32_t m_wait_count;
+ volatile uint32_t m_close_called;
+ bucket_head2 m_current_head;
+ net_utils::i_service_endpoint* m_pservice_endpoint;
+ config_type& m_config;
+ t_connection_context& m_connection_context;
+
+ std::string m_cache_in_buffer;
+ stream_state m_state;
+
+ boost::int32_t m_oponent_protocol_ver;
+ bool m_connection_initialized;
+
+ struct invoke_response_handler_base
+ {
+ virtual bool handle(int res, const std::string& buff, connection_context& context)=0;
+ virtual bool is_timer_started() const=0;
+ virtual void cancel()=0;
+ virtual bool cancel_timer()=0;
+ };
+ template <class callback_t>
+ struct anvoke_handler: invoke_response_handler_base
+ {
+ anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
+ :m_cb(cb), 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())
+ {
+ m_timer.expires_from_now(boost::posix_time::milliseconds(timeout));
+ m_timer.async_wait([&con, command, cb](const boost::system::error_code& ec)
+ {
+ if(ec == boost::asio::error::operation_aborted)
+ return;
+ LOG_PRINT_CC(con.get_context_ref(), "Timeout on invoke operation happened, command: " << command, LOG_LEVEL_2);
+ std::string fake;
+ cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
+ con.close();
+ con.finish_outer_call();
+ });
+ m_timer_started = true;
+ }
+ }
+ virtual ~anvoke_handler()
+ {}
+ callback_t m_cb;
+ async_protocol_handler& m_con;
+ boost::asio::deadline_timer m_timer;
+ bool m_timer_started;
+ bool m_cancel_timer_called;
+ bool m_timer_cancelled;
+ int m_command;
+ virtual bool handle(int res, const std::string& buff, typename async_protocol_handler::connection_context& context)
+ {
+ if(!cancel_timer())
+ return false;
+ m_cb(res, buff, context);
+ m_con.finish_outer_call();
+ return true;
+ }
+ virtual bool is_timer_started() const
+ {
+ return m_timer_started;
+ }
+ virtual void cancel()
+ {
+ if(cancel_timer())
+ {
+ std::string fake;
+ m_cb(LEVIN_ERROR_CONNECTION_DESTROYED, fake, m_con.get_context_ref());
+ m_con.finish_outer_call();
+ }
+ }
+ virtual bool cancel_timer()
+ {
+ if(!m_cancel_timer_called)
+ {
+ m_cancel_timer_called = true;
+ boost::system::error_code ignored_ec;
+ m_timer_cancelled = 1 == m_timer.cancel(ignored_ec);
+ }
+ return m_timer_cancelled;
+ }
+ };
+ critical_section m_invoke_response_handlers_lock;
+ std::list<boost::shared_ptr<invoke_response_handler_base> > m_invoke_response_handlers;
+
+ template<class callback_t>
+ 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<invoke_response_handler_base> handler(boost::make_shared<anvoke_handler<callback_t>>(cb, timeout, con, command));
+ m_invoke_response_handlers.push_back(handler);
+ return handler->is_timer_started();
+ }
+ template<class callback_t> friend struct anvoke_handler;
+public:
+ async_protocol_handler(net_utils::i_service_endpoint* psnd_hndlr,
+ config_type& config,
+ t_connection_context& conn_context):
+ m_current_head(bucket_head2()),
+ m_pservice_endpoint(psnd_hndlr),
+ m_config(config),
+ m_connection_context(conn_context),
+ m_state(stream_state_head)
+ {
+ m_close_called = 0;
+ m_deletion_initiated = false;
+ m_protocol_released = false;
+ m_wait_count = 0;
+ m_oponent_protocol_ver = 0;
+ m_connection_initialized = false;
+ }
+ virtual ~async_protocol_handler()
+ {
+ m_deletion_initiated = true;
+ if(m_connection_initialized)
+ {
+ m_config.del_connection(this);
+ }
+
+ for (size_t i = 0; i < 60 * 1000 / 100 && 0 != boost::interprocess::ipcdetail::atomic_read32(&m_wait_count); ++i)
+ {
+ misc_utils::sleep_no_w(100);
+ }
+ CHECK_AND_ASSERT_MES_NO_RET(0 == boost::interprocess::ipcdetail::atomic_read32(&m_wait_count), "Failed to wait for operation completion. m_wait_count = " << m_wait_count);
+
+ LOG_PRINT_CC(m_connection_context, "~async_protocol_handler()", LOG_LEVEL_4);
+ }
+
+ bool start_outer_call()
+ {
+ LOG_PRINT_CC_L4(m_connection_context, "[levin_protocol] -->> start_outer_call");
+ if(!m_pservice_endpoint->add_ref())
+ {
+ LOG_PRINT_CC_RED(m_connection_context, "[levin_protocol] -->> start_outer_call failed", LOG_LEVEL_4);
+ return false;
+ }
+ boost::interprocess::ipcdetail::atomic_inc32(&m_wait_count);
+ return true;
+ }
+ bool finish_outer_call()
+ {
+ LOG_PRINT_CC_L4(m_connection_context, "[levin_protocol] <<-- finish_outer_call");
+ boost::interprocess::ipcdetail::atomic_dec32(&m_wait_count);
+ m_pservice_endpoint->release();
+ return true;
+ }
+
+ bool release_protocol()
+ {
+ decltype(m_invoke_response_handlers) local_invoke_response_handlers;
+ CRITICAL_REGION_BEGIN(m_invoke_response_handlers_lock);
+ local_invoke_response_handlers.swap(m_invoke_response_handlers);
+ m_protocol_released = true;
+ CRITICAL_REGION_END();
+
+ // Never call callback inside critical section, that can cause deadlock. Callback can be called when
+ // invoke_response_handler_base is cancelled
+ std::for_each(local_invoke_response_handlers.begin(), local_invoke_response_handlers.end(), [](const boost::shared_ptr<invoke_response_handler_base>& pinv_resp_hndlr) {
+ pinv_resp_hndlr->cancel();
+ });
+
+ return true;
+ }
+
+ bool close()
+ {
+ boost::interprocess::ipcdetail::atomic_inc32(&m_close_called);
+
+ m_pservice_endpoint->close();
+ return true;
+ }
+
+ void update_connection_context(const connection_context& contxt)
+ {
+ m_connection_context = contxt;
+ }
+
+ void request_callback()
+ {
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
+ boost::bind(&async_protocol_handler::finish_outer_call, this));
+
+ m_pservice_endpoint->request_callback();
+ }
+
+ void handle_qued_callback()
+ {
+ m_config.m_pcommands_handler->callback(m_connection_context);
+ }
+
+ virtual bool handle_recv(const void* ptr, size_t cb)
+ {
+ if(boost::interprocess::ipcdetail::atomic_read32(&m_close_called))
+ return false; //closing connections
+
+ if(!m_config.m_pcommands_handler)
+ {
+ LOG_ERROR_CC(m_connection_context, "Commands handler not set!");
+ return false;
+ }
+
+ if(m_cache_in_buffer.size() + cb > m_config.m_max_packet_size)
+ {
+ LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
+ << ", packet received " << m_cache_in_buffer.size() + cb
+ << ", connection will be closed.");
+ return false;
+ }
+
+ m_cache_in_buffer.append((const char*)ptr, cb);
+
+ bool is_continue = true;
+ while(is_continue)
+ {
+ switch(m_state)
+ {
+ case stream_state_body:
+ if(m_cache_in_buffer.size() < m_current_head.m_cb)
+ {
+ is_continue = false;
+ break;
+ }
+ {
+ std::string buff_to_invoke;
+ if(m_cache_in_buffer.size() == m_current_head.m_cb)
+ buff_to_invoke.swap(m_cache_in_buffer);
+ else
+ {
+ buff_to_invoke.assign(m_cache_in_buffer, 0, (std::string::size_type)m_current_head.m_cb);
+ m_cache_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb);
+ }
+
+ bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
+
+ LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_RECIEVED. [len=" << m_current_head.m_cb
+ << ", flags" << m_current_head.m_flags
+ << ", r?=" << m_current_head.m_have_to_return_data
+ <<", cmd = " << m_current_head.m_command
+ << ", v=" << m_current_head.m_protocol_version);
+
+ if(is_response)
+ {//response to some invoke
+
+ epee::critical_region_t<decltype(m_invoke_response_handlers_lock)> invoke_response_handlers_guard(m_invoke_response_handlers_lock);
+ if(!m_invoke_response_handlers.empty())
+ {//async call scenario
+ boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
+ bool timer_cancelled = response_handler->cancel_timer();
+ // Don't pop handler, to avoid destroying it
+ if(timer_cancelled)
+ m_invoke_response_handlers.pop_front();
+ invoke_response_handlers_guard.unlock();
+
+ if(timer_cancelled)
+ response_handler->handle(m_current_head.m_command, buff_to_invoke, m_connection_context);
+ }
+ else
+ {
+ invoke_response_handlers_guard.unlock();
+ //use sync call scenario
+ if(!boost::interprocess::ipcdetail::atomic_read32(&m_wait_count) && !boost::interprocess::ipcdetail::atomic_read32(&m_close_called))
+ {
+ LOG_ERROR_CC(m_connection_context, "no active invoke when response came, wtf?");
+ return false;
+ }else
+ {
+ CRITICAL_REGION_BEGIN(m_local_inv_buff_lock);
+ buff_to_invoke.swap(m_local_inv_buff);
+ buff_to_invoke.clear();
+ m_invoke_result_code = m_current_head.m_return_code;
+ CRITICAL_REGION_END();
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 1);
+ }
+ }
+ }else
+ {
+ if(m_current_head.m_have_to_return_data)
+ {
+ std::string return_buff;
+ m_current_head.m_return_code = m_config.m_pcommands_handler->invoke(
+ m_current_head.m_command,
+ buff_to_invoke,
+ return_buff,
+ m_connection_context);
+ m_current_head.m_cb = return_buff.size();
+ m_current_head.m_have_to_return_data = false;
+ m_current_head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ m_current_head.m_flags = LEVIN_PACKET_RESPONSE;
+ std::string send_buff((const char*)&m_current_head, sizeof(m_current_head));
+ send_buff += return_buff;
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ if(!m_pservice_endpoint->do_send(send_buff.data(), send_buff.size()))
+ return false;
+ CRITICAL_REGION_END();
+ LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << m_current_head.m_cb
+ << ", flags" << m_current_head.m_flags
+ << ", r?=" << m_current_head.m_have_to_return_data
+ <<", cmd = " << m_current_head.m_command
+ << ", ver=" << m_current_head.m_protocol_version);
+ }
+ else
+ m_config.m_pcommands_handler->notify(m_current_head.m_command, buff_to_invoke, m_connection_context);
+ }
+ }
+ m_state = stream_state_head;
+ break;
+ case stream_state_head:
+ {
+ if(m_cache_in_buffer.size() < sizeof(bucket_head2))
+ {
+ if(m_cache_in_buffer.size() >= sizeof(boost::uint64_t) && *((boost::uint64_t*)m_cache_in_buffer.data()) != LEVIN_SIGNATURE)
+ {
+ LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
+ return false;
+ }
+ is_continue = false;
+ break;
+ }
+
+ bucket_head2* phead = (bucket_head2*)m_cache_in_buffer.data();
+ if(LEVIN_SIGNATURE != phead->m_signature)
+ {
+ LOG_ERROR_CC(m_connection_context, "Signature mismatch, connection will be closed");
+ return false;
+ }
+ m_current_head = *phead;
+
+ m_cache_in_buffer.erase(0, sizeof(bucket_head2));
+ m_state = stream_state_body;
+ m_oponent_protocol_ver = m_current_head.m_protocol_version;
+ if(m_current_head.m_cb > m_config.m_max_packet_size)
+ {
+ LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
+ << ", packet header received " << m_current_head.m_cb
+ << ", connection will be closed.");
+ return false;
+ }
+ }
+ break;
+ default:
+ LOG_ERROR_CC(m_connection_context, "Undefined state in levin_server_impl::connection_handler, m_state=" << m_state);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool after_init_connection()
+ {
+ if (!m_connection_initialized)
+ {
+ m_connection_initialized = true;
+ m_config.add_connection(this);
+ }
+ return true;
+ }
+
+ template<class callback_t>
+ bool async_invoke(int command, const std::string& in_buff, callback_t cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ {
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
+ boost::bind(&async_protocol_handler::finish_outer_call, this));
+
+ if(timeout == LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ timeout = m_config.m_invoke_timeout;
+
+ int err_code = LEVIN_OK;
+ do
+ {
+ if(m_deletion_initiated)
+ {
+ err_code = LEVIN_ERROR_CONNECTION_DESTROYED;
+ break;
+ }
+
+ CRITICAL_REGION_LOCAL(m_call_lock);
+
+ if(m_deletion_initiated)
+ {
+ err_code = LEVIN_ERROR_CONNECTION_DESTROYED;
+ break;
+ }
+
+ bucket_head2 head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = true;
+
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0);
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ CRITICAL_REGION_LOCAL1(m_invoke_response_handlers_lock);
+ if(!m_pservice_endpoint->do_send(&head, sizeof(head)))
+ {
+ LOG_ERROR_CC(m_connection_context, "Failed to do_send");
+ err_code = LEVIN_ERROR_CONNECTION;
+ break;
+ }
+
+ if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ {
+ LOG_ERROR_CC(m_connection_context, "Failed to do_send");
+ err_code = LEVIN_ERROR_CONNECTION;
+ break;
+ }
+
+ if(!add_invoke_response_handler(cb, timeout, *this, command))
+ {
+ err_code = LEVIN_ERROR_CONNECTION_DESTROYED;
+ break;
+ }
+ CRITICAL_REGION_END();
+ } while (false);
+
+ if (LEVIN_OK != err_code)
+ {
+ std::string stub_buff;
+ // Never call callback inside critical section, that can cause deadlock
+ cb(err_code, stub_buff, m_connection_context);
+ return false;
+ }
+
+ return true;
+ }
+
+ int invoke(int command, const std::string& in_buff, std::string& buff_out)
+ {
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
+ boost::bind(&async_protocol_handler::finish_outer_call, this));
+
+ if(m_deletion_initiated)
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ CRITICAL_REGION_LOCAL(m_call_lock);
+
+ if(m_deletion_initiated)
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ bucket_head2 head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_cb = in_buff.size();
+ head.m_have_to_return_data = true;
+
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+
+ boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0);
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ if(!m_pservice_endpoint->do_send(&head, sizeof(head)))
+ {
+ LOG_ERROR_CC(m_connection_context, "Failed to do_send");
+ return LEVIN_ERROR_CONNECTION;
+ }
+
+ if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ {
+ LOG_ERROR_CC(m_connection_context, "Failed to do_send");
+ return LEVIN_ERROR_CONNECTION;
+ }
+ CRITICAL_REGION_END();
+
+ LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << head.m_cb
+ << ", f=" << head.m_flags
+ << ", r?=" << head.m_have_to_return_data
+ << ", cmd = " << head.m_command
+ << ", ver=" << head.m_protocol_version);
+
+ uint64_t ticks_start = misc_utils::get_tick_count();
+
+ while(!boost::interprocess::ipcdetail::atomic_read32(&m_invoke_buf_ready) && !m_deletion_initiated && !m_protocol_released)
+ {
+ if(misc_utils::get_tick_count() - ticks_start > m_config.m_invoke_timeout)
+ {
+ LOG_PRINT_CC_L2(m_connection_context, "invoke timeout (" << m_config.m_invoke_timeout << "), closing connection ");
+ close();
+ return LEVIN_ERROR_CONNECTION_TIMEDOUT;
+ }
+ if(!m_pservice_endpoint->call_run_once_service_io())
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ }
+
+ if(m_deletion_initiated || m_protocol_released)
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ CRITICAL_REGION_BEGIN(m_local_inv_buff_lock);
+ buff_out.swap(m_local_inv_buff);
+ m_local_inv_buff.clear();
+ CRITICAL_REGION_END();
+
+ return m_invoke_result_code;
+ }
+
+ int notify(int command, const std::string& in_buff)
+ {
+ misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
+ boost::bind(&async_protocol_handler::finish_outer_call, this));
+
+ if(m_deletion_initiated)
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ CRITICAL_REGION_LOCAL(m_call_lock);
+
+ if(m_deletion_initiated)
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+
+ bucket_head2 head = {0};
+ head.m_signature = LEVIN_SIGNATURE;
+ head.m_have_to_return_data = false;
+ head.m_cb = in_buff.size();
+
+ head.m_command = command;
+ head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ head.m_flags = LEVIN_PACKET_REQUEST;
+ CRITICAL_REGION_BEGIN(m_send_lock);
+ if(!m_pservice_endpoint->do_send(&head, sizeof(head)))
+ {
+ LOG_ERROR_CC(m_connection_context, "Failed to do_send()");
+ return -1;
+ }
+
+ if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ {
+ LOG_ERROR("Failed to do_send()");
+ return -1;
+ }
+ CRITICAL_REGION_END();
+ LOG_PRINT_CC_L4(m_connection_context, "LEVIN_PACKET_SENT. [len=" << head.m_cb <<
+ ", f=" << head.m_flags <<
+ ", r?=" << head.m_have_to_return_data <<
+ ", cmd = " << head.m_command <<
+ ", ver=" << head.m_protocol_version);
+
+ return 1;
+ }
+ //------------------------------------------------------------------------------------------
+ boost::uuids::uuid get_connection_id() {return m_connection_context.m_connection_id;}
+ //------------------------------------------------------------------------------------------
+ t_connection_context& get_context_ref() {return m_connection_context;}
+};
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+void async_protocol_handler_config<t_connection_context>::del_connection(async_protocol_handler<t_connection_context>* pconn)
+{
+ CRITICAL_REGION_BEGIN(m_connects_lock);
+ m_connects.erase(pconn->get_connection_id());
+ CRITICAL_REGION_END();
+ m_pcommands_handler->on_connection_close(pconn->m_connection_context);
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+void async_protocol_handler_config<t_connection_context>::add_connection(async_protocol_handler<t_connection_context>* pconn)
+{
+ CRITICAL_REGION_BEGIN(m_connects_lock);
+ m_connects[pconn->get_connection_id()] = pconn;
+ CRITICAL_REGION_END();
+ m_pcommands_handler->on_connection_new(pconn->m_connection_context);
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+async_protocol_handler<t_connection_context>* async_protocol_handler_config<t_connection_context>::find_connection(boost::uuids::uuid connection_id) const
+{
+ auto it = m_connects.find(connection_id);
+ return it == m_connects.end() ? 0 : it->second;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+int async_protocol_handler_config<t_connection_context>::find_and_lock_connection(boost::uuids::uuid connection_id, async_protocol_handler<t_connection_context>*& aph)
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ aph = find_connection(connection_id);
+ if(0 == aph)
+ return LEVIN_ERROR_CONNECTION_NOT_FOUND;
+ if(!aph->start_outer_call())
+ return LEVIN_ERROR_CONNECTION_DESTROYED;
+ return LEVIN_OK;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+int async_protocol_handler_config<t_connection_context>::invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id)
+{
+ async_protocol_handler<t_connection_context>* aph;
+ int r = find_and_lock_connection(connection_id, aph);
+ return LEVIN_OK == r ? aph->invoke(command, in_buff, buff_out) : r;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context> template<class callback_t>
+int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, callback_t cb, size_t timeout)
+{
+ async_protocol_handler<t_connection_context>* aph;
+ int r = find_and_lock_connection(connection_id, aph);
+ return LEVIN_OK == r ? aph->async_invoke(command, in_buff, cb, timeout) : r;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context> template<class callback_t>
+bool async_protocol_handler_config<t_connection_context>::foreach_connection(callback_t cb)
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ for(auto& c: m_connects)
+ {
+ async_protocol_handler<t_connection_context>* aph = c.second;
+ if(!cb(aph->get_context_ref()))
+ return false;
+ }
+ return true;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+size_t async_protocol_handler_config<t_connection_context>::get_connections_count()
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ return m_connects.size();
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+int async_protocol_handler_config<t_connection_context>::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id)
+{
+ async_protocol_handler<t_connection_context>* aph;
+ int r = find_and_lock_connection(connection_id, aph);
+ return LEVIN_OK == r ? aph->notify(command, in_buff) : r;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+bool async_protocol_handler_config<t_connection_context>::close(boost::uuids::uuid connection_id)
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
+ return 0 != aph ? aph->close() : false;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+bool async_protocol_handler_config<t_connection_context>::update_connection_context(const t_connection_context& contxt)
+{
+ CRITICAL_REGION_LOCAL(m_connects_lock);
+ async_protocol_handler<t_connection_context>* aph = find_connection(contxt.m_connection_id);
+ if(0 == aph)
+ return false;
+ aph->update_connection_context(contxt);
+ return true;
+}
+//------------------------------------------------------------------------------------------
+template<class t_connection_context>
+bool async_protocol_handler_config<t_connection_context>::request_callback(boost::uuids::uuid connection_id)
+{
+ async_protocol_handler<t_connection_context>* aph;
+ int r = find_and_lock_connection(connection_id, aph);
+ if(LEVIN_OK == r)
+ {
+ aph->request_callback();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+}
+}
diff --git a/contrib/epee/include/net/levin_server_cp.h b/contrib/epee/include/net/levin_server_cp.h
new file mode 100644
index 000000000..8ece35059
--- /dev/null
+++ b/contrib/epee/include/net/levin_server_cp.h
@@ -0,0 +1,47 @@
+// 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<levin::protocol_handler> cp_levin_server;
+}
+}
+
+
+
+#endif
+
+
diff --git a/contrib/epee/include/net/levin_server_cp2.h b/contrib/epee/include/net/levin_server_cp2.h
new file mode 100644
index 000000000..b29d49bf8
--- /dev/null
+++ b/contrib/epee/include/net/levin_server_cp2.h
@@ -0,0 +1,49 @@
+// 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_server2.h"
+#include "levin_protocol_handler.h"
+#include "levin_protocol_handler_async.h"
+
+namespace epee
+{
+namespace net_utils
+{
+ typedef boosted_tcp_server<levin::protocol_handler<> > boosted_levin_server;
+ typedef boosted_tcp_server<levin::async_protocol_handler<> > boosted_levin_async_server;
+}
+}
+
+
+
+#endif
+
+
diff --git a/contrib/epee/include/net/local_ip.h b/contrib/epee/include/net/local_ip.h
new file mode 100644
index 000000000..028ad73ef
--- /dev/null
+++ b/contrib/epee/include/net/local_ip.h
@@ -0,0 +1,72 @@
+// 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
+
+namespace epee
+{
+ namespace net_utils
+ {
+ inline
+ bool is_ip_local(boost::uint32_t ip)
+ {
+ /*
+ local ip area
+ 10.0.0.0 — 10.255.255.255
+ 172.16.0.0 — 172.31.255.255
+ 192.168.0.0 — 192.168.255.255
+ */
+ if( (ip | 0xffffff00) == 0xffffff0a)
+ return true;
+
+ if( (ip | 0xffff0000) == 0xffffa8c0)
+ return true;
+
+ if( (ip | 0xffffff00) == 0xffffffac)
+ {
+ uint32_t second_num = (ip << 8) & 0xff000000;
+ if(second_num >= 16 && second_num <= 31 )
+ return true;
+ }
+ return false;
+ }
+ inline
+ bool is_ip_loopback(boost::uint32_t ip)
+ {
+ if( (ip | 0xffffff00) == 0xffffff7f)
+ return true;
+ //MAKE_IP
+ /*
+ loopback ip
+ 127.0.0.0 — 127.255.255.255
+ */
+ return false;
+ }
+
+ }
+}
+
diff --git a/contrib/epee/include/net/multiprotocols_server.h b/contrib/epee/include/net/multiprotocols_server.h
new file mode 100644
index 000000000..4807a4421
--- /dev/null
+++ b/contrib/epee/include/net/multiprotocols_server.h
@@ -0,0 +1,47 @@
+// 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<net_utils::protocol_switcher> multiprotocol_server;
+ typedef boosted_tcp_server<net_utils::protocol_switcher> 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
new file mode 100644
index 000000000..8579339c5
--- /dev/null
+++ b/contrib/epee/include/net/munin_connection_handler.h
@@ -0,0 +1,376 @@
+// 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 <string>
+#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<std::string>(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<munin_service> 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! Unkonwon 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<munin_service>::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<munin_service>::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_ \ No newline at end of file
diff --git a/contrib/epee/include/net/munin_node_server.h b/contrib/epee/include/net/munin_node_server.h
new file mode 100644
index 000000000..07637f550
--- /dev/null
+++ b/contrib/epee/include/net/munin_node_server.h
@@ -0,0 +1,49 @@
+// 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 <string>
+//#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_connection_handler> munin_node_server;
+ //typedef cp_server_impl<munin_node_server_connection_handler> munin_node_cp_server;
+ }
+}
+}
+#endif//!_MUNIN_NODE_SERVER_H_ \ No newline at end of file
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
new file mode 100644
index 000000000..d2a4cfec3
--- /dev/null
+++ b/contrib/epee/include/net/net_helper.h
@@ -0,0 +1,683 @@
+// 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 <Winsock2.h>
+//#include <Ws2tcpip.h>
+#include <boost/lexical_cast.hpp>
+#include <iostream>
+#include <istream>
+#include <ostream>
+#include <string>
+#include <boost/asio.hpp>
+#include <boost/preprocessor/selection/min.hpp>
+#include <boost/lambda/bind.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include "net/net_utils_base.h"
+#include "misc_language.h"
+//#include "profile_tools.h"
+#include "../string_tools.h"
+
+#ifndef MAKE_IP
+#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
+#endif
+
+
+namespace epee
+{
+namespace net_utils
+{
+
+ 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)
+ {}
+ handler_obj(const handler_obj& other_obj):ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred)
+ {}
+
+ boost::system::error_code& ref_error;
+ size_t& ref_bytes_transferred;
+
+ void operator()(const boost::system::error_code& error, // Result of operation.
+ std::size_t bytes_transferred // Number of bytes read.
+ )
+ {
+ ref_error = error;
+ 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)
+ {
+
+
+ m_initialized = true;
+
+
+ // No deadline is required until the first socket operation is started. We
+ // set the deadline to positive infinity so that the actor takes no action
+ // until a specific deadline is set.
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+
+ // Start the persistent actor that checks for deadline expiry.
+ check_deadline();
+
+ }
+ inline
+ ~blocked_mode_client()
+ {
+ //profile_tools::local_coast lc("~blocked_mode_client()", 3);
+ shutdown();
+ }
+
+ inline void set_recv_timeout(int reciev_timeout)
+ {
+ m_reciev_timeout = reciev_timeout;
+ }
+
+ inline
+ bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0")
+ {
+ return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip);
+ }
+
+ inline
+ bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0")
+ {
+ m_connect_timeout = connect_timeout;
+ m_reciev_timeout = reciev_timeout;
+ m_connected = false;
+ if(!m_reciev_timeout)
+ m_reciev_timeout = m_connect_timeout;
+
+ try
+ {
+ m_socket.close();
+ // Get a list of endpoints corresponding to the server name.
+
+
+ //////////////////////////////////////////////////////////////////////////
+
+ 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::iterator iterator = resolver.resolve(query);
+ boost::asio::ip::tcp::resolver::iterator end;
+ if(iterator == end)
+ {
+ LOG_ERROR("Failed to resolve " << addr);
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+
+
+ //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
+ boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
+
+
+ m_socket.open(remote_endpoint.protocol());
+ if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
+ {
+ boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
+ m_socket.bind(local_endpoint);
+ }
+
+
+ m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout));
+
+
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ //m_socket.connect(remote_endpoint);
+ 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();
+ }
+
+ if (!ec && m_socket.is_open())
+ {
+ m_connected = true;
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ return true;
+ }else
+ {
+ LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3);
+ return false;
+ }
+
+ }
+ catch(const boost::system::system_error& er)
+ {
+ LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4);
+ return false;
+ }
+ catch(...)
+ {
+ LOG_PRINT("Some fatal problems.", LOG_LEVEL_4);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ inline
+ bool disconnect()
+ {
+ try
+ {
+ if(m_connected)
+ {
+ m_connected = false;
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+
+ }
+ }
+
+ catch(const boost::system::system_error& /*er*/)
+ {
+ //LOG_ERROR("Some problems at disconnect, message: " << er.what());
+ return false;
+ }
+ catch(...)
+ {
+ //LOG_ERROR("Some fatal problems.");
+ return false;
+ }
+ return true;
+ }
+
+
+ inline
+ bool send(const std::string& buff)
+ {
+
+ try
+ {
+ m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
+
+ // Set up the variable that receives the result of the asynchronous
+ // operation. The error code is set to would_block to signal that the
+ // operation is incomplete. Asio guarantees that its asynchronous
+ // operations will never fail with would_block, so any other value in
+ // ec indicates completion.
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ // Start the asynchronous operation itself. The boost::lambda function
+ // object is used as a callback and will update the ec variable when the
+ // operation completes. The blocking_udp_client.cpp example shows how you
+ // can use boost::bind rather than boost::lambda.
+ boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1);
+
+ // Block until the asynchronous operation has completed.
+ while (ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }
+
+ if (ec)
+ {
+ LOG_PRINT_L3("Problems at write: " << ec.message());
+ m_connected = false;
+ return false;
+ }else
+ {
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+ }
+
+ catch(const boost::system::system_error& er)
+ {
+ LOG_ERROR("Some problems at connect, message: " << er.what());
+ return false;
+ }
+ catch(...)
+ {
+ LOG_ERROR("Some fatal problems.");
+ return false;
+ }
+
+ return true;
+ }
+
+ inline
+ bool send(const void* data, size_t sz)
+ {
+ try
+ {
+ /*
+ m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
+
+ // Set up the variable that receives the result of the asynchronous
+ // operation. The error code is set to would_block to signal that the
+ // operation is incomplete. Asio guarantees that its asynchronous
+ // operations will never fail with would_block, so any other value in
+ // ec indicates completion.
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ // Start the asynchronous operation itself. The boost::lambda function
+ // object is used as a callback and will update the ec variable when the
+ // operation completes. The blocking_udp_client.cpp example shows how you
+ // can use boost::bind rather than boost::lambda.
+ boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+
+ // Block until the asynchronous operation has completed.
+ while (ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }
+ */
+ boost::system::error_code ec;
+
+ size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
+
+
+
+ if (!writen || ec)
+ {
+ LOG_PRINT_L3("Problems at write: " << ec.message());
+ m_connected = false;
+ return false;
+ }else
+ {
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+ }
+
+ catch(const boost::system::system_error& er)
+ {
+ LOG_ERROR("Some problems at send, message: " << er.what());
+ m_connected = false;
+ return false;
+ }
+ catch(...)
+ {
+ LOG_ERROR("Some fatal problems.");
+ return false;
+ }
+
+ return true;
+ }
+
+ bool is_connected()
+ {
+ return m_connected && m_socket.is_open();
+ //TRY_ENTRY()
+ //return m_socket.is_open();
+ //CATCH_ENTRY_L0("is_connected", false)
+ }
+
+ inline
+ bool recv(std::string& buff)
+ {
+
+ try
+ {
+ // Set a deadline for the asynchronous operation. Since this function uses
+ // a composed operation (async_read_until), the deadline applies to the
+ // entire operation, rather than individual reads from the socket.
+ m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
+
+ // Set up the variable that receives the result of the asynchronous
+ // operation. The error code is set to would_block to signal that the
+ // operation is incomplete. Asio guarantees that its asynchronous
+ // operations will never fail with would_block, so any other value in
+ // ec indicates completion.
+ //boost::system::error_code ec = boost::asio::error::would_block;
+
+ // Start the asynchronous operation itself. The boost::lambda function
+ // object is used as a callback and will update the ec variable when the
+ // operation completes. The blocking_udp_client.cpp example shows how you
+ // can use boost::bind rather than boost::lambda.
+
+ boost::system::error_code ec = boost::asio::error::would_block;
+ size_t bytes_transfered = 0;
+
+ handler_obj hndlr(ec, bytes_transfered);
+
+ char local_buff[10000] = {0};
+ //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr);
+ boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr);
+
+ // 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();
+ }
+
+
+ if (ec)
+ {
+ LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value());
+ if(ec == boost::asio::error::eof)
+ {
+ LOG_PRINT_L4("Connection err_code eof.");
+ //connection closed there, empty
+ return true;
+ }
+
+ LOG_PRINT_L3("Problems at read: " << ec.message());
+ m_connected = false;
+ return false;
+ }else
+ {
+ LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered);
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+
+ /*if(!bytes_transfered)
+ return false;*/
+
+ buff.assign(local_buff, bytes_transfered);
+ return true;
+ }
+
+ catch(const boost::system::system_error& er)
+ {
+ LOG_ERROR("Some problems at read, message: " << er.what());
+ m_connected = false;
+ return false;
+ }
+ catch(...)
+ {
+ LOG_ERROR("Some fatal problems at read.");
+ return false;
+ }
+
+
+
+ return false;
+
+ }
+
+ inline bool recv_n(std::string& buff, boost::int64_t sz)
+ {
+
+ try
+ {
+ // Set a deadline for the asynchronous operation. Since this function uses
+ // a composed operation (async_read_until), the deadline applies to the
+ // entire operation, rather than individual reads from the socket.
+ m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
+
+ // Set up the variable that receives the result of the asynchronous
+ // operation. The error code is set to would_block to signal that the
+ // operation is incomplete. Asio guarantees that its asynchronous
+ // operations will never fail with would_block, so any other value in
+ // ec indicates completion.
+ //boost::system::error_code ec = boost::asio::error::would_block;
+
+ // Start the asynchronous operation itself. The boost::lambda function
+ // object is used as a callback and will update the ec variable when the
+ // operation completes. The blocking_udp_client.cpp example shows how you
+ // can use boost::bind rather than boost::lambda.
+
+ buff.resize(static_cast<size_t>(sz));
+ boost::system::error_code ec = boost::asio::error::would_block;
+ size_t bytes_transfered = 0;
+
+
+ handler_obj hndlr(ec, bytes_transfered);
+
+ //char local_buff[10000] = {0};
+ boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr);
+
+ // 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();
+ }
+
+ if (ec)
+ {
+ LOG_PRINT_L3("Problems at read: " << ec.message());
+ m_connected = false;
+ return false;
+ }else
+ {
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+
+ if(bytes_transfered != buff.size())
+ {
+ LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size());
+ return false;
+ }
+
+ return true;
+ }
+
+ catch(const boost::system::system_error& er)
+ {
+ LOG_ERROR("Some problems at read, message: " << er.what());
+ m_connected = false;
+ return false;
+ }
+ catch(...)
+ {
+ LOG_ERROR("Some fatal problems at read.");
+ return false;
+ }
+
+
+
+ return false;
+ }
+
+ bool shutdown()
+ {
+ m_deadline.cancel();
+ boost::system::error_code ignored_ec;
+ m_socket.cancel(ignored_ec);
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
+ m_socket.close(ignored_ec);
+ boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
+ m_connected = false;
+ return true;
+ }
+
+ void set_connected(bool connected)
+ {
+ m_connected = connected;
+ }
+ boost::asio::io_service& get_io_service()
+ {
+ return m_io_service;
+ }
+
+ boost::asio::ip::tcp::socket& get_socket()
+ {
+ return m_socket;
+ }
+
+ private:
+
+ void check_deadline()
+ {
+ // Check whether the deadline has passed. We compare the deadline against
+ // the current time since a new asynchronous operation may have moved the
+ // deadline before this actor had a chance to run.
+ if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
+ {
+ // The deadline has passed. The socket is closed so that any outstanding
+ // asynchronous operations are cancelled. This allows the blocked
+ // connect(), read_line() or write_line() functions to return.
+ LOG_PRINT_L3("Timed out socket");
+ m_connected = false;
+ m_socket.close();
+
+ // There is no longer an active deadline. The expiry is set to positive
+ // infinity so that the actor takes no action until a new deadline is set.
+ m_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+
+ // Put the actor back to sleep.
+ m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this));
+ }
+
+
+
+ protected:
+ boost::asio::io_service m_io_service;
+ boost::asio::ip::tcp::socket m_socket;
+ int m_connect_timeout;
+ int m_reciev_timeout;
+ bool m_initialized;
+ bool m_connected;
+ boost::asio::deadline_timer m_deadline;
+ volatile boost::uint32_t m_shutdowned;
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class async_blocked_mode_client: public blocked_mode_client
+ {
+ public:
+ async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service)
+ {
+
+ // No deadline is required until the first socket operation is started. We
+ // set the deadline to positive infinity so that the actor takes no action
+ // until a specific deadline is set.
+ m_send_deadline.expires_at(boost::posix_time::pos_infin);
+
+ // Start the persistent actor that checks for deadline expiry.
+ check_send_deadline();
+ }
+ ~async_blocked_mode_client()
+ {
+ m_send_deadline.cancel();
+ }
+
+ bool shutdown()
+ {
+ blocked_mode_client::shutdown();
+ m_send_deadline.cancel();
+ return true;
+ }
+
+ inline
+ bool send(const void* data, size_t sz)
+ {
+ try
+ {
+ /*
+ m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
+
+ // Set up the variable that receives the result of the asynchronous
+ // operation. The error code is set to would_block to signal that the
+ // operation is incomplete. Asio guarantees that its asynchronous
+ // operations will never fail with would_block, so any other value in
+ // ec indicates completion.
+ boost::system::error_code ec = boost::asio::error::would_block;
+
+ // Start the asynchronous operation itself. The boost::lambda function
+ // object is used as a callback and will update the ec variable when the
+ // operation completes. The blocking_udp_client.cpp example shows how you
+ // can use boost::bind rather than boost::lambda.
+ boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+
+ // Block until the asynchronous operation has completed.
+ while(ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }*/
+
+ boost::system::error_code ec;
+
+ size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
+
+ if (!writen || ec)
+ {
+ LOG_PRINT_L3("Problems at write: " << ec.message());
+ return false;
+ }else
+ {
+ m_send_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+ }
+
+ catch(const boost::system::system_error& er)
+ {
+ LOG_ERROR("Some problems at connect, message: " << er.what());
+ return false;
+ }
+ catch(...)
+ {
+ LOG_ERROR("Some fatal problems.");
+ return false;
+ }
+
+ return true;
+ }
+
+
+ private:
+
+ boost::asio::deadline_timer m_send_deadline;
+
+ void check_send_deadline()
+ {
+ // Check whether the deadline has passed. We compare the deadline against
+ // the current time since a new asynchronous operation may have moved the
+ // deadline before this actor had a chance to run.
+ if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
+ {
+ // The deadline has passed. The socket is closed so that any outstanding
+ // asynchronous operations are cancelled. This allows the blocked
+ // connect(), read_line() or write_line() functions to return.
+ LOG_PRINT_L3("Timed out socket");
+ m_socket.close();
+
+ // There is no longer an active deadline. The expiry is set to positive
+ // infinity so that the actor takes no action until a new deadline is set.
+ m_send_deadline.expires_at(boost::posix_time::pos_infin);
+ }
+
+ // 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_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h
new file mode 100644
index 000000000..16641a970
--- /dev/null
+++ b/contrib/epee/include/net/net_parse_helpers.h
@@ -0,0 +1,168 @@
+// 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 "http_base.h"
+#include "reg_exp_definer.h"
+
+
+namespace epee
+{
+namespace net_utils
+{
+
+ inline bool parse_uri_query(const std::string& query, std::list<std::pair<std::string, std::string> >& params)
+ {
+ enum state
+ {
+ st_param_name,
+ st_param_val
+ };
+ state st = st_param_name;
+ std::string::const_iterator start_it = query.begin();
+ std::pair<std::string, std::string> e;
+ for(std::string::const_iterator it = query.begin(); it != query.end(); it++)
+ {
+ switch(st)
+ {
+ case st_param_name:
+ if(*it == '=')
+ {
+ e.first.assign(start_it, it);
+ start_it = it;++start_it;
+ st = st_param_val;
+ }
+ break;
+ case st_param_val:
+ if(*it == '&')
+ {
+ e.second.assign(start_it, it);
+ start_it = it;++start_it;
+ params.push_back(e);
+ e.first.clear();e.second.clear();
+ st = st_param_name;
+ }
+ break;
+ default:
+ LOG_ERROR("Unknown state " << (int)st);
+ return false;
+ }
+ }
+ if(st == st_param_name)
+ {
+ if(start_it != query.end())
+ {
+ e.first.assign(start_it, query.end());
+ params.push_back(e);
+ }
+ }else
+ {
+ if(start_it != query.end())
+ e.second.assign(start_it, query.end());
+
+ if(e.first.size())
+ params.push_back(e);
+ }
+ return true;
+ }
+
+ inline
+ bool parse_uri(const std::string uri, http::uri_content& content)
+ {
+
+ ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
+ content.m_query_params.clear();
+ STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal);
+
+ boost::smatch result;
+ if(!boost::regex_search(uri, result, rexp_match_uri, boost::match_default) && result[0].matched)
+ {
+ LOG_PRINT_L0("[PARSE URI] regex not matched for uri: " << uri);
+ content.m_path = uri;
+ return true;
+ }
+ if(result[1].matched)
+ {
+ content.m_path = result[1];
+ }
+ if(result[3].matched)
+ {
+ content.m_query = result[3];
+ }
+ if(result[5].matched)
+ {
+ content.m_fragment = result[5];
+ }
+ if(content.m_query.size())
+ {
+ parse_uri_query(content.m_query, content.m_query_params);
+ }
+ return true;
+ }
+
+
+ inline
+ bool parse_url(const std::string url_str, http::url_content& content)
+ {
+
+ ///iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
+ //STATIC_REGEXP_EXPR_1(rexp_match_uri, "^([^?#]*)(\\?([^#]*))?(#(.*))?", boost::regex::icase | boost::regex::normal);
+ STATIC_REGEXP_EXPR_1(rexp_match_uri, "^((.*?)://)?(([^/:]*)(:(\\d+))?)(.*)?", boost::regex::icase | boost::regex::normal);
+ // 12 34 5 6 7
+ content.port = 0;
+ boost::smatch result;
+ if(!boost::regex_search(url_str, result, rexp_match_uri, boost::match_default) && result[0].matched)
+ {
+ LOG_PRINT_L0("[PARSE URI] regex not matched for uri: " << rexp_match_uri);
+ //content.m_path = uri;
+ return true;
+ }
+ if(result[2].matched)
+ {
+ content.schema = result[2];
+ }
+ if(result[4].matched)
+ {
+ content.host = result[4];
+ }
+ if(result[6].matched)
+ {
+ content.port = boost::lexical_cast<boost::uint64_t>(result[6]);
+ }
+ if(result[7].matched)
+ {
+ content.uri = result[7];
+ return parse_uri(result[7], content.m_uri_content);
+ }
+
+ return true;
+ }
+
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h
new file mode 100644
index 000000000..86797bb85
--- /dev/null
+++ b/contrib/epee/include/net/net_utils_base.h
@@ -0,0 +1,150 @@
+// 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 _NET_UTILS_BASE_H_
+#define _NET_UTILS_BASE_H_
+
+#include <boost/uuid/uuid.hpp>
+#include "string_tools.h"
+
+#ifndef MAKE_IP
+#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(a4<<24))
+#endif
+
+
+namespace epee
+{
+namespace net_utils
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct connection_context_base
+ {
+ const boost::uuids::uuid m_connection_id;
+ const boost::uint32_t m_remote_ip;
+ const boost::uint32_t m_remote_port;
+ const bool m_is_income;
+
+ connection_context_base(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income):
+ m_connection_id(connection_id),
+ m_remote_ip(remote_ip),
+ m_remote_port(remote_port),
+ m_is_income(is_income)
+
+
+ {}
+
+ connection_context_base(): m_connection_id(),
+ m_remote_ip(0),
+ m_remote_port(0),
+ m_is_income(false)
+ {}
+
+ connection_context_base& operator=(const connection_context_base& a)
+ {
+ set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income);
+ return *this;
+ }
+
+ private:
+ template<class t_protocol_handler>
+ friend class connection;
+ void set_details(boost::uuids::uuid connection_id, long remote_ip, int remote_port, bool is_income)
+ {
+ this->~connection_context_base();
+ new(this) connection_context_base(connection_id, remote_ip, remote_port, is_income);
+ }
+
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct i_service_endpoint
+ {
+ virtual bool do_send(const void* ptr, size_t cb)=0;
+ virtual bool close()=0;
+ virtual bool call_run_once_service_io()=0;
+ virtual bool request_callback()=0;
+ virtual boost::asio::io_service& get_io_service()=0;
+ //protect from deletion connection object(with protocol instance) during external call "invoke"
+ virtual bool add_ref()=0;
+ virtual bool release()=0;
+ protected:
+ virtual ~i_service_endpoint(){}
+ };
+
+
+ //some helpers
+
+
+ inline
+ std::string print_connection_context(const connection_context_base& ctx)
+ {
+ std::stringstream ss;
+ ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
+ return ss.str();
+ }
+
+ inline
+ std::string print_connection_context_short(const connection_context_base& ctx)
+ {
+ std::stringstream ss;
+ ss << epee::string_tools::get_ip_string_from_int32(ctx.m_remote_ip) << ":" << ctx.m_remote_port << (ctx.m_is_income ? " INC":" OUT");
+ return ss.str();
+ }
+
+#define LOG_PRINT_CC(ct, message, log_level) LOG_PRINT("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
+#define LOG_PRINT_CC_GREEN(ct, message, log_level) LOG_PRINT_GREEN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
+#define LOG_PRINT_CC_RED(ct, message, log_level) LOG_PRINT_RED("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
+#define LOG_PRINT_CC_BLUE(ct, message, log_level) LOG_PRINT_BLUE("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
+#define LOG_ERROR_CC(ct, message) LOG_ERROR("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+
+#define LOG_PRINT_CC_L0(ct, message) LOG_PRINT_L0("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+#define LOG_PRINT_CC_L1(ct, message) LOG_PRINT_L1("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+#define LOG_PRINT_CC_L2(ct, message) LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+#define LOG_PRINT_CC_L3(ct, message) LOG_PRINT_L3("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+#define LOG_PRINT_CC_L4(ct, message) LOG_PRINT_L4("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message)
+
+#define LOG_PRINT_CCONTEXT_L0(message) LOG_PRINT_CC_L0(context, message)
+#define LOG_PRINT_CCONTEXT_L1(message) LOG_PRINT_CC_L1(context, message)
+#define LOG_PRINT_CCONTEXT_L2(message) LOG_PRINT_CC_L2(context, message)
+#define LOG_PRINT_CCONTEXT_L3(message) LOG_PRINT_CC_L3(context, message)
+#define LOG_ERROR_CCONTEXT(message) LOG_ERROR_CC(context, message)
+
+#define LOG_PRINT_CCONTEXT_GREEN(message, log_level) LOG_PRINT_CC_GREEN(context, message, log_level)
+#define LOG_PRINT_CCONTEXT_RED(message, log_level) LOG_PRINT_CC_RED(context, message, log_level)
+#define LOG_PRINT_CCONTEXT_BLUE(message, log_level) LOG_PRINT_CC_BLUE(context, message, log_level)
+
+#define CHECK_AND_ASSERT_MES_CC(condition, return_val, err_message) CHECK_AND_ASSERT_MES(condition, return_val, "[" << epee::net_utils::print_connection_context_short(context) << "]" << err_message)
+
+}
+}
+
+#endif //_NET_UTILS_BASE_H_
diff --git a/contrib/epee/include/net/protocol_switcher.h b/contrib/epee/include/net/protocol_switcher.h
new file mode 100644
index 000000000..f9a6dbe6f
--- /dev/null
+++ b/contrib/epee/include/net/protocol_switcher.h
@@ -0,0 +1,121 @@
+// 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>
+ 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<http::http_custom_handler> m_http_handler;
+ t_protocol_handler<levin::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(boost::uint64_t))
+ return true;
+
+ if(*((boost::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_ \ No newline at end of file
diff --git a/contrib/epee/include/net/rpc_method_name.h b/contrib/epee/include/net/rpc_method_name.h
new file mode 100644
index 000000000..c226639c4
--- /dev/null
+++ b/contrib/epee/include/net/rpc_method_name.h
@@ -0,0 +1,31 @@
+// 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;} \ No newline at end of file
diff --git a/contrib/epee/include/net/smtp.h b/contrib/epee/include/net/smtp.h
new file mode 100644
index 000000000..d2e8598fd
--- /dev/null
+++ b/contrib/epee/include/net/smtp.h
@@ -0,0 +1,181 @@
+// 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 <iostream>
+#include <istream>
+#include <ostream>
+#include <string>
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/archive/iterators/ostream_iterator.hpp>
+
+
+namespace epee
+{
+namespace net_utils
+{
+ namespace smtp
+ {
+
+ using boost::asio::ip::tcp;
+ using namespace boost::archive::iterators;
+ typedef base64_from_binary<transform_width<const char *,6,8> > base64_text;
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class smtp_client
+ {
+ public:
+ smtp_client(std::string pServer,unsigned int pPort,std::string pUser,std::string pPassword):
+ mServer(pServer),mPort(pPort),mUserName(pUser),mPassword(pPassword),mSocket(mIOService),mResolver(mIOService)
+ {
+ tcp::resolver::query qry(mServer,boost::lexical_cast<std::string>( mPort ));
+ mResolver.async_resolve(qry,boost::bind(&smtp_client::handleResolve,this,boost::asio::placeholders::error,
+ boost::asio::placeholders::iterator));
+ }
+ bool Send(std::string pFrom,std::string pTo,std::string pSubject,std::string pMessage)
+ {
+ mHasError = true;
+ mFrom=pFrom;
+ mTo=pTo;
+ mSubject=pSubject;
+ mMessage=pMessage;
+ mIOService.run();
+ return !mHasError;
+ }
+ private:
+ std::string encodeBase64(std::string pData)
+ {
+ std::stringstream os;
+ size_t sz=pData.size();
+ std::copy(base64_text(pData.c_str()),base64_text(pData.c_str()+sz),std::ostream_iterator<char>(os));
+ return os.str();
+ }
+ void handleResolve(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
+ {
+ if(!err)
+ {
+ tcp::endpoint endpoint=*endpoint_iterator;
+ mSocket.async_connect(endpoint,
+ boost::bind(&smtp_client::handleConnect,this,boost::asio::placeholders::error,++endpoint_iterator));
+ }
+ else
+ {
+ mHasError=true;
+ mErrorMsg= err.message();
+ }
+ }
+ void writeLine(std::string pData)
+ {
+ std::ostream req_strm(&mRequest);
+ req_strm << pData << "\r\n";
+ boost::asio::write(mSocket,mRequest);
+ req_strm.clear();
+ }
+ void readLine(std::string& pData)
+ {
+ boost::asio::streambuf response;
+ boost::asio::read_until(mSocket, response, "\r\n");
+ std::istream response_stream(&response);
+ response_stream >> pData;
+ }
+ void handleConnect(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
+ {
+ if (!err)
+ {
+ std::string read_buff;
+ // The connection was successful. Send the request.
+ std::ostream req_strm(&mRequest);
+ writeLine("EHLO "+mServer);
+ readLine(read_buff);//220
+ writeLine("AUTH LOGIN");
+ readLine(read_buff);//
+ writeLine(encodeBase64(mUserName));
+ readLine(read_buff);
+ writeLine(encodeBase64(mPassword));
+ readLine(read_buff);
+ writeLine( "MAIL FROM:<"+mFrom+">");
+ writeLine( "RCPT TO:<"+mTo+">");
+ writeLine( "DATA");
+ writeLine( "SUBJECT:"+mSubject);
+ writeLine( "From:"+mFrom);
+ writeLine( "To:"+mTo);
+ writeLine( "");
+ writeLine( mMessage );
+ writeLine( "\r\n.\r\n");
+ readLine(read_buff);
+ if(read_buff == "250")
+ mHasError = false;
+ writeLine( "QUIT");
+ }
+ else
+ {
+ mHasError=true;
+ mErrorMsg= err.message();
+ }
+ }
+ std::string mServer;
+ std::string mUserName;
+ std::string mPassword;
+ std::string mFrom;
+ std::string mTo;
+ std::string mSubject;
+ std::string mMessage;
+ unsigned int mPort;
+ boost::asio::io_service mIOService;
+ tcp::resolver mResolver;
+ tcp::socket mSocket;
+ boost::asio::streambuf mRequest;
+ boost::asio::streambuf mResponse;
+ bool mHasError;
+ std::string mErrorMsg;
+ };
+
+
+ bool send_mail(const std::string& server, int port, const std::string& login, const std::string& pass, const std::string& from_email, /*"STIL CRAWLER",*/
+ const std::string& maillist, const std::string& subject, const std::string& body)
+ {
+ STD_TRY_BEGIN();
+ //smtp_client mailc("yoursmtpserver.com",25,"user@yourdomain.com","password");
+ //mailc.Send("from@yourdomain.com","to@somewhere.com","subject","Hello from C++ SMTP Client!");
+ smtp_client mailc(server,port,login,pass);
+ return mailc.Send(from_email,maillist,subject,body);
+ STD_TRY_CATCH("at send_mail", false);
+ }
+
+ }
+}
+}
+
+//#include "smtp.inl" \ No newline at end of file
diff --git a/contrib/epee/include/net/smtp.inl b/contrib/epee/include/net/smtp.inl
new file mode 100644
index 000000000..d42c8b950
--- /dev/null
+++ b/contrib/epee/include/net/smtp.inl
@@ -0,0 +1,1569 @@
+// 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.
+//
+
+
+
+#include "md5.h"
+
+namespace epee
+{
+namespace net_utils
+{
+ namespace smtp
+ {
+
+
+ //////////////////////////////////////////////////////////////////////////
+ inline char * convert_hex( unsigned char *in, int len )
+ {
+ static char hex[] = "0123456789abcdef";
+ char * out;
+ int i;
+
+ out = (char *) malloc(len * 2 + 1);
+ if (out == NULL)
+ return NULL;
+
+ for (i = 0; i < len; i++) {
+ out[i * 2] = hex[in[i] >> 4];
+ out[i * 2 + 1] = hex[in[i] & 15];
+ }
+
+ out[i*2] = 0;
+
+ return out;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline char * hash_md5(const char * sec_key, const char * data, int len)
+ {
+ char key[65], digest[24];
+ char * hash_hex;
+
+ int sec_len, i;
+
+ sec_len = strlen(sec_key);
+
+ if (sec_len < 64) {
+ memcpy(key, sec_key, sec_len);
+ for (i = sec_len; i < 64; i++) {
+ key[i] = 0;
+ }
+ } else {
+ memcpy(key, sec_key, 64);
+ }
+
+ md5::hmac_md5( (const unsigned char*)data, len, (const unsigned char*)key, 64, (unsigned char*)digest );
+ hash_hex = convert_hex( (unsigned char*)digest, 16 );
+
+ return hash_hex;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ inline CSMTPClient::CSMTPClient(void)
+ {
+ m_dwSupportedAuthModesCount = 0;
+ m_bConnected = FALSE;
+ m_hSocket = INVALID_SOCKET;
+ m_pErrorText = NULL;
+
+ // Initialize WinSock
+ WORD wVer = MAKEWORD( 2, 2 );
+ if ( WSAStartup( wVer, &m_wsaData ) != NO_ERROR )
+ {
+ SetErrorText( "WSAStartup.", WSAGetLastError() );
+ throw;
+ }
+ if ( LOBYTE( m_wsaData.wVersion ) != 2 || HIBYTE( m_wsaData.wVersion ) != 2 )
+ {
+ SetErrorText( "Can't find a useable WinSock DLL." );
+ WSACleanup();
+ throw;
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline CSMTPClient::~CSMTPClient(void)
+ {
+ if ( m_pErrorText )
+ {
+ free( m_pErrorText );
+ m_pErrorText = NULL;
+ }
+
+ if ( m_bConnected )
+ ServerDisconnect();
+
+ // Cleanup
+ WSACleanup();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline void CSMTPClient::SetErrorText( LPCSTR szErrorText, DWORD dwErrorCode )
+ {
+ if ( m_pErrorText )
+ {
+ free( m_pErrorText );
+ m_pErrorText = NULL;
+ }
+
+ LPVOID lpMsgBuf = NULL;
+ if ( dwErrorCode )
+ {
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwErrorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR) &lpMsgBuf,
+ 0, NULL );
+ }
+
+ if ( szErrorText && strlen( szErrorText ) )
+ {
+ m_pErrorText = (LPBYTE)malloc( strlen( szErrorText ) + 1 );
+ strcpy( (char*)m_pErrorText, szErrorText );
+
+ if ( lpMsgBuf )
+ {
+ strcat( (char*)m_pErrorText, " " );
+ strcpy( (char*)m_pErrorText, (char*)lpMsgBuf );
+
+ LocalFree( lpMsgBuf );
+ }
+ }
+ }
+
+ inline void CSMTPClient::SetErrorText( PBYTE szErrorText, DWORD dwErrorCode )
+ {
+ SetErrorText( (LPCSTR)szErrorText, dwErrorCode );
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline char* CSMTPClient::GetLastErrorText()
+ {
+ return (char*)m_pErrorText;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline DWORD CSMTPClient::ReceiveData( SOCKET hSocket, PBYTE pReceiveBuffer, DWORD dwReceiveBufferSize )
+ {
+ DWORD dwReceivedDataSize = 0;
+
+ if ( hSocket != INVALID_SOCKET && pReceiveBuffer && dwReceiveBufferSize )
+ {
+ int iReceived = 0;
+ int iLength = 0;
+
+ iLength = recv( hSocket, (LPSTR)pReceiveBuffer + iReceived, dwReceiveBufferSize - iReceived,
+ NO_FLAGS );
+
+ if ( iLength != 0 && iLength != SOCKET_ERROR )
+ iReceived += iLength;
+
+ dwReceivedDataSize = iReceived;
+
+ pReceiveBuffer[ iReceived ] = 0;
+ }
+
+ return dwReceivedDataSize;
+ }
+
+ inline //////////////////////////////////////////////////////////////////////////
+ DWORD CSMTPClient::SendData( SOCKET hSocket, PBYTE pSendBuffer, DWORD dwSendBufferSize )
+ {
+ DWORD dwSended = 0;
+
+ if ( hSocket != INVALID_SOCKET && pSendBuffer && dwSendBufferSize )
+ {
+ int iSended = 0;
+ int iLength = 0;
+
+ while ( iLength != SOCKET_ERROR && dwSendBufferSize - iSended > 0 )
+ {
+ iLength = send( hSocket, (LPSTR)pSendBuffer + iSended, dwSendBufferSize - iSended,
+ NO_FLAGS );
+
+ if ( iLength != 0 && iLength != SOCKET_ERROR )
+ iSended += iLength;
+ }
+
+ dwSended = iSended;
+ }
+
+ //if ( dwSended )
+ // printf( "C: %s", pSendBuffer );
+
+ return dwSended;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline unsigned short CSMTPClient::GetResponseCode( LPBYTE pBuffer, DWORD dwBufferSize )
+ {
+ unsigned short iCode = 0;
+
+ if ( dwBufferSize >= 3 )
+ {
+ CHAR szResponseCode[ 4 ] = { 0 };
+ memcpy( szResponseCode, pBuffer, 3 );
+ szResponseCode[ 3 ] = 0;
+ iCode = atoi( szResponseCode );
+ }
+
+ return iCode;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline void CSMTPClient::ParseESMTPExtensions( LPBYTE pBuffer, DWORD dwBufferSize )
+ {
+ const char *szSubstring = strstr( (const char*)pBuffer, "250-AUTH " );
+ if ( !szSubstring )
+ {
+ szSubstring = strstr( (const char*)pBuffer, "250 AUTH " );
+ }
+
+ if ( szSubstring )
+ {
+ const char *szSubstringEnd = strstr( (const char*)szSubstring, "\r\n" );
+ if ( szSubstringEnd )
+ {
+ szSubstring += 9;
+ char szAuthMode[ 256 ] = { 0 };
+ for ( ; szSubstring < szSubstringEnd + 1 ; szSubstring++ )
+ {
+ if ( *szSubstring == ' ' || *szSubstring == '\r' )
+ {
+ if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_PLAIN ) == 0 )
+ {
+ m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_PLAIN;
+ m_dwSupportedAuthModesCount++;
+ }
+ else if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_LOGIN ) == 0 )
+ {
+ m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_LOGIN;
+ m_dwSupportedAuthModesCount++;
+ }
+ else if ( _strcmpi( szAuthMode, SMTP_COMMAND_AUTH_CRAM_MD5 ) == 0 )
+ {
+ m_aSupportedAuthModes[ m_dwSupportedAuthModesCount ] = AUTH_MODE_CRAM_MD5;
+ m_dwSupportedAuthModesCount++;
+ }
+
+ szAuthMode[ 0 ] = 0;
+
+ if ( m_dwSupportedAuthModesCount == MAX_AUTH_MODES_COUND )
+ break;
+ }
+ else
+ {
+ szAuthMode[ strlen( szAuthMode ) + 1 ] = 0;
+ szAuthMode[ strlen( szAuthMode ) ] = *szSubstring;
+ }
+ }
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerConnect( LPCSTR szServerAddress, const unsigned short iPortNumber )
+ {
+ if ( m_bConnected )
+ ServerDisconnect();
+
+ m_bConnected = FALSE;
+ m_hSocket = INVALID_SOCKET;
+
+ m_hSocket = _connectServerSocket( szServerAddress, iPortNumber );
+
+ if ( m_hSocket != INVALID_SOCKET )
+ {
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ // Connected. Wait server hello string.
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ // Check 220
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 220 )
+ {
+ SetErrorText( pReceiveBuffer );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error. ", WSAGetLastError() );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+
+ // EHLO / HELO
+ BYTE szHelloBuffer[ 256 ];
+ sprintf( (char*)szHelloBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_EHLO, (char*)szServerAddress );
+ if ( SendData( m_hSocket, (PBYTE)szHelloBuffer, strlen( (const char*)szHelloBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ // Check 250
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode == 500 )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ sprintf( (char*)szHelloBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_HELO, (char*)szServerAddress );
+ if ( SendData( m_hSocket, (PBYTE)szHelloBuffer, strlen( (const char*)szHelloBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+
+ iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 250 )
+ {
+ SetErrorText( pReceiveBuffer );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+ }
+ else if ( iResponseCode != 250 )
+ {
+ SetErrorText( pReceiveBuffer );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+
+ // Parse AUTH supported modes
+ ParseESMTPExtensions( pReceiveBuffer, iReceived );
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ ServerDisconnect();
+ return FALSE;
+ }
+
+ free( pReceiveBuffer );
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ m_bConnected = TRUE;
+
+ return TRUE;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerConnect( LPCSTR szServerAddress, const unsigned short iPortNumber, LPCSTR szUsername, LPCSTR szPassword )
+ {
+ BOOL bSuccess = FALSE;
+
+ bSuccess = ServerConnect( szServerAddress, iPortNumber );
+ if ( bSuccess )
+ {
+ if ( GetAuthModeIsSupported( AUTH_MODE_CRAM_MD5 ) )
+ {
+ ServerLogin( szUsername, szPassword, AUTH_MODE_CRAM_MD5 );
+ }
+ else
+ if ( GetAuthModeIsSupported( AUTH_MODE_PLAIN ) )
+ {
+ ServerLogin( szUsername, szPassword, AUTH_MODE_PLAIN );
+ }
+ else
+ if ( GetAuthModeIsSupported( AUTH_MODE_LOGIN ) )
+ {
+ ServerLogin( szUsername, szPassword, AUTH_MODE_LOGIN );
+ }
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline SOCKET CSMTPClient::_connectServerSocket( LPCSTR szServerAddress, const unsigned short iPortNumber )
+ {
+ int nConnect;
+ short nProtocolPort = iPortNumber;
+ LPHOSTENT lpHostEnt;
+ SOCKADDR_IN sockAddr;
+
+ SOCKET hServerSocket = INVALID_SOCKET;
+
+ lpHostEnt = gethostbyname( szServerAddress );
+ if (lpHostEnt)
+ {
+ hServerSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
+ if (hServerSocket != INVALID_SOCKET)
+ {
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_port = htons( nProtocolPort );
+ sockAddr.sin_addr = *((LPIN_ADDR)*lpHostEnt->h_addr_list);
+
+ nConnect = connect( hServerSocket, (PSOCKADDR)&sockAddr,
+ sizeof(sockAddr) );
+
+ if ( nConnect != 0 )
+ {
+ SetErrorText( "connect error.", WSAGetLastError() );
+ hServerSocket = INVALID_SOCKET;
+ }
+ }
+ else
+ {
+ SetErrorText( "Invalid socket." );
+ throw;
+ }
+ }
+ else
+ {
+ SetErrorText( "Error retrieving host by name.", WSAGetLastError() );
+ }
+
+ return hServerSocket ;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline void CSMTPClient::ServerDisconnect()
+ {
+ if ( m_hSocket != INVALID_SOCKET )
+ {
+ if ( SendData( m_hSocket, (PBYTE)SMTP_COMMAND_QUIT, strlen( SMTP_COMMAND_QUIT ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ return;
+ }
+
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+
+ if ( iReceived )
+ SetErrorText( pReceiveBuffer );
+
+ free( pReceiveBuffer );
+ }
+
+ m_hSocket = INVALID_SOCKET;
+ }
+
+ m_bConnected = FALSE;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::GetAuthModeIsSupported( int iMode )
+ {
+ BOOL bSupported = FALSE;
+
+ for ( int i = 0 ; i < m_dwSupportedAuthModesCount ; i++ )
+ {
+ if ( m_aSupportedAuthModes[ i ] == iMode )
+ {
+ bSupported = TRUE;
+ break;
+ }
+ }
+
+ return bSupported;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerLogin( LPCSTR szUsername, LPCSTR szPassword, int iAuthMode )
+ {
+ BOOL bSuccess = FALSE;
+
+ if ( iAuthMode == AUTH_MODE_PLAIN )
+ {
+ bSuccess = ServerLoginMethodPlain( szUsername, szPassword );
+ }
+ else if ( iAuthMode == AUTH_MODE_LOGIN )
+ {
+ bSuccess = ServerLoginMethodLogin( szUsername, szPassword );
+ }
+ else if ( iAuthMode == AUTH_MODE_CRAM_MD5 )
+ {
+ bSuccess = ServerLoginMethodCramMD5( szUsername, szPassword );
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerLogin( LPCSTR szUsername, LPCSTR szPassword )
+ {
+ BOOL bSuccess = FALSE;
+
+ if ( GetAuthModeIsSupported( AUTH_MODE_CRAM_MD5 ) )
+ {
+ bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_CRAM_MD5 );
+ }
+ else
+ if ( GetAuthModeIsSupported( AUTH_MODE_PLAIN ) )
+ {
+ bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_PLAIN );
+ }
+ else
+ if ( GetAuthModeIsSupported( AUTH_MODE_LOGIN ) )
+ {
+ bSuccess = ServerLogin( szUsername, szPassword, AUTH_MODE_LOGIN );
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerLoginMethodPlain( LPCSTR szUsername, LPCSTR szPassword )
+ {
+ BOOL bSuccess = FALSE;
+
+ BYTE szCommandBuffer[ 256 ];
+ sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_PLAIN );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ return FALSE;
+ }
+
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ // Connected. Wait server hello string.
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 334
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 334 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Encode.
+ DWORD dwLoginBuffer = strlen( szUsername ) + strlen( szPassword ) + 3;
+ char *pLoginBuffer = (char*)malloc( dwLoginBuffer );
+ if ( pLoginBuffer )
+ {
+ ZeroMemory( pLoginBuffer, dwLoginBuffer );
+ strcpy( pLoginBuffer + 1, szUsername );
+ strcpy( pLoginBuffer + 1 + strlen( szUsername ) + 1, szPassword );
+
+ Base64Coder coder;
+ coder.Encode( (const PBYTE)pLoginBuffer, dwLoginBuffer - 1 );
+ LPCSTR szLoginBufferEncoded = coder.EncodedMessage();
+
+ if ( szLoginBufferEncoded && strlen( szLoginBufferEncoded ) > 0 )
+ {
+ DWORD dwSendBufferSize = strlen( szLoginBufferEncoded ) + 4;
+ char* pSendBuffer = (char*)malloc( dwSendBufferSize );
+ if ( pSendBuffer )
+ {
+ strcpy( pSendBuffer, szLoginBufferEncoded );
+ strcat( pSendBuffer, "\r\n" );
+
+ if ( SendData( m_hSocket, (PBYTE)pSendBuffer, strlen( (const char*)pSendBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pSendBuffer );
+ free( pLoginBuffer );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( pSendBuffer );
+ }
+ }
+
+ free( pLoginBuffer );
+
+ // check result
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 235
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 235 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ bSuccess = TRUE;
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+
+ free( pReceiveBuffer );
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerLoginMethodLogin( LPCSTR szUsername, LPCSTR szPassword )
+ {
+ BOOL bSuccess = FALSE;
+
+ BYTE szCommandBuffer[ 256 ];
+ sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_LOGIN );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ return FALSE;
+ }
+
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 334
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 334 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Check request
+ if ( iReceived > 6 )
+ {
+ Base64Coder coder;
+ coder.Decode( pReceiveBuffer + 4, iReceived - 6 );
+ LPCSTR szRequest = coder.DecodedMessage();
+ if ( szRequest && strlen( szRequest ) > 0 )
+ {
+ if ( strcmpi( szRequest, "Username:" ) == 0 )
+ {
+ coder.Encode( (const PBYTE)szUsername, strlen( szUsername ) );
+ LPCSTR szUsernameEncoded = coder.EncodedMessage();
+
+ char* szLoginUsernameBuffer = (char*)malloc( strlen( szUsernameEncoded ) + 4 );
+ if ( szLoginUsernameBuffer )
+ {
+ strcpy( szLoginUsernameBuffer, szUsernameEncoded );
+ strcat( szLoginUsernameBuffer, "\r\n" );
+
+ if ( SendData( m_hSocket, (PBYTE)szLoginUsernameBuffer, strlen( (const char*)szLoginUsernameBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( szLoginUsernameBuffer );
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 334
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 334 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Check request
+ if ( iReceived > 6 )
+ {
+ coder.Decode( pReceiveBuffer + 4, iReceived - 6 );
+ LPCSTR szRequest2 = coder.DecodedMessage();
+ if ( szRequest2 && strlen( szRequest2 ) > 0 )
+ {
+ if ( strcmpi( szRequest2, "Password:" ) == 0 )
+ {
+ coder.Encode( (const PBYTE)szPassword, strlen( szPassword ) );
+ LPCSTR szPasswordEncoded = coder.EncodedMessage();
+
+ char* szLoginPasswordBuffer = (char*)malloc( strlen( szPasswordEncoded ) + 4 );
+ if ( szLoginPasswordBuffer )
+ {
+ strcpy( szLoginPasswordBuffer, szPasswordEncoded );
+ strcat( szLoginPasswordBuffer, "\r\n" );
+
+ if ( SendData( m_hSocket, (PBYTE)szLoginPasswordBuffer, strlen( (const char*)szLoginPasswordBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( szLoginPasswordBuffer );
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 235
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 235 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ bSuccess = TRUE;
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( pReceiveBuffer );
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::ServerLoginMethodCramMD5( LPCSTR szUsername, LPCSTR szPassword )
+ {
+ BOOL bSuccess = FALSE;
+
+ BYTE szCommandBuffer[ 256 ];
+ sprintf( (char*)szCommandBuffer, "%s %s\r\n", (char*)SMTP_COMMAND_AUTH, (char*)SMTP_COMMAND_AUTH_CRAM_MD5 );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ return FALSE;
+ }
+
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ // Connected. Wait server hello string.
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 334
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 334 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Check request
+ if ( iReceived > 6 )
+ {
+ Base64Coder coder;
+ coder.Decode( pReceiveBuffer + 4, iReceived - 6 );
+ LPCSTR szResponse = coder.DecodedMessage();
+ if ( szResponse && strlen( szResponse ) > 0 )
+ {
+ char *auth_hex = hash_md5( szPassword, szResponse, strlen(szResponse) );
+ if ( !auth_hex )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ char *szCommand = (char*)malloc( strlen( szUsername ) + strlen( auth_hex ) + 5 );
+ if ( szCommand )
+ {
+ sprintf( szCommand, "%s %s", szUsername, auth_hex );
+
+ free( auth_hex );
+
+ coder.Encode( (const PBYTE)szCommand, strlen( szCommand ) );
+
+ free( szCommand );
+
+ LPCSTR szAuthEncoded = coder.EncodedMessage();
+ if ( szAuthEncoded == NULL )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ char *szAuthCommand = (char*)malloc( strlen( szAuthEncoded ) + 4 );
+ if ( szAuthCommand )
+ {
+ strcpy( szAuthCommand, szAuthEncoded );
+ strcat( szAuthCommand, "\r\n" );
+
+ // Send auth data
+ if ( SendData( m_hSocket, (PBYTE)szAuthCommand, strlen( (const char*)szAuthCommand ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( szAuthCommand );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Check response
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 235
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 235 )
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ bSuccess = TRUE;
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( szAuthCommand );
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ free( auth_hex );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ free( pReceiveBuffer );
+ }
+ else
+ {
+ SetErrorText( "malloc() failed.", GetLastError() );
+ }
+
+ return bSuccess;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ inline BOOL CSMTPClient::SendMessage( LPCSTR szFromAddress, LPCSTR szFromName, LPCSTR szToAddresses, LPCSTR szSubject, LPCSTR szXMailer, LPBYTE pBodyBuffer, DWORD dwBodySize )
+ {
+ BOOL bSuccess = FALSE;
+
+ // Format Header
+ if ( !szFromAddress )
+ {
+ SetErrorText( "SendMessage. Invalid Parameters!" );
+ return NULL;
+ }
+
+ char *szHeaderBuffer = (char*)malloc( 1024 * 16 );
+ if ( szHeaderBuffer )
+ {
+ // get the current date and time
+ char szDate[ 500 ];
+ char sztTime[ 500 ];
+
+ SYSTEMTIME st = { 0 };
+ ::GetSystemTime(&st);
+
+ ::GetDateFormatA( MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, &st, "ddd',' dd MMM yyyy", szDate , sizeof( szDate ) );
+ ::GetTimeFormatA( MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), TIME_FORCE24HOURFORMAT, &st, "HH':'mm':'ss", sztTime, sizeof( sztTime ) );
+
+ sprintf( szHeaderBuffer, "DATE: %s %s\r\n", szDate, sztTime );
+
+ // X-Mailer Field
+ if ( szXMailer && strlen( szXMailer ) )
+ {
+ strcat( szHeaderBuffer, "X-Mailer: " );
+ strcat( szHeaderBuffer, szXMailer );
+ strcat( szHeaderBuffer, "\r\n" );
+ }
+
+ // From:
+ strcat( szHeaderBuffer, "From: " );
+ if ( szFromName )
+ {
+ strcat( szHeaderBuffer, "\"" );
+ strcat( szHeaderBuffer, szFromName );
+ strcat( szHeaderBuffer, "\" <" );
+ strcat( szHeaderBuffer, szFromAddress );
+ strcat( szHeaderBuffer, ">\r\n" );
+ }
+ else
+ {
+ strcat( szHeaderBuffer, "<" );
+ strcat( szHeaderBuffer, szFromAddress );
+ strcat( szHeaderBuffer, ">\r\n" );
+ }
+
+ // Subject:
+ if ( szSubject && strlen( szSubject ) )
+ {
+ strcat( szHeaderBuffer, "Subject: " );
+ strcat( szHeaderBuffer, szSubject );
+ strcat( szHeaderBuffer, "\r\n" );
+ }
+
+ // To Fields
+ strcat( szHeaderBuffer, "To: " );
+ strcat( szHeaderBuffer, szToAddresses );
+ strcat( szHeaderBuffer, "\r\n" );
+
+ // MIME
+ strcat( szHeaderBuffer, "MIME-Version: 1.0\r\nContent-type: text/plain; charset=US-ASCII\r\n" );
+
+ // End Header
+ strcat( szHeaderBuffer, "\r\n" );
+ }
+ else
+ {
+ SetErrorText( "malloc error.", GetLastError() );
+ return FALSE;
+ }
+
+
+ BYTE szCommandBuffer[ 256 ];
+ sprintf( (char*)szCommandBuffer, "MAIL FROM:<%s> SIZE=%u\r\n", (char*)szFromAddress, strlen( szHeaderBuffer ) + dwBodySize + 2 );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ DWORD dwReceiveBufferSize = 1024*16;
+ PBYTE pReceiveBuffer = (PBYTE)malloc( dwReceiveBufferSize );
+ if ( pReceiveBuffer )
+ {
+ DWORD iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 250
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 250 )
+ {
+ free( szHeaderBuffer );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( szHeaderBuffer );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ // Post "RCTP TO:"
+ char *szCurrentAddr = (char*)malloc( strlen( szToAddresses ) + 1 );
+ if ( !szCurrentAddr )
+ {
+ SetErrorText( "malloc error.", GetLastError() );
+ free( szHeaderBuffer );
+ free( pReceiveBuffer );
+ return FALSE;
+ }
+
+ const char* szToOffset = szToAddresses;
+ char* szZap = NULL;
+
+ BOOL bRCPTAccepted = FALSE;
+ do
+ {
+ strcpy( szCurrentAddr, szToOffset );
+ char *szExtractedAdress = szCurrentAddr;
+ szZap = strchr( szCurrentAddr, ',' );
+
+ if ( szZap )
+ {
+ *szZap = 0;
+ szToOffset = szZap + 1;
+ }
+
+ char *pSkobka1 = strchr( szCurrentAddr, '<' );
+ char *pSkobka2 = strchr( szCurrentAddr, '>' );
+
+ if ( pSkobka1 && pSkobka2 && pSkobka2 > pSkobka1 )
+ {
+ szExtractedAdress = pSkobka1 + 1;
+ *pSkobka2 = NULL;
+ }
+
+ if ( szExtractedAdress && strlen( szExtractedAdress ) > 0 )
+ {
+ sprintf( (char*)szCommandBuffer, "RCPT TO:<%s>\r\n", (char*)szExtractedAdress );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( szCurrentAddr );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 250
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode == 250 )
+ {
+ bRCPTAccepted = TRUE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( szCurrentAddr );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+ }
+
+ } while( szZap );
+
+ free( szCurrentAddr );
+
+ if ( bRCPTAccepted )
+ {
+ sprintf( (char*)szCommandBuffer, "DATA\r\n" );
+ if ( SendData( m_hSocket, (PBYTE)szCommandBuffer, strlen( (const char*)szCommandBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 354
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode != 354 )
+ {
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ // Send message data (header + body + .)
+ if ( SendData( m_hSocket, (PBYTE)szHeaderBuffer, strlen( (const char*)szHeaderBuffer ) ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ if ( SendData( m_hSocket, (PBYTE)pBodyBuffer, dwBodySize ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ if ( SendData( m_hSocket, (PBYTE)"\r\n.\r\n", 5 ) == 0 )
+ {
+ SetErrorText( "SendData error.", WSAGetLastError() );
+ free( pReceiveBuffer );
+ free( szHeaderBuffer );
+ return FALSE;
+ }
+
+ iReceived = ReceiveData( m_hSocket, pReceiveBuffer, dwReceiveBufferSize );
+ if ( iReceived )
+ {
+ SetErrorText( pReceiveBuffer );
+
+ // Check 250
+ int iResponseCode = GetResponseCode( pReceiveBuffer, iReceived );
+ if ( iResponseCode == 250 )
+ {
+ bSuccess = TRUE;
+ }
+ }
+ else
+ {
+ SetErrorText( "ReceiveData error.", WSAGetLastError() );
+ }
+ }
+
+ free( pReceiveBuffer );
+ }
+ else
+ {
+ SetErrorText( "malloc error.", GetLastError() );
+ }
+
+ if ( szHeaderBuffer )
+ free( szHeaderBuffer );
+
+ return bSuccess;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+
+
+#ifndef PAGESIZE
+#define PAGESIZE 4096
+#endif
+
+#ifndef ROUNDTOPAGE
+#define ROUNDTOPAGE(a) (((a/4096)+1)*4096)
+#endif
+
+ //////////////////////////////////////////////////////////////////////
+ // Construction/Destruction
+ //////////////////////////////////////////////////////////////////////
+
+ inline Base64Coder::Base64Coder()
+ : m_pDBuffer(NULL),
+ m_pEBuffer(NULL),
+ m_nDBufLen(0),
+ m_nEBufLen(0)
+ {
+
+ }
+
+ inline Base64Coder::~Base64Coder()
+ {
+ if(m_pDBuffer != NULL)
+ delete [] m_pDBuffer;
+
+ if(m_pEBuffer != NULL)
+ delete [] m_pEBuffer;
+ }
+
+ inline LPCSTR Base64Coder::DecodedMessage() const
+ {
+ return (LPCSTR) m_pDBuffer;
+ }
+
+ inline LPCSTR Base64Coder::EncodedMessage() const
+ {
+ return (LPCSTR) m_pEBuffer;
+ }
+
+ inline void Base64Coder::AllocEncode(DWORD nSize)
+ {
+ if(m_nEBufLen < nSize)
+ {
+ if(m_pEBuffer != NULL)
+ delete [] m_pEBuffer;
+
+ m_nEBufLen = ROUNDTOPAGE(nSize);
+ m_pEBuffer = new BYTE[m_nEBufLen];
+ }
+
+ ::ZeroMemory(m_pEBuffer, m_nEBufLen);
+ m_nEDataLen = 0;
+ }
+
+ inline void Base64Coder::AllocDecode(DWORD nSize)
+ {
+ if(m_nDBufLen < nSize)
+ {
+ if(m_pDBuffer != NULL)
+ delete [] m_pDBuffer;
+
+ m_nDBufLen = ROUNDTOPAGE(nSize);
+ m_pDBuffer = new BYTE[m_nDBufLen];
+ }
+
+ ::ZeroMemory(m_pDBuffer, m_nDBufLen);
+ m_nDDataLen = 0;
+ }
+
+ inline void Base64Coder::SetEncodeBuffer(const PBYTE pBuffer, DWORD nBufLen)
+ {
+ DWORD i = 0;
+
+ AllocEncode(nBufLen);
+ while(i < nBufLen)
+ {
+ if(!_IsBadMimeChar(pBuffer[i]))
+ {
+ m_pEBuffer[m_nEDataLen] = pBuffer[i];
+ m_nEDataLen++;
+ }
+
+ i++;
+ }
+ }
+
+ inline void Base64Coder::SetDecodeBuffer(const PBYTE pBuffer, DWORD nBufLen)
+ {
+ AllocDecode(nBufLen);
+ ::CopyMemory(m_pDBuffer, pBuffer, nBufLen);
+ m_nDDataLen = nBufLen;
+ }
+
+ inline void Base64Coder::Encode(const PBYTE pBuffer, DWORD nBufLen)
+ {
+ SetDecodeBuffer(pBuffer, nBufLen);
+ AllocEncode(nBufLen * 2);
+
+ TempBucket Raw;
+ DWORD nIndex = 0;
+
+ while((nIndex + 3) <= nBufLen)
+ {
+ Raw.Clear();
+ ::CopyMemory(&Raw, m_pDBuffer + nIndex, 3);
+ Raw.nSize = 3;
+ _EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen);
+ nIndex += 3;
+ m_nEDataLen += 4;
+ }
+
+ if(nBufLen > nIndex)
+ {
+ Raw.Clear();
+ Raw.nSize = (BYTE) (nBufLen - nIndex);
+ ::CopyMemory(&Raw, m_pDBuffer + nIndex, nBufLen - nIndex);
+ _EncodeToBuffer(Raw, m_pEBuffer + m_nEDataLen);
+ m_nEDataLen += 4;
+ }
+ }
+
+ inline void Base64Coder::Encode(LPCSTR szMessage)
+ {
+ if(szMessage != NULL)
+ Base64Coder::Encode((const PBYTE)szMessage, strlen( (const char*)szMessage));
+ }
+
+ inline void Base64Coder::Decode(const PBYTE pBuffer, DWORD dwBufLen)
+ {
+ if(is_init())
+ _Init();
+
+ SetEncodeBuffer(pBuffer, dwBufLen);
+
+ AllocDecode(dwBufLen);
+
+ TempBucket Raw;
+
+ DWORD nIndex = 0;
+
+ while((nIndex + 4) <= m_nEDataLen)
+ {
+ Raw.Clear();
+ Raw.nData[0] = DecodeTable()[m_pEBuffer[nIndex]];
+ Raw.nData[1] = DecodeTable()[m_pEBuffer[nIndex + 1]];
+ Raw.nData[2] = DecodeTable()[m_pEBuffer[nIndex + 2]];
+ Raw.nData[3] = DecodeTable()[m_pEBuffer[nIndex + 3]];
+
+ if(Raw.nData[2] == 255)
+ Raw.nData[2] = 0;
+ if(Raw.nData[3] == 255)
+ Raw.nData[3] = 0;
+
+ Raw.nSize = 4;
+ _DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen);
+ nIndex += 4;
+ m_nDDataLen += 3;
+ }
+
+ // If nIndex < m_nEDataLen, then we got a decode message without padding.
+ // We may want to throw some kind of warning here, but we are still required
+ // to handle the decoding as if it was properly padded.
+ if(nIndex < m_nEDataLen)
+ {
+ Raw.Clear();
+ for(DWORD i = nIndex; i < m_nEDataLen; i++)
+ {
+ Raw.nData[i - nIndex] = DecodeTable()[m_pEBuffer[i]];
+ Raw.nSize++;
+ if(Raw.nData[i - nIndex] == 255)
+ Raw.nData[i - nIndex] = 0;
+ }
+
+ _DecodeToBuffer(Raw, m_pDBuffer + m_nDDataLen);
+ m_nDDataLen += (m_nEDataLen - nIndex);
+ }
+ }
+
+ inline void Base64Coder::Decode(LPCSTR szMessage)
+ {
+ if(szMessage != NULL)
+ Base64Coder::Decode((const PBYTE)szMessage, strlen((const char*)szMessage));
+ }
+
+ inline DWORD Base64Coder::_DecodeToBuffer(const TempBucket &Decode, PBYTE pBuffer)
+ {
+ TempBucket Data;
+ DWORD nCount = 0;
+
+ _DecodeRaw(Data, Decode);
+
+ for(int i = 0; i < 3; i++)
+ {
+ pBuffer[i] = Data.nData[i];
+ if(pBuffer[i] != 255)
+ nCount++;
+ }
+
+ return nCount;
+ }
+
+
+ inline void Base64Coder::_EncodeToBuffer(const TempBucket &Decode, PBYTE pBuffer)
+ {
+ TempBucket Data;
+
+ _EncodeRaw(Data, Decode);
+
+ for(int i = 0; i < 4; i++)
+ pBuffer[i] = Base64Digits()[Data.nData[i]];
+
+ switch(Decode.nSize)
+ {
+ case 1:
+ pBuffer[2] = '=';
+ case 2:
+ pBuffer[3] = '=';
+ }
+ }
+
+ inline void Base64Coder::_DecodeRaw(TempBucket &Data, const TempBucket &Decode)
+ {
+ BYTE nTemp;
+
+ Data.nData[0] = Decode.nData[0];
+ Data.nData[0] <<= 2;
+
+ nTemp = Decode.nData[1];
+ nTemp >>= 4;
+ nTemp &= 0x03;
+ Data.nData[0] |= nTemp;
+
+ Data.nData[1] = Decode.nData[1];
+ Data.nData[1] <<= 4;
+
+ nTemp = Decode.nData[2];
+ nTemp >>= 2;
+ nTemp &= 0x0F;
+ Data.nData[1] |= nTemp;
+
+ Data.nData[2] = Decode.nData[2];
+ Data.nData[2] <<= 6;
+ nTemp = Decode.nData[3];
+ nTemp &= 0x3F;
+ Data.nData[2] |= nTemp;
+ }
+
+ inline void Base64Coder::_EncodeRaw(TempBucket &Data, const TempBucket &Decode)
+ {
+ BYTE nTemp;
+
+ Data.nData[0] = Decode.nData[0];
+ Data.nData[0] >>= 2;
+
+ Data.nData[1] = Decode.nData[0];
+ Data.nData[1] <<= 4;
+ nTemp = Decode.nData[1];
+ nTemp >>= 4;
+ Data.nData[1] |= nTemp;
+ Data.nData[1] &= 0x3F;
+
+ Data.nData[2] = Decode.nData[1];
+ Data.nData[2] <<= 2;
+
+ nTemp = Decode.nData[2];
+ nTemp >>= 6;
+
+ Data.nData[2] |= nTemp;
+ Data.nData[2] &= 0x3F;
+
+ Data.nData[3] = Decode.nData[2];
+ Data.nData[3] &= 0x3F;
+ }
+
+ inline BOOL Base64Coder::_IsBadMimeChar(BYTE nData)
+ {
+ switch(nData)
+ {
+ case '\r': case '\n': case '\t': case ' ' :
+ case '\b': case '\a': case '\f': case '\v':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+
+ inline void Base64Coder::_Init()
+ { // Initialize Decoding table.
+
+ int i;
+
+ for(i = 0; i < 256; i++)
+ DecodeTable()[i] = -2;
+
+ for(i = 0; i < 64; i++)
+ {
+ DecodeTable()[Base64Digits()[i]] = i;
+ DecodeTable()[Base64Digits()[i]|0x80] = i;
+ }
+
+ DecodeTable()['='] = -1;
+ DecodeTable()['='|0x80] = -1;
+
+ is_init() = TRUE;
+ }
+
+
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/net/smtp_helper.h b/contrib/epee/include/net/smtp_helper.h
new file mode 100644
index 000000000..b8252e1cf
--- /dev/null
+++ b/contrib/epee/include/net/smtp_helper.h
@@ -0,0 +1,88 @@
+// 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 "smtp.h"
+
+namespace epee
+{
+namespace net_utils
+{
+ namespace smtp
+ {
+
+ inline bool send_mail(const std::string& server, int port, const std::string& login, const std::string& pass, const std::string& from_addres, const std::string& from_name, const std::string& maillist, const std::string& subject, const std::string& mail_body)
+ {
+ net_utils::smtp::CSMTPClient smtp;
+
+ if ( !smtp.ServerConnect( server.c_str(), port ) )
+ {
+ LOG_PRINT("Reporting: Failed to connect to server " << server <<":"<< port, LOG_LEVEL_0);
+ return false;
+ }
+
+ if(login.size() && pass.size())
+ {
+ if ( !smtp.ServerLogin( login.c_str(), pass.c_str()) )
+ {
+ LOG_PRINT("Reporting: Failed to auth on server " << server <<":"<< port, LOG_LEVEL_0);
+ return false;
+
+ }
+ }
+
+ if ( !smtp.SendMessage( from_addres.c_str(),
+ from_name.c_str(),
+ maillist.c_str(),
+ subject.c_str(),
+ "bicycle-client",
+ (LPBYTE)mail_body.data(),
+ mail_body.size()))
+ {
+ char *szErrorText = smtp.GetLastErrorText();
+ if ( szErrorText )
+ {
+ LOG_PRINT("Failed to send message, error text: " << szErrorText, LOG_LEVEL_0);
+ }
+ else
+ {
+ LOG_PRINT("Failed to send message, error text: null", LOG_LEVEL_0);
+ }
+ return false;
+ }
+
+ smtp.ServerDisconnect();
+
+ return true;
+
+
+ }
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/pragma_comp_defs.h b/contrib/epee/include/pragma_comp_defs.h
new file mode 100644
index 000000000..f4ef7057e
--- /dev/null
+++ b/contrib/epee/include/pragma_comp_defs.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#if defined(__GNUC__)
+ #define PRAGMA_WARNING_PUSH _Pragma("GCC diagnostic push")
+ #define PRAGMA_WARNING_POP _Pragma("GCC diagnostic pop")
+ #define PRAGMA_WARNING_DISABLE_VS(w)
+ #define PRAGMA_GCC(w) _Pragma(w)
+#elif defined(_MSC_VER)
+ #define PRAGMA_WARNING_PUSH __pragma(warning( push ))
+ #define PRAGMA_WARNING_POP __pragma(warning( pop ))
+ #define PRAGMA_WARNING_DISABLE_VS(w) __pragma( warning ( disable: w ))
+ //#define PRAGMA_WARNING_DISABLE_GCC(w)
+ #define PRAGMA_GCC(w)
+#endif
diff --git a/contrib/epee/include/profile_tools.h b/contrib/epee/include/profile_tools.h
new file mode 100644
index 000000000..ff925ea86
--- /dev/null
+++ b/contrib/epee/include/profile_tools.h
@@ -0,0 +1,111 @@
+// 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 _PROFILE_TOOLS_H_
+#define _PROFILE_TOOLS_H_
+
+namespace epee
+{
+
+#ifdef ENABLE_PROFILING
+#define PROFILE_FUNC(immortal_ptr_str) static profile_tools::local_call_account lcl_acc(immortal_ptr_str); \
+ profile_tools::call_frame cf(lcl_acc);
+
+#define PROFILE_FUNC_SECOND(immortal_ptr_str) static profile_tools::local_call_account lcl_acc2(immortal_ptr_str); \
+ profile_tools::call_frame cf2(lcl_acc2);
+
+#define PROFILE_FUNC_THIRD(immortal_ptr_str) static profile_tools::local_call_account lcl_acc3(immortal_ptr_str); \
+ profile_tools::call_frame cf3(lcl_acc3);
+
+#define PROFILE_FUNC_ACC(acc) \
+ profile_tools::call_frame cf(acc);
+
+
+#else
+#define PROFILE_FUNC(immortal_ptr_str)
+#define PROFILE_FUNC_SECOND(immortal_ptr_str)
+#define PROFILE_FUNC_THIRD(immortal_ptr_str)
+#endif
+
+#define START_WAY_POINTS() boost::uint64_t _____way_point_time = misc_utils::get_tick_count();
+#define WAY_POINT(name) {boost::uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();}
+#define WAY_POINT2(name, avrg_obj) {boost::uint64_t delta = misc_utils::get_tick_count()-_____way_point_time; avrg_obj.push(delta); LOG_PRINT("Way point " << name << ": " << delta, LOG_LEVEL_2);_____way_point_time = misc_utils::get_tick_count();}
+
+
+#define TIME_MEASURE_START(var_name) boost::uint64_t var_name = misc_utils::get_tick_count();
+#define TIME_MEASURE_FINISH(var_name) var_name = misc_utils::get_tick_count() - var_name;
+
+namespace profile_tools
+{
+ struct local_call_account
+ {
+ local_call_account(const char* pstr):m_count_of_call(0), m_summary_time_used(0),m_pname(pstr)
+ {}
+ ~local_call_account()
+ {
+ LOG_PRINT2("profile_details.log", "PROFILE "<<m_pname<<":av_time:\t" << (m_count_of_call ? (m_summary_time_used/m_count_of_call):0) <<" sum_time:\t"<<m_summary_time_used<<" call_count:\t" << m_count_of_call, LOG_LEVEL_0);
+ }
+
+ size_t m_count_of_call;
+ boost::uint64_t m_summary_time_used;
+ const char* m_pname;
+ };
+
+ struct call_frame
+ {
+
+ call_frame(local_call_account& cc):m_cc(cc)
+ {
+ cc.m_count_of_call++;
+ m_call_time = boost::posix_time::microsec_clock::local_time();
+ //::QueryPerformanceCounter((LARGE_INTEGER *)&m_call_time);
+ }
+
+ ~call_frame()
+ {
+ //__int64 ret_time = 0;
+
+ boost::posix_time::ptime now_t(boost::posix_time::microsec_clock::local_time());
+ boost::posix_time::time_duration delta_microsec = now_t - m_call_time;
+ boost::uint64_t miliseconds_used = delta_microsec.total_microseconds();
+
+ //::QueryPerformanceCounter((LARGE_INTEGER *)&ret_time);
+ //m_call_time = (ret_time-m_call_time)/1000;
+ m_cc.m_summary_time_used += miliseconds_used;
+ }
+
+ private:
+ local_call_account& m_cc;
+ boost::posix_time::ptime m_call_time;
+ };
+
+
+}
+}
+
+
+#endif //_PROFILE_TOOLS_H_
diff --git a/contrib/epee/include/reg_exp_definer.h b/contrib/epee/include/reg_exp_definer.h
new file mode 100644
index 000000000..b05e1a9ae
--- /dev/null
+++ b/contrib/epee/include/reg_exp_definer.h
@@ -0,0 +1,84 @@
+// 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 _REG_EXP_DEFINER_H_
+#define _REG_EXP_DEFINER_H_
+
+#include <boost/interprocess/detail/atomic.hpp>
+
+
+namespace epee
+{
+ class global_regexp_critical_section
+ {
+ private:
+ mutable critical_section regexp_lock;
+ public:
+ global_regexp_critical_section(){}
+ critical_section& get_lock()const {return regexp_lock;}
+ };
+
+ const static global_regexp_critical_section gregexplock;
+
+#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags) \
+ static volatile boost::uint32_t regexp_initialized_1 = 0;\
+ volatile boost::uint32_t local_is_initialized_1 = regexp_initialized_1;\
+ if(!local_is_initialized_1)\
+ gregexplock.get_lock().lock();\
+ static const boost::regex var_name(xpr_text , reg_exp_flags);\
+ if(!local_is_initialized_1)\
+{\
+ boost::interprocess::ipcdetail::atomic_write32(&regexp_initialized_1, 1);\
+ gregexplock.get_lock().unlock();\
+}
+
+#define STATIC_REGEXP_EXPR_2(var_name, xpr_text, reg_exp_flags) \
+ static volatile boost::uint32_t regexp_initialized_2 = 0;\
+ volatile boost::uint32_t local_is_initialized_2 = regexp_initialized_2;\
+ if(!local_is_initialized_2)\
+ gregexplock.get_lock().lock().lock();\
+ static const boost::regex var_name(xpr_text , reg_exp_flags);\
+ if(!local_is_initialized_2)\
+{\
+ boost::interprocess::ipcdetail::atomic_write32(&regexp_initialized_2, 1);\
+ gregexplock.get_lock().lock().unlock();\
+}
+
+#define STATIC_REGEXP_EXPR_3(var_name, xpr_text, reg_exp_flags) \
+ static volatile boost::uint32_t regexp_initialized_3 = 0;\
+ volatile boost::uint32_t local_is_initialized_3 = regexp_initialized_3;\
+ if(!local_is_initialized_3)\
+ gregexplock.get_lock().lock().lock();\
+ static const boost::regex var_name(xpr_text , reg_exp_flags);\
+ if(!local_is_initialized_3)\
+{\
+ boost::interprocess::ipcdetail::atomic_write32(&regexp_initialized_3, 1);\
+ gregexplock.get_lock().lock().unlock();\
+}
+}
+
+#endif //_REG_EXP_DEFINER_H_
diff --git a/contrib/epee/include/reg_utils.h b/contrib/epee/include/reg_utils.h
new file mode 100644
index 000000000..22227a9b2
--- /dev/null
+++ b/contrib/epee/include/reg_utils.h
@@ -0,0 +1,249 @@
+// 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 _MUSC_UTILS_EX_H_
+#define _MUSC_UTILS_EX_H_
+
+namespace epee
+{
+namespace reg_utils
+{
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class T>
+ bool RegSetPODValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const T& valToSave, bool force_create = true)
+ {
+ HKEY hRegKey = 0;
+ DWORD dw = 0;
+
+ if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS )
+ if(force_create && (::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS) )
+ return false;
+
+
+ DWORD val_type = (sizeof(valToSave) == sizeof(DWORD)) ? REG_DWORD:REG_BINARY;
+
+ BOOL res = ::RegSetValueExA( hRegKey, pValName, 0, val_type, (LPBYTE)&valToSave, sizeof(valToSave)) == ERROR_SUCCESS;
+
+ ::RegCloseKey(hRegKey);
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class T>
+ bool RegGetPODValue(HKEY hParentKey, const char* pSubKey, const char* pValName, T& valToSave)
+ {
+ HKEY hRegKey = 0;
+ LONG res = 0;
+
+
+ if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS )
+ {
+ DWORD dwType, lSize = 0;
+ res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, NULL, &lSize);
+ if(ERROR_SUCCESS!=res || (sizeof(valToSave) < lSize) )
+ {
+ ::RegCloseKey(hRegKey);
+ return false;
+ }
+ res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, (LPBYTE)&valToSave, &lSize);
+ }
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ inline
+ bool RegSetANSIString(HKEY hParentKey, const char* pSubKey, const char* pValName, const std::string& strToSave)
+ {
+ HKEY hRegKey = 0;
+ DWORD dw = 0;
+ DWORD res_ = 0;
+ if( (res_ = ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw)) != ERROR_SUCCESS )
+ if( (res_= ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey)) != ERROR_SUCCESS )
+ return false;
+
+ DWORD valType = REG_SZ;
+ const char* pStr = strToSave.c_str();
+ DWORD sizeOfStr = (DWORD)strToSave.size()+1;
+ LSTATUS res = ::RegSetValueExA(hRegKey, pValName, 0, valType, (LPBYTE)pStr, sizeOfStr);
+
+ ::RegCloseKey(hRegKey);
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ inline
+ bool RegGetANSIString(HKEY hParentKey, const char* pSubKey, const char* pValName, std::string& strToSave)
+ {
+ HKEY hRegKey = 0;
+ LONG res = 0;
+
+
+ if((res = ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey)) == ERROR_SUCCESS )
+ {
+ DWORD dwType, lSize = 0;
+ res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, NULL, &lSize);
+ if(ERROR_SUCCESS!=res)
+ {
+
+ ::RegCloseKey(hRegKey);
+ return false;
+ }
+ char* pTmpStr = new char[lSize+2];
+ memset(pTmpStr, 0, lSize+2);
+ res = ::RegQueryValueExA(hRegKey, pValName, 0, &dwType, (LPBYTE)pTmpStr, &lSize);
+ pTmpStr[lSize+1] = 0; //be happy ;)
+ strToSave = pTmpStr;
+ delete [] pTmpStr;
+ ::RegCloseKey(hRegKey);
+ }
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class TMemoryObject>
+ bool RegSetRAWValue(HKEY hKey, const char* pValName, const TMemoryObject& valToSave, DWORD valType = REG_BINARY)
+ {
+ LONG res = ::RegSetValueExA( hKey, pValName, 0, valType, (CONST BYTE*)valToSave.get(0), (DWORD)valToSave.get_size());
+
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //----------------------------------------------------------------------------------------------------------------------------------
+ bool RegSetRAWValue(HKEY hKey, const char* pValName, const std::string & valToSave, DWORD valType = REG_BINARY)
+ {
+ LONG res = ::RegSetValueExA( hKey, pValName, 0, valType, (CONST BYTE*)valToSave.data(), (DWORD)valToSave.size());
+
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class TMemoryObject>
+ bool RegGetRAWValue(HKEY hKey, const char* pValName, TMemoryObject& valToSave, DWORD* pRegType)
+ {
+ DWORD dwType, lSize = 0;
+ LONG res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, NULL, &lSize);
+ if(ERROR_SUCCESS!=res || 0 >= lSize)
+ {
+ valToSave.release();
+ return false;
+ }
+ if(valToSave.get_size() < lSize)
+ valToSave.alloc_buff(lSize);
+ res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, (LPBYTE)valToSave.get(0), &lSize);
+ if(pRegType) *pRegType = dwType;
+
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ bool RegGetRAWValue(HKEY hKey, const char* pValName, std::string& valToSave, DWORD* pRegType)
+ {
+ DWORD dwType, lSize = 0;
+ LONG res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, NULL, &lSize);
+ if(ERROR_SUCCESS!=res || 0 >= lSize)
+ {
+ return false;
+ }
+
+ valToSave.resize(lSize);
+ res = ::RegQueryValueExA(hKey, pValName, 0, &dwType, (LPBYTE)valToSave.data(), &lSize);
+ if(pRegType) *pRegType = dwType;
+
+ return ERROR_SUCCESS==res ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class TMemoryObject>
+ bool RegSetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const TMemoryObject& valToSave, DWORD valType = REG_BINARY)
+ {
+ HKEY hRegKey = 0;
+ DWORD dw = 0;
+ bool res = false;
+
+ if( ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS )
+ if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS )
+ return false;
+
+ res = RegSetRAWValue(hRegKey, pValName, valToSave, valType);
+
+ ::RegCloseKey(hRegKey);
+ return res;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ bool RegSetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, const std::string& valToSave, DWORD valType = REG_BINARY)
+ {
+ HKEY hRegKey = 0;
+ DWORD dw = 0;
+ bool res = false;
+
+ if( ::RegCreateKeyExA(hParentKey, pSubKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRegKey, &dw) != ERROR_SUCCESS )
+ if( ::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_WRITE, &hRegKey) != ERROR_SUCCESS )
+ return false;
+
+ res = RegSetRAWValue(hRegKey, pValName, valToSave, valType);
+
+ ::RegCloseKey(hRegKey);
+ return res;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ template<class TMemoryObject>
+ bool RegGetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, TMemoryObject& valToSave, DWORD* pRegType)
+ {
+ HKEY hRegKey = 0;
+ bool res = false;
+
+ if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS )
+ {
+ res = RegGetRAWValue(hRegKey, pValName, valToSave, pRegType);
+ ::RegCloseKey(hRegKey);
+ }
+ return res;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ inline
+ bool RegGetRAWValue(HKEY hParentKey, const char* pSubKey, const char* pValName, std::string& valToSave, DWORD* pRegType)
+ {
+ HKEY hRegKey = 0;
+ bool res = false;
+
+ if(::RegOpenKeyExA(hParentKey, pSubKey, 0, KEY_READ, &hRegKey) == ERROR_SUCCESS )
+ {
+ res = RegGetRAWValue(hRegKey, pValName, valToSave, pRegType);
+ ::RegCloseKey(hRegKey);
+ }
+ return res;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ inline
+ bool RegRemoveValue(HKEY hParentKey, const char* pValName)
+ {
+ //CHECK_AND_ASSERT(hParentKey&&pValName, false);
+ return ::RegDeleteValueA(hParentKey, pValName)==ERROR_SUCCESS ? true:false;
+ }
+ //-----------------------------------------------------------------------------------------------------------------------------------
+ inline
+ bool RegRemoveKey(HKEY hParentKey, const char* pKeyName)
+ {
+ //CHECK_AND_ASSERT(hParentKey&&pKeyName, false);
+ return ::RegDeleteKeyA(hParentKey, pKeyName)==ERROR_SUCCESS ? true:false;
+ }
+
+}
+}
+#endif //_MUSC_UTILS_EX_H_
diff --git a/contrib/epee/include/serialization/enableable.h b/contrib/epee/include/serialization/enableable.h
new file mode 100644
index 000000000..ab1d799e6
--- /dev/null
+++ b/contrib/epee/include/serialization/enableable.h
@@ -0,0 +1,53 @@
+// 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
+
+namespace epee
+{
+
+ template<class t_obj>
+ struct enableable
+ {
+ t_obj v;
+ bool enabled;
+
+ enableable()
+ : v(t_obj()), enabled(true)
+ { // construct from defaults
+ }
+
+ enableable(const t_obj& _v)
+ : v(_v), enabled(true)
+ { // construct from specified values
+ }
+
+ enableable(const enableable<t_obj>& _v)
+ : v(_v.v), enabled(_v.enabled)
+ { // construct from specified values
+ }
+ };
+} \ No newline at end of file
diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h
new file mode 100644
index 000000000..27fb0f1e2
--- /dev/null
+++ b/contrib/epee/include/serialization/keyvalue_serialization.h
@@ -0,0 +1,92 @@
+// 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 <boost/utility/value_init.hpp>
+#include <boost/foreach.hpp>
+#include "misc_log_ex.h"
+#include "enableable.h"
+#include "keyvalue_serialization_overloads.h"
+namespace epee
+{
+ /************************************************************************/
+ /* Serialize map declarations */
+ /************************************************************************/
+#define BEGIN_KV_SERIALIZE_MAP() \
+public: \
+ template<class t_storage> \
+ bool store( t_storage& st, typename t_storage::hsection hparent_section = nullptr) const\
+ {\
+ return serialize_map<true>(*this, st, hparent_section);\
+ }\
+ template<class t_storage> \
+ bool _load( t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\
+ {\
+ return serialize_map<false>(*this, stg, hparent_section);\
+ }\
+ template<class t_storage> \
+ bool load( t_storage& stg, typename t_storage::hsection hparent_section = nullptr)\
+ {\
+ try{\
+ return serialize_map<false>(*this, stg, hparent_section);\
+ }\
+ catch(const std::exception& err) \
+ { \
+ (void)(err); \
+ LOG_ERROR("Exception on unserializing: " << err.what());\
+ return false; \
+ }\
+ }\
+ template<bool is_store, class this_type, class t_storage> \
+ static bool serialize_map(this_type& this_ref, t_storage& stg, typename t_storage::hsection hparent_section) \
+ {
+
+#define KV_SERIALIZE_N(varialble, val_name) \
+ epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name);
+
+#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
+ epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
+
+#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \
+ static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
+ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
+
+#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
+ epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
+
+#define END_KV_SERIALIZE_MAP() return true;}
+
+#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
+#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
+#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
+#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
+
+}
+
+
+
+
diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
new file mode 100644
index 000000000..2ad9a82a4
--- /dev/null
+++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
@@ -0,0 +1,366 @@
+// 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
+
+namespace epee
+{
+ namespace serialization
+ {
+
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool serialize_t_val(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return stg.set_value(pname, d, hparent_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool unserialize_t_val(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return stg.get_value(pname, d, hparent_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ std::string blob((const char *)&d, sizeof(d));
+ return stg.set_value(pname, blob, hparent_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool unserialize_t_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ std::string blob;
+ if(!stg.get_value(pname, blob, hparent_section))
+ return false;
+ CHECK_AND_ASSERT_MES(blob.size() == sizeof(d), false, "unserialize_t_val_as_blob: size of " << typeid(t_type).name() << " = " << sizeof(t_type) << ", but stored blod size = " << blob.size() << ", value name = " << pname);
+ d = *(const t_type*)blob.data();
+ return true;
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class serializible_type, class t_storage>
+ static bool serialize_t_obj(const serializible_type& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true);
+ CHECK_AND_ASSERT_MES(hchild_section, false, "serialize_t_obj: failed to open/create section " << pname);
+ return obj.store(stg, hchild_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class serializible_type, class t_storage>
+ static bool unserialize_t_obj(serializible_type& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true);
+ if(!hchild_section) return false;
+ return obj._load(stg, hchild_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class serializible_type, class t_storage>
+ static bool serialize_t_obj(enableable<serializible_type>& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ if(!obj.enabled)
+ return true;
+ return serialize_t_obj(obj.v, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class serializible_type, class t_storage>
+ static bool unserialize_t_obj(enableable<serializible_type>& obj, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ obj.enabled = false;
+ typename t_storage::hsection hchild_section = stg.open_section(pname, hparent_section, true);
+ if(!hchild_section) return false;
+ obj.enabled = true;
+ return obj.v._load(stg, hchild_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool serialize_stl_container_t_val (const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ if(!container.size()) return true;
+ typename stl_container::const_iterator it = container.begin();
+ typename t_storage::harray hval_array = stg.insert_first_value(pname, *it, hparent_section);
+ CHECK_AND_ASSERT_MES(hval_array, false, "failed to insert first value to storage");
+ it++;
+ for(;it!= container.end();it++)
+ stg.insert_next_value(hval_array, *it);
+
+ return true;
+ }
+ //--------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool unserialize_stl_container_t_val(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ container.clear();
+ typename stl_container::value_type exchange_val;
+ typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section);
+ if(!hval_array) return false;
+ container.push_back(std::move(exchange_val));
+ while(stg.get_next_value(hval_array, exchange_val))
+ container.push_back(std::move(exchange_val));
+ return true;
+ }//--------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ if(!container.size()) return true;
+ typename stl_container::const_iterator it = container.begin();
+ std::string mb;
+ mb.resize(sizeof(typename stl_container::value_type)*container.size());
+ typename stl_container::value_type* p_elem = (typename stl_container::value_type*)mb.data();
+ BOOST_FOREACH(const typename stl_container::value_type& v, container)
+ {
+ *p_elem = v;
+ p_elem++;
+ }
+ return stg.set_value(pname, mb, hparent_section);
+ }
+ //--------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ container.clear();
+ std::string buff;
+ bool res = stg.get_value(pname, buff, hparent_section);
+ if(res)
+ {
+ size_t loaded_size = buff.size();
+ typename stl_container::value_type* pelem = (typename stl_container::value_type*)buff.data();
+ CHECK_AND_ASSERT_MES(!(loaded_size%sizeof(typename stl_container::value_type)),
+ false,
+ "size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
+ size_t count = (loaded_size/sizeof(typename stl_container::value_type));
+ for(size_t i = 0; i < count; i++)
+ container.push_back(*(pelem++));
+ }
+ return res;
+ }
+ //--------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool serialize_stl_container_t_obj (const stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ bool res = false;
+ if(!container.size()) return true;
+ typename stl_container::const_iterator it = container.begin();
+ typename t_storage::hsection hchild_section = nullptr;
+ typename t_storage::harray hsec_array = stg.insert_first_section(pname, hchild_section, hparent_section);
+ CHECK_AND_ASSERT_MES(hsec_array && hchild_section, false, "failed to insert first section with section name " << pname);
+ res = it->store(stg, hchild_section);
+ it++;
+ for(;it!= container.end();it++)
+ {
+ stg.insert_next_section(hsec_array, hchild_section);
+ res |= it->store(stg, hchild_section);
+ }
+ return res;
+ }
+ //--------------------------------------------------------------------------------------------------------------------
+ template<class stl_container, class t_storage>
+ static bool unserialize_stl_container_t_obj(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ bool res = false;
+ container.clear();
+ typename stl_container::value_type val = typename stl_container::value_type();
+ typename t_storage::hsection hchild_section = nullptr;
+ typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section);
+ if(!hsec_array || !hchild_section) return false;
+ res = val._load(stg, hchild_section);
+ container.push_back(val);
+ while(stg.get_next_section(hsec_array, hchild_section))
+ {
+ typename stl_container::value_type val_l = typename stl_container::value_type();
+ res |= val_l._load(stg, hchild_section);
+ container.push_back(std::move(val_l));
+ }
+ return res;
+ }
+ //--------------------------------------------------------------------------------------------------------------------
+ template<bool>
+ struct kv_serialization_overloads_impl_is_base_serializable_types;
+
+ template<>
+ struct kv_serialization_overloads_impl_is_base_serializable_types<true>
+ {
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return stg.set_value(pname, d, hparent_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return stg.get_value(pname, d, hparent_section);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ };
+ template<>
+ struct kv_serialization_overloads_impl_is_base_serializable_types<false>
+ {
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_t_obj(d, stg, hparent_section, pname);
+ }
+
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ };
+ typedef boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string>::type base_serializable_types;
+ //-------------------------------------------------------------------------------------------------------------------
+ template<bool> struct selector;
+ template<>
+ struct selector<true>
+ {
+ template<class t_type, class t_storage>
+ static bool serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialize(d, stg, hparent_section, pname);
+ }
+
+ template<class t_type, class t_storage>
+ static bool serialize_stl_container_pod_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return epee::serialization::serialize_stl_container_pod_val_as_blob(d, stg, hparent_section, pname);
+ }
+
+ template<class t_type, class t_storage>
+ static bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return epee::serialization::serialize_t_val_as_blob(d, stg, hparent_section, pname);
+ }
+
+
+ };
+ template<>
+ struct selector<false>
+ {
+ template<class t_type, class t_storage>
+ static bool serialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_unserialize(d, stg, hparent_section, pname);
+ }
+ template<class t_type, class t_storage>
+ static bool serialize_stl_container_pod_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return epee::serialization::unserialize_stl_container_pod_val_as_blob(d, stg, hparent_section, pname);
+ }
+
+ template<class t_type, class t_storage>
+ static bool serialize_t_val_as_blob(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return epee::serialization::unserialize_t_val_as_blob(d, stg, hparent_section, pname);
+ }
+ };
+
+ template<class t_type, class t_storage>
+ bool kv_serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_unserialize(t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_serialize(const std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_unserialize(std::vector<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_serialize(const std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_unserialize(std::list<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/serialization/serialize_base.h b/contrib/epee/include/serialization/serialize_base.h
new file mode 100644
index 000000000..84a1624cb
--- /dev/null
+++ b/contrib/epee/include/serialization/serialize_base.h
@@ -0,0 +1,2 @@
+#pragma once
+
diff --git a/contrib/epee/include/service_impl_base.h b/contrib/epee/include/service_impl_base.h
new file mode 100644
index 000000000..6e9aefc46
--- /dev/null
+++ b/contrib/epee/include/service_impl_base.h
@@ -0,0 +1,323 @@
+// 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 _SERVICE_IMPL_BASE_H_
+#define _SERVICE_IMPL_BASE_H_
+
+#pragma comment(lib, "advapi32.lib")
+
+
+namespace epee
+{
+class service_impl_base {
+ public:
+ service_impl_base();
+ virtual ~service_impl_base();
+
+ virtual const char *get_name() = 0;
+ virtual const char *get_caption() = 0;
+ virtual const char *get_description() = 0;
+
+ bool run_service();
+ virtual bool install();
+ virtual bool remove();
+ virtual bool init();
+ void set_control_accepted(unsigned controls);
+ void set_status(unsigned state, unsigned pending = 0);
+ unsigned get_control_accepted();
+
+ private:
+ virtual void service_main() = 0;
+ virtual unsigned service_handler(unsigned control, unsigned event_code,
+ void *pdata) = 0;
+ //-------------------------------------------------------------------------
+ static service_impl_base*& instance();
+ //-------------------------------------------------------------------------
+ static DWORD __stdcall _service_handler(DWORD control, DWORD event,
+ void *pdata, void *pcontext);
+ static void __stdcall service_entry(DWORD argc, char **pargs);
+ virtual SERVICE_FAILURE_ACTIONSA* get_failure_actions();
+
+ private:
+ SC_HANDLE m_manager;
+ SC_HANDLE m_service;
+ SERVICE_STATUS_HANDLE m_status_handle;
+ DWORD m_accepted_control;
+};
+
+inline service_impl_base::service_impl_base() {
+ m_manager = 0;
+ m_service = 0;
+ m_status_handle = 0;
+ m_accepted_control = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN
+ | SERVICE_ACCEPT_PAUSE_CONTINUE;
+
+ instance() = this;
+}
+//-----------------------------------------------------------------------------
+inline service_impl_base::~service_impl_base() {
+ if (m_service) {
+ ::CloseServiceHandle(m_service);
+ }
+ m_service = 0;
+ if (m_manager) {
+ ::CloseServiceHandle(m_manager);
+ }
+ m_manager = 0;
+ instance() = 0;
+}
+//-----------------------------------------------------------------------------
+inline service_impl_base*& service_impl_base::instance() {
+ static service_impl_base *pservice = NULL;
+ return pservice;
+}
+//-----------------------------------------------------------------------------
+inline
+bool service_impl_base::install() {
+ CHECK_AND_ASSERT(!m_service, false);
+ const char *psz_descr = get_description();
+ SERVICE_FAILURE_ACTIONSA* fail_acts = get_failure_actions();
+
+ char sz_path[MAX_PATH];
+ ::GetModuleFileNameA(0, sz_path, sizeof(sz_path));
+ ::GetShortPathNameA(sz_path, sz_path, sizeof(sz_path));
+
+ while (TRUE) {
+ if (!m_manager) {
+ m_manager = ::OpenSCManager(NULL, NULL, GENERIC_ALL);
+ if (!m_manager) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to OpenSCManager(), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+ m_service = ::CreateServiceA(m_manager, get_name(), get_caption(),
+ SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
+ SERVICE_ERROR_IGNORE, sz_path, 0, 0, 0, 0, 0);
+ if (!m_service) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to CreateService(), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+
+ if (psz_descr) {
+ SERVICE_DESCRIPTIONA sd = { (char*) psz_descr };
+ if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_DESCRIPTION,
+ &sd)) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to ChangeServiceConfig2(SERVICE_CONFIG_DESCRIPTION), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+
+ if (fail_acts) {
+ if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_FAILURE_ACTIONS,
+ fail_acts)) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to ChangeServiceConfig2(SERVICE_CONFIG_FAILURE_ACTIONS), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+ LOG_PRINT("Installed succesfully.", LOG_LEVEL_0);
+ return true;
+ }
+ LOG_PRINT("Failed to install.", LOG_LEVEL_0);
+ return false;
+}
+//-----------------------------------------------------------------------------
+inline
+bool service_impl_base::remove() {
+ CHECK_AND_ASSERT(!m_service, false);
+
+ while (TRUE) {
+ if (!m_manager) {
+ m_manager = ::OpenSCManager(0, 0, GENERIC_ALL);
+ if (!m_manager) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to OpenSCManager(), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+
+ if (!m_service) {
+ m_service = ::OpenServiceA(m_manager, get_name(), SERVICE_STOP | DELETE);
+ if (!m_service) {
+ int err = GetLastError();
+ LOG_ERROR(
+ "Failed to OpenService(), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+
+ SERVICE_STATUS status = { };
+ if (!::ControlService(m_service, SERVICE_CONTROL_STOP, &status)) {
+ int err = ::GetLastError();
+ if (err == ERROR_SHUTDOWN_IN_PROGRESS)
+ continue;
+ else if (err != ERROR_SERVICE_NOT_ACTIVE) {
+ LOG_ERROR(
+ "Failed to ControlService(SERVICE_CONTROL_STOP), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+ }
+
+ if (!::DeleteService(m_service)) {
+ int err = ::GetLastError();
+ LOG_ERROR(
+ "Failed to ControlService(SERVICE_CONTROL_STOP), last err="
+ << log_space::get_win32_err_descr(err));
+ break;
+ }
+
+ LOG_PRINT("Removed successfully.", LOG_LEVEL_0);
+ break;
+ }
+
+ return true;
+}
+//-----------------------------------------------------------------------------
+inline
+bool service_impl_base::init() {
+ return true;
+}
+//-----------------------------------------------------------------------------
+inline
+bool service_impl_base::run_service() {
+ CHECK_AND_ASSERT(!m_service, false);
+
+ long error_code = 0;
+
+ SERVICE_TABLE_ENTRYA service_table[2];
+ ZeroMemory(&service_table, sizeof(service_table));
+
+ service_table->lpServiceName = (char*) get_name();
+ service_table->lpServiceProc = service_entry;
+
+ LOG_PRINT("[+] Start service control dispatcher for \"" << get_name() << "\"",
+ LOG_LEVEL_1);
+
+ error_code = 1;
+ BOOL res = ::StartServiceCtrlDispatcherA(service_table);
+ if (!res) {
+ int err = GetLastError();
+ LOG_PRINT(
+ "[+] Error starting service control dispatcher, err="
+ << log_space::get_win32_err_descr(err), LOG_LEVEL_1);
+ return false;
+ } else {
+ LOG_PRINT("[+] End service control dispatcher for \"" << get_name() << "\"",
+ LOG_LEVEL_1);
+ }
+ return true;
+}
+//-----------------------------------------------------------------------------
+inline DWORD __stdcall service_impl_base::_service_handler(DWORD control,
+ DWORD event, void *pdata, void *pcontext) {
+ CHECK_AND_ASSERT(pcontext, ERROR_CALL_NOT_IMPLEMENTED);
+
+ service_impl_base *pservice = (service_impl_base*) pcontext;
+ return pservice->service_handler(control, event, pdata);
+}
+//-----------------------------------------------------------------------------
+inline
+void __stdcall service_impl_base::service_entry(DWORD argc, char **pargs) {
+ service_impl_base *pme = instance();
+ LOG_PRINT("instance: " << pme, LOG_LEVEL_4);
+ if (!pme) {
+ LOG_ERROR("Error: at service_entry() pme = NULL");
+ return;
+ }
+ pme->m_status_handle = ::RegisterServiceCtrlHandlerExA(pme->get_name(),
+ _service_handler, pme);
+
+ pme->set_status(SERVICE_RUNNING);
+ pme->service_main();
+ pme->set_status(SERVICE_STOPPED);
+}
+//-----------------------------------------------------------------------------
+inline
+void service_impl_base::set_status(unsigned state, unsigned pending) {
+ if (!m_status_handle)
+ return;
+
+ SERVICE_STATUS status = { 0 };
+ status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ status.dwCurrentState = state;
+ status.dwControlsAccepted = m_accepted_control;
+ /*status.dwWin32ExitCode = NO_ERROR;
+ status.dwServiceSpecificExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
+ status.dwCheckPoint = 0;
+ status.dwWaitHint = 0;
+
+ status.dwCurrentState = state;*/
+
+ if (state == SERVICE_START_PENDING || state == SERVICE_STOP_PENDING
+ || state == SERVICE_CONTINUE_PENDING || state == SERVICE_PAUSE_PENDING) {
+ status.dwWaitHint = 2000;
+ status.dwCheckPoint = pending;
+ }
+ ::SetServiceStatus(m_status_handle, &status);
+}
+//-----------------------------------------------------------------------------------------
+inline
+void service_impl_base::set_control_accepted(unsigned controls) {
+ m_accepted_control = controls;
+}
+//-----------------------------------------------------------------------------------------
+inline
+unsigned service_impl_base::get_control_accepted() {
+ return m_accepted_control;
+}
+//-----------------------------------------------------------------------------------------
+inline SERVICE_FAILURE_ACTIONSA* service_impl_base::get_failure_actions() {
+ // first 3 failures in 30 minutes. Service will be restarted.
+ // do nothing for next failures
+ static SC_ACTION sa[] = { { SC_ACTION_RESTART, 3 * 1000 }, {
+ SC_ACTION_RESTART, 3 * 1000 }, { SC_ACTION_RESTART, 3 * 1000 }, {
+ SC_ACTION_NONE, 0 } };
+
+ static SERVICE_FAILURE_ACTIONSA sfa = { 1800, // interval for failures counter - 30 min
+ "", NULL, 4, (SC_ACTION*) &sa };
+
+ // TODO: refactor this code, really unsafe!
+ return &sfa;
+}
+}
+
+#endif //_SERVICE_IMPL_BASE_H_
diff --git a/contrib/epee/include/sha1.h b/contrib/epee/include/sha1.h
new file mode 100644
index 000000000..ce42082f8
--- /dev/null
+++ b/contrib/epee/include/sha1.h
@@ -0,0 +1,51 @@
+
+/*
+ Copyright (c) 2011, Micael Hildenborg
+ 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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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 SHA1_DEFINED
+#define SHA1_DEFINED
+
+namespace sha1 {
+
+ /**
+ @param src points to any kind of data to be hashed.
+ @param bytelength the number of bytes to hash from the src pointer.
+ @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
+ */
+ void calc(const void* src, const int bytelength, unsigned char* hash);
+
+ /**
+ @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
+ @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
+ */
+ void toHexString(const unsigned char* hash, char* hexstring);
+
+} // namespace sha1
+
+#include "sha1.inl"
+
+#endif // SHA1_DEFINED
diff --git a/contrib/epee/include/sha1.inl b/contrib/epee/include/sha1.inl
new file mode 100644
index 000000000..d33202724
--- /dev/null
+++ b/contrib/epee/include/sha1.inl
@@ -0,0 +1,179 @@
+
+/*
+ Copyright (c) 2011, Micael Hildenborg
+ 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 Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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.
+ */
+
+/*
+ Contributors:
+ Gustav
+ Several members in the gamedev.se forum.
+ Gregory Petrosyan
+ */
+
+#include "sha1.h"
+
+namespace sha1 {
+namespace {// local
+// Rotate an integer value to left.
+inline const unsigned int rol(const unsigned int value,
+ const unsigned int steps) {
+ return ((value << steps) | (value >> (32 - steps)));
+}
+
+// Sets the first 16 integers in the buffert to zero.
+// Used for clearing the W buffert.
+inline void clearWBuffert(unsigned int* buffert) {
+ for (int pos = 16; --pos >= 0;)
+ {
+ buffert[pos] = 0;
+ }
+}
+
+inline
+void innerHash(unsigned int* result, unsigned int* w) {
+ unsigned int a = result[0];
+ unsigned int b = result[1];
+ unsigned int c = result[2];
+ unsigned int d = result[3];
+ unsigned int e = result[4];
+
+ int round = 0;
+
+#define sha1macro(func,val) \
+ { \
+ const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
+ e = d; \
+ d = c; \
+ c = rol(b, 30); \
+ b = a; \
+ a = t; \
+ }
+
+ while (round < 16) {
+ sha1macro((b & c) | (~b & d), 0x5a827999)
+ ++round;
+ }
+ while (round < 20) {
+ w[round] = rol(
+ (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro((b & c) | (~b & d), 0x5a827999)
+ ++round;
+ }
+ while (round < 40) {
+ w[round] = rol(
+ (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro(b ^ c ^ d, 0x6ed9eba1)
+ ++round;
+ }
+ while (round < 60) {
+ w[round] = rol(
+ (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
+ ++round;
+ }
+ while (round < 80) {
+ w[round] = rol(
+ (w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
+ sha1macro(b ^ c ^ d, 0xca62c1d6)
+ ++round;
+ }
+
+#undef sha1macro
+
+ result[0] += a;
+ result[1] += b;
+ result[2] += c;
+ result[3] += d;
+ result[4] += e;
+}
+} // namespace
+
+inline
+void calc(const void* src, const int bytelength, unsigned char* hash) {
+ // Init the result array.
+ unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476,
+ 0xc3d2e1f0 };
+
+ // Cast the void src pointer to be the byte array we can work with.
+ const unsigned char* sarray = (const unsigned char*) src;
+
+ // The reusable round buffer
+ unsigned int w[80];
+
+ // Loop through all complete 64byte blocks.
+ const int endOfFullBlocks = bytelength - 64;
+ int endCurrentBlock;
+ int currentBlock(0);
+
+ while (currentBlock <= endOfFullBlocks) {
+ endCurrentBlock = currentBlock + 64;
+
+ // Init the round buffer with the 64 byte block data.
+ for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
+ {
+ // This line will swap endian on big endian and keep endian on little endian.
+ w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
+ | (((unsigned int) sarray[currentBlock + 2]) << 8)
+ | (((unsigned int) sarray[currentBlock + 1]) << 16)
+ | (((unsigned int) sarray[currentBlock]) << 24);
+ }
+ innerHash(result, w);
+ }
+
+ // Handle the last and not full 64 byte block if existing.
+ endCurrentBlock = bytelength - currentBlock;
+ clearWBuffert(w);
+ int lastBlockBytes = 0;
+ for (; lastBlockBytes < endCurrentBlock; ++lastBlockBytes) {
+ w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes
+ + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
+ }
+ w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
+ if (endCurrentBlock >= 56) {
+ innerHash(result, w);
+ clearWBuffert(w);
+ }
+ w[15] = bytelength << 3;
+ innerHash(result, w);
+
+ // Store hash in result pointer, and make sure we get in in the correct order on both endian models.
+ for (int hashByte = 20; --hashByte >= 0;) {
+ hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3))
+ & 0xff;
+ }
+}
+inline
+void toHexString(const unsigned char* hash, char* hexstring) {
+ const char hexDigits[] = { "0123456789abcdef" };
+
+ for (int hashByte = 20; --hashByte >= 0;)
+ {
+ hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
+ hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
+ }
+ hexstring[40] = 0;
+}
+} // namespace sha1
diff --git a/contrib/epee/include/soci_helper.h b/contrib/epee/include/soci_helper.h
new file mode 100644
index 000000000..a154f97fc
--- /dev/null
+++ b/contrib/epee/include/soci_helper.h
@@ -0,0 +1,142 @@
+// 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 "soci.h"
+#include "soci-postgresql.h"
+
+using namespace epee;
+namespace soci
+{
+
+ template <>
+ struct type_conversion<boost::uint64_t>
+ {
+ typedef long long base_type;
+
+ static void from_base(base_type a_, indicator ind, boost::uint64_t & mi)
+ {
+ if (ind == i_null)
+ {
+ mi = 0;
+ //throw soci_error("Null value not allowed for this type");
+ }
+ mi = (boost::uint64_t)a_;
+ //mi.set(i);
+ }
+
+ static void to_base(const boost::uint64_t & mi, base_type & i, indicator & ind)
+ {
+ i = (base_type)mi;
+ ind = i_ok;
+ }
+ };
+
+
+
+ template <>
+ struct type_conversion<bool>
+ {
+ typedef int base_type;
+
+ static void from_base(base_type a_, indicator ind, bool& mi)
+ {
+ if (ind == i_null)
+ {
+ mi = false;
+ //throw soci_error("Null value not allowed for this type");
+ }
+ mi = a_? true:false;
+ //mi.set(i);
+ }
+
+ static void to_base(const bool & mi, base_type & i, indicator & ind)
+ {
+ i = mi? 1:0;
+ ind = i_ok;
+ }
+ };
+
+
+
+ class per_thread_session
+ {
+ public:
+ bool init(const std::string& connection_string)
+ {
+ m_connection_string = connection_string;
+
+ return true;
+ }
+
+ soci::session& get()
+ {
+
+ //soci::session
+
+ m_db_connections_lock.lock();
+ boost::shared_ptr<soci::session>& conn_ptr = m_db_connections[epee::misc_utils::get_thread_string_id()];
+ m_db_connections_lock.unlock();
+ if(!conn_ptr.get())
+ {
+ conn_ptr.reset(new soci::session(soci::postgresql, m_connection_string));
+ }
+ //init new connection
+ return *conn_ptr.get();
+ }
+
+ bool reopen()
+ {
+ //soci::session
+
+ m_db_connections_lock.lock();
+ boost::shared_ptr<soci::session>& conn_ptr = m_db_connections[misc_utils::get_thread_string_id()];
+ m_db_connections_lock.unlock();
+ if(conn_ptr.get())
+ {
+ conn_ptr->close();
+ conn_ptr.reset(new soci::session(soci::postgresql, m_connection_string));
+ }
+
+ //init new connection
+ return true;
+ }
+
+ //----------------------------------------------------------------------------------------------
+ bool check_status()
+ {
+ return true;
+ }
+
+ protected:
+ private:
+ std::map<std::string, boost::shared_ptr<soci::session> > m_db_connections;
+ epee::critical_section m_db_connections_lock;
+ std::string m_connection_string;
+ };
+}
+/*}*/ \ No newline at end of file
diff --git a/contrib/epee/include/static_initializer.h b/contrib/epee/include/static_initializer.h
new file mode 100644
index 000000000..3463a5607
--- /dev/null
+++ b/contrib/epee/include/static_initializer.h
@@ -0,0 +1,82 @@
+// 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 _STATIC_INITIALIZER_H_
+#define _STATIC_INITIALIZER_H_
+
+
+namespace epee
+{
+/***********************************************************************
+class initializer - useful to initialize some static classes
+ which have init() and un_init() static members
+************************************************************************/
+
+template<class to_initialize>
+class initializer
+{
+public:
+ initializer()
+ {
+ to_initialize::init();
+ //get_set_is_initialized(true, true);
+ }
+ ~initializer()
+ {
+ to_initialize::un_init();
+ //get_set_is_uninitialized(true, true);
+ }
+
+ /*static inline bool is_initialized()
+ {
+ return get_set_is_initialized();
+ }
+ static inline bool is_uninitialized()
+ {
+ return get_set_is_uninitialized();
+ }
+
+private:
+ static inline bool get_set_is_initialized(bool need_to_set = false, bool val_to_set= false)
+ {
+ static bool val_is_initialized = false;
+ if(need_to_set)
+ val_is_initialized = val_to_set;
+ return val_is_initialized;
+ }
+ static inline bool get_set_is_uninitialized(bool need_to_set = false, bool val_to_set = false)
+ {
+ static bool val_is_uninitialized = false;
+ if(need_to_set)
+ val_is_uninitialized = val_to_set;
+ return val_is_uninitialized;
+ }*/
+};
+
+}
+#endif //_STATIC_INITIALIZER_H_
diff --git a/contrib/epee/include/storages/activity_notifier.h b/contrib/epee/include/storages/activity_notifier.h
new file mode 100644
index 000000000..14b6ebbfb
--- /dev/null
+++ b/contrib/epee/include/storages/activity_notifier.h
@@ -0,0 +1,132 @@
+// 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 "inmemtoxml.h"
+
+//#include "levin/levin_server.h"
+
+namespace epee
+{
+
+class activity_printer_base
+{
+public:
+ activity_printer_base(){}
+ virtual ~activity_printer_base(){}
+};
+
+template<class A>
+class notify_activity_printer: public activity_printer_base
+{
+public:
+ notify_activity_printer(int level, A& arg, bool is_notify_mode = true):m_ref_arg(arg), m_level(level), m_is_notify_mode(is_notify_mode)
+ {
+ m_command_name = typeid(m_ref_arg).name();
+ m_command_name.erase(0, 7);
+ m_command_name.erase(m_command_name.size()-10, m_command_name.size()-1);
+ if(level == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(m_command_name, level);
+ }
+ else if(level+1 == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(" -->>" << m_command_name, level);
+ }
+ else if(level+2 == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(" -->>" << m_command_name << "\n" << StorageNamed::xml::get_t_as_xml(m_ref_arg), level);
+ }
+ }
+
+ virtual ~notify_activity_printer()
+ {
+ if(m_is_notify_mode)
+ {
+ if(m_level+1 == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(" <<--" << m_command_name, m_level);
+ }
+ }
+ }
+protected:
+ std::string m_command_name;
+ A& m_ref_arg;
+ int m_level;
+ bool m_is_notify_mode;
+};
+
+template<class A, class R>
+class command_activity_printer: public notify_activity_printer<A>
+{
+public:
+ command_activity_printer(int level, A& arg, R& rsp):notify_activity_printer(level, arg, false), m_ref_rsp(rsp)
+ {
+ }
+
+ virtual ~command_activity_printer()
+ {
+ if(m_level+1 == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(" <<--" << m_command_name, m_level);
+ }
+ else if(m_level+2 == log_space::get_set_log_detalisation_level())
+ {
+ LOG_PRINT(" <<--" << m_command_name << "\n" << StorageNamed::trace_as_xml(m_ref_rsp), m_level);
+ }
+ }
+private:
+ R& m_ref_rsp;
+};
+
+template<class A, class R>
+activity_printer_base* create_activity_printer(int level, A& arg, R& rsp)
+{
+ return new command_activity_printer<A, R>(level, arg, rsp);
+}
+
+template<class A>
+activity_printer_base* create_activity_printer(int level, A& arg)
+{
+ return new notify_activity_printer<A>(level, arg);
+}
+
+}
+
+#define PRINT_COMMAND_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct, out_struct));
+#define PRINT_NOTIFY_ACTIVITY(level) boost::shared_ptr<activity_printer_base> local_activity_printer(create_activity_printer(level, in_struct));
+
+#define PRINT_ACTIVITY(level) \
+{std::string some_str = typeid(in_struct).name(); \
+ some_str.erase(0, 7); \
+ some_str.erase(some_str.size()-10, some_str.size()-1); \
+ LOG_PRINT(some_str, level);}
+
+}
+
diff --git a/contrib/epee/include/storages/crypted_storage.h b/contrib/epee/include/storages/crypted_storage.h
new file mode 100644
index 000000000..d6e6edcba
--- /dev/null
+++ b/contrib/epee/include/storages/crypted_storage.h
@@ -0,0 +1,62 @@
+// 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 _CRYPTED_STORAGE_H_
+#define _CRYPTED_STORAGE_H_
+
+#include "cryptopp_helper.h"
+
+namespace epee
+{
+template<class t_base_storage, class crypt_provider, class t_key_provider>
+class crypted_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(!crypt_provider::encrypt(targetObj, t_key_provider::get_storage_default_key()))
+ return 0;
+
+ return targetObj.size();
+ }
+
+ size_t LoadFromSolidBuffer(const std::string& pTargetObj)
+ {
+ std::string buff_to_decrypt = pTargetObj;
+ if(crypt_provider::decrypt(buff_to_decrypt, t_key_provider::get_storage_default_key()))
+ return t_base_storage::LoadFromSolidBuffer(buff_to_decrypt);
+
+ return 0;
+ }
+};
+}
+
+#endif //_CRYPTED_STORAGE_H_ \ No newline at end of file
diff --git a/contrib/epee/include/storages/gzipped_inmemstorage.h b/contrib/epee/include/storages/gzipped_inmemstorage.h
new file mode 100644
index 000000000..5c53fffa7
--- /dev/null
+++ b/contrib/epee/include/storages/gzipped_inmemstorage.h
@@ -0,0 +1,68 @@
+// 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 t_base_storage>
+ 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 \ No newline at end of file
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
new file mode 100644
index 000000000..07720f496
--- /dev/null
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -0,0 +1,126 @@
+
+// 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 "portable_storage_template_helper.h"
+#include "net/http_base.h"
+#include "net/http_server_handlers_map2.h"
+
+namespace epee
+{
+ namespace net_utils
+ {
+ template<class t_request, class t_response, class t_transport>
+ bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& 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(!invoke_request(url, transport, timeout, &pri, method, req_param))
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url);
+ return false;
+ }
+
+ if(!pri->m_response_code)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
+ return false;
+ }
+
+ if(pri->m_response_code != 200)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
+ return false;
+ }
+
+ return serialization::load_t_from_json(result_struct, pri->m_body);
+ }
+
+
+
+ template<class t_request, class t_response, class t_transport>
+ bool invoke_http_bin_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
+ {
+ std::string req_param;
+ if(!serialization::store_t_to_binary(out_struct, req_param))
+ return false;
+
+ const http::http_response_info* pri = NULL;
+ if(!invoke_request(url, transport, timeout, &pri, method, req_param))
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url);
+ return false;
+ }
+
+ if(!pri->m_response_code)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
+ return false;
+ }
+
+ if(pri->m_response_code != 200)
+ {
+ LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
+ return false;
+ }
+
+ return serialization::load_t_from_binary(result_struct, pri->m_body);
+ }
+
+ template<class t_request, class t_response, class t_transport>
+ bool invoke_http_json_rpc(const std::string& url, const std::string& method_name, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0")
+ {
+ epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
+ req_t.params = out_struct;
+ req_t.id = req_id;
+ req_t.method = method_name;
+ req_t.version = "2.0";
+ epee::json_rpc::response<t_response, epee::json_rpc::error> resp_t = AUTO_VAL_INIT(resp_t);
+ if(!epee::net_utils::invoke_http_json_remote_command2(url, req_t, resp_t, transport, timeout, http_method))
+ {
+ return false;
+ }
+ if(resp_t.error.code || resp_t.error.message.size())
+ {
+ LOG_ERROR("RPC call of \"" << method_name << "\" returned error: " << resp_t.error.code << ", message: " << resp_t.error.message);
+ return false;
+ }
+ result_struct = resp_t.result;
+ return true;
+ }
+
+ template<class t_command, class t_transport>
+ bool invoke_http_json_rpc(const std::string& url, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& http_method = "GET", const std::string& req_id = "0")
+ {
+ return invoke_http_json_rpc(url, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
+ }
+
+ }
+}
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
new file mode 100644
index 000000000..1b32c51d1
--- /dev/null
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -0,0 +1,289 @@
+// 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 "portable_storage_template_helper.h"
+#include <boost/utility/value_init.hpp>
+#include "net/levin_base.h"
+
+namespace epee
+{
+ namespace net_utils
+ {
+ template<class t_arg, class t_result, class t_transport>
+ bool invoke_remote_command2(int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport)
+ {
+ if(!transport.is_connected())
+ return false;
+
+ serialization::portable_storage stg;
+ out_struct.store(stg);
+ std::string buff_to_send, buff_to_recv;
+ stg.store_to_binary(buff_to_send);
+
+ int res = transport.invoke(command, buff_to_send, buff_to_recv);
+ if( res <=0 )
+ {
+ LOG_PRINT_RED("Failed to invoke command " << command << " return code " << res, LOG_LEVEL_1);
+ return false;
+ }
+ serialization::portable_storage stg_ret;
+ if(!stg_ret.load_from_binary(buff_to_recv))
+ {
+ LOG_ERROR("Failed to load_from_binary on command " << command);
+ return false;
+ }
+ result_struct.load(stg_ret);
+ return true;
+ }
+
+ template<class t_arg, class t_transport>
+ bool notify_remote_command2(int command, const t_arg& out_struct, t_transport& transport)
+ {
+ if(!transport.is_connected())
+ return false;
+
+ serialization::portable_storage stg;
+ out_struct.store(&stg);
+ std::string buff_to_send;
+ stg.store_to_binary(buff_to_send);
+
+ int res = transport.notify(command, buff_to_send);
+ if(res <=0 )
+ {
+ LOG_ERROR("Failed to notify command " << command << " return code " << res);
+ return false;
+ }
+ return true;
+ }
+
+ template<class t_arg, class t_result, class t_transport>
+ bool invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_result& result_struct, t_transport& transport)
+ {
+
+ typename serialization::portable_storage stg;
+ out_struct.store(stg);
+ std::string buff_to_send, buff_to_recv;
+ stg.store_to_binary(buff_to_send);
+
+ int res = transport.invoke(command, buff_to_send, buff_to_recv, conn_id);
+ if( res <=0 )
+ {
+ LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
+ return false;
+ }
+ typename serialization::portable_storage stg_ret;
+ if(!stg_ret.load_from_binary(buff_to_recv))
+ {
+ LOG_ERROR("Failed to load_from_binary on command " << command);
+ return false;
+ }
+ result_struct.load(stg_ret);
+
+ return true;
+ }
+
+ template<class t_result, class t_arg, class callback_t, class t_transport>
+ bool async_invoke_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport, callback_t cb, size_t inv_timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ {
+ typename serialization::portable_storage stg;
+ const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
+ std::string buff_to_send, buff_to_recv;
+ stg.store_to_binary(buff_to_send);
+ int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
+ {
+ t_result result_struct = AUTO_VAL_INIT(result_struct);
+ if( code <=0 )
+ {
+ LOG_PRINT_L1("Failed to invoke command " << command << " return code " << code);
+ cb(code, result_struct, context);
+ return false;
+ }
+ serialization::portable_storage stg_ret;
+ if(!stg_ret.load_from_binary(buff))
+ {
+ LOG_ERROR("Failed to load_from_binary on command " << command);
+ cb(LEVIN_ERROR_FORMAT, result_struct, context);
+ return false;
+ }
+ result_struct.load(stg_ret);
+ cb(code, result_struct, context);
+ return true;
+ }, inv_timeout);
+ if( res <=0 )
+ {
+ LOG_PRINT_L1("Failed to invoke command " << command << " return code " << res);
+ return false;
+ }
+ return true;
+ }
+
+ template<class t_arg, class t_transport>
+ bool notify_remote_command2(boost::uuids::uuid conn_id, int command, const t_arg& out_struct, t_transport& transport)
+ {
+
+ serialization::portable_storage stg;
+ out_struct.store(stg);
+ std::string buff_to_send, buff_to_recv;
+ stg.store_to_binary(buff_to_send);
+
+ int res = transport.notify(command, buff_to_send, conn_id);
+ if(res <=0 )
+ {
+ LOG_PRINT_RED_L0("Failed to notify command " << command << " return code " << res);
+ return false;
+ }
+ return true;
+ }
+ //----------------------------------------------------------------------------------------------------
+ //----------------------------------------------------------------------------------------------------
+ template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
+ int buff_to_t_adapter(int command, const std::string& in_buff, std::string& buff_out, callback_t cb, t_context& context )
+ {
+ serialization::portable_storage strg;
+ if(!strg.load_from_binary(in_buff))
+ {
+ LOG_ERROR("Failed to load_from_binary in command " << command);
+ return -1;
+ }
+ boost::value_initialized<t_in_type> in_struct;
+ boost::value_initialized<t_out_type> out_struct;
+
+ static_cast<t_in_type&>(in_struct).load(strg);
+ int res = cb(command, static_cast<t_in_type&>(in_struct), static_cast<t_out_type&>(out_struct), context);
+ serialization::portable_storage strg_out;
+ static_cast<t_out_type&>(out_struct).store(strg_out);
+
+ if(!strg_out.store_to_binary(buff_out))
+ {
+ LOG_ERROR("Failed to store_to_binary in command" << command);
+ return -1;
+ }
+
+ return res;
+ };
+
+ template<class t_owner, class t_in_type, class t_context, class callback_t>
+ int buff_to_t_adapter(t_owner* powner, int command, const std::string& in_buff, callback_t cb, t_context& context)
+ {
+ serialization::portable_storage strg;
+ if(!strg.load_from_binary(in_buff))
+ {
+ LOG_ERROR("Failed to load_from_binary in notify " << command);
+ return -1;
+ }
+ boost::value_initialized<t_in_type> in_struct;
+ static_cast<t_in_type&>(in_struct).load(strg);
+ return cb(command, in_struct, context);
+ };
+
+#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
+ int invoke(int command, const std::string& in_buff, std::string& buff_out, context_type& context) \
+ { \
+ bool handled = false; \
+ return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
+ }
+
+#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
+ int notify(int command, const std::string& in_buff, context_type& context) \
+ { \
+ bool handled = false; std::string fake_str;\
+ return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
+ }
+
+
+#define CHAIN_LEVIN_INVOKE_MAP() \
+ int invoke(int command, const std::string& in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
+ { \
+ bool handled = false; \
+ return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
+ }
+
+#define CHAIN_LEVIN_NOTIFY_MAP() \
+ int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ { \
+ bool handled = false; std::string fake_str;\
+ return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
+ }
+
+#define CHAIN_LEVIN_NOTIFY_STUB() \
+ int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ { \
+ return -1; \
+ }
+
+#define BEGIN_INVOKE_MAP2(owner_type) \
+ template <class t_context> int handle_invoke_map(bool is_notify, int command, const std::string& in_buff, std::string& buff_out, t_context& context, bool& handled) \
+ { \
+ typedef owner_type internal_owner_type_name;
+
+#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
+ if(!is_notify && command_id == command) \
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
+
+#define HANDLE_INVOKE_T2(COMMAND, func) \
+ if(!is_notify && COMMAND::ID == command) \
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
+
+
+#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
+ if(is_notify && command_id == command) \
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+
+#define HANDLE_NOTIFY_T2(NOTIFY, func) \
+ if(is_notify && NOTIFY::ID == command) \
+ {handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+
+
+#define CHAIN_INVOKE_MAP2(func) \
+ { \
+ int res = func(is_notify, command, in_buff, buff_out, context, handled); \
+ if(handled) \
+ return res; \
+ }
+
+#define CHAIN_INVOKE_MAP_TO_OBJ2(obj) \
+ { \
+ int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, context, handled); \
+ if(handled) \
+ return res; \
+ }
+
+#define CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(obj, context_type) \
+ { \
+ int res = obj.handle_invoke_map(is_notify, command, in_buff, buff_out, static_cast<context_type>(context), handled); \
+ if(handled) return res; \
+ }
+
+
+#define END_INVOKE_MAP2() \
+ LOG_ERROR("Unkonown command:" << command); \
+ return LEVIN_ERROR_CONNECTION_HANDLER_NOT_DEFINED; \
+ }
+ }
+}
+
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
new file mode 100644
index 000000000..baafb5623
--- /dev/null
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -0,0 +1,260 @@
+// 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
+
+namespace epee
+{
+namespace misc_utils
+{
+ namespace parse
+ {
+ inline std::string transform_to_escape_sequence(const std::string& src)
+ {
+ //std::stringstream res;
+ std::string res;
+ for(std::string::const_iterator it = src.begin(); it!=src.end(); ++it)
+ {
+ switch(*it)
+ {
+ case '\b': //Backspace (ascii code 08)
+ res+="\\b"; break;
+ case '\f': //Form feed (ascii code 0C)
+ res+="\\f"; break;
+ case '\n': //New line
+ res+="\\n"; break;
+ case '\r': //Carriage return
+ res+="\\r"; break;
+ case '\t': //Tab
+ res+="\\t"; break;
+ case '\v': //Vertical tab
+ res+="\\v"; break;
+ //case '\'': //Apostrophe or single quote
+ // res+="\\'"; break;
+ case '"': //Double quote
+ res+="\\\""; break;
+ case '\\': //Backslash caracter
+ res+="\\\\"; break;
+ case '/': //Backslash caracter
+ res+="\\/"; break;
+ default:
+ res.push_back(*it);
+ }
+ }
+ return res;
+ }
+ /*
+
+ \b Backspace (ascii code 08)
+ \f Form feed (ascii code 0C)
+ \n New line
+ \r Carriage return
+ \t Tab
+ \v Vertical tab
+ \' Apostrophe or single quote
+ \" Double quote
+ \\ Backslash character
+
+ */
+ inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ val.clear();
+ bool escape_mode = false;
+ std::string::const_iterator it = star_end_string;
+ ++it;
+ for(;it != buf_end;it++)
+ {
+ if(escape_mode/*prev_ch == '\\'*/)
+ {
+ switch(*it)
+ {
+ case 'b': //Backspace (ascii code 08)
+ val.push_back(0x08);break;
+ case 'f': //Form feed (ascii code 0C)
+ val.push_back(0x0C);break;
+ case 'n': //New line
+ val.push_back('\n');break;
+ case 'r': //Carriage return
+ val.push_back('\r');break;
+ case 't': //Tab
+ val.push_back('\t');break;
+ case 'v': //Vertical tab
+ val.push_back('\v');break;
+ case '\'': //Apostrophe or single quote
+ val.push_back('\'');break;
+ case '"': //Double quote
+ val.push_back('"');break;
+ case '\\': //Backslash character
+ val.push_back('\\');break;
+ case '/': //Slash character
+ val.push_back('/');break;
+ default:
+ val.push_back(*it);
+ LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
+ }
+ escape_mode = false;
+ }else if(*it == '"')
+ {
+ star_end_string = it;
+ return;
+ }else if(*it == '\\')
+ {
+ escape_mode = true;
+ }
+ else
+ {
+ val.push_back(*it);
+ }
+ }
+ ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
+ }
+ inline bool match_string(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ try
+ {
+
+ match_string2(star_end_string, buf_end, val);
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val, bool& is_float_val, bool& is_signed_val)
+ {
+ val.clear();
+ is_float_val = false;
+ for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ {
+ if(isdigit(*it) || (it == star_end_string && *it == '-') || (val.size() && *it == '.' ) || (is_float_val && (*it == 'e' || *it == 'E' || *it == '-' || *it == '+' )) )
+ {
+ if(!val.size() && *it == '-')
+ is_signed_val = true;
+ if(*it == '.' )
+ is_float_val = true;
+ val.push_back(*it);
+ }
+ else
+ {
+ if(val.size())
+ {
+ star_end_string = --it;
+ return;
+ }
+ else
+ ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
+ }
+ }
+ ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
+ }
+ inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ try
+ {
+ bool is_v_float = false;bool is_signed_val = false;
+ match_number2(star_end_string, buf_end, val, is_v_float, is_signed_val);
+ return !is_v_float;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ val.clear();
+
+ for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ {
+ if(!isalpha(*it))
+ {
+ val.assign(star_end_string, it);
+ if(val.size())
+ {
+ star_end_string = --it;
+ return;
+ }else
+ ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
+ }
+ }
+ ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
+ }
+ inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ try
+ {
+ match_word2(star_end_string, buf_end, val);
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ inline bool match_word_with_extrasymb(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ {
+ val.clear();
+
+ for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ {
+ if(!isalnum(*it) && *it != '-' && *it != '_')
+ {
+ val.assign(star_end_string, it);
+ if(val.size())
+ {
+ star_end_string = --it;
+ return true;
+ }else
+ return false;
+ }
+ }
+ return false;
+ }
+ inline bool match_word_til_equal_mark(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string::const_iterator& word_end)
+ {
+ word_end = star_end_string;
+
+ for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ {
+ if(isspace(*it))
+ {
+
+ continue;
+ }else if( *it == '=' )
+ {
+ star_end_string = it;
+ word_end = it;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h
new file mode 100644
index 000000000..8f4ebc6ae
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage.h
@@ -0,0 +1,463 @@
+// 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 "misc_language.h"
+#include "portable_storage_base.h"
+#include "portable_storage_to_bin.h"
+#include "portable_storage_from_bin.h"
+#include "portable_storage_to_json.h"
+#include "portable_storage_from_json.h"
+#include "portable_storage_val_converters.h"
+
+namespace epee
+{
+ namespace serialization
+ {
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class portable_storage
+ {
+ public:
+ typedef epee::serialization::hsection hsection;
+ typedef epee::serialization::harray harray;
+
+ portable_storage(){}
+ virtual ~portable_storage(){}
+ hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false);
+ template<class t_value>
+ bool get_value(const std::string& value_name, t_value& val, hsection hparent_section);
+ template<class t_value>
+ bool set_value(const std::string& value_name, const t_value& target, hsection hparent_section);
+
+ //serial access for arrays of values --------------------------------------
+ //values
+ template<class t_value>
+ harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section);
+ template<class t_value>
+ bool get_next_value(harray hval_array, t_value& target);
+ template<class t_value>
+ harray insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section);
+ template<class t_value>
+ bool insert_next_value(harray hval_array, const t_value& target);
+ //sections
+ harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section);
+ bool get_next_section(harray hSecArray, hsection& h_child_section);
+ harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section);
+ bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
+ //------------------------------------------------------------------------
+ //delete entry (section, value or array)
+ bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
+
+ //-------------------------------------------------------------------------------
+ bool store_to_binary(binarybuffer& target);
+ bool load_from_binary(const binarybuffer& target);
+ template<class trace_policy>
+ bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
+ bool dump_as_json(std::string& targetObj, size_t indent = 0);
+ bool load_from_json(const std::string& source);
+
+ private:
+ section m_root;
+ hsection get_root_section() {return &m_root;}
+ storage_entry* find_storage_entry(const std::string& pentry_name, hsection psection);
+ template<class entry_type>
+ storage_entry* insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry);
+
+ hsection insert_new_section(const std::string& pentry_name, hsection psection);
+
+#pragma pack(push)
+#pragma pack(1)
+ struct storage_block_header
+ {
+ uint32_t m_signature_a;
+ uint32_t m_signature_b;
+ uint8_t m_ver;
+ };
+#pragma pack(pop)
+ };
+ inline
+ bool portable_storage::dump_as_json(std::string& buff, size_t indent)
+ {
+ TRY_ENTRY();
+ std::stringstream ss;
+ epee::serialization::dump_as_json(ss, m_root, indent);
+ buff = ss.str();
+ return true;
+ CATCH_ENTRY("portable_storage::dump_as_json", false)
+ }
+ inline
+ bool portable_storage::load_from_json(const std::string& source)
+ {
+ TRY_ENTRY();
+ return json::load_from_json(source, *this);
+ CATCH_ENTRY("portable_storage::load_from_json", false)
+ }
+
+ template<class trace_policy>
+ bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name)
+ {
+ return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
+ }
+
+ inline
+ bool portable_storage::store_to_binary(binarybuffer& target)
+ {
+ TRY_ENTRY();
+ std::stringstream ss;
+ storage_block_header sbh = AUTO_VAL_INIT(sbh);
+ sbh.m_signature_a = PORTABLE_STORAGE_SIGNATUREA;
+ sbh.m_signature_b = PORTABLE_STORAGE_SIGNATUREB;
+ sbh.m_ver = PORTABLE_STORAGE_FORMAT_VER;
+ ss.write((const char*)&sbh, sizeof(storage_block_header));
+ pack_entry_to_buff(ss, m_root);
+ target = ss.str();
+ return true;
+ CATCH_ENTRY("portable_storage::store_to_binary", false)
+ }
+ inline
+ bool portable_storage::load_from_binary(const binarybuffer& source)
+ {
+ m_root.m_entries.clear();
+ if(source.size() < sizeof(storage_block_header))
+ {
+ LOG_ERROR("portable_storage: wrong binary format, packet size = " << source.size() << " less than expected sizeof(storage_block_header)=" << sizeof(storage_block_header));
+ return false;
+ }
+ storage_block_header* pbuff = (storage_block_header*)source.data();
+ if(pbuff->m_signature_a != PORTABLE_STORAGE_SIGNATUREA ||
+ pbuff->m_signature_b != PORTABLE_STORAGE_SIGNATUREB
+ )
+ {
+ LOG_ERROR("portable_storage: wrong binary format - signature missmatch");
+ return false;
+ }
+ if(pbuff->m_ver != PORTABLE_STORAGE_FORMAT_VER)
+ {
+ LOG_ERROR("portable_storage: wrong binary format - unknown format ver = " << pbuff->m_ver);
+ return false;
+ }
+ TRY_ENTRY();
+ throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
+ buf_reader.read(m_root);
+ return true;//TODO:
+ CATCH_ENTRY("portable_storage::load_from_binary", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist)
+ {
+ TRY_ENTRY();
+ hparent_section = hparent_section ? hparent_section:&m_root;
+ storage_entry* pentry = find_storage_entry(section_name, hparent_section);
+ if(!pentry)
+ {
+ if(!create_if_notexist)
+ return nullptr;
+ return insert_new_section(section_name, hparent_section);
+ }
+ CHECK_AND_ASSERT(pentry , nullptr);
+ //check that section_entry we find is real "CSSection"
+ if(pentry->type() != typeid(section))
+ {
+ if(create_if_notexist)
+ *pentry = storage_entry(section());//replace
+ else
+ return nullptr;
+ }
+ return &boost::get<section>(*pentry);
+ CATCH_ENTRY("portable_storage::open_section", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class to_type>
+ struct get_value_visitor: boost::static_visitor<void>
+ {
+ to_type& m_target;
+ get_value_visitor(to_type& target):m_target(target){}
+ template<class from_type>
+ void operator()(const from_type& v){convert_t(v, m_target);}
+ };
+
+ template<class t_value>
+ bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section)
+ {
+ BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
+ //TRY_ENTRY();
+ if(!hparent_section) hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(value_name, hparent_section);
+ if(!pentry)
+ return false;
+
+ get_value_visitor<t_value> gvv(val);
+ boost::apply_visitor(gvv, *pentry);
+ return true;
+ //CATCH_ENTRY("portable_storage::template<>get_value", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class t_value>
+ bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section)
+ {
+ BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
+ TRY_ENTRY();
+ if(!hparent_section)
+ hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(value_name, hparent_section);
+ if(!pentry)
+ {
+ pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, v);
+ if(!pentry)
+ return false;
+ return true;
+ }
+ *pentry = storage_entry(v);
+ return true;
+ CATCH_ENTRY("portable_storage::template<>set_value", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, hsection psection)
+ {
+ TRY_ENTRY();
+ CHECK_AND_ASSERT(psection, nullptr);
+ auto it = psection->m_entries.find(pentry_name);
+ if(it == psection->m_entries.end())
+ return nullptr;
+
+ return &it->second;
+ CATCH_ENTRY("portable_storage::find_storage_entry", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class entry_type>
+ storage_entry* portable_storage::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry)
+ {
+ TRY_ENTRY();
+ CHECK_AND_ASSERT(psection, nullptr);
+ auto ins_res = psection->m_entries.insert(std::pair<std::string, storage_entry>(pentry_name, entry));
+ return &ins_res.first->second;
+ CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ hsection portable_storage::insert_new_section(const std::string& pentry_name, hsection psection)
+ {
+ TRY_ENTRY();
+ storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section());
+ if(!pse) return nullptr;
+ return &boost::get<section>(*pse);
+ CATCH_ENTRY("portable_storage::insert_new_section", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class to_type>
+ struct get_first_value_visitor: boost::static_visitor<bool>
+ {
+ to_type& m_target;
+ get_first_value_visitor(to_type& target):m_target(target){}
+ template<class from_type>
+ bool operator()(const array_entry_t<from_type>& a)
+ {
+ const from_type* pv = a.get_first_val();
+ if(!pv)
+ return false;
+ convert_t(*pv, m_target);
+ return true;
+ }
+ };
+ //---------------------------------------------------------------------------------------------------------------
+ template<class t_value>
+ harray portable_storage::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section)
+ {
+ BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
+ //TRY_ENTRY();
+ if(!hparent_section) hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(value_name, hparent_section);
+ if(!pentry)
+ return nullptr;
+ if(pentry->type() != typeid(array_entry))
+ return nullptr;
+ array_entry& ar_entry = boost::get<array_entry>(*pentry);
+
+ get_first_value_visitor<t_value> gfv(target);
+ if(!boost::apply_visitor(gfv, ar_entry))
+ return nullptr;
+ return &ar_entry;
+ //CATCH_ENTRY("portable_storage::get_first_value", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class to_type>
+ struct get_next_value_visitor: boost::static_visitor<bool>
+ {
+ to_type& m_target;
+ get_next_value_visitor(to_type& target):m_target(target){}
+ template<class from_type>
+ bool operator()(const array_entry_t<from_type>& a)
+ {
+ //TODO: optimize code here: work without get_next_val function
+ const from_type* pv = a.get_next_val();
+ if(!pv)
+ return false;
+ convert_t(*pv, m_target);
+ return true;
+ }
+ };
+
+
+ template<class t_value>
+ bool portable_storage::get_next_value(harray hval_array, t_value& target)
+ {
+ BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
+ //TRY_ENTRY();
+ CHECK_AND_ASSERT(hval_array, false);
+ array_entry& ar_entry = *hval_array;
+ get_next_value_visitor<t_value> gnv(target);
+ if(!boost::apply_visitor(gnv, ar_entry))
+ return false;
+ return true;
+ //CATCH_ENTRY("portable_storage::get_next_value", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class t_value>
+ harray portable_storage::insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section)
+ {
+ TRY_ENTRY();
+ if(!hparent_section) hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(value_name, hparent_section);
+ if(!pentry)
+ {
+ pentry = insert_new_entry_get_storage_entry(value_name, hparent_section, array_entry(array_entry_t<t_value>()));
+ if(!pentry)
+ return nullptr;
+ }
+ if(pentry->type() != typeid(array_entry))
+ *pentry = storage_entry(array_entry(array_entry_t<t_value>()));
+
+ array_entry& arr = boost::get<array_entry>(*pentry);
+ if(arr.type() != typeid(array_entry_t<t_value>))
+ arr = array_entry(array_entry_t<t_value>());
+
+ array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(arr);
+ arr_typed.insert_first_val(target);
+ return &arr;
+ CATCH_ENTRY("portable_storage::insert_first_value", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ template<class t_value>
+ bool portable_storage::insert_next_value(harray hval_array, const t_value& target)
+ {
+ TRY_ENTRY();
+ CHECK_AND_ASSERT(hval_array, false);
+
+ CHECK_AND_ASSERT_MES(hval_array->type() == typeid(array_entry_t<t_value>),
+ false, "unexpected type in insert_next_value: " << typeid(array_entry_t<t_value>).name());
+
+ array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(*hval_array);
+ arr_typed.insert_next_value(target);
+ return true;
+ CATCH_ENTRY("portable_storage::insert_next_value", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ //sections
+ inline
+ harray portable_storage::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section)
+ {
+ TRY_ENTRY();
+ if(!hparent_section) hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
+ if(!pentry)
+ return nullptr;
+ if(pentry->type() != typeid(array_entry))
+ return nullptr;
+ array_entry& ar_entry = boost::get<array_entry>(*pentry);
+ if(ar_entry.type() != typeid(array_entry_t<section>))
+ return nullptr;
+ array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
+ section* psec = sec_array.get_first_val();
+ if(!psec)
+ return nullptr;
+ h_child_section = psec;
+ return &ar_entry;
+ CATCH_ENTRY("portable_storage::get_first_section", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ bool portable_storage::get_next_section(harray hsec_array, hsection& h_child_section)
+ {
+ TRY_ENTRY();
+ CHECK_AND_ASSERT(hsec_array, false);
+ if(hsec_array->type() != typeid(array_entry_t<section>))
+ return nullptr;
+ array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
+ h_child_section = sec_array.get_next_val();
+ if(!h_child_section)
+ return false;
+ return true;
+ CATCH_ENTRY("portable_storage::get_next_section", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ harray portable_storage::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section)
+ {
+ TRY_ENTRY();
+ if(!hparent_section) hparent_section = &m_root;
+ storage_entry* pentry = find_storage_entry(sec_name, hparent_section);
+ if(!pentry)
+ {
+ pentry = insert_new_entry_get_storage_entry(sec_name, hparent_section, array_entry(array_entry_t<section>()));
+ if(!pentry)
+ return nullptr;
+ }
+ if(pentry->type() != typeid(array_entry))
+ *pentry = storage_entry(array_entry(array_entry_t<section>()));
+
+ array_entry& ar_entry = boost::get<array_entry>(*pentry);
+ if(ar_entry.type() != typeid(array_entry_t<section>))
+ ar_entry = array_entry(array_entry_t<section>());
+
+ array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
+ hinserted_childsection = &sec_array.insert_first_val(section());
+ return &ar_entry;
+ CATCH_ENTRY("portable_storage::insert_first_section", nullptr);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ inline
+ bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection)
+ {
+ TRY_ENTRY();
+ CHECK_AND_ASSERT(hsec_array, false);
+ CHECK_AND_ASSERT_MES(hsec_array->type() == typeid(array_entry_t<section>),
+ false, "unexpected type(not 'section') in insert_next_section, type: " << hsec_array->type().name());
+
+ array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
+ hinserted_childsection = &sec_array.insert_next_value(section());
+ return true;
+ CATCH_ENTRY("portable_storage::insert_next_section", false);
+ }
+ //---------------------------------------------------------------------------------------------------------------
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_base.h b/contrib/epee/include/storages/portable_storage_base.h
new file mode 100644
index 000000000..3f1637538
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_base.h
@@ -0,0 +1,160 @@
+// 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 <boost/variant.hpp>
+#include <boost/any.hpp>
+#include <string>
+#include <list>
+
+#define PORTABLE_STORAGE_SIGNATUREA 0x01011101
+#define PORTABLE_STORAGE_SIGNATUREB 0x01020101 // bender's nightmare
+#define PORTABLE_STORAGE_FORMAT_VER 1
+
+#define PORTABLE_RAW_SIZE_MARK_MASK 0x03
+#define PORTABLE_RAW_SIZE_MARK_BYTE 0
+#define PORTABLE_RAW_SIZE_MARK_WORD 1
+#define PORTABLE_RAW_SIZE_MARK_DWORD 2
+#define PORTABLE_RAW_SIZE_MARK_INT64 3
+
+#ifndef MAX_STRING_LEN_POSSIBLE
+#define MAX_STRING_LEN_POSSIBLE 2000000000 //do not let string be so big
+#endif
+
+//data types
+#define SERIALIZE_TYPE_INT64 1
+#define SERIALIZE_TYPE_INT32 2
+#define SERIALIZE_TYPE_INT16 3
+#define SERIALIZE_TYPE_INT8 4
+#define SERIALIZE_TYPE_UINT64 5
+#define SERIALIZE_TYPE_UINT32 6
+#define SERIALIZE_TYPE_UINT16 7
+#define SERIALIZE_TYPE_UINT8 8
+#define SERIALIZE_TYPE_DUOBLE 9
+#define SERIALIZE_TYPE_STRING 10
+#define SERIALIZE_TYPE_BOOL 11
+#define SERIALIZE_TYPE_OBJECT 12
+#define SERIALIZE_TYPE_ARRAY 13
+
+#define SERIALIZE_FLAG_ARRAY 0x80
+
+
+namespace epee
+{
+ namespace serialization
+ {
+ struct section;
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_entry_type>
+ struct array_entry_t
+ {
+ array_entry_t():m_it(m_array.end()){}
+
+ const t_entry_type* get_first_val() const
+ {
+ m_it = m_array.begin();
+ return get_next_val();
+ }
+
+ t_entry_type* get_first_val()
+ {
+ m_it = m_array.begin();
+ return get_next_val();
+ }
+
+
+ const t_entry_type* get_next_val() const
+ {
+ if(m_it == m_array.end())
+ return nullptr;
+ return &(*(m_it++));
+ }
+
+ t_entry_type* get_next_val()
+ {
+ if(m_it == m_array.end())
+ return nullptr;
+ return (t_entry_type*)&(*(m_it++));//fuckoff
+ }
+
+ t_entry_type& insert_first_val(const t_entry_type& v)
+ {
+ m_array.clear();
+ m_it = m_array.end();
+ return insert_next_value(v);
+ }
+
+ t_entry_type& insert_next_value(const t_entry_type& v)
+ {
+ m_array.push_back(v);
+ return m_array.back();
+ }
+
+ std::list<t_entry_type> m_array;
+ mutable typename std::list<t_entry_type>::const_iterator m_it;
+ };
+
+
+ typedef boost::make_recursive_variant<
+ array_entry_t<section>,
+ array_entry_t<uint64_t>,
+ array_entry_t<uint32_t>,
+ array_entry_t<uint16_t>,
+ array_entry_t<uint8_t>,
+ array_entry_t<int64_t>,
+ array_entry_t<int32_t>,
+ array_entry_t<int16_t>,
+ array_entry_t<int8_t>,
+ array_entry_t<double>,
+ array_entry_t<bool>,
+ array_entry_t<std::string>,
+ array_entry_t<section>,
+ array_entry_t<boost::recursive_variant_>
+ >::type array_entry;
+
+ typedef boost::variant<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, section, array_entry> storage_entry;
+
+ typedef std::string binarybuffer;//it's ok
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct section
+ {
+ std::map<std::string, storage_entry> m_entries;
+ };
+
+ //handle-like aliases
+ typedef section* hsection;
+ typedef array_entry* harray;
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
new file mode 100644
index 000000000..e9b7e2e6f
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -0,0 +1,281 @@
+// 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 "misc_language.h"
+#include "portable_storage_base.h"
+
+#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
+#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
+#else
+#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL 100
+#endif
+
+namespace epee
+{
+ namespace serialization
+ {
+ struct throwable_buffer_reader
+ {
+ throwable_buffer_reader(const void* ptr, size_t sz);
+ void read(void* target, size_t count);
+ void read_sec_name(std::string& sce_name);
+ template<class t_pod_type>
+ void read(t_pod_type& pod_val);
+ template<class t_type>
+ t_type read();
+ template<class type_name>
+ storage_entry read_ae();
+ storage_entry load_storage_array_entry(uint8_t type);
+ size_t read_varint();
+ template<class t_type>
+ storage_entry read_se();
+ storage_entry load_storage_entry();
+ void read(section& sec);
+ void read(std::string& str);
+ private:
+ struct recursuion_limitation_guard
+ {
+ size_t& m_counter_ref;
+ recursuion_limitation_guard(size_t& counter):m_counter_ref(counter)
+ {
+ ++m_counter_ref;
+ CHECK_AND_ASSERT_THROW_MES(m_counter_ref < EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL, "Wrong blob data in portable storage: recursion limitation (" << EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL << ") exceeded");
+ }
+ ~recursuion_limitation_guard()
+ {
+ CHECK_AND_ASSERT_THROW_MES(m_counter_ref != 0, "Internal error: m_counter_ref == 0 while ~recursuion_limitation_guard()");
+ --m_counter_ref;
+ }
+ };
+#define RECURSION_LIMITATION() recursuion_limitation_guard rl(m_recursion_count)
+
+ const uint8_t* m_ptr;
+ size_t m_count;
+ size_t m_recursion_count;
+ };
+
+ inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz)
+ {
+ if(!ptr)
+ throw std::runtime_error("throwable_buffer_reader: ptr==nullptr");
+ if(!sz)
+ throw std::runtime_error("throwable_buffer_reader: sz==0");
+ m_ptr = (uint8_t*)ptr;
+ m_count = sz;
+ m_recursion_count = 0;
+ }
+ inline
+ void throwable_buffer_reader::read(void* target, size_t count)
+ {
+ RECURSION_LIMITATION();
+ CHECK_AND_ASSERT_THROW_MES(m_count >= count, " attempt to read " << count << " bytes from buffer with " << m_count << " bytes remained");
+ memcpy(target, m_ptr, count);
+ m_ptr += count;
+ m_count -= count;
+ }
+ inline
+ void throwable_buffer_reader::read_sec_name(std::string& sce_name)
+ {
+ RECURSION_LIMITATION();
+ uint8_t name_len = 0;
+ read(name_len);
+ sce_name.resize(name_len);
+ read((void*)sce_name.data(), name_len);
+ }
+
+ template<class t_pod_type>
+ void throwable_buffer_reader::read(t_pod_type& pod_val)
+ {
+ RECURSION_LIMITATION();
+ read(&pod_val, sizeof(pod_val));
+ }
+
+ template<class t_type>
+ t_type throwable_buffer_reader::read()
+ {
+ RECURSION_LIMITATION();
+ t_type v;
+ read(v);
+ return v;
+ }
+
+
+ template<class type_name>
+ storage_entry throwable_buffer_reader::read_ae()
+ {
+ RECURSION_LIMITATION();
+ //for pod types
+ array_entry_t<type_name> sa;
+ size_t size = read_varint();
+ //TODO: add some optimization here later
+ while(size--)
+ sa.m_array.push_back(read<type_name>());
+ return storage_entry(array_entry(sa));
+ }
+
+ inline
+ storage_entry throwable_buffer_reader::load_storage_array_entry(uint8_t type)
+ {
+ RECURSION_LIMITATION();
+ type &= ~SERIALIZE_FLAG_ARRAY;
+ switch(type)
+ {
+ case SERIALIZE_TYPE_INT64: return read_ae<int64_t>();
+ case SERIALIZE_TYPE_INT32: return read_ae<int32_t>();
+ case SERIALIZE_TYPE_INT16: return read_ae<int16_t>();
+ case SERIALIZE_TYPE_INT8: return read_ae<int8_t>();
+ case SERIALIZE_TYPE_UINT64: return read_ae<uint64_t>();
+ case SERIALIZE_TYPE_UINT32: return read_ae<uint32_t>();
+ case SERIALIZE_TYPE_UINT16: return read_ae<uint16_t>();
+ case SERIALIZE_TYPE_UINT8: return read_ae<uint8_t>();
+ case SERIALIZE_TYPE_DUOBLE: return read_ae<double>();
+ case SERIALIZE_TYPE_BOOL: return read_ae<bool>();
+ case SERIALIZE_TYPE_STRING: return read_ae<std::string>();
+ case SERIALIZE_TYPE_OBJECT: return read_ae<section>();
+ case SERIALIZE_TYPE_ARRAY: return read_ae<array_entry>();
+ default:
+ CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type);
+ }
+ }
+
+ inline
+ size_t throwable_buffer_reader::read_varint()
+ {
+ RECURSION_LIMITATION();
+ CHECK_AND_ASSERT_THROW_MES(m_count >= 1, "empty buff, expected place for varint");
+ size_t v = 0;
+ uint8_t size_mask = (*(uint8_t*)m_ptr) &PORTABLE_RAW_SIZE_MARK_MASK;
+ switch (size_mask)
+ {
+ case PORTABLE_RAW_SIZE_MARK_BYTE: v = read<uint8_t>();break;
+ case PORTABLE_RAW_SIZE_MARK_WORD: v = read<uint16_t>();break;
+ case PORTABLE_RAW_SIZE_MARK_DWORD: v = read<uint32_t>();break;
+ case PORTABLE_RAW_SIZE_MARK_INT64: v = read<uint64_t>();break;
+ default:
+ CHECK_AND_ASSERT_THROW_MES(false, "unknown varint size_mask = " << size_mask);
+ }
+ v >>= 2;
+ return v;
+ }
+
+ template<class t_type>
+ storage_entry throwable_buffer_reader::read_se()
+ {
+ RECURSION_LIMITATION();
+ t_type v;
+ read(v);
+ return storage_entry(v);
+ }
+
+ template<>
+ inline storage_entry throwable_buffer_reader::read_se<std::string>()
+ {
+ RECURSION_LIMITATION();
+ return storage_entry(read<std::string>());
+ }
+
+
+ template<>
+ inline storage_entry throwable_buffer_reader::read_se<section>()
+ {
+ RECURSION_LIMITATION();
+ section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio
+ storage_entry se(s);
+ section& section_entry = boost::get<section>(se);
+ read(section_entry);
+ return se;
+ }
+
+ template<>
+ inline storage_entry throwable_buffer_reader::read_se<array_entry>()
+ {
+ RECURSION_LIMITATION();
+ uint8_t ent_type = 0;
+ read(ent_type);
+ CHECK_AND_ASSERT_THROW_MES(ent_type&SERIALIZE_FLAG_ARRAY, "wrong type sequenses");
+ return load_storage_array_entry(ent_type);
+ }
+
+ inline
+ storage_entry throwable_buffer_reader::load_storage_entry()
+ {
+ RECURSION_LIMITATION();
+ uint8_t ent_type = 0;
+ read(ent_type);
+ if(ent_type&SERIALIZE_FLAG_ARRAY)
+ return load_storage_array_entry(ent_type);
+
+ switch(ent_type)
+ {
+ case SERIALIZE_TYPE_INT64: return read_se<int64_t>();
+ case SERIALIZE_TYPE_INT32: return read_se<int32_t>();
+ case SERIALIZE_TYPE_INT16: return read_se<int16_t>();
+ case SERIALIZE_TYPE_INT8: return read_se<int8_t>();
+ case SERIALIZE_TYPE_UINT64: return read_se<uint64_t>();
+ case SERIALIZE_TYPE_UINT32: return read_se<uint32_t>();
+ case SERIALIZE_TYPE_UINT16: return read_se<uint16_t>();
+ case SERIALIZE_TYPE_UINT8: return read_se<uint8_t>();
+ case SERIALIZE_TYPE_DUOBLE: return read_se<double>();
+ case SERIALIZE_TYPE_BOOL: return read_se<bool>();
+ case SERIALIZE_TYPE_STRING: return read_se<std::string>();
+ case SERIALIZE_TYPE_OBJECT: return read_se<section>();
+ case SERIALIZE_TYPE_ARRAY: return read_se<array_entry>();
+ default:
+ CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type);
+ }
+ }
+ inline
+ void throwable_buffer_reader::read(section& sec)
+ {
+ RECURSION_LIMITATION();
+ sec.m_entries.clear();
+ size_t count = read_varint();
+ while(count--)
+ {
+ //read section name string
+ std::string sec_name;
+ read_sec_name(sec_name);
+ sec.m_entries.insert(std::make_pair(sec_name, load_storage_entry()));
+ }
+ }
+ inline
+ void throwable_buffer_reader::read(std::string& str)
+ {
+ RECURSION_LIMITATION();
+ size_t len = read_varint();
+ CHECK_AND_ASSERT_THROW_MES(len < MAX_STRING_LEN_POSSIBLE, "to big string len value in storage: " << len);
+ CHECK_AND_ASSERT_THROW_MES(m_count >= len, "string len count value " << len << " goes out of remain storage len " << m_count);
+ //do this manually to avoid double memory write in huge strings (first time at resize, second at read)
+ str.assign((const char*)m_ptr, len);
+ m_ptr+=len;
+ m_count -= len;
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
new file mode 100644
index 000000000..557db3da6
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -0,0 +1,379 @@
+// 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 "parserse_base_utils.h"
+#include "file_io_utils.h"
+
+namespace epee
+{
+ using namespace misc_utils::parse;
+ namespace serialization
+ {
+ namespace json
+ {
+#define CHECK_ISSPACE() if(!isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
+
+ /*inline void parse_error()
+ {
+ ASSERT_MES_AND_THROW("json parse error");
+ }*/
+ template<class t_storage>
+ inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg)
+ {
+
+ std::string::const_iterator sub_element_start;
+ std::string name;
+ typename t_storage::harray h_array = nullptr;
+ enum match_state
+ {
+ match_state_lookup_for_section_start,
+ match_state_lookup_for_name,
+ match_state_waiting_separator,
+ match_state_wonder_after_separator,
+ match_state_wonder_after_value,
+ match_state_wonder_array,
+ match_state_array_after_value,
+ match_state_array_waiting_value,
+ match_state_error
+ };
+
+ enum array_mode
+ {
+ array_mode_undifined = 0,
+ array_mode_sections,
+ array_mode_string,
+ array_mode_numbers,
+ array_mode_booleans
+ };
+
+ match_state state = match_state_lookup_for_section_start;
+ array_mode array_md = array_mode_undifined;
+ std::string::const_iterator it = sec_buf_begin;
+ for(;it != buf_end;it++)
+ {
+ switch (state)
+ {
+ case match_state_lookup_for_section_start:
+ if(*it == '{')
+ state = match_state_lookup_for_name;
+ else CHECK_ISSPACE();
+ break;
+ case match_state_lookup_for_name:
+ switch(*it)
+ {
+ case '"':
+ match_string2(it, buf_end, name);
+ state = match_state_waiting_separator;
+ break;
+ case '}':
+ //this is it! section ends here.
+ //seems that it is empty section
+ sec_buf_begin = it;
+ return;
+ default:
+ CHECK_ISSPACE();
+ }
+ break;
+ case match_state_waiting_separator:
+ if(*it == ':')
+ state = match_state_wonder_after_separator;
+ else CHECK_ISSPACE();
+ break;
+ case match_state_wonder_after_separator:
+ if(*it == '"')
+ {//just a named string value started
+ std::string val;
+ match_string2(it, buf_end, val);
+ //insert text value
+ stg.set_value(name, val, current_section);
+ state = match_state_wonder_after_value;
+ }else if (isdigit(*it) || *it == '-')
+ {//just a named number value started
+ std::string val;
+ bool is_v_float = false;bool is_signed = false;
+ match_number2(it, buf_end, val, is_v_float, is_signed);
+ if(!is_v_float)
+ {
+ if(is_signed)
+ {
+ int64_t nval = boost::lexical_cast<int64_t>(val);
+ stg.set_value(name, nval, current_section);
+ }else
+ {
+ uint64_t nval = boost::lexical_cast<uint64_t >(val);
+ stg.set_value(name, nval, current_section);
+ }
+ }else
+ {
+ double nval = boost::lexical_cast<double>(val);
+ stg.set_value(name, nval, current_section);
+ }
+ state = match_state_wonder_after_value;
+ }else if(isalpha(*it) )
+ {// could be null, true or false
+ std::string word;
+ match_word2(it, buf_end, word);
+ if(boost::iequals(word, "null"))
+ {
+ state = match_state_wonder_after_value;
+ //just skip this,
+ }else if(boost::iequals(word, "true"))
+ {
+ stg.set_value(name, true, current_section);
+ state = match_state_wonder_after_value;
+ }else if(boost::iequals(word, "false"))
+ {
+ stg.set_value(name, false, current_section);
+ state = match_state_wonder_after_value;
+ }else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
+ }else if(*it == '{')
+ {
+ //sub section here
+ typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
+ CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
+ run_handler(new_sec, it, buf_end, stg);
+ state = match_state_wonder_after_value;
+ }else if(*it == '[')
+ {//array of something
+ state = match_state_wonder_array;
+ }else CHECK_ISSPACE();
+ break;
+ case match_state_wonder_after_value:
+ if(*it == ',')
+ state = match_state_lookup_for_name;
+ else if(*it == '}')
+ {
+ //this is it! section ends here.
+ sec_buf_begin = it;
+ return;
+ }else CHECK_ISSPACE();
+ break;
+ case match_state_wonder_array:
+ if(*it == '[')
+ {
+ ASSERT_MES_AND_THROW("array of array not suppoerted yet :( sorry");
+ //mean array of array
+ }
+ if(*it == '{')
+ {
+ //mean array of sections
+ typename t_storage::hsection new_sec = nullptr;
+ h_array = stg.insert_first_section(name, new_sec, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
+ run_handler(new_sec, it, buf_end, stg);
+ state = match_state_array_after_value;
+ array_md = array_mode_sections;
+ }else if(*it == '"')
+ {
+ //mean array of strings
+ std::string val;
+ match_string2(it, buf_end, val);
+ h_array = stg.insert_first_value(name, val, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
+ state = match_state_array_after_value;
+ array_md = array_mode_string;
+ }else if (isdigit(*it) || *it == '-')
+ {//array of numbers value started
+ std::string val;
+ bool is_v_float = false;bool is_signed_val = false;
+ match_number2(it, buf_end, val, is_v_float, is_signed_val);
+ if(!is_v_float)
+ {
+ int64_t nval = boost::lexical_cast<int64_t>(val);//bool res = string_tools::string_to_num_fast(val, nval);
+ h_array = stg.insert_first_value(name, nval, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
+ }else
+ {
+ double nval = boost::lexical_cast<double>(val);//bool res = string_tools::string_to_num_fast(val, nval);
+ h_array = stg.insert_first_value(name, nval, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
+ }
+
+ state = match_state_array_after_value;
+ array_md = array_mode_numbers;
+ }else if(*it == ']')//empty array
+ {
+ array_md = array_mode_undifined;
+ state = match_state_wonder_after_value;
+ }else if(isalpha(*it) )
+ {// array of booleans
+ std::string word;
+ match_word2(it, buf_end, word);
+ if(boost::iequals(word, "true"))
+ {
+ h_array = stg.insert_first_value(name, true, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
+ state = match_state_array_after_value;
+ array_md = array_mode_booleans;
+ }else if(boost::iequals(word, "false"))
+ {
+ h_array = stg.insert_first_value(name, false, current_section);
+ CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
+ state = match_state_array_after_value;
+ array_md = array_mode_booleans;
+
+ }else ASSERT_MES_AND_THROW("Unknown value keyword " << word)
+ }else CHECK_ISSPACE();
+ break;
+ case match_state_array_after_value:
+ if(*it == ',')
+ state = match_state_array_waiting_value;
+ else if(*it == ']')
+ {
+ h_array = nullptr;
+ array_md = array_mode_undifined;
+ state = match_state_wonder_after_value;
+ }else CHECK_ISSPACE();
+ break;
+ case match_state_array_waiting_value:
+ switch(array_md)
+ {
+ case array_mode_sections:
+ if(*it == '{')
+ {
+ typename t_storage::hsection new_sec = NULL;
+ bool res = stg.insert_next_section(h_array, new_sec);
+ CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
+ run_handler(new_sec, it, buf_end, stg);
+ state = match_state_array_after_value;
+ }else CHECK_ISSPACE();
+ break;
+ case array_mode_string:
+ if(*it == '"')
+ {
+ std::string val;
+ match_string2(it, buf_end, val);
+ bool res = stg.insert_next_value(h_array, val);
+ CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
+ state = match_state_array_after_value;
+ }else CHECK_ISSPACE();
+ break;
+ case array_mode_numbers:
+ if (isdigit(*it) || *it == '-')
+ {//array of numbers value started
+ std::string val;
+ bool is_v_float = false;bool is_signed_val = false;
+ match_number2(it, buf_end, val, is_v_float, is_signed_val);
+ bool insert_res = false;
+ if(!is_v_float)
+ {
+ boost::int64_t nval = boost::lexical_cast<int64_t>(val); //bool res = string_tools::string_to_num_fast(val, nval);
+ insert_res = stg.insert_next_value(h_array, nval);
+
+ }else
+ {
+ //TODO: optimize here if need
+ double nval = boost::lexical_cast<double>(val); //string_tools::string_to_num_fast(val, nval);
+ insert_res = stg.insert_next_value(h_array, nval);
+ }
+ CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
+ state = match_state_array_after_value;
+ array_md = array_mode_numbers;
+ }else CHECK_ISSPACE();
+ break;
+ case array_mode_booleans:
+ if(isalpha(*it) )
+ {// array of booleans
+ std::string word;
+ match_word2(it, buf_end, word);
+ if(boost::iequals(word, "true"))
+ {
+ bool r = stg.insert_next_value(h_array, true);
+ CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
+ state = match_state_array_after_value;
+ }else if(boost::iequals(word, "false"))
+ {
+ bool r = stg.insert_next_value(h_array, false);
+ CHECK_AND_ASSERT_THROW_MES(r, " failed to insert values section entry");
+ state = match_state_array_after_value;
+ }
+ else ASSERT_MES_AND_THROW("Unknown value keyword " << word);
+ }else CHECK_ISSPACE();
+ break;
+ case array_mode_undifined:
+ default:
+ ASSERT_MES_AND_THROW("Bad array state");
+ }
+ break;
+ case match_state_error:
+ default:
+ ASSERT_MES_AND_THROW("WRONG JSON STATE");
+ }
+ }
+ }
+/*
+{
+ "firstName": "John",
+ "lastName": "Smith",
+ "age": 25,
+ "address": {
+ "streetAddress": "21 2nd Street",
+ "city": "New York",
+ "state": "NY",
+ "postalCode": -10021,
+ "have_boobs": true,
+ "have_balls": false
+ },
+ "phoneNumber": [
+ {
+ "type": "home",
+ "number": "212 555-1234"
+ },
+ {
+ "type": "fax",
+ "number": "646 555-4567"
+ }
+ ],
+ "phoneNumbers": [
+ "812 123-1234",
+ "916 123-4567"
+ ]
+}
+*/
+ template<class t_storage>
+ inline bool load_from_json(const std::string& buff_json, t_storage& stg)
+ {
+ std::string::const_iterator sec_buf_begin = buff_json.begin();
+ try
+ {
+ run_handler(nullptr, sec_buf_begin, buff_json.end(), stg);
+ return true;
+ }
+ catch(const std::exception& ex)
+ {
+ LOG_PRINT_RED_L0("Failed to parse json, what: " << ex.what());
+ return false;
+ }
+ catch(...)
+ {
+ LOG_PRINT_RED_L0("Failed to parse json");
+ return false;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h
new file mode 100644
index 000000000..2163cb879
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_template_helper.h
@@ -0,0 +1,120 @@
+// 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 "parserse_base_utils.h"
+#include "portable_storage.h"
+#include "file_io_utils.h"
+
+namespace epee
+{
+ namespace serialization
+ {
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool load_t_from_json(t_struct& out, const std::string& json_buff)
+ {
+ portable_storage ps;
+ bool rs = ps.load_from_json(json_buff);
+ if(!rs)
+ return false;
+
+ return out.load(ps);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool load_t_from_json_file(t_struct& out, const std::string& json_file)
+ {
+ std::string f_buff;
+ if(!file_io_utils::load_file_to_string(json_file, f_buff))
+ return false;
+
+ return load_t_from_json(out, f_buff);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool store_t_to_json(t_struct& str_in, std::string& json_buff, size_t indent = 0)
+ {
+ portable_storage ps;
+ str_in.store(ps);
+ ps.dump_as_json(json_buff, indent);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ std::string store_t_to_json(t_struct& str_in, size_t indent = 0)
+ {
+ std::string json_buff;
+ store_t_to_json(str_in, json_buff, indent);
+ return std::move(json_buff);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool store_t_to_json_file(t_struct& str_in, const std::string& fpath)
+ {
+ std::string json_buff;
+ store_t_to_json(str_in, json_buff);
+ return file_io_utils::save_string_to_file(fpath, json_buff);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
+ {
+ portable_storage ps;
+ bool rs = ps.load_from_binary(binary_buff);
+ if(!rs)
+ return false;
+
+ return out.load(ps);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool load_t_from_binary_file(t_struct& out, const std::string& binary_file)
+ {
+ std::string f_buff;
+ if(!file_io_utils::load_file_to_string(binary_file, f_buff))
+ return false;
+
+ return load_t_from_binary(out, f_buff);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ bool store_t_to_binary(t_struct& str_in, std::string& binary_buff, size_t indent = 0)
+ {
+ portable_storage ps;
+ str_in.store(ps);
+ return ps.store_to_binary(binary_buff);
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
+ std::string store_t_to_binary(t_struct& str_in, size_t indent = 0)
+ {
+ std::string binary_buff;
+ store_t_to_binary(str_in, binary_buff, indent);
+ return std::move(binary_buff);
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_to_bin.h b/contrib/epee/include/storages/portable_storage_to_bin.h
new file mode 100644
index 000000000..baf90290a
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_to_bin.h
@@ -0,0 +1,212 @@
+// 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 "misc_language.h"
+#include "portable_storage_base.h"
+
+namespace epee
+{
+ namespace serialization
+ {
+
+ template<class pack_value, class t_stream>
+ size_t pack_varint_t(t_stream& strm, uint8_t type_or, size_t& pv)
+ {
+ pack_value v = (*((pack_value*)&pv)) << 2;
+ v |= type_or;
+ strm.write((const char*)&v, sizeof(pack_value));
+ return sizeof(pack_value);
+ }
+
+ PRAGMA_WARNING_PUSH
+ PRAGMA_GCC("GCC diagnostic ignored \"-Wstrict-aliasing\"")
+ template<class t_stream>
+ size_t pack_varint(t_stream& strm, size_t val)
+ { //the first two bits always reserved for size information
+
+ if(val <= 63)
+ {//mean enough one byte
+ return pack_varint_t<uint8_t>(strm, PORTABLE_RAW_SIZE_MARK_BYTE, val);
+ }
+ else if(val <= 16383)
+ {//mean need word
+ return pack_varint_t<uint16_t>(strm, PORTABLE_RAW_SIZE_MARK_WORD, val);
+ }else if(val <= 1073741823)
+ {//mean need dword
+ return pack_varint_t<uint32_t>(strm, PORTABLE_RAW_SIZE_MARK_DWORD, val);
+ }else
+ {
+ CHECK_AND_ASSERT_THROW_MES(val <= 4611686018427387903, "failed to pack varint - too big amount = " << val);
+ return pack_varint_t<uint64_t>(strm, PORTABLE_RAW_SIZE_MARK_INT64, val);
+ }
+ }
+ PRAGMA_WARNING_POP
+
+ template<class t_stream>
+ bool put_string(t_stream& strm, const std::string& v)
+ {
+ pack_varint(strm, v.size());
+ if(v.size())
+ strm.write((const char*)v.data(), v.size());
+ return true;
+ }
+
+ template<class t_stream>
+ struct array_entry_store_visitor: public boost::static_visitor<bool>
+ {
+ t_stream& m_strm;
+
+ template<class t_pod_type>
+ bool pack_pod_array_type(uint8_t contained_type, const array_entry_t<t_pod_type>& arr_pod)
+ {
+ uint8_t type = contained_type|SERIALIZE_FLAG_ARRAY;
+ m_strm.write((const char*)&type, 1);
+ pack_varint(m_strm, arr_pod.m_array.size());
+ for(const t_pod_type& x: arr_pod.m_array)
+ m_strm.write((const char*)&x, sizeof(t_pod_type));
+ return true;
+ }
+
+ array_entry_store_visitor(t_stream& strm):m_strm(strm){}
+ bool operator()(const array_entry_t<uint64_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT64, v);}
+ bool operator()(const array_entry_t<uint32_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT32, v);}
+ bool operator()(const array_entry_t<uint16_t>& v){ return pack_pod_array_type(SERIALIZE_TYPE_UINT16, v);}
+ bool operator()(const array_entry_t<uint8_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_UINT8, v);}
+ bool operator()(const array_entry_t<int64_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT64, v);}
+ bool operator()(const array_entry_t<int32_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT32, v);}
+ bool operator()(const array_entry_t<int16_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT16, v);}
+ bool operator()(const array_entry_t<int8_t>& v) { return pack_pod_array_type(SERIALIZE_TYPE_INT8, v);}
+ bool operator()(const array_entry_t<double>& v) { return pack_pod_array_type(SERIALIZE_TYPE_DUOBLE, v);}
+ bool operator()(const array_entry_t<bool>& v) { return pack_pod_array_type(SERIALIZE_TYPE_BOOL, v);}
+ bool operator()(const array_entry_t<std::string>& arr_str)
+ {
+ uint8_t type = SERIALIZE_TYPE_STRING|SERIALIZE_FLAG_ARRAY;
+ m_strm.write((const char*)&type, 1);
+ pack_varint(m_strm, arr_str.m_array.size());
+ for(const std::string& s: arr_str.m_array)
+ put_string(m_strm, s);
+ return true;
+ }
+ bool operator()(const array_entry_t<section>& arr_sec)
+ {
+ uint8_t type = SERIALIZE_TYPE_OBJECT|SERIALIZE_FLAG_ARRAY;
+ m_strm.write((const char*)&type, 1);
+ pack_varint(m_strm, arr_sec.m_array.size());
+ for(const section& s: arr_sec.m_array)
+ pack_entry_to_buff(m_strm, s);
+ return true;
+ }
+ bool operator()(const array_entry_t<array_entry>& arra_ar)
+ {
+ uint8_t type = SERIALIZE_TYPE_ARRAY|SERIALIZE_FLAG_ARRAY;
+ m_strm.write((const char*)&type, 1);
+ pack_varint(m_strm, arra_ar.m_array.size());
+ for(const array_entry& s: arra_ar.m_array)
+ pack_entry_to_buff(m_strm, s);
+ return true;
+ }
+ };
+
+ template<class t_stream>
+ struct storage_entry_store_visitor: public boost::static_visitor<bool>
+ {
+ t_stream& m_strm;
+ storage_entry_store_visitor(t_stream& strm):m_strm(strm){}
+ template<class pod_type>
+ bool pack_pod_type(uint8_t type, const pod_type& v)
+ {
+ m_strm.write((const char*)&type, 1);
+ m_strm.write((const char*)&v, sizeof(pod_type));
+ return true;
+ }
+ //section, array_entry
+ bool operator()(const uint64_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT64, v);}
+ bool operator()(const uint32_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT32, v);}
+ bool operator()(const uint16_t& v){ return pack_pod_type(SERIALIZE_TYPE_UINT16, v);}
+ bool operator()(const uint8_t& v) { return pack_pod_type(SERIALIZE_TYPE_UINT8, v);}
+ bool operator()(const int64_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT64, v);}
+ bool operator()(const int32_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT32, v);}
+ bool operator()(const int16_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT16, v);}
+ bool operator()(const int8_t& v) { return pack_pod_type(SERIALIZE_TYPE_INT8, v);}
+ bool operator()(const double& v) { return pack_pod_type(SERIALIZE_TYPE_DUOBLE, v);}
+ bool operator()(const bool& v) { return pack_pod_type(SERIALIZE_TYPE_BOOL, v);}
+ bool operator()(const std::string& v)
+ {
+ uint8_t type = SERIALIZE_TYPE_STRING;
+ m_strm.write((const char*)&type, 1);
+ put_string(m_strm, v);
+ return true;
+ }
+ bool operator()(const section& v)
+ {
+ uint8_t type = SERIALIZE_TYPE_OBJECT;
+ m_strm.write((const char*)&type, 1);
+ return pack_entry_to_buff(m_strm, v);
+ }
+
+ bool operator()(const array_entry& v)
+ {
+ //uint8_t type = SERIALIZE_TYPE_ARRAY;
+ //m_strm.write((const char*)&type, 1);
+ return pack_entry_to_buff(m_strm, v);
+ }
+ };
+
+ template<class t_stream>
+ bool pack_entry_to_buff(t_stream& strm, const array_entry& ae)
+ {
+ array_entry_store_visitor<t_stream> aesv(strm);
+ return boost::apply_visitor(aesv, ae);
+ }
+
+ template<class t_stream>
+ bool pack_entry_to_buff(t_stream& strm, const storage_entry& se)
+ {
+ storage_entry_store_visitor<t_stream> sv(strm);
+ return boost::apply_visitor(sv, se);
+ }
+
+ template<class t_stream>
+ bool pack_entry_to_buff(t_stream& strm, const section& sec)
+ {
+ typedef std::map<std::string, storage_entry>::value_type section_pair;
+ pack_varint(strm, sec.m_entries.size());
+ for(const section_pair& se: sec.m_entries)
+ {
+ CHECK_AND_ASSERT_THROW_MES(se.first.size() < std::numeric_limits<uint8_t>::max(), "storage_entry_name is too long: " << se.first.size() << ", val: " << se.first);
+ uint8_t len = static_cast<uint8_t>(se.first.size());
+ strm.write((const char*)&len, sizeof(len));
+ strm.write(se.first.data(), size_t(len));
+ pack_entry_to_buff(strm, se.second);
+ }
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_to_json.h b/contrib/epee/include/storages/portable_storage_to_json.h
new file mode 100644
index 000000000..aff85b201
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_to_json.h
@@ -0,0 +1,172 @@
+// 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 "misc_language.h"
+#include "portable_storage_base.h"
+
+namespace epee
+{
+ namespace serialization
+ {
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const std::string& v, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const int8_t& v, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const bool& v, size_t indent);
+ template<class t_stream, class t_type>
+ void dump_as_json(t_stream& strm, const t_type& v, size_t indent);
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const section& sec, size_t indent);
+
+
+ inline std::string make_indent(size_t indent)
+ {
+ return std::string(indent*2, ' ');
+ }
+
+ template<class t_stream>
+ struct array_entry_store_to_json_visitor: public boost::static_visitor<void>
+ {
+ t_stream& m_strm;
+ size_t m_indent;
+ array_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent){}
+
+ template<class t_type>
+ void operator()(const array_entry_t<t_type>& a)
+ {
+ m_strm << "[";
+ if(a.m_array.size())
+ {
+ auto last_it = --a.m_array.end();
+ for(auto it = a.m_array.begin(); it != a.m_array.end(); it++)
+ {
+ dump_as_json(m_strm, *it, m_indent);
+ if(it != last_it)
+ m_strm << ",";
+ }
+ }
+ m_strm << "]";
+ }
+ };
+
+ template<class t_stream>
+ struct storage_entry_store_to_json_visitor: public boost::static_visitor<void>
+ {
+ t_stream& m_strm;
+ size_t m_indent;
+ storage_entry_store_to_json_visitor(t_stream& strm, size_t indent):m_strm(strm), m_indent(indent)
+ {}
+ //section, array_entry
+ template<class visited_type>
+ void operator()(const visited_type& v)
+ {
+ dump_as_json(m_strm, v, m_indent);
+ }
+ };
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent)
+ {
+ array_entry_store_to_json_visitor<t_stream> aesv(strm, indent);
+ boost::apply_visitor(aesv, ae);
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent)
+ {
+ storage_entry_store_to_json_visitor<t_stream> sv(strm, indent);
+ boost::apply_visitor(sv, se);
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const std::string& v, size_t indent)
+ {
+ strm << "\"" << misc_utils::parse::transform_to_escape_sequence(v) << "\"";
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const int8_t& v, size_t indent)
+ {
+ strm << static_cast<int32_t>(v);
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent)
+ {
+ strm << static_cast<int32_t>(v);
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const bool& v, size_t indent)
+ {
+ if(v)
+ strm << "true";
+ else
+ strm << "false";
+ }
+
+
+
+ template<class t_stream, class t_type>
+ void dump_as_json(t_stream& strm, const t_type& v, size_t indent)
+ {
+ strm << v;
+ }
+
+ template<class t_stream>
+ void dump_as_json(t_stream& strm, const section& sec, size_t indent)
+ {
+ size_t local_indent = indent + 1;
+ strm << "{\r\n";
+ std::string indent_str = make_indent(local_indent);
+ if(sec.m_entries.size())
+ {
+ auto it_last = --sec.m_entries.end();
+ for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++)
+ {
+ strm << indent_str << "\"" << misc_utils::parse::transform_to_escape_sequence(it->first) << "\"" << ": ";
+ dump_as_json(strm, it->second, local_indent);
+ if(it_last != it)
+ strm << ",";
+ strm << "\r\n";
+ }
+ }
+ strm << make_indent(indent) << "}";
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h
new file mode 100644
index 000000000..6ea505886
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_val_converters.h
@@ -0,0 +1,169 @@
+// 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 "misc_language.h"
+#include "portable_storage_base.h"
+#include "warnings.h"
+
+namespace epee
+{
+ namespace serialization
+ {
+#define ASSERT_AND_THROW_WRONG_CONVERSION() ASSERT_MES_AND_THROW("WRONG DATA CONVERSION: from type=" << typeid(from).name() << " to type " << typeid(to).name())
+
+ template<typename from_type, typename to_type>
+ void convert_int_to_uint(const from_type& from, to_type& to)
+ {
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4018)
+ CHECK_AND_ASSERT_THROW_MES(from >=0, "unexpected int value with signed storage value less than 0, and unsigned receiver value");
+DISABLE_GCC_AND_CLANG_WARNING(sign-compare)
+ CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
+ to = static_cast<to_type>(from);
+POP_WARNINGS
+ }
+ template<typename from_type, typename to_type>
+ void convert_int_to_int(const from_type& from, to_type& to)
+ {
+ CHECK_AND_ASSERT_THROW_MES(from >= boost::numeric::bounds<to_type>::lowest(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with lowest possible value = " << boost::numeric::bounds<to_type>::lowest());
+PUSH_WARNINGS
+DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare)
+ CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "int value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
+POP_WARNINGS
+ to = static_cast<to_type>(from);
+ }
+ template<typename from_type, typename to_type>
+ void convert_uint_to_any_int(const from_type& from, to_type& to)
+ {
+PUSH_WARNINGS
+DISABLE_VS_WARNINGS(4018)
+DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare)
+ CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits<to_type>::max(), "uint value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits<to_type>::max());
+ to = static_cast<to_type>(from);
+POP_WARNINGS
+ }
+
+ template<typename from_type, typename to_type, bool, bool> //is from signed, is from to signed
+ struct convert_to_signed_unsigned;
+
+ template<typename from_type, typename to_type>
+ struct convert_to_signed_unsigned<from_type, to_type, true, true>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {//from signed to signed
+ convert_int_to_int(from, to);
+ }
+ };
+
+ template<typename from_type, typename to_type>
+ struct convert_to_signed_unsigned<from_type, to_type, true, false>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {//from signed to unsigned
+ convert_int_to_uint(from, to);
+ }
+ };
+
+ template<typename from_type, typename to_type>
+ struct convert_to_signed_unsigned<from_type, to_type, false, true>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {//from unsigned to signed
+ convert_uint_to_any_int(from, to);
+ }
+ };
+
+ template<typename from_type, typename to_type>
+ struct convert_to_signed_unsigned<from_type, to_type, false, false>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {
+ //from unsigned to unsigned
+ convert_uint_to_any_int(from, to);
+ }
+ };
+
+ template<typename from_type, typename to_type, bool>
+ struct convert_to_integral;
+
+ template<typename from_type, typename to_type>
+ struct convert_to_integral<from_type, to_type, true>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {
+ convert_to_signed_unsigned<from_type, to_type, std::is_signed<from_type>::value, std::is_signed<to_type>::value>::convert(from, to);
+ }
+ };
+
+ template<typename from_type, typename to_type>
+ struct convert_to_integral<from_type, to_type, false>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {
+ ASSERT_AND_THROW_WRONG_CONVERSION();
+ }
+ };
+
+ template<class from_type, class to_type>
+ struct is_convertable: std::integral_constant<bool,
+ std::is_integral<to_type>::value &&
+ std::is_integral<from_type>::value &&
+ !std::is_same<from_type, bool>::value &&
+ !std::is_same<to_type, bool>::value > {};
+
+ template<typename from_type, typename to_type, bool>
+ struct convert_to_same;
+
+ template<typename from_type, typename to_type>
+ struct convert_to_same<from_type, to_type, true>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {
+ to = from;
+ }
+ };
+
+ template<typename from_type, typename to_type>
+ struct convert_to_same<from_type, to_type, false>
+ {
+ static void convert(const from_type& from, to_type& to)
+ {
+ convert_to_integral<from_type, to_type, is_convertable<from_type, to_type>::value>::convert(from, to);// ASSERT_AND_THROW_WRONG_CONVERSION();
+ }
+ };
+
+
+ template<class from_type, class to_type>
+ void convert_t(const from_type& from, to_type& to)
+ {
+ convert_to_same<from_type, to_type, std::is_same<to_type, from_type>::value>::convert(from, to);
+ }
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/include/string_coding.h b/contrib/epee/include/string_coding.h
new file mode 100644
index 000000000..a2e3d6eb2
--- /dev/null
+++ b/contrib/epee/include/string_coding.h
@@ -0,0 +1,295 @@
+// 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 _STRING_CODING_H_
+#define _STRING_CODING_H_
+
+#include <string>
+//#include "md5_l.h"
+namespace epee
+{
+namespace string_encoding
+{
+ inline std::string convert_to_ansii(const std::wstring& str_from)
+ {
+
+ std::string res(str_from.begin(), str_from.end());
+ return res;
+ /*
+ std::string result;
+ std::locale loc;
+ for(unsigned int i= 0; i < str_from.size(); ++i)
+ {
+ result += std::use_facet<std::ctype<wchar_t> >(loc).narrow(str_from[i]);
+ }
+ return result;
+ */
+
+ //return boost::lexical_cast<std::string>(str_from);
+ /*
+ std::string str_trgt;
+ if(!str_from.size())
+ return str_trgt;
+ int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 );
+ if(!cb)
+ return str_trgt;
+ str_trgt.resize(cb);
+ ::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(),
+ (char*)str_trgt.data(), (int)str_trgt.size(), 0, 0);
+ return str_trgt;*/
+ }
+#ifdef WINDOWS_PLATFORM_EX
+ inline std::string convert_to_ansii_win(const std::wstring& str_from)
+ {
+
+ int code_page = CP_ACP;
+ std::string str_trgt;
+ if(!str_from.size())
+ return str_trgt;
+ int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 );
+ if(!cb)
+ return str_trgt;
+ str_trgt.resize(cb);
+ ::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(),
+ (char*)str_trgt.data(), (int)str_trgt.size(), 0, 0);
+ return str_trgt;
+ }
+#endif
+
+ inline std::string convert_to_ansii(const std::string& str_from)
+ {
+ return str_from;
+ }
+
+ inline std::wstring convert_to_unicode(const std::string& str_from)
+ {
+ std::wstring result;
+ std::locale loc;
+ for(unsigned int i= 0; i < str_from.size(); ++i)
+ {
+ result += std::use_facet<std::ctype<wchar_t> >(loc).widen(str_from[i]);
+ }
+ return result;
+
+ //return boost::lexical_cast<std::wstring>(str_from);
+ /*
+ std::wstring str_trgt;
+ if(!str_from.size())
+ return str_trgt;
+
+ int cb = ::MultiByteToWideChar( code_page, 0, str_from.data(), (int)str_from.size(), 0, 0 );
+ if(!cb)
+ return str_trgt;
+
+ str_trgt.resize(cb);
+ ::MultiByteToWideChar( code_page, 0, str_from.data(),(int)str_from.size(),
+ (wchar_t*)str_trgt.data(),(int)str_trgt.size());
+ return str_trgt;*/
+ }
+ inline std::wstring convert_to_unicode(const std::wstring& str_from)
+ {
+ return str_from;
+ }
+
+ template<class target_string>
+ inline target_string convert_to_t(const std::wstring& str_from);
+
+ template<>
+ inline std::string convert_to_t<std::string>(const std::wstring& str_from)
+ {
+ return convert_to_ansii(str_from);
+ }
+
+ template<>
+ inline std::wstring convert_to_t<std::wstring>(const std::wstring& str_from)
+ {
+ return str_from;
+ }
+
+ template<class target_string>
+ inline target_string convert_to_t(const std::string& str_from);
+
+ template<>
+ inline std::string convert_to_t<std::string>(const std::string& str_from)
+ {
+ return str_from;
+ }
+
+ template<>
+ inline std::wstring convert_to_t<std::wstring>(const std::string& str_from)
+ {
+ return convert_to_unicode(str_from);
+ }
+
+ inline
+ std::string& base64_chars()
+ {
+
+ static std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+ return chars;
+
+ }
+
+ inline
+ std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len) {
+ std::string ret;
+ int i = 0;
+ int j = 0;
+ unsigned char char_array_3[3];
+ unsigned char char_array_4[4];
+
+ while (in_len--) {
+ char_array_3[i++] = *(bytes_to_encode++);
+ if (i == 3) {
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for(i = 0; (i <4) ; i++)
+ ret += base64_chars()[char_array_4[i]];
+ i = 0;
+ }
+ }
+
+ if (i)
+ {
+ for(j = i; j < 3; j++)
+ char_array_3[j] = '\0';
+
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for (j = 0; (j < i + 1); j++)
+ ret += base64_chars()[char_array_4[j]];
+
+ while((i++ < 3))
+ ret += '=';
+
+ }
+
+ return ret;
+
+ }
+
+ inline
+ std::string base64_encode(const std::string& str)
+ {
+ return base64_encode((unsigned char const* )str.data(), str.size());
+ }
+
+ inline bool is_base64(unsigned char c) {
+ return (isalnum(c) || (c == '+') || (c == '/'));
+ }
+
+
+ inline
+ std::string base64_decode(std::string const& encoded_string) {
+ size_t in_len = encoded_string.size();
+ size_t i = 0;
+ size_t j = 0;
+ size_t in_ = 0;
+ unsigned char char_array_4[4], char_array_3[3];
+ std::string ret;
+
+ while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+ char_array_4[i++] = encoded_string[in_]; in_++;
+ if (i ==4) {
+ for (i = 0; i <4; i++)
+ char_array_4[i] = (unsigned char)base64_chars().find(char_array_4[i]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (i = 0; (i < 3); i++)
+ ret += char_array_3[i];
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j <4; j++)
+ char_array_4[j] = 0;
+
+ for (j = 0; j <4; j++)
+ char_array_4[j] = (unsigned char)base64_chars().find(char_array_4[j]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+ }
+
+ return ret;
+ }
+
+ //md5
+#ifdef MD5_H
+ inline
+ std::string get_buf_as_hex_string(const void* pbuf, size_t len)
+ {
+ std::ostringstream result;
+
+ const unsigned char* p_buff = (const unsigned char*)pbuf;
+
+ for(unsigned int i=0;i<len;i++)
+ { // convert md to hex-represented string (hex-letters in upper case!)
+ result << std::setw(2) << std::setfill('0')
+ << std::setbase(16) << std::nouppercase
+ << (int)*p_buff++;
+ }
+
+ return result.str();
+ }
+
+ inline
+ std::string get_md5_as_hexstring(const void* pbuff, size_t len)
+ {
+ unsigned char output[16] = {0};
+ md5::md5((unsigned char*)pbuff, static_cast<unsigned int>(len), output);
+ return get_buf_as_hex_string(output, sizeof(output));
+ }
+
+ inline
+ std::string get_md5_as_hexstring(const std::string& src)
+ {
+ return get_md5_as_hexstring(src.data(), src.size());
+ }
+#endif
+
+
+}
+}
+
+#endif //_STRING_CODING_H_
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
new file mode 100644
index 000000000..53be7c3ae
--- /dev/null
+++ b/contrib/epee/include/string_tools.h
@@ -0,0 +1,736 @@
+// 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 _STRING_TOOLS_H_
+#define _STRING_TOOLS_H_
+
+//#include <objbase.h>
+#include <locale>
+#include <cstdlib>
+//#include <strsafe.h>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/asio.hpp>
+#include <boost/algorithm/string/compare.hpp>
+#include <boost/algorithm/string.hpp>
+#include "warnings.h"
+
+
+#ifndef OUT
+ #define OUT
+#endif
+
+#ifdef WINDOWS_PLATFORM
+#pragma comment (lib, "Rpcrt4.lib")
+#endif
+
+namespace epee
+{
+namespace string_tools
+{
+ inline std::wstring get_str_from_guid(const boost::uuids::uuid& rid)
+ {
+ return boost::lexical_cast<std::wstring>(rid);
+ }
+ //----------------------------------------------------------------------------
+ inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
+ {
+ return boost::lexical_cast<std::string>(rid);
+ }
+ //----------------------------------------------------------------------------
+ inline bool get_guid_from_string( boost::uuids::uuid& inetifer, std::wstring str_id)
+ {
+ if(str_id.size() < 36)
+ return false;
+
+ if('{' == *str_id.begin())
+ str_id.erase(0, 1);
+
+ if('}' == *(--str_id.end()))
+ str_id.erase(--str_id.end());
+
+ try
+ {
+ inetifer = boost::lexical_cast<boost::uuids::uuid>(str_id);
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ //----------------------------------------------------------------------------
+ inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
+ {
+ std::string local_str_id = str_id;
+ if(local_str_id.size() < 36)
+ return false;
+
+ if('{' == *local_str_id.begin())
+ local_str_id.erase(0, 1);
+
+ if('}' == *(--local_str_id.end()))
+ local_str_id.erase(--local_str_id.end());
+
+ try
+ {
+ inetifer = boost::lexical_cast<boost::uuids::uuid>(local_str_id);
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ //----------------------------------------------------------------------------
+ template<class CharT>
+ std::basic_string<CharT> buff_to_hex(const std::basic_string<CharT>& s)
+ {
+ using namespace std;
+ basic_stringstream<CharT> hexStream;
+ hexStream << hex << noshowbase << setw(2);
+
+ for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
+ {
+ hexStream << "0x"<< static_cast<unsigned int>(static_cast<unsigned char>(*it)) << " ";
+ }
+ return hexStream.str();
+ }
+ //----------------------------------------------------------------------------
+ template<class CharT>
+ std::basic_string<CharT> buff_to_hex_nodelimer(const std::basic_string<CharT>& s)
+ {
+ using namespace std;
+ basic_stringstream<CharT> hexStream;
+ hexStream << hex << noshowbase;
+
+ for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
+ {
+ hexStream << setw(2) << setfill('0') << static_cast<unsigned int>(static_cast<unsigned char>(*it));
+ }
+ return hexStream.str();
+ }
+ //----------------------------------------------------------------------------
+ template<class CharT>
+ bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res)
+ {
+ res.clear();
+ try
+ {
+ long v = 0;
+ for(size_t i = 0; i < (s.size() + 1) / 2; i++)
+ {
+ CharT byte_str[3];
+ size_t copied = s.copy(byte_str, 2, 2 * i);
+ byte_str[copied] = CharT(0);
+ CharT* endptr;
+ v = strtoul(byte_str, &endptr, 16);
+ if (v < 0 || 0xFF < v || endptr != byte_str + copied)
+ {
+ return false;
+ }
+ res.push_back(static_cast<unsigned char>(v));
+ }
+
+ return true;
+ }catch(...)
+ {
+ return false;
+ }
+ }
+ //----------------------------------------------------------------------------
+ template<class t_pod_type>
+ bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod)
+ {
+ std::string buf;
+ bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
+ if (!res || buf.size() != sizeof(t_pod_type))
+ {
+ return false;
+ }
+ else
+ {
+ buf.copy(reinterpret_cast<char *>(&t_pod), sizeof(t_pod_type));
+ return true;
+ }
+ }
+ //----------------------------------------------------------------------------
+PUSH_WARNINGS
+DISABLE_GCC_WARNING(maybe-uninitialized)
+ template<class XType>
+ inline bool get_xtype_from_string(OUT XType& val, const std::string& str_id)
+ {
+ try
+ {
+ val = boost::lexical_cast<XType>(str_id);
+ return true;
+ }
+ catch(std::exception& /*e*/)
+ {
+ //const char* pmsg = e.what();
+ return false;
+ }
+
+ catch(...)
+ {
+ return false;
+ }
+
+ return true;
+ }
+POP_WARNINGS
+ //---------------------------------------------------
+ template<typename int_t>
+ bool get_xnum_from_hex_string(const std::string str, int_t& res )
+ {
+ try
+ {
+ std::stringstream ss;
+ ss << std::hex << str;
+ ss >> res;
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+ //----------------------------------------------------------------------------
+ template<class XType>
+ inline bool xtype_to_string(const XType& val, std::string& str)
+ {
+ try
+ {
+ str = boost::lexical_cast<std::string>(val);
+ }
+ catch(...)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ typedef std::map<std::string, std::string> command_line_params_a;
+ typedef std::map<std::wstring, std::wstring> command_line_params_w;
+
+ template<class t_string>
+ bool parse_commandline(std::map<t_string, t_string>& res, int argc, char** argv)
+ {
+ t_string key;
+ for(int i = 1; i < argc; i++)
+ {
+ if(!argv[i])
+ break;
+ t_string s = argv[i];
+ std::string::size_type p = s.find('=');
+ if(std::string::npos == p)
+ {
+ res[s] = "";
+ }else
+ {
+ std::string ss;
+ t_string nm = s.substr(0, p);
+ t_string vl = s.substr(p+1, s.size());
+ res[nm] = vl;
+ }
+ }
+ return true;
+ }
+
+/* template<typename t_type>
+ bool get_xparam_from_command_line(const std::map<std::string, std::string>& res, const std::basic_string<typename t_string::value_type> & key, t_type& val)
+ {
+
+ }
+ */
+
+ template<class t_string, typename t_type>
+ bool get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, t_type& val)
+ {
+ typename std::map<t_string, t_string>::const_iterator it = res.find(key);
+ if(it == res.end())
+ return false;
+
+ if(it->second.size())
+ {
+ return get_xtype_from_string(val, it->second);
+ }
+
+ return true;
+ }
+
+ template<class t_string, typename t_type>
+ t_type get_xparam_from_command_line(const std::map<t_string, t_string>& res, const t_string & key, const t_type& default_value)
+ {
+ typename std::map<t_string, t_string>::const_iterator it = res.find(key);
+ if(it == res.end())
+ return default_value;
+
+ if(it->second.size())
+ {
+ t_type s;
+ get_xtype_from_string(s, it->second);
+ return s;
+ }
+
+ return default_value;
+ }
+
+ template<class t_string>
+ bool have_in_command_line(const std::map<t_string, t_string>& res, const std::basic_string<typename t_string::value_type>& key)
+ {
+ typename std::map<t_string, t_string>::const_iterator it = res.find(key);
+ if(it == res.end())
+ return false;
+
+ return true;
+ }
+
+ //----------------------------------------------------------------------------
+//#ifdef _WINSOCK2API_
+ inline std::string get_ip_string_from_int32(boost::uint32_t ip)
+ {
+ in_addr adr;
+ adr.s_addr = ip;
+ const char* pbuf = inet_ntoa(adr);
+ if(pbuf)
+ return pbuf;
+ else
+ return "[failed]";
+ }
+ //----------------------------------------------------------------------------
+ inline bool get_ip_int32_from_string(boost::uint32_t& ip, const std::string& ip_str)
+ {
+ ip = inet_addr(ip_str.c_str());
+ if(INADDR_NONE == ip)
+ return false;
+
+ return true;
+ }
+ //----------------------------------------------------------------------------
+ inline bool parse_peer_from_string(uint32_t& ip, uint32_t& port, const std::string& addres)
+ {
+ //parse ip and address
+ std::string::size_type p = addres.find(':');
+ if(p == std::string::npos)
+ {
+ return false;
+ }
+ std::string ip_str = addres.substr(0, p);
+ std::string port_str = addres.substr(p+1, addres.size());
+
+ if(!get_ip_int32_from_string(ip, ip_str))
+ {
+ return false;
+ }
+
+ if(!get_xtype_from_string(port, port_str))
+ {
+ return false;
+ }
+ return true;
+ }
+
+//#endif
+ //----------------------------------------------------------------------------
+ template<typename t>
+ inline std::string get_t_as_hex_nwidth(const t& v, std::streamsize w = 8)
+ {
+ std::stringstream ss;
+ ss << std::setfill ('0') << std::setw (w) << std::hex << std::noshowbase;
+ ss << v;
+ return ss.str();
+ }
+
+ inline std::string num_to_string_fast(boost::int64_t val)
+ {
+ /*
+ char buff[30] = {0};
+ i64toa_s(val, buff, sizeof(buff)-1, 10);
+ return buff;*/
+ return boost::lexical_cast<std::string>(val);
+ }
+ //----------------------------------------------------------------------------
+ inline bool string_to_num_fast(const std::string& buff, boost::int64_t& val)
+ {
+ //return get_xtype_from_string(val, buff);
+#if (defined _MSC_VER)
+ val = _atoi64(buff.c_str());
+#else
+ val = atoll(buff.c_str());
+#endif
+ /*
+ * val = atoi64(buff.c_str());
+ */
+ if(buff != "0" && val == 0)
+ return false;
+ return true;
+ }
+ //----------------------------------------------------------------------------
+ inline bool string_to_num_fast(const std::string& buff, int& val)
+ {
+ val = atoi(buff.c_str());
+ if(buff != "0" && val == 0)
+ return false;
+
+ return true;
+ }
+ //----------------------------------------------------------------------------
+#ifdef WINDOWS_PLATFORM
+ inline std::string system_time_to_string(const SYSTEMTIME& st)
+ {
+
+ /*
+ TIME_ZONE_INFORMATION tzi;
+ GetTimeZoneInformation(&tzi);
+ SystemTimeToTzSpecificLocalTime(&tzi, &stUTC, &stLocal);
+ */
+
+ char szTime[25], szDate[25];
+ ::GetTimeFormatA(
+ LOCALE_USER_DEFAULT, // locale
+ TIME_FORCE24HOURFORMAT, // options
+ &st, // time
+ NULL, // time format string
+ szTime, // formatted string buffer
+ 25 // size of string buffer
+ );
+
+ ::GetDateFormatA(
+ LOCALE_USER_DEFAULT, // locale
+ NULL, // options
+ &st, // date
+ NULL, // date format
+ szDate, // formatted string buffer
+ 25 // size of buffer
+ );
+ szTime[24] = szDate[24] = 0; //be happy :)
+
+ std::string res = szDate;
+ (res += " " )+= szTime;
+ return res;
+
+ }
+#endif
+ //----------------------------------------------------------------------------
+
+ inline bool compare_no_case(const std::string& str1, const std::string& str2)
+ {
+
+ return !boost::iequals(str1, str2);
+ }
+ //----------------------------------------------------------------------------
+ inline bool compare_no_case(const std::wstring& str1, const std::wstring& str2)
+ {
+ return !boost::iequals(str1, str2);
+ }
+ //----------------------------------------------------------------------------
+ inline bool is_match_prefix(const std::wstring& str1, const std::wstring& prefix)
+ {
+ if(prefix.size()>str1.size())
+ return false;
+
+ if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
+ return true;
+ else
+ return false;
+ }
+ //----------------------------------------------------------------------------
+ inline bool is_match_prefix(const std::string& str1, const std::string& prefix)
+ {
+ if(prefix.size()>str1.size())
+ return false;
+
+ if(!compare_no_case(str1.substr(0, prefix.size()), prefix))
+ return true;
+ else
+ return false;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string& get_current_module_name()
+ {
+ static std::string module_name;
+ return module_name;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string& get_current_module_folder()
+ {
+ static std::string module_folder;
+ return module_folder;
+ }
+ //----------------------------------------------------------------------------
+#ifdef _WIN32
+ inline std::string get_current_module_path()
+ {
+ char pname [5000] = {0};
+ GetModuleFileNameA( NULL, pname, sizeof(pname));
+ pname[sizeof(pname)-1] = 0; //be happy ;)
+ return pname;
+ }
+#endif
+ //----------------------------------------------------------------------------
+ inline bool set_module_name_and_folder(const std::string& path_to_process_)
+ {
+ std::string path_to_process = path_to_process_;
+#ifdef _WIN32
+ path_to_process = get_current_module_path();
+#endif
+ std::string::size_type a = path_to_process.rfind( '\\' );
+ if(a == std::string::npos )
+ {
+ a = path_to_process.rfind( '/' );
+ }
+ if ( a != std::string::npos )
+ {
+ get_current_module_name() = path_to_process.substr(a+1, path_to_process.size());
+ get_current_module_folder() = path_to_process.substr(0, a);
+ return true;
+ }else
+ return false;
+
+ }
+
+ //----------------------------------------------------------------------------
+ inline bool trim_left(std::string& str)
+ {
+ for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
+ str.erase(str.begin());
+
+ return true;
+ }
+ //----------------------------------------------------------------------------
+ inline bool trim_right(std::string& str)
+ {
+
+ for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
+ str.erase( --((it++).base()));
+
+ return true;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string& trim(std::string& str)
+ {
+
+ trim_left(str);
+ trim_right(str);
+ return str;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string trim(const std::string& str_)
+ {
+ std::string str = str_;
+ trim_left(str);
+ trim_right(str);
+ return str;
+ }
+ //----------------------------------------------------------------------------
+ template<class t_pod_type>
+ std::string pod_to_hex(const t_pod_type& s)
+ {
+ std::string buff;
+ buff.assign(reinterpret_cast<const char*>(&s), sizeof(s));
+ return buff_to_hex_nodelimer(buff);
+ }
+ //----------------------------------------------------------------------------
+ template<class t_pod_type>
+ bool hex_to_pod(const std::string& hex_str, t_pod_type& s)
+ {
+ std::string hex_str_tr = trim(hex_str);
+ if(sizeof(s)*2 != hex_str.size())
+ return false;
+ std::string bin_buff;
+ if(!parse_hexstr_to_binbuff(hex_str_tr, bin_buff))
+ return false;
+ if(bin_buff.size()!=sizeof(s))
+ return false;
+
+ s = *(t_pod_type*)bin_buff.data();
+ return true;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string get_extension(const std::string& str)
+ {
+ std::string res;
+ std::string::size_type pos = str.rfind('.');
+ if(std::string::npos == pos)
+ return res;
+
+ res = str.substr(pos+1, str.size()-pos);
+ return res;
+ }
+ //----------------------------------------------------------------------------
+ inline std::string get_filename_from_path(const std::string& str)
+ {
+ std::string res;
+ std::string::size_type pos = str.rfind('\\');
+ if(std::string::npos == pos)
+ return str;
+
+ res = str.substr(pos+1, str.size()-pos);
+ return res;
+ }
+ //----------------------------------------------------------------------------
+
+
+
+ inline std::string cut_off_extension(const std::string& str)
+ {
+ std::string res;
+ std::string::size_type pos = str.rfind('.');
+ if(std::string::npos == pos)
+ return str;
+
+ res = str.substr(0, pos);
+ return res;
+ }
+
+ //----------------------------------------------------------------------------
+#ifdef _WININET_
+ inline std::string get_string_from_systemtime(const SYSTEMTIME& sys_time)
+ {
+ std::string result_string;
+
+ char buff[100] = {0};
+ BOOL res = ::InternetTimeFromSystemTimeA(&sys_time, INTERNET_RFC1123_FORMAT, buff, 99);
+ if(!res)
+ {
+ LOG_ERROR("Failed to load SytemTime to string");
+ }
+
+ result_string = buff;
+ return result_string;
+
+ }
+ //-------------------------------------------------------------------------------------
+ inline SYSTEMTIME get_systemtime_from_string(const std::string& buff)
+ {
+ SYSTEMTIME result_time = {0};
+
+ BOOL res = ::InternetTimeToSystemTimeA(buff.c_str(), &result_time, NULL);
+ if(!res)
+ {
+ LOG_ERROR("Failed to load SytemTime from string " << buff << "interval set to 15 minutes");
+ }
+
+ return result_time;
+ }
+#endif
+
+#ifdef WINDOWS_PLATFORM
+ static const DWORD INFO_BUFFER_SIZE = 10000;
+
+ static const wchar_t* get_pc_name()
+ {
+ static wchar_t info[INFO_BUFFER_SIZE];
+ static DWORD bufCharCount = INFO_BUFFER_SIZE;
+ static bool init = false;
+
+ if (!init) {
+ if (!GetComputerNameW( info, &bufCharCount ))
+ info[0] = 0;
+ else
+ init = true;
+ }
+
+ return info;
+ }
+
+ static const wchar_t* get_user_name()
+ {
+ static wchar_t info[INFO_BUFFER_SIZE];
+ static DWORD bufCharCount = INFO_BUFFER_SIZE;
+ static bool init = false;
+
+ if (!init) {
+ if (!GetUserNameW( info, &bufCharCount ))
+ info[0] = 0;
+ else
+ init = true;
+ }
+
+ return info;
+ }
+#endif
+
+#ifdef _LM_
+ static const wchar_t* get_domain_name()
+ {
+ static wchar_t info[INFO_BUFFER_SIZE];
+ static DWORD bufCharCount = 0;
+ static bool init = false;
+
+ if (!init) {
+ LPWSTR domain( NULL );
+ NETSETUP_JOIN_STATUS status;
+ info[0] = 0;
+
+ if (NET_API_STATUS result = NetGetJoinInformation( NULL, &domain, &status ))
+ {
+ LOG_ERROR("get_domain_name error: " << log_space::get_win32_err_descr(result));
+ } else
+ {
+ StringCchCopyW( info, sizeof(info)/sizeof( info[0] ), domain );
+ NetApiBufferFree((void*)domain);
+ init = true;
+ }
+ }
+
+ return info;
+ }
+#endif
+#ifdef WINDOWS_PLATFORM
+ inline
+ std::string load_resource_string_a(int id, const char* pmodule_name = NULL)
+ {
+ //slow realization
+ HMODULE h = ::GetModuleHandleA( pmodule_name );
+
+ char buff[2000] = {0};
+
+ ::LoadStringA( h, id, buff, sizeof(buff));
+ buff[sizeof(buff)-1] = 0; //be happy :)
+ return buff;
+ }
+ inline
+ std::wstring load_resource_string_w(int id, const char* pmodule_name = NULL)
+ {
+ //slow realization
+ HMODULE h = ::GetModuleHandleA( pmodule_name );
+
+ wchar_t buff[2000] = {0};
+
+ ::LoadStringW( h, id, buff, sizeof(buff) / sizeof( buff[0] ) );
+ buff[(sizeof(buff)/sizeof(buff[0]))-1] = 0; //be happy :)
+ return buff;
+ }
+#endif
+}
+}
+#endif //_STRING_TOOLS_H_
diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h
new file mode 100644
index 000000000..ca7514ede
--- /dev/null
+++ b/contrib/epee/include/syncobj.h
@@ -0,0 +1,241 @@
+// 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 __WINH_OBJ_H__
+#define __WINH_OBJ_H__
+
+#include <condition_variable>
+#include <mutex>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+
+namespace epee
+{
+
+ struct simple_event
+ {
+ simple_event()
+ {
+ rised = false;
+ }
+ std::mutex m_mx;
+ std::condition_variable m_cond_var;
+ bool rised;
+
+ void rise()
+ {
+ std::unique_lock<std::mutex> lock(m_mx);
+ rised = true;
+ m_cond_var.notify_one();
+ }
+
+ void wait()
+ {
+ std::unique_lock<std::mutex> lock(m_mx);
+ while (!rised)
+ m_cond_var.wait(lock);
+ }
+ };
+
+ class critical_region;
+
+ class critical_section
+ {
+ boost::recursive_mutex m_section;
+
+ public:
+ //to make copy fake!
+ critical_section(const critical_section& section)
+ {
+ }
+
+ critical_section()
+ {
+ }
+
+ ~critical_section()
+ {
+ }
+
+ void lock()
+ {
+ m_section.lock();
+ //EnterCriticalSection( &m_section );
+ }
+
+ void unlock()
+ {
+ m_section.unlock();
+ }
+
+ bool tryLock()
+ {
+ return m_section.try_lock();
+ }
+
+ // to make copy fake
+ critical_section& operator=(const critical_section& section)
+ {
+ return *this;
+ }
+ };
+
+
+ template<class t_lock>
+ class critical_region_t
+ {
+ t_lock& m_locker;
+ bool m_unlocked;
+
+ critical_region_t(const critical_region_t&) {}
+
+ public:
+ critical_region_t(t_lock& cs): m_locker(cs), m_unlocked(false)
+ {
+ m_locker.lock();
+ }
+
+ ~critical_region_t()
+ {
+ unlock();
+ }
+
+ void unlock()
+ {
+ if (!m_unlocked)
+ {
+ m_locker.unlock();
+ m_unlocked = true;
+ }
+ }
+ };
+
+
+#if defined(WINDWOS_PLATFORM)
+ class shared_critical_section
+ {
+ public:
+ shared_critical_section()
+ {
+ ::InitializeSRWLock(&m_srw_lock);
+ }
+ ~shared_critical_section()
+ {}
+
+ bool lock_shared()
+ {
+ AcquireSRWLockShared(&m_srw_lock);
+ return true;
+ }
+ bool unlock_shared()
+ {
+ ReleaseSRWLockShared(&m_srw_lock);
+ return true;
+ }
+ bool lock_exclusive()
+ {
+ ::AcquireSRWLockExclusive(&m_srw_lock);
+ return true;
+ }
+ bool unlock_exclusive()
+ {
+ ::ReleaseSRWLockExclusive(&m_srw_lock);
+ return true;
+ }
+ private:
+ SRWLOCK m_srw_lock;
+ };
+
+
+ class shared_guard
+ {
+ public:
+ shared_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec)
+ {
+ m_ref_sec.lock_shared();
+ }
+
+ ~shared_guard()
+ {
+ m_ref_sec.unlock_shared();
+ }
+
+ private:
+ shared_critical_section& m_ref_sec;
+ };
+
+
+ class exclusive_guard
+ {
+ public:
+ exclusive_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec)
+ {
+ m_ref_sec.lock_exclusive();
+ }
+
+ ~exclusive_guard()
+ {
+ m_ref_sec.unlock_exclusive();
+ }
+
+ private:
+ shared_critical_section& m_ref_sec;
+ };
+#endif
+
+#define SHARED_CRITICAL_REGION_BEGIN(x) { shared_guard critical_region_var(x)
+#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { exclusive_guard critical_region_var(x)
+
+#define CRITICAL_REGION_LOCAL(x) epee::critical_region_t<decltype(x)> critical_region_var(x)
+#define CRITICAL_REGION_BEGIN(x) { epee::critical_region_t<decltype(x)> critical_region_var(x)
+#define CRITICAL_REGION_LOCAL1(x) epee::critical_region_t<decltype(x)> critical_region_var1(x)
+#define CRITICAL_REGION_BEGIN1(x) { epee::critical_region_t<decltype(x)> critical_region_var1(x)
+
+#define CRITICAL_REGION_END() }
+
+
+#if defined(WINDWOS_PLATFORM)
+ inline const char* get_wait_for_result_as_text(DWORD res)
+ {
+ switch(res)
+ {
+ case WAIT_ABANDONED: return "WAIT_ABANDONED";
+ case WAIT_TIMEOUT: return "WAIT_TIMEOUT";
+ case WAIT_OBJECT_0: return "WAIT_OBJECT_0";
+ case WAIT_OBJECT_0+1: return "WAIT_OBJECT_1";
+ case WAIT_OBJECT_0+2: return "WAIT_OBJECT_2";
+ default: return "UNKNOWN CODE";
+ }
+ }
+#endif
+
+}
+
+#endif
diff --git a/contrib/epee/include/time_helper.h b/contrib/epee/include/time_helper.h
new file mode 100644
index 000000000..958176da6
--- /dev/null
+++ b/contrib/epee/include/time_helper.h
@@ -0,0 +1,159 @@
+// 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 <atltime.h>
+//#include <sqlext.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/date_time/local_time/local_time.hpp>
+#include "pragma_comp_defs.h"
+
+namespace epee
+{
+namespace misc_utils
+{
+
+#ifdef __ATLTIME_H__
+
+ inline
+ bool get_time_t_from_ole_date(DATE src, time_t& res)
+ {
+ SYSTEMTIME st = {0};
+ if(TRUE != ::VariantTimeToSystemTime(src, &st))
+ return false;
+ ATL::CTime ss(st);
+ res = ss.GetTime();
+ return true;
+ }
+#endif
+ inline
+ std::string get_time_str(const time_t& time_)
+ {
+
+
+ char tmpbuf[200] = {0};
+ tm* pt = NULL;
+PRAGMA_WARNING_PUSH
+PRAGMA_WARNING_DISABLE_VS(4996)
+ pt = localtime(&time_);
+PRAGMA_WARNING_POP
+
+ if(pt)
+ strftime( tmpbuf, 199, "%d.%m.%Y %H:%M:%S", pt );
+ else
+ {
+ std::stringstream strs;
+ strs << "[wrong_time: " << std::hex << time_ << "]";
+ return strs.str();
+ }
+ return tmpbuf;
+ }
+
+ inline
+ std::string get_time_str_v2(const time_t& time_)
+ {
+
+ char tmpbuf[200] = {0};
+ tm* pt = NULL;
+PRAGMA_WARNING_PUSH
+PRAGMA_WARNING_DISABLE_VS(4996)
+ pt = localtime(&time_);
+PRAGMA_WARNING_POP
+
+ if(pt)
+ strftime( tmpbuf, 199, "%Y_%m_%d %H_%M_%S", pt );
+ else
+ {
+ std::stringstream strs;
+ strs << "[wrong_time: " << std::hex << time_ << "]";
+ return strs.str();
+ }
+ return tmpbuf;
+ }
+
+ inline
+ std::string get_time_str_v3(const boost::posix_time::ptime& time_)
+ {
+ return boost::posix_time::to_simple_string(time_);
+ }
+
+
+
+ inline std::string get_internet_time_str(const time_t& time_)
+ {
+ char tmpbuf[200] = {0};
+ tm* pt = NULL;
+PRAGMA_WARNING_PUSH
+PRAGMA_WARNING_DISABLE_VS(4996)
+ pt = gmtime(&time_);
+PRAGMA_WARNING_POP
+ strftime( tmpbuf, 199, "%a, %d %b %Y %H:%M:%S GMT", pt );
+ return tmpbuf;
+ }
+
+ inline std::string get_time_interval_string(const time_t& time_)
+ {
+ std::string res;
+ time_t tail = time_;
+PRAGMA_WARNING_PUSH
+PRAGMA_WARNING_DISABLE_VS(4244)
+ int days = tail/(60*60*24);
+ tail = tail%(60*60*24);
+ int hours = tail/(60*60);
+ tail = tail%(60*60);
+ int minutes = tail/(60);
+ tail = tail%(60);
+ int seconds = tail;
+PRAGMA_WARNING_POP
+ res = std::string() + "d" + boost::lexical_cast<std::string>(days) + ".h" + boost::lexical_cast<std::string>(hours) + ".m" + boost::lexical_cast<std::string>(minutes) + ".s" + boost::lexical_cast<std::string>(seconds);
+ return res;
+ }
+
+#ifdef __SQLEXT
+ inline
+ bool odbc_time_to_oledb_taime(const SQL_TIMESTAMP_STRUCT& odbc_timestamp, DATE& oledb_date)
+ {
+
+ SYSTEMTIME st = {0};
+ st.wYear = odbc_timestamp.year;
+ st.wDay = odbc_timestamp.day;
+ st.wHour = odbc_timestamp.hour ;
+ st.wMilliseconds = (WORD)odbc_timestamp.fraction ;
+ st.wMinute = odbc_timestamp.minute ;
+ st.wMonth = odbc_timestamp.month ;
+ st.wSecond = odbc_timestamp.second ;
+
+ if(TRUE != ::SystemTimeToVariantTime(&st, &oledb_date))
+ return false;
+ return true;
+ }
+
+#endif
+}
+} \ No newline at end of file
diff --git a/contrib/epee/include/tiny_ini.h b/contrib/epee/include/tiny_ini.h
new file mode 100644
index 000000000..2bc71fc1a
--- /dev/null
+++ b/contrib/epee/include/tiny_ini.h
@@ -0,0 +1,75 @@
+// 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 _TINY_INI_H_
+#define _TINY_INI_H_
+
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+#include "string_tools.h"
+
+namespace epee
+{
+namespace tiny_ini
+{
+
+ inline
+ bool get_param_value(const std::string& param_name, const std::string& ini_entry, std::string& res)
+ {
+ std::string expr_str = std::string() + "^("+ param_name +") *=(.*?)$";
+ const boost::regex match_ini_entry( expr_str, boost::regex::icase | boost::regex::normal);
+ boost::smatch result;
+ if(!boost::regex_search(ini_entry, result, match_ini_entry, boost::match_default))
+ return false;
+ res = result[2];
+ string_tools::trim(res);
+ return true;
+ }
+ inline
+ std::string get_param_value(const std::string& param_name, const std::string& ini_entry)
+ {
+ std::string buff;
+ get_param_value(param_name, ini_entry, buff);
+ return buff;
+ }
+
+ template<class T>
+ bool get_param_value_as_t(const std::string& param_name, const std::string& ini_entry, T& res)
+ {
+ std::string str_res = get_param_value(param_name, ini_entry);
+
+ string_tools::trim(str_res);
+ if(!str_res.size())
+ return false;
+
+ return string_tools::get_xtype_from_string(res, str_res);
+ }
+
+}
+}
+
+#endif //_TINY_INI_H_
diff --git a/contrib/epee/include/to_nonconst_iterator.h b/contrib/epee/include/to_nonconst_iterator.h
new file mode 100644
index 000000000..729b0e8b2
--- /dev/null
+++ b/contrib/epee/include/to_nonconst_iterator.h
@@ -0,0 +1,52 @@
+// 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 _TO_NONCONST_ITERATOR_H_
+#define _TO_NONCONST_ITERATOR_H_
+
+namespace epee
+{
+
+template<class Type>
+typename Type::iterator to_nonsonst_iterator(Type& obj, typename Type::const_iterator it)
+{
+ typename Type::difference_type dist = std::distance(static_cast<typename Type::const_iterator>(obj.begin()), it);
+ typename Type::iterator res_it = obj.begin()+dist;
+ return res_it;
+}
+
+
+template<class Type>
+typename Type::iterator to_nonsonst_iterator(typename Type::iterator base_it, typename Type::const_iterator it)
+{
+ typename Type::difference_type dist = std::distance(static_cast<typename Type::const_iterator>(base_it), it);
+ typename Type::iterator res_it = base_it+dist;
+ return res_it;
+}
+}//namespace epee
+#endif //_TO_NONCONST_ITERATOR_H_
diff --git a/contrib/epee/include/warnings.h b/contrib/epee/include/warnings.h
new file mode 100644
index 000000000..37d7a2900
--- /dev/null
+++ b/contrib/epee/include/warnings.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#if defined(_MSC_VER)
+
+#define PUSH_WARNINGS __pragma(warning(push))
+#define POP_WARNINGS __pragma(warning(pop))
+#define DISABLE_VS_WARNINGS(w) __pragma(warning(disable: w))
+#define DISABLE_GCC_WARNING(w)
+#define DISABLE_CLANG_WARNING(w)
+#define DISABLE_GCC_AND_CLANG_WARNING(w)
+
+#else
+
+#include <boost/preprocessor/stringize.hpp>
+
+#define PUSH_WARNINGS _Pragma("GCC diagnostic push")
+#define POP_WARNINGS _Pragma("GCC diagnostic pop")
+#define DISABLE_VS_WARNINGS(w)
+
+#if defined(__clang__)
+#define DISABLE_GCC_WARNING(w)
+#define DISABLE_CLANG_WARNING DISABLE_GCC_AND_CLANG_WARNING
+#else
+#define DISABLE_GCC_WARNING DISABLE_GCC_AND_CLANG_WARNING
+#define DISABLE_CLANG_WARNING(w)
+#endif
+
+#define DISABLE_GCC_AND_CLANG_WARNING(w) _Pragma(BOOST_PP_STRINGIZE(GCC diagnostic ignored BOOST_PP_STRINGIZE(-W##w)))
+
+#endif \ No newline at end of file
diff --git a/contrib/epee/include/winobj.h b/contrib/epee/include/winobj.h
new file mode 100644
index 000000000..3279cdac6
--- /dev/null
+++ b/contrib/epee/include/winobj.h
@@ -0,0 +1,227 @@
+// 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 __WINH_OBJ_H__
+#define __WINH_OBJ_H__
+
+#include <boost/thread/locks.hpp>
+
+namespace epee
+{
+class critical_region;
+
+class critical_section {
+
+ boost::mutex m_section;
+
+public:
+
+ critical_section( const critical_section& section ) {
+ InitializeCriticalSection( &m_section );
+ }
+
+ critical_section() {
+ InitializeCriticalSection( &m_section );
+ }
+
+ ~critical_section() {
+ DeleteCriticalSection( &m_section );
+ }
+
+ void lock() {
+ EnterCriticalSection( &m_section );
+ }
+
+ void unlock() {
+ LeaveCriticalSection( &m_section );
+ }
+
+ bool tryLock() {
+ return TryEnterCriticalSection( &m_section )? true:false;
+ }
+
+ critical_section& operator=( const critical_section& section )
+ {
+ return *this;
+ }
+
+
+};
+
+class critical_region {
+
+ ::critical_section *m_locker;
+
+ critical_region( const critical_region& ){}
+
+public:
+
+ critical_region(critical_section &cs ) {
+ m_locker = &cs;
+ cs.lock();
+ }
+
+ ~critical_region()
+ {
+ m_locker->unlock();
+ }
+};
+
+
+class shared_critical_section
+{
+public:
+ shared_critical_section()
+ {
+ ::InitializeSRWLock(&m_srw_lock);
+ }
+ ~shared_critical_section()
+ {}
+
+ bool lock_shared()
+ {
+ AcquireSRWLockShared(&m_srw_lock);
+ return true;
+ }
+ bool unlock_shared()
+ {
+ ReleaseSRWLockShared(&m_srw_lock);
+ return true;
+ }
+ bool lock_exclusive()
+ {
+ ::AcquireSRWLockExclusive(&m_srw_lock);
+ return true;
+ }
+ bool unlock_exclusive()
+ {
+ ::ReleaseSRWLockExclusive(&m_srw_lock);
+ return true;
+ }
+private:
+ SRWLOCK m_srw_lock;
+
+};
+
+
+class shared_guard
+{
+public:
+ shared_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec)
+ {
+ m_ref_sec.lock_shared();
+ }
+
+ ~shared_guard()
+ {
+ m_ref_sec.unlock_shared();
+ }
+
+private:
+ shared_critical_section& m_ref_sec;
+};
+
+
+class exclusive_guard
+{
+public:
+ exclusive_guard(shared_critical_section& ref_sec):m_ref_sec(ref_sec)
+ {
+ m_ref_sec.lock_exclusive();
+ }
+
+ ~exclusive_guard()
+ {
+ m_ref_sec.unlock_exclusive();
+ }
+
+private:
+ shared_critical_section& m_ref_sec;
+};
+
+
+class event
+{
+public:
+ event()
+ {
+ m_hevent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ }
+ ~event()
+ {
+ ::CloseHandle(m_hevent);
+
+ }
+
+ bool set()
+ {
+ return ::SetEvent(m_hevent) ? true:false;
+ }
+
+ bool reset()
+ {
+ return ::ResetEvent(m_hevent) ? true:false;
+ }
+
+ HANDLE get_handle()
+ {
+ return m_hevent;
+ }
+private:
+ HANDLE m_hevent;
+
+};
+
+
+#define SHARED_CRITICAL_REGION_BEGIN(x) { shared_guard critical_region_var(x)
+#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { exclusive_guard critical_region_var(x)
+
+
+
+#define CRITICAL_REGION_LOCAL(x) critical_region critical_region_var(x)
+#define CRITICAL_REGION_BEGIN(x) { critical_region critical_region_var(x)
+#define CRITICAL_REGION_END() }
+
+
+ inline const char* get_wait_for_result_as_text(DWORD res)
+ {
+ switch(res)
+ {
+ case WAIT_ABANDONED: return "WAIT_ABANDONED";
+ case WAIT_TIMEOUT: return "WAIT_TIMEOUT";
+ case WAIT_OBJECT_0: return "WAIT_OBJECT_0";
+ case WAIT_OBJECT_0+1: return "WAIT_OBJECT_1";
+ case WAIT_OBJECT_0+2: return "WAIT_OBJECT_2";
+ default:
+ return "UNKNOWN CODE";
+ }
+
+ }
+
+}// namespace epee
+
+#endif
diff --git a/contrib/epee/include/zlib_helper.h b/contrib/epee/include/zlib_helper.h
new file mode 100644
index 000000000..46c7f48e6
--- /dev/null
+++ b/contrib/epee/include/zlib_helper.h
@@ -0,0 +1,139 @@
+// 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/tests/.gitignore b/contrib/epee/tests/.gitignore
new file mode 100644
index 000000000..d9b4f015d
--- /dev/null
+++ b/contrib/epee/tests/.gitignore
@@ -0,0 +1 @@
+/build/*
diff --git a/contrib/epee/tests/data/storages/invalid_storage_1.bin b/contrib/epee/tests/data/storages/invalid_storage_1.bin
new file mode 100644
index 000000000..fac7b3e97
--- /dev/null
+++ b/contrib/epee/tests/data/storages/invalid_storage_1.bin
Binary files differ
diff --git a/contrib/epee/tests/data/storages/invalid_storage_2.bin b/contrib/epee/tests/data/storages/invalid_storage_2.bin
new file mode 100644
index 000000000..a8c29f155
--- /dev/null
+++ b/contrib/epee/tests/data/storages/invalid_storage_2.bin
Binary files differ
diff --git a/contrib/epee/tests/data/storages/invalid_storage_3.bin b/contrib/epee/tests/data/storages/invalid_storage_3.bin
new file mode 100644
index 000000000..b5c31aa05
--- /dev/null
+++ b/contrib/epee/tests/data/storages/invalid_storage_3.bin
@@ -0,0 +1 @@
+¢IMóÙŸˆm_bo \ No newline at end of file
diff --git a/contrib/epee/tests/data/storages/invalid_storage_4.bin b/contrib/epee/tests/data/storages/invalid_storage_4.bin
new file mode 100644
index 000000000..4f8372d19
--- /dev/null
+++ b/contrib/epee/tests/data/storages/invalid_storage_4.bin
Binary files differ
diff --git a/contrib/epee/tests/data/storages/valid_storage.bin b/contrib/epee/tests/data/storages/valid_storage.bin
new file mode 100644
index 000000000..e13f780b1
--- /dev/null
+++ b/contrib/epee/tests/data/storages/valid_storage.bin
Binary files differ
diff --git a/contrib/epee/tests/generate_vc_proj.bat b/contrib/epee/tests/generate_vc_proj.bat
new file mode 100644
index 000000000..a81bdce05
--- /dev/null
+++ b/contrib/epee/tests/generate_vc_proj.bat
@@ -0,0 +1,5 @@
+mkdir build
+cd build
+cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" ../src
+cd ..
+pause \ No newline at end of file
diff --git a/contrib/epee/tests/src/CMakeLists.txt b/contrib/epee/tests/src/CMakeLists.txt
new file mode 100644
index 000000000..c7d31735b
--- /dev/null
+++ b/contrib/epee/tests/src/CMakeLists.txt
@@ -0,0 +1,33 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+set(Boost_USE_MULTITHREADED ON)
+
+include_directories(.)
+include_directories(../../include)
+
+find_package(Boost COMPONENTS system filesystem thread date_time chrono regex)
+include_directories( ${Boost_INCLUDE_DIRS} )
+
+IF (MSVC)
+ add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /nologo /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /bigobj" )
+ include_directories(SYSTEM platform/msvc)
+ELSE()
+ # set stuff for other systems
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Werror")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror -Wno-reorder")
+ENDIF()
+
+
+# Add folders to filters
+file(GLOB_RECURSE SRC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.inl
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
+
+source_group(general FILES ${SRC})
+
+
+add_executable(tests ${SRC} )
+target_link_libraries( tests ${Boost_LIBRARIES} )
+
diff --git a/contrib/epee/tests/src/misc/test_math.h b/contrib/epee/tests/src/misc/test_math.h
new file mode 100644
index 000000000..8b3064c2a
--- /dev/null
+++ b/contrib/epee/tests/src/misc/test_math.h
@@ -0,0 +1,82 @@
+// 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 "misc_language.h"
+
+namespace epee
+{
+ namespace tests
+ {
+ bool test_median()
+ {
+ LOG_PRINT_L0("Testing median");
+ std::vector<size_t> sz;
+ size_t m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 0, false, "test failed");
+ sz.push_back(1);
+ m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 1, false, "test failed");
+ sz.push_back(10);
+ m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 5, false, "test failed");
+
+ sz.clear();
+ sz.resize(3);
+ sz[0] = 0;
+ sz[1] = 9;
+ sz[2] = 3;
+ m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 3, false, "test failed");
+
+ sz.clear();
+ sz.resize(4);
+ sz[0] = 77;
+ sz[1] = 9;
+ sz[2] = 22;
+ sz[3] = 60;
+ m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 41, false, "test failed");
+
+
+
+ sz.clear();
+ sz.resize(5);
+ sz[0] = 77;
+ sz[1] = 9;
+ sz[2] = 22;
+ sz[3] = 60;
+ sz[4] = 11;
+ m = misc_utils::median(sz);
+ CHECK_AND_ASSERT_MES(m == 22, false, "test failed");
+ return true;
+ }
+ }
+}
+
diff --git a/contrib/epee/tests/src/net/test_net.h b/contrib/epee/tests/src/net/test_net.h
new file mode 100644
index 000000000..8d73c1f02
--- /dev/null
+++ b/contrib/epee/tests/src/net/test_net.h
@@ -0,0 +1,403 @@
+// 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 <boost/thread.hpp>
+#include <boost/bind.hpp>
+
+#include "net/levin_server_cp2.h"
+#include "storages/abstract_invoke.h"
+
+namespace epee
+{
+namespace StorageNamed
+{
+ typedef CInMemStorage DefaultStorageType;
+}
+namespace tests
+{
+ struct some_subdata
+ {
+
+ std::string str1;
+ std::list<boost::uint64_t> array_of_id;
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_STL_ANSI_STRING(str1)
+ SERIALIZE_STL_CONTAINER_POD(array_of_id)
+ END_NAMED_SERIALIZE_MAP()
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct COMMAND_EXAMPLE_1
+ {
+ const static int ID = 1000;
+
+ struct request
+ {
+
+ std::string example_string_data;
+ boost::uint64_t example_id_data;
+ some_subdata sub;
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_STL_ANSI_STRING(example_string_data)
+ SERIALIZE_POD(example_id_data)
+ SERIALIZE_T(sub)
+ END_NAMED_SERIALIZE_MAP()
+ };
+
+
+ struct response
+ {
+ bool m_success;
+ boost::uint64_t example_id_data;
+ std::list<some_subdata> subs;
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_POD(m_success)
+ SERIALIZE_POD(example_id_data)
+ SERIALIZE_STL_CONTAINER_T(subs)
+ END_NAMED_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_EXAMPLE_2
+ {
+ const static int ID = 1001;
+
+ struct request
+ {
+ std::string example_string_data2;
+ boost::uint64_t example_id_data;
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_POD(example_id_data)
+ SERIALIZE_STL_ANSI_STRING(example_string_data2)
+ END_NAMED_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ bool m_success;
+ boost::uint64_t example_id_data;
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_POD(example_id_data)
+ SERIALIZE_POD(m_success)
+ END_NAMED_SERIALIZE_MAP()
+ };
+ };
+ typedef boost::uuids::uuid uuid;
+
+ class test_levin_server: public levin::levin_commands_handler<>
+ {
+ test_levin_server(const test_levin_server&){}
+ public:
+ test_levin_server(){}
+ void set_thread_prefix(const std::string& pref)
+ {
+ m_net_server.set_threads_prefix(pref);
+ }
+ template<class calback_t>
+ bool connect_async(const std::string adr, const std::string& port, boost::uint32_t conn_timeot, calback_t cb, const std::string& bind_ip = "0.0.0.0")
+ {
+ return m_net_server.connect_async(adr, port, conn_timeot, cb, bind_ip);
+ }
+
+ bool connect(const std::string adr, const std::string& port, boost::uint32_t conn_timeot, net_utils::connection_context_base& cn, const std::string& bind_ip = "0.0.0.0")
+ {
+ return m_net_server.connect(adr, port, conn_timeot, cn, bind_ip);
+ }
+ void close(net_utils::connection_context_base& cn)
+ {
+ m_net_server.get_config_object().close(cn.m_connection_id);
+ }
+
+ template<class t_request, class t_response>
+ bool invoke(uuid con_id, int command, t_request& req, t_response& resp)
+ {
+ return invoke_remote_command(con_id, command, req, resp, m_net_server.get_config_object());
+ }
+
+ template< class t_response, class t_request, class callback_t>
+ bool invoke_async(uuid con_id, int command, t_request& req, callback_t cb)
+ {
+ return async_invoke_remote_command<t_response>(con_id, command, req, m_net_server.get_config_object(), cb);
+ }
+
+ bool init(const std::string& bind_port = "", const std::string& bind_ip = "0.0.0.0")
+ {
+ m_net_server.get_config_object().m_pcommands_handler = this;
+ m_net_server.get_config_object().m_invoke_timeout = 1000;
+ LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
+ return m_net_server.init_server(bind_port, bind_ip);
+ }
+
+ bool run()
+ {
+ //here you can set worker threads count
+ int thrds_count = 4;
+
+ //go to loop
+ LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
+ if(!m_net_server.run_server(thrds_count))
+ {
+ LOG_ERROR("Failed to run net tcp server!");
+ }
+
+ LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
+ return true;
+ }
+
+ bool deinit()
+ {
+ return m_net_server.deinit_server();
+ }
+
+ bool send_stop_signal()
+ {
+ m_net_server.send_stop_signal();
+ return true;
+ }
+
+ uint32_t get_binded_port()
+ {
+ return m_net_server.get_binded_port();
+ }
+ private:
+
+
+ CHAIN_LEVIN_INVOKE_TO_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map
+ CHAIN_LEVIN_NOTIFY_TO_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing
+
+ BEGIN_INVOKE_MAP(test_levin_server)
+ HANDLE_INVOKE_T(COMMAND_EXAMPLE_1, &test_levin_server::handle_1)
+ HANDLE_INVOKE_T(COMMAND_EXAMPLE_2, &test_levin_server::handle_2)
+ END_INVOKE_MAP()
+
+ //----------------- commands handlers ----------------------------------------------
+ int handle_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context)
+ {
+ LOG_PRINT_L0("on_command_1: id " << arg.example_id_data << "---->>");
+ COMMAND_EXAMPLE_2::request arg_ = AUTO_VAL_INIT(arg_);
+ arg_.example_id_data = arg.example_id_data;
+ COMMAND_EXAMPLE_2::response rsp_ = AUTO_VAL_INIT(rsp_);
+ invoke_async<COMMAND_EXAMPLE_2::response>(context.m_connection_id, COMMAND_EXAMPLE_2::ID, arg_, [](int code, const COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
+ {
+ if(code < 0)
+ {LOG_PRINT_RED_L0("on_command_1: command_2 failed to invoke");}
+ else
+ {LOG_PRINT_L0("on_command_1: command_2 response " << rsp.example_id_data);}
+ });
+ rsp.example_id_data = arg.example_id_data;
+ LOG_PRINT_L0("on_command_1: id " << arg.example_id_data << "<<----");
+ return true;
+ }
+ int handle_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
+ {
+ LOG_PRINT_L0("on_command_2: id "<< arg.example_id_data);
+ rsp.example_id_data = arg.example_id_data;
+ //misc_utils::sleep_no_w(6000);
+ return true;
+ }
+ //----------------------------------------------------------------------------------
+ net_utils::boosted_levin_async_server m_net_server;
+ };
+
+
+ inline
+ bool do_run_test_server()
+ {
+
+ test_levin_server srv1, srv2;
+
+
+ std::string bind_param = "0.0.0.0";
+ std::string port = "";
+
+ if(!srv1.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ if(!srv2.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ srv1.set_thread_prefix("SRV_A");
+ srv2.set_thread_prefix("SRV_B");
+
+ boost::thread th1( boost::bind(&test_levin_server::run, &srv1));
+ boost::thread th2( boost::bind(&test_levin_server::run, &srv2));
+
+ LOG_PRINT_L0("Initalized servers, waiting for worker threads started...");
+ misc_utils::sleep_no_w(1000);
+
+
+ LOG_PRINT_L0("Connecting to each other...");
+ uint32_t port1 = srv1.get_binded_port();
+ uint32_t port2 = srv2.get_binded_port();
+
+ COMMAND_EXAMPLE_1::request arg;
+ COMMAND_EXAMPLE_1::request resp;
+
+ net_utils::connection_context_base cntxt_1;
+ bool r = srv1.connect("127.0.0.1", string_tools::num_to_string_fast(port2), 5000, cntxt_1);
+ CHECK_AND_ASSERT_MES(r, false, "connect to server failed");
+
+ net_utils::connection_context_base cntxt_2;
+ r = srv2.connect("127.0.0.1", string_tools::num_to_string_fast(port1), 5000, cntxt_2);
+ CHECK_AND_ASSERT_MES(r, false, "connect to server failed");
+
+ while(true)
+ {
+ LOG_PRINT_L0("Invoking from A to B...");
+ int r = srv1.invoke(cntxt_1.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, resp);
+ if(r<=0)
+ {
+ LOG_ERROR("Failed tp invoke A to B");
+ break;
+ }
+
+ LOG_PRINT_L0("Invoking from B to A...");
+ r = srv2.invoke(cntxt_2.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, resp);
+ if(r<=0)
+ {
+ LOG_ERROR("Failed tp invoke B to A");
+ break;
+ }
+ }
+ srv1.send_stop_signal();
+ srv2.send_stop_signal();
+ th1.join();
+ th1.join();
+
+ return true;
+ }
+
+
+
+ inline bool do_test2_work_with_srv(test_levin_server& srv, int port)
+ {
+ uint64_t i = 0;
+ boost::mutex wait_event;
+ wait_event.lock();
+ while(true)
+ {
+ net_utils::connection_context_base cntxt_local = AUTO_VAL_INIT(cntxt_local);
+ bool r = srv.connect_async("127.0.0.1", string_tools::num_to_string_fast(port), 5000, [&srv, &port, &wait_event, &i, &cntxt_local](const net_utils::connection_context_base& cntxt, const boost::system::error_code& ec)
+ {
+ CHECK_AND_ASSERT_MES(!ec, void(), "Some problems at connect, message: " << ec.message() );
+ cntxt_local = cntxt;
+ LOG_PRINT_L0("Invoking command 1 to " << port);
+ COMMAND_EXAMPLE_1::request arg = AUTO_VAL_INIT(arg);
+ arg.example_id_data = i;
+ /*vc2010 workaround*/
+ int port_ = port;
+ boost::mutex& wait_event_ = wait_event;
+ int r = srv.invoke_async<COMMAND_EXAMPLE_1::request>(cntxt.m_connection_id, COMMAND_EXAMPLE_1::ID, arg, [port_, &wait_event_](int code, const COMMAND_EXAMPLE_1::request& rsp, const net_utils::connection_context_base& cntxt)
+ {
+ CHECK_AND_ASSERT_MES(code > 0, void(), "Failed to invoke");
+ LOG_PRINT_L0("command 1 invoke to " << port_ << " OK.");
+ wait_event_.unlock();
+ });
+ });
+ wait_event.lock();
+ srv.close(cntxt_local);
+ ++i;
+ }
+ return true;
+ }
+
+ inline
+ bool do_run_test_server_async_connect()
+ {
+ test_levin_server srv1, srv2;
+
+
+ std::string bind_param = "0.0.0.0";
+ std::string port = "";
+
+ if(!srv1.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ if(!srv2.init(port, bind_param))
+ {
+ LOG_ERROR("Failed to initialize srv!");
+ return 1;
+ }
+
+ srv1.set_thread_prefix("SRV_A");
+ srv2.set_thread_prefix("SRV_B");
+
+ boost::thread thmain1( boost::bind(&test_levin_server::run, &srv1));
+ boost::thread thmain2( boost::bind(&test_levin_server::run, &srv2));
+
+ LOG_PRINT_L0("Initalized servers, waiting for worker threads started...");
+ misc_utils::sleep_no_w(1000);
+
+
+ LOG_PRINT_L0("Connecting to each other...");
+ uint32_t port1 = srv1.get_binded_port();
+ uint32_t port2 = srv2.get_binded_port();
+
+ COMMAND_EXAMPLE_1::request arg;
+ COMMAND_EXAMPLE_1::request resp;
+
+
+ boost::thread work_1( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2));
+ boost::thread work_2( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1));
+ boost::thread work_3( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2));
+ boost::thread work_4( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1));
+ boost::thread work_5( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2));
+ boost::thread work_6( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1));
+ boost::thread work_7( boost::bind(do_test2_work_with_srv, boost::ref(srv1), port2));
+ boost::thread work_8( boost::bind(do_test2_work_with_srv, boost::ref(srv2), port1));
+
+
+ work_1.join();
+ work_2.join();
+ srv1.send_stop_signal();
+ srv2.send_stop_signal();
+ thmain1.join();
+ thmain2.join();
+
+ return true;
+ }
+
+}
+} \ No newline at end of file
diff --git a/contrib/epee/tests/src/storages/portable_storages_test.h b/contrib/epee/tests/src/storages/portable_storages_test.h
new file mode 100644
index 000000000..ecded8dad
--- /dev/null
+++ b/contrib/epee/tests/src/storages/portable_storages_test.h
@@ -0,0 +1,232 @@
+// 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 <list>
+#include <string>
+#include "storages/serializeble_struct_helper.h"
+#include "serialization/keyvalue_serialization.h"
+#include "storages/portable_storage.h"
+#include "storages/portable_storage_template_helper.h"
+
+namespace epee
+{
+ namespace tests
+ {
+
+ struct port_test_struct_sub
+ {
+ std::string m_str;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_VAL(m_str)
+ END_KV_SERIALIZE_MAP()
+ };
+
+#pragma pack (push, 1)
+ struct some_pod_struct
+ {
+ uint64_t a;
+ int32_t b;
+ };
+#pragma pack(pop)
+
+ struct port_test_struct
+ {
+ std::string m_str;
+ uint64_t m_uint64;
+ uint32_t m_uint32;
+ uint16_t m_uint16;
+ uint8_t m_uint8;
+ int64_t m_int64;
+ int32_t m_int32;
+ int16_t m_int16;
+ int8_t m_int8;
+ double m_double;
+ bool m_bool;
+ some_pod_struct m_pod;
+ std::list<std::string> m_list_of_str;
+ std::list<uint64_t> m_list_of_uint64_t;
+ std::list<uint32_t> m_list_of_uint32_t;
+ std::list<uint16_t> m_list_of_uint16_t;
+ std::list<uint8_t> m_list_of_uint8_t;
+ std::list<int64_t> m_list_of_int64_t;
+ std::list<int32_t> m_list_of_int32_t;
+ std::list<int16_t> m_list_of_int16_t;
+ std::list<int8_t> m_list_of_int8_t;
+ std::list<double> m_list_of_double;
+ std::list<bool> m_list_of_bool;
+ port_test_struct_sub m_subobj;
+ std::list<port_test_struct> m_list_of_self;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_VAL(m_str)
+ KV_SERIALIZE_VAL(m_uint64)
+ KV_SERIALIZE_VAL(m_uint32)
+ KV_SERIALIZE_VAL(m_uint16)
+ KV_SERIALIZE_VAL(m_uint8)
+ KV_SERIALIZE_VAL(m_int64)
+ KV_SERIALIZE_VAL(m_int32)
+ KV_SERIALIZE_VAL(m_int16)
+ KV_SERIALIZE_VAL(m_int8)
+ KV_SERIALIZE_VAL(m_double)
+ KV_SERIALIZE_VAL(m_bool)
+ KV_SERIALIZE_VAL_POD_AS_BLOB(m_pod)
+ KV_SERIALIZE_OBJ(m_subobj)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_str)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint64_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint32_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint16_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_uint8_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_int64_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_int32_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_int16_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_int8_t)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_double)
+ KV_SERIALIZE_CONTAINER_VAL(m_list_of_bool)
+ KV_SERIALIZE_CONTAINER_OBJ(m_list_of_self)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ bool operator != (const port_test_struct_sub& a, const port_test_struct_sub& b)
+ {
+ return b.m_str != a.m_str;
+ }
+
+ bool operator == (const port_test_struct& a, const port_test_struct& b)
+ {
+ if( b.m_str != a.m_str
+ || b.m_uint64 != a.m_uint64
+ || b.m_uint32 != a.m_uint32
+ || b.m_uint16 != a.m_uint16
+ || b.m_uint8 != a.m_uint8
+ || b.m_int64 != a.m_int64
+ || b.m_int32 != a.m_int32
+ || b.m_int16 != a.m_int16
+ || b.m_int8 != a.m_int8
+ || b.m_double != a.m_double
+ || b.m_bool != a.m_bool
+ || b.m_pod.a != a.m_pod.a
+ || b.m_pod.b != a.m_pod.b
+ || b.m_list_of_str != a.m_list_of_str
+ || b.m_list_of_uint64_t != a.m_list_of_uint64_t
+ || b.m_list_of_uint32_t != a.m_list_of_uint32_t
+ || b.m_list_of_uint16_t != a.m_list_of_uint16_t
+ || b.m_list_of_uint8_t != a.m_list_of_uint8_t
+ || b.m_list_of_int64_t != a.m_list_of_int64_t
+ || b.m_list_of_int32_t != a.m_list_of_int32_t
+ || b.m_list_of_int16_t != a.m_list_of_int16_t
+ || b.m_list_of_int8_t != a.m_list_of_int8_t
+ || b.m_list_of_double != a.m_list_of_double
+ || b.m_list_of_bool != a.m_list_of_bool
+ || b.m_subobj != a.m_subobj
+ || b.m_list_of_self != a.m_list_of_self
+ )
+ return false;
+ return true;
+ }
+
+ void fill_struct_with_test_values(port_test_struct& s)
+ {
+ s.m_str = "zuzuzuzuzuz";
+ s.m_uint64 = 111111111111111;
+ s.m_uint32 = 2222222;
+ s.m_uint16 = 2222;
+ s.m_uint8 = 22;
+ s.m_int64 = -111111111111111;
+ s.m_int32 = -2222222;
+ s.m_int16 = -2222;
+ s.m_int8 = -24;
+ s.m_double = 0.11111;
+ s.m_bool = true;
+ s.m_pod.a = 32342342342342;
+ s.m_pod.b = -342342;
+ s.m_list_of_str.push_back("1112121");
+ s.m_list_of_uint64_t.push_back(1111111111);
+ s.m_list_of_uint64_t.push_back(2222222222);
+ s.m_list_of_uint32_t.push_back(1111111);
+ s.m_list_of_uint32_t.push_back(2222222);
+ s.m_list_of_uint16_t.push_back(1111);
+ s.m_list_of_uint16_t.push_back(2222);
+ s.m_list_of_uint8_t.push_back(11);
+ s.m_list_of_uint8_t.push_back(22);
+
+
+ s.m_list_of_int64_t.push_back(-1111111111);
+ s.m_list_of_int64_t.push_back(-222222222);
+ s.m_list_of_int32_t.push_back(-1111111);
+ s.m_list_of_int32_t.push_back(-2222222);
+ s.m_list_of_int16_t.push_back(-1111);
+ s.m_list_of_int16_t.push_back(-2222);
+ s.m_list_of_int8_t.push_back(-11);
+ s.m_list_of_int8_t.push_back(-22);
+
+ s.m_list_of_double.push_back(0.11111);
+ s.m_list_of_double.push_back(0.22222);
+ s.m_list_of_bool.push_back(true);
+ s.m_list_of_bool.push_back(false);
+
+ s.m_subobj.m_str = "subszzzzzzzz";
+ s.m_list_of_self.push_back(s);
+ }
+
+ bool test_portable_storages(const std::string& tests_folder)
+ {
+ serialization::portable_storage ps, ps2;
+ port_test_struct s1, s2;
+ fill_struct_with_test_values(s1);
+
+ s1.store(ps);
+ std::string binbuf;
+ bool r = ps.store_to_binary(binbuf);
+
+ ps2.load_from_binary(binbuf);
+ s2.load(ps2);
+ if(!(s1 == s2))
+ {
+ LOG_ERROR("Portable storage test failed!");
+ return false;
+ }
+
+
+ port_test_struct ss1, ss2;
+ fill_struct_with_test_values(ss1);
+ std::string json_buff = epee::serialization::store_t_to_json(ss1);
+ epee::serialization::load_t_from_json(ss2, json_buff);
+ if(!(ss1 == ss2))
+ {
+ LOG_ERROR("Portable storage test failed!");
+ return false;
+ }
+
+ return true;
+ }
+
+ }
+} \ No newline at end of file
diff --git a/contrib/epee/tests/src/storages/storage_tests.h b/contrib/epee/tests/src/storages/storage_tests.h
new file mode 100644
index 000000000..522e589c4
--- /dev/null
+++ b/contrib/epee/tests/src/storages/storage_tests.h
@@ -0,0 +1,142 @@
+// 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 "storages/serializeble_struct_helper.h"
+#include "storages/portable_storage.h"
+
+namespace epee
+{
+ namespace tests
+ {
+
+
+ struct test_struct
+ {
+
+ std::string m_str;
+ unsigned int m_uint;
+ bool m_bool;
+ std::list<std::string> m_list_of_str;
+ std::list<int> m_list_of_int;
+ std::list<test_struct> m_list_of_self;
+
+
+ BEGIN_NAMED_SERIALIZE_MAP()
+ SERIALIZE_STL_ANSI_STRING(m_str)
+ SERIALIZE_POD(m_uint)
+ SERIALIZE_POD(m_bool)
+ SERIALIZE_STL_CONTAINER_ANSII_STRING(m_list_of_str)
+ SERIALIZE_STL_CONTAINER_POD(m_list_of_int)
+ SERIALIZE_STL_CONTAINER_T(m_list_of_self)
+ END_NAMED_SERIALIZE_MAP()
+
+ };
+
+
+ bool operator == (const test_struct& a, const test_struct& b)
+ {
+ if( b.m_str != a.m_str
+ || b.m_uint != a.m_uint
+ || b.m_bool != a.m_bool
+ || b.m_list_of_str != a.m_list_of_str
+ || b.m_list_of_int != a.m_list_of_int
+ || b.m_list_of_self != a.m_list_of_self
+ )
+ return false;
+ return true;
+ }
+
+ inline test_struct get_test_struct()
+ {
+ test_struct t = boost::value_initialized<test_struct>();
+ t.m_bool = true;
+ t.m_str = "ackamdc'kmecemcececmacmecmcm[aicm[oeicm[oeicm[qaicm[qoe";
+ t.m_uint = 233242;
+ for(int i = 0; i!=500; i++)
+ t.m_list_of_int.push_back(i);
+
+ for(int i = 0; i!=500; i++)
+ t.m_list_of_str.push_back("ssccd");
+
+ for(int i = 0; i!=5; i++)
+ {
+ t.m_list_of_self.push_back(t);
+ }
+ return t;
+ }
+
+ bool test_storages(const std::string& tests_folder)
+ {
+
+ epee::serialization::portable_storage ps;
+ auto s = ps.open_section("zzz", nullptr);
+ uint64_t i = 0;
+ ps.get_value("afdsdf", i, s);
+
+
+ LOG_PRINT_L0("Generating test struct...");
+ boost::filesystem::path storage_folder = tests_folder;
+ storage_folder /= "storages";
+
+
+ test_struct t = get_test_struct();
+
+ LOG_PRINT_L0("Loading test struct from storage...");
+ test_struct t2;
+ bool res = epee::StorageNamed::load_struct_from_storage_file(t2, (storage_folder /+ "valid_storage.bin").string());
+ CHECK_AND_ASSERT_MES(res, false, "Failed to load valid_storage.bin");
+
+ LOG_PRINT_L0("Comparing generated and loaded test struct...");
+ if(!(t == t2))
+ return false;
+
+ LOG_PRINT_L0("Loading broken archive 1...");
+ test_struct t3;
+ res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_1.bin").string());
+ CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_1.bin loaded, but should not ");
+
+
+ LOG_PRINT_L0("Loading broken archive 2...");
+ res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_2.bin").string());
+ CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_2.bin loaded, but should not ");
+
+ LOG_PRINT_L0("Loading broken archive 3...");
+ res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_3.bin").string());
+ CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_3.bin loaded, but should not ");
+
+ LOG_PRINT_L0("Loading broken archive 4...");
+ res = epee::StorageNamed::load_struct_from_storage_file(t3, (storage_folder /+ "invalid_storage_4.bin").string());
+ CHECK_AND_ASSERT_MES(!res, false, "invalid_storage_3.bin loaded, but should not ");
+
+ return true;
+ }
+ }
+}
+
diff --git a/contrib/epee/tests/src/tests.cpp b/contrib/epee/tests/src/tests.cpp
new file mode 100644
index 000000000..ed045d833
--- /dev/null
+++ b/contrib/epee/tests/src/tests.cpp
@@ -0,0 +1,59 @@
+
+#include "include_base_utils.h"
+#include "storages/storage_tests.h"
+#include "misc/test_math.h"
+#include "storages/portable_storages_test.h"
+#include "net/test_net.h"
+
+using namespace epee;
+
+int main(int argc, char* argv[])
+{
+
+ string_tools::set_module_name_and_folder(argv[0]);
+
+ //set up logging options
+ log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
+ log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
+ log_space::log_singletone::add_logger(LOGGER_FILE,
+ log_space::log_singletone::get_default_log_file().c_str(),
+ log_space::log_singletone::get_default_log_folder().c_str());
+
+
+ string_tools::command_line_params_a start_params;
+ string_tools::parse_commandline(start_params, argc, argv);
+ std::string tests_data_path;
+ string_tools::get_xparam_from_command_line(start_params, std::string("/tests_folder"), tests_data_path);
+
+ if(string_tools::have_in_command_line(start_params, std::string("/run_net_tests")))
+ {
+ if(!tests::do_run_test_server())
+ {
+ LOG_ERROR("net tests failed");
+ return 1;
+ }
+ if(!tests::do_run_test_server_async_connect() )
+ {
+ LOG_ERROR("net tests failed");
+ return 1;
+ }
+ }else if(string_tools::have_in_command_line(start_params, std::string("/run_unit_tests")))
+ {
+ if(!tests::test_median())
+ {
+ LOG_ERROR("median test failed");
+ return 1;
+ }
+
+
+ if(!tests::test_storages(tests_data_path))
+ {
+ LOG_ERROR("storage test failed");
+ return 1;
+ }
+ }else if(string_tools::have_in_command_line(start_params, std::string("/run_portable_storage_test")))
+ {
+ tests::test_portable_storages(tests_data_path);
+ }
+ return 1;
+} \ No newline at end of file