diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/base58.cpp | 246 | ||||
-rw-r--r-- | src/common/base58.h | 20 | ||||
-rw-r--r-- | src/common/boost_serialization_helper.h | 44 | ||||
-rw-r--r-- | src/common/command_line.cpp | 12 | ||||
-rw-r--r-- | src/common/command_line.h | 177 | ||||
-rw-r--r-- | src/common/int-util.h | 205 | ||||
-rw-r--r-- | src/common/pod-class.h | 11 | ||||
-rw-r--r-- | src/common/unordered_containers_boost_serialization.h | 80 | ||||
-rw-r--r-- | src/common/util.cpp | 363 | ||||
-rw-r--r-- | src/common/util.h | 29 | ||||
-rw-r--r-- | src/common/varint.h | 62 |
11 files changed, 1249 insertions, 0 deletions
diff --git a/src/common/base58.cpp b/src/common/base58.cpp new file mode 100644 index 000000000..30042eeba --- /dev/null +++ b/src/common/base58.cpp @@ -0,0 +1,246 @@ +// 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 "base58.h" + +#include <assert.h> +#include <string> +#include <vector> + +#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++; + case 2: res <<= 8; res |= *data++; + case 3: res <<= 8; res |= *data++; + case 4: res <<= 8; res |= *data++; + case 5: res <<= 8; res |= *data++; + case 6: res <<= 8; res |= *data++; + case 7: res <<= 8; res |= *data++; + 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 <= sizeof(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; + uint64_t tmp = res_num + mul128(order, digit, &product_hi); + if (tmp < res_num || 0 != product_hi) + return false; // Overflow + + res_num = tmp; + 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; + + 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; + } + } +} diff --git a/src/common/base58.h b/src/common/base58.h new file mode 100644 index 000000000..4055f62ba --- /dev/null +++ b/src/common/base58.h @@ -0,0 +1,20 @@ +// 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); + } +} diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h new file mode 100644 index 000000000..74016ae75 --- /dev/null +++ b/src/common/boost_serialization_helper.h @@ -0,0 +1,44 @@ +// 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> + + +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 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); + } +} diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp new file mode 100644 index 000000000..0b90345d9 --- /dev/null +++ b/src/common/command_line.cpp @@ -0,0 +1,12 @@ +// 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" + +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"}; +} diff --git a/src/common/command_line.h b/src/common/command_line.h new file mode 100644 index 000000000..860653772 --- /dev/null +++ b/src/common/command_line.h @@ -0,0 +1,177 @@ +// 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; +} diff --git a/src/common/int-util.h b/src/common/int-util.h new file mode 100644 index 000000000..ad0ef60e0 --- /dev/null +++ b/src/common/int-util.h @@ -0,0 +1,205 @@ +// 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 <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 + +inline uint64_t hi_dword(uint64_t val) { + return val >> 32; +} + +inline uint64_t lo_dword(uint64_t val) { + return val & 0xFFFFFFFF; +} + +inline uint64_t mul128(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; +} + +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 +inline uint32_t div128_32(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; +} + +#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 diff --git a/src/common/pod-class.h b/src/common/pod-class.h new file mode 100644 index 000000000..c07edb208 --- /dev/null +++ b/src/common/pod-class.h @@ -0,0 +1,11 @@ +// 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 + +#if defined(_MSC_VER) +#define POD_CLASS struct +#else +#define POD_CLASS class +#endif diff --git a/src/common/unordered_containers_boost_serialization.h b/src/common/unordered_containers_boost_serialization.h new file mode 100644 index 000000000..0804660ca --- /dev/null +++ b/src/common/unordered_containers_boost_serialization.h @@ -0,0 +1,80 @@ +// 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) + { + 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 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) + { + 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 hval> + inline void serialize(Archive &a, std::unordered_set<hval> &x, const boost::serialization::version_type ver) + { + split_free(a, x, ver); + } + } +} diff --git a/src/common/util.cpp b/src/common/util.cpp new file mode 100644 index 000000000..b24016cc3 --- /dev/null +++ b/src/common/util.cpp @@ -0,0 +1,363 @@ +// 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 <cstdio> + +#include "include_base_utils.h" +using namespace epee; + +#include "util.h" +#include "cryptonote_config.h" + +#ifdef WIN32 +#include <windows.h> +#include <shlobj.h> +#include <strsafe.h> +#else +#include <sys/utsname.h> +#endif + + +namespace tools +{ + +#ifdef WIN32 + 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\CRYPTONOTE_NAME + // Windows >= Vista: C:\Users\Username\AppData\Roaming\CRYPTONOTE_NAME + // Mac: ~/Library/Application Support/CRYPTONOTE_NAME + // Unix: ~/.CRYPTONOTE_NAME + std::string config_folder; +#ifdef WIN32 + // Windows + config_folder = get_special_folder_path(CSIDL_APPDATA, true) + "/" + CRYPTONOTE_NAME; +#else + std::string pathRet; + char* pszHome = getenv("HOME"); + if (pszHome == NULL || strlen(pszHome) == 0) + pathRet = "/"; + else + pathRet = pszHome; +#ifdef MAC_OSX + // Mac + pathRet /= "Library/Application Support"; + config_folder = (pathRet + "/" + CRYPTONOTE_NAME); +#else + // Unix + config_folder = (pathRet + "/." + CRYPTONOTE_NAME); +#endif +#endif + + return config_folder; + } + + 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()); + } +} diff --git a/src/common/util.h b/src/common/util.h new file mode 100644 index 000000000..a29a30fff --- /dev/null +++ b/src/common/util.h @@ -0,0 +1,29 @@ +// 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 <system_error> +#include <boost/filesystem.hpp> + +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "misc_language.h" +#include "p2p/p2p_protocol_defs.h" + +namespace tools +{ + std::string get_default_data_dir(); + 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()); + } +} diff --git a/src/common/varint.h b/src/common/varint.h new file mode 100644 index 000000000..e62470fdf --- /dev/null +++ b/src/common/varint.h @@ -0,0 +1,62 @@ +// 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 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); + } +} |