Merge remote-tracking branch 'bytecoin/master'
This commit is contained in:
commit
cde1b8ecde
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,3 +1,8 @@
|
|||
.DS_Store
|
||||
/build
|
||||
/tags
|
||||
.idea
|
||||
.ycm_extra_conf.py
|
||||
.ycm_extra_conf.pyc
|
||||
Release
|
||||
Debug
|
||||
|
|
|
@ -4,12 +4,20 @@ set(VERSION "0.1")
|
|||
# $Format:Packaged from commit %H%nset(COMMIT %h)%nset(REFS "%d")$
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
||||
set(CMAKE_CONFIGURATION_TYPES Debug RelWithDebInfo Release CACHE TYPE INTERNAL)
|
||||
set(CMAKE_SKIP_INSTALL_RULES ON)
|
||||
set(CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY ON)
|
||||
set(CMAKE_SUPPRESS_REGENERATION ON)
|
||||
enable_testing()
|
||||
# copy CTestCustom.cmake to build dir to disable long running tests in 'make test'
|
||||
configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_BINARY_DIR})
|
||||
|
||||
include_directories(include src contrib/epee/include external "${CMAKE_BINARY_DIR}/version")
|
||||
project(CryptoNote)
|
||||
|
||||
include_directories(include src external "${CMAKE_BINARY_DIR}/version")
|
||||
if(APPLE)
|
||||
include_directories(SYSTEM /usr/include/malloc)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
|
@ -20,26 +28,30 @@ else()
|
|||
include_directories(src/Platform/Linux)
|
||||
endif()
|
||||
|
||||
|
||||
set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
|
||||
|
||||
if(MSVC)
|
||||
add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D_VARIADIC_MAX=8 /D__SSE4_1__")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760")
|
||||
if(STATIC)
|
||||
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE)
|
||||
string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}")
|
||||
endforeach()
|
||||
endif()
|
||||
include_directories(SYSTEM src/platform/msc)
|
||||
else()
|
||||
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
# This option has no effect in glibc version less than 2.20.
|
||||
# Since glibc 2.20 _BSD_SOURCE is deprecated, this macro is recomended instead
|
||||
add_definitions("-D_DEFAULT_SOURCE -D_GNU_SOURCE")
|
||||
endif()
|
||||
set(ARCH native CACHE STRING "CPU to build for: -march value or default")
|
||||
if("${ARCH}" STREQUAL "default")
|
||||
set(ARCH_FLAG "")
|
||||
else()
|
||||
set(ARCH_FLAG "-march=${ARCH}")
|
||||
endif()
|
||||
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Werror -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized -Wno-error=unused-result")
|
||||
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Werror -Wno-error=extra -Wno-error=unused-function -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized -Wno-error=unused-result")
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNINGS "${WARNINGS} -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration -Wno-error=unused-function")
|
||||
else()
|
||||
|
@ -52,10 +64,16 @@ else()
|
|||
else()
|
||||
set(MINGW_FLAG "")
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 5.1))
|
||||
set(WARNINGS "${WARNINGS} -Wno-error=odr")
|
||||
endif()
|
||||
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes")
|
||||
set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} -maes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${MINGW_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} -maes")
|
||||
if(NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} -maes")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0")
|
||||
endif()
|
||||
|
@ -67,6 +85,12 @@ else()
|
|||
set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable")
|
||||
if(NOT APPLE)
|
||||
# There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_SYSTEM_NAME STREQUAL "Linux"
|
||||
AND CMAKE_BUILD_TYPE STREQUAL "Release" AND ((CMAKE_C_COMPILER_VERSION VERSION_GREATER 4.9) OR (CMAKE_C_COMPILER_VERSION VERSION_EQUAL 4.9)))
|
||||
# On linux, to build in lto mode, check that ld.gold linker is used: 'update-alternatives --install /usr/bin/ld ld /usr/bin/ld.gold HIGHEST_PRIORITY'
|
||||
set(CMAKE_AR gcc-ar)
|
||||
set(CMAKE_RANLIB gcc-ranlib)
|
||||
endif()
|
||||
set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto")
|
||||
endif()
|
||||
#if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
|
||||
|
@ -85,10 +109,7 @@ if(STATIC)
|
|||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
endif()
|
||||
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options coroutine context)
|
||||
if((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54))
|
||||
message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA")
|
||||
endif()
|
||||
find_package(Boost 1.55 REQUIRED COMPONENTS system filesystem thread date_time chrono regex serialization program_options)
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
if(MINGW)
|
||||
set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock")
|
||||
|
@ -124,7 +145,6 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(contrib)
|
||||
add_subdirectory(external)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(tests)
|
||||
|
|
11
CTestCustom.cmake
Normal file
11
CTestCustom.cmake
Normal file
|
@ -0,0 +1,11 @@
|
|||
set(CTEST_CUSTOM_TESTS_IGNORE
|
||||
CoreTests
|
||||
IntegrationTestLibrary
|
||||
TestGenerator
|
||||
CryptoTests
|
||||
IntegrationTests
|
||||
NodeRpcProxyTests
|
||||
PerformanceTests
|
||||
TransfersTests
|
||||
)
|
||||
|
30
README.md
30
README.md
|
@ -20,7 +20,7 @@ This is the reference code for [CryptoNote](https://cryptonote.org) cryptocurren
|
|||
|
||||
Name must be specified twice:
|
||||
|
||||
**1. in file src/cryptonote_config.h** - `CRYPTONOTE_NAME` constant
|
||||
**1. in file src/CryptoNoteConfig.h** - `CRYPTONOTE_NAME` constant
|
||||
|
||||
Example:
|
||||
```
|
||||
|
@ -39,7 +39,7 @@ set_property(TARGET daemon PROPERTY OUTPUT_NAME "furiouscoind")
|
|||
|
||||
### Second step. Emission logic
|
||||
|
||||
**1. Total money supply** (src/cryptonote_config.h)
|
||||
**1. Total money supply** (src/CryptoNoteConfig.h)
|
||||
|
||||
Total amount of coins to be emitted. Most of CryptoNote based coins use `(uint64_t)(-1)` (equals to 18446744073709551616). You can define number explicitly (for example `UINT64_C(858986905600000000)`).
|
||||
|
||||
|
@ -48,7 +48,7 @@ Example:
|
|||
const uint64_t MONEY_SUPPLY = (uint64_t)(-1);
|
||||
```
|
||||
|
||||
**2. Emission curve** (src/cryptonote_config.h)
|
||||
**2. Emission curve** (src/CryptoNoteConfig.h)
|
||||
|
||||
Be default CryptoNote provides emission formula with slight decrease of block reward with each block. This is different from Bitcoin where block reward halves every 4 years.
|
||||
|
||||
|
@ -59,7 +59,7 @@ Example:
|
|||
const unsigned EMISSION_SPEED_FACTOR = 18;
|
||||
```
|
||||
|
||||
**3. Difficulty target** (src/cryptonote_config.h)
|
||||
**3. Difficulty target** (src/CryptoNoteConfig.h)
|
||||
|
||||
Difficulty target is an ideal time period between blocks. In case an average time between blocks becomes less than difficulty target, the difficulty increases. Difficulty target is measured in seconds.
|
||||
|
||||
|
@ -78,7 +78,7 @@ const uint64_t DIFFICULTY_TARGET = 120;
|
|||
|
||||
**4. Block reward formula**
|
||||
|
||||
In case you are not satisfied with CryptoNote default implementation of block reward logic you can also change it. The implementation is in `src/cryptonote_core/Currency.cpp`:
|
||||
In case you are not satisfied with CryptoNote default implementation of block reward logic you can also change it. The implementation is in `src/CryptoNoteCore/Currency.cpp`:
|
||||
```
|
||||
bool Currency::getBlockReward(size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee, uint64_t& reward, int64_t& emissionChange) const
|
||||
```
|
||||
|
@ -93,7 +93,7 @@ Only the first part of this function is directly related to the emission logic.
|
|||
|
||||
### Third step. Networking
|
||||
|
||||
**1. Default ports for P2P and RPC networking** (src/cryptonote_config.h)
|
||||
**1. Default ports for P2P and RPC networking** (src/CryptoNoteConfig.h)
|
||||
|
||||
P2P port is used by daemons to talk to each other through P2P protocol.
|
||||
RPC port is used by wallet and other programs to talk to daemon.
|
||||
|
@ -111,7 +111,7 @@ const int RPC_DEFAULT_PORT = 18236;
|
|||
```
|
||||
|
||||
|
||||
**2. Network identifier** (src/p2p/p2p_networks.h)
|
||||
**2. Network identifier** (src/P2p/P2pNetworks.h)
|
||||
|
||||
This identifier is used in network packages in order not to mix two different cryptocoin networks. Change all the bytes to random values for your network:
|
||||
```
|
||||
|
@ -119,7 +119,7 @@ const static boost::uuids::uuid CRYPTONOTE_NETWORK = { { 0xA1, 0x1A, 0xA1, 0x1A,
|
|||
```
|
||||
|
||||
|
||||
**3. Seed nodes** (src/cryptonote_config.h)
|
||||
**3. Seed nodes** (src/CryptoNoteConfig.h)
|
||||
|
||||
Add IP addresses of your seed nodes.
|
||||
|
||||
|
@ -134,7 +134,7 @@ const std::initializer_list<const char*> SEED_NODES = {
|
|||
|
||||
### Fourth step. Transaction fee and related parameters
|
||||
|
||||
**1. Minimum transaction fee** (src/cryptonote_config.h)
|
||||
**1. Minimum transaction fee** (src/CryptoNoteConfig.h)
|
||||
|
||||
Zero minimum fee can lead to transaction flooding. Transactions cheaper than the minimum transaction fee wouldn't be accepted by daemons. 100000 value for `MINIMUM_FEE` is usually enough.
|
||||
|
||||
|
@ -144,7 +144,7 @@ const uint64_t MINIMUM_FEE = 100000;
|
|||
```
|
||||
|
||||
|
||||
**2. Penalty free block size** (src/cryptonote_config.h)
|
||||
**2. Penalty free block size** (src/CryptoNoteConfig.h)
|
||||
|
||||
CryptoNote protects chain from tx flooding by reducing block reward for blocks larger than the median block size. However, this rule applies for blocks larger than `CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE` bytes.
|
||||
|
||||
|
@ -166,7 +166,7 @@ const uint64_t CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0xe9; // addresses star
|
|||
|
||||
### Sixth step. Genesis block
|
||||
|
||||
**1. Build the binaries with blank genesis tx hex** (src/cryptonote_config.h)
|
||||
**1. Build the binaries with blank genesis tx hex** (src/CryptoNoteConfig.h)
|
||||
|
||||
You should leave `const char GENESIS_COINBASE_TX_HEX[]` blank and compile the binaries without it.
|
||||
|
||||
|
@ -186,9 +186,9 @@ furiouscoind --print-genesis-tx
|
|||
```
|
||||
|
||||
|
||||
**3. Copy the printed transaction hash** (src/cryptonote_config.h)
|
||||
**3. Copy the printed transaction hash** (src/CryptoNoteConfig.h)
|
||||
|
||||
Copy the tx hash that has been printed by the daemon to `GENESIS_COINBASE_TX_HEX` in `src/cryptonote_config.h`
|
||||
Copy the tx hash that has been printed by the daemon to `GENESIS_COINBASE_TX_HEX` in `src/CryptoNoteConfig.h`
|
||||
|
||||
Example:
|
||||
```
|
||||
|
@ -224,7 +224,7 @@ To build, change to a directory where this file is located, and run `make`. The
|
|||
* Building with Clang: it may be possible to use Clang instead of GCC, but this may not work everywhere. To build, run `export CC=clang CXX=clang++` before running `make`.
|
||||
|
||||
### On Windows
|
||||
Dependencies: MSVC 2012 or later, CMake 2.8.6 or later, and Boost 1.55. You may download them from:
|
||||
Dependencies: MSVC 2013 or later, CMake 2.8.6 or later, and Boost 1.55. You may download them from:
|
||||
|
||||
* http://www.microsoft.com/
|
||||
* http://www.cmake.org/
|
||||
|
@ -234,7 +234,7 @@ To build, change to a directory where this file is located, and run theas comman
|
|||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 11 Win64" ..
|
||||
cmake -G "Visual Studio 12 Win64" ..
|
||||
```
|
||||
|
||||
And then do Build.
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
Release notes 1.1.0
|
||||
|
||||
- CryptoNote RPC Wallet
|
||||
- Aggregate multi-addresses for CryptoNote RPC Wallet
|
||||
- Fusion transactions
|
||||
- Transactions pool synchronization
|
||||
- Wallet synchronization speed increase
|
||||
- High-level API update
|
||||
|
||||
- Full network layer refactoring
|
||||
- New multithreading library
|
||||
- Improved console logging
|
||||
- JSON RPC improvements
|
||||
|
||||
Release notes 1.0.2
|
||||
|
||||
- Multisignature with API
|
||||
|
|
|
@ -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,429 +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 "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,816 +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
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue