re-created new repo with all Zano changes
This commit is contained in:
parent
ac1b65b938
commit
82f2c63c15
542 changed files with 145625 additions and 2 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/nbproject/
|
||||
3
.travis.yml
Normal file
3
.travis.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
|
|
@ -1,2 +1,7 @@
|
|||
# Zano-node-util
|
||||
Zano tools for building pools and other stuff
|
||||
Node-Cryptonote-Util
|
||||
====================
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* Boost (http://www.boost.org/)
|
||||
53
binding.gyp
Normal file
53
binding.gyp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "cryptonote",
|
||||
"sources": [
|
||||
"src/main.cc",
|
||||
"src/currency_core/currency_format_utils.cpp",
|
||||
"src/currency_core/currency_format_utils_blocks.cpp",
|
||||
"src/crypto/tree-hash.c",
|
||||
"src/crypto/crypto.cpp",
|
||||
"src/crypto/crypto-ops.c",
|
||||
"src/crypto/crypto-ops-data.c",
|
||||
"src/crypto/hash.c",
|
||||
"src/crypto/keccak.c",
|
||||
"src/crypto/wild_keccak.cpp",
|
||||
"src/common/base58.cpp"
|
||||
],
|
||||
"include_dirs": [
|
||||
"src",
|
||||
"src/contrib/epee/include",
|
||||
"src/contrib/eos_portable_archive",
|
||||
"src/contrib",
|
||||
"<!(node -e \"require('nan')\")"
|
||||
],
|
||||
"link_settings": {
|
||||
"libraries": [
|
||||
"-lboost_system",
|
||||
"-lboost_date_time"
|
||||
]
|
||||
},
|
||||
"cflags_cc!": [
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti"
|
||||
],
|
||||
"cflags_cc": [
|
||||
"-std=c++0x",
|
||||
"-fexceptions",
|
||||
"-frtti"
|
||||
],
|
||||
"conditions": [
|
||||
[
|
||||
"OS=='mac'",
|
||||
{
|
||||
"xcode_settings": {
|
||||
"GCC_ENABLE_CPP_RTTI": "YES",
|
||||
"GCC_ENABLE_CPP_EXCEPTIONS": "YES"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
1
index.js
Normal file
1
index.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('bindings')('cryptonote.node')
|
||||
22
package.json
Normal file
22
package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "cryptonote-util",
|
||||
"version": "0.0.1",
|
||||
"main": "cryptonote",
|
||||
"author": {
|
||||
"name": "LucasJones, CryptoZoidberg",
|
||||
"email": "lucasjonesdev@hotmail.co.uk, crypto.zoidberg@gmail.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hyle-team/zano-node-util.gitt"
|
||||
},
|
||||
"dependencies" : {
|
||||
"bindings" : "*",
|
||||
"nan" : "^2.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"cryptonight",
|
||||
"cryptonote",
|
||||
"zano"
|
||||
]
|
||||
}
|
||||
248
src/common/base58.cpp
Normal file
248
src/common/base58.cpp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "int-util.h"
|
||||
#include "util.h"
|
||||
#include "varint.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace base58
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char alphabet[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
const size_t alphabet_size = sizeof(alphabet) - 1;
|
||||
const size_t encoded_block_sizes[] = {0, 2, 3, 5, 6, 7, 9, 10, 11};
|
||||
const size_t full_block_size = sizeof(encoded_block_sizes) / sizeof(encoded_block_sizes[0]) - 1;
|
||||
const size_t full_encoded_block_size = encoded_block_sizes[full_block_size];
|
||||
const size_t addr_checksum_size = 4;
|
||||
|
||||
struct reverse_alphabet
|
||||
{
|
||||
reverse_alphabet()
|
||||
{
|
||||
m_data.resize(alphabet[alphabet_size - 1] - alphabet[0] + 1, -1);
|
||||
|
||||
for (size_t i = 0; i < alphabet_size; ++i)
|
||||
{
|
||||
size_t idx = static_cast<size_t>(alphabet[i] - alphabet[0]);
|
||||
m_data[idx] = static_cast<int8_t>(i);
|
||||
}
|
||||
}
|
||||
|
||||
int operator()(char letter) const
|
||||
{
|
||||
size_t idx = static_cast<size_t>(letter - alphabet[0]);
|
||||
return idx < m_data.size() ? m_data[idx] : -1;
|
||||
}
|
||||
|
||||
static reverse_alphabet instance;
|
||||
|
||||
private:
|
||||
std::vector<int8_t> m_data;
|
||||
};
|
||||
|
||||
reverse_alphabet reverse_alphabet::instance;
|
||||
|
||||
struct decoded_block_sizes
|
||||
{
|
||||
decoded_block_sizes()
|
||||
{
|
||||
m_data.resize(encoded_block_sizes[full_block_size] + 1, -1);
|
||||
for (size_t i = 0; i <= full_block_size; ++i)
|
||||
{
|
||||
m_data[encoded_block_sizes[i]] = static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
|
||||
int operator()(size_t encoded_block_size) const
|
||||
{
|
||||
assert(encoded_block_size <= full_encoded_block_size);
|
||||
return m_data[encoded_block_size];
|
||||
}
|
||||
|
||||
static decoded_block_sizes instance;
|
||||
|
||||
private:
|
||||
std::vector<int> m_data;
|
||||
};
|
||||
|
||||
decoded_block_sizes decoded_block_sizes::instance;
|
||||
|
||||
uint64_t uint_8be_to_64(const uint8_t* data, size_t size)
|
||||
{
|
||||
assert(1 <= size && size <= sizeof(uint64_t));
|
||||
|
||||
uint64_t res = 0;
|
||||
switch (9 - size)
|
||||
{
|
||||
case 1: res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 2: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 3: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 4: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 5: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 6: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 7: res <<= 8; res |= *data++; BOOST_FALLTHROUGH;
|
||||
case 8: res <<= 8; res |= *data; break;
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void uint_64_to_8be(uint64_t num, size_t size, uint8_t* data)
|
||||
{
|
||||
assert(1 <= size && size <= sizeof(uint64_t));
|
||||
|
||||
uint64_t num_be = SWAP64BE(num);
|
||||
memcpy(data, reinterpret_cast<uint8_t*>(&num_be) + sizeof(uint64_t) - size, size);
|
||||
}
|
||||
|
||||
void encode_block(const char* block, size_t size, char* res)
|
||||
{
|
||||
assert(1 <= size && size <= full_block_size);
|
||||
|
||||
uint64_t num = uint_8be_to_64(reinterpret_cast<const uint8_t*>(block), size);
|
||||
int i = static_cast<int>(encoded_block_sizes[size]) - 1;
|
||||
while (0 < num)
|
||||
{
|
||||
uint64_t remainder = num % alphabet_size;
|
||||
num /= alphabet_size;
|
||||
res[i] = alphabet[remainder];
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
bool decode_block(const char* block, size_t size, char* res)
|
||||
{
|
||||
assert(1 <= size && size <= full_encoded_block_size);
|
||||
|
||||
int res_size = decoded_block_sizes::instance(size);
|
||||
if (res_size <= 0)
|
||||
return false; // Invalid block size
|
||||
|
||||
uint64_t res_num = 0;
|
||||
uint64_t order = 1;
|
||||
for (size_t i = size - 1; i < size; --i)
|
||||
{
|
||||
int digit = reverse_alphabet::instance(block[i]);
|
||||
if (digit < 0)
|
||||
return false; // Invalid symbol
|
||||
|
||||
//uint64_t product_hi;
|
||||
boost::multiprecision::uint128_t tmp = res_num;
|
||||
tmp += boost::multiprecision::uint128_t(order) * digit;
|
||||
|
||||
if (tmp < res_num || tmp > std::numeric_limits<uint64_t>::max() )
|
||||
return false; // Overflow
|
||||
|
||||
res_num = tmp.convert_to<uint64_t>();
|
||||
order *= alphabet_size; // Never overflows, 58^10 < 2^64
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(res_size) < full_block_size && (UINT64_C(1) << (8 * res_size)) <= res_num)
|
||||
return false; // Overflow
|
||||
|
||||
uint_64_to_8be(res_num, res_size, reinterpret_cast<uint8_t*>(res));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string encode(const std::string& data)
|
||||
{
|
||||
if (data.empty())
|
||||
return std::string();
|
||||
|
||||
size_t full_block_count = data.size() / full_block_size;
|
||||
size_t last_block_size = data.size() % full_block_size;
|
||||
size_t res_size = full_block_count * full_encoded_block_size + encoded_block_sizes[last_block_size];
|
||||
|
||||
std::string res(res_size, alphabet[0]);
|
||||
for (size_t i = 0; i < full_block_count; ++i)
|
||||
{
|
||||
encode_block(data.data() + i * full_block_size, full_block_size, &res[i * full_encoded_block_size]);
|
||||
}
|
||||
|
||||
if (0 < last_block_size)
|
||||
{
|
||||
encode_block(data.data() + full_block_count * full_block_size, last_block_size, &res[full_block_count * full_encoded_block_size]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool decode(const std::string& enc, std::string& data)
|
||||
{
|
||||
if (enc.empty())
|
||||
{
|
||||
data.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t full_block_count = enc.size() / full_encoded_block_size;
|
||||
size_t last_block_size = enc.size() % full_encoded_block_size;
|
||||
int last_block_decoded_size = decoded_block_sizes::instance(last_block_size);
|
||||
if (last_block_decoded_size < 0)
|
||||
return false; // Invalid enc length
|
||||
size_t data_size = full_block_count * full_block_size + last_block_decoded_size;
|
||||
|
||||
data.resize(data_size, 0);
|
||||
for (size_t i = 0; i < full_block_count; ++i)
|
||||
{
|
||||
if (!decode_block(enc.data() + i * full_encoded_block_size, full_encoded_block_size, &data[i * full_block_size]))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 < last_block_size)
|
||||
{
|
||||
if (!decode_block(enc.data() + full_block_count * full_encoded_block_size, last_block_size,
|
||||
&data[full_block_count * full_block_size]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string encode_addr(uint64_t tag, const std::string& data)
|
||||
{
|
||||
std::string buf = get_varint_data(tag);
|
||||
buf += data;
|
||||
crypto::hash hash = crypto::cn_fast_hash(buf.data(), buf.size());
|
||||
const char* hash_data = reinterpret_cast<const char*>(&hash);
|
||||
buf.append(hash_data, addr_checksum_size);
|
||||
return encode(buf);
|
||||
}
|
||||
|
||||
bool decode_addr(std::string addr, uint64_t& tag, std::string& data)
|
||||
{
|
||||
std::string addr_data;
|
||||
bool r = decode(addr, addr_data);
|
||||
if (!r) return false;
|
||||
if (addr_data.size() <= addr_checksum_size) return false;
|
||||
|
||||
std::string checksum(addr_checksum_size, '\0');
|
||||
checksum = addr_data.substr(addr_data.size() - addr_checksum_size);
|
||||
|
||||
addr_data.resize(addr_data.size() - addr_checksum_size);
|
||||
crypto::hash hash = crypto::cn_fast_hash(addr_data.data(), addr_data.size());
|
||||
std::string expected_checksum(reinterpret_cast<const char*>(&hash), addr_checksum_size);
|
||||
if (expected_checksum != checksum) return false;
|
||||
|
||||
int read = tools::read_varint(addr_data.begin(), addr_data.end(), tag);
|
||||
if (read <= 0) return false;
|
||||
|
||||
data = addr_data.substr(read);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/common/base58.h
Normal file
22
src/common/base58.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace base58
|
||||
{
|
||||
std::string encode(const std::string& data);
|
||||
bool decode(const std::string& enc, std::string& data);
|
||||
|
||||
std::string encode_addr(uint64_t tag, const std::string& data);
|
||||
bool decode_addr(std::string addr, uint64_t& tag, std::string& data);
|
||||
}
|
||||
}
|
||||
103
src/common/boost_serialization_helper.h
Normal file
103
src/common/boost_serialization_helper.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/archive/binary_oarchive.hpp>
|
||||
#include <boost/archive/binary_iarchive.hpp>
|
||||
#include <eos/portable_archive.hpp>
|
||||
|
||||
|
||||
|
||||
#define CHECK_PROJECT_NAME() std::string project_name = CURRENCY_NAME; ar & project_name; if(!(project_name == CURRENCY_NAME) ) {throw std::runtime_error(std::string("wrong storage file: project name in file: ") + project_name + ", expected: " + CURRENCY_NAME );}
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
template<class t_object>
|
||||
bool serialize_obj_to_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::ofstream data_file;
|
||||
data_file.open( file_path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
|
||||
boost::archive::binary_oarchive a(data_file);
|
||||
a << obj;
|
||||
|
||||
return !data_file.fail();
|
||||
CATCH_ENTRY_L0("serialize_obj_to_file", false);
|
||||
}
|
||||
|
||||
|
||||
template<class t_object>
|
||||
bool serialize_obj_to_buff(t_object& obj, std::string& buff)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
std::stringstream data_buff;
|
||||
|
||||
boost::archive::binary_oarchive a(data_buff);
|
||||
a << obj;
|
||||
buff = data_buff.str();
|
||||
return !data_buff.fail();
|
||||
CATCH_ENTRY_L0("serialize_obj_to_buff", false);
|
||||
}
|
||||
|
||||
template<class t_object, class t_stream>
|
||||
bool portble_serialize_obj_to_stream(t_object& obj, t_stream& stream)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
eos::portable_oarchive a(stream);
|
||||
a << obj;
|
||||
|
||||
return !stream.fail();
|
||||
CATCH_ENTRY_L0("serialize_obj_to_file", false);
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool unserialize_obj_from_file(t_object& obj, const std::string& file_path)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
std::ifstream data_file;
|
||||
data_file.open( file_path, std::ios_base::binary | std::ios_base::in);
|
||||
if(data_file.fail())
|
||||
return false;
|
||||
boost::archive::binary_iarchive a(data_file);
|
||||
|
||||
a >> obj;
|
||||
return !data_file.fail();
|
||||
CATCH_ENTRY_L0("unserialize_obj_from_file", false);
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool unserialize_obj_from_buff(t_object& obj, const std::string& buff)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
std::stringstream ss(buff);
|
||||
boost::archive::binary_iarchive a(ss);
|
||||
|
||||
a >> obj;
|
||||
return !ss.fail();
|
||||
CATCH_ENTRY_L0("unserialize_obj_from_obj", false);
|
||||
}
|
||||
|
||||
|
||||
template<class t_object, class t_stream>
|
||||
bool portable_unserialize_obj_from_stream(t_object& obj, t_stream& stream)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
eos::portable_iarchive a(stream);
|
||||
|
||||
a >> obj;
|
||||
return !stream.fail();
|
||||
CATCH_ENTRY_L0("unserialize_obj_from_file", false);
|
||||
}
|
||||
}
|
||||
25
src/common/command_line.cpp
Normal file
25
src/common/command_line.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include "command_line.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
|
||||
namespace command_line
|
||||
{
|
||||
const arg_descriptor<bool> arg_help = {"help", "Produce help message"};
|
||||
const arg_descriptor<bool> arg_version = {"version", "Output version information"};
|
||||
const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory"};
|
||||
|
||||
const arg_descriptor<std::string> arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") };
|
||||
const arg_descriptor<bool> arg_os_version = { "os-version", "" };
|
||||
const arg_descriptor<std::string> arg_log_dir = { "log-dir", "", "", true};
|
||||
const arg_descriptor<int> arg_log_level = { "log-level", "", LOG_LEVEL_0, true};
|
||||
const arg_descriptor<bool> arg_console = { "no-console", "Disable daemon console commands" };
|
||||
const arg_descriptor<bool> arg_show_details = { "currency-details", "Display currency details" };
|
||||
const arg_descriptor<bool> arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" };
|
||||
|
||||
}
|
||||
186
src/common/command_line.h
Normal file
186
src/common/command_line.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include "include_base_utils.h"
|
||||
|
||||
namespace command_line
|
||||
{
|
||||
template<typename T, bool required = false>
|
||||
struct arg_descriptor;
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<T, false>
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
T default_value;
|
||||
bool not_use_default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<std::vector<T>, false>
|
||||
{
|
||||
typedef std::vector<T> value_type;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<T, true>
|
||||
{
|
||||
static_assert(!std::is_same<T, bool>::value, "Boolean switch can't be required");
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/)
|
||||
{
|
||||
return boost::program_options::value<T>()->required();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
semantic->default_value(arg.default_value);
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
semantic->default_value(def);
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
boost::program_options::typed_value<std::vector<T>, char>* make_semantic(const arg_descriptor<std::vector<T>, false>& /*arg*/)
|
||||
{
|
||||
auto semantic = boost::program_options::value< std::vector<T> >();
|
||||
semantic->default_value(std::vector<T>(), "");
|
||||
return semantic;
|
||||
}
|
||||
|
||||
template<typename T, bool required>
|
||||
void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required>& arg, bool unique = true)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, make_semantic(arg), arg.description);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, false>& arg, const T& def, bool unique = true)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, make_semantic(arg, def), arg.description);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void add_arg(boost::program_options::options_description& description, const arg_descriptor<bool, false>& arg, bool unique)
|
||||
{
|
||||
if (0 != description.find_nothrow(arg.name, false))
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!unique, void(), "Argument already exists: " << arg.name);
|
||||
return;
|
||||
}
|
||||
|
||||
description.add_options()(arg.name, boost::program_options::bool_switch(), arg.description);
|
||||
}
|
||||
|
||||
template<typename charT>
|
||||
boost::program_options::basic_parsed_options<charT> parse_command_line(int argc, const charT* const argv[],
|
||||
const boost::program_options::options_description& desc, bool allow_unregistered = false)
|
||||
{
|
||||
auto parser = boost::program_options::command_line_parser(argc, argv);
|
||||
parser.options(desc);
|
||||
if (allow_unregistered)
|
||||
{
|
||||
parser.allow_unregistered();
|
||||
}
|
||||
return parser.run();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool handle_error_helper(const boost::program_options::options_description& desc, F parser)
|
||||
{
|
||||
try
|
||||
{
|
||||
return parser();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "Failed to parse arguments: " << e.what() << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Failed to parse arguments: unknown exception" << std::endl;
|
||||
std::cerr << desc << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, bool required>
|
||||
bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
|
||||
{
|
||||
auto value = vm[arg.name];
|
||||
return !value.empty();
|
||||
}
|
||||
|
||||
|
||||
template<typename T, bool required>
|
||||
T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
|
||||
{
|
||||
return vm[arg.name].template as<T>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool has_arg<bool, false>(const boost::program_options::variables_map& vm, const arg_descriptor<bool, false>& arg)
|
||||
{
|
||||
return get_arg<bool, false>(vm, arg);
|
||||
}
|
||||
|
||||
|
||||
extern const arg_descriptor<bool> arg_help;
|
||||
extern const arg_descriptor<bool> arg_version;
|
||||
extern const arg_descriptor<std::string> arg_data_dir;
|
||||
extern const arg_descriptor<std::string> arg_config_file;
|
||||
extern const arg_descriptor<bool> arg_os_version;
|
||||
extern const arg_descriptor<std::string> arg_log_dir;
|
||||
extern const arg_descriptor<int> arg_log_level;
|
||||
extern const arg_descriptor<bool> arg_console;
|
||||
extern const arg_descriptor<bool> arg_show_details;
|
||||
extern const arg_descriptor<bool> arg_show_rpc_autodoc;
|
||||
}
|
||||
57
src/common/crypto_boost_serialization.h
Normal file
57
src/common/crypto_boost_serialization.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
36
src/common/crypto_stream_operators.h
Normal file
36
src/common/crypto_stream_operators.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
//------
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
|
||||
template <class T>
|
||||
std::ostream &print256(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::ostream &print16(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v).substr(0, 5) << "..>";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string print16(const T &v) {
|
||||
return std::string("<") + epee::string_tools::pod_to_hex(v).substr(0, 5) + "..>";
|
||||
}
|
||||
|
||||
|
||||
namespace crypto {
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
|
||||
}
|
||||
1028
src/common/db_abstract_accessor.h
Normal file
1028
src/common/db_abstract_accessor.h
Normal file
File diff suppressed because it is too large
Load diff
51
src/common/db_backend_base.h
Normal file
51
src/common/db_backend_base.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ENV32BIT
|
||||
#define CACHE_SIZE uint64_t(uint64_t(1UL * 128UL) * 1024UL * 1024UL * 1024UL)
|
||||
#else
|
||||
#define CACHE_SIZE (1 * 1024UL * 1024UL * 1024UL)
|
||||
#endif
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
typedef size_t container_handle;
|
||||
const uint64_t invalid_tx_id = 0;
|
||||
struct i_db_callback
|
||||
{
|
||||
virtual bool on_enum_item(uint64_t i, const void* pkey, uint64_t ks, const void* pval, uint64_t vs) = 0;
|
||||
};
|
||||
|
||||
struct stat_info
|
||||
{
|
||||
uint64_t tx_count;
|
||||
uint64_t write_tx_count;
|
||||
uint64_t map_size;
|
||||
};
|
||||
|
||||
struct i_db_backend
|
||||
{
|
||||
virtual bool close()=0;
|
||||
virtual bool begin_transaction(bool read_only = false) = 0;
|
||||
virtual bool commit_transaction()=0;
|
||||
virtual void abort_transaction()=0;
|
||||
virtual bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE) = 0;
|
||||
virtual bool open_container(const std::string& name, container_handle& h)=0;
|
||||
virtual bool erase(container_handle h, const char* k, size_t s) = 0;
|
||||
virtual uint64_t size(container_handle h) = 0;
|
||||
virtual bool get(container_handle h, const char* k, size_t s, std::string& res_buff) = 0;
|
||||
virtual bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs) = 0;
|
||||
virtual bool clear(container_handle h) = 0;
|
||||
virtual bool enumerate(container_handle h, i_db_callback* pcb)=0;
|
||||
virtual bool get_stat_info(stat_info& si) = 0;
|
||||
virtual ~i_db_backend(){};
|
||||
};
|
||||
}
|
||||
}
|
||||
109
src/common/db_backend_leveldb.cpp
Normal file
109
src/common/db_backend_leveldb.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
|
||||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
//
|
||||
// #pragma once
|
||||
// #include "db_backend_leveldb.h"
|
||||
//
|
||||
// namespace tools
|
||||
// {
|
||||
// namespace db
|
||||
// {
|
||||
// level_db_backend : public i_db_backend
|
||||
// {
|
||||
// std::string m_path;
|
||||
// db_handle m_pdb;
|
||||
// public:
|
||||
// basic_db() :m_pdb(nullptr)
|
||||
// {}
|
||||
// ~basic_db(){ close(); }
|
||||
// bool close()
|
||||
// {
|
||||
// if (m_pdb)
|
||||
// delete m_pdb;
|
||||
// m_pdb = nullptr;
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// void begin_transaction()
|
||||
// {
|
||||
// //leveldb is not supporting transactions yet
|
||||
// }
|
||||
//
|
||||
// void commit_transaction()
|
||||
// {
|
||||
// //leveldb is not supporting transactions yet
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool open(const std::string& path)
|
||||
// {
|
||||
// m_path = path;
|
||||
// close();
|
||||
// leveldb::Options options;
|
||||
// options.create_if_missing = true;
|
||||
// leveldb::Status status = leveldb::DB::Open(options, path, &m_pdb);
|
||||
// if (!status.ok())
|
||||
// {
|
||||
// LOG_ERROR("Unable to open/create database " << path << ", error: " << status.ToString());
|
||||
// return err_handle;
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// bool erase(const char* k, size s)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::WriteOptions wo;
|
||||
// wo.sync = true;
|
||||
// leveldb::Status s = m_pdb->Delete(wo, leveldb::Slice(k, s));
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// CATCH_ENTRY_L0("get_t_object_from_db", false);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool get(const char* k, size s, std::string& res_buff)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::ReadOptions ro;
|
||||
// leveldb::Status s = m_pdb->Get(ro, leveldb::Slice(k, s), &res_buff);
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// CATCH_ENTRY_L0("get_t_object_from_db", false);
|
||||
// }
|
||||
//
|
||||
// bool clear()
|
||||
// {
|
||||
// close();
|
||||
// boost::system::error_code ec;
|
||||
// bool res = boost::filesystem::remove_all(m_path, ec);
|
||||
// if (!res)
|
||||
// {
|
||||
// LOG_ERROR("Failed to remove db file " << m_path << ", why: " << ec);
|
||||
// return false;
|
||||
// }
|
||||
// return open(m_path);
|
||||
// }
|
||||
//
|
||||
// bool set(const char* k, size s, const char* v, size vs)
|
||||
// {
|
||||
// TRY_ENTRY();
|
||||
// leveldb::WriteOptions wo;
|
||||
// wo.sync = true;
|
||||
// leveldb::Status s = m_pdb->Put(wo, leveldb::Slice(k, s), leveldb::Slice(v, vs));
|
||||
// if (!s.ok())
|
||||
// return false;
|
||||
//
|
||||
// return true;
|
||||
// CATCH_ENTRY_L0("set_t_object_to_db", false);
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
46
src/common/db_backend_leveldb.h
Normal file
46
src/common/db_backend_leveldb.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "include_base_utils.h"
|
||||
|
||||
// #include "db_backend_base.h"
|
||||
//
|
||||
// #include "currency_db_base.h"
|
||||
// #include "leveldb/db.h"
|
||||
// #include "common/boost_serialization_helper.h"
|
||||
// #include "common/difficulty_boost_serialization.h"
|
||||
// #include "currency_format_utils.h"
|
||||
//
|
||||
//
|
||||
// namespace tools
|
||||
// {
|
||||
// namespace db
|
||||
// {
|
||||
// typedef leveldb::DB* db_handle;
|
||||
//
|
||||
// static const db_handle err_handle = nullptr;
|
||||
//
|
||||
// class level_db_backend : public i_db_backend
|
||||
// {
|
||||
// std::string m_path;
|
||||
// db_handle m_pdb;
|
||||
// public:
|
||||
// level_db_backend() :m_pdb(nullptr)
|
||||
// {}
|
||||
// ~level_db_backend(){ close(); }
|
||||
// bool close();
|
||||
// void begin_transaction();
|
||||
// void commit_transaction();
|
||||
// bool open(const std::string& path);
|
||||
// bool erase(const char* k, size s);
|
||||
// bool get(const char* k, size s, std::string& res_buff);
|
||||
// bool clear();
|
||||
// bool set(const char* k, size s, const char* v, size vs);
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
366
src/common/db_backend_lmdb.cpp
Normal file
366
src/common/db_backend_lmdb.cpp
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "db_backend_lmdb.h"
|
||||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
#include "profile_tools.h"
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
|
||||
#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "lmdb"
|
||||
// 'lmdb' channel is disabled by default
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
lmdb_db_backend::lmdb_db_backend() : m_penv(AUTO_VAL_INIT(m_penv))
|
||||
{
|
||||
|
||||
}
|
||||
lmdb_db_backend::~lmdb_db_backend()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::open(const std::string& path_, uint64_t cache_sz)
|
||||
{
|
||||
int res = 0;
|
||||
res = mdb_env_create(&m_penv);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_create");
|
||||
|
||||
res = mdb_env_set_maxdbs(m_penv, 15);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_maxdbs");
|
||||
|
||||
res = mdb_env_set_mapsize(m_penv, cache_sz);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_set_mapsize");
|
||||
|
||||
m_path = path_;
|
||||
#ifdef WIN32
|
||||
m_path = epee::string_encoding::convert_ansii_to_utf8(m_path);
|
||||
#endif
|
||||
|
||||
res = mdb_env_open(m_penv, m_path.c_str(), MDB_NORDAHEAD , 0644);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_env_open, m_path=" << m_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::open_container(const std::string& name, container_handle& h)
|
||||
{
|
||||
|
||||
MDB_dbi dbi = AUTO_VAL_INIT(dbi);
|
||||
begin_transaction();
|
||||
int res = mdb_dbi_open(get_current_tx(), name.c_str(), MDB_CREATE, &dbi);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_dbi_open with container name: " << name);
|
||||
commit_transaction();
|
||||
h = static_cast<container_handle>(dbi);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::close()
|
||||
{
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& tx_thread : m_txs)
|
||||
{
|
||||
for (auto txe : tx_thread.second)
|
||||
{
|
||||
int res = mdb_txn_commit(txe.ptx);
|
||||
if (res != MDB_SUCCESS)
|
||||
{
|
||||
LOG_ERROR("[DB ERROR]: On close tranactions: " << mdb_strerror(res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_txs.clear();
|
||||
}
|
||||
if (m_penv)
|
||||
{
|
||||
mdb_env_close(m_penv);
|
||||
m_penv = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::begin_transaction(bool read_only)
|
||||
{
|
||||
if (!read_only)
|
||||
{
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE LOCKED", LOG_LEVEL_3);
|
||||
CRITICAL_SECTION_LOCK(m_write_exclusive_lock);
|
||||
}
|
||||
PROFILE_FUNC("lmdb_db_backend::begin_transaction");
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
transactions_list& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
MDB_txn* pparent_tx = nullptr;
|
||||
MDB_txn* p_new_tx = nullptr;
|
||||
if (rtxlist.size())
|
||||
pparent_tx = rtxlist.back().ptx;
|
||||
|
||||
|
||||
if (pparent_tx && read_only)
|
||||
{
|
||||
++rtxlist.back().count;
|
||||
}
|
||||
else
|
||||
{
|
||||
int res = 0;
|
||||
unsigned int flags = 0;
|
||||
if (read_only)
|
||||
flags += MDB_RDONLY;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(m_penv, "m_penv==null, db closed");
|
||||
res = mdb_txn_begin(m_penv, pparent_tx, flags, &p_new_tx);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_txn_begin");
|
||||
|
||||
rtxlist.push_back(tx_entry());
|
||||
rtxlist.back().count = read_only ? 1 : 0;
|
||||
rtxlist.back().ptx = p_new_tx;
|
||||
rtxlist.back().read_only = read_only;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LOG_PRINT_L4("[DB] Transaction started");
|
||||
return true;
|
||||
}
|
||||
|
||||
MDB_txn* lmdb_db_backend::get_current_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto& rtxlist = m_txs[std::this_thread::get_id()];
|
||||
CHECK_AND_ASSERT_MES(rtxlist.size(), nullptr, "Unable to find active tx for thread " << std::this_thread::get_id());
|
||||
return rtxlist.back().ptx;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::pop_tx_entry(tx_entry& txe)
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
CHECK_AND_ASSERT_MES(it != m_txs.end(), false, "[DB] Unable to find id cor current thread");
|
||||
CHECK_AND_ASSERT_MES(it->second.size(), false, "[DB] No active tx for current thread");
|
||||
|
||||
txe = it->second.back();
|
||||
|
||||
if (it->second.back().read_only && it->second.back().count == 0)
|
||||
{
|
||||
LOG_ERROR("Internal db tx state error: read_only and count readers == 0");
|
||||
}
|
||||
|
||||
if ((it->second.back().read_only && it->second.back().count < 2) || (!it->second.back().read_only && it->second.back().count < 1))
|
||||
{
|
||||
it->second.pop_back();
|
||||
if (!it->second.size())
|
||||
m_txs.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--it->second.back().count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::commit_transaction()
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::commit_transaction");
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Unable to pop_tx_entry");
|
||||
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
int res = 0;
|
||||
res = mdb_txn_commit(txe.ptx);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_txn_commit (error " << res << ")");
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction committed");
|
||||
return true;
|
||||
}
|
||||
|
||||
void lmdb_db_backend::abort_transaction()
|
||||
{
|
||||
{
|
||||
tx_entry txe = AUTO_VAL_INIT(txe);
|
||||
bool r = pop_tx_entry(txe);
|
||||
CHECK_AND_ASSERT_MES(r, void(), "Unable to pop_tx_entry");
|
||||
if (txe.count == 0 || (txe.read_only && txe.count == 1))
|
||||
{
|
||||
mdb_txn_abort(txe.ptx);
|
||||
if (!txe.read_only && !txe.count)
|
||||
{
|
||||
CRITICAL_SECTION_UNLOCK(m_write_exclusive_lock);
|
||||
LOG_PRINT_CYAN("[DB " << m_path << "] WRITE UNLOCKED(ABORTED)", LOG_LEVEL_3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
LOG_PRINT_L4("[DB] Transaction aborted");
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::erase(container_handle h, const char* k, size_t ks)
|
||||
{
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
|
||||
res = mdb_del(get_current_tx(), static_cast<MDB_dbi>(h), &key, nullptr);
|
||||
if (res == MDB_NOTFOUND)
|
||||
return false;
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_del");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::have_tx()
|
||||
{
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
auto it = m_txs.find(std::this_thread::get_id());
|
||||
if (it == m_txs.end())
|
||||
return false;
|
||||
return it->second.size() ? true : false;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::get(container_handle h, const char* k, size_t ks, std::string& res_buff)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::get");
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data = AUTO_VAL_INIT(data);
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
|
||||
res = mdb_get(get_current_tx(), static_cast<MDB_dbi>(h), &key, &data);
|
||||
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
|
||||
if (res == MDB_NOTFOUND)
|
||||
return false;
|
||||
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_get, h: " << h << ", ks: " << ks);
|
||||
res_buff.assign((const char*)data.mv_data, data.mv_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::clear(container_handle h)
|
||||
{
|
||||
int res = mdb_drop(get_current_tx(), static_cast<MDB_dbi>(h), 0);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_drop");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t lmdb_db_backend::size(container_handle h)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::size");
|
||||
MDB_stat container_stat = AUTO_VAL_INIT(container_stat);
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
int res = mdb_stat(get_current_tx(), static_cast<MDB_dbi>(h), &container_stat);
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_stat");
|
||||
return container_stat.ms_entries;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::set(container_handle h, const char* k, size_t ks, const char* v, size_t vs)
|
||||
{
|
||||
PROFILE_FUNC("lmdb_db_backend::set");
|
||||
int res = 0;
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data = AUTO_VAL_INIT(data);
|
||||
key.mv_data = (void*)k;
|
||||
key.mv_size = ks;
|
||||
data.mv_data = (void*)v;
|
||||
data.mv_size = vs;
|
||||
|
||||
res = mdb_put(get_current_tx(), static_cast<MDB_dbi>(h), &key, &data, 0);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_put");
|
||||
return true;
|
||||
}
|
||||
bool lmdb_db_backend::enumerate(container_handle h, i_db_callback* pcb)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(pcb, false, "null capback ptr passed to enumerate");
|
||||
MDB_val key = AUTO_VAL_INIT(key);
|
||||
MDB_val data = AUTO_VAL_INIT(data);
|
||||
|
||||
bool need_to_commit = false;
|
||||
if (!have_tx())
|
||||
{
|
||||
need_to_commit = true;
|
||||
begin_transaction(true);
|
||||
}
|
||||
MDB_cursor* cursor_ptr = nullptr;
|
||||
int res = mdb_cursor_open(get_current_tx(), static_cast<MDB_dbi>(h), &cursor_ptr);
|
||||
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_cursor_open");
|
||||
CHECK_AND_ASSERT_MES(cursor_ptr, false, "cursor_ptr is null after mdb_cursor_open");
|
||||
|
||||
uint64_t count = 0;
|
||||
do
|
||||
{
|
||||
int res = mdb_cursor_get(cursor_ptr, &key, &data, MDB_NEXT);
|
||||
if (res == MDB_NOTFOUND)
|
||||
break;
|
||||
if (!pcb->on_enum_item(count, key.mv_data, key.mv_size, data.mv_data, data.mv_size))
|
||||
break;
|
||||
count++;
|
||||
} while (cursor_ptr);
|
||||
|
||||
mdb_cursor_close(cursor_ptr);
|
||||
if (need_to_commit)
|
||||
commit_transaction();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lmdb_db_backend::get_stat_info(tools::db::stat_info& si)
|
||||
{
|
||||
si = AUTO_VAL_INIT_T(tools::db::stat_info);
|
||||
|
||||
MDB_envinfo ei = AUTO_VAL_INIT(ei);
|
||||
mdb_env_info(m_penv, &ei);
|
||||
si.map_size = ei.me_mapsize;
|
||||
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_cs);
|
||||
for (auto& e : m_txs)
|
||||
{
|
||||
for (auto& pr : e.second)
|
||||
{
|
||||
++si.tx_count;
|
||||
if(!pr.read_only)
|
||||
++si.write_tx_count;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL NULL
|
||||
66
src/common/db_backend_lmdb.h
Normal file
66
src/common/db_backend_lmdb.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <thread>
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "db_backend_base.h"
|
||||
#include "db/liblmdb/lmdb.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
||||
|
||||
class lmdb_db_backend : public i_db_backend
|
||||
{
|
||||
|
||||
struct tx_entry
|
||||
{
|
||||
MDB_txn* ptx;
|
||||
bool read_only; // needed for thread-top transaction, for figure out if we need to unlock exclusive access
|
||||
size_t count; //count of read-only nested emulated transactions
|
||||
};
|
||||
typedef std::list<tx_entry> transactions_list;
|
||||
|
||||
|
||||
std::string m_path;
|
||||
MDB_env *m_penv;
|
||||
|
||||
boost::recursive_mutex m_cs;
|
||||
boost::recursive_mutex m_write_exclusive_lock;
|
||||
std::map<std::thread::id, transactions_list> m_txs; // size_t -> count of nested read_only transactions
|
||||
bool pop_tx_entry(tx_entry& txe);
|
||||
public:
|
||||
lmdb_db_backend();
|
||||
~lmdb_db_backend();
|
||||
|
||||
//----------------- i_db_backend -----------------------------------------------------
|
||||
bool close();
|
||||
bool begin_transaction(bool read_only = false);
|
||||
bool commit_transaction();
|
||||
void abort_transaction();
|
||||
bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE);
|
||||
bool open_container(const std::string& name, container_handle& h);
|
||||
bool erase(container_handle h, const char* k, size_t s);
|
||||
bool get(container_handle h, const char* k, size_t s, std::string& res_buff);
|
||||
bool clear(container_handle h);
|
||||
uint64_t size(container_handle h);
|
||||
bool set(container_handle h, const char* k, size_t s, const char* v, size_t vs);
|
||||
bool enumerate(container_handle h, i_db_callback* pcb);
|
||||
bool get_stat_info(tools::db::stat_info& si);
|
||||
//-------------------------------------------------------------------------------------
|
||||
bool have_tx();
|
||||
MDB_txn* get_current_tx();
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
69
src/common/difficulty_boost_serialization.h
Normal file
69
src/common/difficulty_boost_serialization.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//---------------------------------------------------
|
||||
template <class archive_t>
|
||||
inline void serialize(archive_t &a, currency::wide_difficulty_type &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
if(archive_t::is_loading::value)
|
||||
{
|
||||
//load high part
|
||||
uint64_t v = 0;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "loading" << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
x = v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "hight part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
//load low part
|
||||
x = x << 64;
|
||||
a & v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "low part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
x += v;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "loaded value: " << std::hex << x << ENDL;
|
||||
#endif
|
||||
}else
|
||||
{
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "storing" << ENDL;
|
||||
#endif
|
||||
//store high part
|
||||
currency::wide_difficulty_type x_ = x;
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "original: " << std::hex << x_ << ENDL;
|
||||
#endif
|
||||
x_ = x_ >> 64;
|
||||
uint64_t v = x_.convert_to<uint64_t>();
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "hight part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
//store low part
|
||||
x_ = x;
|
||||
x_ = x_ << 64;
|
||||
x_ = x_ >> 64;
|
||||
v = x_.convert_to<uint64_t>();
|
||||
#ifdef DEBUG_DIFFICULTY_SERIALIZATION
|
||||
std::cout << "low part: " << std::hex << v << ENDL;
|
||||
#endif
|
||||
a & v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
src/common/int-util.h
Normal file
237
src/common/int-util.h
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static inline uint32_t rol32(uint32_t x, int r) {
|
||||
static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers");
|
||||
return _rotl(x, r);
|
||||
}
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int r) {
|
||||
return _rotl64(x, r);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint32_t rol32(uint32_t x, int r) {
|
||||
return (x << (r & 31)) | (x >> (-r & 31));
|
||||
}
|
||||
|
||||
static inline uint64_t rol64(uint64_t x, int r) {
|
||||
return (x << (r & 63)) | (x >> (-r & 63));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline uint64_t hi_dword(uint64_t val) {
|
||||
return val >> 32;
|
||||
}
|
||||
|
||||
static inline uint64_t lo_dword(uint64_t val) {
|
||||
return val & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline uint64_t mul128_manually(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi) {
|
||||
// multiplier = ab = a * 2^32 + b
|
||||
// multiplicand = cd = c * 2^32 + d
|
||||
// ab * cd = a * c * 2^64 + (a * d + b * c) * 2^32 + b * d
|
||||
uint64_t a = hi_dword(multiplier);
|
||||
uint64_t b = lo_dword(multiplier);
|
||||
uint64_t c = hi_dword(multiplicand);
|
||||
uint64_t d = lo_dword(multiplicand);
|
||||
|
||||
uint64_t ac = a * c;
|
||||
uint64_t ad = a * d;
|
||||
uint64_t bc = b * c;
|
||||
uint64_t bd = b * d;
|
||||
|
||||
uint64_t adbc = ad + bc;
|
||||
uint64_t adbc_carry = adbc < ad ? 1 : 0;
|
||||
|
||||
// multiplier * multiplicand = product_hi * 2^64 + product_lo
|
||||
uint64_t product_lo = bd + (adbc << 32);
|
||||
uint64_t product_lo_carry = product_lo < bd ? 1 : 0;
|
||||
*product_hi = ac + (adbc >> 32) + (adbc_carry << 32) + product_lo_carry;
|
||||
assert(ac <= *product_hi);
|
||||
|
||||
return product_lo;
|
||||
}
|
||||
|
||||
static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
|
||||
dividend |= ((uint64_t)*remainder) << 32;
|
||||
*remainder = dividend % divisor;
|
||||
return dividend / divisor;
|
||||
}
|
||||
|
||||
// Long division with 2^32 base
|
||||
static inline uint32_t div128_32_manually(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
|
||||
uint64_t dividend_dwords[4];
|
||||
uint32_t remainder = 0;
|
||||
|
||||
dividend_dwords[3] = hi_dword(dividend_hi);
|
||||
dividend_dwords[2] = lo_dword(dividend_hi);
|
||||
dividend_dwords[1] = hi_dword(dividend_lo);
|
||||
dividend_dwords[0] = lo_dword(dividend_lo);
|
||||
|
||||
*quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32;
|
||||
*quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder);
|
||||
*quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32;
|
||||
*quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder);
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
static inline uint64_t mul128(uint64_t multiplier, uint64_t multiplicand, uint64_t* product_hi)
|
||||
{
|
||||
// #if defined(_MSC_VER)
|
||||
// return _umul128(multiplier, multiplicand, product_hi);
|
||||
// #elif defined(__GNUC__)
|
||||
// __uint128_t product = ((__uint128_t)multiplier) * multiplicand;
|
||||
// *product_hi = (uint64_t)(product >> 64);
|
||||
// return ((uint64_t)product) & ~(UINT64_C(0));
|
||||
// #else
|
||||
return mul128_manually(multiplier, multiplicand, product_hi);
|
||||
//#endif*/
|
||||
}
|
||||
//*/
|
||||
|
||||
static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo)
|
||||
{
|
||||
// #if defined(__GNUC__)
|
||||
// __uint128_t dividend = (((__uint128_t)dividend_hi) << 64) | dividend_lo;
|
||||
// __uint128_t quotient = dividend / divisor;
|
||||
// __uint128_t reminder = dividend % divisor;
|
||||
// *quotient_hi = (uint64_t)(quotient >> 64);
|
||||
// *quotient_lo = ((uint64_t)quotient) & ~(UINT64_C(0));
|
||||
// return (uint32_t)reminder;
|
||||
// #else
|
||||
return div128_32_manually(dividend_hi, dividend_lo, divisor, quotient_hi, quotient_lo);
|
||||
//#endif
|
||||
}
|
||||
//*/
|
||||
#define IDENT32(x) ((uint32_t) (x))
|
||||
#define IDENT64(x) ((uint64_t) (x))
|
||||
|
||||
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
|
||||
(((uint32_t) (x) & 0x0000ff00) << 8) | \
|
||||
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
|
||||
(((uint32_t) (x) & 0xff000000) >> 24))
|
||||
#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
|
||||
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
|
||||
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
|
||||
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
|
||||
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
|
||||
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
|
||||
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
|
||||
(((uint64_t) (x) & 0xff00000000000000) >> 56))
|
||||
|
||||
static inline uint32_t ident32(uint32_t x) { return x; }
|
||||
static inline uint64_t ident64(uint64_t x) { return x; }
|
||||
|
||||
static inline uint32_t swap32(uint32_t x) {
|
||||
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||
return (x << 16) | (x >> 16);
|
||||
}
|
||||
static inline uint64_t swap64(uint64_t x) {
|
||||
x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8);
|
||||
x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16);
|
||||
return (x << 32) | (x >> 32);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define UNUSED
|
||||
#endif
|
||||
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
|
||||
#undef UNUSED
|
||||
|
||||
static inline void mem_inplace_swap32(void *mem, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint32_t *) mem)[i] = swap32(((const uint32_t *) mem)[i]);
|
||||
}
|
||||
}
|
||||
static inline void mem_inplace_swap64(void *mem, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint64_t *) mem)[i] = swap64(((const uint64_t *) mem)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
|
||||
memcpy(dst, src, 4 * n);
|
||||
}
|
||||
static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
|
||||
memcpy(dst, src, 8 * n);
|
||||
}
|
||||
|
||||
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint32_t *) dst)[i] = swap32(((const uint32_t *) src)[i]);
|
||||
}
|
||||
}
|
||||
static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
((uint64_t *) dst)[i] = swap64(((const uint64_t *) src)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define SWAP32LE IDENT32
|
||||
#define SWAP32BE SWAP32
|
||||
#define swap32le ident32
|
||||
#define swap32be swap32
|
||||
#define mem_inplace_swap32le mem_inplace_ident
|
||||
#define mem_inplace_swap32be mem_inplace_swap32
|
||||
#define memcpy_swap32le memcpy_ident32
|
||||
#define memcpy_swap32be memcpy_swap32
|
||||
#define SWAP64LE IDENT64
|
||||
#define SWAP64BE SWAP64
|
||||
#define swap64le ident64
|
||||
#define swap64be swap64
|
||||
#define mem_inplace_swap64le mem_inplace_ident
|
||||
#define mem_inplace_swap64be mem_inplace_swap64
|
||||
#define memcpy_swap64le memcpy_ident64
|
||||
#define memcpy_swap64be memcpy_swap64
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define SWAP32BE IDENT32
|
||||
#define SWAP32LE SWAP32
|
||||
#define swap32be ident32
|
||||
#define swap32le swap32
|
||||
#define mem_inplace_swap32be mem_inplace_ident
|
||||
#define mem_inplace_swap32le mem_inplace_swap32
|
||||
#define memcpy_swap32be memcpy_ident32
|
||||
#define memcpy_swap32le memcpy_swap32
|
||||
#define SWAP64BE IDENT64
|
||||
#define SWAP64LE SWAP64
|
||||
#define swap64be ident64
|
||||
#define swap64le swap64
|
||||
#define mem_inplace_swap64be mem_inplace_ident
|
||||
#define mem_inplace_swap64le mem_inplace_swap64
|
||||
#define memcpy_swap64be memcpy_ident64
|
||||
#define memcpy_swap64le memcpy_swap64
|
||||
#endif
|
||||
39
src/common/make_hashable.h
Normal file
39
src/common/make_hashable.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
#define POD_MAKE_COMPARABLE(space, type) \
|
||||
namespace space { \
|
||||
inline bool operator==(const type &_v1, const type &_v2) { \
|
||||
return std::memcmp(&_v1, &_v2, sizeof(type)) == 0; \
|
||||
} \
|
||||
inline bool operator!=(const type &_v1, const type &_v2) { \
|
||||
return std::memcmp(&_v1, &_v2, sizeof(type)) != 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define POD_MAKE_HASHABLE(space, type) \
|
||||
POD_MAKE_COMPARABLE(space, type) \
|
||||
namespace space { \
|
||||
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
|
||||
inline std::size_t hash_value(const type &_v) { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
} \
|
||||
} \
|
||||
namespace std { \
|
||||
template<> \
|
||||
struct hash<space::type> { \
|
||||
std::size_t operator()(const space::type &_v) const { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
133
src/common/median_db_cache.h
Normal file
133
src/common/median_db_cache.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "misc_language.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
#define LOC_INT_ERR(cond, msg) CHECK_AND_ASSERT_THROW_MES(cond, "internal error in median_db_cache: " << msg << ENDL << *this)
|
||||
template<typename key, typename associated_data>
|
||||
class median_db_cache : public epee::misc_utils::median_helper<key, associated_data>
|
||||
{
|
||||
typedef epee::misc_utils::median_helper<key, associated_data> super_t;
|
||||
struct db_entry_type
|
||||
{
|
||||
key k;
|
||||
associated_data d;
|
||||
};
|
||||
|
||||
//m_tx_median_helper;
|
||||
typedef tools::db::cached_key_value_accessor<uint64_t, db_entry_type, false, true> median_db_container;
|
||||
median_db_container m_median_container;
|
||||
uint64_t m_counter_hi;
|
||||
uint64_t m_counter_lo;
|
||||
bool m_is_loading_from_db;
|
||||
|
||||
bool load_items_from_db()
|
||||
{
|
||||
std::map<uint64_t, db_entry_type> loaded_entries;
|
||||
LOG_PRINT_L0("Loading median from db cache...");
|
||||
m_median_container.enumerate_items([&](uint64_t i, uint64_t index, const db_entry_type& entry)
|
||||
{
|
||||
//adjust counters
|
||||
if (index > m_counter_hi)
|
||||
m_counter_hi = index;
|
||||
if (index < m_counter_lo)
|
||||
m_counter_lo = index;
|
||||
loaded_entries[index] = entry;
|
||||
return true;
|
||||
});
|
||||
LOG_PRINT_L0("Loaded " << loaded_entries.size() << " items, building median cache...");
|
||||
|
||||
m_is_loading_from_db = true;
|
||||
for (auto i : loaded_entries)
|
||||
{
|
||||
this->push_item(i.second.k, i.second.d);
|
||||
}
|
||||
m_is_loading_from_db = false;
|
||||
LOG_PRINT_L0("Median cache build OK");
|
||||
return true;
|
||||
}
|
||||
virtual void handle_add_front_item(const key& k, const associated_data& ad)
|
||||
{
|
||||
if (m_is_loading_from_db)
|
||||
return;
|
||||
db_entry_type det = AUTO_VAL_INIT(det);
|
||||
det.k = k;
|
||||
det.d = ad;
|
||||
m_median_container.set(++m_counter_hi, det);
|
||||
|
||||
//in case if it was totally empty at init(which is very doubtful)
|
||||
if (m_counter_lo == std::numeric_limits<uint64_t>::max())
|
||||
m_counter_lo = m_counter_hi;
|
||||
|
||||
}
|
||||
virtual void handle_remove_front_item(const key& k)
|
||||
{
|
||||
LOC_INT_ERR(!m_is_loading_from_db, "m_is_loading_from_db is true");
|
||||
LOC_INT_ERR(m_median_container.erase_validate(m_counter_hi), "erase_validate failed");
|
||||
--m_counter_hi;
|
||||
//TODO: check coretests and make a decision on what to do with the following check
|
||||
//LOC_INT_ERR(m_counter_lo <= m_counter_hi, "handle_remove_front_item: m_counter_lo(" << m_counter_lo << ") > m_counter_hi(" << m_counter_hi << ")");
|
||||
}
|
||||
virtual void handle_purge_back_item()
|
||||
{
|
||||
LOC_INT_ERR(m_counter_lo < m_counter_hi, "handle_purge_back_item: m_counter_lo(" << m_counter_lo << ") >= m_counter_hi(" << m_counter_hi << ")");
|
||||
m_median_container.erase(m_counter_lo++);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
median_db_cache(db::basic_db_accessor& db) :
|
||||
m_median_container(db),
|
||||
m_counter_hi(0),
|
||||
m_counter_lo(std::numeric_limits<uint64_t>::max()),
|
||||
m_is_loading_from_db(false)
|
||||
{
|
||||
|
||||
}
|
||||
bool init(const std::string& name)
|
||||
{
|
||||
bool r = m_median_container.init(name);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to init m_median_container");
|
||||
return load_items_from_db();
|
||||
}
|
||||
|
||||
~median_db_cache()
|
||||
{
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
super_t::clear();
|
||||
m_median_container.clear();
|
||||
m_counter_hi = 0;
|
||||
m_counter_lo = std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
friend std::ostream& operator<<(std::ostream& ss, const median_db_cache<key_t, associated_data_t> &mdbc);
|
||||
}; // class median_db_cache
|
||||
#undef LOC_INT_ERR
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
inline std::ostream& operator<<(std::ostream& s, const median_db_cache<key_t, associated_data_t> &mdbc)
|
||||
{
|
||||
s << "median_db_cache<" << typeid(key_t).name() << ", " << typeid(associated_data_t).name() << "> instance 0x" << &mdbc << ENDL
|
||||
<< " m_counter_lo: " << mdbc.m_counter_lo << ENDL
|
||||
<< " m_counter_hi: " << mdbc.m_counter_hi << ENDL
|
||||
<< " m_is_loading_from_db: " << mdbc.m_is_loading_from_db << ENDL
|
||||
<< " m_median_container.size: " << mdbc.m_median_container.size() << ENDL
|
||||
<< " m_median_container.size_no_cache(): " << mdbc.m_median_container.size_no_cache() << ENDL
|
||||
<< "parent " << static_cast<epee::misc_utils::median_helper<key_t, associated_data_t>>(mdbc);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
159
src/common/miniupnp_helper.h
Normal file
159
src/common/miniupnp_helper.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Boolberry developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <boost/thread.hpp>
|
||||
#include "include_base_utils.h"
|
||||
extern "C" {
|
||||
#include "miniupnpc/miniupnpc.h"
|
||||
#include "miniupnpc/upnpcommands.h"
|
||||
#include "miniupnpc/upnperrors.h"
|
||||
}
|
||||
|
||||
#include "misc_language.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
class miniupnp_helper
|
||||
{
|
||||
UPNPDev *m_devlist;
|
||||
UPNPUrls m_urls;
|
||||
IGDdatas m_data;
|
||||
char m_lanaddr[64];
|
||||
int m_IGD;
|
||||
boost::thread m_mapper_thread;
|
||||
uint32_t m_external_port;
|
||||
public:
|
||||
miniupnp_helper():m_devlist(nullptr),
|
||||
m_urls(AUTO_VAL_INIT(m_urls)),
|
||||
m_data(AUTO_VAL_INIT(m_data)),
|
||||
m_IGD(0)
|
||||
{
|
||||
m_lanaddr[0] = 0;
|
||||
}
|
||||
~miniupnp_helper()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
bool start_regular_mapping(uint32_t internal_port, uint32_t external_port, uint32_t period_ms)
|
||||
{
|
||||
m_external_port = external_port;
|
||||
if(!init())
|
||||
return false;
|
||||
m_mapper_thread = boost::thread([=](){run_port_mapping_loop(internal_port, external_port, period_ms);});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stop_mapping()
|
||||
{
|
||||
if(m_mapper_thread.joinable())
|
||||
{
|
||||
m_mapper_thread.interrupt();
|
||||
m_mapper_thread.join();
|
||||
}
|
||||
|
||||
if(m_IGD == 1)
|
||||
{
|
||||
do_port_unmapping();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool init()
|
||||
{
|
||||
deinit();
|
||||
|
||||
int error = 0;
|
||||
m_devlist = upnpDiscover(2000, nullptr, nullptr, 0, 0, &error);
|
||||
if(error)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to call upnpDiscover");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_IGD = UPNP_GetValidIGD(m_devlist, &m_urls, &m_data, m_lanaddr, sizeof(m_lanaddr));
|
||||
if(m_IGD != 1)
|
||||
{
|
||||
LOG_PRINT_L2("IGD not found");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool deinit()
|
||||
{
|
||||
stop_mapping();
|
||||
|
||||
if(m_devlist)
|
||||
{
|
||||
freeUPNPDevlist(m_devlist);
|
||||
m_devlist = nullptr;
|
||||
}
|
||||
|
||||
if(m_IGD > 0)
|
||||
{
|
||||
FreeUPNPUrls(&m_urls);
|
||||
m_IGD = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_port_mapping_loop(uint32_t internal_port, uint32_t external_port, uint32_t period_ms)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
do_port_mapping(external_port, internal_port);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds( period_ms ));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_port_mapping(uint32_t external_port, uint32_t internal_port)
|
||||
{
|
||||
std::string internal_port_str = std::to_string(internal_port);
|
||||
std::string external_port_str = std::to_string(external_port);
|
||||
std::string str_desc = CURRENCY_NAME " v" PROJECT_VERSION_LONG;
|
||||
|
||||
int r = UPNP_AddPortMapping(m_urls.controlURL, m_data.first.servicetype,
|
||||
external_port_str.c_str(), internal_port_str.c_str(), m_lanaddr, str_desc.c_str(), "TCP", nullptr, "0");
|
||||
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LOG_PRINT_L1("AddPortMapping with external_port_str= " << external_port_str <<
|
||||
", internal_port_str=" << internal_port_str <<
|
||||
", failed with code=" << r << "(" << strupnperror(r) << ")");
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("[upnp] port mapped successful (ext: " << external_port_str << ", int:" << internal_port_str << ")");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void do_port_unmapping()
|
||||
{
|
||||
std::string external_port_str = std::to_string(m_external_port);
|
||||
|
||||
int r = UPNP_DeletePortMapping(m_urls.controlURL, m_data.first.servicetype, external_port_str.c_str(), "TCP", nullptr);
|
||||
if(r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LOG_PRINT_L1("DeletePortMapping with external_port_str= " << external_port_str <<
|
||||
", failed with code=" << r << "(" << strupnperror(r) << ")");
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("[upnp] port unmapped successful (ext: " << external_port_str << ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
3390
src/common/mnemonic-encoding.cpp
Normal file
3390
src/common/mnemonic-encoding.cpp
Normal file
File diff suppressed because it is too large
Load diff
48
src/common/mnemonic-encoding.h
Normal file
48
src/common/mnemonic-encoding.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2014, The Monero Project
|
||||
//
|
||||
// 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 copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER 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.
|
||||
|
||||
/*
|
||||
* This file and its cpp file are for translating Electrum-style word lists
|
||||
* into their equivalent byte representations for cross-compatibility with
|
||||
* that method of "backing up" one's wallet keys.
|
||||
*/
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
namespace mnemonic_encoding
|
||||
{
|
||||
std::vector<unsigned char> text2binary(const std::string& text);
|
||||
std::string binary2text(const std::vector<unsigned char>& binary);
|
||||
std::string word_by_num(uint32_t n);
|
||||
uint64_t num_by_word(const std::string& w);
|
||||
}
|
||||
}
|
||||
9
src/common/pod-class.h
Normal file
9
src/common/pod-class.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
// in C++ no difference 'class' vs 'struct' except the default members access.
|
||||
// maybe be better to erase the 'POD_CLASS' macro completely?
|
||||
#define POD_CLASS struct
|
||||
119
src/common/unordered_containers_boost_serialization.h
Normal file
119
src/common/unordered_containers_boost_serialization.h
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/split_free.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void save(Archive &a, const std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v.first;
|
||||
a << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void load(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
h_key k;
|
||||
hval v;
|
||||
a >> k;
|
||||
a >> v;
|
||||
x.insert(std::pair<h_key, hval>(k, v));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void save(Archive &a, const std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v.first;
|
||||
a << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void load(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
h_key k;
|
||||
hval v;
|
||||
a >> k;
|
||||
a >> v;
|
||||
x.emplace(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void save(Archive &a, const std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
size_t s = x.size();
|
||||
a << s;
|
||||
BOOST_FOREACH(auto& v, x)
|
||||
{
|
||||
a << v;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void load(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.clear();
|
||||
size_t s = 0;
|
||||
a >> s;
|
||||
for(size_t i = 0; i != s; i++)
|
||||
{
|
||||
hval v;
|
||||
a >> v;
|
||||
x.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_map<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class h_key, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_multimap<h_key, hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
|
||||
template <class Archive, class hval>
|
||||
inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
split_free(a, x, ver);
|
||||
}
|
||||
}
|
||||
}
|
||||
591
src/common/util.cpp
Normal file
591
src/common/util.cpp
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "zlib_helper.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "util.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <strsafe.h>
|
||||
#include <lm.h>
|
||||
#pragma comment(lib, "netapi32.lib")
|
||||
#else
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::function<void(void)> signal_handler::m_handler;
|
||||
std::function<void(int, void*)> signal_handler::m_fatal_handler;
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
bool GetWinMajorMinorVersion(DWORD& major, DWORD& minor)
|
||||
{
|
||||
bool bRetCode = false;
|
||||
LPBYTE pinfoRawData = 0;
|
||||
if (NERR_Success == NetWkstaGetInfo(NULL, 100, &pinfoRawData))
|
||||
{
|
||||
WKSTA_INFO_100* pworkstationInfo = (WKSTA_INFO_100*)pinfoRawData;
|
||||
major = pworkstationInfo->wki100_ver_major;
|
||||
minor = pworkstationInfo->wki100_ver_minor;
|
||||
::NetApiBufferFree(pinfoRawData);
|
||||
bRetCode = true;
|
||||
}
|
||||
return bRetCode;
|
||||
}
|
||||
|
||||
|
||||
std::string get_windows_version_display_string()
|
||||
{
|
||||
std::string winver;
|
||||
OSVERSIONINFOEX osver;
|
||||
SYSTEM_INFO sysInfo;
|
||||
typedef void(__stdcall *GETSYSTEMINFO) (LPSYSTEM_INFO);
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4996)
|
||||
memset(&osver, 0, sizeof(osver));
|
||||
osver.dwOSVersionInfoSize = sizeof(osver);
|
||||
GetVersionEx((LPOSVERSIONINFO)&osver);
|
||||
#pragma warning (pop)
|
||||
DWORD major = 0;
|
||||
DWORD minor = 0;
|
||||
if (GetWinMajorMinorVersion(major, minor))
|
||||
{
|
||||
osver.dwMajorVersion = major;
|
||||
osver.dwMinorVersion = minor;
|
||||
}
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi;
|
||||
ULONGLONG cm = 0;
|
||||
cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL);
|
||||
ZeroMemory(&osvi, sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
osvi.dwMinorVersion = 3;
|
||||
if (VerifyVersionInfoW(&osvi, VER_MINORVERSION, cm))
|
||||
{
|
||||
osver.dwMinorVersion = 3;
|
||||
}
|
||||
}
|
||||
|
||||
GETSYSTEMINFO getSysInfo = (GETSYSTEMINFO)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
|
||||
if (getSysInfo == NULL) getSysInfo = ::GetSystemInfo;
|
||||
getSysInfo(&sysInfo);
|
||||
|
||||
if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows 10 Server";
|
||||
else if (osver.dwMajorVersion == 10 && osver.dwMinorVersion >= 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 10";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012 R2";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8.1";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2012";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 8";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008 R2";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows 7";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType != VER_NT_WORKSTATION) winver = "Windows Server 2008";
|
||||
else if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0 && osver.wProductType == VER_NT_WORKSTATION) winver = "Windows Vista";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2 && osver.wProductType == VER_NT_WORKSTATION
|
||||
&& sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
winver = "Windows XP x64";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 2) winver = "Windows Server 2003";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1) winver = "Windows XP";
|
||||
else if (osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) winver = "Windows 2000";
|
||||
else winver = "unknown";
|
||||
|
||||
if (osver.wServicePackMajor != 0)
|
||||
{
|
||||
std::string sp;
|
||||
char buf[128] = { 0 };
|
||||
sp = " Service Pack ";
|
||||
sprintf_s(buf, sizeof(buf), "%hd", osver.wServicePackMajor);
|
||||
sp.append(buf);
|
||||
winver += sp;
|
||||
}
|
||||
|
||||
if (osver.dwMajorVersion >= 6)
|
||||
{
|
||||
if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
|
||||
winver += ", 64-bit";
|
||||
else if (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
|
||||
winver += ", 32-bit";
|
||||
}
|
||||
|
||||
|
||||
winver += "("
|
||||
+ std::to_string(osver.dwMajorVersion) + ":"
|
||||
+ std::to_string(osver.dwMinorVersion) + ":"
|
||||
+ std::to_string(osver.dwBuildNumber) + ":"
|
||||
+ std::to_string(osver.dwPlatformId) + ":"
|
||||
+ std::to_string(osver.wServicePackMajor) + ":"
|
||||
+ std::to_string(osver.wServicePackMinor) + ":"
|
||||
+ std::to_string(osver.wSuiteMask) + ":"
|
||||
+ std::to_string(osver.wProductType) + ")";
|
||||
|
||||
return winver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::string get_windows_version_display_string_()
|
||||
{
|
||||
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
|
||||
typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
|
||||
#define BUFSIZE 10000
|
||||
|
||||
char pszOS[BUFSIZE] = {0};
|
||||
OSVERSIONINFOEX osvi;
|
||||
SYSTEM_INFO si;
|
||||
PGNSI pGNSI;
|
||||
PGPI pGPI;
|
||||
BOOL bOsVersionInfoEx;
|
||||
DWORD dwType;
|
||||
|
||||
ZeroMemory(&si, sizeof(SYSTEM_INFO));
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
||||
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
|
||||
|
||||
if(!bOsVersionInfoEx) return pszOS;
|
||||
|
||||
// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
|
||||
|
||||
pGNSI = (PGNSI) GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetNativeSystemInfo");
|
||||
if(NULL != pGNSI)
|
||||
pGNSI(&si);
|
||||
else GetSystemInfo(&si);
|
||||
|
||||
if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId &&
|
||||
osvi.dwMajorVersion > 4 )
|
||||
{
|
||||
StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
|
||||
|
||||
// Test for the specific product.
|
||||
|
||||
if ( osvi.dwMajorVersion == 6 )
|
||||
{
|
||||
if( osvi.dwMinorVersion == 0 )
|
||||
{
|
||||
if( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 " ));
|
||||
}
|
||||
|
||||
if ( osvi.dwMinorVersion == 1 )
|
||||
{
|
||||
if( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 "));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
|
||||
}
|
||||
|
||||
pGPI = (PGPI) GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"GetProductInfo");
|
||||
|
||||
pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
|
||||
|
||||
switch( dwType )
|
||||
{
|
||||
case PRODUCT_ULTIMATE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
|
||||
break;
|
||||
case PRODUCT_PROFESSIONAL:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Professional" ));
|
||||
break;
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
|
||||
break;
|
||||
case PRODUCT_BUSINESS:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
|
||||
break;
|
||||
case PRODUCT_STARTER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
|
||||
break;
|
||||
case PRODUCT_CLUSTER_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
|
||||
break;
|
||||
case PRODUCT_DATACENTER_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE_SERVER_IA64:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
|
||||
break;
|
||||
case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
|
||||
break;
|
||||
case PRODUCT_STANDARD_SERVER_CORE:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
|
||||
break;
|
||||
case PRODUCT_WEB_SERVER:
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
|
||||
{
|
||||
if( GetSystemMetrics(SM_SERVERR2) )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2, "));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003"));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_WH_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server"));
|
||||
else if( osvi.wProductType == VER_NT_WORKSTATION &&
|
||||
si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition"));
|
||||
}
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
|
||||
|
||||
// Test for the server type.
|
||||
if ( osvi.wProductType != VER_NT_WORKSTATION )
|
||||
{
|
||||
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
|
||||
}
|
||||
|
||||
else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
|
||||
else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP "));
|
||||
if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
|
||||
}
|
||||
|
||||
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 "));
|
||||
|
||||
if ( osvi.wProductType == VER_NT_WORKSTATION )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
|
||||
}
|
||||
else
|
||||
{
|
||||
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
|
||||
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
|
||||
else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
|
||||
}
|
||||
}
|
||||
|
||||
// Include service pack (if any) and build number.
|
||||
|
||||
if( strlen(osvi.szCSDVersion) > 0 )
|
||||
{
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
|
||||
StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
|
||||
}
|
||||
|
||||
TCHAR buf[80];
|
||||
|
||||
StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
|
||||
StringCchCat(pszOS, BUFSIZE, buf);
|
||||
|
||||
if ( osvi.dwMajorVersion >= 6 )
|
||||
{
|
||||
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
|
||||
else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
|
||||
StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
|
||||
}
|
||||
|
||||
return pszOS;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "This sample does not support this version of Windows.\n");
|
||||
return pszOS;
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::string get_nix_version_display_string()
|
||||
{
|
||||
utsname un;
|
||||
|
||||
if(uname(&un) < 0)
|
||||
return std::string("*nix: failed to get os version");
|
||||
return std::string() + un.sysname + " " + un.version + " " + un.release;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string get_os_version_string()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return get_windows_version_display_string();
|
||||
#else
|
||||
return get_nix_version_display_string();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
std::string get_special_folder_path(int nfolder, bool iscreate)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
char psz_path[MAX_PATH] = "";
|
||||
|
||||
if(SHGetSpecialFolderPathA(NULL, psz_path, nfolder, iscreate))
|
||||
{
|
||||
return psz_path;
|
||||
}
|
||||
|
||||
LOG_ERROR("SHGetSpecialFolderPathA() failed, could not obtain requested path.");
|
||||
return "";
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string get_default_data_dir()
|
||||
{
|
||||
//namespace fs = boost::filesystem;
|
||||
// Windows < Vista: C:\Documents and Settings\Username\Application Data\CURRENCY_NAME_SHORT
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
|
||||
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
|
||||
// Unix: ~/.CURRENCY_NAME_SHORT
|
||||
std::string config_folder;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
#ifdef _M_X64
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT;
|
||||
#else
|
||||
config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CURRENCY_NAME_SHORT + "-x86";
|
||||
#endif
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||
pathRet = "/";
|
||||
else
|
||||
pathRet = pszHome;
|
||||
#ifdef __APPLE__
|
||||
// Mac
|
||||
pathRet += "/Library/Application Support";
|
||||
config_folder = (pathRet + "/" + CURRENCY_NAME_SHORT);
|
||||
#else
|
||||
// Unix
|
||||
config_folder = (pathRet + "/." + CURRENCY_NAME_SHORT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return config_folder;
|
||||
}
|
||||
std::string get_host_computer_name()
|
||||
{
|
||||
char szname[1024] = "";
|
||||
gethostname(szname, sizeof(szname));
|
||||
szname[sizeof(szname)-1] = 0; //just to be sure
|
||||
return szname;
|
||||
}
|
||||
|
||||
|
||||
std::string get_default_user_dir()
|
||||
{
|
||||
//namespace fs = boost::filesystem;
|
||||
// Windows < Vista: C:\Documents and Settings\Username
|
||||
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CURRENCY_NAME_SHORT
|
||||
// Mac: ~/Library/Application Support/CURRENCY_NAME_SHORT
|
||||
// Unix: ~/.CURRENCY_NAME_SHORT
|
||||
std::string wallets_dir;
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
wallets_dir = get_special_folder_path(CSIDL_PERSONAL, true) + "/" + CURRENCY_NAME_BASE;
|
||||
#else
|
||||
std::string pathRet;
|
||||
char* pszHome = getenv("HOME");
|
||||
if (pszHome == NULL || strlen(pszHome) == 0)
|
||||
pathRet = "/";
|
||||
else
|
||||
pathRet = pszHome;
|
||||
|
||||
wallets_dir = (pathRet + "/" + CURRENCY_NAME_BASE);
|
||||
|
||||
#endif
|
||||
return wallets_dir;
|
||||
}
|
||||
|
||||
std::string get_current_username()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Windows
|
||||
const char* psz_username = getenv("USERNAME");
|
||||
#else
|
||||
const char* psz_username = getenv("USER");
|
||||
#endif
|
||||
if (psz_username == NULL || strlen(psz_username) == 0)
|
||||
psz_username = "unknown_user";
|
||||
|
||||
return std::string(psz_username);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool create_directories_if_necessary(const std::string& path)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
boost::system::error_code ec;
|
||||
fs::path fs_path(path);
|
||||
if (fs::is_directory(fs_path, ec))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool res = fs::create_directories(fs_path, ec);
|
||||
if (res)
|
||||
{
|
||||
LOG_PRINT_L2("Created directory: " << path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L2("Can't create directory: " << path << ", err: "<< ec.message());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name)
|
||||
{
|
||||
int code;
|
||||
#if defined(WIN32)
|
||||
// Maximizing chances for success
|
||||
DWORD attributes = ::GetFileAttributes(replaced_name.c_str());
|
||||
if (INVALID_FILE_ATTRIBUTES != attributes)
|
||||
{
|
||||
::SetFileAttributes(replaced_name.c_str(), attributes & (~FILE_ATTRIBUTE_READONLY));
|
||||
}
|
||||
|
||||
bool ok = 0 != ::MoveFileEx(replacement_name.c_str(), replaced_name.c_str(), MOVEFILE_REPLACE_EXISTING);
|
||||
code = ok ? 0 : static_cast<int>(::GetLastError());
|
||||
#else
|
||||
bool ok = 0 == std::rename(replacement_name.c_str(), replaced_name.c_str());
|
||||
code = ok ? 0 : errno;
|
||||
#endif
|
||||
return std::error_code(code, std::system_category());
|
||||
}
|
||||
|
||||
#define REQUEST_LOG_CHUNK_SIZE_MAX (10 * 1024 * 1024)
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error)
|
||||
{
|
||||
if (size > REQUEST_LOG_CHUNK_SIZE_MAX)
|
||||
{
|
||||
error = std::string("size is exceeding the limit = ") + epee::string_tools::num_to_string_fast(REQUEST_LOG_CHUNK_SIZE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
if (std::ifstream log{ log_filename, std::ifstream::ate | std::ifstream::binary })
|
||||
{
|
||||
uint64_t file_size = log.tellg();
|
||||
|
||||
if (offset >= file_size)
|
||||
{
|
||||
error = "offset is out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + size > file_size)
|
||||
{
|
||||
error = "offset + size if out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
log.seekg(offset);
|
||||
output.resize(size);
|
||||
log.read(&output.front(), size);
|
||||
uint64_t read_bytes = log.gcount();
|
||||
if (read_bytes != size)
|
||||
{
|
||||
error = std::string("read bytes: ") + epee::string_tools::num_to_string_fast(read_bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::pack(output))
|
||||
{
|
||||
error = "zlib pack failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
error = std::string("can't open ") + log_filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t get_log_file_size()
|
||||
{
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
std::ifstream in(log_filename, std::ifstream::ate | std::ifstream::binary);
|
||||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
}
|
||||
336
src/common/util.h
Normal file
336
src/common/util.h
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
|
||||
#include <mutex>
|
||||
#include <system_error>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "misc_language.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <dbghelp.h>
|
||||
#endif
|
||||
|
||||
namespace tools
|
||||
{
|
||||
std::string get_host_computer_name();
|
||||
std::string get_default_data_dir();
|
||||
std::string get_default_user_dir();
|
||||
std::string get_current_username();
|
||||
std::string get_os_version_string();
|
||||
bool create_directories_if_necessary(const std::string& path);
|
||||
std::error_code replace_file(const std::string& replacement_name, const std::string& replaced_name);
|
||||
|
||||
inline crypto::hash get_proof_of_trust_hash(const nodetool::proof_of_trust& pot)
|
||||
{
|
||||
std::string s;
|
||||
s.append(reinterpret_cast<const char*>(&pot.peer_id), sizeof(pot.peer_id));
|
||||
s.append(reinterpret_cast<const char*>(&pot.time), sizeof(pot.time));
|
||||
return crypto::cn_fast_hash(s.data(), s.size());
|
||||
}
|
||||
|
||||
inline
|
||||
crypto::public_key get_public_key_from_string(const std::string& str_key)
|
||||
{
|
||||
crypto::public_key k = AUTO_VAL_INIT(k);
|
||||
epee::string_tools::hex_to_pod(str_key, k);
|
||||
return k;
|
||||
}
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error);
|
||||
uint64_t get_log_file_size();
|
||||
|
||||
class signal_handler
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
static bool install(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
bool r = TRUE == ::SetConsoleCtrlHandler(&win_handler, TRUE);
|
||||
if (r)
|
||||
{
|
||||
m_handler = t;
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
signal(SIGINT, posix_handler);
|
||||
signal(SIGTERM, posix_handler);
|
||||
m_handler = t;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void install_fatal(T t)
|
||||
{
|
||||
#if defined(WIN32)
|
||||
// NOTE: Unfortunately, there's no way to handle heap corruption signals/exceptions. More info: https://connect.microsoft.com/VisualStudio/feedback/details/664497/cant-catch-0xc0000374-exception-status-heap-corruption
|
||||
::SetUnhandledExceptionFilter(win_unhandled_exception_handler);
|
||||
#else
|
||||
signal(SIGABRT, posix_fatal_handler);
|
||||
signal(SIGSEGV, posix_fatal_handler);
|
||||
signal(SIGILL, posix_fatal_handler);
|
||||
#endif
|
||||
|
||||
m_fatal_handler = t;
|
||||
}
|
||||
|
||||
static void uninstall_fatal()
|
||||
{
|
||||
#if defined(WIN32)
|
||||
::SetUnhandledExceptionFilter(NULL);
|
||||
#endif
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
signal(SIGILL, SIG_DFL);
|
||||
m_fatal_handler = &noop_fatal_handler;
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
static BOOL WINAPI win_handler(DWORD type)
|
||||
{
|
||||
if (CTRL_C_EVENT == type || CTRL_BREAK_EVENT == type)
|
||||
{
|
||||
handle_signal();
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED_L0("Got control signal " << type << ". Exiting without saving...");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
// This code borrowed from http://www.debuginfo.com/articles/effminidumps2.html
|
||||
/************************************************************************/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// This function determines whether we need data sections of the given module
|
||||
//
|
||||
|
||||
static bool IsDataSectionNeeded(const WCHAR* pModuleName)
|
||||
{
|
||||
// Check parameters
|
||||
if (pModuleName == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the module name
|
||||
|
||||
WCHAR szFileName[_MAX_FNAME] = L"";
|
||||
|
||||
_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);
|
||||
// Compare the name with the list of known names and decide
|
||||
// Note: For this to work, the executable name must be "mididump.exe"
|
||||
if (wcsicmp(szFileName, L"mididump") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (wcsicmp(szFileName, L"ntdll") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Complete
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Custom minidump callback
|
||||
//
|
||||
|
||||
static BOOL CALLBACK MyMiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput,
|
||||
PMINIDUMP_CALLBACK_OUTPUT pOutput)
|
||||
{
|
||||
BOOL bRet = FALSE;
|
||||
// Check parameters
|
||||
if (pInput == 0)
|
||||
return FALSE;
|
||||
|
||||
if (pOutput == 0)
|
||||
return FALSE;
|
||||
|
||||
// Process the callbacks
|
||||
switch (pInput->CallbackType)
|
||||
{
|
||||
case IncludeModuleCallback:
|
||||
{
|
||||
// Include the module into the dump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IncludeThreadCallback:
|
||||
{
|
||||
// Include the thread into the dump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ModuleCallback:
|
||||
{
|
||||
// Are data sections available for this module ?
|
||||
|
||||
if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
|
||||
{
|
||||
// Yes, they are, but do we need them?
|
||||
|
||||
if (!IsDataSectionNeeded(pInput->Module.FullPath))
|
||||
{
|
||||
wprintf(L"Excluding module data sections: %s \n", pInput->Module.FullPath);
|
||||
|
||||
pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
|
||||
}
|
||||
}
|
||||
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ThreadCallback:
|
||||
{
|
||||
// Include all thread information into the minidump
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case ThreadExCallback:
|
||||
{
|
||||
// Include this information
|
||||
bRet = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case MemoryCallback:
|
||||
{
|
||||
// We do not include any information here -> return FALSE
|
||||
bRet = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case CancelCallback:
|
||||
break;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
|
||||
}
|
||||
|
||||
static void GenerateCrashDump(EXCEPTION_POINTERS *pep = NULL)
|
||||
|
||||
{
|
||||
SYSTEMTIME sysTime = { 0 };
|
||||
GetSystemTime(&sysTime);
|
||||
// get the computer name
|
||||
char compName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||
DWORD compNameLen = ARRAYSIZE(compName);
|
||||
GetComputerNameA(compName, &compNameLen);
|
||||
// build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP
|
||||
char path[MAX_PATH*10] = { 0 };
|
||||
std::string folder = epee::log_space::log_singletone::get_default_log_folder();
|
||||
sprintf_s(path, ARRAYSIZE(path),"%s\\crashdump_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp",
|
||||
folder.c_str(), compName, sysTime.wYear, sysTime.wMonth, sysTime.wDay,
|
||||
sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
|
||||
|
||||
HANDLE hFile = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
// Create the minidump
|
||||
MINIDUMP_EXCEPTION_INFORMATION mdei;
|
||||
|
||||
mdei.ThreadId = GetCurrentThreadId();
|
||||
mdei.ExceptionPointers = pep;
|
||||
mdei.ClientPointers = FALSE;
|
||||
|
||||
MINIDUMP_CALLBACK_INFORMATION mci;
|
||||
|
||||
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
|
||||
mci.CallbackParam = 0;
|
||||
|
||||
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |
|
||||
MiniDumpWithDataSegs |
|
||||
MiniDumpWithHandleData |
|
||||
MiniDumpWithFullMemoryInfo |
|
||||
MiniDumpWithThreadInfo |
|
||||
MiniDumpWithUnloadedModules);
|
||||
|
||||
BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
|
||||
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
|
||||
|
||||
if (!rv)
|
||||
{
|
||||
LOG_ERROR("Minidump file create FAILED(error " << GetLastError() << ") on path: " << path);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Minidump file created on path: " << path);
|
||||
}
|
||||
// Close the file
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Minidump FAILED to create file (error " << GetLastError() << ") on path: " << path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static LONG WINAPI win_unhandled_exception_handler(_In_ struct _EXCEPTION_POINTERS *ep)
|
||||
{
|
||||
GenerateCrashDump(ep);
|
||||
handle_fatal_signal(ep->ExceptionRecord->ExceptionCode, ep->ExceptionRecord->ExceptionAddress);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
#else
|
||||
static void posix_handler(int /*type*/)
|
||||
{
|
||||
handle_signal();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void posix_fatal_handler(int sig_number)
|
||||
{
|
||||
handle_fatal_signal(sig_number, 0);
|
||||
}
|
||||
|
||||
static void noop_fatal_handler(int, void*) {}
|
||||
|
||||
static void handle_signal()
|
||||
{
|
||||
static std::mutex m_mutex;
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_handler();
|
||||
}
|
||||
|
||||
static void handle_fatal_signal(int sig_number, void* address)
|
||||
{
|
||||
static std::mutex m_mutex_fatal;
|
||||
std::unique_lock<std::mutex> lock(m_mutex_fatal);
|
||||
m_fatal_handler(sig_number, address);
|
||||
uninstall_fatal();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::function<void(void)> m_handler;
|
||||
static std::function<void(int, void*)> m_fatal_handler;
|
||||
};
|
||||
}
|
||||
86
src/common/varint.h
Normal file
86
src/common/varint.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace tools {
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
template<typename T>
|
||||
size_t get_varint_packed_size(T v)
|
||||
{
|
||||
if(v <= 127)
|
||||
return 1;
|
||||
else if(v <= 16383)
|
||||
return 2;
|
||||
else if(v <= 2097151)
|
||||
return 3;
|
||||
else if(v <= 268435455)
|
||||
return 4;
|
||||
else if(v <= 34359738367)
|
||||
return 5;
|
||||
else if(v <= 4398046511103)
|
||||
return 6;
|
||||
else if(v <= 562949953421311)
|
||||
return 7;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
template<typename OutputIt, typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, void>::type
|
||||
write_varint(OutputIt &&dest, T i) {
|
||||
while (i >= 0x80) {
|
||||
*dest++ = (static_cast<char>(i) & 0x7f) | 0x80;
|
||||
i >>= 7;
|
||||
}
|
||||
*dest++ = static_cast<char>(i);
|
||||
}
|
||||
|
||||
template<typename t_type>
|
||||
std::string get_varint_data(const t_type& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
write_varint(std::ostreambuf_iterator<char>(ss), v);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<int bits, typename InputIt, typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value && 0 <= bits && bits <= std::numeric_limits<T>::digits, int>::type
|
||||
read_varint(InputIt &&first, InputIt &&last, T &i) {
|
||||
int read = 0;
|
||||
i = 0;
|
||||
for (int shift = 0;; shift += 7) {
|
||||
if (first == last) {
|
||||
return read; // End of input.
|
||||
}
|
||||
unsigned char byte = *first++;
|
||||
++read;
|
||||
if (shift + 7 >= bits && byte >= 1 << (bits - shift)) {
|
||||
return -1; // Overflow.
|
||||
}
|
||||
if (byte == 0 && shift != 0) {
|
||||
return -2; // Non-canonical representation.
|
||||
}
|
||||
i |= static_cast<T>(byte & 0x7f) << shift;
|
||||
if ((byte & 0x80) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
template<typename InputIt, typename T>
|
||||
int read_varint(InputIt &&first, InputIt &&last, T &i) {
|
||||
return read_varint<std::numeric_limits<T>::digits, InputIt, T>(std::move(first), std::move(last), i);
|
||||
}
|
||||
}
|
||||
36
src/contrib/eos_portable_archive/change_log.txt
Normal file
36
src/contrib/eos_portable_archive/change_log.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
IMPORTANT:
|
||||
|
||||
This is the last release from me as EOS employee. I plan to contribute all of this
|
||||
work to the official boost libraries distribution and will continue to support users.
|
||||
Francois Mauger joined me recently and already added a valuable tutorial for you!
|
||||
|
||||
Changelog:
|
||||
|
||||
26.06.2012 5.0 Ported to boost versions up to 1.49.
|
||||
Added support for wstring, added tutorial by Francois Mauger.
|
||||
|
||||
01.04.2011 4.2 Ported to boost versions up to 1.46.1.
|
||||
Allow serialization of inf and nan values.
|
||||
|
||||
17.12.2009 4.1 Ported to boost versions up to 1.41.
|
||||
|
||||
4.0 Changes in inheritance make arrays work.
|
||||
|
||||
13.02.2009 3.1 Shared pointer serialization capabilities added
|
||||
Ported to recent boost versions (up to 1.38)
|
||||
|
||||
25.09.2008 3.0 Refactored, fixed and ported to recent boost versions
|
||||
Archives are now named eos::portable_[io]archive
|
||||
|
||||
17.09.2008 2.1 Improved floating point handling and error detection.
|
||||
Extracted the exception class into an extra file.
|
||||
|
||||
28.04.2008 2.0 Major Bugfix resolving negative number collision!
|
||||
|
||||
28.11.2007 1.1 Small Bugfix in portable_binary_archive_exception class:
|
||||
throwing specifiers did not match base class declaration
|
||||
|
||||
12.11.2007 1.0 Initial Release to boost-users!
|
||||
|
||||
Christian Pfligersdorffer
|
||||
christian.pfligersdorffer@gmx.at
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*****************************************************************************/
|
||||
/**
|
||||
* \file polymorphic_portable_archive.hpp
|
||||
* \brief Needed for unit tests on portable archives.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
*
|
||||
* Header for testing portable archives with all of the serialization tests.
|
||||
* Before use copy all hpp files from this directory to your boost folder
|
||||
* boost_.../libs/serialization/test and run from there a visual studio
|
||||
* prompt with b2 oder bjam -sBOOST_ARCHIVE_LIST=portable_archive.hpp
|
||||
*
|
||||
* \note Since portable archives version 5.0 we depend on program_options!
|
||||
* Edit libs/serialization/test/Jamfile.v2 and change the requirements to
|
||||
* : requirements <source>/boost/filesystem <source>/boost/program_options
|
||||
*/
|
||||
/****************************************************************************/
|
||||
|
||||
#pragma warning( disable:4217 4127 4310 4244 4800 4267 )
|
||||
|
||||
// text_archive test header
|
||||
// include output archive header
|
||||
#include "portable_oarchive.hpp"
|
||||
// set name of test output archive
|
||||
typedef eos::polymorphic_portable_oarchive test_oarchive;
|
||||
// set name of test output stream
|
||||
typedef std::ofstream test_ostream;
|
||||
|
||||
// repeat the above for input archive
|
||||
#include "portable_iarchive.hpp"
|
||||
typedef eos::polymorphic_portable_iarchive test_iarchive;
|
||||
typedef std::ifstream test_istream;
|
||||
|
||||
// define open mode for streams
|
||||
// binary archives should use std::ios_base::binary
|
||||
#define TEST_STREAM_FLAGS std::ios_base::binary
|
||||
36
src/contrib/eos_portable_archive/eos/portable_archive.hpp
Normal file
36
src/contrib/eos_portable_archive/eos/portable_archive.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*****************************************************************************/
|
||||
/**
|
||||
* \file portable_archive.hpp
|
||||
* \brief Needed for unit tests on portable archives.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
*
|
||||
* Header for testing portable archives with all of the serialization tests.
|
||||
* Before use copy all hpp files from this directory to your boost folder
|
||||
* boost_.../libs/serialization/test and run from there a visual studio
|
||||
* prompt with b2 oder bjam -sBOOST_ARCHIVE_LIST=portable_archive.hpp
|
||||
*
|
||||
* \note Since portable archives version 5.0 we depend on program_options!
|
||||
* Edit libs/serialization/test/Jamfile.v2 and change the requirements to
|
||||
* : requirements <source>/boost/filesystem <source>/boost/program_options
|
||||
*/
|
||||
/****************************************************************************/
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning( disable:4217 4127 4310 4244 4800 4267 )
|
||||
#endif
|
||||
|
||||
// text_archive test header
|
||||
// include output archive header
|
||||
#include "portable_oarchive.hpp"
|
||||
// set name of test output archive
|
||||
typedef eos::portable_oarchive test_oarchive;
|
||||
// set name of test output stream
|
||||
typedef std::ofstream test_ostream;
|
||||
|
||||
// repeat the above for input archive
|
||||
#include "portable_iarchive.hpp"
|
||||
typedef eos::portable_iarchive test_iarchive;
|
||||
typedef std::ifstream test_istream;
|
||||
|
||||
// define open mode for streams
|
||||
// binary archives should use std::ios_base::binary
|
||||
#define TEST_STREAM_FLAGS std::ios_base::binary
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*****************************************************************************/
|
||||
/**
|
||||
* \file portable_archive_exception.hpp
|
||||
* \brief Provides error handling and constants.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
*
|
||||
* Portable archive exceptions derive from the boost archive exceptions
|
||||
* and add failure causes specific to the portable binary usecase.
|
||||
*
|
||||
* Additionally this header serves as common include for important
|
||||
* constants or typedefs.
|
||||
*/
|
||||
/****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/archive/basic_archive.hpp>
|
||||
#include <boost/archive/archive_exception.hpp>
|
||||
|
||||
namespace eos {
|
||||
|
||||
// this value is written to the top of the stream
|
||||
const signed char magic_byte = 'e' | 'o' | 's';
|
||||
|
||||
// flag for fp serialization
|
||||
const unsigned no_infnan = 64;
|
||||
|
||||
// integral type for the archive version
|
||||
#if BOOST_VERSION < 104400
|
||||
typedef boost::archive::version_type archive_version_type;
|
||||
#else
|
||||
typedef boost::archive::library_version_type archive_version_type;
|
||||
#endif
|
||||
|
||||
// version of the linked boost archive library
|
||||
const archive_version_type archive_version(
|
||||
#if BOOST_VERSION < 103700
|
||||
boost::archive::ARCHIVE_VERSION()
|
||||
#else
|
||||
boost::archive::BOOST_ARCHIVE_VERSION()
|
||||
#endif
|
||||
);
|
||||
|
||||
/**
|
||||
* \brief Exception being thrown when serialization cannot proceed.
|
||||
*
|
||||
* There are several situations in which the portable archives may fail and
|
||||
* hence throw an exception:
|
||||
* -# deserialization of an integer value that exceeds the range of the type
|
||||
* -# (de)serialization of inf/nan through an archive with no_infnan flag set
|
||||
* -# deserialization of a denormalized value without the floating point type
|
||||
* supporting denormalized numbers
|
||||
*
|
||||
* Note that this exception will also be thrown if you mixed up your stream
|
||||
* position and accidentially interpret some value for size data (in this case
|
||||
* the reported size will be totally amiss most of the time).
|
||||
*/
|
||||
class portable_archive_exception : public boost::archive::archive_exception
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
public:
|
||||
//! type size is not large enough for deserialized number
|
||||
portable_archive_exception(signed char invalid_size)
|
||||
: boost::archive::archive_exception(other_exception)
|
||||
, msg("requested integer size exceeds type size: ")
|
||||
{
|
||||
msg += boost::lexical_cast<std::string, int>(invalid_size);
|
||||
}
|
||||
|
||||
//! negative number in unsigned type
|
||||
portable_archive_exception()
|
||||
: boost::archive::archive_exception(other_exception)
|
||||
, msg("cannot read a negative number into an unsigned type")
|
||||
{
|
||||
}
|
||||
|
||||
//! serialization of inf, nan and denormals
|
||||
template <typename T>
|
||||
portable_archive_exception(const T& abnormal)
|
||||
: boost::archive::archive_exception(other_exception)
|
||||
, msg("serialization of illegal floating point value: ")
|
||||
{
|
||||
msg += boost::lexical_cast<std::string>(abnormal);
|
||||
}
|
||||
|
||||
//! override the base class function with our message
|
||||
const char* what() const throw() { return msg.c_str(); }
|
||||
~portable_archive_exception() throw() {}
|
||||
};
|
||||
|
||||
} // namespace eos
|
||||
489
src/contrib/eos_portable_archive/eos/portable_iarchive.hpp
Normal file
489
src/contrib/eos_portable_archive/eos/portable_iarchive.hpp
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
/*****************************************************************************/
|
||||
/**
|
||||
* \file portable_iarchive.hpp
|
||||
* \brief Provides an archive to read from portable binary files.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
* \version 5.1
|
||||
*
|
||||
* This pair of archives brings the advantages of binary streams to the cross
|
||||
* platform boost::serialization user. While being almost as fast as the native
|
||||
* binary archive it allows its files to be exchanged between cpu architectures
|
||||
* using different byte order (endianness). Speaking of speed: in serializing
|
||||
* numbers the (portable) binary approach is approximately ten times faster than
|
||||
* the ascii implementation (that is inherently portable)!
|
||||
*
|
||||
* Based on the portable archive example by Robert Ramey this implementation
|
||||
* uses Beman Dawes endian library and fp_utilities from Johan Rade, both being
|
||||
* in boost since 1.36. Prior to that you need to add them both (header only)
|
||||
* to your boost directory before you're able to use the archives provided.
|
||||
* Our archives have been tested successfully for boost versions 1.33 to 1.49!
|
||||
*
|
||||
* \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32
|
||||
* and x86-64 platforms featuring different byte order. So there is a good
|
||||
* chance it will instantly work for your specific setup. If you encounter
|
||||
* problems or have suggestions please contact the author.
|
||||
*
|
||||
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
|
||||
* ecotax for pointing to the issue with shared_ptr_helper.
|
||||
*
|
||||
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
|
||||
* serialization of std::wstring by converting it to/from utf8 (thanks to
|
||||
* Arash Abghari for this suggestion). With that all unit tests from the
|
||||
* serialization library pass again with the notable exception of user
|
||||
* defined primitive types. Those are not supported and as a result any
|
||||
* user defined type to be used with the portable archives are required
|
||||
* to be at least object_serializable.
|
||||
*
|
||||
* \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds
|
||||
* serialization of special floating point values inf and NaN as proposed
|
||||
* by Francois Mauger.
|
||||
*
|
||||
* \note Version 4.1 makes the archives work together with boost 1.40 and 1.41.
|
||||
* Thanks to Francois Mauger for his suggestions.
|
||||
*
|
||||
* \note Version 4 removes one level of the inheritance hierarchy and directly
|
||||
* builds upon binary primitive and basic binary archive, thereby fixing
|
||||
* the last open issue regarding array serialization. Thanks to Robert
|
||||
* Ramey for the hint.
|
||||
*
|
||||
* \note A few fixes introduced in version 3.1 let the archives pass all of the
|
||||
* serialization tests. Thanks to Sergey Morozov for running the tests.
|
||||
* Wouter Bijlsma pointed out where to find the fp_utilities and endian
|
||||
* libraries headers inside the boost distribution. I would never have
|
||||
* found them so thank him it works out of the box since boost 1.36.
|
||||
*
|
||||
* \note With Version 3.0 the archives have been made portable across different
|
||||
* boost versions. For that purpose a header is added to the data that
|
||||
* supplies the underlying serialization library version. Backwards
|
||||
* compatibility is maintained by assuming library version boost 1.33 if
|
||||
* the iarchive is created using the no_header flag. Whether a header is
|
||||
* present or not can be guessed by peeking into the stream: the header's
|
||||
* first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-)
|
||||
*
|
||||
* \note Version 2.1 removes several compiler warnings and enhances floating
|
||||
* point diagnostics to inform the user if some preconditions are violated
|
||||
* on his platform. We do not strive for the universally portable solution
|
||||
* in binary floating point serialization as desired by some boost users.
|
||||
* Instead we support only the most widely used IEEE 754 format and try to
|
||||
* detect when requirements are not met and hence our approach must fail.
|
||||
* Contributions we made by Johan Rade and Ákos Maróy.
|
||||
*
|
||||
* \note Version 2.0 fixes a serious bug that effectively transformed most
|
||||
* of negative integral values into positive values! For example the two
|
||||
* numbers -12 and 234 were stored in the same 8-bit pattern and later
|
||||
* always restored to 234. This was fixed in this version in a way that
|
||||
* does not change the interpretation of existing archives that did work
|
||||
* because there were no negative numbers. The other way round archives
|
||||
* created by version 2.0 and containing negative numbers will raise an
|
||||
* integer type size exception when reading it with version 1.0. Thanks
|
||||
* to Markus Frohnmaier for testing the archives and finding the bug.
|
||||
*
|
||||
* \copyright The boost software license applies.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
|
||||
// basic headers
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/archive/basic_binary_iprimitive.hpp>
|
||||
#include <boost/archive/basic_binary_iarchive.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
#include <boost/archive/shared_ptr_helper.hpp>
|
||||
#endif
|
||||
|
||||
// funny polymorphics
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <boost/archive/detail/polymorphic_iarchive_impl.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_impl<T>
|
||||
|
||||
#elif BOOST_VERSION < 103600
|
||||
#include <boost/archive/detail/polymorphic_iarchive_dispatch.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_dispatch<T>
|
||||
|
||||
#else
|
||||
#include <boost/archive/detail/polymorphic_iarchive_route.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_iarchive_route<T>
|
||||
#endif
|
||||
|
||||
// endian and fpclassify
|
||||
#if BOOST_VERSION < 103600
|
||||
#include <boost/integer/endian.hpp>
|
||||
#include <boost/math/fpclassify.hpp>
|
||||
#elif BOOST_VERSION < 104800
|
||||
#include <boost/spirit/home/support/detail/integer/endian.hpp>
|
||||
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
|
||||
#elif BOOST_VERSION < 106900
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#else
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#endif
|
||||
|
||||
// namespace alias
|
||||
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
|
||||
namespace fp = boost::math;
|
||||
#else
|
||||
namespace fp = boost::spirit::math;
|
||||
#endif
|
||||
|
||||
// namespace alias endian
|
||||
#if BOOST_VERSION < 104800
|
||||
namespace endian = boost::detail;
|
||||
#else
|
||||
namespace endian = boost::spirit::detail;
|
||||
#endif
|
||||
|
||||
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
|
||||
// used for wstring to utf8 conversion
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#endif
|
||||
|
||||
// generic type traits for numeric types
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_unsigned.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
|
||||
#include "portable_archive_exception.hpp"
|
||||
|
||||
// hint from Johan Rade: on VMS there is still support for
|
||||
// the VAX floating point format and this macro detects it
|
||||
#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
|
||||
#error "VAX floating point format is not supported!"
|
||||
#endif
|
||||
|
||||
namespace eos {
|
||||
|
||||
// forward declaration
|
||||
class portable_iarchive;
|
||||
|
||||
typedef boost::archive::basic_binary_iprimitive<
|
||||
portable_iarchive
|
||||
#if BOOST_VERSION < 103400
|
||||
, std::istream
|
||||
#else
|
||||
, std::istream::char_type
|
||||
, std::istream::traits_type
|
||||
#endif
|
||||
> portable_iprimitive;
|
||||
|
||||
/**
|
||||
* \brief Portable binary input archive using little endian format.
|
||||
*
|
||||
* This archive addresses integer size, endianness and floating point types so
|
||||
* that data can be transferred across different systems. There may still be
|
||||
* constraints as to what systems are compatible and the user will have to take
|
||||
* care that e.g. a very large int being saved on a 64 bit machine will result
|
||||
* in a portable_archive_exception if loaded into an int on a 32 bit system.
|
||||
* A possible workaround to this would be to use fixed types like
|
||||
* boost::uint64_t in your serialization structures.
|
||||
*
|
||||
* \note The class is based on the portable binary example by Robert Ramey and
|
||||
* uses Beman Dawes endian library plus fp_utilities by Johan Rade.
|
||||
*/
|
||||
class portable_iarchive : public portable_iprimitive
|
||||
|
||||
// the example derives from common_oarchive but that lacks the
|
||||
// load_override functions so we chose to stay one level higher
|
||||
, public boost::archive::basic_binary_iarchive<portable_iarchive>
|
||||
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
// mix-in helper class for serializing shared_ptr
|
||||
, public boost::archive::detail::shared_ptr_helper
|
||||
#endif
|
||||
{
|
||||
// only needed for Robert's hack in basic_binary_iarchive::init
|
||||
friend class boost::archive::basic_binary_iarchive<portable_iarchive>;
|
||||
|
||||
// workaround for gcc: use a dummy struct
|
||||
// as additional argument type for overloading
|
||||
template <int> struct dummy { dummy(int) {}};
|
||||
|
||||
// loads directly from stream
|
||||
inline signed char load_signed_char()
|
||||
{
|
||||
signed char c;
|
||||
portable_iprimitive::load(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
// archive initialization
|
||||
void init(unsigned flags)
|
||||
{
|
||||
using namespace boost::archive;
|
||||
archive_version_type input_library_version(3);
|
||||
|
||||
// it is vital to have version information!
|
||||
// if we don't have any we assume boost 1.33
|
||||
if (flags & no_header)
|
||||
set_library_version(input_library_version);
|
||||
|
||||
// extract and check the magic eos byte
|
||||
else if (load_signed_char() != magic_byte)
|
||||
throw archive_exception(archive_exception::invalid_signature);
|
||||
|
||||
else
|
||||
{
|
||||
// extract version information
|
||||
operator>>(input_library_version);
|
||||
|
||||
// throw if file version is newer than we are
|
||||
if (input_library_version > archive_version)
|
||||
throw archive_exception(archive_exception::unsupported_version);
|
||||
|
||||
// else set the library version accordingly
|
||||
else set_library_version(input_library_version);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor on a stream using ios::binary mode!
|
||||
*
|
||||
* We cannot call basic_binary_iprimitive::init which tries to detect
|
||||
* if the binary archive stems from a different platform by examining
|
||||
* type sizes.
|
||||
*
|
||||
* We could have called basic_binary_iarchive::init which would create
|
||||
* the boost::serialization standard archive header containing also the
|
||||
* library version. Due to efficiency we stick with our own.
|
||||
*/
|
||||
portable_iarchive(std::istream& is, unsigned flags = 0)
|
||||
#if BOOST_VERSION < 103400
|
||||
: portable_iprimitive(is, flags & boost::archive::no_codecvt)
|
||||
#else
|
||||
: portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt)
|
||||
#endif
|
||||
, boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
|
||||
#if BOOST_VERSION >= 103400
|
||||
portable_iarchive(std::streambuf& sb, unsigned flags = 0)
|
||||
: portable_iprimitive(sb, flags & boost::archive::no_codecvt)
|
||||
, boost::archive::basic_binary_iarchive<portable_iarchive>(flags)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Load narrow strings.
|
||||
void load(std::string& s)
|
||||
{
|
||||
portable_iprimitive::load(s);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
/**
|
||||
* \brief Load wide strings.
|
||||
*
|
||||
* This is rather tricky to get right for true portability as there
|
||||
* are so many different character encodings around. However, wide
|
||||
* strings that are encoded in one of the Unicode schemes only need
|
||||
* to be _transcoded_ which is a lot easier actually.
|
||||
*
|
||||
* We generate the output string to be encoded in the system's native
|
||||
* format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't
|
||||
* know about Mac here so I can't really say about that.
|
||||
*/
|
||||
void load(std::wstring& s)
|
||||
{
|
||||
std::string utf8;
|
||||
load(utf8);
|
||||
s = boost::from_utf8(utf8);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Loading bool type.
|
||||
*
|
||||
* Byte pattern is same as with integer types, so this function
|
||||
* is somewhat redundant but treating bool as integer generates
|
||||
* a lot of compiler warnings.
|
||||
*
|
||||
* \note If you cannot compile your application and it says something
|
||||
* about load(bool) cannot convert your type A& into bool& then you
|
||||
* should check your BOOST_CLASS_IMPLEMENTATION setting for A, as
|
||||
* portable_archive is not able to handle custom primitive types in
|
||||
* a general manner.
|
||||
*/
|
||||
void load(bool& b)
|
||||
{
|
||||
switch (signed char c = load_signed_char())
|
||||
{
|
||||
case 0: b = false; break;
|
||||
case 1: b = load_signed_char(); break;
|
||||
default: throw portable_archive_exception(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load integer types.
|
||||
*
|
||||
* First we load the size information ie. the number of bytes that
|
||||
* hold the actual data. Then we retrieve the data and transform it
|
||||
* to the original value by using load_little_endian.
|
||||
*/
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_integral<T> >::type
|
||||
load(T & t, dummy<2> = 0)
|
||||
{
|
||||
// get the number of bytes in the stream
|
||||
if (signed char size = load_signed_char())
|
||||
{
|
||||
// check for negative value in unsigned type
|
||||
if (size < 0 && boost::is_unsigned<T>::value)
|
||||
throw portable_archive_exception();
|
||||
|
||||
// check that our type T is large enough
|
||||
else if ((unsigned) abs(size) > sizeof(T))
|
||||
throw portable_archive_exception(size);
|
||||
|
||||
// reconstruct the value
|
||||
T temp = size < 0 ? -1 : 0;
|
||||
load_binary(&temp, abs(size));
|
||||
|
||||
// load the value from little endian - it is then converted
|
||||
// to the target type T and fits it because size <= sizeof(T)
|
||||
t = endian::load_little_endian<T, sizeof(T)>(&temp);
|
||||
}
|
||||
|
||||
else t = 0; // zero optimization
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load floating point types.
|
||||
*
|
||||
* We simply rely on fp_traits to set the bit pattern from the (unsigned)
|
||||
* integral type that was stored in the stream. Francois Mauger provided
|
||||
* standardized behaviour for special values like inf and NaN, that need to
|
||||
* be serialized in his application.
|
||||
*
|
||||
* \note by Johan Rade (author of the floating point utilities library):
|
||||
* Be warned that the math::detail::fp_traits<T>::type::get_bits() function
|
||||
* is *not* guaranteed to give you all bits of the floating point number. It
|
||||
* will give you all bits if and only if there is an integer type that has
|
||||
* the same size as the floating point you are copying from. It will not
|
||||
* give you all bits for double if there is no uint64_t. It will not give
|
||||
* you all bits for long double if sizeof(long double) > 8 or there is no
|
||||
* uint64_t.
|
||||
*
|
||||
* The member fp_traits<T>::type::coverage will tell you whether all bits
|
||||
* are copied. This is a typedef for either math::detail::all_bits or
|
||||
* math::detail::not_all_bits.
|
||||
*
|
||||
* If the function does not copy all bits, then it will copy the most
|
||||
* significant bits. So if you serialize and deserialize the way you
|
||||
* describe, and fp_traits<T>::type::coverage is math::detail::not_all_bits,
|
||||
* then your floating point numbers will be truncated. This will introduce
|
||||
* small rounding off errors.
|
||||
*/
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_floating_point<T> >::type
|
||||
load(T & t, dummy<3> = 0)
|
||||
{
|
||||
typedef typename fp::detail::fp_traits<T>::type traits;
|
||||
|
||||
// if you end here there are three possibilities:
|
||||
// 1. you're serializing a long double which is not portable
|
||||
// 2. you're serializing a double but have no 64 bit integer
|
||||
// 3. your machine is using an unknown floating point format
|
||||
// after reading the note above you still might decide to
|
||||
// deactivate this static assert and try if it works out.
|
||||
typename traits::bits bits;
|
||||
BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
|
||||
|
||||
load(bits);
|
||||
traits::set_bits(t, bits);
|
||||
|
||||
// if the no_infnan flag is set we must throw here
|
||||
if (get_flags() & no_infnan && !fp::isfinite(t))
|
||||
throw portable_archive_exception(t);
|
||||
|
||||
// if you end here your floating point type does not support
|
||||
// denormalized numbers. this might be the case even though
|
||||
// your type conforms to IEC 559 (and thus to IEEE 754)
|
||||
if (std::numeric_limits<T>::has_denorm == std::denorm_absent
|
||||
&& fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4
|
||||
throw portable_archive_exception(t);
|
||||
}
|
||||
|
||||
// in boost 1.44 version_type was splitted into library_version_type and
|
||||
// item_version_type, plus a whole bunch of additional strong typedefs.
|
||||
template <typename T>
|
||||
typename boost::disable_if<boost::is_arithmetic<T> >::type
|
||||
load(T& t, dummy<4> = 0)
|
||||
{
|
||||
// we provide a generic load routine for all types that feature
|
||||
// conversion operators into an unsigned integer value like those
|
||||
// created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
|
||||
// library_version_type, collection_size_type, item_version_type,
|
||||
// class_id_type, object_id_type, version_type and tracking_type
|
||||
load((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least&)(t));
|
||||
}
|
||||
};
|
||||
|
||||
// polymorphic portable binary iarchive typedef
|
||||
typedef POLYMORPHIC(portable_iarchive) polymorphic_portable_iarchive;
|
||||
#undef POLYMORPHIC
|
||||
|
||||
} // namespace eos
|
||||
|
||||
// this is required by export which registers all of your
|
||||
// classes with all the inbuilt archives plus our archive.
|
||||
#if BOOST_VERSION < 103500
|
||||
#define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive
|
||||
#else
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive)
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::polymorphic_portable_iarchive)
|
||||
#endif
|
||||
|
||||
// if you include this header multiple times and your compiler is picky
|
||||
// about multiple template instantiations (eg. gcc is) then you need to
|
||||
// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
|
||||
// or you move the instantiation section into an implementation file
|
||||
#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
|
||||
|
||||
#include <boost/archive/impl/basic_binary_iarchive.ipp>
|
||||
#include <boost/archive/impl/basic_binary_iprimitive.ipp>
|
||||
|
||||
#if BOOST_VERSION < 104000
|
||||
#include <boost/archive/impl/archive_pointer_iserializer.ipp>
|
||||
#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
|
||||
#include <boost/archive/impl/archive_serializer_map.ipp>
|
||||
#define BOOST_ARCHIVE_SERIALIZER_INCLUDED
|
||||
#endif
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
// explicitly instantiate for this type of binary stream
|
||||
template class basic_binary_iarchive<eos::portable_iarchive>;
|
||||
|
||||
template class basic_binary_iprimitive<
|
||||
eos::portable_iarchive
|
||||
#if BOOST_VERSION < 103400
|
||||
, std::istream
|
||||
#else
|
||||
, std::istream::char_type
|
||||
, std::istream::traits_type
|
||||
#endif
|
||||
>;
|
||||
|
||||
#if BOOST_VERSION < 104000
|
||||
template class detail::archive_pointer_iserializer<eos::portable_iarchive>;
|
||||
#else
|
||||
template class detail::archive_serializer_map<eos::portable_iarchive>;
|
||||
//template class detail::archive_serializer_map<eos::polymorphic_portable_iarchive>;
|
||||
#endif
|
||||
|
||||
} } // namespace boost::archive
|
||||
|
||||
#endif
|
||||
471
src/contrib/eos_portable_archive/eos/portable_oarchive.hpp
Normal file
471
src/contrib/eos_portable_archive/eos/portable_oarchive.hpp
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/*****************************************************************************/
|
||||
/**
|
||||
* \file portable_oarchive.hpp
|
||||
* \brief Provides an archive to create portable binary files.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
* \version 5.1
|
||||
*
|
||||
* This pair of archives brings the advantages of binary streams to the cross
|
||||
* platform boost::serialization user. While being almost as fast as the native
|
||||
* binary archive it allows its files to be exchanged between cpu architectures
|
||||
* using different byte order (endianness). Speaking of speed: in serializing
|
||||
* numbers the (portable) binary approach is approximately ten times faster than
|
||||
* the ascii implementation (that is inherently portable)!
|
||||
*
|
||||
* Based on the portable archive example by Robert Ramey this implementation
|
||||
* uses Beman Dawes endian library and fp_utilities from Johan Rade, both being
|
||||
* in boost since 1.36. Prior to that you need to add them both (header only)
|
||||
* to your boost directory before you're able to use the archives provided.
|
||||
* Our archives have been tested successfully for boost versions 1.33 to 1.49!
|
||||
*
|
||||
* \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32
|
||||
* and x86-64 platforms featuring different byte order. So there is a good
|
||||
* chance it will instantly work for your specific setup. If you encounter
|
||||
* problems or have suggestions please contact the author.
|
||||
*
|
||||
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
|
||||
* ecotax for pointing to the issue with shared_ptr_helper.
|
||||
*
|
||||
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
|
||||
* serialization of std::wstring by converting it to/from utf8 (thanks to
|
||||
* Arash Abghari for this suggestion). With that all unit tests from the
|
||||
* serialization library pass again with the notable exception of user
|
||||
* defined primitive types. Those are not supported and as a result any
|
||||
* user defined type to be used with the portable archives are required
|
||||
* to be at least object_serializable.
|
||||
*
|
||||
* \note Oliver Putz pointed out that -0.0 was not serialized correctly, so
|
||||
* version 4.3 provides a fix for that. Thanks Ollie!
|
||||
*
|
||||
* \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds
|
||||
* serialization of special floating point values inf and NaN as proposed
|
||||
* by Francois Mauger.
|
||||
*
|
||||
* \note Version 4.1 makes the archives work together with boost 1.40 and 1.41.
|
||||
* Thanks to Francois Mauger for his suggestions.
|
||||
*
|
||||
* \note Version 4 removes one level of the inheritance hierarchy and directly
|
||||
* builds upon binary primitive and basic binary archive, thereby fixing
|
||||
* the last open issue regarding array serialization. Thanks to Robert
|
||||
* Ramey for the hint.
|
||||
*
|
||||
* \note A few fixes introduced in version 3.1 let the archives pass all of the
|
||||
* serialization tests. Thanks to Sergey Morozov for running the tests.
|
||||
* Wouter Bijlsma pointed out where to find the fp_utilities and endian
|
||||
* libraries headers inside the boost distribution. I would never have
|
||||
* found them so thank him it works out of the box since boost 1.36.
|
||||
*
|
||||
* \note With Version 3.0 the archives have been made portable across different
|
||||
* boost versions. For that purpose a header is added to the data that
|
||||
* supplies the underlying serialization library version. Backwards
|
||||
* compatibility is maintained by assuming library version boost 1.33 if
|
||||
* the iarchive is created using the no_header flag. Whether a header is
|
||||
* present or not can be guessed by peeking into the stream: the header's
|
||||
* first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-)
|
||||
*
|
||||
* \note Version 2.1 removes several compiler warnings and enhances floating
|
||||
* point diagnostics to inform the user if some preconditions are violated
|
||||
* on his platform. We do not strive for the universally portable solution
|
||||
* in binary floating point serialization as desired by some boost users.
|
||||
* Instead we support only the most widely used IEEE 754 format and try to
|
||||
* detect when requirements are not met and hence our approach must fail.
|
||||
* Contributions we made by Johan Rade and Ákos Maróy.
|
||||
*
|
||||
* \note Version 2.0 fixes a serious bug that effectively transformed most
|
||||
* of negative integral values into positive values! For example the two
|
||||
* numbers -12 and 234 were stored in the same 8-bit pattern and later
|
||||
* always restored to 234. This was fixed in this version in a way that
|
||||
* does not change the interpretation of existing archives that did work
|
||||
* because there were no negative numbers. The other way round archives
|
||||
* created by version 2.0 and containing negative numbers will raise an
|
||||
* integer type size exception when reading it with version 1.0. Thanks
|
||||
* to Markus Frohnmaier for testing the archives and finding the bug.
|
||||
*
|
||||
* \copyright The boost software license applies.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
|
||||
// basic headers
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/archive/basic_binary_oprimitive.hpp>
|
||||
#include <boost/archive/basic_binary_oarchive.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
#include <boost/archive/shared_ptr_helper.hpp>
|
||||
#endif
|
||||
|
||||
// funny polymorphics
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <boost/archive/detail/polymorphic_oarchive_impl.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_impl<T>
|
||||
|
||||
#elif BOOST_VERSION < 103600
|
||||
#include <boost/archive/detail/polymorphic_oarchive_dispatch.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_dispatch<T>
|
||||
|
||||
#else
|
||||
#include <boost/archive/detail/polymorphic_oarchive_route.hpp>
|
||||
#define POLYMORPHIC(T) boost::archive::detail::polymorphic_oarchive_route<T>
|
||||
#endif
|
||||
|
||||
// endian and fpclassify
|
||||
#if BOOST_VERSION < 103600
|
||||
#include <boost/integer/endian.hpp>
|
||||
#include <boost/math/fpclassify.hpp>
|
||||
#elif BOOST_VERSION < 104800
|
||||
#include <boost/spirit/home/support/detail/integer/endian.hpp>
|
||||
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
|
||||
#elif BOOST_VERSION < 106900
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#else
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#endif
|
||||
|
||||
// namespace alias fp_classify
|
||||
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
|
||||
namespace fp = boost::math;
|
||||
#else
|
||||
namespace fp = boost::spirit::math;
|
||||
#endif
|
||||
|
||||
// namespace alias endian
|
||||
#if BOOST_VERSION < 104800
|
||||
namespace endian = boost::detail;
|
||||
#else
|
||||
namespace endian = boost::spirit::detail;
|
||||
#endif
|
||||
|
||||
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
|
||||
// used for wstring to utf8 conversion
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#endif
|
||||
|
||||
// generic type traits for numeric types
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/is_signed.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
|
||||
#include "portable_archive_exception.hpp"
|
||||
|
||||
// hint from Johan Rade: on VMS there is still support for
|
||||
// the VAX floating point format and this macro detects it
|
||||
#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
|
||||
#error "VAX floating point format is not supported!"
|
||||
#endif
|
||||
|
||||
namespace eos {
|
||||
|
||||
// forward declaration
|
||||
class portable_oarchive;
|
||||
|
||||
typedef boost::archive::basic_binary_oprimitive<
|
||||
portable_oarchive
|
||||
#if BOOST_VERSION < 103400
|
||||
, std::ostream
|
||||
#else
|
||||
, std::ostream::char_type
|
||||
, std::ostream::traits_type
|
||||
#endif
|
||||
> portable_oprimitive;
|
||||
|
||||
/**
|
||||
* \brief Portable binary output archive using little endian format.
|
||||
*
|
||||
* This archive addresses integer size, endianness and floating point types so
|
||||
* that data can be transferred across different systems. The archive consists
|
||||
* primarily of three different save implementations for integral types,
|
||||
* floating point types and string types. Those functions are templates and use
|
||||
* enable_if to be correctly selected for overloading.
|
||||
*
|
||||
* \note The class is based on the portable binary example by Robert Ramey and
|
||||
* uses Beman Dawes endian library plus fp_utilities by Johan Rade.
|
||||
*/
|
||||
class portable_oarchive : public portable_oprimitive
|
||||
|
||||
// the example derives from common_oarchive but that lacks the
|
||||
// save_override functions so we chose to stay one level higher
|
||||
, public boost::archive::basic_binary_oarchive<portable_oarchive>
|
||||
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
// mix-in helper class for serializing shared_ptr
|
||||
, public boost::archive::detail::shared_ptr_helper
|
||||
#endif
|
||||
{
|
||||
// workaround for gcc: use a dummy struct
|
||||
// as additional argument type for overloading
|
||||
template<int> struct dummy { dummy(int) {}};
|
||||
|
||||
// stores a signed char directly to stream
|
||||
inline void save_signed_char(const signed char& c)
|
||||
{
|
||||
portable_oprimitive::save(c);
|
||||
}
|
||||
|
||||
// archive initialization
|
||||
void init(unsigned flags)
|
||||
{
|
||||
// it is vital to have version information if the archive is
|
||||
// to be parsed with a newer version of boost::serialization
|
||||
// therefor we create a header, no header means boost 1.33
|
||||
if (flags & boost::archive::no_header)
|
||||
BOOST_ASSERT(archive_version == 3);
|
||||
else
|
||||
{
|
||||
// write our minimalistic header (magic byte plus version)
|
||||
// the boost archives write a string instead - by calling
|
||||
// boost::archive::basic_binary_oarchive<derived_t>::init()
|
||||
save_signed_char(magic_byte);
|
||||
|
||||
// write current version
|
||||
// save<unsigned>(archive_version);
|
||||
operator<<(archive_version);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor on a stream using ios::binary mode!
|
||||
*
|
||||
* We cannot call basic_binary_oprimitive::init which stores type
|
||||
* sizes to the archive in order to detect transfers to non-compatible
|
||||
* platforms.
|
||||
*
|
||||
* We could have called basic_binary_oarchive::init which would create
|
||||
* the boost::serialization standard archive header containing also the
|
||||
* library version. Due to efficiency we stick with our own.
|
||||
*/
|
||||
portable_oarchive(std::ostream& os, unsigned flags = 0)
|
||||
#if BOOST_VERSION < 103400
|
||||
: portable_oprimitive(os, flags & boost::archive::no_codecvt)
|
||||
#else
|
||||
: portable_oprimitive(*os.rdbuf(), flags & boost::archive::no_codecvt)
|
||||
#endif
|
||||
, boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
|
||||
#if BOOST_VERSION >= 103400
|
||||
portable_oarchive(std::streambuf& sb, unsigned flags = 0)
|
||||
: portable_oprimitive(sb, flags & boost::archive::no_codecvt)
|
||||
, boost::archive::basic_binary_oarchive<portable_oarchive>(flags)
|
||||
{
|
||||
init(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
//! Save narrow strings.
|
||||
void save(const std::string& s)
|
||||
{
|
||||
portable_oprimitive::save(s);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
/**
|
||||
* \brief Save wide strings.
|
||||
*
|
||||
* This is rather tricky to get right for true portability as there
|
||||
* are so many different character encodings around. However, wide
|
||||
* strings that are encoded in one of the Unicode schemes only need
|
||||
* to be _transcoded_ which is a lot easier actually.
|
||||
*
|
||||
* We expect the input string to be encoded in the system's native
|
||||
* format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't
|
||||
* know about Mac here so I can't really say about that.
|
||||
*/
|
||||
void save(const std::wstring& s)
|
||||
{
|
||||
save(boost::to_utf8(s));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Saving bool type.
|
||||
*
|
||||
* Saving bool directly, not by const reference
|
||||
* because of tracking_type's operator (bool).
|
||||
*
|
||||
* \note If you cannot compile your application and it says something
|
||||
* about save(bool) cannot convert your type const A& into bool then
|
||||
* you should check your BOOST_CLASS_IMPLEMENTATION setting for A, as
|
||||
* portable_archive is not able to handle custom primitive types in
|
||||
* a general manner.
|
||||
*/
|
||||
void save(const bool& b)
|
||||
{
|
||||
save_signed_char(b);
|
||||
if (b) save_signed_char('T');
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Save integer types.
|
||||
*
|
||||
* First we save the size information ie. the number of bytes that hold the
|
||||
* actual data. We subsequently transform the data using store_little_endian
|
||||
* and store non-zero bytes to the stream.
|
||||
*/
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_integral<T> >::type
|
||||
save(const T & t, dummy<2> = 0)
|
||||
{
|
||||
if (T temp = t)
|
||||
{
|
||||
// examine the number of bytes
|
||||
// needed to represent the number
|
||||
signed char size = 0;
|
||||
do { temp >>= CHAR_BIT; ++size; }
|
||||
while (temp != 0 && temp != (T) -1);
|
||||
|
||||
// encode the sign bit into the size
|
||||
save_signed_char(t > 0 ? size : -size);
|
||||
BOOST_ASSERT(t > 0 || boost::is_signed<T>::value);
|
||||
|
||||
// we choose to use little endian because this way we just
|
||||
// save the first size bytes to the stream and skip the rest
|
||||
endian::store_little_endian<T, sizeof(T)>(&temp, t);
|
||||
save_binary(&temp, size);
|
||||
}
|
||||
// zero optimization
|
||||
else save_signed_char(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Save floating point types.
|
||||
*
|
||||
* We simply rely on fp_traits to extract the bit pattern into an (unsigned)
|
||||
* integral type and store that into the stream. Francois Mauger provided
|
||||
* standardized behaviour for special values like inf and NaN, that need to
|
||||
* be serialized in his application.
|
||||
*
|
||||
* \note by Johan Rade (author of the floating point utilities library):
|
||||
* Be warned that the math::detail::fp_traits<T>::type::get_bits() function
|
||||
* is *not* guaranteed to give you all bits of the floating point number. It
|
||||
* will give you all bits if and only if there is an integer type that has
|
||||
* the same size as the floating point you are copying from. It will not
|
||||
* give you all bits for double if there is no uint64_t. It will not give
|
||||
* you all bits for long double if sizeof(long double) > 8 or there is no
|
||||
* uint64_t.
|
||||
*
|
||||
* The member fp_traits<T>::type::coverage will tell you whether all bits
|
||||
* are copied. This is a typedef for either math::detail::all_bits or
|
||||
* math::detail::not_all_bits.
|
||||
*
|
||||
* If the function does not copy all bits, then it will copy the most
|
||||
* significant bits. So if you serialize and deserialize the way you
|
||||
* describe, and fp_traits<T>::type::coverage is math::detail::not_all_bits,
|
||||
* then your floating point numbers will be truncated. This will introduce
|
||||
* small rounding off errors.
|
||||
*/
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_floating_point<T> >::type
|
||||
save(const T & t, dummy<3> = 0)
|
||||
{
|
||||
typedef typename fp::detail::fp_traits<T>::type traits;
|
||||
|
||||
// if the no_infnan flag is set we must throw here
|
||||
if (get_flags() & no_infnan && !fp::isfinite(t))
|
||||
throw portable_archive_exception(t);
|
||||
|
||||
// if you end here there are three possibilities:
|
||||
// 1. you're serializing a long double which is not portable
|
||||
// 2. you're serializing a double but have no 64 bit integer
|
||||
// 3. your machine is using an unknown floating point format
|
||||
// after reading the note above you still might decide to
|
||||
// deactivate this static assert and try if it works out.
|
||||
typename traits::bits bits;
|
||||
BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T));
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_iec559);
|
||||
|
||||
// examine value closely
|
||||
switch (fp::fpclassify(t))
|
||||
{
|
||||
//case FP_ZERO: bits = 0; break;
|
||||
case FP_NAN: bits = traits::exponent | traits::mantissa; break;
|
||||
case FP_INFINITE: bits = traits::exponent | (t<0) * traits::sign; break;
|
||||
case FP_SUBNORMAL: assert(std::numeric_limits<T>::has_denorm); // pass
|
||||
case FP_ZERO: // note that floats can be ±0.0
|
||||
case FP_NORMAL: traits::get_bits(t, bits); break;
|
||||
default: throw portable_archive_exception(t);
|
||||
}
|
||||
|
||||
save(bits);
|
||||
}
|
||||
|
||||
// in boost 1.44 version_type was splitted into library_version_type and
|
||||
// item_version_type, plus a whole bunch of additional strong typedefs.
|
||||
template <typename T>
|
||||
typename boost::disable_if<boost::is_arithmetic<T> >::type
|
||||
save(const T& t, dummy<4> = 0)
|
||||
{
|
||||
// we provide a generic save routine for all types that feature
|
||||
// conversion operators into an unsigned integer value like those
|
||||
// created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like
|
||||
// library_version_type, collection_size_type, item_version_type,
|
||||
// class_id_type, object_id_type, version_type and tracking_type
|
||||
save((typename boost::uint_t<sizeof(T)*CHAR_BIT>::least)(t));
|
||||
}
|
||||
};
|
||||
|
||||
// polymorphic portable binary oarchive typedef
|
||||
typedef POLYMORPHIC(portable_oarchive) polymorphic_portable_oarchive;
|
||||
#undef POLYMORPHIC
|
||||
|
||||
} // namespace eos
|
||||
|
||||
// required by export
|
||||
#if BOOST_VERSION < 103500
|
||||
#define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive
|
||||
#else
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive)
|
||||
BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::polymorphic_portable_oarchive)
|
||||
#endif
|
||||
|
||||
// if you include this header multiple times and your compiler is picky
|
||||
// about multiple template instantiations (eg. gcc is) then you need to
|
||||
// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one
|
||||
// or you move the instantiation section into an implementation file
|
||||
#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION
|
||||
|
||||
#include <boost/archive/impl/basic_binary_oarchive.ipp>
|
||||
#include <boost/archive/impl/basic_binary_oprimitive.ipp>
|
||||
|
||||
#if BOOST_VERSION < 104000
|
||||
#include <boost/archive/impl/archive_pointer_oserializer.ipp>
|
||||
#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED
|
||||
#include <boost/archive/impl/archive_serializer_map.ipp>
|
||||
#define BOOST_ARCHIVE_SERIALIZER_INCLUDED
|
||||
#endif
|
||||
|
||||
namespace boost { namespace archive {
|
||||
|
||||
// explicitly instantiate for this type of binary stream
|
||||
template class basic_binary_oarchive<eos::portable_oarchive>;
|
||||
|
||||
template class basic_binary_oprimitive<
|
||||
eos::portable_oarchive
|
||||
#if BOOST_VERSION < 103400
|
||||
, std::ostream
|
||||
#else
|
||||
, std::ostream::char_type
|
||||
, std::ostream::traits_type
|
||||
#endif
|
||||
>;
|
||||
|
||||
#if BOOST_VERSION < 104000
|
||||
template class detail::archive_pointer_oserializer<eos::portable_oarchive>;
|
||||
#else
|
||||
template class detail::archive_serializer_map<eos::portable_oarchive>;
|
||||
//template class detail::archive_serializer_map<eos::polymorphic_portable_oarchive>;
|
||||
#endif
|
||||
|
||||
} } // namespace boost::archive
|
||||
|
||||
#endif
|
||||
36
src/contrib/eos_portable_archive/release_notes.txt
Normal file
36
src/contrib/eos_portable_archive/release_notes.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
IMPORTANT:
|
||||
|
||||
This is the last release from me as EOS employee. I plan to contribute all of this
|
||||
work to the official boost libraries distribution and will continue to support users.
|
||||
Francois Mauger joined me recently and already added a valuable tutorial for you!
|
||||
|
||||
|
||||
Dear user,
|
||||
|
||||
I am proud to announce the very first release of our portable_binary_[io]archive
|
||||
which we use here at EOS to move data between different platforms. It really is
|
||||
a conglomerate of pieces that already were there - as is most often the case in
|
||||
OO world - we simply put them together in a way that seemed to make sense. I know
|
||||
a lot of people were interested in portable binary archives, so here you are -
|
||||
give it a try and let me know what you think about it!
|
||||
|
||||
We rely heavily on boost::serialization and really appreciate the amount of time
|
||||
and knowledge that went into it. By publishing this small missing piece we hope
|
||||
to contribute our mite to this great library.
|
||||
|
||||
The work extends the portable binary example which was done by Robert Ramey and
|
||||
uses Beman Dawes' endian library plus the fp_utilities by Johan Rade. You will
|
||||
need to get those two libraries in order to use our classes - look for them at
|
||||
the boost vault (http://www.boost-consulting.com/vault/) in categories 'integer'
|
||||
and 'math - numerics'. Finally you will find the portable binary archive in
|
||||
category 'serialization' as well.
|
||||
|
||||
Regards,
|
||||
Christian Pfligersdorffer
|
||||
|
||||
Munich, End of 2007
|
||||
|
||||
--
|
||||
christian.pfligersdorffer@eos.info
|
||||
christian.pfligersdorffer@gmx.at
|
||||
http://www.eos.info
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/** tutorial_pba_0.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This quick start example shows how to store some variables
|
||||
* of basic types (bool, integer, floating point numbers, STL string)
|
||||
* using the portable binary archive format associated to a
|
||||
* standard output file stream.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
// The name for the example data file :
|
||||
std::string filename = "pba_0.data";
|
||||
|
||||
// Some variables of various primitive types :
|
||||
bool b = true;
|
||||
char c = 'B';
|
||||
uint32_t answer = 42;
|
||||
float computing_time = 7.5e6;
|
||||
double e = 2.71828182845905;
|
||||
std::string slogan = "DON'T PANIC";
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
std::ofstream fout (filename.c_str (), std::ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file :
|
||||
boost::archive::portable_binary_oarchive opba (fout);
|
||||
|
||||
// Store (serializing) variables :
|
||||
opba & b & c & answer & computing_time & e & slogan;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_0.cpp
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/** tutorial_pba_1.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization package.
|
||||
*
|
||||
* This quick start example shows how to load some variables
|
||||
* of basic types (bool, integer, floating point numbers, STL string)
|
||||
* using the portable binary archive format associated to a
|
||||
* standard input file stream.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// The name for the example data file :
|
||||
string filename = "pba_0.data";
|
||||
|
||||
// Some variables of various types :
|
||||
bool b;
|
||||
char c;
|
||||
uint32_t answer;
|
||||
float computing_time;
|
||||
double e;
|
||||
string slogan;
|
||||
|
||||
// Open an input file stream in binary mode :
|
||||
ifstream fin (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an input portable binary archive attached to the input file :
|
||||
boost::archive::portable_binary_iarchive ipba (fin);
|
||||
|
||||
// Loading (de-serializing) variables using the same
|
||||
// order than for serialization (see tutorial_pba_0.cpp) :
|
||||
ipba & b & c & answer & computing_time & e & slogan;
|
||||
}
|
||||
|
||||
cout.precision (15);
|
||||
cout << "Variable 'b' is : " << b << " " << "(bool)" << endl;
|
||||
cout << "Variable 'c' is : '" << c << "' " << " " << "(char)" << endl;
|
||||
cout << "Variable 'answer' is : " << answer << " " << "(unsigned 32-bit integer)" << endl;
|
||||
cout << "Variable 'computing_time' is : " << computing_time << " " << "(single precision 32-bit float)" << endl;
|
||||
cout << "Variable 'e' is : " << e << " " << "(double precision 64-bit float)" << endl;
|
||||
cout << "Variable 'slogan' is : \"" << slogan << "\" " << "(std::string)" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_1.cpp
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/** tutorial_pba_10.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example shows how use PBAs combined with on-the-fly
|
||||
* compressed I/O streams.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class data_type
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version);
|
||||
public:
|
||||
void print (ostream & out, const string & title) const;
|
||||
public:
|
||||
vector<double> values;
|
||||
data_type ();
|
||||
};
|
||||
|
||||
data_type::data_type () : values ()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void data_type::print (ostream & out, const string & title) const
|
||||
{
|
||||
out << endl;
|
||||
out << title << " :" << endl;
|
||||
for (int i = 0; i < this->values.size (); ++i)
|
||||
{
|
||||
out.precision (16);
|
||||
out.width (18);
|
||||
out << this->values [i] << ' ' ;
|
||||
if ((i%4) == 3) clog << endl;
|
||||
}
|
||||
out << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void data_type::serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & values;
|
||||
return;
|
||||
}
|
||||
|
||||
void do_gzipped_out (void)
|
||||
{
|
||||
// The name for the output data file :
|
||||
string filename = "pba_10.data.gz";
|
||||
|
||||
// A data structure to be stored :
|
||||
data_type my_data;
|
||||
|
||||
// Fill the vector with arbitrary (possibly non-finite) values :
|
||||
size_t dim = 1000;
|
||||
my_data.values.reserve (dim);
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
double val = (i + 1) * (1.0 + 3 * numeric_limits<double>::epsilon ());
|
||||
if (i == 4) val = numeric_limits<double>::quiet_NaN ();
|
||||
if (i == 23) val = numeric_limits<double>::infinity ();
|
||||
if (i == 73) val = -numeric_limits<double>::infinity ();
|
||||
if (i == 90) val = 0.0;
|
||||
my_data.values.push_back (val);
|
||||
}
|
||||
|
||||
// Print:
|
||||
my_data.print (clog, "Stored data");
|
||||
|
||||
// Create an output filtering stream :
|
||||
boost::iostreams::filtering_ostream zout;
|
||||
zout.push (boost::iostreams::gzip_compressor ());
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
ofstream fout (filename.c_str (), ios_base::binary);
|
||||
zout.push (fout);
|
||||
|
||||
// Save to PBA :
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file :
|
||||
boost::archive::portable_binary_oarchive opba (zout);
|
||||
|
||||
// Store (serializing) the data :
|
||||
opba & my_data;
|
||||
}
|
||||
|
||||
// Clean termination of the streams :
|
||||
zout.flush ();
|
||||
zout.reset ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void do_gzipped_in (void)
|
||||
{
|
||||
// The name for the input data file :
|
||||
string filename = "pba_10.data.gz";
|
||||
|
||||
// A data structure to be loaded :
|
||||
data_type my_data;
|
||||
|
||||
// Create an input filtering stream :
|
||||
boost::iostreams::filtering_istream zin;
|
||||
zin.push (boost::iostreams::gzip_decompressor ());
|
||||
|
||||
// Open an input file stream in binary mode :
|
||||
ifstream fin (filename.c_str (), ios_base::binary);
|
||||
zin.push (fin);
|
||||
|
||||
// Load from PBA :
|
||||
{
|
||||
// Create an input portable binary archive attached to the input file :
|
||||
boost::archive::portable_binary_iarchive ipba (zin);
|
||||
|
||||
// Load (deserializing) the data :
|
||||
ipba & my_data;
|
||||
}
|
||||
|
||||
// Print:
|
||||
my_data.print (clog, "Loaded data");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
do_gzipped_out ();
|
||||
do_gzipped_in ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_10.cpp
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
/** tutorial_pba_10b.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example shows how use PBAs combined with on-the-fly
|
||||
* compressed I/O streams.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
#include <boost/archive/xml_oarchive.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/gzip.hpp>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class data_type
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version);
|
||||
public:
|
||||
void print (ostream & out, const string & title) const;
|
||||
public:
|
||||
vector<double> values;
|
||||
data_type ();
|
||||
};
|
||||
|
||||
//BOOST_CLASS_VERSION(data_type, 7)
|
||||
|
||||
data_type::data_type () : values ()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void data_type::print (ostream & out, const string & title) const
|
||||
{
|
||||
out << endl;
|
||||
out << title << " :" << endl;
|
||||
for (int i = 0; i < this->values.size (); ++i)
|
||||
{
|
||||
out.precision (16);
|
||||
out.width (18);
|
||||
out << this->values [i] << ' ' ;
|
||||
if ((i%4) == 3) clog << endl;
|
||||
}
|
||||
out << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void data_type::serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & BOOST_SERIALIZATION_NVP (values);
|
||||
return;
|
||||
}
|
||||
|
||||
class data_type2
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version);
|
||||
public:
|
||||
double value;
|
||||
data_type2 ();
|
||||
};
|
||||
|
||||
BOOST_CLASS_VERSION(data_type2, 99)
|
||||
|
||||
data_type2::data_type2 () : value (666.666)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void data_type2::serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & BOOST_SERIALIZATION_NVP (value);
|
||||
return;
|
||||
}
|
||||
|
||||
class data_type3
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version);
|
||||
public:
|
||||
vector<data_type2> values;
|
||||
data_type3 ();
|
||||
};
|
||||
|
||||
BOOST_CLASS_VERSION(data_type3, 33)
|
||||
|
||||
data_type3::data_type3 ()
|
||||
{
|
||||
{
|
||||
data_type2 d;
|
||||
d.value = 6.66;
|
||||
values.push_back (d);
|
||||
}
|
||||
{
|
||||
data_type2 d;
|
||||
d.value = 66.66;
|
||||
values.push_back (d);
|
||||
}
|
||||
{
|
||||
data_type2 d;
|
||||
d.value = 666.66;
|
||||
values.push_back (d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void data_type3::serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & BOOST_SERIALIZATION_NVP (values);
|
||||
return;
|
||||
}
|
||||
|
||||
/********************/
|
||||
|
||||
void do_xml_out (void)
|
||||
{
|
||||
// The name for the output data file :
|
||||
string filename = "pba_10.xml";
|
||||
|
||||
// A data structure to be stored :
|
||||
data_type my_data;
|
||||
|
||||
// Fill the vector with arbitrary (possibly non-finite) values :
|
||||
size_t dim = 6;
|
||||
my_data.values.reserve (dim);
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
double val = (i + 1) * (1.0 + 3 * numeric_limits<double>::epsilon ());
|
||||
if (i == 4) val = numeric_limits<double>::quiet_NaN ();
|
||||
if (i == 7) val = numeric_limits<double>::infinity ();
|
||||
if (i == 9) val = -numeric_limits<double>::infinity ();
|
||||
if (i == 13) val = 0.0;
|
||||
my_data.values.push_back (val);
|
||||
}
|
||||
|
||||
// Print:
|
||||
my_data.print (clog, "Stored data");
|
||||
|
||||
data_type2 my_data2;
|
||||
data_type3 my_data3;
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
ofstream fout (filename.c_str ());
|
||||
|
||||
// Save to PBA :
|
||||
{
|
||||
// Create an output XML archive attached to the output file :
|
||||
boost::archive::xml_oarchive oxa (fout);
|
||||
|
||||
// Store (serializing) the data :
|
||||
oxa & BOOST_SERIALIZATION_NVP(my_data);
|
||||
oxa & BOOST_SERIALIZATION_NVP(my_data2);
|
||||
oxa & BOOST_SERIALIZATION_NVP(my_data3);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
do_xml_out ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_10b.cpp
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
/** tutorial_pba_11.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example program compares the times needed to serialize
|
||||
* and deserialize some large amount of data using PBA and
|
||||
* text archives.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/uniform_real_distribution.hpp>
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class data_type
|
||||
{
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version);
|
||||
public:
|
||||
void print (ostream & out, const string & title) const;
|
||||
public:
|
||||
vector<double> values;
|
||||
data_type ();
|
||||
};
|
||||
|
||||
data_type::data_type () : values ()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void data_type::print (ostream & out, const string & title) const
|
||||
{
|
||||
out << endl;
|
||||
out << title << " :" << endl;
|
||||
bool skip = false;
|
||||
for (int i = 0; i < this->values.size (); ++i)
|
||||
{
|
||||
if ((i >= 12) && (i < (int) this->values.size () - 8))
|
||||
{
|
||||
if (! skip) out << " ..." << endl;
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
out.precision (16);
|
||||
out.width (18);
|
||||
out << this->values [i] << ' ' ;
|
||||
if ((i%4) == 3) clog << endl;
|
||||
}
|
||||
out << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void data_type::serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & values;
|
||||
return;
|
||||
}
|
||||
|
||||
double do_pba_out (const data_type & a_data)
|
||||
{
|
||||
string filename = "pba_11.data";
|
||||
ofstream fout (filename.c_str (), ios_base::binary);
|
||||
boost::timer io_timer;
|
||||
{
|
||||
boost::archive::portable_binary_oarchive opba (fout);
|
||||
opba & a_data;
|
||||
}
|
||||
return io_timer.elapsed ();
|
||||
}
|
||||
|
||||
double do_pba_in (data_type & a_data)
|
||||
{
|
||||
string filename = "pba_11.data";
|
||||
ifstream fin (filename.c_str (), ios_base::binary);
|
||||
boost::timer io_timer;
|
||||
{
|
||||
boost::archive::portable_binary_iarchive ipba (fin);
|
||||
ipba & a_data;
|
||||
}
|
||||
return io_timer.elapsed ();
|
||||
}
|
||||
|
||||
double do_text_out (const data_type & a_data)
|
||||
{
|
||||
string filename = "pba_11.txt";
|
||||
ofstream fout (filename.c_str ());
|
||||
boost::timer io_timer;
|
||||
{
|
||||
boost::archive::text_oarchive ota (fout);
|
||||
ota & a_data;
|
||||
}
|
||||
return io_timer.elapsed ();
|
||||
}
|
||||
|
||||
double do_text_in (data_type & a_data)
|
||||
{
|
||||
string filename = "pba_11.txt";
|
||||
ifstream fin (filename.c_str ());
|
||||
boost::timer io_timer;
|
||||
{
|
||||
boost::archive::text_iarchive ita (fin);
|
||||
ita & a_data;
|
||||
}
|
||||
return io_timer.elapsed ();
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
double elapsed_time_pba_out;
|
||||
double elapsed_time_text_out;
|
||||
double elapsed_time_pba_in;
|
||||
double elapsed_time_text_in;
|
||||
data_type my_data; // A data structure to be stored then loaded.
|
||||
|
||||
{
|
||||
// Fill the vector with random values :
|
||||
size_t dim = 10000000;
|
||||
my_data.values.reserve (dim);
|
||||
boost::random::mt19937 rng;
|
||||
boost::random::uniform_real_distribution<> flat (0.0, 100.0);
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
double val = flat (rng);
|
||||
my_data.values.push_back (val);
|
||||
}
|
||||
my_data.print (clog, "Stored data in PBA and text archive");
|
||||
}
|
||||
|
||||
{
|
||||
// Store in PBA :
|
||||
elapsed_time_pba_out = do_pba_out (my_data);
|
||||
}
|
||||
|
||||
{
|
||||
// Store in text archive :
|
||||
elapsed_time_text_out = do_text_out (my_data);
|
||||
}
|
||||
|
||||
{
|
||||
my_data.values.clear ();
|
||||
// Load from PBA :
|
||||
elapsed_time_pba_in = do_pba_in (my_data);
|
||||
my_data.print (clog, "Loaded data from PBA");
|
||||
}
|
||||
|
||||
{
|
||||
my_data.values.clear ();
|
||||
// Load from text archive :
|
||||
elapsed_time_text_in = do_text_in (my_data);
|
||||
my_data.print (clog, "Loaded data from text archive");
|
||||
}
|
||||
|
||||
clog << "PBA store I/O elapsed time : " << elapsed_time_pba_out << " (second)" << endl;
|
||||
clog << "Text store I/O elapsed time : " << elapsed_time_text_out << " (second)" << endl;
|
||||
clog << "PBA load I/O elapsed time : " << elapsed_time_pba_in << " (second)" << endl;
|
||||
clog << "Text load I/O elapsed time : " << elapsed_time_text_in << " (second)" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_11.cpp
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/** tutorial_pba_2.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This sample program shows how to use a portable binary archive
|
||||
* to store/load floating point numbers including non-finite and
|
||||
* special (denormalized) values.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// The name for the example data file :
|
||||
string filename = "pba_2.data";
|
||||
|
||||
{
|
||||
// A normal single precision floating point number :
|
||||
float pi = 3.14159265;
|
||||
|
||||
// Single precision zeroed floating point number :
|
||||
float zero = 0.0;
|
||||
|
||||
// A denormalized single precision floating point number :
|
||||
float tiny = 1.e-40;
|
||||
|
||||
// A single precision floating point number with `+Infinity' value :
|
||||
float plus_infinity = numeric_limits<float>::infinity ();
|
||||
|
||||
// A single precision floating point number with `-Infinity' value :
|
||||
float minus_infinity = -numeric_limits<float>::infinity ();
|
||||
|
||||
// A single precision `Not-a-Number' (NaN):
|
||||
float nan = numeric_limits<float>::quiet_NaN ();
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
ofstream fout (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file :
|
||||
boost::archive::portable_binary_oarchive opba (fout);
|
||||
|
||||
// Store (serialize) variables :
|
||||
opba & pi & zero & tiny & plus_infinity & minus_infinity & nan;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Single precision floating point numbers to be loaded :
|
||||
float x[6];
|
||||
|
||||
// Open an input file stream in binary mode :
|
||||
ifstream fin (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an input portable binary archive attached to the input file :
|
||||
boost::archive::portable_binary_iarchive ipba (fin);
|
||||
|
||||
// Load (de-serialize) variables using the same
|
||||
// order than for serialization :
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
ipba & x[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Print :
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
cout.precision (8);
|
||||
cout << "Loaded x[" << i << "] = " << x[i];
|
||||
switch (fp::fpclassify(x[i]))
|
||||
{
|
||||
case FP_NAN: cout << " (NaN)"; break;
|
||||
case FP_INFINITE: cout << " (infinite)"; break;
|
||||
case FP_SUBNORMAL: cout << " (denormalized)"; break;
|
||||
case FP_NORMAL: cout << " (normalized)"; break;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_2.cpp
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/** tutorial_pba_3.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This sample program shows how to use a portable binary archive
|
||||
* and prevent the serialization of non-finite floating numbers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// The name for the example data file :
|
||||
string filename = "pba_3.data";
|
||||
|
||||
try
|
||||
{
|
||||
// An array of single precision floating numbers:
|
||||
float x[5];
|
||||
x[0] = 3.14159; // Pi
|
||||
x[1] = 6.022e22; // Avogadro constant
|
||||
x[2] = 1.6e-19; // Electron charge magnitude
|
||||
x[3] = 1.e-40; // A tiny (denormalized) value
|
||||
x[4] = numeric_limits<float>::infinity (); // This will fail while serializing...
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
ofstream fout (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file,
|
||||
// using the special 'boost::archive::no_infnan' flag :
|
||||
boost::archive::portable_binary_oarchive opba (fout, boost::archive::no_infnan);
|
||||
|
||||
// Store (serialize) variables :
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
clog << "Serializing value : " << x[i] << " ... ";
|
||||
opba & x[i];
|
||||
clog << "Ok !" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (exception & x)
|
||||
{
|
||||
cerr << "ERROR: " << x.what () << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_3.cpp
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/** tutorial_pba_4.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This sample program shows how to use a portable binary archive
|
||||
* to store/load integer numbers of various sizes using the Boost
|
||||
* portable integer typedefs.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// The name for the example data file :
|
||||
string filename = "pba_4.data";
|
||||
|
||||
{
|
||||
// Some integer numbers :
|
||||
bool t = true;
|
||||
char c = 'c';
|
||||
unsigned char u = 'u';
|
||||
int8_t b = -3; // char
|
||||
uint8_t B = +6; // unsigned char
|
||||
int16_t s = -16;
|
||||
uint16_t S = +32;
|
||||
int32_t l = -128;
|
||||
uint32_t L = +127;
|
||||
int64_t ll = -1024;
|
||||
uint64_t LL = +2048;
|
||||
|
||||
// Open an output file stream in binary mode :
|
||||
ofstream fout (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file :
|
||||
boost::archive::portable_binary_oarchive opba (fout);
|
||||
|
||||
// Store (serialize) variables :
|
||||
opba & t & c & u & b & B & s & S & l & L & ll & LL;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Single precision floating numbers to be loaded :
|
||||
// Some integer numbers :
|
||||
bool t;
|
||||
char c;
|
||||
unsigned char u;
|
||||
int8_t b;
|
||||
uint8_t B;
|
||||
int16_t s;
|
||||
uint16_t S;
|
||||
int32_t l;
|
||||
uint32_t L;
|
||||
int64_t ll;
|
||||
uint64_t LL;
|
||||
|
||||
// Open an input file stream in binary mode :
|
||||
ifstream fin (filename.c_str (), ios_base::binary);
|
||||
|
||||
{
|
||||
// Create an input portable binary archive attached to the input file :
|
||||
boost::archive::portable_binary_iarchive ipba (fin);
|
||||
|
||||
// Load (de-serialize) variables using the same
|
||||
// order than for serialization :
|
||||
ipba & t & c & u & b & B & s & S & l & L & ll & LL;
|
||||
}
|
||||
|
||||
clog << "t = " << t << " (bool)" << endl;
|
||||
clog << "c = '" << c << "' (char)" << endl;
|
||||
clog << "u = '" << u << "' (unsigned char)" << endl;
|
||||
clog << "b = " << (int) b << " (int8_t)" << endl;
|
||||
clog << "B = " << (int) B << " (uint8_t)" << endl;
|
||||
clog << "s = " << s << " (int16_t)" << endl;
|
||||
clog << "S = " << S << " (uint16_t)" << endl;
|
||||
clog << "l = " << l << " (int32_t)" << endl;
|
||||
clog << "L = " << L << " (uint32_t)" << endl;
|
||||
clog << "ll = " << ll << " (int64_t)" << endl;
|
||||
clog << "LL = " << LL << " (uint64_t)" << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_4.cpp
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/** tutorial_pba_5.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This sample program shows how to use a portable binary archive
|
||||
* to store/load data in a memory buffer.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
#include <boost/iostreams/device/array.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// The memory buffer is implemented using a STL vector :
|
||||
typedef std::vector<char> buffer_type;
|
||||
buffer_type buffer;
|
||||
|
||||
{
|
||||
// Some data to be stored :
|
||||
bool t = true;
|
||||
char c = 'c';
|
||||
int16_t s = +16;
|
||||
int32_t l = -128;
|
||||
int64_t ll = +10000000000;
|
||||
float pi = 3.14159;
|
||||
double nan = numeric_limits<double>::quiet_NaN ();
|
||||
string hello = "World !";
|
||||
|
||||
buffer.reserve (1024); // pre-allocate some memory
|
||||
|
||||
// The output stream interface to the buffer :
|
||||
boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type> > output_stream (buffer);
|
||||
|
||||
{
|
||||
// Create an output portable binary archive attached to the output file :
|
||||
boost::archive::portable_binary_oarchive opba (output_stream);
|
||||
|
||||
// Store (serialize) variables :
|
||||
opba & t & c & s & l & ll & pi & nan & hello;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
clog << "Buffer content is " << buffer.size () << " bytes : " << endl << " ";
|
||||
for (int i = 0; i < buffer.size (); ++i)
|
||||
{
|
||||
clog << (int) ((unsigned char) buffer[i]) << ' ';
|
||||
if ((i + 1) % 20 == 0) clog << endl << " ";
|
||||
}
|
||||
clog << endl;
|
||||
|
||||
{
|
||||
// Some data to be loaded :
|
||||
bool t;
|
||||
char c;
|
||||
int16_t s;
|
||||
int32_t l;
|
||||
int64_t ll;
|
||||
float pi;
|
||||
double nan;
|
||||
string hello;
|
||||
|
||||
// The input stream interface to the buffer :
|
||||
boost::iostreams::stream<boost::iostreams::array_source> input_stream (&buffer[0],
|
||||
buffer.size ());
|
||||
|
||||
{
|
||||
// Create an input portable binary archive attached to the input file :
|
||||
boost::archive::portable_binary_iarchive ipba (input_stream);
|
||||
|
||||
// Load (de-serialize) variables :
|
||||
ipba & t & c & s & l & ll & pi & nan & hello;
|
||||
}
|
||||
|
||||
clog << "Loaded values from the buffer are: " << endl;
|
||||
clog << " t = " << t << " (bool)" << endl;
|
||||
clog << " c = '" << c << "' (char)" << endl;
|
||||
clog << " s = " << s << " (int16_t)" << endl;
|
||||
clog << " l = " << l << " (int32_t)" << endl;
|
||||
clog << " ll = " << ll << " (int64_t)" << endl;
|
||||
clog << " pi = " << pi << " (float)" << endl;
|
||||
clog << " nan = " << nan << " (double)" << endl;
|
||||
clog << " hello = \"" << hello << "\" (std::string)" << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_5.cpp
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/** tutorial_pba_6.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This sample program shows how to use a portable binary archive
|
||||
* associated to a memory buffer to copy a non-copyable object.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
#include <boost/iostreams/device/array.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* A foo noncopyable class */
|
||||
struct foo : boost::noncopyable
|
||||
{
|
||||
uint32_t status;
|
||||
double value;
|
||||
double special;
|
||||
|
||||
string to_string () const
|
||||
{
|
||||
ostringstream sout;
|
||||
sout << "foo={status=" << status << "; value=" << value << "; special=" << special<< "}";
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void serialize (Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & status;
|
||||
ar & value;
|
||||
ar & special;
|
||||
return;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// A templatized copy function for Boost/Serialization equipped classes.
|
||||
// Here we use PBAs associated to a memory buffer :
|
||||
template <class Serializable>
|
||||
void copy (const Serializable & source, Serializable & target)
|
||||
{
|
||||
namespace io = boost::iostreams;
|
||||
namespace ba = boost::archive;
|
||||
if (&source == &target) return; // self-copy guard
|
||||
typedef std::vector<char> buffer_type;
|
||||
buffer_type buffer;
|
||||
buffer.reserve (1024);
|
||||
{
|
||||
io::stream<io::back_insert_device<buffer_type> > output_stream (buffer);
|
||||
ba::portable_binary_oarchive opba (output_stream);
|
||||
opba & source;
|
||||
}
|
||||
{
|
||||
io::stream<io::array_source> input_stream (&buffer[0], buffer.size ());
|
||||
ba::portable_binary_iarchive ipba (input_stream);
|
||||
ipba & target;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
// Some instance of the 'foo' class :
|
||||
foo dummy;
|
||||
dummy.status = 1;
|
||||
dummy.value = 3.14159;
|
||||
dummy.special = numeric_limits<double>::quiet_NaN ();
|
||||
clog << "dummy is : " << dummy.to_string () << endl;
|
||||
|
||||
// Another instance of the 'foo' class :
|
||||
foo clone;
|
||||
|
||||
/* The following instruction is forbidden because foo
|
||||
inherits 'boost::noncopyable' :
|
||||
|
||||
clone = dummy; // this ends in a compilation error.
|
||||
|
||||
*/
|
||||
|
||||
// Anyway, we can use this workaround :
|
||||
copy (dummy, clone);
|
||||
clog << "clone is : " << clone.to_string () << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_6.cpp
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/** tutorial_pba_7.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example shows how the default behaviour of standard
|
||||
* I/O streams does not support the read/write operations of
|
||||
* non-finite floating point values in a portable way.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main (void)
|
||||
{
|
||||
{
|
||||
float x = numeric_limits<float>::infinity ();
|
||||
double y = numeric_limits<double>::quiet_NaN ();
|
||||
cout.precision (8);
|
||||
cout << "x = " << x << endl;
|
||||
cout.precision (16);
|
||||
cout << "y = " << y << endl;
|
||||
}
|
||||
|
||||
{
|
||||
string input ("inf nan");
|
||||
istringstream iss (input);
|
||||
float x;
|
||||
double y;
|
||||
iss >> x >> y;
|
||||
if (! iss)
|
||||
{
|
||||
cerr << "Cannot read 'x' or 'y' : non finite values are not supported !" << endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_7.cpp
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/** tutorial_pba_8.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example shows how to store some variables
|
||||
* of basic types (bool, integer, floating point numbers, STL string)
|
||||
* using the text or XML archive format associated to a
|
||||
* standard output file stream supporting portable non-finite
|
||||
* floating point values.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/xml_oarchive.hpp>
|
||||
#include <boost/archive/text_oarchive.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/archive/codecvt_null.hpp>
|
||||
#include <boost/math/special_functions/nonfinite_num_facets.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void do_text_out (void)
|
||||
{
|
||||
// The name for the example data text file :
|
||||
string filename = "pba_8.txt";
|
||||
|
||||
// Some variables of various primitive types :
|
||||
bool b = true;
|
||||
char c = 'B';
|
||||
uint32_t answer = 42;
|
||||
float value = numeric_limits<float>::infinity ();
|
||||
double precision = numeric_limits<double>::quiet_NaN ();
|
||||
string question = "What makes you think she's a witch?";
|
||||
|
||||
// Open an output file stream :
|
||||
ofstream fout (filename.c_str ());
|
||||
|
||||
// Prepare the output file stream for inf/NaN support :
|
||||
locale default_locale (locale::classic (),
|
||||
new boost::archive::codecvt_null<char>);
|
||||
locale infnan_locale (default_locale,
|
||||
new boost::math::nonfinite_num_put<char>);
|
||||
fout.imbue (infnan_locale);
|
||||
|
||||
{
|
||||
// Create an output text archive attached to the output file :
|
||||
boost::archive::text_oarchive ota (fout, boost::archive::no_codecvt);
|
||||
|
||||
// Store (serializing) variables :
|
||||
ota & b & c & answer & value & precision & question;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void do_xml_out (void)
|
||||
{
|
||||
// The name for the example data XML file :
|
||||
string filename = "pba_8.xml";
|
||||
|
||||
// Some variables of various primitive types :
|
||||
bool b = true;
|
||||
char c = 'B';
|
||||
uint32_t answer = 42;
|
||||
float value = numeric_limits<float>::infinity ();
|
||||
double precision = numeric_limits<double>::quiet_NaN ();
|
||||
string question = "What makes you think she's a witch?";
|
||||
|
||||
// Open an output file stream :
|
||||
ofstream fout (filename.c_str ());
|
||||
|
||||
// Prepare the output file stream for inf/NaN support :
|
||||
locale default_locale (locale::classic (),
|
||||
new boost::archive::codecvt_null<char>);
|
||||
locale infnan_locale (default_locale,
|
||||
new boost::math::nonfinite_num_put<char>);
|
||||
fout.imbue (infnan_locale);
|
||||
|
||||
{
|
||||
// Create an output text archive attached to the output file :
|
||||
boost::archive::xml_oarchive oxa (fout, boost::archive::no_codecvt);
|
||||
|
||||
// Store (serializing) variables :
|
||||
oxa & BOOST_SERIALIZATION_NVP(b)
|
||||
& BOOST_SERIALIZATION_NVP(c)
|
||||
& BOOST_SERIALIZATION_NVP(answer)
|
||||
& BOOST_SERIALIZATION_NVP(value)
|
||||
& BOOST_SERIALIZATION_NVP(precision)
|
||||
& BOOST_SERIALIZATION_NVP(question);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
do_text_out ();
|
||||
do_xml_out ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_8.cpp
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/** tutorial_pba_9.cpp
|
||||
*
|
||||
* (C) Copyright 2011 François Mauger, Christian Pfligersdorffer
|
||||
*
|
||||
* Use, modification and distribution is subject to the Boost Software
|
||||
* License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* The intent of this program is to serve as a tutorial for
|
||||
* users of the portable binary archive in the framework of
|
||||
* the Boost/Serialization library.
|
||||
*
|
||||
* This example shows how to load some variables of basic
|
||||
* types (bool, char, integer, floating point numbers, STL string)
|
||||
* using the text or XML archive format associated to a
|
||||
* standard file input stream supporting portable non-finite
|
||||
* floating point values.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/archive/xml_iarchive.hpp>
|
||||
#include <boost/archive/text_iarchive.hpp>
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/archive/codecvt_null.hpp>
|
||||
#include <boost/math/special_functions/nonfinite_num_facets.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void do_text_in (void)
|
||||
{
|
||||
// The name for the example data text file :
|
||||
string filename = "pba_8.txt";
|
||||
// Some variables of various primitive types :
|
||||
bool b;
|
||||
char c;
|
||||
uint32_t answer;
|
||||
float value;
|
||||
double precision;
|
||||
string question;
|
||||
|
||||
// Open an input file stream :
|
||||
ifstream fin (filename.c_str ());
|
||||
|
||||
// Prepare the input file stream for inf/NaN support :
|
||||
locale default_locale (locale::classic (),
|
||||
new boost::archive::codecvt_null<char>);
|
||||
locale infnan_locale (default_locale,
|
||||
new boost::math::nonfinite_num_get<char>);
|
||||
fin.imbue (infnan_locale);
|
||||
|
||||
{
|
||||
// Create an input text archive attached to the input file :
|
||||
boost::archive::text_iarchive ita (fin, boost::archive::no_codecvt);
|
||||
|
||||
// Store (serializing) variables :
|
||||
ita & b & c & answer & value & precision & question;
|
||||
}
|
||||
|
||||
clog << "Loaded values from text archive are: " << endl;
|
||||
clog << " b = " << b << endl;
|
||||
clog << " c = '" << c << "'" << endl;
|
||||
clog << " answer = " << answer << endl;
|
||||
clog << " value = " << value << endl;
|
||||
clog << " precision = " << precision << endl;
|
||||
clog << " question = \"" << question << "\"" << endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void do_xml_in (void)
|
||||
{
|
||||
// The name for the example data text file :
|
||||
string filename = "pba_8.xml";
|
||||
|
||||
// Some variables of various primitive types :
|
||||
bool b;
|
||||
char c;
|
||||
uint32_t answer;
|
||||
float value;
|
||||
double precision;
|
||||
string question;
|
||||
|
||||
// Open an input file stream :
|
||||
ifstream fin (filename.c_str ());
|
||||
|
||||
// Prepare the input file stream for inf/NaN support :
|
||||
locale default_locale (locale::classic (),
|
||||
new boost::archive::codecvt_null<char>);
|
||||
locale infnan_locale (default_locale,
|
||||
new boost::math::nonfinite_num_get<char>);
|
||||
fin.imbue (infnan_locale);
|
||||
|
||||
{
|
||||
// Create an output text archive attached to the output file :
|
||||
boost::archive::xml_iarchive ixa (fin, boost::archive::no_codecvt);
|
||||
|
||||
// Store (serializing) variables :
|
||||
ixa & BOOST_SERIALIZATION_NVP(b)
|
||||
& BOOST_SERIALIZATION_NVP(c)
|
||||
& BOOST_SERIALIZATION_NVP(answer)
|
||||
& BOOST_SERIALIZATION_NVP(value)
|
||||
& BOOST_SERIALIZATION_NVP(precision)
|
||||
& BOOST_SERIALIZATION_NVP(question);
|
||||
}
|
||||
|
||||
clog << "Loaded values from XML archive are: " << endl;
|
||||
clog << " b = " << b << endl;
|
||||
clog << " c = '" << c << "'" << endl;
|
||||
clog << " answer = " << answer << endl;
|
||||
clog << " value = " << value << endl;
|
||||
clog << " precision = " << precision << endl;
|
||||
clog << " question = \"" << question << "\"" << endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
do_text_in ();
|
||||
do_xml_in ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tutorial_pba_9.cpp
|
||||
BIN
src/contrib/eos_portable_archive/tutorial/images/boost.png
Normal file
BIN
src/contrib/eos_portable_archive/tutorial/images/boost.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
151
src/contrib/eos_portable_archive/tutorial/scripts/jquery-1.4.min.js
vendored
Normal file
151
src/contrib/eos_portable_archive/tutorial/scripts/jquery-1.4.min.js
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*!
|
||||
* jQuery JavaScript Library v1.4
|
||||
* http://jquery.com/
|
||||
*
|
||||
* Copyright 2010, John Resig
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://docs.jquery.com/License
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
* http://sizzlejs.com/
|
||||
* Copyright 2010, The Dojo Foundation
|
||||
* Released under the MIT, BSD, and GPL Licenses.
|
||||
*
|
||||
* Date: Wed Jan 13 15:23:05 2010 -0500
|
||||
*/
|
||||
(function(A,w){function oa(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(oa,1);return}c.ready()}}function La(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function $(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var o in b)$(a,o,b[o],f,e,d);return a}if(d!==w){f=!i&&f&&c.isFunction(d);for(o=0;o<j;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,i);return a}return j?
|
||||
e(a[0],b):null}function K(){return(new Date).getTime()}function aa(){return false}function ba(){return true}function pa(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function qa(a){var b=true,d=[],f=[],e=arguments,i,j,o,p,n,t=c.extend({},c.data(this,"events").live);for(p in t){j=t[p];if(j.live===a.type||j.altLive&&c.inArray(a.type,j.altLive)>-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete t[p]}i=c(a.target).closest(f,a.currentTarget);
|
||||
n=0;for(l=i.length;n<l;n++)for(p in t){j=t[p];o=i[n].elem;f=null;if(i[n].selector===j.selector){if(j.live==="mouseenter"||j.live==="mouseleave")f=c(a.relatedTarget).closest(j.selector)[0];if(!f||f!==o)d.push({elem:o,fn:j})}}n=0;for(l=d.length;n<l;n++){i=d[n];a.currentTarget=i.elem;a.data=i.fn.data;if(i.fn.apply(i.elem,e)===false){b=false;break}}return b}function ra(a,b){return["live",a,b.replace(/\./g,"`").replace(/ /g,"&")].join(".")}function sa(a){return!a||!a.parentNode||a.parentNode.nodeType===
|
||||
11}function ta(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var i in f)for(var j in f[i])c.event.add(this,i,f[i][j],f[i][j].data)}}})}function ua(a,b,d){var f,e,i;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&a[0].indexOf("<option")<0){e=true;if(i=c.fragments[a[0]])if(i!==1)f=i}if(!f){b=b&&b[0]?b[0].ownerDocument||b[0]:s;f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=
|
||||
i?f:1;return{fragment:f,cacheable:e}}function T(a){for(var b=0,d,f;(d=a[b])!=null;b++)if(!c.noData[d.nodeName.toLowerCase()]&&(f=d[H]))delete c.cache[f]}function L(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ma=A.jQuery,Na=A.$,s=A.document,U,Oa=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Pa=/^.[^:#\[\.,]*$/,Qa=/\S/,
|
||||
Ra=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Sa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],M,ca=Object.prototype.toString,da=Object.prototype.hasOwnProperty,ea=Array.prototype.push,R=Array.prototype.slice,V=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Oa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Sa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];
|
||||
c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ua([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return U.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a)}else return!b||b.jquery?(b||U).find(a):c(b).find(a);else if(c.isFunction(a))return U.ready(a);if(a.selector!==w){this.selector=a.selector;
|
||||
this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a,this)},selector:"",jquery:"1.4",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=
|
||||
0;ea.apply(this,a);return this},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||
|
||||
c(null)},push:ea,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(i in e){j=a[i];o=e[i];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){j=j&&(c.isPlainObject(j)||c.isArray(j))?j:c.isArray(o)?[]:{};a[i]=c.extend(f,j,o)}else if(o!==w)a[i]=
|
||||
o}return a};c.extend({noConflict:function(a){A.$=Na;if(a)A.jQuery=Ma;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",M,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",
|
||||
M);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&oa()}}},isFunction:function(a){return ca.call(a)==="[object Function]"},isArray:function(a){return ca.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||ca.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!da.call(a,"constructor")&&!da.call(a.constructor.prototype,"isPrototypeOf"))return false;var b;for(b in a);return b===w||da.call(a,b)},
|
||||
isEmptyObject:function(a){for(var b in a)return false;return true},noop:function(){},globalEval:function(a){if(a&&Qa.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,i=a.length,j=i===w||c.isFunction(a);
|
||||
if(d)if(j)for(f in a){if(b.apply(a[f],d)===false)break}else for(;e<i;){if(b.apply(a[e++],d)===false)break}else if(j)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<i&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Ra,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ea.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=
|
||||
0,f=b.length;d<f;d++)if(b[d]===a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,i=a.length;e<i;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,i=0,j=a.length;i<j;i++){e=b(a[i],i,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b===
|
||||
"string"){d=a;a=d[b];b=w}else if(b&&!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){var b={browser:""};a=a.toLowerCase();if(/webkit/.test(a))b={browser:"webkit",version:/webkit[\/ ]([\w.]+)/};else if(/opera/.test(a))b={browser:"opera",version:/version/.test(a)?/version[\/ ]([\w.]+)/:/opera[\/ ]([\w.]+)/};else if(/msie/.test(a))b={browser:"msie",version:/msie ([\w.]+)/};else if(/mozilla/.test(a)&&
|
||||
!/compatible/.test(a))b={browser:"mozilla",version:/rv:([\w.]+)/};b.version=(b.version&&b.version.exec(a)||[0,"0"])[1];return b},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=true;if(V)c.inArray=function(a,b){return V.call(b,a)};U=c(s);if(s.addEventListener)M=function(){s.removeEventListener("DOMContentLoaded",M,false);c.ready()};else if(s.attachEvent)M=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",
|
||||
M);c.ready()}};if(V)c.inArray=function(a,b){return V.call(b,a)};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+K();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,
|
||||
htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,
|
||||
a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function o(){c.support.noCloneEvent=false;d.detachEvent("onclick",o)});d.cloneNode(true).fireEvent("onclick")}c(function(){var o=s.createElement("div");o.style.width=o.style.paddingLeft="1px";s.body.appendChild(o);c.boxModel=c.support.boxModel=o.offsetWidth===2;s.body.removeChild(o).style.display="none"});a=function(o){var p=s.createElement("div");o="on"+o;var n=o in
|
||||
p;if(!n){p.setAttribute(o,"return;");n=typeof p[o]==="function"}return n};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var H="jQuery"+K(),Ta=0,ya={},Ua={};c.extend({cache:{},expando:H,noData:{embed:true,object:true,applet:true},data:function(a,
|
||||
b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var f=a[H],e=c.cache;if(!b&&!f)return null;f||(f=++Ta);if(typeof b==="object"){a[H]=f;e=e[f]=c.extend(true,{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Ua:(e[f]={});if(d!==w){a[H]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?ya:a;var d=a[H],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[H]}catch(i){a.removeAttribute&&
|
||||
a.removeAttribute(H)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,
|
||||
a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,
|
||||
a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var za=/[\n\t]/g,fa=/\s+/,Va=/\r/g,Wa=/href|src|style/,Xa=/(button|input)/i,Ya=/(button|input|object|select|textarea)/i,Za=/^(a|area)$/i,Aa=/radio|checkbox/;c.fn.extend({attr:function(a,
|
||||
b){return $(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(p){var n=c(this);n.addClass(a.call(this,p,n.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(fa),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className)for(var i=" "+e.className+" ",j=0,o=b.length;j<o;j++){if(i.indexOf(" "+b[j]+" ")<0)e.className+=
|
||||
" "+b[j]}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(p){var n=c(this);n.removeClass(a.call(this,p,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(fa),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var i=(" "+e.className+" ").replace(za," "),j=0,o=b.length;j<o;j++)i=i.replace(" "+b[j]+" "," ");e.className=i.substring(1,i.length-1)}else e.className=""}return this},toggleClass:function(a,
|
||||
b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var i=c(this);i.toggleClass(a.call(this,e,i.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,i=0,j=c(this),o=b,p=a.split(fa);e=p[i++];){o=f?o:!j.hasClass(e);j[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=
|
||||
" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(za," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i<d;i++){var j=e[i];if(j.selected){a=c(j).val();if(b)return a;f.push(a)}}return f}if(Aa.test(b.type)&&
|
||||
!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Va,"")}return w}var o=c.isFunction(a);return this.each(function(p){var n=c(this),t=a;if(this.nodeType===1){if(o)t=a.call(this,p,n.val());if(typeof t==="number")t+="";if(c.isArray(t)&&Aa.test(this.type))this.checked=c.inArray(n.val(),t)>=0;else if(c.nodeName(this,"select")){var z=c.makeArray(t);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),z)>=0});if(!z.length)this.selectedIndex=
|
||||
-1}else this.value=t}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Wa.test(b);if(b in a&&f&&!i){if(e){if(b==="type"&&Xa.test(a.nodeName)&&a.parentNode)throw"type property can't be changed";a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;
|
||||
if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Ya.test(a.nodeName)||Za.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var $a=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===
|
||||
3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;if(!d.guid)d.guid=c.guid++;if(f!==w){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):w};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var o,p=0;o=b[p++];){var n=o.split(".");o=n.shift();d.type=n.slice(0).sort().join(".");var t=e[o],z=this.special[o]||{};if(!t){t=e[o]={};
|
||||
if(!z.setup||z.setup.call(a,f,n,d)===false)if(a.addEventListener)a.addEventListener(o,i,false);else a.attachEvent&&a.attachEvent("on"+o,i)}if(z.add)if((n=z.add.call(a,d,f,n,t))&&c.isFunction(n)){n.guid=n.guid||d.guid;d=n}t[d.guid]=d;this.global[o]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===w||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);
|
||||
for(var o=0;i=b[o++];){var p=i.split(".");i=p.shift();var n=!p.length,t=c.map(p.slice(0).sort(),$a);t=new RegExp("(^|\\.)"+t.join("\\.(?:.*\\.)?")+"(\\.|$)");var z=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var B in f[i])if(n||t.test(f[i][B].type))delete f[i][B];z.remove&&z.remove.call(a,p,j);for(e in f[i])break;if(!e){if(!z.teardown||z.teardown.call(a,p)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+
|
||||
i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(B=c.data(a,"handle"))B.elem=null;c.removeData(a,"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[H]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
|
||||
8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;var i=c.data(d,"handle");i&&i.apply(d,b);var j,o;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){j=d[e];o=d["on"+e]}}catch(p){}i=c.nodeName(d,"a")&&e==="click";if(!f&&j&&!a.isDefaultPrevented()&&!i){this.triggered=true;try{d[e]()}catch(n){}}else if(o&&d["on"+e].apply(d,b)===false)a.result=false;this.triggered=false;if(!a.isPropagationStopped())(d=d.parentNode||d.ownerDocument)&&c.event.trigger(a,b,d,true)},
|
||||
handle:function(a){var b,d;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},
|
||||
props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[H])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||
|
||||
s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&
|
||||
a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;c.event.add(this,b.live,qa,b)},remove:function(a){if(a.length){var b=0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],qa)}},special:{}},beforeunload:{setup:function(a,
|
||||
b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=K();this[H]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=
|
||||
ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:aa,isPropagationStopped:aa,isImmediatePropagationStopped:aa};var Ba=function(a){for(var b=a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ca=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",
|
||||
mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ca:Ba,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ca:Ba)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return pa("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+
|
||||
d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return pa("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this,"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var ga=/textarea|input|select/i;function Da(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>
|
||||
-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ha(a,b){var d=a.target,f,e;if(!(!ga.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Da(d);if(e!==f){if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",e);if(d.type!=="select"&&(f!=null||e)){a.type="change";return c.event.trigger(a,b,this)}}}}c.event.special.change={filters:{focusout:ha,click:function(a){var b=a.target,d=b.type;if(d===
|
||||
"radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ha.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ha.call(this,a)},beforeactivate:function(a){a=a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Da(a))}},setup:function(a,b,d){for(var f in W)c.event.add(this,f+".specialChange."+d.guid,W[f]);return ga.test(this.nodeName)},
|
||||
remove:function(a,b){for(var d in W)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),W[d]);return ga.test(this.nodeName)}};var W=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,
|
||||
f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){thisObject=e;e=f;f=w}var j=b==="one"?c.proxy(e,function(o){c(this).unbind(o,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e,thisObject):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,
|
||||
b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||
|
||||
a)},live:function(a,b,d){if(c.isFunction(b)){d=b;b=w}c(this.context).bind(ra(a,this.selector),{data:b,selector:this.selector,live:a},d);return this},die:function(a,b){c(this.context).unbind(ra(a,this.selector),b?{guid:b.guid+this.selector+a}:null);return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d){return d?
|
||||
this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",k,m=0;g[m];m++){k=g[m];if(k.nodeType===3||k.nodeType===4)h+=k.nodeValue;else if(k.nodeType!==8)h+=a(k.childNodes)}return h}function b(g,h,k,m,r,q){r=0;for(var v=m.length;r<v;r++){var u=m[r];if(u){u=u[g];for(var y=false;u;){if(u.sizcache===
|
||||
k){y=m[u.sizset];break}if(u.nodeType===1&&!q){u.sizcache=k;u.sizset=r}if(u.nodeName.toLowerCase()===h){y=u;break}u=u[g]}m[r]=y}}}function d(g,h,k,m,r,q){r=0;for(var v=m.length;r<v;r++){var u=m[r];if(u){u=u[g];for(var y=false;u;){if(u.sizcache===k){y=m[u.sizset];break}if(u.nodeType===1){if(!q){u.sizcache=k;u.sizset=r}if(typeof h!=="string"){if(u===h){y=true;break}}else if(p.filter(h,[u]).length>0){y=u;break}}u=u[g]}m[r]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
||||
e=0,i=Object.prototype.toString,j=false,o=true;[0,0].sort(function(){o=false;return 0});var p=function(g,h,k,m){k=k||[];var r=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return k;for(var q=[],v,u,y,S,I=true,N=x(h),J=g;(f.exec(""),v=f.exec(J))!==null;){J=v[3];q.push(v[1]);if(v[2]){S=v[3];break}}if(q.length>1&&t.exec(g))if(q.length===2&&n.relative[q[0]])u=ia(q[0]+q[1],h);else for(u=n.relative[q[0]]?[h]:p(q.shift(),h);q.length;){g=q.shift();if(n.relative[g])g+=q.shift();
|
||||
u=ia(g,u)}else{if(!m&&q.length>1&&h.nodeType===9&&!N&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){v=p.find(q.shift(),h,N);h=v.expr?p.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:q.pop(),set:B(m)}:p.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&h.parentNode?h.parentNode:h,N);u=v.expr?p.filter(v.expr,v.set):v.set;if(q.length>0)y=B(u);else I=false;for(;q.length;){var E=q.pop();v=E;if(n.relative[E])v=q.pop();else E="";if(v==null)v=h;n.relative[E](y,v,N)}}else y=[]}y||(y=u);if(!y)throw"Syntax error, unrecognized expression: "+
|
||||
(E||g);if(i.call(y)==="[object Array]")if(I)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&F(h,y[g])))k.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&k.push(u[g]);else k.push.apply(k,y);else B(y,k);if(S){p(S,r,k,m);p.uniqueSort(k)}return k};p.uniqueSort=function(g){if(D){j=o;g.sort(D);if(j)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};p.matches=function(g,h){return p(g,null,null,h)};p.find=function(g,h,k){var m,r;if(!g)return[];
|
||||
for(var q=0,v=n.order.length;q<v;q++){var u=n.order[q];if(r=n.leftMatch[u].exec(g)){var y=r[1];r.splice(1,1);if(y.substr(y.length-1)!=="\\"){r[1]=(r[1]||"").replace(/\\/g,"");m=n.find[u](r,h,k);if(m!=null){g=g.replace(n.match[u],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};p.filter=function(g,h,k,m){for(var r=g,q=[],v=h,u,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var I in n.filter)if((u=n.leftMatch[I].exec(g))!=null&&u[2]){var N=n.filter[I],J,E;E=u[1];y=false;u.splice(1,1);if(E.substr(E.length-
|
||||
1)!=="\\"){if(v===q)q=[];if(n.preFilter[I])if(u=n.preFilter[I](u,v,k,q,m,S)){if(u===true)continue}else y=J=true;if(u)for(var X=0;(E=v[X])!=null;X++)if(E){J=N(E,u,X,v);var Ea=m^!!J;if(k&&J!=null)if(Ea)y=true;else v[X]=false;else if(Ea){q.push(E);y=true}}if(J!==w){k||(v=q);g=g.replace(n.match[I],"");if(!y)return[];break}}}if(g===r)if(y==null)throw"Syntax error, unrecognized expression: "+g;else break;r=g}return v};var n=p.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
|
||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
|
||||
relative:{"+":function(g,h){var k=typeof h==="string",m=k&&!/\W/.test(h);k=k&&!m;if(m)h=h.toLowerCase();m=0;for(var r=g.length,q;m<r;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=k||q&&q.nodeName.toLowerCase()===h?q||false:q===h}k&&p.filter(h,g,true)},">":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,r=g.length;m<r;m++){var q=g[m];if(q){k=q.parentNode;g[m]=k.nodeName.toLowerCase()===h?k:false}}}else{m=0;for(r=g.length;m<r;m++)if(q=g[m])g[m]=
|
||||
k?q.parentNode:q.parentNode===h;k&&p.filter(h,g,true)}},"":function(g,h,k){var m=e++,r=d;if(typeof h==="string"&&!/\W/.test(h)){var q=h=h.toLowerCase();r=b}r("parentNode",h,m,g,q,k)},"~":function(g,h,k){var m=e++,r=d;if(typeof h==="string"&&!/\W/.test(h)){var q=h=h.toLowerCase();r=b}r("previousSibling",h,m,g,q,k)}},find:{ID:function(g,h,k){if(typeof h.getElementById!=="undefined"&&!k)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var k=[];
|
||||
h=h.getElementsByName(g[1]);for(var m=0,r=h.length;m<r;m++)h[m].getAttribute("name")===g[1]&&k.push(h[m]);return k.length===0?null:k}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,k,m,r,q){g=" "+g[1].replace(/\\/g,"")+" ";if(q)return g;q=0;for(var v;(v=h[q])!=null;q++)if(v)if(r^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))k||m.push(v);else if(k)h[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
|
||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,m,r,q){h=g[1].replace(/\\/g,"");if(!q&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,m,r){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=p(g[3],null,null,h);else{g=p.filter(g[3],h,k,true^r);k||m.push.apply(m,
|
||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!p(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
|
||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
|
||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,k,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return h<k[3]-0},gt:function(g,h,k){return h>k[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,m){var r=h[1],q=n.filters[r];if(q)return q(g,k,h,m);else if(r==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(r==="not"){h=
|
||||
h[3];k=0;for(m=h.length;k<m;k++)if(h[k]===g)return false;return true}else throw"Syntax error, unrecognized expression: "+r;},CHILD:function(g,h){var k=h[1],m=g;switch(k){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(k==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":k=h[2];var r=h[3];if(k===1&&r===0)return true;h=h[0];var q=g.parentNode;if(q&&(q.sizcache!==h||!g.nodeIndex)){var v=0;for(m=q.firstChild;m;m=
|
||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;q.sizcache=h}g=g.nodeIndex-r;return k===0?g===0:g%k===0&&g/k>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=n.attrHandle[k]?n.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
|
||||
"="?k===h:m==="*="?k.indexOf(h)>=0:m==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:m==="!="?k!==h:m==="^="?k.indexOf(h)===0:m==="$="?k.substr(k.length-h.length)===h:m==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,m){var r=n.setFilters[h[2]];if(r)return r(g,k,h,m)}}},t=n.match.POS;for(var z in n.match){n.match[z]=new RegExp(n.match[z].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[z]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[z].source.replace(/\\(\d+)/g,function(g,
|
||||
h){return"\\"+(h-0+1)}))}var B=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){B=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,m=g.length;k<m;k++)h.push(g[k]);else for(k=0;g[k];k++)h.push(g[k]);return h}}var D;if(s.documentElement.compareDocumentPosition)D=function(g,h){if(!g.compareDocumentPosition||
|
||||
!h.compareDocumentPosition){if(g==h)j=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)j=true;return g};else if("sourceIndex"in s.documentElement)D=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)j=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)j=true;return g};else if(s.createRange)D=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)j=true;return g.ownerDocument?-1:1}var k=g.ownerDocument.createRange(),m=
|
||||
h.ownerDocument.createRange();k.setStart(g,0);k.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=k.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)j=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var k=s.documentElement;k.insertBefore(g,k.firstChild);if(s.getElementById(h)){n.find.ID=function(m,r,q){if(typeof r.getElementById!=="undefined"&&!q)return(r=r.getElementById(m[1]))?r.id===m[1]||typeof r.getAttributeNode!=="undefined"&&
|
||||
r.getAttributeNode("id").nodeValue===m[1]?[r]:w:[]};n.filter.ID=function(m,r){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===r}}k.removeChild(g);k=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;k[m];m++)k[m].nodeType===1&&h.push(k[m]);k=h}return k};g.innerHTML="<a href='#'></a>";
|
||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=p,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){p=function(m,r,q,v){r=r||s;if(!v&&r.nodeType===9&&!x(r))try{return B(r.querySelectorAll(m),q)}catch(u){}return g(m,r,q,v)};for(var k in g)p[k]=g[k];h=null}}();
|
||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,k,m){if(typeof k.getElementsByClassName!=="undefined"&&!m)return k.getElementsByClassName(h[1])};g=null}}})();var F=s.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,
|
||||
h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ia=function(g,h){var k=[],m="",r;for(h=h.nodeType?[h]:h;r=n.match.PSEUDO.exec(g);){m+=r[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;r=0;for(var q=h.length;r<q;r++)p(g,h[r],k);return p.filter(m,k)};c.find=p;c.expr=p.selectors;c.expr[":"]=c.expr.filters;c.unique=p.uniqueSort;c.getText=a;c.isXMLDoc=x;c.contains=F})();var ab=/Until$/,bb=/^(?:parents|prevUntil|prevAll)/,
|
||||
cb=/,/;R=Array.prototype.slice;var Fa=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,i){return!!b.call(e,i,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Pa.test(b))return c.filter(b,f,!d);else b=c.filter(b,a)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
|
||||
c.find(a,this[f],b);if(f>0)for(var i=d;i<b.length;i++)for(var j=0;j<d;j++)if(b[j]===b[i]){b.splice(i--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Fa(this,a,false),"not",a)},filter:function(a){return this.pushStack(Fa(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i=
|
||||
{},j;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){j=a[e];i[j]||(i[j]=c.expr.match.POS.test(j)?c(j,b||this.context):j)}for(;f&&f.ownerDocument&&f!==b;){for(j in i){e=i[j];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var p=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,t){for(;t&&t.ownerDocument&&t!==b;){if(p?p.index(t)>-1:c(t).is(a))return t;t=t.parentNode}return null})},index:function(a){if(!a||typeof a===
|
||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(sa(a[0])||sa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
|
||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
|
||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);ab.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||cb.test(f))&&bb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||!c(a).is(d));){a.nodeType===
|
||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ga=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,db=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/<tbody/i,gb=/<|&\w+;/,hb=function(a,b,d){return eb.test(d)?a:b+"></"+d+">"},G={option:[1,"<select multiple='multiple'>","</select>"],
|
||||
legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};G.optgroup=G.option;G.tbody=G.tfoot=G.colgroup=G.caption=G.thead;G.th=G.td;if(!c.support.htmlSerialize)G._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);
|
||||
return d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.getText(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
||||
wrapInner:function(a){return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&
|
||||
this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,
|
||||
"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ga,"").replace(Y,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ta(this,b);ta(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===
|
||||
1?this[0].innerHTML.replace(Ga,""):null;else if(typeof a==="string"&&!/<script/i.test(a)&&(c.support.leadingWhitespace||!Y.test(a))&&!G[(Ha.exec(a)||["",""])[1].toLowerCase()])try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){T(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}else c.isFunction(a)?this.each(function(e){var i=c(this),j=i.html();i.empty().append(function(){return a.call(this,e,j)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
|
||||
this[0].parentNode){c.isFunction(a)||(a=c(a).detach());return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(t){return c.nodeName(t,"table")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}var e,i,j=a[0],o=[];if(c.isFunction(j))return this.each(function(t){var z=
|
||||
c(this);a[0]=j.call(this,t,b?z.html():w);return z.domManip(a,b,d)});if(this[0]){e=a[0]&&a[0].parentNode&&a[0].parentNode.nodeType===11?{fragment:a[0].parentNode}:ua(a,this,o);if(i=e.fragment.firstChild){b=b&&c.nodeName(i,"tr");for(var p=0,n=this.length;p<n;p++)d.call(b?f(this[p],i):this[p],e.cacheable||this.length>1||p>0?e.fragment.cloneNode(true):e.fragment)}o&&c.each(o,La)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},
|
||||
function(a,b){c.fn[a]=function(d){var f=[];d=c(d);for(var e=0,i=d.length;e<i;e++){var j=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),j);f=f.concat(j)}return this.pushStack(f,a,d.selector)}});c.each({remove:function(a,b){if(!a||c.filter(a,[this]).length){if(!b&&this.nodeType===1){T(this.getElementsByTagName("*"));T([this])}this.parentNode&&this.parentNode.removeChild(this)}},empty:function(){for(this.nodeType===1&&T(this.getElementsByTagName("*"));this.firstChild;)this.removeChild(this.firstChild)}},
|
||||
function(a,b){c.fn[a]=function(){return this.each(b,arguments)}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;var e=[];c.each(a,function(i,j){if(typeof j==="number")j+="";if(j){if(typeof j==="string"&&!gb.test(j))j=b.createTextNode(j);else if(typeof j==="string"){j=j.replace(db,hb);var o=(Ha.exec(j)||["",""])[1].toLowerCase(),p=G[o]||G._default,n=p[0];i=b.createElement("div");for(i.innerHTML=p[1]+j+p[2];n--;)i=i.lastChild;
|
||||
if(!c.support.tbody){n=fb.test(j);o=o==="table"&&!n?i.firstChild&&i.firstChild.childNodes:p[1]==="<table>"&&!n?i.childNodes:[];for(p=o.length-1;p>=0;--p)c.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!c.support.leadingWhitespace&&Y.test(j)&&i.insertBefore(b.createTextNode(Y.exec(j)[0]),i.firstChild);j=c.makeArray(i.childNodes)}if(j.nodeType)e.push(j);else e=c.merge(e,j)}});if(d)for(a=0;e[a];a++)if(f&&c.nodeName(e[a],"script")&&(!e[a].type||e[a].type.toLowerCase()===
|
||||
"text/javascript"))f.push(e[a].parentNode?e[a].parentNode.removeChild(e[a]):e[a]);else{e[a].nodeType===1&&e.splice.apply(e,[a+1,0].concat(c.makeArray(e[a].getElementsByTagName("script"))));d.appendChild(e[a])}return e}});var ib=/z-?index|font-?weight|opacity|zoom|line-?height/i,Ia=/alpha\([^)]*\)/,Ja=/opacity=([^)]*)/,ja=/float/i,ka=/-([a-z])/ig,jb=/([A-Z])/g,kb=/^-?\d+(?:px)?$/i,lb=/^-?\d/,mb={position:"absolute",visibility:"hidden",display:"block"},nb=["Left","Right"],ob=["Top","Bottom"],pb=s.defaultView&&
|
||||
s.defaultView.getComputedStyle,Ka=c.support.cssFloat?"cssFloat":"styleFloat",la=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return $(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!ib.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""===
|
||||
"NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=Ia.test(a)?a.replace(Ia,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Ja.exec(f.filter)[1])/100+"":""}if(ja.test(b))b=Ka;b=b.replace(ka,la);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,i=b==="width"?nb:ob;function j(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(i,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=
|
||||
parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,"border"+this+"Width",true))||0})}a.offsetWidth!==0?j():c.swap(a,mb,j);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Ja.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ja.test(b))b=Ka;if(!d&&e&&e[b])f=e[b];else if(pb){if(ja.test(b))b="float";b=b.replace(jb,"-$1").toLowerCase();e=
|
||||
a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ka,la);f=a.currentStyle[b]||a.currentStyle[d];if(!kb.test(f)&&lb.test(f)){b=e.left;var i=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=i}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=
|
||||
f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var qb=K(),rb=/<script(.|\s)*?\/script>/gi,sb=/select|textarea/i,tb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,O=/=\?(&|$)/,ma=/\?/,ub=/(\?|&)_=.*?(&|$)/,vb=/^(\w+:)?\/\/([^\/?#]+)/,
|
||||
wb=/%20/g;c.fn.extend({_load:c.fn.load,load:function(a,b,d){if(typeof a!=="string")return this._load(a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}c.ajax({url:a,type:f,dataType:"html",data:b,context:this,complete:function(i,j){if(j==="success"||j==="notmodified")this.html(e?c("<div />").append(i.responseText.replace(rb,
|
||||
"")).find(e):i.responseText);d&&this.each(d,[i.responseText,j,i])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||sb.test(this.nodeName)||tb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});
|
||||
c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},
|
||||
ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",
|
||||
text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&e.success.call(p,o,j,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(p,x,j);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(r,q){(e.context?c(e.context):c.event).trigger(r,q)}var e=c.extend(true,{},c.ajaxSettings,a),i,j,o,p=e.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,
|
||||
e.traditional);if(e.dataType==="jsonp"){if(n==="GET")O.test(e.url)||(e.url+=(ma.test(e.url)?"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!O.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&O.test(e.data)||O.test(e.url))){i=e.jsonpCallback||"jsonp"+qb++;if(e.data)e.data=(e.data+"").replace(O,"="+i+"$1");e.url=e.url.replace(O,"="+i+"$1");e.dataType="script";A[i]=A[i]||function(r){o=r;b();d();A[i]=w;try{delete A[i]}catch(q){}B&&
|
||||
B.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===false&&n==="GET"){var t=K(),z=e.url.replace(ub,"$1_="+t+"$2");e.url=z+(z===e.url?(ma.test(e.url)?"&":"?")+"_="+t:"")}if(e.data&&n==="GET")e.url+=(ma.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");t=(t=vb.exec(e.url))&&(t[1]&&t[1]!==location.protocol||t[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&t){var B=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");
|
||||
C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!i){var D=false;C.onload=C.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;b();d();C.onload=C.onreadystatechange=null;B&&C.parentNode&&B.removeChild(C)}}}B.insertBefore(C,B.firstChild);return w}var F=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",
|
||||
e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}t||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ia){}if(e.beforeSend&&e.beforeSend.call(p,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",
|
||||
[x,e]);var g=x.onreadystatechange=function(r){if(!x||x.readyState===0){F||d();F=true;if(x)x.onreadystatechange=c.noop}else if(!F&&x&&(x.readyState===4||r==="timeout")){F=true;x.onreadystatechange=c.noop;j=r==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";if(j==="success")try{o=c.httpData(x,e.dataType,e)}catch(q){j="parsererror"}if(j==="success"||j==="notmodified")i||b();else c.handleError(e,x,j);d();r==="timeout"&&x.abort();if(e.async)x=
|
||||
null}};try{var h=x.abort;x.abort=function(){if(x){h.call(x);if(x)x.readyState=0}g()}}catch(k){}e.async&&e.timeout>0&&setTimeout(function(){x&&!F&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||A,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol===
|
||||
"file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;if(e&&a.documentElement.nodeName==="parsererror")throw"parsererror";if(d&&
|
||||
d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&f.indexOf("json")>=0)if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))a=A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+a))();else throw"Invalid JSON: "+a;else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(e,i){i=
|
||||
c.isFunction(i)?i():i;f[f.length]=encodeURIComponent(e)+"="+encodeURIComponent(i)}var f=[];if(b===w)b=c.ajaxSettings.traditional;c.isArray(a)||a.jquery?c.each(a,function(){d(this.name,this.value)}):c.each(a,function e(i,j){if(c.isArray(j))c.each(j,function(o,p){b?d(i,p):e(i+"["+(typeof p==="object"||c.isArray(p)?o:"")+"]",p)});else!b&&j!=null&&typeof j==="object"?c.each(j,function(o,p){e(i+"["+o+"]",p)}):d(i,j)});return f.join("&").replace(wb,"+")}});var na={},xb=/toggle|show|hide/,yb=/^([+-]=)?([\d+-.]+)(.*)$/,
|
||||
Z,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a!=null)return this.animate(L("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(na[d])f=na[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();
|
||||
na[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a!=null)return this.animate(L("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&
|
||||
c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(L("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var i=c.extend({},e),j,o=this.nodeType===1&&c(this).is(":hidden"),
|
||||
p=this;for(j in a){var n=j.replace(ka,la);if(j!==n){a[n]=a[j];delete a[j];j=n}if(a[j]==="hide"&&o||a[j]==="show"&&!o)return i.complete.call(this);if((j==="height"||j==="width")&&this.style){i.display=c.css(this,"display");i.overflow=this.style.overflow}if(c.isArray(a[j])){(i.specialEasing=i.specialEasing||{})[j]=a[j][1];a[j]=a[j][0]}}if(i.overflow!=null)this.style.overflow="hidden";i.curAnim=c.extend({},a);c.each(a,function(t,z){var B=new c.fx(p,i,t);if(xb.test(z))B[z==="toggle"?o?"show":"hide":z](a);
|
||||
else{var C=yb.exec(z),D=B.cur(true)||0;if(C){z=parseFloat(C[2]);var F=C[3]||"px";if(F!=="px"){p.style[t]=(z||1)+F;D=(z||1)/B.cur(true)*D;p.style[t]=D+F}if(C[1])z=(C[1]==="-="?-1:1)*z+D;B.custom(D,z,F)}else B.custom(D,z,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:L("show",1),slideUp:L("hide",1),slideToggle:L("toggle",
|
||||
1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration==="number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,
|
||||
b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==
|
||||
null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(i){return e.step(i)}this.startTime=K();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!Z)Z=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop===
|
||||
"width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=K(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=
|
||||
this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=
|
||||
c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},stop:function(){clearInterval(Z);Z=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=
|
||||
null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),
|
||||
f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(!b||!b.ownerDocument)return null;if(a)return this.each(function(t){c.offset.setOffset(this,a,t)});if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=
|
||||
b,e=b.ownerDocument,i,j=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var p=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==j;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;i=e?e.getComputedStyle(b,null):b.currentStyle;p-=b.scrollTop;n-=b.scrollLeft;if(b===d){p+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){p+=parseFloat(i.borderTopWidth)||
|
||||
0;n+=parseFloat(i.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&i.overflow!=="visible"){p+=parseFloat(i.borderTopWidth)||0;n+=parseFloat(i.borderLeftWidth)||0}f=i}if(f.position==="relative"||f.position==="static"){p+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){p+=Math.max(j.scrollTop,o.scrollTop);n+=Math.max(j.scrollLeft,o.scrollLeft)}return{top:p,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),
|
||||
d,f,e,i=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);
|
||||
d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i;a.removeChild(b);c.offset.initialize=c.noop},
|
||||
bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),i=parseInt(c.curCSS(a,"top",true),10)||0,j=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,d,e);d={top:b.top-e.top+i,left:b.left-
|
||||
e.left+j};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=
|
||||
this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],i;if(!e)return null;if(f!==w)return this.each(function(){if(i=wa(this))i.scrollTo(!a?f:c(i).scrollLeft(),a?f:c(i).scrollTop());else this[d]=f});else return(i=wa(e))?"pageXOffset"in i?i[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&i.document.documentElement[d]||i.document.body[d]:e[d]}});
|
||||
c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+
|
||||
b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
|
||||
39
src/contrib/eos_portable_archive/tutorial/styles/boost.css
Normal file
39
src/contrib/eos_portable_archive/tutorial/styles/boost.css
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*=============================================================================
|
||||
Copyright 2002 William E. Kempf
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompany-
|
||||
ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
=============================================================================*/
|
||||
|
||||
H1
|
||||
{
|
||||
FONT-SIZE: 200%;
|
||||
COLOR: #00008B;
|
||||
}
|
||||
H2
|
||||
{
|
||||
FONT-SIZE: 150%;
|
||||
}
|
||||
H3
|
||||
{
|
||||
FONT-SIZE: 125%;
|
||||
}
|
||||
H4
|
||||
{
|
||||
FONT-SIZE: 108%;
|
||||
}
|
||||
/*
|
||||
BODY
|
||||
{
|
||||
FONT-SIZE: 100%;
|
||||
BACKGROUND-COLOR: #ffffff;
|
||||
COLOR: #000000;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
PRE
|
||||
{
|
||||
MARGIN-LEFT: 2em;
|
||||
FONT-FAMILY: Courier,
|
||||
monospace;
|
||||
}
|
||||
*/
|
||||
92
src/contrib/eos_portable_archive/tutorial/styles/style.css
Normal file
92
src/contrib/eos_portable_archive/tutorial/styles/style.css
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
body
|
||||
{
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
pre
|
||||
{
|
||||
border-right: gray 1pt solid;
|
||||
border-top: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
margin-left: 0pt;
|
||||
background-color: #EEEEEE;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.button
|
||||
{
|
||||
color : black;
|
||||
background-color : #FFFFFF;
|
||||
border-radius: 0px;
|
||||
border: outset 3px #d6d6d6;
|
||||
text-decoration : none;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.fs
|
||||
{
|
||||
font-family: courier;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
color: maroon;
|
||||
}
|
||||
|
||||
.code_string
|
||||
{
|
||||
font-family: courier;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
color: #bc8f8f;
|
||||
}
|
||||
|
||||
.code
|
||||
{
|
||||
/*
|
||||
top: 0;
|
||||
border-style: inset;
|
||||
margin-top: 5pt;
|
||||
margin-bottom: 5pt;
|
||||
margin-left: 5pt;
|
||||
margin-right: 5pt;
|
||||
border-width: 2px 2px 2px 2px ;
|
||||
*/
|
||||
font-family: courier;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
color: #228b22;
|
||||
}
|
||||
|
||||
.byte
|
||||
{
|
||||
border-right: gray 1pt solid;
|
||||
border-top: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
margin-left: 2pt;
|
||||
margin-right: 2pt;
|
||||
font-family: courier;
|
||||
font-size: 11pt;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
#pre
|
||||
{
|
||||
border-right: gray 1pt solid;
|
||||
border-top: gray 1pt solid;
|
||||
border-left: gray 1pt solid;
|
||||
border-bottom: gray 1pt solid;
|
||||
margin-left: 1pt;
|
||||
margin-right: 1pt;
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
|
||||
/*
|
||||
(C) Copyright 2011 François Mauger.
|
||||
Use, modification and distribution is subject to the Boost Software
|
||||
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
2348
src/contrib/eos_portable_archive/tutorial/tutorial.html
Normal file
2348
src/contrib/eos_portable_archive/tutorial/tutorial.html
Normal file
File diff suppressed because it is too large
Load diff
25
src/contrib/epee/LICENSE.txt
Normal file
25
src/contrib/epee/LICENSE.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Andrey N. Sabelnikov nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL Andrey N. Sabelnikov BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1
src/contrib/epee/README.md
Normal file
1
src/contrib/epee/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
epee - is a small library of helpers, wrappers, tools and and so on, used to make my life easier.
|
||||
1
src/contrib/epee/demo/.gitignore
vendored
Normal file
1
src/contrib/epee/demo/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build/*
|
||||
49
src/contrib/epee/demo/CMakeLists.txt
Normal file
49
src/contrib/epee/demo/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
#set(Boost_DEBUG 1)
|
||||
find_package(Boost COMPONENTS system filesystem thread date_time chrono regex )
|
||||
|
||||
include_directories( ${Boost_INCLUDE_DIRS} )
|
||||
|
||||
|
||||
IF (MSVC)
|
||||
add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /nologo /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /bigobj" )
|
||||
ELSE()
|
||||
# set stuff for other systems
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder -D_GNU_SOURCE")
|
||||
ENDIF()
|
||||
|
||||
|
||||
include_directories(.)
|
||||
include_directories(../include)
|
||||
include_directories(iface)
|
||||
|
||||
|
||||
# Add folders to filters
|
||||
file(GLOB_RECURSE LEVIN_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_levin_server/*.cpp)
|
||||
|
||||
file(GLOB_RECURSE HTTP_GENERAL_SECTION RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.inl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/demo_http_server/*.cpp)
|
||||
|
||||
|
||||
|
||||
source_group(general FILES ${LEVIN_GENERAL_SECTION} FILES ${HTTP_GENERAL_SECTION})
|
||||
#source_group(general FILES ${HTTP_GENERAL_SECTION})
|
||||
|
||||
add_executable(demo_http_server ${HTTP_GENERAL_SECTION} )
|
||||
add_executable(demo_levin_server ${LEVIN_GENERAL_SECTION} )
|
||||
|
||||
target_link_libraries( demo_http_server ${Boost_LIBRARIES} )
|
||||
target_link_libraries( demo_levin_server ${Boost_LIBRARIES} )
|
||||
|
||||
IF (NOT WIN32)
|
||||
target_link_libraries (demo_http_server rt)
|
||||
target_link_libraries (demo_levin_server rt)
|
||||
ENDIF()
|
||||
|
||||
|
||||
0
src/contrib/epee/demo/README.txt
Normal file
0
src/contrib/epee/demo/README.txt
Normal file
217
src/contrib/epee/demo/demo_http_server/demo_http_server.cpp
Normal file
217
src/contrib/epee/demo/demo_http_server/demo_http_server.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "console_handler.h"
|
||||
#include "demo_http_server.h"
|
||||
#include "net/http_client.h"
|
||||
#include "storages/http_abstract_invoke.h"
|
||||
|
||||
|
||||
template<class t_request, class t_response>
|
||||
bool communicate(const std::string url, t_request& req, t_response& rsp, const std::string& ip, const std::string& port, bool use_json, bool use_jrpc = false)
|
||||
{
|
||||
epee::net_utils::http::http_simple_client http_client;
|
||||
bool r = http_client.connect(ip, port, 1000);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to connect");
|
||||
if(use_json)
|
||||
{
|
||||
if(use_jrpc)
|
||||
{
|
||||
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
|
||||
req_t.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;
|
||||
}
|
||||
}
|
||||
103
src/contrib/epee/demo/demo_http_server/demo_http_server.h
Normal file
103
src/contrib/epee/demo/demo_http_server/demo_http_server.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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;
|
||||
};
|
||||
}
|
||||
|
||||
8
src/contrib/epee/demo/demo_http_server/stdafx.cpp
Normal file
8
src/contrib/epee/demo/demo_http_server/stdafx.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// demo_http_server.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
40
src/contrib/epee/demo/demo_http_server/stdafx.h
Normal file
40
src/contrib/epee/demo/demo_http_server/stdafx.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define ENABLE_RELEASE_LOGGING
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
||||
13
src/contrib/epee/demo/demo_http_server/targetver.h
Normal file
13
src/contrib/epee/demo/demo_http_server/targetver.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// The following macros define the minimum required platform. The minimum required platform
|
||||
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
|
||||
// your application. The macros work by enabling all features available on platform versions up to and
|
||||
// including the version specified.
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
|
||||
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
||||
200
src/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
Normal file
200
src/contrib/epee/demo/demo_levin_server/demo_levin_server.cpp
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "demo_levin_server.h"
|
||||
#include "console_handler.h"
|
||||
|
||||
|
||||
template<class t_request>
|
||||
bool communicate(net_utils::boosted_levin_async_server& transport, int id, t_request& req, const std::string& ip, const std::string& port, bool use_async)
|
||||
{
|
||||
if(use_async)
|
||||
{
|
||||
//IMPORTANT: do not pass local parameters from stack by reference! connect_async returns immediately, and callback will call in any thread later
|
||||
transport.connect_async(ip, port, 10000, [&transport, id, req, ip, port](net_utils::connection_context_base& ctx, const boost::system::error_code& ec_)
|
||||
{
|
||||
if(!!ec_)
|
||||
{
|
||||
LOG_ERROR("Failed to connect to " << ip << ":" << port);
|
||||
}else
|
||||
{//connected ok!
|
||||
|
||||
epee::net_utils::async_invoke_remote_command2<demo::COMMAND_EXAMPLE_1::response>(ctx.m_connection_id, id, req, transport.get_config_object(), [&transport, ip, port](int res_code, demo::COMMAND_EXAMPLE_1::response& rsp, net_utils::connection_context_base& ctx)
|
||||
{
|
||||
if(res_code < 0)
|
||||
{
|
||||
LOG_ERROR("Failed to invoke to " << ip << ":" << port);
|
||||
}else
|
||||
{//invoked ok
|
||||
CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoked ok", LOG_LEVEL_0);
|
||||
}
|
||||
transport.get_config_object().close(ctx.m_connection_id);
|
||||
return true;
|
||||
});
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 async invoke requested", LOG_LEVEL_0);
|
||||
}
|
||||
});
|
||||
}else
|
||||
{
|
||||
net_utils::connection_context_base ctx = AUTO_VAL_INIT(ctx);
|
||||
bool r = transport.connect(ip, port, 10000, ctx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to connect to " << ip << ":" << port);
|
||||
demo::COMMAND_EXAMPLE_1::response rsp = AUTO_VAL_INIT(rsp);
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoke requested", LOG_LEVEL_0);
|
||||
r = epee::net_utils::invoke_remote_command2(ctx.m_connection_id, id, req, rsp, transport.get_config_object());
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to invoke levin request");
|
||||
CHECK_AND_ASSERT_MES(rsp.m_success, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.size()==1, false, "wrong response");
|
||||
CHECK_AND_ASSERT_MES(rsp.subs.front() == demo::get_test_data(), false, "wrong response");
|
||||
transport.get_config_object().close(ctx.m_connection_id);
|
||||
LOG_PRINT_GREEN("Client COMMAND_EXAMPLE_1 sync invoked ok", LOG_LEVEL_0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
//set up logging options
|
||||
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
log_space::log_singletone::add_logger(LOGGER_FILE,
|
||||
log_space::log_singletone::get_default_log_file().c_str(),
|
||||
log_space::log_singletone::get_default_log_folder().c_str());
|
||||
|
||||
|
||||
|
||||
LOG_PRINT("Demo server starting ...", LOG_LEVEL_0);
|
||||
|
||||
|
||||
demo::demo_levin_server srv;
|
||||
|
||||
start_default_console(&srv, "#");
|
||||
|
||||
std::string bind_param = "0.0.0.0";
|
||||
std::string port = "12345";
|
||||
|
||||
if(!srv.init(port, bind_param))
|
||||
{
|
||||
LOG_ERROR("Failed to initialize srv!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
srv.run();
|
||||
|
||||
size_t c = 1;
|
||||
while (!srv.is_stop())
|
||||
{
|
||||
|
||||
demo::COMMAND_EXAMPLE_1::request req;
|
||||
req.sub = demo::get_test_data();
|
||||
bool r = communicate(srv.get_server(), demo::COMMAND_EXAMPLE_1::ID, req, "127.0.0.1", port, (c%2 == 0));
|
||||
misc_utils::sleep_no_w(1000);
|
||||
++c;
|
||||
}
|
||||
bool r = srv.wait_stop();
|
||||
CHECK_AND_ASSERT_MES(r, 1, "failed to wait server stop");
|
||||
|
||||
|
||||
srv.deinit();
|
||||
|
||||
LOG_PRINT("Demo server stoped.", LOG_LEVEL_0);
|
||||
return 1;
|
||||
|
||||
CATCH_ENTRY_L0("main", 1);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
namespace demo
|
||||
{
|
||||
bool demo_levin_server::init(const std::string& bind_port, const std::string& bind_ip)
|
||||
{
|
||||
m_net_server.get_config_object().m_pcommands_handler = this;
|
||||
LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port);
|
||||
return m_net_server.init_server(bind_port, bind_ip);
|
||||
}
|
||||
|
||||
bool demo_levin_server::run()
|
||||
{
|
||||
m_stop = false;
|
||||
//here you can set worker threads count
|
||||
int thrds_count = 4;
|
||||
m_net_server.get_config_object().m_invoke_timeout = 10000;
|
||||
m_net_server.get_config_object().m_pcommands_handler = this;
|
||||
|
||||
//go to loop
|
||||
LOG_PRINT("Run net_service loop( " << thrds_count << " threads)...", LOG_LEVEL_0);
|
||||
if(!m_net_server.run_server(thrds_count, false))
|
||||
{
|
||||
LOG_ERROR("Failed to run net tcp server!");
|
||||
}
|
||||
|
||||
LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool demo_levin_server::deinit()
|
||||
{
|
||||
return m_net_server.deinit_server();
|
||||
}
|
||||
|
||||
bool demo_levin_server::send_stop_signal()
|
||||
{
|
||||
m_net_server.send_stop_signal();
|
||||
return true;
|
||||
}
|
||||
int demo_levin_server::handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(arg.sub == demo::get_test_data(), false, "wrong request");
|
||||
rsp.m_success = true;
|
||||
rsp.subs.push_back(arg.sub);
|
||||
LOG_PRINT_GREEN("Server COMMAND_EXAMPLE_1 ok", LOG_LEVEL_0);
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int demo_levin_server::handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
76
src/contrib/epee/demo/demo_levin_server/demo_levin_server.h
Normal file
76
src/contrib/epee/demo/demo_levin_server/demo_levin_server.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "net/levin_server_cp2.h"
|
||||
#include "transport_defs.h"
|
||||
#include "storages/levin_abstract_invoke2.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
namespace demo
|
||||
{
|
||||
|
||||
class demo_levin_server: public levin::levin_commands_handler<>
|
||||
{
|
||||
public:
|
||||
bool run();
|
||||
bool init(const std::string& bind_port = "11112", const std::string& bind_ip = "0.0.0.0");
|
||||
bool deinit();
|
||||
bool send_stop_signal();
|
||||
bool is_stop(){return m_stop;}
|
||||
bool wait_stop(){return m_net_server.timed_wait_server_stop(100000);}
|
||||
net_utils::boosted_levin_async_server& get_server(){return m_net_server;}
|
||||
private:
|
||||
|
||||
|
||||
CHAIN_LEVIN_INVOKE_MAP(); //move levin_commands_handler interface invoke(...) callbacks into invoke map
|
||||
CHAIN_LEVIN_NOTIFY_STUB(); //move levin_commands_handler interface notify(...) callbacks into nothing
|
||||
|
||||
BEGIN_INVOKE_MAP2(demo_levin_server)
|
||||
HANDLE_INVOKE_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_command_1)
|
||||
HANDLE_INVOKE_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_command_2)
|
||||
HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_1, &demo_levin_server::handle_notify_1)
|
||||
HANDLE_NOTIFY_T2(COMMAND_EXAMPLE_2, &demo_levin_server::handle_notify_2)
|
||||
END_INVOKE_MAP2()
|
||||
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
int handle_command_1(int command, COMMAND_EXAMPLE_1::request& arg, COMMAND_EXAMPLE_1::response& rsp, const net_utils::connection_context_base& context);
|
||||
int handle_command_2(int command, COMMAND_EXAMPLE_2::request& arg, COMMAND_EXAMPLE_2::response& rsp, const net_utils::connection_context_base& context);
|
||||
int handle_notify_1(int command, COMMAND_EXAMPLE_1::request& arg, const net_utils::connection_context_base& context);
|
||||
int handle_notify_2(int command, COMMAND_EXAMPLE_2::request& arg, const net_utils::connection_context_base& context);
|
||||
//----------------------------------------------------------------------------------
|
||||
net_utils::boosted_levin_async_server m_net_server;
|
||||
std::atomic<bool> m_stop;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
30
src/contrib/epee/demo/demo_levin_server/stdafx.cpp
Normal file
30
src/contrib/epee/demo/demo_levin_server/stdafx.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
41
src/contrib/epee/demo/demo_levin_server/stdafx.h
Normal file
41
src/contrib/epee/demo/demo_levin_server/stdafx.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define ENABLE_RELEASE_LOGGING
|
||||
#include "log_opt_defs.h"
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
||||
13
src/contrib/epee/demo/demo_levin_server/targetver.h
Normal file
13
src/contrib/epee/demo/demo_levin_server/targetver.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// The following macros define the minimum required platform. The minimum required platform
|
||||
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
|
||||
// your application. The macros work by enabling all features available on platform versions up to and
|
||||
// including the version specified.
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
|
||||
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
||||
4
src/contrib/epee/demo/generate_gcc.sh
Normal file
4
src/contrib/epee/demo/generate_gcc.sh
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
#cmake -DBOOST_ROOT=/usr/local/proj/boost_1_49_0 -DBOOST_LIBRARYDIR=/usr/local/proj/boost_1_49_0/stage/lib ..
|
||||
7
src/contrib/epee/demo/generate_vc_proj.bat
Normal file
7
src/contrib/epee/demo/generate_vc_proj.bat
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake "-DBoost_USE_STATIC_LIBS=TRUE" -G "Visual Studio 11 Win64" ..
|
||||
cd ..
|
||||
pause
|
||||
221
src/contrib/epee/demo/iface/transport_defs.h
Normal file
221
src/contrib/epee/demo/iface/transport_defs.h
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
34
src/contrib/epee/include/auto_val_init.h
Normal file
34
src/contrib/epee/include/auto_val_init.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2006-2017, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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>
|
||||
|
||||
|
||||
|
||||
#define AUTO_VAL_INIT(v) boost::value_initialized<decltype(v)>()
|
||||
#define AUTO_VAL_INIT_T(t) boost::value_initialized<t>()
|
||||
260
src/contrib/epee/include/cache_helper.h
Normal file
260
src/contrib/epee/include/cache_helper.h
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright (c) 2006-2016, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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 <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include "boost/optional.hpp"
|
||||
#include "syncobj.h"
|
||||
#include "include_base_utils.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace misc_utils
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<bool is_ordered_type, class t_key, class t_value>
|
||||
struct container_selector;
|
||||
|
||||
template<class t_key, class t_value>
|
||||
struct container_selector<true, t_key, t_value>
|
||||
{
|
||||
typedef std::map<t_key, t_value > container;
|
||||
};
|
||||
|
||||
template<class t_key, class t_value>
|
||||
struct container_selector<false, t_key, t_value>
|
||||
{
|
||||
typedef std::unordered_map<t_key, t_value > container;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<bool is_ordered_container, typename t_key, typename t_value, uint64_t max_elements>
|
||||
class cache_base
|
||||
{
|
||||
uint64_t mac_allowed_elements;
|
||||
std::list<t_key> most_recet_acessed;
|
||||
typename container_selector<is_ordered_container, t_key, std::pair<t_value, typename std::list<t_key>::iterator> >::container data;
|
||||
protected:
|
||||
critical_section m_lock;
|
||||
public:
|
||||
|
||||
cache_base() : mac_allowed_elements(max_elements)
|
||||
{}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
|
||||
return data.size();
|
||||
}
|
||||
|
||||
void set_max_elements(uint64_t e)
|
||||
{
|
||||
mac_allowed_elements = e;
|
||||
}
|
||||
|
||||
bool get(const t_key& k, t_value& v)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
auto it = data.find(k);
|
||||
if (it == data.end())
|
||||
return false;
|
||||
|
||||
most_recet_acessed.splice(most_recet_acessed.begin(), most_recet_acessed, it->second.second);
|
||||
v = it->second.first;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set(const t_key& k, const t_value& v)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
most_recet_acessed.push_front(k);
|
||||
data[k] = std::pair<t_value, typename std::list<t_key>::iterator>(v, most_recet_acessed.begin());
|
||||
|
||||
trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
data.clear();
|
||||
most_recet_acessed.clear();
|
||||
}
|
||||
|
||||
bool erase(const t_key& k)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
auto data_it = data.find(k);
|
||||
if (data_it == data.end())
|
||||
return false;
|
||||
|
||||
most_recet_acessed.erase(data_it->second.second);
|
||||
data.erase(data_it);
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
void trim()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
while (most_recet_acessed.size() > mac_allowed_elements)
|
||||
{
|
||||
auto data_it = data.find(most_recet_acessed.back());
|
||||
if (data_it != data.end())
|
||||
data.erase(data_it);
|
||||
most_recet_acessed.erase(--most_recet_acessed.end());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class isolation_lock
|
||||
{
|
||||
private:
|
||||
critical_section m_my_lock;
|
||||
critical_section& m_lock;
|
||||
boost::optional<std::thread::id> m_current_writer_thread;
|
||||
public:
|
||||
isolation_lock() :m_lock(m_my_lock)
|
||||
{}
|
||||
|
||||
isolation_lock(critical_section& lock) :m_lock(lock)
|
||||
{}
|
||||
|
||||
template<typename res_type, typename callback_t>
|
||||
res_type isolated_access(callback_t cb) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if (m_current_writer_thread.is_initialized())
|
||||
{
|
||||
//has writer
|
||||
if (std::this_thread::get_id() != m_current_writer_thread.get())
|
||||
{
|
||||
// cache isolated (not allowed)
|
||||
return cb(false);
|
||||
}
|
||||
}
|
||||
//cache shared(allowed)
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
|
||||
template<typename res_type, typename callback_t>
|
||||
res_type isolated_write_access(callback_t cb) const
|
||||
{
|
||||
return isolated_access<res_type>([&](bool is_allowed_cache)
|
||||
{
|
||||
if (!is_allowed_cache)
|
||||
{
|
||||
ASSERT_MES_AND_THROW("internal error: writer not allowed while it's not in writer transaction");
|
||||
}
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
|
||||
void set_isolation_mode()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
CHECK_AND_ASSERT_THROW_MES(!m_current_writer_thread.is_initialized(), "Isolation mode already enabled for cache");
|
||||
m_current_writer_thread = std::this_thread::get_id();
|
||||
}
|
||||
|
||||
void reset_isolation_mode()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_current_writer_thread.is_initialized(), "Isolation mode already disable for cache");
|
||||
m_current_writer_thread = boost::optional<std::thread::id>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<bool is_ordered_container, typename t_key, typename t_value, uint64_t max_elements>
|
||||
class cache_with_write_isolation : public cache_base<is_ordered_container, t_key, t_value, max_elements>
|
||||
{
|
||||
typedef cache_base<is_ordered_container, t_key, t_value, max_elements> base_class;
|
||||
isolation_lock& m_isolation;
|
||||
public:
|
||||
cache_with_write_isolation(isolation_lock& isolation) : m_isolation(isolation)
|
||||
{}
|
||||
|
||||
bool get(const t_key& k, t_value& v)
|
||||
{
|
||||
return m_isolation.isolated_access<bool>([&](bool allowed_cache)
|
||||
{
|
||||
if (allowed_cache)
|
||||
return base_class::get(k, v);
|
||||
else
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
bool set(const t_key& k, const t_value& v)
|
||||
{
|
||||
return m_isolation.isolated_access<bool>([&] (bool cache_allowed)
|
||||
{
|
||||
if (cache_allowed)
|
||||
return base_class::set(k, v);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_isolation.isolated_access<bool>([&](bool cache_allowed)
|
||||
{
|
||||
if (cache_allowed)
|
||||
base_class::clear();
|
||||
return true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
bool erase(const t_key& k)
|
||||
{
|
||||
return m_isolation.isolated_write_access<bool>([&](){return base_class::erase(k); });
|
||||
}
|
||||
};
|
||||
|
||||
template<bool is_ordered_container, typename t_key, typename t_value, uint64_t max_elements>
|
||||
class cache_dummy : public cache_base<is_ordered_container, t_key, t_value, max_elements>
|
||||
{
|
||||
typedef cache_base<is_ordered_container, t_key, t_value, max_elements> base_class;
|
||||
isolation_lock& m_isolation;
|
||||
public:
|
||||
cache_dummy(isolation_lock& isolation) : m_isolation(isolation){}
|
||||
bool get(const t_key& k, t_value& v){return false;}
|
||||
bool set(const t_key& k, const t_value& v){return true;}
|
||||
void clear(){}
|
||||
bool erase(const t_key& k){return true;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
528
src/contrib/epee/include/console_handler.h
Normal file
528
src/contrib/epee/include/console_handler.h
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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>
|
||||
|
||||
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"))
|
||||
{
|
||||
cmd_handler(command);
|
||||
continue_handle = false;
|
||||
}else if (!command.compare(0, 7, "set_log"))
|
||||
{
|
||||
//parse set_log command
|
||||
static const std::string command_wrong_syntax = "set_log: wrong syntax, usage: set_log log_level_number | log_channel_name_1,log_channel_name_2,... 0|1";
|
||||
std::string args = epee::string_tools::trim(command.substr(7));
|
||||
if (args.empty())
|
||||
{
|
||||
std::set<std::string>& enabled_channels = epee::log_space::log_singletone::get_enabled_channels();
|
||||
std::cout << "current log level: " << log_space::get_set_log_detalisation_level() << ", enabled channels: ";
|
||||
for(auto& channel : enabled_channels)
|
||||
std::cout << channel << " ";
|
||||
std::cout << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t args_space_pos = args.find(' ');
|
||||
if (args_space_pos != std::string::npos)
|
||||
{
|
||||
// channel enabling / disabling
|
||||
std::string channel_str = args.substr(0, args_space_pos);
|
||||
std::string value_str = args.substr(args_space_pos + 1);
|
||||
if (channel_str.empty() || value_str.empty())
|
||||
{
|
||||
std::cout << command_wrong_syntax << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool multi_channels = channel_str.find_first_of(",;:") != std::string::npos;
|
||||
|
||||
if (value_str == "1" || value_str == "e" || value_str == "y")
|
||||
if (multi_channels)
|
||||
epee::log_space::log_singletone::enable_channels(channel_str);
|
||||
else
|
||||
epee::log_space::log_singletone::enable_channel(channel_str);
|
||||
else
|
||||
if (multi_channels)
|
||||
epee::log_space::log_singletone::disable_channels(channel_str);
|
||||
else
|
||||
epee::log_space::log_singletone::disable_channel(channel_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
// log level set
|
||||
uint16_t n = 0;
|
||||
if(!string_tools::get_xtype_from_string(n, args))
|
||||
{
|
||||
std::cout << command_wrong_syntax << std::endl;
|
||||
continue;
|
||||
}
|
||||
uint16_t previous_log_level = log_space::get_set_log_detalisation_level();
|
||||
log_space::get_set_log_detalisation_level(true, n);
|
||||
if (n < LOG_LEVEL_2)
|
||||
std::cout << "log level: " << previous_log_level << " -> " << n << std::endl;
|
||||
LOG_PRINT_L2("log level: " << previous_log_level << " -> " << n);
|
||||
}
|
||||
|
||||
if (args.empty())
|
||||
{
|
||||
std::cout << "wrong syntax: " << command << std::endl << "use set_log n" << std::endl;
|
||||
continue;
|
||||
}
|
||||
}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>();
|
||||
boost::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, boost::bind<bool>(no_srv_param_adapter<t_server, t_handler>, _1, _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 = "")
|
||||
{
|
||||
boost::thread( boost::bind(run_default_console_handler_no_srv_param<t_server, t_handler>, ptsrv, handlr, prompt, usage) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*template<class a>
|
||||
bool f(int i, a l)
|
||||
{
|
||||
return true;
|
||||
}*/
|
||||
/*
|
||||
template<class chain_handler>
|
||||
bool default_console_handler2(chain_handler ch_handler, const std::string usage)
|
||||
*/
|
||||
|
||||
|
||||
/*template<class t_handler>
|
||||
bool start_default_console2(t_handler handlr, const std::string& usage = "")
|
||||
{
|
||||
//std::string usage_local = usage;
|
||||
boost::thread( boost::bind(default_console_handler2<t_handler>, handlr, usage) );
|
||||
//boost::function<bool ()> p__ = boost::bind(f<t_handler>, 1, handlr);
|
||||
//boost::function<bool ()> p__ = boost::bind(default_console_handler2<t_handler>, handlr, usage);
|
||||
//boost::thread tr(p__);
|
||||
return true;
|
||||
}*/
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class console_handlers_binder
|
||||
{
|
||||
typedef boost::function<bool (const std::vector<std::string> &)> console_command_handler;
|
||||
typedef std::map<std::string, std::pair<console_command_handler, std::string> > command_handlers_map;
|
||||
std::unique_ptr<boost::thread> m_console_thread;
|
||||
command_handlers_map m_command_handlers;
|
||||
async_console_handler m_console_handler;
|
||||
public:
|
||||
std::string get_usage()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Commands: " << ENDL;
|
||||
size_t max_command_len = 0;
|
||||
for(auto& x:m_command_handlers)
|
||||
if(x.first.size() > max_command_len)
|
||||
max_command_len = x.first.size();
|
||||
|
||||
for(auto& x:m_command_handlers)
|
||||
{
|
||||
ss.width(max_command_len + 3);
|
||||
ss << " " << std::left << x.first << " " << x.second.second << ENDL;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
void set_handler(const std::string& cmd, const console_command_handler& hndlr, const std::string& usage = "")
|
||||
{
|
||||
command_handlers_map::mapped_type & vt = m_command_handlers[cmd];
|
||||
vt.first = hndlr;
|
||||
vt.second = usage;
|
||||
}
|
||||
bool process_command_vec(const std::vector<std::string>& cmd)
|
||||
{
|
||||
if(!cmd.size())
|
||||
return false;
|
||||
auto it = m_command_handlers.find(cmd.front());
|
||||
if(it == m_command_handlers.end())
|
||||
return false;
|
||||
std::vector<std::string> cmd_local(cmd.begin()+1, cmd.end());
|
||||
return it->second.first(cmd_local);
|
||||
}
|
||||
|
||||
bool process_command_str(const std::string& cmd)
|
||||
{
|
||||
std::vector<std::string> cmd_v;
|
||||
boost::split(cmd_v,cmd,boost::is_any_of(" "), boost::token_compress_on);
|
||||
return process_command_vec(cmd_v);
|
||||
}
|
||||
|
||||
/*template<class t_srv>
|
||||
bool start_handling(t_srv& srv, const std::string& usage_string = "")
|
||||
{
|
||||
start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1));
|
||||
return true;
|
||||
}*/
|
||||
|
||||
bool start_handling(const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
m_console_thread.reset(new boost::thread(boost::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(boost::bind(&console_handlers_binder::process_command_str, this, _1), prompt, usage_string);
|
||||
}
|
||||
|
||||
bool help(const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
std::cout << get_usage() << ENDL;
|
||||
return true;
|
||||
}
|
||||
/*template<class t_srv>
|
||||
bool run_handling(t_srv& srv, const std::string& usage_string)
|
||||
{
|
||||
return run_default_console_handler_no_srv_param(&srv, boost::bind<bool>(&console_handlers_binder::process_command_str, this, _1), usage_string);
|
||||
}*/
|
||||
};
|
||||
|
||||
/* work around because of broken boost bind */
|
||||
template<class t_server>
|
||||
class srv_console_handlers_binder: public console_handlers_binder
|
||||
{
|
||||
bool process_command_str(t_server* /*psrv*/, const std::string& cmd)
|
||||
{
|
||||
return console_handlers_binder::process_command_str(cmd);
|
||||
}
|
||||
public:
|
||||
bool start_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string = "")
|
||||
{
|
||||
boost::thread(boost::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, boost::bind(&srv_console_handlers_binder<t_server>::process_command_str, this, _1, _2), prompt, usage_string);
|
||||
}
|
||||
|
||||
void stop_handling()
|
||||
{
|
||||
m_console_handler.stop();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
async_console_handler m_console_handler;
|
||||
};
|
||||
}
|
||||
54
src/contrib/epee/include/copyable_atomic.h
Normal file
54
src/contrib/epee/include/copyable_atomic.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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);
|
||||
}
|
||||
};
|
||||
}
|
||||
570
src/contrib/epee/include/file_io_utils.h
Normal file
570
src/contrib/epee/include/file_io_utils.h
Normal file
|
|
@ -0,0 +1,570 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#ifndef _FILE_IO_UTILS_H_
|
||||
#define _FILE_IO_UTILS_H_
|
||||
|
||||
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.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
|
||||
|
||||
#ifndef WIN32
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#include "include_base_utils.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace file_io_utils
|
||||
{
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
|
||||
inline
|
||||
std::string get_temp_file_name_a()
|
||||
{
|
||||
std::string str_result;
|
||||
char sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
|
||||
return str_result;
|
||||
|
||||
char sz_temp_file[MAX_PATH*2] = {0};
|
||||
if(!::GetTempFileNameA( sz_temp, "mail", 0, sz_temp_file))
|
||||
return str_result;
|
||||
sz_temp_file[sizeof(sz_temp_file)-1] = 0; //be happy!
|
||||
str_result = sz_temp_file;
|
||||
return str_result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_LEXICAL_CAST_INCLUDED
|
||||
inline
|
||||
bool get_not_used_filename(const std::string& folder, OUT std::string& result_name)
|
||||
{
|
||||
DWORD folder_attr = ::GetFileAttributesA(folder.c_str());
|
||||
if(folder_attr == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
if(!(folder_attr&FILE_ATTRIBUTE_DIRECTORY))
|
||||
return false;
|
||||
|
||||
|
||||
std::string base_name = folder + "\\tmp";
|
||||
std::string tmp_name;
|
||||
bool name_found = false;
|
||||
int current_index = 0;
|
||||
tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
|
||||
while(!name_found)
|
||||
{
|
||||
if(INVALID_FILE_ATTRIBUTES == ::GetFileAttributesA(tmp_name.c_str()))
|
||||
name_found = true;
|
||||
else
|
||||
{
|
||||
current_index++;
|
||||
tmp_name = base_name + boost::lexical_cast<std::string>(current_index) + ".tmp";
|
||||
}
|
||||
}
|
||||
result_name = tmp_name;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline
|
||||
std::string get_temp_folder_a()
|
||||
{
|
||||
std::string str_result;
|
||||
char sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathA( sizeof( sz_temp ), sz_temp ))
|
||||
return str_result;
|
||||
sz_temp[(sizeof(sz_temp)/sizeof(sz_temp[0])) -1] = 0;
|
||||
str_result = sz_temp;
|
||||
return str_result;
|
||||
}
|
||||
|
||||
std::string convert_from_device_path_to_standart(const std::string& path)
|
||||
{
|
||||
|
||||
|
||||
STRSAFE_LPSTR pszFilename = (STRSAFE_LPSTR)path.c_str();
|
||||
|
||||
// Translate path with device name to drive letters.
|
||||
char szTemp[4000] = {0};
|
||||
|
||||
if (::GetLogicalDriveStringsA(sizeof(szTemp)-1, szTemp))
|
||||
{
|
||||
char szName[MAX_PATH];
|
||||
char szDrive[3] = " :";
|
||||
BOOL bFound = FALSE;
|
||||
char* p = szTemp;
|
||||
|
||||
do
|
||||
{
|
||||
// Copy the drive letter to the template string
|
||||
*szDrive = *p;
|
||||
|
||||
// Look up each device name
|
||||
if (::QueryDosDeviceA(szDrive, szName, sizeof(szName)))
|
||||
{
|
||||
UINT uNameLen = strlen(szName);
|
||||
|
||||
if (uNameLen < MAX_PATH)
|
||||
{
|
||||
bFound = _mbsnbicmp((const unsigned char*)pszFilename, (const unsigned char*)szName,
|
||||
uNameLen) == 0;
|
||||
|
||||
if (bFound)
|
||||
{
|
||||
// Reconstruct pszFilename using szTempFile
|
||||
// Replace device path with DOS path
|
||||
char szTempFile[MAX_PATH] = {0};
|
||||
StringCchPrintfA(szTempFile,
|
||||
MAX_PATH,
|
||||
"%s%s",
|
||||
szDrive,
|
||||
pszFilename+uNameLen);
|
||||
return szTempFile;
|
||||
//::StringCchCopyNA(pszFilename, MAX_PATH+1, szTempFile, strlen(szTempFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go to the next NULL character.
|
||||
while (*p++);
|
||||
} while (!bFound && *p); // end of string
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
inline
|
||||
std::string get_process_path_by_pid(DWORD pid)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
HANDLE hprocess = 0;
|
||||
if( hprocess = ::OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pid) )
|
||||
{
|
||||
char buff[MAX_PATH]= {0};
|
||||
if(!::GetModuleFileNameExA( hprocess, 0, buff, MAX_PATH - 1 ))
|
||||
res = "Unknown_b";
|
||||
else
|
||||
{
|
||||
buff[MAX_PATH - 1]=0; //be happy!
|
||||
res = buff;
|
||||
std::string::size_type a = res.rfind( '\\' );
|
||||
if ( a != std::string::npos )
|
||||
res.erase( 0, a+1);
|
||||
|
||||
}
|
||||
::CloseHandle( hprocess );
|
||||
}else
|
||||
res = "Unknown_a";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
std::wstring get_temp_file_name_w()
|
||||
{
|
||||
std::wstring str_result;
|
||||
wchar_t sz_temp[MAX_PATH*2] = {0};
|
||||
if(!::GetTempPathW( sizeof(sz_temp)/sizeof(sz_temp[0]), sz_temp ))
|
||||
return str_result;
|
||||
|
||||
wchar_t sz_temp_file[MAX_PATH+1] = {0};
|
||||
if(!::GetTempFileNameW( sz_temp, L"mail", 0, sz_temp_file))
|
||||
return str_result;
|
||||
|
||||
sz_temp_file[(sizeof(sz_temp_file)/sizeof(sz_temp_file[0]))-1] = 0; //be happy!
|
||||
str_result = sz_temp_file;
|
||||
return str_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class t_string>
|
||||
bool is_file_exist(const t_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;
|
||||
}*/
|
||||
|
||||
|
||||
template<class t_string>
|
||||
bool save_string_to_file_throw(const t_string& path_to_file, const std::string& str)
|
||||
{
|
||||
//std::ofstream fstream;
|
||||
boost::filesystem::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;
|
||||
}
|
||||
|
||||
template<class t_string>
|
||||
bool save_string_to_file(const t_string& path_to_file, const std::string& str)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
return save_string_to_file_throw(path_to_file, str);
|
||||
}
|
||||
catch (const std::exception& /*ex*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
inline
|
||||
bool load_form_handle(HANDLE hfile, std::string& str)
|
||||
{
|
||||
if( INVALID_HANDLE_VALUE != hfile )
|
||||
{
|
||||
bool res = true;
|
||||
DWORD dw = 0;
|
||||
DWORD fsize = ::GetFileSize(hfile, &dw);
|
||||
if(fsize > 300000000)
|
||||
{
|
||||
::CloseHandle(hfile);
|
||||
return false;
|
||||
}
|
||||
if(fsize)
|
||||
{
|
||||
str.resize(fsize);
|
||||
if(!::ReadFile( hfile, (LPVOID)str.data(), (DWORD)str.size(), &dw, NULL))
|
||||
res = false;
|
||||
}
|
||||
::CloseHandle(hfile);
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
inline
|
||||
bool get_file_time(const std::string& path_to_file, OUT time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
ft = boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ec);
|
||||
if(!ec)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
bool set_file_time(const std::string& path_to_file, const time_t& ft)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::last_write_time(boost::filesystem::path(path_to_file), ft, ec);
|
||||
if(!ec)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
bool load_file_to_string(const std::string& path_to_file, std::string& target_str)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ifstream fstream;
|
||||
//fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file, std::ios_base::binary | std::ios_base::in | std::ios::ate);
|
||||
if (!fstream.good())
|
||||
return false;
|
||||
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());
|
||||
if (!fstream.good())
|
||||
return false;
|
||||
|
||||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
typedef HANDLE native_filesystem_handle;
|
||||
#else
|
||||
typedef int native_filesystem_handle;
|
||||
#endif
|
||||
|
||||
inline bool open_and_lock_file(const std::string file_path, native_filesystem_handle& h_file)
|
||||
{
|
||||
#ifdef WIN32
|
||||
h_file = ::CreateFileA(file_path.c_str(), // name of the write
|
||||
GENERIC_WRITE, // open for writing
|
||||
0, // do not share
|
||||
NULL, // default security
|
||||
OPEN_ALWAYS, // create new file only
|
||||
FILE_ATTRIBUTE_NORMAL, // normal file
|
||||
NULL); // no attr. template
|
||||
if (h_file == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
#else
|
||||
h_file = open(file_path.c_str(), O_RDWR | O_CREAT, 0666); // open or create lockfile
|
||||
if (h_file < 0)
|
||||
return false;
|
||||
//check open success...
|
||||
int rc = flock(h_file, LOCK_EX | LOCK_NB); // grab exclusive lock, fail if can't obtain.
|
||||
if (rc < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool unlock_and_close_file(native_filesystem_handle& h_file)
|
||||
{
|
||||
#ifdef WIN32
|
||||
::CloseHandle(h_file); // no attr. template
|
||||
#else
|
||||
flock(h_file, LOCK_UN); // grab exclusive lock, fail if can't obtain.
|
||||
close(h_file);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
bool load_last_n_from_file_to_string(const std::string& path_to_file, uint64_t size_to_load, 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);
|
||||
if (!fstream.good())
|
||||
return false;
|
||||
std::ifstream::pos_type file_size = fstream.tellg();
|
||||
|
||||
uint64_t size_to_load_to_buff = file_size;
|
||||
if (static_cast<uint64_t>(file_size) > size_to_load)
|
||||
{
|
||||
fstream.seekg(size_to_load_to_buff - size_to_load, std::ios::beg);
|
||||
size_to_load_to_buff = size_to_load;
|
||||
}else
|
||||
{
|
||||
fstream.seekg(0, std::ios::beg);
|
||||
}
|
||||
|
||||
size_t size_to_load_to_buff_t = static_cast<size_t>(size_to_load_to_buff);
|
||||
|
||||
target_str.resize(size_to_load_to_buff_t);
|
||||
|
||||
|
||||
fstream.read((char*)target_str.data(), target_str.size());
|
||||
if (!fstream.good())
|
||||
return false;
|
||||
|
||||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
bool copy_file(const std::string& source, const std::string& destination)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::copy_file(source, destination, ec);
|
||||
if (ec)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
inline
|
||||
bool append_string_to_file(const std::string& path_to_file, const std::string& str)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::ofstream fstream;
|
||||
fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
fstream.open(path_to_file.c_str(), std::ios_base::binary | std::ios_base::out | std::ios_base::app);
|
||||
fstream << str;
|
||||
fstream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool remove_dir_and_subirs(const char* path_to_dir);
|
||||
|
||||
inline
|
||||
bool clean_dir(const char* path_to_dir)
|
||||
{
|
||||
if(!path_to_dir)
|
||||
return false;
|
||||
|
||||
std::string folder = path_to_dir;
|
||||
WIN32_FIND_DATAA find_data = {0};
|
||||
HANDLE hfind = ::FindFirstFileA((folder + "\\*.*").c_str(), &find_data);
|
||||
if(INVALID_HANDLE_VALUE == hfind)
|
||||
return false;
|
||||
do{
|
||||
if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
|
||||
continue;
|
||||
|
||||
if(find_data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if(!remove_dir_and_subirs((folder + "\\" + find_data.cFileName).c_str()))
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
if(!::DeleteFileA((folder + "\\" + find_data.cFileName).c_str()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}while(::FindNextFileA(hfind, &find_data));
|
||||
::FindClose(hfind);
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
#ifdef WINDOWS_PLATFORM
|
||||
inline bool get_folder_content(const std::string& path, std::list<WIN32_FIND_DATAA>& OUT target_list)
|
||||
{
|
||||
WIN32_FIND_DATAA find_data = {0};
|
||||
HANDLE hfind = ::FindFirstFileA((path + "\\*.*").c_str(), &find_data);
|
||||
if(INVALID_HANDLE_VALUE == hfind)
|
||||
return false;
|
||||
do{
|
||||
if(!strcmp("..", find_data.cFileName) || (!strcmp(".", find_data.cFileName)))
|
||||
continue;
|
||||
|
||||
target_list.push_back(find_data);
|
||||
|
||||
}while(::FindNextFileA(hfind, &find_data));
|
||||
::FindClose(hfind);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
inline bool get_folder_content(const std::string& path, std::list<std::string>& OUT target_list, bool only_files = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( boost::filesystem::directory_iterator itr( path ); itr != end_itr; ++itr )
|
||||
{
|
||||
if ( only_files && boost::filesystem::is_directory(itr->status()) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
target_list.push_back(itr->path().filename().string());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
catch(...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_FILE_IO_UTILS_H_
|
||||
35
src/contrib/epee/include/global_stream_operators.h
Normal file
35
src/contrib/epee/include/global_stream_operators.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
std::stringstream& operator<<(std::stringstream& out, const std::wstring& ws)
|
||||
{
|
||||
std::string as = string_encoding::convert_to_ansii(ws);
|
||||
out << as;
|
||||
return out;
|
||||
}
|
||||
227
src/contrib/epee/include/gzip_encoding.h
Normal file
227
src/contrib/epee/include/gzip_encoding.h
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef _GZIP_ENCODING_H_
|
||||
#define _GZIP_ENCODING_H_
|
||||
#include "net/http_client_base.h"
|
||||
#include "zlib/zlib.h"
|
||||
//#include "http.h"
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
|
||||
|
||||
|
||||
class content_encoding_gzip: public i_sub_handler
|
||||
{
|
||||
public:
|
||||
/*! \brief
|
||||
* Function content_encoding_gzip : Constructor
|
||||
*
|
||||
*/
|
||||
inline
|
||||
content_encoding_gzip(i_target_handler* powner_filter, bool is_deflate_mode = false):m_powner_filter(powner_filter),
|
||||
m_is_stream_ended(false),
|
||||
m_is_deflate_mode(is_deflate_mode),
|
||||
m_is_first_update_in(true)
|
||||
{
|
||||
memset(&m_zstream_in, 0, sizeof(m_zstream_in));
|
||||
memset(&m_zstream_out, 0, sizeof(m_zstream_out));
|
||||
int ret = 0;
|
||||
if(is_deflate_mode)
|
||||
{
|
||||
ret = inflateInit(&m_zstream_in);
|
||||
ret = deflateInit(&m_zstream_out, Z_DEFAULT_COMPRESSION);
|
||||
}else
|
||||
{
|
||||
ret = inflateInit2(&m_zstream_in, 0x1F);
|
||||
ret = deflateInit2(&m_zstream_out, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8, Z_DEFAULT_STRATEGY);
|
||||
}
|
||||
}
|
||||
/*! \brief
|
||||
* Function content_encoding_gzip : Destructor
|
||||
*
|
||||
*/
|
||||
inline
|
||||
~content_encoding_gzip()
|
||||
{
|
||||
inflateEnd(& m_zstream_in );
|
||||
deflateEnd(& m_zstream_out );
|
||||
}
|
||||
/*! \brief
|
||||
* Function update_in : Entry point for income data
|
||||
*
|
||||
*/
|
||||
inline
|
||||
virtual bool update_in( std::string& piece_of_transfer)
|
||||
{
|
||||
|
||||
bool is_first_time_here = m_is_first_update_in;
|
||||
m_is_first_update_in = false;
|
||||
|
||||
if(m_pre_decode.size())
|
||||
m_pre_decode += piece_of_transfer;
|
||||
else
|
||||
m_pre_decode.swap(piece_of_transfer);
|
||||
piece_of_transfer.clear();
|
||||
|
||||
std::string decode_summary_buff;
|
||||
|
||||
size_t ungzip_size = m_pre_decode.size() * 0x30;
|
||||
std::string current_decode_buff(ungzip_size, 'X');
|
||||
|
||||
//Here the cycle is introduced where we unpack the buffer, the cycle is required
|
||||
//because of the case where if after unpacking the data will exceed the awaited size, we will not halt with error
|
||||
bool continue_unpacking = true;
|
||||
bool first_step = true;
|
||||
while(m_pre_decode.size() && continue_unpacking)
|
||||
{
|
||||
|
||||
//fill buffers
|
||||
m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
|
||||
m_zstream_in.avail_in = (uInt)m_pre_decode.size();
|
||||
m_zstream_in.next_out = (Bytef*)current_decode_buff.data();
|
||||
m_zstream_in.avail_out = (uInt)ungzip_size;
|
||||
|
||||
int flag = Z_SYNC_FLUSH;
|
||||
int ret = inflate(&m_zstream_in, flag);
|
||||
CHECK_AND_ASSERT_MES(ret>=0 || m_zstream_in.avail_out ||m_is_deflate_mode, false, "content_encoding_gzip::update_in() Failed to inflate. err = " << ret);
|
||||
|
||||
if(Z_STREAM_END == ret)
|
||||
m_is_stream_ended = true;
|
||||
else if(Z_DATA_ERROR == ret && is_first_time_here && m_is_deflate_mode&& first_step)
|
||||
{
|
||||
// some servers (notably Apache with mod_deflate) don't generate zlib headers
|
||||
// insert a dummy header and try again
|
||||
static char dummy_head[2] =
|
||||
{
|
||||
0x8 + 0x7 * 0x10,
|
||||
(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
|
||||
};
|
||||
inflateReset(&m_zstream_in);
|
||||
m_zstream_in.next_in = (Bytef*) dummy_head;
|
||||
m_zstream_in.avail_in = sizeof(dummy_head);
|
||||
|
||||
ret = inflate(&m_zstream_in, Z_NO_FLUSH);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
LOCAL_ASSERT(0);
|
||||
m_pre_decode.swap(piece_of_transfer);
|
||||
return false;
|
||||
}
|
||||
m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
|
||||
m_zstream_in.avail_in = (uInt)m_pre_decode.size();
|
||||
|
||||
ret = inflate(&m_zstream_in, Z_NO_FLUSH);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
LOCAL_ASSERT(0);
|
||||
m_pre_decode.swap(piece_of_transfer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//leave only unpacked part in the output buffer to start with it the next time
|
||||
m_pre_decode.erase(0, m_pre_decode.size()-m_zstream_in.avail_in);
|
||||
//if decoder gave nothing to return, then everything is ahead, now simply break
|
||||
if(ungzip_size == m_zstream_in.avail_out)
|
||||
break;
|
||||
|
||||
//decode_buff currently stores data parts that were unpacked, fix this size
|
||||
current_decode_buff.resize(ungzip_size - m_zstream_in.avail_out);
|
||||
if(decode_summary_buff.size())
|
||||
decode_summary_buff += current_decode_buff;
|
||||
else
|
||||
current_decode_buff.swap(decode_summary_buff);
|
||||
|
||||
current_decode_buff.resize(ungzip_size);
|
||||
first_step = false;
|
||||
}
|
||||
|
||||
//Process these data if required
|
||||
bool res = true;
|
||||
|
||||
res = m_powner_filter->handle_target_data(decode_summary_buff);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
/*! \brief
|
||||
* Function stop : Entry point for stop signal and flushing cached data buffer.
|
||||
*
|
||||
*/
|
||||
inline
|
||||
virtual void stop(std::string& OUT collect_remains)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
private:
|
||||
/*! \brief
|
||||
* Pointer to parent HTTP-parser
|
||||
*/
|
||||
i_target_handler* m_powner_filter;
|
||||
/*! \brief
|
||||
* ZLIB object for income stream
|
||||
*/
|
||||
z_stream m_zstream_in;
|
||||
/*! \brief
|
||||
* ZLIB object for outcome stream
|
||||
*/
|
||||
z_stream m_zstream_out;
|
||||
/*! \brief
|
||||
* Data that could not be unpacked immediately, left to wait for the next packet of data
|
||||
*/
|
||||
std::string m_pre_decode;
|
||||
/*! \brief
|
||||
* The data are accumulated for a package in the buffer to send the web client
|
||||
*/
|
||||
std::string m_pre_encode;
|
||||
/*! \brief
|
||||
* Signals that stream looks like ended
|
||||
*/
|
||||
bool m_is_stream_ended;
|
||||
/*! \brief
|
||||
* If this flag is set, income data is in HTTP-deflate mode
|
||||
*/
|
||||
bool m_is_deflate_mode;
|
||||
/*! \brief
|
||||
* Marks that it is a first data packet
|
||||
*/
|
||||
bool m_is_first_update_in;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //_GZIP_ENCODING_H_
|
||||
93
src/contrib/epee/include/hmac-md5.h
Normal file
93
src/contrib/epee/include/hmac-md5.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* hmac-md5.h -- HMAC_MD5 functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: hmac-md5.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
|
||||
*/
|
||||
|
||||
#ifndef HMAC_MD5_H
|
||||
#define HMAC_MD5_H 1
|
||||
|
||||
namespace md5
|
||||
{
|
||||
|
||||
|
||||
|
||||
#define HMAC_MD5_SIZE 16
|
||||
|
||||
/* intermediate MD5 context */
|
||||
typedef struct HMAC_MD5_CTX_s {
|
||||
MD5_CTX ictx, octx;
|
||||
} HMAC_MD5_CTX;
|
||||
|
||||
/* intermediate HMAC state
|
||||
* values stored in network byte order (Big Endian)
|
||||
*/
|
||||
typedef struct HMAC_MD5_STATE_s {
|
||||
UINT4 istate[4];
|
||||
UINT4 ostate[4];
|
||||
} HMAC_MD5_STATE;
|
||||
|
||||
/* One step hmac computation
|
||||
*
|
||||
* digest may be same as text or key
|
||||
*/
|
||||
void hmac_md5(const unsigned char *text, int text_len,
|
||||
const unsigned char *key, int key_len,
|
||||
unsigned char digest[HMAC_MD5_SIZE]);
|
||||
|
||||
/* create context from key
|
||||
*/
|
||||
void hmac_md5_init(HMAC_MD5_CTX *hmac,
|
||||
const unsigned char *key, int key_len);
|
||||
|
||||
/* precalculate intermediate state from key
|
||||
*/
|
||||
void hmac_md5_precalc(HMAC_MD5_STATE *hmac,
|
||||
const unsigned char *key, int key_len);
|
||||
|
||||
/* initialize context from intermediate state
|
||||
*/
|
||||
void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);
|
||||
|
||||
#define hmac_md5_update(hmac, text, text_len) MD5Update(&(hmac)->ictx, (text), (text_len))
|
||||
|
||||
/* finish hmac from intermediate result. Intermediate result is zeroed.
|
||||
*/
|
||||
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
|
||||
HMAC_MD5_CTX *hmac);
|
||||
|
||||
}
|
||||
|
||||
#endif /* HMAC_MD5_H */
|
||||
34
src/contrib/epee/include/include_base_utils.h
Normal file
34
src/contrib/epee/include/include_base_utils.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BOOST_FILESYSTEM_VERSION 3
|
||||
#define ENABLE_RELEASE_LOGGING
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
|
||||
|
||||
271
src/contrib/epee/include/math_helper.h
Normal file
271
src/contrib/epee/include/math_helper.h
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <list>
|
||||
#include <numeric>
|
||||
#include <boost/timer.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
|
||||
#include "misc_os_dependent.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace math_helper
|
||||
{
|
||||
|
||||
template<typename val, int default_base>
|
||||
class average
|
||||
{
|
||||
public:
|
||||
|
||||
average()
|
||||
{
|
||||
m_base = default_base;
|
||||
}
|
||||
|
||||
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() const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL( static_cast<critical_section&>(m_lock));
|
||||
|
||||
value_type vl = std::accumulate(m_list.begin(), m_list.end(), value_type(0));
|
||||
if(m_list.size())
|
||||
return (double)(vl/m_list.size());
|
||||
|
||||
return (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;
|
||||
std::list<value_type> m_list;
|
||||
mutable 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);
|
||||
}
|
||||
|
||||
}
|
||||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(strict-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]));
|
||||
}
|
||||
POP_WARNINGS
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
97
src/contrib/epee/include/md5_l.h
Normal file
97
src/contrib/epee/include/md5_l.h
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: md5.h,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
|
||||
*/
|
||||
|
||||
/* MD5.H - header file for MD5C.C
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
|
||||
#include "md5global.h"
|
||||
|
||||
namespace md5
|
||||
{
|
||||
/* MD5 context. */
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
static void MD5Init(MD5_CTX * context);
|
||||
static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen );
|
||||
static void MD5Final ( unsigned char digest[16], MD5_CTX *context );
|
||||
static void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest);
|
||||
|
||||
|
||||
inline bool md5( unsigned char *input, int ilen, unsigned char output[16] )
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
|
||||
MD5Init( &ctx );
|
||||
MD5Update( &ctx, input, ilen );
|
||||
MD5Final( output, &ctx);
|
||||
|
||||
memset( &ctx, 0, sizeof( MD5_CTX) );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include "md5_l.inl"
|
||||
|
||||
#endif
|
||||
563
src/contrib/epee/include/md5_l.inl
Normal file
563
src/contrib/epee/include/md5_l.inl
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: md5.c,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
|
||||
*/
|
||||
|
||||
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
/* do i need all of this just for htonl()? damn. */
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/param.h>
|
||||
//#include <sys/socket.h>
|
||||
//#include <netinet/in.h>
|
||||
|
||||
|
||||
|
||||
#include "md5global.h"
|
||||
#include "md5_l.h"
|
||||
#include "hmac-md5.h"
|
||||
|
||||
namespace md5
|
||||
{
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
/*
|
||||
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
|
||||
static void Encode PROTO_LIST
|
||||
((unsigned char *, UINT4 *, unsigned int));
|
||||
static void Decode PROTO_LIST
|
||||
((UINT4 *, unsigned char *, unsigned int));
|
||||
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
|
||||
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
|
||||
*/
|
||||
|
||||
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
|
||||
static void MD5_memset (POINTER output, int value, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *)output)[i] = (char)value;
|
||||
}
|
||||
|
||||
static void MD5Transform (UINT4 state[4], unsigned char block[64]);
|
||||
|
||||
static unsigned char* PADDING()
|
||||
{
|
||||
static unsigned char local_PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
return local_PADDING;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
|
||||
*/
|
||||
#ifdef I
|
||||
/* This might be defined via NANA */
|
||||
#undef I
|
||||
#endif
|
||||
|
||||
#define MD5_M_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define MD5_M_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define MD5_M_H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define MD5_M_I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
|
||||
*/
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
|
||||
#define FF(a, b, c, d, x, s, ac) { (a) += MD5_M_F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
|
||||
#define GG(a, b, c, d, x, s, ac) { (a) += MD5_M_G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
|
||||
#define HH(a, b, c, d, x, s, ac) { (a) += MD5_M_H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
|
||||
#define II(a, b, c, d, x, s, ac) { (a) += MD5_M_I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
|
||||
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
|
||||
static void MD5Init(MD5_CTX * context)
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
|
||||
/* Load magic initialization constants.
|
||||
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
operation, processing another message block, and updating the context.
|
||||
*/
|
||||
|
||||
static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen )
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||
< ((UINT4)inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.
|
||||
|
||||
*/
|
||||
if (inputLen >= partLen)
|
||||
{
|
||||
MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)input, partLen );
|
||||
MD5Transform( context->state, context->buffer );
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context->state, (unsigned char*)&input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i );
|
||||
|
||||
}
|
||||
|
||||
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
a multiple of 4.
|
||||
|
||||
*/
|
||||
|
||||
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
a multiple of 4.
|
||||
|
||||
*/
|
||||
|
||||
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16)
|
||||
| (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
the message digest and zeroizing the context.
|
||||
|
||||
*/
|
||||
|
||||
static void MD5Final ( unsigned char digest[16], MD5_CTX *context )
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
|
||||
*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (context, PADDING(), padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (context, bits, 8);
|
||||
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
|
||||
*/
|
||||
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
||||
}
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
|
||||
*/
|
||||
|
||||
static void MD5Transform (UINT4 state[4], unsigned char block[64])
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||
|
||||
*/
|
||||
inline
|
||||
void hmac_md5_init(HMAC_MD5_CTX *hmac,
|
||||
const unsigned char *key,
|
||||
int key_len)
|
||||
{
|
||||
unsigned char k_ipad[65]; /* inner padding -
|
||||
* key XORd with ipad
|
||||
*/
|
||||
unsigned char k_opad[65]; /* outer padding -
|
||||
* key XORd with opad
|
||||
*/
|
||||
unsigned char tk[16];
|
||||
int i;
|
||||
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||
if (key_len > 64) {
|
||||
|
||||
MD5_CTX tctx;
|
||||
|
||||
MD5Init(&tctx);
|
||||
MD5Update(&tctx, key, key_len);
|
||||
MD5Final(tk, &tctx);
|
||||
|
||||
key = tk;
|
||||
key_len = 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected
|
||||
*/
|
||||
|
||||
/* start out by storing key in pads */
|
||||
MD5_memset(k_ipad, '\0', sizeof k_ipad);
|
||||
MD5_memset(k_opad, '\0', sizeof k_opad);
|
||||
MD5_memcpy( k_ipad, (POINTER)key, key_len);
|
||||
MD5_memcpy( k_opad, (POINTER)key, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i=0; i<64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
MD5Init(&hmac->ictx); /* init inner context */
|
||||
MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
|
||||
|
||||
MD5Init(&hmac->octx); /* init outer context */
|
||||
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
|
||||
|
||||
/* scrub the pads and key context (if used) */
|
||||
MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
|
||||
MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
|
||||
MD5_memset( (POINTER)&tk, 0, sizeof(tk));
|
||||
|
||||
/* and we're done. */
|
||||
}
|
||||
|
||||
/* The precalc and import routines here rely on the fact that we pad
|
||||
* the key out to 64 bytes and use that to initialize the md5
|
||||
* contexts, and that updating an md5 context with 64 bytes of data
|
||||
* leaves nothing left over; all of the interesting state is contained
|
||||
* in the state field, and none of it is left over in the count and
|
||||
* buffer fields. So all we have to do is save the state field; we
|
||||
* can zero the others when we reload it. Which is why the decision
|
||||
* was made to pad the key out to 64 bytes in the first place. */
|
||||
inline
|
||||
void hmac_md5_precalc(HMAC_MD5_STATE *state,
|
||||
const unsigned char *key,
|
||||
int key_len)
|
||||
{
|
||||
HMAC_MD5_CTX hmac;
|
||||
unsigned lupe;
|
||||
|
||||
hmac_md5_init(&hmac, key, key_len);
|
||||
for (lupe = 0; lupe < 4; lupe++) {
|
||||
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
|
||||
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
|
||||
}
|
||||
MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void hmac_md5_import(HMAC_MD5_CTX *hmac,
|
||||
HMAC_MD5_STATE *state)
|
||||
{
|
||||
unsigned lupe;
|
||||
MD5_memset( (POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
|
||||
for (lupe = 0; lupe < 4; lupe++) {
|
||||
hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
|
||||
hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
|
||||
}
|
||||
/* Init the counts to account for our having applied
|
||||
* 64 bytes of key; this works out to 0x200 (64 << 3; see
|
||||
* MD5Update above...) */
|
||||
hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
|
||||
}
|
||||
|
||||
inline
|
||||
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
|
||||
HMAC_MD5_CTX *hmac)
|
||||
{
|
||||
MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
|
||||
MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
|
||||
MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
|
||||
}
|
||||
|
||||
|
||||
void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest)
|
||||
{
|
||||
MD5_CTX context;
|
||||
|
||||
unsigned char k_ipad[65]; /* inner padding -
|
||||
* key XORd with ipad
|
||||
*/
|
||||
unsigned char k_opad[65]; /* outer padding -
|
||||
* key XORd with opad
|
||||
*/
|
||||
unsigned char tk[16];
|
||||
int i;
|
||||
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||
if (key_len > 64) {
|
||||
|
||||
MD5_CTX tctx;
|
||||
|
||||
MD5Init(&tctx);
|
||||
MD5Update(&tctx, key, key_len);
|
||||
MD5Final(tk, &tctx);
|
||||
|
||||
key = tk;
|
||||
key_len = 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected
|
||||
*/
|
||||
|
||||
/* start out by storing key in pads */
|
||||
MD5_memset(k_ipad, '\0', sizeof k_ipad);
|
||||
MD5_memset(k_opad, '\0', sizeof k_opad);
|
||||
MD5_memcpy( k_ipad, (POINTER)key, key_len);
|
||||
MD5_memcpy( k_opad, (POINTER)key, key_len);
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i=0; i<64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
/*
|
||||
* perform inner MD5
|
||||
*/
|
||||
|
||||
MD5Init(&context); /* init context for 1st
|
||||
* pass */
|
||||
MD5Update(&context, k_ipad, 64); /* start with inner pad */
|
||||
MD5Update(&context, text, text_len); /* then text of datagram */
|
||||
MD5Final(digest, &context); /* finish up 1st pass */
|
||||
|
||||
/*
|
||||
* perform outer MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 2nd
|
||||
* pass */
|
||||
MD5Update(&context, k_opad, 64); /* start with outer pad */
|
||||
MD5Update(&context, digest, 16); /* then results of 1st
|
||||
* hash */
|
||||
MD5Final(digest, &context); /* finish up 2nd pass */
|
||||
|
||||
}
|
||||
}
|
||||
77
src/contrib/epee/include/md5global.h
Normal file
77
src/contrib/epee/include/md5global.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* libEtPan! -- a mail stuff library
|
||||
*
|
||||
* Copyright (C) 2001, 2005 - DINH Viet Hoa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the libEtPan! project nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Id: md5global.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
|
||||
*/
|
||||
|
||||
/* GLOBAL.H - RSAREF types and constants
|
||||
*/
|
||||
|
||||
#ifndef MD5GLOBAL_H
|
||||
#define MD5GLOBAL_H
|
||||
|
||||
namespace md5
|
||||
{
|
||||
|
||||
|
||||
/* PROTOTYPES should be set to one if and only if the compiler supports
|
||||
function argument prototyping.
|
||||
The following makes PROTOTYPES default to 0 if it has not already
|
||||
been defined with C compiler flags.
|
||||
*/
|
||||
#ifndef PROTOTYPES
|
||||
#define PROTOTYPES 0
|
||||
#endif
|
||||
|
||||
/* POINTER defines a generic pointer type */
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
typedef unsigned short int UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
//typedef unsigned long int UINT4;
|
||||
typedef unsigned int UINT4;
|
||||
|
||||
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||
returns an empty list.
|
||||
*/
|
||||
#if PROTOTYPES
|
||||
#define PROTO_LIST(list) list
|
||||
#else
|
||||
#define PROTO_LIST(list) ()
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
432
src/contrib/epee/include/misc_language.h
Normal file
432
src/contrib/epee/include/misc_language.h
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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 <set>
|
||||
#include <iterator>
|
||||
#include <boost/thread.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "auto_val_init.h"
|
||||
|
||||
|
||||
#define MARK_AS_POD_C11(type) \
|
||||
namespace std \
|
||||
{ \
|
||||
template<> \
|
||||
struct is_pod< type > \
|
||||
{ \
|
||||
static const bool value = true; \
|
||||
}; \
|
||||
}
|
||||
|
||||
|
||||
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; \
|
||||
}
|
||||
|
||||
|
||||
/* helper class, to make able get namespace via decltype()::*/
|
||||
template<class base_class>
|
||||
class namespace_accessor: public base_class{};
|
||||
|
||||
|
||||
#define STRINGIFY_EXPAND(s) STRINGIFY(s)
|
||||
#define STRINGIFY(s) #s
|
||||
|
||||
|
||||
|
||||
namespace misc_utils
|
||||
{
|
||||
template<typename t_type>
|
||||
t_type get_max_t_val(t_type t)
|
||||
{
|
||||
return (std::numeric_limits<t_type>::max)();
|
||||
}
|
||||
|
||||
// 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<typename key, typename associated_data>
|
||||
class median_helper
|
||||
{
|
||||
typedef std::multiset<key> ordered_items_container;
|
||||
typedef std::pair<typename ordered_items_container::iterator, associated_data> queued_item_type;
|
||||
typedef std::list<queued_item_type> queued_items_container;
|
||||
typedef std::list<std::pair<key, associated_data> > recent_items_container;
|
||||
ordered_items_container ordered_items;
|
||||
queued_items_container queued_items;
|
||||
recent_items_container recent_items; // this needed to have chance to roll back at least for some depth, so we keep elements removed from median window for a while
|
||||
bool had_been_in_recent_items;
|
||||
mutable critical_section m_lock;
|
||||
|
||||
typename ordered_items_container::iterator m_current_median_it;
|
||||
uint64_t current_index;
|
||||
|
||||
virtual void handle_purge_back_item() {}
|
||||
virtual void handle_add_front_item(const key& k, const associated_data& ad) {}
|
||||
virtual void handle_remove_front_item(const key& k) {}
|
||||
void push_item_as_recent(const key& k, const associated_data& ad)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
auto it = ordered_items.insert(k);
|
||||
queued_items.push_front(queued_item_type(it, ad));
|
||||
}
|
||||
public:
|
||||
median_helper() :had_been_in_recent_items(false)
|
||||
{
|
||||
m_current_median_it = ordered_items.end();
|
||||
current_index = 0;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
ordered_items.clear();
|
||||
queued_items.clear();
|
||||
recent_items.clear();
|
||||
had_been_in_recent_items = false;
|
||||
m_current_median_it = ordered_items.end();
|
||||
current_index = 0;
|
||||
}
|
||||
|
||||
void push_item(const key& k, const associated_data& ad)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
auto it = ordered_items.insert(k);
|
||||
queued_items.push_back(queued_item_type(it, ad));
|
||||
handle_add_front_item(k, ad);
|
||||
}
|
||||
|
||||
void pop_item()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if (!queued_items.empty())
|
||||
{
|
||||
auto it = queued_items.back().first;
|
||||
handle_remove_front_item(*it);
|
||||
ordered_items.erase(it);
|
||||
queued_items.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
cb(key, associated_data) - enumerating while result is false
|
||||
when returned true - clean items behind and move it to recent_items
|
||||
|
||||
cb_final_remove(key, associated_data) - for every element in recent_items if returned false - element removed forever
|
||||
*/
|
||||
template<class cb_t, class cb_t2>
|
||||
bool scan_items(cb_t cb, cb_t2 cb_final_remove)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
//process median window items
|
||||
for (auto it = queued_items.begin(); it != queued_items.end(); it++)
|
||||
{
|
||||
if (cb(*it->first, it->second))
|
||||
{
|
||||
//stop element, remove all items before this
|
||||
for (auto clean_it = queued_items.begin(); clean_it != it; clean_it++)
|
||||
{
|
||||
//std::pair<key, associated_data> p(*it->first, it->second);
|
||||
recent_items.push_back(std::make_pair(*clean_it->first, clean_it->second));
|
||||
had_been_in_recent_items = true;
|
||||
ordered_items.erase(clean_it->first);
|
||||
}
|
||||
queued_items.erase(queued_items.begin(), it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//process recent items front part (put back to median window set if needed)
|
||||
for (auto it = recent_items.rbegin(); it != recent_items.rend();)
|
||||
{
|
||||
if (!cb(it->first, it->second))
|
||||
break;//element should stay in recent
|
||||
|
||||
//element should be back to median window
|
||||
this->push_item_as_recent(it->first, it->second);
|
||||
it = typename recent_items_container::reverse_iterator(recent_items.erase((++it).base())); // remove *it and advance 'it' by 1
|
||||
}
|
||||
|
||||
|
||||
//process recent items back part (remove outdated elements)
|
||||
while (recent_items.size() && !cb_final_remove(recent_items.begin()->first, recent_items.begin()->second))
|
||||
{
|
||||
recent_items.erase(recent_items.begin());
|
||||
handle_purge_back_item();
|
||||
}
|
||||
|
||||
//detect if recent_items exhausted
|
||||
if (!recent_items.size() && had_been_in_recent_items)
|
||||
{
|
||||
LOG_PRINT_RED_L0("[MEDIAN_HELPER]: recent_items exhausted, need to rebuild median from scratch");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t get_median() const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if (!ordered_items.size())
|
||||
return 0;
|
||||
|
||||
size_t n = ordered_items.size() / 2;
|
||||
//std::sort(v.begin(), v.end());
|
||||
|
||||
auto n_it = std::next(ordered_items.begin(), n);
|
||||
|
||||
//nth_element(v.begin(), v.begin()+n-1, v.end());
|
||||
if (ordered_items.size() % 2)
|
||||
{//1, 3, 5...
|
||||
return *n_it;
|
||||
}
|
||||
else
|
||||
{//2, 4, 6...
|
||||
auto n_it_sub = n_it;
|
||||
--n_it_sub;
|
||||
return (*n_it_sub + *n_it) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
friend std::ostream & operator<< (std::ostream &out, median_helper<key_t, associated_data_t> const &mh);
|
||||
}; // class median_helper
|
||||
|
||||
template<typename key_t, typename associated_data_t>
|
||||
std::ostream & operator<< (std::ostream &s, median_helper<key_t, associated_data_t> const &mh)
|
||||
{
|
||||
s << "median_helper<" << typeid(key_t).name() << ", " << typeid(associated_data_t).name() << "> instance 0x" << &mh << ENDL
|
||||
<< " ordered_items: " << mh.ordered_items.size() << ENDL
|
||||
<< " queued_items: " << mh.queued_items.size() << ENDL
|
||||
<< " recent_items: " << mh.recent_items.size() << ENDL
|
||||
<< " had_been_in_recent_items: " << mh.had_been_in_recent_items << ENDL;
|
||||
return s;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class type_vec_type>
|
||||
type_vec_type median(std::vector<type_vec_type> &v)
|
||||
{
|
||||
//CRITICAL_REGION_LOCAL(m_lock);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
#define ON_EXIT misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler
|
||||
|
||||
|
||||
template< typename t_contaner, typename t_redicate>
|
||||
void erase_if( t_contaner& items, const t_redicate& predicate )
|
||||
{
|
||||
for(auto it = items.begin(); it != items.end(); )
|
||||
{
|
||||
if( predicate(*it) )
|
||||
it = items.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct call_basic
|
||||
{
|
||||
virtual void do_call(){};
|
||||
};
|
||||
|
||||
|
||||
template<typename t_callback>
|
||||
struct call_specific: public call_basic
|
||||
{
|
||||
call_specific(t_callback cb):m_cb(cb)
|
||||
{}
|
||||
virtual void do_call()
|
||||
{
|
||||
m_cb();
|
||||
}
|
||||
private:
|
||||
t_callback m_cb;
|
||||
};
|
||||
|
||||
template<typename t_callback>
|
||||
auto build_abstract_callback(t_callback cb) -> std::shared_ptr<call_basic>
|
||||
{
|
||||
return std::shared_ptr<call_basic>(new call_specific<t_callback>(cb));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class callback_type>
|
||||
bool static_initializer(callback_type cb)
|
||||
{
|
||||
return cb();
|
||||
};
|
||||
|
||||
|
||||
template<class t_container_type>
|
||||
typename t_container_type::mapped_type& get_or_insert_value_initialized(t_container_type& container, const typename t_container_type::key_type& key)
|
||||
{
|
||||
auto it = container.find(key);
|
||||
if (it != container.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto res = container.insert(typename t_container_type::value_type(key, AUTO_VAL_INIT(typename t_container_type::mapped_type())));
|
||||
return res.first->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& print_container_content(std::ostream& out, const T& v);
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v)
|
||||
{
|
||||
return print_container_content(out, v);
|
||||
}
|
||||
template<typename T>
|
||||
std::ostream& operator<< (std::ostream& out, const std::list<T>& v)
|
||||
{
|
||||
return print_container_content(out, v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& print_container_content(std::ostream& out, const T& v)
|
||||
{
|
||||
|
||||
out << "[";
|
||||
if (!v.size())
|
||||
{
|
||||
out << "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
typename T::const_iterator last_it = --v.end();
|
||||
|
||||
for (typename T::const_iterator it = v.begin(); it != v.end(); it++)
|
||||
{
|
||||
out << *it;
|
||||
if (it != last_it)
|
||||
out << ", ";
|
||||
}
|
||||
out << "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
1692
src/contrib/epee/include/misc_log_ex.h
Normal file
1692
src/contrib/epee/include/misc_log_ex.h
Normal file
File diff suppressed because it is too large
Load diff
138
src/contrib/epee/include/misc_os_dependent.h
Normal file
138
src/contrib/epee/include/misc_os_dependent.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifdef WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
//#ifdef _WIN32_WINNT
|
||||
// #undef _WIN32_WINNT
|
||||
// #define _WIN32_WINNT 0x0600
|
||||
//#endif
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
namespace epee
|
||||
{
|
||||
namespace misc_utils
|
||||
{
|
||||
|
||||
inline uint64_t get_tick_count()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
typedef ULONGLONG(*GetTickCount64Ptr)();
|
||||
static GetTickCount64Ptr get_tick_count64 = (GetTickCount64Ptr)(GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetTickCount64"));
|
||||
if (get_tick_count64)
|
||||
return (*get_tick_count64)();
|
||||
return GetTickCount();
|
||||
#elif defined(__MACH__)
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
return (mts.tv_sec * 1000) + (mts.tv_nsec/1000000);
|
||||
#else
|
||||
struct timespec ts;
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return (ts.tv_sec * 1000) + (ts.tv_nsec/1000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
inline int call_sys_cmd(const std::string& cmd)
|
||||
{
|
||||
std::cout << "# " << cmd << std::endl;
|
||||
|
||||
FILE * fp ;
|
||||
//char tstCommand[] ="ls *";
|
||||
char path[1000] = {0};
|
||||
#if !defined(__GNUC__)
|
||||
fp = _popen(cmd.c_str(), "r");
|
||||
#else
|
||||
fp = popen(cmd.c_str(), "r");
|
||||
#endif
|
||||
while ( fgets( path, 1000, fp ) != NULL )
|
||||
std::cout << path;
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
_pclose(fp);
|
||||
#else
|
||||
pclose(fp);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline std::string get_thread_string_id()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return boost::lexical_cast<std::string>(GetCurrentThreadId());
|
||||
#elif defined(__GNUC__)
|
||||
return boost::lexical_cast<std::string>(pthread_self());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#include <execinfo.h>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#endif
|
||||
inline std::string print_trace()
|
||||
{
|
||||
std::stringstream ss;
|
||||
#if defined(__GNUC__)
|
||||
ss << std::endl << "STACK" << std::endl;
|
||||
const size_t max_depth = 100;
|
||||
size_t stack_depth;
|
||||
void *stack_addrs[max_depth];
|
||||
char **stack_strings;
|
||||
|
||||
stack_depth = backtrace(stack_addrs, max_depth);
|
||||
stack_strings = backtrace_symbols(stack_addrs, stack_depth);
|
||||
|
||||
for (size_t i = 1; i < stack_depth; i++)
|
||||
{
|
||||
ss << boost::core::demangle(stack_strings[i]) << std::endl;
|
||||
}
|
||||
free(stack_strings); // malloc()ed by backtrace_symbols
|
||||
#endif
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
293
src/contrib/epee/include/net/abstract_tcp_server2.h
Normal file
293
src/contrib/epee/include/net/abstract_tcp_server2.h
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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"
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "net_server"
|
||||
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
|
||||
|
||||
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();
|
||||
bool is_shutdown(){return m_was_shutdown;}
|
||||
bool cancel();
|
||||
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);
|
||||
|
||||
/// 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
|
||||
try{
|
||||
if (!ptr->call_handler())
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
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::mutex connections_mutex;
|
||||
//std::deque<connection_ptr> connections_;
|
||||
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"
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL NULL
|
||||
|
||||
#endif
|
||||
843
src/contrib/epee/include/net/abstract_tcp_server2.inl
Normal file
843
src/contrib/epee/include/net/abstract_tcp_server2.inl
Normal file
|
|
@ -0,0 +1,843 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include "net_utils_base.h"
|
||||
#include <boost/lambda/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include "misc_language.h"
|
||||
#include "warnings.h"
|
||||
|
||||
PUSH_WARNINGS
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
DISABLE_VS_WARNINGS(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_protocol_handler(this, config, context),
|
||||
m_want_close_connection(0),
|
||||
m_was_shutdown(0),
|
||||
m_ref_sockets_count(sock_count),
|
||||
m_pfilter(pfilter)
|
||||
{
|
||||
boost::interprocess::ipcdetail::atomic_inc32(&m_ref_sockets_count);
|
||||
}
|
||||
DISABLE_VS_WARNINGS(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);
|
||||
VALIDATE_MUTEX_IS_FREE(m_send_que_lock);
|
||||
VALIDATE_MUTEX_IS_FREE(m_self_refs_lock);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
LOG_PRINT_RED("Failed to start conntection, failed to call safe_shared_from_this", LOG_LEVEL_2);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_is_multithreaded = is_multithreaded;
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto remote_ep = socket_.remote_endpoint(ec);
|
||||
CHECK_AND_NO_ASSERT_MES(!m_was_shutdown, false, "was shutdown on start connection");
|
||||
|
||||
CHECK_AND_NO_ASSERT_MES_LEVEL(!ec, false, "Failed to get remote endpoint(" << (is_income?"INT":"OUT") << "): " << ec.message() << ':' << ec.value(), LOG_LEVEL_2);
|
||||
|
||||
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);
|
||||
context.m_last_send = context.m_last_recv = time(NULL);
|
||||
|
||||
LOG_PRINT_L3("[sock " << socket_.native_handle() << "] new connection, remote end_point: " << print_connection_context_short(context) <<
|
||||
" local end_point: " << local_ep.address().to_string() << ':' << local_ep.port() <<
|
||||
", total sockets objects " << m_ref_sockets_count);
|
||||
|
||||
if(is_income && m_pfilter && !m_pfilter->is_remote_ip_allowed(context.m_remote_ip))
|
||||
{
|
||||
LOG_PRINT_L0("[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() << "] Assync 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() << "]Assync 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
|
||||
|
||||
CRITICAL_REGION_LOCAL_VAR(m_send_que_lock, send_guard);
|
||||
if(m_send_que.size() > ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
|
||||
{
|
||||
send_guard.unlock();//manual unlock
|
||||
LOG_ERROR("send to [" << print_connection_context_short(context) << ", (" << (void*)this << ")] que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_send_que.resize(m_send_que.size()+1);
|
||||
m_send_que.back().assign((const char*)ptr, cb);
|
||||
|
||||
if(m_send_que.size() > 1)
|
||||
{
|
||||
//active operation should be in progress, nothing to do, just wait last operation callback
|
||||
}else
|
||||
{
|
||||
//no active operation
|
||||
if(m_send_que.size()!=1)
|
||||
{
|
||||
LOG_ERROR("Looks like no active operations, but send que size != 1!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), m_send_que.front().size()),
|
||||
//strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2)
|
||||
//)
|
||||
);
|
||||
|
||||
LOG_PRINT_L4("[sock " << socket_.native_handle() << "] Assync 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>
|
||||
bool connection<t_protocol_handler>::cancel()
|
||||
{
|
||||
return close();
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
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() << "] Assync 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)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
m_threads_count = threads_count;
|
||||
m_main_thread_id = boost::this_thread::get_id();
|
||||
log_space::log_singletone::set_thread_log_prefix("[SRV_MAIN]");
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
CRITICAL_REGION_BEGIN(m_threads_lock);
|
||||
for (std::size_t i = 0; i < threads_count; ++i)
|
||||
{
|
||||
boost::shared_ptr<boost::thread> thread(new boost::thread(
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::worker_thread, this)));
|
||||
m_threads.push_back(thread);
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
// Wait for all threads in the pool to exit.
|
||||
if(wait)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_threads.size(); ++i)
|
||||
m_threads[i]->join();
|
||||
m_threads.clear();
|
||||
|
||||
}else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(wait && !m_stop_signal_sent)
|
||||
{
|
||||
//some problems with the listening socket ?..
|
||||
LOG_PRINT_L0("Net service stopped without stop request, restarting...");
|
||||
if(!this->init_server(m_port, m_address))
|
||||
{
|
||||
LOG_PRINT_L0("Reiniting service failed, exit.");
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
LOG_PRINT_L0("Reiniting OK.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::run_server", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::is_thread_worker()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
CRITICAL_REGION_LOCAL(m_threads_lock);
|
||||
BOOST_FOREACH(boost::shared_ptr<boost::thread>& thp, m_threads)
|
||||
{
|
||||
if(thp->get_id() == boost::this_thread::get_id())
|
||||
return true;
|
||||
}
|
||||
if(m_threads_count == 1 && boost::this_thread::get_id() == m_main_thread_id)
|
||||
return true;
|
||||
return false;
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::is_thread_worker", false);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::timed_wait_server_stop(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();
|
||||
m_config.on_send_stop_signal();
|
||||
|
||||
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));
|
||||
|
||||
conn->start(true, 1 < m_threads_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)
|
||||
{
|
||||
CRITICAL_SECTION_LOCK(shared_context->connect_mut);
|
||||
shared_context->ec = ec_;
|
||||
CRITICAL_SECTION_UNLOCK(shared_context->connect_mut);
|
||||
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 = false;
|
||||
try{
|
||||
r = local_shared_context->cond.timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(conn_timeout));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
//timeout
|
||||
sock_.close();
|
||||
LOG_PRINT_L3("timed_wait throwed, " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")");
|
||||
return false;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
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 if(new_connection_l->is_shutdown())
|
||||
{
|
||||
//if deadline timer started and finished callback right after async_connect callback is started and before deadline timer sh_deadline->cancel() is called
|
||||
cb(conn_context, boost::asio::error::operation_aborted);
|
||||
}
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
POP_WARNINGS
|
||||
184
src/contrib/epee/include/net/http_base.h
Normal file
184
src/contrib/epee/include/net/http_base.h
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "string_tools.h"
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
|
||||
enum http_method{
|
||||
http_method_get,
|
||||
http_method_post,
|
||||
http_method_put,
|
||||
http_method_head,
|
||||
http_method_etc,
|
||||
http_method_unknown
|
||||
};
|
||||
|
||||
enum http_content_type
|
||||
{
|
||||
http_content_type_text_html,
|
||||
http_content_type_image_gif,
|
||||
http_content_type_other,
|
||||
http_content_type_not_set
|
||||
};
|
||||
|
||||
typedef std::list<std::pair<std::string, std::string> > fields_list;
|
||||
|
||||
inline
|
||||
std::string get_value_from_fields_list(const std::string& param_name, const net_utils::http::fields_list& fields)
|
||||
{
|
||||
fields_list::const_iterator it = fields.begin();
|
||||
for(; it != fields.end(); it++)
|
||||
if(!string_tools::compare_no_case(param_name, it->first))
|
||||
break;
|
||||
|
||||
if(it==fields.end())
|
||||
return std::string();
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
std::string get_value_from_uri_line(const std::string& param_name, const std::string& uri)
|
||||
{
|
||||
std::string buff = "([\\?|&])";
|
||||
buff += param_name + "=([^&]*)";
|
||||
boost::regex match_param(buff.c_str(), boost::regex::icase | boost::regex::normal);
|
||||
boost::smatch result;
|
||||
if(boost::regex_search(uri, result, match_param, boost::match_default) && result[0].matched)
|
||||
{
|
||||
return result[2];
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct http_header_info
|
||||
{
|
||||
std::string m_connection; //"Connection:"
|
||||
std::string m_referer; //"Referer:"
|
||||
std::string m_content_length; //"Content-Length:"
|
||||
std::string m_content_type; //"Content-Type:"
|
||||
std::string m_transfer_encoding;//"Transfer-Encoding:"
|
||||
std::string m_content_encoding; //"Content-Encoding:"
|
||||
std::string m_host; //"Host:"
|
||||
std::string m_cookie; //"Cookie:"
|
||||
fields_list m_etc_fields;
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_connection.clear();
|
||||
m_referer.clear();
|
||||
m_content_length.clear();
|
||||
m_content_type.clear();
|
||||
m_transfer_encoding.clear();
|
||||
m_content_encoding.clear();
|
||||
m_host.clear();
|
||||
m_cookie.clear();
|
||||
m_etc_fields.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct uri_content
|
||||
{
|
||||
std::string m_path;
|
||||
std::string m_query;
|
||||
std::string m_fragment;
|
||||
std::list<std::pair<std::string, std::string> > m_query_params;
|
||||
};
|
||||
|
||||
struct url_content
|
||||
{
|
||||
std::string schema;
|
||||
std::string host;
|
||||
std::string uri;
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
882
src/contrib/epee/include/net/http_client.h
Normal file
882
src/contrib/epee/include/net/http_client.h
Normal file
|
|
@ -0,0 +1,882 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::socket& get_socket()
|
||||
{
|
||||
return m_net_client.get_socket();
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
98
src/contrib/epee/include/net/http_client_abstract_invoke.h
Normal file
98
src/contrib/epee/include/net/http_client_abstract_invoke.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "storages/serializeble_struct_helper.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
template<class TArg, class TResult, class TTransport>
|
||||
bool invoke_http_json_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
StorageNamed::InMemStorageSpace::json::store_t_to_json(out_struct, req_param);
|
||||
|
||||
const http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return StorageNamed::InMemStorageSpace::json::load_t_from_json(result_struct, pri->m_body);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class TArg, class TResult, class TTransport>
|
||||
bool invoke_http_bin_remote_command(const std::string& url, TArg& out_struct, TResult& result_struct, TTransport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
|
||||
{
|
||||
std::string req_param;
|
||||
epee::StorageNamed::save_struct_as_storage_to_buff(out_struct, req_param);
|
||||
|
||||
const http_response_info* pri = NULL;
|
||||
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pri->m_response_code)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", internal error (null response ptr)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pri->m_response_code != 200)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
return epee::StorageNamed::load_struct_from_storage_buff(result_struct, pri->m_body);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/contrib/epee/include/net/http_client_base.h
Normal file
73
src/contrib/epee/include/net/http_client_base.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
struct i_sub_handler
|
||||
{
|
||||
virtual ~i_sub_handler(){}
|
||||
|
||||
virtual bool update_in( std::string& piece_of_transfer)=0;
|
||||
virtual void stop(std::string& OUT collect_remains)=0;
|
||||
virtual bool update_and_stop(std::string& OUT collect_remains, bool& is_changed)
|
||||
{
|
||||
is_changed = true;
|
||||
bool res = this->update_in(collect_remains);
|
||||
if(res)
|
||||
this->stop(collect_remains);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct i_target_handler
|
||||
{
|
||||
virtual ~i_target_handler(){}
|
||||
virtual bool handle_target_data( std::string& piece_of_transfer)=0;
|
||||
};
|
||||
|
||||
|
||||
class do_nothing_sub_handler: public i_sub_handler
|
||||
{
|
||||
public:
|
||||
do_nothing_sub_handler(i_target_handler* powner_filter):m_powner_filter(powner_filter)
|
||||
{}
|
||||
virtual bool update_in( std::string& piece_of_transfer)
|
||||
{
|
||||
return m_powner_filter->handle_target_data(piece_of_transfer);
|
||||
}
|
||||
virtual void stop(std::string& OUT collect_remains)
|
||||
{
|
||||
|
||||
}
|
||||
i_target_handler* m_powner_filter;
|
||||
};
|
||||
}
|
||||
}
|
||||
177
src/contrib/epee/include/net/http_client_via_api_helper.h
Normal file
177
src/contrib/epee/include/net/http_client_via_api_helper.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <wininet.h>
|
||||
#include <atlutil.h>
|
||||
#pragma comment(lib, "Wininet.lib")
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
inline
|
||||
bool http_ssl_invoke(const std::string& url, const std::string usr, const std::string psw, std::string& http_response_body, bool use_post = false)
|
||||
{
|
||||
bool final_res = false;
|
||||
|
||||
ATL::CUrl url_obj;
|
||||
BOOL crack_rss = url_obj.CrackUrl(string_encoding::convert_to_t<std::basic_string<TCHAR> >(url).c_str());
|
||||
|
||||
HINTERNET hinet = ::InternetOpenA(SHARED_JOBSCOMMON_HTTP_AGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
||||
if(!hinet)
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetOpenA, \nError: " << err << " " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwFlags = 0;
|
||||
DWORD dwBuffLen = sizeof(dwFlags);
|
||||
|
||||
if(usr.size())
|
||||
{
|
||||
dwFlags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID|
|
||||
INTERNET_FLAG_PRAGMA_NOCACHE | SECURITY_FLAG_IGNORE_UNKNOWN_CA|INTERNET_FLAG_SECURE;
|
||||
}else
|
||||
{
|
||||
dwFlags |= INTERNET_FLAG_PRAGMA_NOCACHE;
|
||||
}
|
||||
|
||||
|
||||
int port = url_obj.GetPortNumber();
|
||||
BOOL res = FALSE;
|
||||
|
||||
HINTERNET hsession = ::InternetConnectA(hinet, string_encoding::convert_to_ansii(url_obj.GetHostName()).c_str(), port/*INTERNET_DEFAULT_HTTPS_PORT*/, usr.c_str(), psw.c_str(), INTERNET_SERVICE_HTTP, dwFlags, NULL);
|
||||
if(hsession)
|
||||
{
|
||||
const std::string uri = string_encoding::convert_to_ansii(url_obj.GetUrlPath()) + string_encoding::convert_to_ansii(url_obj.GetExtraInfo());
|
||||
|
||||
HINTERNET hrequest = ::HttpOpenRequestA(hsession, use_post?"POST":NULL, uri.c_str(), NULL, NULL,NULL, dwFlags, NULL);
|
||||
if(hrequest)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
res = ::HttpSendRequestA(hrequest, NULL, 0, NULL, 0);
|
||||
if(!res)
|
||||
{
|
||||
//ERROR_INTERNET_INVALID_CA 45
|
||||
//ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5)
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call HttpSendRequestA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD code = 0;
|
||||
DWORD buf_len = sizeof(code);
|
||||
DWORD index = 0;
|
||||
res = ::HttpQueryInfo(hrequest, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &code, &buf_len, &index);
|
||||
if(!res)
|
||||
{
|
||||
//ERROR_INTERNET_INVALID_CA 45
|
||||
//ERROR_INTERNET_INVALID_URL (INTERNET_ERROR_BASE + 5)
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call HttpQueryInfo, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
break;
|
||||
}
|
||||
if(code < 200 || code > 299)
|
||||
{
|
||||
LOG_PRINT("Wrong server response, HttpQueryInfo returned statuse code" << code , LOG_LEVEL_0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
char buff[100000] = {0};
|
||||
DWORD readed = 0;
|
||||
while(true)
|
||||
{
|
||||
res = ::InternetReadFile(hrequest, buff, sizeof(buff), &readed);
|
||||
if(!res)
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetReadFile, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
break;
|
||||
}
|
||||
if(readed)
|
||||
{
|
||||
http_response_body.append(buff, readed);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(!res)
|
||||
break;
|
||||
|
||||
|
||||
//we success
|
||||
final_res = true;
|
||||
|
||||
res = ::InternetCloseHandle(hrequest);
|
||||
if(!res)
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//ERROR_INTERNET_INVALID_CA
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetOpenUrlA, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
return false;
|
||||
}
|
||||
|
||||
res = ::InternetCloseHandle(hsession);
|
||||
if(!res)
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
}
|
||||
}else
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetConnectA(" << string_encoding::convert_to_ansii(url_obj.GetHostName()) << ", port " << port << " \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
res = ::InternetCloseHandle(hinet);
|
||||
if(!res)
|
||||
{
|
||||
int err = ::GetLastError();
|
||||
LOG_PRINT("Failed to call InternetCloseHandle, \nError: " << log_space::get_win32_err_descr(err), LOG_LEVEL_0);
|
||||
}
|
||||
return final_res;
|
||||
}
|
||||
}
|
||||
}
|
||||
214
src/contrib/epee/include/net/http_protocol_handler.h
Normal file
214
src/contrib/epee/include/net/http_protocol_handler.h
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef _HTTP_SERVER_H_
|
||||
#define _HTTP_SERVER_H_
|
||||
|
||||
#include <string>
|
||||
#include "net_utils_base.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
#include "http_base.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct http_server_config
|
||||
{
|
||||
void on_send_stop_signal(){}
|
||||
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);
|
||||
|
||||
|
||||
//temporary here
|
||||
//bool parse_uri(const std::string uri, uri_content& content);
|
||||
|
||||
private:
|
||||
enum machine_state{
|
||||
http_state_retriving_comand_line,
|
||||
http_state_retriving_header,
|
||||
http_state_retriving_body,
|
||||
http_state_connection_close,
|
||||
http_state_error
|
||||
};
|
||||
|
||||
enum body_transfer_type{
|
||||
http_body_transfer_chunked,
|
||||
http_body_transfer_measure,//mean "Content-Length" valid
|
||||
http_body_transfer_chunked_instead_measure,
|
||||
http_body_transfer_connection_close,
|
||||
http_body_transfer_multipart,
|
||||
http_body_transfer_undefined
|
||||
};
|
||||
|
||||
bool handle_buff_in(std::string& buf);
|
||||
|
||||
bool analize_cached_request_header_and_invoke_state(size_t pos);
|
||||
|
||||
bool handle_invoke_query_line();
|
||||
bool parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos);
|
||||
std::string::size_type match_end_of_header(const std::string& buf);
|
||||
bool get_len_from_content_lenght(const std::string& str, size_t& len);
|
||||
bool handle_retriving_query_body();
|
||||
bool handle_query_measure();
|
||||
bool set_ready_state();
|
||||
bool slash_to_back_slash(std::string& str);
|
||||
std::string get_file_mime_tipe(const std::string& path);
|
||||
std::string get_response_header(const http_response_info& response);
|
||||
|
||||
//major function
|
||||
inline bool handle_request_and_send_response(const http::http_request_info& query_info);
|
||||
|
||||
|
||||
std::string get_not_found_response_body(const std::string& URI);
|
||||
|
||||
std::string m_root_path;
|
||||
std::string m_cache;
|
||||
machine_state m_state;
|
||||
body_transfer_type m_body_transfer_type;
|
||||
bool m_is_stop_handling;
|
||||
http::http_request_info m_query_info;
|
||||
size_t m_len_summary, m_len_remain;
|
||||
size_t m_precommand_line_chars;
|
||||
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_
|
||||
696
src/contrib/epee/include/net/http_protocol_handler.inl
Normal file
696
src/contrib/epee/include/net/http_protocol_handler.inl
Normal file
|
|
@ -0,0 +1,696 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "http_protocol_handler.h"
|
||||
#include "reg_exp_definer.h"
|
||||
#include "string_tools.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "net_parse_helpers.h"
|
||||
|
||||
#define HTTP_MAX_URI_LEN 9000
|
||||
#define HTTP_MAX_PRE_COMMAND_LINE_CHARS 20
|
||||
#define HTTP_MAX_HEADER_LEN 100000
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
|
||||
|
||||
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),
|
||||
m_precommand_line_chars(0)
|
||||
{
|
||||
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
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;
|
||||
m_precommand_line_chars = 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 down without panic and asserts
|
||||
m_cache.erase(0, 1);
|
||||
|
||||
//fixed bug with possible '\r\n' chars flood, thanks to @anonimal (https://github.com/anonimal) for pointing this
|
||||
++m_precommand_line_chars;
|
||||
if (m_precommand_line_chars > HTTP_MAX_PRE_COMMAND_LINE_CHARS)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long URI line");
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
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_in: 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_buff_in: Wrong state: " << m_state);
|
||||
return false;
|
||||
case http_state_error:
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: 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_invoke_query_line(*)", 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);
|
||||
CRITICAL_SECTION_LOCK(m_config.m_lock);
|
||||
std::string destination_file_path = m_config.m_folder + uri_to_path;
|
||||
CRITICAL_SECTION_UNLOCK(m_config.m_lock);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
POP_WARNINGS
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue