Bytecoin v.1.0.5 release
This commit is contained in:
parent
6d45be9ec0
commit
f697d93978
326 changed files with 6977 additions and 28526 deletions
|
@ -12,7 +12,7 @@ set(CMAKE_SUPPRESS_REGENERATION ON)
|
||||||
|
|
||||||
project(Bytecoin)
|
project(Bytecoin)
|
||||||
|
|
||||||
include_directories(include src contrib/epee/include external "${CMAKE_BINARY_DIR}/version")
|
include_directories(include src external "${CMAKE_BINARY_DIR}/version")
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
include_directories(SYSTEM /usr/include/malloc)
|
include_directories(SYSTEM /usr/include/malloc)
|
||||||
enable_language(ASM)
|
enable_language(ASM)
|
||||||
|
@ -140,7 +140,6 @@ else()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(contrib)
|
|
||||||
add_subdirectory(external)
|
add_subdirectory(external)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
Release notes 1.0.5
|
||||||
|
|
||||||
|
- High-level API for blockchain explorer
|
||||||
|
- Full network layer refactoring
|
||||||
|
- Transactions pool synchronization
|
||||||
|
- list_transactions method for RPC Wallet
|
||||||
|
- Various improvements
|
||||||
|
|
||||||
Release notes 1.0.4
|
Release notes 1.0.4
|
||||||
|
|
||||||
- Bytecoin RPC Wallet
|
- Bytecoin RPC Wallet
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
file(GLOB_RECURSE EPEE epee/include/*)
|
|
||||||
|
|
||||||
source_group(epee FILES ${EPEE})
|
|
||||||
|
|
||||||
add_library(epee ${EPEE})
|
|
||||||
|
|
||||||
set_property(TARGET epee PROPERTY FOLDER "external")
|
|
|
@ -1,25 +0,0 @@
|
||||||
Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
* Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
names of its contributors may be used to endorse or promote products
|
|
||||||
derived from this software without specific prior written permission.
|
|
||||||
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL 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.
|
|
|
@ -1 +0,0 @@
|
||||||
epee - is a small library of helpers, wrappers, tools and and so on, used to make my life easier.
|
|
1
contrib/epee/demo/.gitignore
vendored
1
contrib/epee/demo/.gitignore
vendored
|
@ -1 +0,0 @@
|
||||||
/build/*
|
|
|
@ -1,49 +0,0 @@
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#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.jsonrpc = "2.0";
|
|
||||||
req_t.id = epee::serialization::storage_entry(10);
|
|
||||||
req_t.method = "command_example_1";
|
|
||||||
req_t.params = req;
|
|
||||||
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, connection_context& ctxt)
|
|
||||||
{
|
|
||||||
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, connection_context& ctxt)
|
|
||||||
{
|
|
||||||
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, connection_context& ctxt)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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<epee::net_utils::connection_context_base>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef epee::net_utils::connection_context_base connection_context;
|
|
||||||
|
|
||||||
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(connection_context); //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, connection_context& ctxt);
|
|
||||||
bool on_request_api_2(const COMMAND_EXAMPLE_2::request& req, COMMAND_EXAMPLE_2::response& res, connection_context& ctxt);
|
|
||||||
|
|
||||||
bool on_request_api_1_with_error(const COMMAND_EXAMPLE_1::request& req, COMMAND_EXAMPLE_1::response& res, epee::json_rpc::error& error_resp, connection_context& ctxt);
|
|
||||||
|
|
||||||
net_utils::boosted_http_server_custum_handling m_net_server;
|
|
||||||
std::atomic<bool> m_stop;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// 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
|
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "targetver.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define BOOST_FILESYSTEM_VERSION 3
|
|
||||||
#define ENABLE_RELEASE_LOGGING
|
|
||||||
#include "misc_log_ex.h"
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
|
@ -1,200 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "stdafx.h"
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "targetver.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define BOOST_FILESYSTEM_VERSION 3
|
|
||||||
#define ENABLE_RELEASE_LOGGING
|
|
||||||
#include "misc_log_ex.h"
|
|
|
@ -1,13 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
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 ..
|
|
|
@ -1,7 +0,0 @@
|
||||||
mkdir build
|
|
||||||
|
|
||||||
cd build
|
|
||||||
|
|
||||||
cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" ..
|
|
||||||
cd ..
|
|
||||||
pause
|
|
|
@ -1,221 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "serialization/keyvalue_serialization.h"
|
|
||||||
#include "storages/portable_storage_base.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;
|
|
||||||
epee::serialization::storage_entry m_storage_entry_int;
|
|
||||||
epee::serialization::storage_entry m_storage_entry_string;
|
|
||||||
|
|
||||||
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)
|
|
||||||
KV_SERIALIZE(m_storage_entry_int)
|
|
||||||
KV_SERIALIZE(m_storage_entry_string)
|
|
||||||
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
|
|
||||||
|| b.m_storage_entry_int.which() != a.m_storage_entry_int.which()
|
|
||||||
|| b.m_storage_entry_string.which() != a.m_storage_entry_string.which()
|
|
||||||
)
|
|
||||||
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);
|
|
||||||
s.m_storage_entry_int = epee::serialization::storage_entry(uint64_t(22222));;
|
|
||||||
s.m_storage_entry_string = epee::serialization::storage_entry(std::string("sdsvsdvs"));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,430 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
|
||||||
#include <boost/algorithm/string/split.hpp>
|
|
||||||
|
|
||||||
#include "include_base_utils.h"
|
|
||||||
#include "string_tools.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
class async_stdin_reader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
async_stdin_reader()
|
|
||||||
: m_run(true)
|
|
||||||
, m_has_read_request(false)
|
|
||||||
, m_read_status(state_init)
|
|
||||||
{
|
|
||||||
m_reader_thread = std::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
~async_stdin_reader()
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not thread safe. Only one thread can call this method at once.
|
|
||||||
bool get_line(std::string& line)
|
|
||||||
{
|
|
||||||
if (!start_read())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(m_response_mutex);
|
|
||||||
while (state_init == m_read_status)
|
|
||||||
{
|
|
||||||
m_response_cv.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool res = false;
|
|
||||||
if (state_success == m_read_status)
|
|
||||||
{
|
|
||||||
line = m_line;
|
|
||||||
res = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_read_status = state_init;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop()
|
|
||||||
{
|
|
||||||
if (m_run)
|
|
||||||
{
|
|
||||||
m_run.store(false, std::memory_order_relaxed);
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_request_cv.notify_one();
|
|
||||||
m_reader_thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool start_read()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_request_mutex);
|
|
||||||
if (!m_run.load(std::memory_order_relaxed) || m_has_read_request)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_has_read_request = true;
|
|
||||||
m_request_cv.notify_one();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wait_read()
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_request_mutex);
|
|
||||||
while (m_run.load(std::memory_order_relaxed) && !m_has_read_request)
|
|
||||||
{
|
|
||||||
m_request_cv.wait(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_has_read_request)
|
|
||||||
{
|
|
||||||
m_has_read_request = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wait_stdin_data()
|
|
||||||
{
|
|
||||||
#if !defined(WIN32)
|
|
||||||
int stdin_fileno = ::fileno(stdin);
|
|
||||||
|
|
||||||
while (m_run.load(std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
fd_set read_set;
|
|
||||||
FD_ZERO(&read_set);
|
|
||||||
FD_SET(stdin_fileno, &read_set);
|
|
||||||
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = 100 * 1000;
|
|
||||||
|
|
||||||
int retval = ::select(stdin_fileno + 1, &read_set, NULL, NULL, &tv);
|
|
||||||
if (retval < 0)
|
|
||||||
return false;
|
|
||||||
else if (0 < retval)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reader_thread_func()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (!wait_read())
|
|
||||||
break;
|
|
||||||
|
|
||||||
std::string line;
|
|
||||||
bool read_ok = true;
|
|
||||||
if (wait_stdin_data())
|
|
||||||
{
|
|
||||||
if (m_run.load(std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
std::getline(std::cin, line);
|
|
||||||
read_ok = !std::cin.eof() && !std::cin.fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
read_ok = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_response_mutex);
|
|
||||||
if (m_run.load(std::memory_order_relaxed))
|
|
||||||
{
|
|
||||||
m_line = std::move(line);
|
|
||||||
m_read_status = read_ok ? state_success : state_error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_read_status = state_cancelled;
|
|
||||||
}
|
|
||||||
m_response_cv.notify_one();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum t_state
|
|
||||||
{
|
|
||||||
state_init,
|
|
||||||
state_success,
|
|
||||||
state_error,
|
|
||||||
state_cancelled
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::thread m_reader_thread;
|
|
||||||
std::atomic<bool> m_run;
|
|
||||||
|
|
||||||
std::string m_line;
|
|
||||||
bool m_has_read_request;
|
|
||||||
t_state m_read_status;
|
|
||||||
|
|
||||||
std::mutex m_request_mutex;
|
|
||||||
std::mutex m_response_mutex;
|
|
||||||
std::condition_variable m_request_cv;
|
|
||||||
std::condition_variable m_response_cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<class t_server>
|
|
||||||
bool empty_commands_handler(t_server* psrv, const std::string& command)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class async_console_handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
async_console_handler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class t_server, class chain_handler>
|
|
||||||
bool run(t_server* psrv, chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
|
|
||||||
{
|
|
||||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(psrv, cmd); }, [&] { psrv->send_stop_signal(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class chain_handler>
|
|
||||||
bool run(chain_handler ch_handler, const std::string& prompt = "#", const std::string& usage = "")
|
|
||||||
{
|
|
||||||
return run(prompt, usage, [&](const std::string& cmd) { return ch_handler(cmd); }, [] { });
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop()
|
|
||||||
{
|
|
||||||
m_stdin_reader.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename t_cmd_handler, typename t_exit_handler>
|
|
||||||
bool run(const std::string& prompt, const std::string& usage, const t_cmd_handler& cmd_handler, const t_exit_handler& exit_handler)
|
|
||||||
{
|
|
||||||
TRY_ENTRY();
|
|
||||||
bool continue_handle = true;
|
|
||||||
while(continue_handle)
|
|
||||||
{
|
|
||||||
if (!prompt.empty())
|
|
||||||
{
|
|
||||||
epee::log_space::set_console_color(epee::log_space::console_color_yellow, true);
|
|
||||||
std::cout << prompt;
|
|
||||||
if (' ' != prompt.back())
|
|
||||||
std::cout << ' ';
|
|
||||||
epee::log_space::reset_console_color();
|
|
||||||
std::cout.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string command;
|
|
||||||
if(!m_stdin_reader.get_line(command))
|
|
||||||
{
|
|
||||||
LOG_PRINT("Failed to read line. Stopping...", LOG_LEVEL_0);
|
|
||||||
continue_handle = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
string_tools::trim(command);
|
|
||||||
|
|
||||||
LOG_PRINT_L2("Read command: " << command);
|
|
||||||
if(0 == command.compare("exit") || 0 == command.compare("q"))
|
|
||||||
{
|
|
||||||
continue_handle = false;
|
|
||||||
}else if (command.empty())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if(cmd_handler(command))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
std::cout << "unknown command: " << command << std::endl;
|
|
||||||
std::cout << usage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit_handler();
|
|
||||||
return true;
|
|
||||||
CATCH_ENTRY_L0("console_handler", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
async_stdin_reader m_stdin_reader;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<class t_server, class t_handler>
|
|
||||||
bool start_default_console(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "")
|
|
||||||
{
|
|
||||||
std::shared_ptr<async_console_handler> console_handler = std::make_shared<async_console_handler>();
|
|
||||||
std::thread([=](){console_handler->run<t_server, t_handler>(ptsrv, handlr, prompt, usage);}).detach();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class t_server>
|
|
||||||
bool start_default_console(t_server* ptsrv, const std::string& prompt, const std::string& usage = "")
|
|
||||||
{
|
|
||||||
return start_default_console(ptsrv, empty_commands_handler<t_server>, prompt, 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& prompt, const std::string& usage = "")
|
|
||||||
{
|
|
||||||
async_console_handler console_handler;
|
|
||||||
return console_handler.run(ptsrv, std::bind<bool>(no_srv_param_adapter<t_server, t_handler>, std::placeholders::_1, std::placeholders::_2, handlr), prompt, 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& prompt, const std::string& usage = "")
|
|
||||||
{
|
|
||||||
std::thread( std::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
class console_handlers_binder
|
|
||||||
{
|
|
||||||
typedef std::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<std::thread> m_console_thread;
|
|
||||||
command_handlers_map m_command_handlers;
|
|
||||||
async_console_handler m_console_handler;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool start_handling(const std::string& prompt, const std::string& usage_string = "")
|
|
||||||
{
|
|
||||||
m_console_thread.reset(new std::thread(std::bind(&console_handlers_binder::run_handling, this, prompt, usage_string)));
|
|
||||||
m_console_thread->detach();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_handling()
|
|
||||||
{
|
|
||||||
m_console_handler.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool run_handling(const std::string& prompt, const std::string& usage_string)
|
|
||||||
{
|
|
||||||
return m_console_handler.run(std::bind(&console_handlers_binder::process_command_str, this, std::placeholders::_1), prompt, 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& prompt, const std::string& usage_string = "")
|
|
||||||
{
|
|
||||||
std::thread(std::bind(&srv_console_handlers_binder<t_server>::run_handling, this, psrv, prompt, usage_string)).detach();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string)
|
|
||||||
{
|
|
||||||
return m_console_handler.run(psrv, std::bind(&srv_console_handlers_binder<t_server>::process_command_str, this,
|
|
||||||
std::placeholders::_1, std::placeholders::_2), prompt, usage_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_handling()
|
|
||||||
{
|
|
||||||
m_console_handler.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
async_console_handler m_console_handler;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
class copyable_atomic: public std::atomic<uint32_t>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
copyable_atomic()
|
|
||||||
{};
|
|
||||||
copyable_atomic(const copyable_atomic& a):std::atomic<uint32_t>(a.load())
|
|
||||||
{}
|
|
||||||
copyable_atomic& operator= (const copyable_atomic& a)
|
|
||||||
{
|
|
||||||
store(a.load());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
uint32_t operator++()
|
|
||||||
{
|
|
||||||
return std::atomic<uint32_t>::operator++();
|
|
||||||
}
|
|
||||||
uint32_t operator++(int fake)
|
|
||||||
{
|
|
||||||
return std::atomic<uint32_t>::operator++(fake);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,452 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _FILE_IO_UTILS_H_
|
|
||||||
#define _FILE_IO_UTILS_H_
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#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, 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, 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>& 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>& 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_
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
std::stringstream& operator<<(std::stringstream& out, const std::wstring& ws)
|
|
||||||
{
|
|
||||||
std::string as = string_encoding::convert_to_ansii(ws);
|
|
||||||
out << as;
|
|
||||||
return out;
|
|
||||||
}
|
|
|
@ -1,227 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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_
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
|
@ -1,34 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define BOOST_FILESYSTEM_VERSION 3
|
|
||||||
#define ENABLE_RELEASE_LOGGING
|
|
||||||
|
|
||||||
#include "misc_log_ex.h"
|
|
||||||
|
|
||||||
|
|
|
@ -1,273 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <numeric>
|
|
||||||
#include <boost/timer.hpp>
|
|
||||||
#include <boost/uuid/uuid.hpp>
|
|
||||||
#include <boost/uuid/random_generator.hpp>
|
|
||||||
|
|
||||||
#include "misc_os_dependent.h"
|
|
||||||
#include "pragma_comp_defs.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<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
|
|
||||||
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(uint64_t ticks)
|
|
||||||
{
|
|
||||||
CRITICAL_REGION_BEGIN(m_lock);
|
|
||||||
std::list<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<uint64_t> m_chicks;
|
|
||||||
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(¤t_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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
|
@ -1,563 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
|
@ -1,162 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,507 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifndef _MISC_LOG_EX_H_
|
|
||||||
#define _MISC_LOG_EX_H_
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
|
||||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "misc_os_dependent.h"
|
|
||||||
#include "static_initializer.h"
|
|
||||||
#include "syncobj.h"
|
|
||||||
#include "warnings.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() const { return 0; }
|
|
||||||
|
|
||||||
virtual bool set_max_logfile_size(uint64_t max_size) { return true; }
|
|
||||||
virtual bool set_log_rotate_cmd(const std::string& cmd) { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
struct delete_ptr
|
|
||||||
{
|
|
||||||
template <class P>
|
|
||||||
void operator() (P p)
|
|
||||||
{
|
|
||||||
delete p.first;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
bool is_stdout_a_tty();
|
|
||||||
void set_console_color(int color, bool bright);
|
|
||||||
void reset_console_color();
|
|
||||||
bool rotate_log_file(const char* pfile_path);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------
|
|
||||||
#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) override;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class console_output_stream: public ibase_log_stream
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
bool m_have_to_kill_console;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
console_output_stream();
|
|
||||||
virtual ~console_output_stream();
|
|
||||||
|
|
||||||
virtual int get_type() const override { return LOGGER_CONSOLE; }
|
|
||||||
virtual bool out_buffer(const char* buffer, int buffer_len , int log_level, int color, const char* plog_name = NULL) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------//
|
|
||||||
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);
|
|
||||||
~file_output_stream();
|
|
||||||
|
|
||||||
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;
|
|
||||||
uint64_t m_max_logfile_size;
|
|
||||||
|
|
||||||
virtual int get_type() const override { return LOGGER_FILE; }
|
|
||||||
virtual bool out_buffer(const char* buffer, int buffer_len, int log_level, int color, const char* plog_name = NULL) override;
|
|
||||||
virtual bool set_max_logfile_size(uint64_t max_size) override;
|
|
||||||
virtual bool set_log_rotate_cmd(const std::string& cmd) override;
|
|
||||||
|
|
||||||
std::ofstream* add_new_stream_and_open(const char* pstream_name);
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
class log_stream_splitter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::list<std::pair<ibase_log_stream*, int> > streams_container;
|
|
||||||
|
|
||||||
log_stream_splitter() { }
|
|
||||||
~log_stream_splitter();
|
|
||||||
|
|
||||||
bool set_max_logfile_size(uint64_t max_size);
|
|
||||||
bool set_log_rotate_cmd(const std::string& cmd);
|
|
||||||
bool do_log_message(const std::string& rlog_mes, int log_level, int color, const char* plog_name = NULL);
|
|
||||||
bool add_logger(int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4);
|
|
||||||
bool add_logger(ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4);
|
|
||||||
bool remove_logger(int type);
|
|
||||||
|
|
||||||
private:
|
|
||||||
streams_container m_log_streams;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
int get_set_log_detalisation_level(bool is_need_set = false, int log_level_to_set = LOG_LEVEL_1);
|
|
||||||
int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0);
|
|
||||||
bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false);
|
|
||||||
bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false);
|
|
||||||
|
|
||||||
std::string get_daytime_string2();
|
|
||||||
std::string get_day_time_string();
|
|
||||||
std::string get_time_string();
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
inline std::string get_time_string_adv(SYSTEMTIME* pst = NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class logger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
friend class log_singletone;
|
|
||||||
|
|
||||||
logger();
|
|
||||||
~logger() { }
|
|
||||||
|
|
||||||
bool set_max_logfile_size(uint64_t max_size);
|
|
||||||
bool set_log_rotate_cmd(const std::string& cmd);
|
|
||||||
bool take_away_journal(std::list<std::string>& journal);
|
|
||||||
bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool add_to_journal = false, const char* plog_name = NULL);
|
|
||||||
bool add_logger(int type, const char* pdefault_file_name, const char* pdefault_log_folder , int log_level_limit = LOG_LEVEL_4);
|
|
||||||
bool add_logger(ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4);
|
|
||||||
bool remove_logger(int type);
|
|
||||||
bool set_thread_prefix(const std::string& prefix);
|
|
||||||
std::string get_default_log_file() { return m_default_log_file; }
|
|
||||||
std::string get_default_log_folder() { return m_default_log_folder; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool init();
|
|
||||||
bool init_default_loggers();
|
|
||||||
bool init_log_path_by_default();
|
|
||||||
|
|
||||||
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();
|
|
||||||
static bool is_filter_error(int error_code);
|
|
||||||
static bool do_log_message(const std::string& rlog_mes, int log_level, int color, bool keep_in_journal, const char* plog_name = NULL);
|
|
||||||
static bool take_away_journal(std::list<std::string>& journal);
|
|
||||||
static bool set_max_logfile_size(uint64_t file_size);
|
|
||||||
static bool set_log_rotate_cmd(const std::string& cmd);
|
|
||||||
static bool add_logger(int type, const char* pdefault_file_name, const char* pdefault_log_folder, int log_level_limit = LOG_LEVEL_4);
|
|
||||||
static std::string get_default_log_file();
|
|
||||||
static std::string get_default_log_folder();
|
|
||||||
static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4);
|
|
||||||
static bool remove_logger(int 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);
|
|
||||||
POP_WARNINGS
|
|
||||||
|
|
||||||
static int get_set_time_level(bool is_need_set = false, int time_log_level = LOG_LEVEL_0);
|
|
||||||
static int get_set_process_level(bool is_need_set = false, int process_log_level = LOG_LEVEL_0);
|
|
||||||
static bool get_set_need_thread_id(bool is_need_set = false, bool is_need_val = false);
|
|
||||||
static bool get_set_need_proc_name(bool is_need_set = false, bool is_need_val = false);
|
|
||||||
static uint64_t get_set_err_count(bool is_need_set = false, uint64_t err_val = false);
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
static void SetThreadName( DWORD dwThreadID, const char* threadName);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static bool set_thread_log_prefix(const std::string& prefix);
|
|
||||||
static std::string get_prefix_entry();
|
|
||||||
|
|
||||||
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();
|
|
||||||
static bool un_init();
|
|
||||||
|
|
||||||
static logger* get_or_create_instance();
|
|
||||||
static logger* get_set_instance_internal(bool is_need_set = false, logger* pnew_logger_val = NULL);
|
|
||||||
static bool get_set_is_uninitialized(bool is_need_set = false, bool is_uninitialized = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const static initializer<log_singletone> log_initializer;
|
|
||||||
|
|
||||||
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);
|
|
||||||
~log_frame();
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
inline bool getwin32_err_text(std::stringstream& ref_message, int error_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#define LOG_WARNING2(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() << "WARNING " << __FILE__ << ":" << __LINE__ << " " << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), y, 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);}}
|
|
||||||
|
|
||||||
#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)
|
|
||||||
|
|
||||||
#define LOG_WARNING2(log_name, x, level)
|
|
||||||
|
|
||||||
|
|
||||||
#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_YELLOW(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_yellow)
|
|
||||||
#define LOG_PRINT_CYAN(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_cyan)
|
|
||||||
#define LOG_PRINT_MAGENTA(mess, level) LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, mess, level, epee::log_space::console_color_magenta)
|
|
||||||
|
|
||||||
#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 LOG_WARNING(mess, level) LOG_WARNING2(LOG_DEFAULT_TARGET, mess, level)
|
|
||||||
|
|
||||||
#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_
|
|
|
@ -1,97 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "misc_os_dependent.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
|
|
||||||
#ifdef __MACH__
|
|
||||||
#include <mach/clock.h>
|
|
||||||
#include <mach/mach.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace misc_utils
|
|
||||||
{
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(NOMINMAX)
|
|
||||||
#define NOMINMAX 1
|
|
||||||
#endif // !defined(NOMINMAX)
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace misc_utils
|
|
||||||
{
|
|
||||||
uint64_t get_tick_count();
|
|
||||||
int call_sys_cmd(const std::string& cmd);
|
|
||||||
std::string get_thread_string_id();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,316 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _ABSTRACT_TCP_SERVER_H_
|
|
||||||
#define _ABSTRACT_TCP_SERVER_H_
|
|
||||||
|
|
||||||
#include <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_
|
|
|
@ -1,276 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _ABSTRACT_TCP_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(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 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 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 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, const boost::thread::attributes& attrs = boost::thread::attributes());
|
|
||||||
|
|
||||||
/// wait for service workers stop
|
|
||||||
bool timed_wait_server_stop(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, 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, 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;
|
|
||||||
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, 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, 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 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
|
|
|
@ -1,817 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "net_utils_base.h"
|
|
||||||
#include <boost/lambda/bind.hpp>
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
#include <boost/lambda/lambda.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/uuid/random_generator.hpp>
|
|
||||||
#include <boost/chrono.hpp>
|
|
||||||
#include <boost/utility/value_init.hpp>
|
|
||||||
#include <boost/asio/deadline_timer.hpp>
|
|
||||||
#include "include_base_utils.h"
|
|
||||||
#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 uint32_t& sock_count, i_connection_filter* &pfilter)
|
|
||||||
: strand_(io_service),
|
|
||||||
socket_(io_service),
|
|
||||||
m_want_close_connection(0),
|
|
||||||
m_was_shutdown(0),
|
|
||||||
m_ref_sockets_count(sock_count),
|
|
||||||
m_pfilter(pfilter),
|
|
||||||
m_protocol_handler(this, config, context)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
context.m_last_recv = time(NULL);
|
|
||||||
context.m_recv_cnt += bytes_transferred;
|
|
||||||
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);
|
|
||||||
context.m_last_send = time(NULL);
|
|
||||||
context.m_send_cnt += cb;
|
|
||||||
//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_WARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection", LOG_LEVEL_2);
|
|
||||||
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)) {
|
|
||||||
LOG_ERROR("Failed to convert port no = " << port);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
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, const boost::thread::attributes& attrs)
|
|
||||||
{
|
|
||||||
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(
|
|
||||||
attrs, 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(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, 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, 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
|
|
|
@ -1,233 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _LEVIN_CP_SERVER_H_
|
|
||||||
#define _LEVIN_CP_SERVER_H_
|
|
||||||
|
|
||||||
#include <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_
|
|
|
@ -1,605 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma comment(lib, "Ws2_32.lib")
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
//-------------------------------------------------------------
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,184 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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;
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,875 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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. header: " << m_header_cache, 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() && !u_c.host.empty())
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
|
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,212 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _HTTP_SERVER_H_
|
|
||||||
#define _HTTP_SERVER_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "include_base_utils.h"
|
|
||||||
#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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
template<class t_connection_context = net_utils::connection_context_base>
|
|
||||||
class simple_http_connection_handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef t_connection_context connection_context;//t_connection_context 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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class t_connection_context>
|
|
||||||
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,
|
|
||||||
t_connection_context& m_conn_context) = 0;
|
|
||||||
virtual bool init_server_thread(){return true;}
|
|
||||||
virtual bool deinit_server_thread(){return true;}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class t_connection_context>
|
|
||||||
struct custum_handler_config: public http_server_config
|
|
||||||
{
|
|
||||||
i_http_server_handler<t_connection_context>* m_phandler;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
template<class t_connection_context = net_utils::connection_context_base>
|
|
||||||
class http_custom_handler: public simple_http_connection_handler<t_connection_context>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef custum_handler_config<t_connection_context> config_type;
|
|
||||||
|
|
||||||
http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context)
|
|
||||||
: simple_http_connection_handler<t_connection_context>(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;
|
|
||||||
t_connection_context& m_conn_context;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "http_protocol_handler.inl"
|
|
||||||
|
|
||||||
#endif //_HTTP_SERVER_H_
|
|
|
@ -1,682 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#include <boost/regex.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include "http_protocol_handler.h"
|
|
||||||
#include "include_base_utils.h"
|
|
||||||
#include "reg_exp_definer.h"
|
|
||||||
#include "string_tools.h"
|
|
||||||
#include "time_helper.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
simple_http_connection_handler<t_connection_context>::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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
|
|
||||||
{
|
|
||||||
LOG_FRAME("simple_http_connection_handler<t_connection_context>::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<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
std::string::size_type simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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<t_connection_context>::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<t_connection_context>::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<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
|
|
||||||
m_state = http_state_error;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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<t_connection_context>::parse_cached_header() not matched last entry in:"<<m_cache_to_process);
|
|
||||||
}
|
|
||||||
|
|
||||||
it_current_bound = result[(int)result.size()-1]. first;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
std::string simple_http_connection_handler<t_connection_context>::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: Epee-based\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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
std::string simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
std::string simple_http_connection_handler<t_connection_context>::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;
|
|
||||||
}
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
template<class t_connection_context>
|
|
||||||
bool simple_http_connection_handler<t_connection_context>::slash_to_back_slash(std::string& str)
|
|
||||||
{
|
|
||||||
for(std::string::iterator it = str.begin(); it!=str.end(); it++)
|
|
||||||
if('/' == *it)
|
|
||||||
*it = '\\';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
||||||
//--------------------------------------------------------------------------------------------
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _HTTP_SERVER_CP_H_
|
|
||||||
#define _HTTP_SERVER_CP_H_
|
|
||||||
|
|
||||||
#include "abstract_tcp_server_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
|
|
||||||
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _HTTP_SERVER_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
|
|
||||||
|
|
||||||
|
|
|
@ -1,230 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "http_base.h"
|
|
||||||
#include "jsonrpc_structs.h"
|
|
||||||
#include "misc_os_dependent.h"
|
|
||||||
#include "storages/portable_storage.h"
|
|
||||||
#include "storages/portable_storage_template_helper.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
|
|
||||||
epee::net_utils::http::http_response_info& response, \
|
|
||||||
context_type& 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() template<class t_context> bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
|
|
||||||
epee::net_utils::http::http_response_info& response_info, \
|
|
||||||
t_context& 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; \
|
|
||||||
uint64_t ticks = epee::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); \
|
|
||||||
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), m_conn_context)) \
|
|
||||||
{ \
|
|
||||||
LOG_ERROR("Failed to " << #callback_f << "()"); \
|
|
||||||
response_info.m_response_code = 500; \
|
|
||||||
response_info.m_response_comment = "Internal Server Error"; \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
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); \
|
|
||||||
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; \
|
|
||||||
uint64_t ticks = epee::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()); \
|
|
||||||
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), m_conn_context)) \
|
|
||||||
{ \
|
|
||||||
LOG_ERROR("Failed to " << #callback_f << "()"); \
|
|
||||||
response_info.m_response_code = 500; \
|
|
||||||
response_info.m_response_comment = "Internal Server Error"; \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
|
||||||
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \
|
|
||||||
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;}
|
|
||||||
|
|
||||||
|
|
||||||
#define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == uri) \
|
|
||||||
{ \
|
|
||||||
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; \
|
|
||||||
} \
|
|
||||||
epee::serialization::storage_entry id_; \
|
|
||||||
id_ = epee::serialization::storage_entry(std::string()); \
|
|
||||||
ps.get_value("id", id_, nullptr); \
|
|
||||||
std::string callback_name; \
|
|
||||||
if(!ps.get_value("method", callback_name, nullptr)) \
|
|
||||||
{ \
|
|
||||||
epee::json_rpc::error_response rsp; \
|
|
||||||
rsp.jsonrpc = "2.0"; \
|
|
||||||
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 PREPARE_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
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_);\
|
|
||||||
if(!req.load(ps)) \
|
|
||||||
{ \
|
|
||||||
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
|
|
||||||
fail_resp.jsonrpc = "2.0"; \
|
|
||||||
fail_resp.id = req.id; \
|
|
||||||
fail_resp.error.code = -32602; \
|
|
||||||
fail_resp.error.message = "Invalid params"; \
|
|
||||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
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.jsonrpc = "2.0"; \
|
|
||||||
resp.id = req.id;
|
|
||||||
|
|
||||||
#define FINALIZE_OBJECTS_TO_JSON(method_name) \
|
|
||||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
|
||||||
epee::serialization::store_t_to_json(resp, response_info.m_body); \
|
|
||||||
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);
|
|
||||||
|
|
||||||
#define MAP_JON_RPC_WE(method_name, callback_f, command_type) \
|
|
||||||
else if(callback_name == method_name) \
|
|
||||||
{ \
|
|
||||||
PREPARE_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
|
|
||||||
fail_resp.jsonrpc = "2.0"; \
|
|
||||||
fail_resp.id = req.id; \
|
|
||||||
if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \
|
|
||||||
{ \
|
|
||||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
FINALIZE_OBJECTS_TO_JSON(method_name) \
|
|
||||||
return true;\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \
|
|
||||||
else if(callback_name == method_name) \
|
|
||||||
{ \
|
|
||||||
PREPARE_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
|
|
||||||
fail_resp.jsonrpc = "2.0"; \
|
|
||||||
fail_resp.id = req.id; \
|
|
||||||
if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context, response_info)) \
|
|
||||||
{ \
|
|
||||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), response_info.m_body); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
FINALIZE_OBJECTS_TO_JSON(method_name) \
|
|
||||||
return true;\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAP_JON_RPC(method_name, callback_f, command_type) \
|
|
||||||
else if(callback_name == method_name) \
|
|
||||||
{ \
|
|
||||||
PREPARE_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
if(!callback_f(req.params, resp.result, m_conn_context)) \
|
|
||||||
{ \
|
|
||||||
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
|
|
||||||
fail_resp.jsonrpc = "2.0"; \
|
|
||||||
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; \
|
|
||||||
} \
|
|
||||||
FINALIZE_OBJECTS_TO_JSON(method_name) \
|
|
||||||
return true;\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define END_JSON_RPC_MAP() \
|
|
||||||
epee::json_rpc::error_response rsp; \
|
|
||||||
rsp.id = id_; \
|
|
||||||
rsp.jsonrpc = "2.0"; \
|
|
||||||
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; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <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 t_connection_context = epee::net_utils::connection_context_base>
|
|
||||||
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
|
|
||||||
{
|
|
||||||
|
|
||||||
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_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _HTTP_SERVER_CP_H_
|
|
||||||
#define _HTTP_SERVER_CP_H_
|
|
||||||
|
|
||||||
#include "abstract_tcp_server.h"
|
|
||||||
#include "http_server.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
typedef abstract_tcp_server<http::simple_http_connection_handler> mt_http_server_file_system;
|
|
||||||
typedef abstract_tcp_server<http::http_custom_handler> mt_http_server_custum_handling;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -1,167 +0,0 @@
|
||||||
#ifndef JSONRPC_PROTOCOL_HANDLER_H
|
|
||||||
#define JSONRPC_PROTOCOL_HANDLER_H
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "net/net_utils_base.h"
|
|
||||||
#include "jsonrpc_structs.h"
|
|
||||||
#include "storages/portable_storage.h"
|
|
||||||
#include "storages/portable_storage_template_helper.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
namespace jsonrpc2
|
|
||||||
{
|
|
||||||
inline
|
|
||||||
std::string& make_error_resp_json(int64_t code, const std::string& message,
|
|
||||||
std::string& response_data,
|
|
||||||
const epee::serialization::storage_entry& id = nullptr)
|
|
||||||
{
|
|
||||||
epee::json_rpc::error_response rsp;
|
|
||||||
rsp.id = id;
|
|
||||||
rsp.jsonrpc = "2.0";
|
|
||||||
rsp.error.code = code;
|
|
||||||
rsp.error.message = message;
|
|
||||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_data, 0, false);
|
|
||||||
response_data += "\n";
|
|
||||||
return response_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class t_connection_context>
|
|
||||||
struct i_jsonrpc2_server_handler
|
|
||||||
{
|
|
||||||
virtual ~i_jsonrpc2_server_handler()
|
|
||||||
{}
|
|
||||||
virtual bool handle_rpc_request(const std::string& req_data,
|
|
||||||
std::string& resp_data,
|
|
||||||
t_connection_context& conn_context) = 0;
|
|
||||||
virtual bool init_server_thread()
|
|
||||||
{ return true; }
|
|
||||||
virtual bool deinit_server_thread()
|
|
||||||
{ return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class t_connection_context>
|
|
||||||
struct jsonrpc2_server_config
|
|
||||||
{
|
|
||||||
i_jsonrpc2_server_handler<t_connection_context>* m_phandler;
|
|
||||||
critical_section m_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class t_connection_context = net_utils::connection_context_base>
|
|
||||||
class jsonrpc2_connection_handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef t_connection_context connection_context;
|
|
||||||
typedef jsonrpc2_server_config<t_connection_context> config_type;
|
|
||||||
|
|
||||||
jsonrpc2_connection_handler(i_service_endpoint* psnd_hndlr,
|
|
||||||
config_type& config,
|
|
||||||
t_connection_context& conn_context)
|
|
||||||
: m_psnd_hndlr(psnd_hndlr),
|
|
||||||
m_config(config),
|
|
||||||
m_conn_context(conn_context),
|
|
||||||
m_is_stop_handling(false)
|
|
||||||
{}
|
|
||||||
virtual ~jsonrpc2_connection_handler()
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool release_protocol()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool thread_init()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool thread_deinit()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void handle_qued_callback()
|
|
||||||
{}
|
|
||||||
bool after_init_connection()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool handle_recv(const void* ptr, size_t cb)
|
|
||||||
{
|
|
||||||
std::string buf((const char*)ptr, cb);
|
|
||||||
LOG_PRINT_L0("JSONRPC2_RECV: " << ptr << "\r\n" << buf);
|
|
||||||
|
|
||||||
bool res = handle_buff_in(buf);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
bool 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) {
|
|
||||||
std::string::size_type pos = match_end_of_request(m_cache);
|
|
||||||
if (std::string::npos == pos) {
|
|
||||||
m_is_stop_handling = true;
|
|
||||||
if (m_cache.size() > 4096) {
|
|
||||||
LOG_ERROR("jsonrpc2_connection_handler::handle_buff_in: Too long request");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
extract_cached_request_and_handle(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_cache.size()) {
|
|
||||||
m_is_stop_handling = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool extract_cached_request_and_handle(std::string::size_type pos)
|
|
||||||
{
|
|
||||||
std::string request_data(m_cache.begin(), m_cache.begin() + pos);
|
|
||||||
m_cache.erase(0, pos);
|
|
||||||
return handle_request_and_send_response(request_data);
|
|
||||||
}
|
|
||||||
bool handle_request_and_send_response(const std::string& request_data)
|
|
||||||
{
|
|
||||||
CHECK_AND_ASSERT_MES(m_config.m_phandler, false, "m_config.m_phandler is NULL!!!!");
|
|
||||||
std::string response_data;
|
|
||||||
|
|
||||||
LOG_PRINT_L3("JSONRPC2_REQUEST: >> \r\n" << request_data);
|
|
||||||
bool rpc_result = m_config.m_phandler->handle_rpc_request(request_data, response_data, m_conn_context);
|
|
||||||
LOG_PRINT_L3("JSONRPC2_RESPONSE: << \r\n" << response_data);
|
|
||||||
|
|
||||||
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
|
|
||||||
return rpc_result;
|
|
||||||
}
|
|
||||||
std::string::size_type match_end_of_request(const std::string& buf)
|
|
||||||
{
|
|
||||||
std::string::size_type res = buf.find("\n");
|
|
||||||
if(std::string::npos != res) {
|
|
||||||
return res + 2;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
i_service_endpoint* m_psnd_hndlr;
|
|
||||||
|
|
||||||
private:
|
|
||||||
config_type& m_config;
|
|
||||||
t_connection_context& m_conn_context;
|
|
||||||
std::string m_cache;
|
|
||||||
bool m_is_stop_handling;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* JSONRPC_PROTOCOL_HANDLER_H */
|
|
|
@ -1,86 +0,0 @@
|
||||||
#ifndef JSONRPC_SERVER_HANDLERS_MAP_H
|
|
||||||
#define JSONRPC_SERVER_HANDLERS_MAP_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "serialization/keyvalue_serialization.h"
|
|
||||||
#include "storages/portable_storage_template_helper.h"
|
|
||||||
#include "storages/portable_storage_base.h"
|
|
||||||
#include "jsonrpc_structs.h"
|
|
||||||
#include "jsonrpc_protocol_handler.h"
|
|
||||||
|
|
||||||
#define BEGIN_JSONRPC2_MAP(t_connection_context) \
|
|
||||||
bool handle_rpc_request(const std::string& req_data, \
|
|
||||||
std::string& resp_data, \
|
|
||||||
t_connection_context& m_conn_context) \
|
|
||||||
{ \
|
|
||||||
bool handled = false; \
|
|
||||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
|
||||||
epee::serialization::portable_storage ps; \
|
|
||||||
if (!ps.load_from_json(req_data)) \
|
|
||||||
{ \
|
|
||||||
epee::net_utils::jsonrpc2::make_error_resp_json(-32700, "Parse error", resp_data); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
epee::serialization::storage_entry id_; \
|
|
||||||
id_ = epee::serialization::storage_entry(std::string()); \
|
|
||||||
if (!ps.get_value("id", id_, nullptr)) \
|
|
||||||
{ \
|
|
||||||
epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
std::string callback_name; \
|
|
||||||
if (!ps.get_value("method", callback_name, nullptr)) \
|
|
||||||
{ \
|
|
||||||
epee::net_utils::jsonrpc2::make_error_resp_json(-32600, "Invalid Request", resp_data, id_); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
if (false) return true; //just a stub to have "else if"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
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_);\
|
|
||||||
if(!req.load(ps)) \
|
|
||||||
{ \
|
|
||||||
epee::net_utils::jsonrpc2::make_error_resp_json(-32602, "Invalid params", resp_data, req.id); \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
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.jsonrpc = "2.0"; \
|
|
||||||
resp.id = req.id;
|
|
||||||
|
|
||||||
#define FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \
|
|
||||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
|
||||||
epee::serialization::store_t_to_json(resp, resp_data, 0, false); \
|
|
||||||
resp_data += "\n"; \
|
|
||||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
|
||||||
LOG_PRINT("[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2);
|
|
||||||
|
|
||||||
|
|
||||||
#define MAP_JSONRPC2_WE(method_name, callback_f, command_type) \
|
|
||||||
else if (callback_name == method_name) \
|
|
||||||
{ \
|
|
||||||
PREPARE_JSONRPC2_OBJECTS_FROM_JSON(command_type) \
|
|
||||||
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
|
|
||||||
fail_resp.jsonrpc = "2.0"; \
|
|
||||||
fail_resp.id = req.id; \
|
|
||||||
if(!callback_f(req.params, resp.result, fail_resp.error, m_conn_context)) \
|
|
||||||
{ \
|
|
||||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(fail_resp), resp_data, 0, false); \
|
|
||||||
resp_data += "\n"; \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
FINALIZE_JSONRPC2_OBJECTS_TO_JSON(method_name) \
|
|
||||||
return true; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define END_JSONRPC2_MAP() \
|
|
||||||
epee::net_utils::jsonrpc2::make_error_resp_json(-32601, "Method not found", resp_data, id_); \
|
|
||||||
return true; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* JSONRPC_SERVER_HANDLERS_MAP_H */
|
|
|
@ -1,84 +0,0 @@
|
||||||
#ifndef JSONRPC_SERVER_IMPL_BASE_H
|
|
||||||
#define JSONRPC_SERVER_IMPL_BASE_H
|
|
||||||
|
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <boost/bind.hpp>
|
|
||||||
|
|
||||||
#include "net/jsonrpc_protocol_handler.h"
|
|
||||||
#include "net/jsonrpc_server_handlers_map.h"
|
|
||||||
#include "net/abstract_tcp_server2.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
|
|
||||||
template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
|
|
||||||
class jsonrpc_server_impl_base: public net_utils::jsonrpc2::i_jsonrpc2_server_handler<t_connection_context>
|
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
|
||||||
jsonrpc_server_impl_base()
|
|
||||||
: m_net_server()
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit jsonrpc_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);
|
|
||||||
|
|
||||||
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_tcp_server<net_utils::jsonrpc2::jsonrpc2_connection_handler<t_connection_context> > m_net_server;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* JSONRPC_SERVER_IMPL_BASE_H */
|
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
#ifndef JSONRPC_STRUCTS_H
|
|
||||||
#define JSONRPC_STRUCTS_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <cstdint>
|
|
||||||
#include "serialization/keyvalue_serialization.h"
|
|
||||||
#include "storages/portable_storage_base.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace json_rpc
|
|
||||||
{
|
|
||||||
template<typename t_param>
|
|
||||||
struct request
|
|
||||||
{
|
|
||||||
std::string jsonrpc;
|
|
||||||
std::string method;
|
|
||||||
epee::serialization::storage_entry id;
|
|
||||||
t_param params;
|
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
|
||||||
KV_SERIALIZE(jsonrpc)
|
|
||||||
KV_SERIALIZE(id)
|
|
||||||
KV_SERIALIZE(method)
|
|
||||||
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()
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dummy_result
|
|
||||||
{
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
|
||||||
END_KV_SERIALIZE_MAP()
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename t_param, typename t_error>
|
|
||||||
struct response
|
|
||||||
{
|
|
||||||
std::string jsonrpc;
|
|
||||||
t_param result;
|
|
||||||
epee::serialization::storage_entry id;
|
|
||||||
t_error error;
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
|
||||||
KV_SERIALIZE(jsonrpc)
|
|
||||||
KV_SERIALIZE(id)
|
|
||||||
KV_SERIALIZE(result)
|
|
||||||
KV_SERIALIZE(error)
|
|
||||||
END_KV_SERIALIZE_MAP()
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename t_param>
|
|
||||||
struct response<t_param, dummy_error>
|
|
||||||
{
|
|
||||||
std::string jsonrpc;
|
|
||||||
t_param result;
|
|
||||||
epee::serialization::storage_entry id;
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
|
||||||
KV_SERIALIZE(jsonrpc)
|
|
||||||
KV_SERIALIZE(id)
|
|
||||||
KV_SERIALIZE(result)
|
|
||||||
END_KV_SERIALIZE_MAP()
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename t_error>
|
|
||||||
struct response<dummy_result, t_error>
|
|
||||||
{
|
|
||||||
std::string jsonrpc;
|
|
||||||
t_error error;
|
|
||||||
epee::serialization::storage_entry id;
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
|
||||||
KV_SERIALIZE(jsonrpc)
|
|
||||||
KV_SERIALIZE(id)
|
|
||||||
KV_SERIALIZE(error)
|
|
||||||
END_KV_SERIALIZE_MAP()
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef response<dummy_result, error> error_response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* JSONRPC_STRUCTS_H */
|
|
|
@ -1,125 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _LEVIN_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
|
|
||||||
{
|
|
||||||
uint64_t m_signature;
|
|
||||||
uint64_t m_cb;
|
|
||||||
bool m_have_to_return_data;
|
|
||||||
uint32_t m_command;
|
|
||||||
int32_t m_return_code;
|
|
||||||
uint32_t m_reservedA; //probably some flags in future
|
|
||||||
uint32_t m_reservedB; //probably some check sum in future
|
|
||||||
};
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct bucket_head2
|
|
||||||
{
|
|
||||||
uint64_t m_signature;
|
|
||||||
uint64_t m_cb;
|
|
||||||
bool m_have_to_return_data;
|
|
||||||
uint32_t m_command;
|
|
||||||
int32_t m_return_code;
|
|
||||||
uint32_t m_flags;
|
|
||||||
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_
|
|
|
@ -1,89 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _LEVIN_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_
|
|
|
@ -1,194 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//------------------------------------------------------------------------------
|
|
|
@ -1,577 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include ""
|
|
||||||
#include "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 uint32_t m_is_stop;
|
|
||||||
volatile 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 uint32_t m_invoke_data_ready;
|
|
||||||
volatile 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;
|
|
||||||
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 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(uint32_t ip, uint32_t port, 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};
|
|
||||||
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, 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};
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,137 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "levin_base.h"
|
|
||||||
#include "serializeble_struct_helper.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _LEVIN_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(uint64_t) && *((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_
|
|
||||||
|
|
|
@ -1,779 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <boost/asio/deadline_timer.hpp>
|
|
||||||
#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;
|
|
||||||
uint64_t m_max_packet_size;
|
|
||||||
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;
|
|
||||||
|
|
||||||
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(uint64_t) && *((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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _HTTP_SERVER_CP_H_
|
|
||||||
#define _HTTP_SERVER_CP_H_
|
|
||||||
|
|
||||||
#include "abstract_tcp_server_cp.h"
|
|
||||||
#include "levin_protocol_handler.h"
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
typedef cp_server_impl<levin::protocol_handler> cp_levin_server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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
|
|
||||||
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
inline
|
|
||||||
bool is_ip_local(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(uint32_t ip)
|
|
||||||
{
|
|
||||||
if( (ip | 0xffffff00) == 0xffffff7f)
|
|
||||||
return true;
|
|
||||||
//MAKE_IP
|
|
||||||
/*
|
|
||||||
loopback ip
|
|
||||||
127.0.0.0 — 127.255.255.255
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _MULTIPROTOCOLS_SERVER_H_
|
|
||||||
#define _MULTIPROTOCOLS_SERVER_H_
|
|
||||||
|
|
||||||
//#include "abstract_tcp_server_cp.h"
|
|
||||||
#include "protocol_switcher.h"
|
|
||||||
#include "abstract_tcp_server2.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
//typedef cp_server_impl<net_utils::protocol_switcher> multiprotocol_server;
|
|
||||||
typedef boosted_tcp_server<net_utils::protocol_switcher> boosted_multiprotocol_server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //_MULTIPROTOCOLS_SERVER_H_
|
|
||||||
|
|
|
@ -1,376 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _MUNIN_CONNECTION_HANDLER_H_
|
|
||||||
#define _MUNIN_CONNECTION_HANDLER_H_
|
|
||||||
|
|
||||||
#include <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_
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _MUNIN_NODE_SERVER_H_
|
|
||||||
#define _MUNIN_NODE_SERVER_H_
|
|
||||||
|
|
||||||
#include <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_
|
|
|
@ -1,683 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
//#include <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, 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 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));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "http_base.h"
|
|
||||||
#include "include_base_utils.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<uint64_t>(result[6]);
|
|
||||||
}
|
|
||||||
if(result[7].matched)
|
|
||||||
{
|
|
||||||
content.uri = result[7];
|
|
||||||
return parse_uri(result[7], content.m_uri_content);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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 boost {
|
|
||||||
namespace asio {
|
|
||||||
class io_service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
/************************************************************************/
|
|
||||||
/* */
|
|
||||||
/************************************************************************/
|
|
||||||
struct connection_context_base
|
|
||||||
{
|
|
||||||
const boost::uuids::uuid m_connection_id;
|
|
||||||
const uint32_t m_remote_ip;
|
|
||||||
const uint32_t m_remote_port;
|
|
||||||
const bool m_is_income;
|
|
||||||
const time_t m_started;
|
|
||||||
time_t m_last_recv;
|
|
||||||
time_t m_last_send;
|
|
||||||
uint64_t m_recv_cnt;
|
|
||||||
uint64_t m_send_cnt;
|
|
||||||
|
|
||||||
connection_context_base(boost::uuids::uuid connection_id,
|
|
||||||
long remote_ip, int remote_port, bool is_income,
|
|
||||||
time_t last_recv = 0, time_t last_send = 0,
|
|
||||||
uint64_t recv_cnt = 0, uint64_t send_cnt = 0):
|
|
||||||
m_connection_id(connection_id),
|
|
||||||
m_remote_ip(remote_ip),
|
|
||||||
m_remote_port(remote_port),
|
|
||||||
m_is_income(is_income),
|
|
||||||
m_started(time(NULL)),
|
|
||||||
m_last_recv(last_recv),
|
|
||||||
m_last_send(last_send),
|
|
||||||
m_recv_cnt(recv_cnt),
|
|
||||||
m_send_cnt(send_cnt)
|
|
||||||
{}
|
|
||||||
|
|
||||||
connection_context_base(): m_connection_id(),
|
|
||||||
m_remote_ip(0),
|
|
||||||
m_remote_port(0),
|
|
||||||
m_is_income(false),
|
|
||||||
m_started(time(NULL)),
|
|
||||||
m_last_recv(0),
|
|
||||||
m_last_send(0),
|
|
||||||
m_recv_cnt(0),
|
|
||||||
m_send_cnt(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
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_PRINT_CC_YELLOW(ct, message, log_level) LOG_PRINT_YELLOW("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
|
||||||
#define LOG_PRINT_CC_CYAN(ct, message, log_level) LOG_PRINT_CYAN("[" << epee::net_utils::print_connection_context_short(ct) << "]" << message, log_level)
|
|
||||||
#define LOG_PRINT_CC_MAGENTA(ct, message, log_level) LOG_PRINT_MAGENTA("[" << 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 LOG_PRINT_CCONTEXT_YELLOW(message, log_level) LOG_PRINT_CC_YELLOW(context, message, log_level)
|
|
||||||
#define LOG_PRINT_CCONTEXT_CYAN(message, log_level) LOG_PRINT_CC_CYAN(context, message, log_level)
|
|
||||||
#define LOG_PRINT_CCONTEXT_MAGENTA(message, log_level) LOG_PRINT_CC_MAGENTA(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_
|
|
|
@ -1,121 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _PROTOCOL_SWITCHER_H_
|
|
||||||
#define _PROTOCOL_SWITCHER_H_
|
|
||||||
|
|
||||||
#include "levin_base.h"
|
|
||||||
#include "http_server.h"
|
|
||||||
#include "levin_protocol_handler.h"
|
|
||||||
//#include "abstract_tcp_server.h"
|
|
||||||
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace net_utils
|
|
||||||
{
|
|
||||||
struct protocl_switcher_config
|
|
||||||
{
|
|
||||||
http::http_custom_handler::config_type m_http_config;
|
|
||||||
levin::protocol_handler::config_type m_levin_config;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct i_protocol_handler
|
|
||||||
{
|
|
||||||
virtual bool handle_recv(const void* ptr, size_t cb)=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class t>
|
|
||||||
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(uint64_t))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(*((uint64_t*)&m_cached_buff[0]) == LEVIN_SIGNATURE)
|
|
||||||
{
|
|
||||||
pcurrent_handler = &m_levin_handler;
|
|
||||||
return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size());
|
|
||||||
}
|
|
||||||
if(m_cached_buff.substr(0, 4) == "GET " || m_cached_buff.substr(0, 4) == "POST")
|
|
||||||
{
|
|
||||||
pcurrent_handler = &m_http_handler;
|
|
||||||
return pcurrent_handler->handle_recv(m_cached_buff.data(), m_cached_buff.size());
|
|
||||||
}else
|
|
||||||
{
|
|
||||||
LOG_ERROR("Wrong protocol accepted on port...");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //_PROTOCOL_SWITCHER_H_
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#define RPC_METHOD_NAME(name) static inline const char* methodname(){return name;}
|
|
|
@ -1,181 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <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"
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,88 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "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;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
#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
|
|
|
@ -1,113 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _PROFILE_TOOLS_H_
|
|
||||||
#define _PROFILE_TOOLS_H_
|
|
||||||
|
|
||||||
#include <boost/date_time/posix_time/ptime.hpp>
|
|
||||||
|
|
||||||
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() uint64_t _____way_point_time = epee::misc_utils::get_tick_count();
|
|
||||||
#define WAY_POINT(name) {uint64_t delta = epee::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) {uint64_t delta = epee::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) uint64_t var_name = epee::misc_utils::get_tick_count();
|
|
||||||
#define TIME_MEASURE_FINISH(var_name) var_name = epee::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;
|
|
||||||
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;
|
|
||||||
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_
|
|
|
@ -1,84 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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 uint32_t regexp_initialized_1 = 0;\
|
|
||||||
volatile 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(®exp_initialized_1, 1);\
|
|
||||||
gregexplock.get_lock().unlock();\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STATIC_REGEXP_EXPR_2(var_name, xpr_text, reg_exp_flags) \
|
|
||||||
static volatile uint32_t regexp_initialized_2 = 0;\
|
|
||||||
volatile 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(®exp_initialized_2, 1);\
|
|
||||||
gregexplock.get_lock().lock().unlock();\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STATIC_REGEXP_EXPR_3(var_name, xpr_text, reg_exp_flags) \
|
|
||||||
static volatile uint32_t regexp_initialized_3 = 0;\
|
|
||||||
volatile 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(®exp_initialized_3, 1);\
|
|
||||||
gregexplock.get_lock().lock().unlock();\
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //_REG_EXP_DEFINER_H_
|
|
|
@ -1,249 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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_
|
|
|
@ -1,53 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <boost/utility/value_init.hpp>
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
#include "misc_log_ex.h"
|
|
||||||
#include "enableable.h"
|
|
||||||
#include "keyvalue_serialization_overloads.h"
|
|
||||||
#include "serialization/serialization.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)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,374 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/mpl/contains.hpp>
|
|
||||||
#include <boost/mpl/vector.hpp>
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<class t_storage>
|
|
||||||
struct base_serializable_types: public boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, typename t_storage::meta_entry>::type
|
|
||||||
{};
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------
|
|
||||||
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<t_storage>, 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<t_storage>, 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<t_storage>, 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<t_storage>, 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<t_storage>, 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<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
|
@ -1,323 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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_
|
|
|
@ -1,51 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
|
@ -1,179 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
|
@ -1,142 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "soci.h"
|
|
||||||
#include "soci-postgresql.h"
|
|
||||||
|
|
||||||
using namespace epee;
|
|
||||||
namespace soci
|
|
||||||
{
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct type_conversion<uint64_t>
|
|
||||||
{
|
|
||||||
typedef long long base_type;
|
|
||||||
|
|
||||||
static void from_base(base_type a_, indicator ind, uint64_t & mi)
|
|
||||||
{
|
|
||||||
if (ind == i_null)
|
|
||||||
{
|
|
||||||
mi = 0;
|
|
||||||
//throw soci_error("Null value not allowed for this type");
|
|
||||||
}
|
|
||||||
mi = (uint64_t)a_;
|
|
||||||
//mi.set(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void to_base(const 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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
/*}*/
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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();
|
|
||||||
}
|
|
||||||
~initializer()
|
|
||||||
{
|
|
||||||
to_initialize::un_init();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //_STATIC_INITIALIZER_H_
|
|
|
@ -1,132 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "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);}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _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_
|
|
|
@ -1,68 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _GZIPPED_INMEMSTORAGE_H_
|
|
||||||
#define _GZIPPED_INMEMSTORAGE_H_
|
|
||||||
|
|
||||||
#include "zlib_helper.h"
|
|
||||||
namespace epee
|
|
||||||
{
|
|
||||||
namespace StorageNamed
|
|
||||||
{
|
|
||||||
|
|
||||||
template<class 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
|
|
|
@ -1,126 +0,0 @@
|
||||||
|
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "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.jsonrpc = "2.0";
|
|
||||||
req_t.id = req_id;
|
|
||||||
req_t.method = method_name;
|
|
||||||
req_t.params = out_struct;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,291 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "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; \
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,260 +0,0 @@
|
||||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer in the
|
|
||||||
// documentation and/or other materials provided with the distribution.
|
|
||||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
|
||||||
// names of its contributors may be used to endorse or promote products
|
|
||||||
// derived from this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
|
||||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue