From 018609fafaf489e9e87e96ac5d665d0679ffc38a Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Sat, 8 Sep 2012 23:46:19 -0400 Subject: [PATCH] moving more functions from mace to fc --- CMakeLists.txt | 3 + include/fc/asio.hpp | 37 +++++----- include/fc/base64.hpp | 10 +++ include/fc/datastream.hpp | 112 +++++++++++++++++++++++++++++ include/fc/error.hpp | 15 ++++ include/fc/filesystem.hpp | 1 + include/fc/fwd_impl.hpp | 9 ++- include/fc/ip.hpp | 5 ++ include/fc/pke.hpp | 148 ++++++++++++++++++++++++++++++++++++++ include/fc/sha1.hpp | 8 ++- include/fc/shared_ptr.hpp | 3 +- include/fc/string.hpp | 1 + include/fc/time.hpp | 1 + include/fc/udp_socket.hpp | 30 ++++++++ include/fc/vector.hpp | 20 +++--- src/base64.cpp | 138 +++++++++++++++++++++++++++++++++++ src/ip.cpp | 10 +++ src/pke.cpp | 141 ++++++++++++++++++++++++++++++++++++ src/sha1.cpp | 4 ++ src/string.cpp | 1 + src/udp_socket.cpp | 81 +++++++++++++++++++++ 21 files changed, 746 insertions(+), 32 deletions(-) create mode 100644 include/fc/base64.hpp create mode 100644 include/fc/datastream.hpp create mode 100644 include/fc/pke.hpp create mode 100644 include/fc/udp_socket.hpp create mode 100644 src/base64.cpp create mode 100644 src/pke.cpp create mode 100644 src/udp_socket.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b6c9603..3105407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,9 @@ set( sources src/ip.cpp src/bigint.cpp src/mutex.cpp + src/pke.cpp + src/base64.cpp + src/udp_socket.cpp ) setup_library( fc SOURCES ${sources} ) diff --git a/include/fc/asio.hpp b/include/fc/asio.hpp index 3d97be0..b2356a5 100644 --- a/include/fc/asio.hpp +++ b/include/fc/asio.hpp @@ -5,17 +5,18 @@ #ifndef _FC_ASIO_HPP_ #define _FC_ASIO_HPP_ #include +#include #include #include #include namespace fc { /** - * @brief defines fc::cmt wrappers for boost::asio functions. + * @brief defines fc wrappers for boost::asio functions. */ namespace asio { /** - * @brief internal implementation types/methods for fc::cmt::asio + * @brief internal implementation types/methods for fc::asio */ namespace detail { using namespace fc; @@ -48,7 +49,7 @@ namespace asio { #endif } /** - * @return the default boost::asio::io_service for use with fc::cmt::asio + * @return the default boost::asio::io_service for use with fc::asio * * This IO service is automatically running in its own thread to service asynchronous * requests without blocking any other threads. @@ -74,7 +75,7 @@ namespace asio { BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } - promise::ptr p(new promise("fc::cmt::asio::read")); + promise::ptr p(new promise("fc::asio::read")); boost::asio::async_read( s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } @@ -105,7 +106,7 @@ namespace asio { BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } - promise::ptr p(new promise("fc::cmt::asio::read_some")); + promise::ptr p(new promise("fc::asio::read_some")); s.async_read_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } @@ -125,7 +126,7 @@ namespace asio { BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } } - promise::ptr p(new promise("fc::cmt::asio::write")); + promise::ptr p(new promise("fc::asio::write")); boost::asio::async_write(s, buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } @@ -147,7 +148,7 @@ namespace asio { BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } } - promise::ptr p(new promise("fc::cmt::asio::write_some")); + promise::ptr p(new promise("fc::asio::write_some")); s.async_write_some( buf, boost::bind( detail::read_write_handler, p, _1, _2 ) ); return p->wait(); } @@ -161,7 +162,7 @@ namespace asio { sink( AsyncWriteStream& p ):m_stream(p){} std::streamsize write( const char* s, std::streamsize n ) { - return fc::cmt::asio::write( m_stream, boost::asio::const_buffers_1(s,n) ); + return fc::asio::write( m_stream, boost::asio::const_buffers_1(s,n) ); } void close() { m_stream.close(); } @@ -178,7 +179,7 @@ namespace asio { source( AsyncReadStream& p ):m_stream(p){} std::streamsize read( char* s, std::streamsize n ) { - return fc::cmt::asio::read_some( m_stream, boost::asio::buffer(s,n) ); + return fc::asio::read_some( m_stream, boost::asio::buffer(s,n) ); } void close() { m_stream.close(); } @@ -194,11 +195,11 @@ namespace asio { io_device( AsyncStream& p ):m_stream(p){} std::streamsize write( const char* s, std::streamsize n ) { - return fc::cmt::asio::write( m_stream, boost::asio::const_buffers_1(s,static_cast(n)) ); + return fc::asio::write( m_stream, boost::asio::const_buffers_1(s,static_cast(n)) ); } std::streamsize read( char* s, std::streamsize n ) { try { - return fc::cmt::asio::read_some( m_stream, boost::asio::buffer(s,n) ); + return fc::asio::read_some( m_stream, boost::asio::buffer(s,n) ); } catch ( const boost::system::system_error& e ) { if( e.code() == boost::asio::error::eof ) return -1; @@ -225,8 +226,8 @@ namespace asio { */ template void accept( AcceptorType& acc, SocketType& sock ) { - promise::ptr p( new promise("fc::cmt::asio::tcp::accept") ); - acc.async_accept( sock, boost::bind( fc::cmt::asio::detail::error_handler, p, _1 ) ); + promise::ptr p( new promise("fc::asio::tcp::accept") ); + acc.async_accept( sock, boost::bind( fc::asio::detail::error_handler, p, _1 ) ); auto ec = p->wait(); if( !ec ) sock.non_blocking(true); if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); @@ -238,16 +239,16 @@ namespace asio { */ template void connect( AsyncSocket& sock, const EndpointType& ep ) { - promise::ptr p(new promise("fc::cmt::asio::tcp::connect")); - sock.async_connect( ep, boost::bind( fc::cmt::asio::detail::error_handler, p, _1 ) ); + promise::ptr p(new promise("fc::asio::tcp::connect")); + sock.async_connect( ep, boost::bind( fc::asio::detail::error_handler, p, _1 ) ); auto ec = p->wait(); if( !ec ) sock.non_blocking(true); if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); } - typedef boost::iostreams::stream > ostream; - typedef boost::iostreams::stream > istream; - typedef boost::iostreams::stream > iostream; + typedef boost::iostreams::stream > ostream; + typedef boost::iostreams::stream > istream; + typedef boost::iostreams::stream > iostream; } namespace udp { diff --git a/include/fc/base64.hpp b/include/fc/base64.hpp new file mode 100644 index 0000000..75778e7 --- /dev/null +++ b/include/fc/base64.hpp @@ -0,0 +1,10 @@ +#ifndef _FC_BASE64_HPP +#define _FC_BASE64_HPP +#include + +namespace fc { +fc::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); +fc::string base64_encode( const fc::string& enc ); +fc::string base64_decode( const fc::string& encoded_string); +} // namespace fc +#endif // _FC_BASE64_HPP diff --git a/include/fc/datastream.hpp b/include/fc/datastream.hpp new file mode 100644 index 0000000..806973d --- /dev/null +++ b/include/fc/datastream.hpp @@ -0,0 +1,112 @@ +#ifndef _FC_DATASTREAM_HPP_ +#define _FC_DATASTREAM_HPP_ +#include +#include +#include + +namespace fc { + +/** + * The purpose of this datastream is to provide a fast, effecient, means + * of calculating the amount of data "about to be written" and then + * writing it. This means having two modes of operation, "test run" where + * you call the entire pack sequence calculating the size, and then + * actually packing it after doing a single allocation. + */ +template +struct datastream { + datastream( T start, uint32_t s ) + :m_start(start),m_pos(start),m_end(start+s){}; + + template + inline datastream& operator<<(const DATA& d) { + static_assert( !fc::is_class::value, "no serialization defined" ); + write( (const char*)&d, sizeof(d) ); + return *this; + } + + template + inline datastream& operator>>(DATA& d) { + static_assert( !fc::is_class::value, "no serialization defined" ); + read((char*)&d, sizeof(d) ); + return *this; + } + + inline void skip( uint32_t s ){ m_pos += s; } + inline bool read( char* d, uint32_t s ) { + if( m_end - m_pos >= (int32_t)s ) { + memcpy( d, m_pos, s ); + m_pos += s; + return true; + } + FC_THROW( "Attempt to read %d bytes beyond end of buffer of size %d", -((m_end-m_pos) - s),(m_end-m_start) ); + return false; + } + + inline bool write( const char* d, uint32_t s ) { + if( m_end - m_pos >= (int32_t)s ) { + memcpy( m_pos, d, s ); + m_pos += s; + return true; + } + FC_THROW( "Attempt to write %d bytes beyond end of buffer of size %d",%-((m_end-m_pos) - s),(m_end-m_start) ); + return false; + } + + inline bool put(char c) { + if( m_pos < m_end ) { + *m_pos = c; + ++m_pos; + return true; + } + FC_THROW( "Attempt to write %d byte beyond end of buffer of size %d", -((m_end-m_pos) - 1), (m_end-m_start) ); + return false; + } + + inline bool get( unsigned char& c ) { return get( *(char*)&c ); } + inline bool get( char& c ) { + if( m_pos < m_end ) { + c = *m_pos; + ++m_pos; + return true; + } + FC_THROW( "Attempt to read %d byte beyond end of buffer of size %d", -((m_end-m_pos) - 1), (m_end-m_start) ); + ++m_pos; + return false; + } + + T pos()const { return m_pos; } + inline bool valid()const { return m_pos <= m_end && m_pos >= m_start; } + inline bool seekp(uint32_t p) { m_pos = m_start + p; return m_pos <= m_end; } + inline uint32_t tellp()const { return m_pos - m_start; } + inline uint32_t remaining()const { return m_end - m_pos; } +private: + T m_start; + T m_pos; + T m_end; +}; + +template<> +struct datastream { + datastream( size_t init_size = 0):m_size(init_size){}; + template + inline datastream& operator<<(const DATA& d) { + static_assert( !fc::is_class::value, "no serialzation defined" ); + m_size += sizeof(d); + return *this; + } + inline bool skip( uint32_t s ) { m_size += s; return true; } + inline bool write( const char* d, uint32_t s ) { m_size += s; return true; } + inline bool put(char c) { ++m_size; return true; } + inline bool valid()const { return true; } + inline bool seekp(uint32_t p) { m_size = p; return true; } + inline uint32_t tellp()const { return m_size; } + inline uint32_t remaining()const { return 0; } +private: + uint32_t m_size; +}; + + +} // namespace fc + +#endif diff --git a/include/fc/error.hpp b/include/fc/error.hpp index cc95cad..cd6b939 100644 --- a/include/fc/error.hpp +++ b/include/fc/error.hpp @@ -1,11 +1,26 @@ #ifndef _FC_ERROR_HPP_ #define _FC_ERROR_HPP_ +#include namespace fc { struct future_wait_timeout: public std::exception{}; struct task_canceled: public std::exception{}; struct thread_quit: public std::exception{}; struct wait_any_error: public std::exception{}; + + struct pke_exception : public std::exception {}; + struct invalid_buffer_length : public pke_exception {}; + struct invalid_key_length : public pke_exception {}; + + struct generic_exception : public std::exception { + generic_exception( const fc::string& msg = "" ):m_msg(msg){} + ~generic_exception()throw() {} + const char* what()const throw() { return m_msg.c_str(); } + private: + fc::string m_msg; + }; + + struct bad_cast: public std::exception{ const char* what()const throw(){ return "bad cast"; } }; diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 87d99d7..de3ca6e 100644 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -17,6 +17,7 @@ namespace fc { ~path(); path( const boost::filesystem::path& ); path( const fc::string& p ); + path( const char* ); path( const path& p ); path( path&& p ); path& operator =( const path& ); diff --git a/include/fc/fwd_impl.hpp b/include/fc/fwd_impl.hpp index f45d971..7979cfb 100644 --- a/include/fc/fwd_impl.hpp +++ b/include/fc/fwd_impl.hpp @@ -55,23 +55,28 @@ namespace fc { bool fwd::operator !()const { return !(**this); } + template + void check_size() { static_assert( (ProvidedSize >= RequiredSize), "Failed to reserve enough space in fc::fwd" ); } + template template fwd::fwd( U&& u ) { - static_assert( sizeof(_store) >= sizeof(*this), "Failed to reserve enough space" ); + check_size(); new (this) T( fc::forward(u) ); } template fwd::fwd() { - static_assert( sizeof(_store) >= sizeof(*this), "Failed to reserve enough space" ); + check_size(); new (this) T(); } template fwd::fwd( const fwd& f ){ + check_size(); new (this) T( *f ); } template fwd::fwd( fwd&& f ){ + check_size(); new (this) T( fc::move(*f) ); } diff --git a/include/fc/ip.hpp b/include/fc/ip.hpp index 143dfd5..5b131b6 100644 --- a/include/fc/ip.hpp +++ b/include/fc/ip.hpp @@ -12,7 +12,9 @@ namespace fc { address& operator=( const fc::string& s ); operator fc::string()const; + operator uint32_t()const; + friend bool operator==( const address& a, const address& b ); private: uint32_t _ip; }; @@ -29,6 +31,8 @@ namespace fc { uint16_t port()const; const address& get_address()const; + + friend bool operator==( const endpoint& a, const endpoint& b ); private: uint16_t _port; @@ -36,4 +40,5 @@ namespace fc { }; } } +bool operator==( const fc::ip::endpoint& a, const fc::ip::endpoint& b ); #endif // _FC_ENDPOINT_HPP_ diff --git a/include/fc/pke.hpp b/include/fc/pke.hpp new file mode 100644 index 0000000..66147ce --- /dev/null +++ b/include/fc/pke.hpp @@ -0,0 +1,148 @@ +#ifndef FC_PKE_HPP_ +#define FC_PKE_HPP_ +#include +#include + +/** + * Define common crypto methods and data types to abstract underlying implementation. + */ +namespace fc { + + template + struct signature { + char data[KeySize/8]; + template + friend T& operator<<( T& ds, const fc::signature& sig ) + { + ds.write(sig.data, KS/8 ); + return ds; + } + template + friend T& operator>>( T& ds, fc::signature& sig ) + { + ds.read(sig.data, KS/8 ); + return ds; + } + bool operator != ( const signature& s )const { + return memcmp( s.data, data, sizeof(data) ) != 0; + } + bool operator == ( const signature& s )const { + return memcmp( s.data, data, sizeof(data) ) == 0; + } + }; + + bool verify_data( const char* key, uint32_t key_size, uint32_t pe, const sha1& hc, const char* sig ); + bool sign_data( const fc::vector& key, uint32_t key_size, uint32_t pe, const sha1& hc, char* sig ); + bool public_encrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); + bool public_decrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); + bool private_encrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); + bool private_decrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ); + bool generate_keys( char* pubkey, fc::vector& privkey, uint32_t key_size, uint32_t pe ); + + template + struct private_key; + + template + struct public_key { + public_key() { memset( key, 0, sizeof(key) ); } + public_key( const public_key& pk ) { memcpy( key, pk.key, sizeof(key) ); } + + bool verify( const sha1& digest, const signature& sig )const { + return verify_data( key, sizeof(key), PublicExponent, digest, sig.data ); + } + bool encrypt( const fc::vector& in, fc::vector& out )const { + return public_encrypt( key, KeySize, PublicExponent, in, out ); + } + bool decrypt( const fc::vector& in, fc::vector& out )const { + return public_decrypt( key, KeySize, PublicExponent, in, out ); + } + + public_key& operator = ( const public_key& pk ) { + memcpy( key, pk.key, sizeof(key) ); + return *this; + } + bool operator == ( const public_key& pk )const { + return 0 == memcmp( key, pk.key, sizeof(key) ); + } + bool operator != ( const public_key& pk )const { + return 0 != memcmp( key, pk.key, sizeof(key) ); + } + bool operator > ( const public_key& pk )const { + return memcmp( key, pk.key, sizeof(key) ) > 0; + } + bool operator < ( const public_key& pk )const { + return memcmp( key, pk.key, sizeof(key) ) < 0; + } + + template + inline friend T& operator<<( T& ds, const fc::public_key& pk ) { + ds.write(pk.key, KS/8 ); + return ds; + } + template + inline friend T& operator>>( T& ds, fc::public_key& pk ) { + ds.read( pk.key, KS/8 ); + return ds; + } + + private: + template + friend void generate_keys( public_key& pub, private_key& priv ); + + char key[KeySize/8]; + }; + + + template + struct private_key { + bool encrypt( const fc::vector& in, fc::vector& out )const { + return private_encrypt( key, KeySize, PublicExponent, in, out ); + } + bool decrypt( const fc::vector& in, fc::vector& out )const { + return private_decrypt( key, KeySize, PublicExponent, in, out ); + } + bool sign( const sha1& digest, signature& sig )const { + return sign_data( key, KeySize, PublicExponent, digest, sig.data ); + } + + template + friend T& operator<<( T& ds, const fc::private_key& pk ) { + ds << uint16_t(pk.key.size()); + ds.write( &pk.key.front(), pk.key.size() ); + return ds; + } + template + friend T& operator>>( T& ds, fc::private_key& pk ) { + uint16_t s; + ds >> s; + pk.key.resize(s); + ds.read( &pk.key.front(), pk.key.size() ); + return ds; + } + private: + template + friend void generate_keys( public_key& pub, private_key& priv ); + fc::vector key; + }; + + template + void generate_keys( public_key& pub, private_key& priv ) { + generate_keys( pub.key, priv.key, KeySize, PublicExponent ); + } + /* + template + inline std::ostream& operator<< ( std::ostream& os, const signature& s ) { + for( uint32_t i = 0; i < KeySize; ++i ) + os << std::hex << int(s.data[i]) << ' '; + return os; + } + */ + + typedef public_key<> public_key_t; + typedef private_key<> private_key_t; + typedef signature<> signature_t; + +} // namespace fc + + +#endif diff --git a/include/fc/sha1.hpp b/include/fc/sha1.hpp index 4e3a529..00279bc 100644 --- a/include/fc/sha1.hpp +++ b/include/fc/sha1.hpp @@ -22,6 +22,7 @@ namespace fc { class encoder { public: encoder(); + ~encoder(); void write( const char* d, uint32_t dlen ); void reset(); @@ -29,18 +30,18 @@ namespace fc { private: struct impl; - fwd my; + fwd my; }; template inline friend T& operator<<( T& ds, const sha1& ep ) { - ds.write( (const char*)ep.hash, sizeof(ep.hash) ); + ds.write( ep.data(), sizeof(ep) ); return ds; } template inline friend T& operator>>( T& ds, sha1& ep ) { - ds.read( (char*)ep.hash, sizeof(ep.hash) ); + ds.read( ep.data(), sizeof(ep) ); return ds; } friend sha1 operator << ( const sha1& h1, uint32_t i ); @@ -49,6 +50,7 @@ namespace fc { friend sha1 operator ^ ( const sha1& h1, const sha1& h2 ); friend bool operator >= ( const sha1& h1, const sha1& h2 ); friend bool operator > ( const sha1& h1, const sha1& h2 ); + friend bool operator < ( const sha1& h1, const sha1& h2 ); uint32_t _hash[5]; }; diff --git a/include/fc/shared_ptr.hpp b/include/fc/shared_ptr.hpp index f864682..0674aca 100644 --- a/include/fc/shared_ptr.hpp +++ b/include/fc/shared_ptr.hpp @@ -43,10 +43,11 @@ namespace fc { if( _ptr ) _ptr->release(); } shared_ptr& reset( T* v = 0 ) { - if( v == _ptr ) return; + if( v == _ptr ) return *this; if( _ptr ) _ptr->release(); _ptr = v; if( _ptr ) _ptr->retain(); + return *this; } shared_ptr& operator=(const shared_ptr& p ) { diff --git a/include/fc/string.hpp b/include/fc/string.hpp index e451995..352957f 100644 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -37,6 +37,7 @@ namespace fc { void reserve( uint64_t ); uint64_t size()const; + uint64_t find( char c, uint64_t pos = 0 )const; void resize( uint64_t s ); void clear(); diff --git a/include/fc/time.hpp b/include/fc/time.hpp index 70690d2..6f0d853 100644 --- a/include/fc/time.hpp +++ b/include/fc/time.hpp @@ -15,6 +15,7 @@ namespace fc { friend class time_point; int64_t _count; }; + inline microseconds seconds( int64_t s ) { return microseconds( s * 1000000 ); } class time_point { public: diff --git a/include/fc/udp_socket.hpp b/include/fc/udp_socket.hpp new file mode 100644 index 0000000..e9c52d1 --- /dev/null +++ b/include/fc/udp_socket.hpp @@ -0,0 +1,30 @@ +#ifndef _FC_UDP_SOCKET_HPP_ +#define _FC_UDP_SOCKET_HPP_ +#include +#include + +namespace fc { + namespace ip { + class endpoint; + } + + class udp_socket { + public: + udp_socket(); + ~udp_socket(); + + void open(); + void set_receive_buffer_size( size_t s ); + void bind( const fc::ip::endpoint& ); + size_t receive_from( char* b, size_t l, fc::ip::endpoint& from ); + size_t send_to( const char* b, size_t l, const fc::ip::endpoint& to ); + void close(); + + private: + class impl; + fwd my; + }; + +} + +#endif diff --git a/include/fc/vector.hpp b/include/fc/vector.hpp index 03981d9..ef78edd 100644 --- a/include/fc/vector.hpp +++ b/include/fc/vector.hpp @@ -49,7 +49,7 @@ namespace fc { vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; } vector_impl( const vector_impl& c):_data(nullptr) { if( c.size() ) { - _data = data::allocate( c.size() ); + _data = detail::data::allocate( c.size() ); memcpy(begin(),c.begin(),c.size() ); } } @@ -69,7 +69,9 @@ namespace fc { T& back() { return (&_data->first)[-1+_data->size]; } const T& back()const { return (&_data->first)[-1+_data->size]; } T& front() { return (&_data->first)[0]; } - const T& front()const { return (&_data->first)[0]; } + const T& front()const { return (&_data->first)[0]; } + const T* data()const { return (&_data->first); } + T* data() { return (&_data->first); } iterator begin() { return _data ? &front() : 0;} const_iterator begin()const { return _data ? &front() : 0;} @@ -90,12 +92,12 @@ namespace fc { } void reserve( uint64_t i ) { - _data = data::reallocate( _data, i ); + _data = detail::data::reallocate( _data, i ); } void resize( uint64_t i ) { if( capacity() < i ) - _data = data::reallocate( _data, i ); + _data = detail::data::reallocate( _data, i ); _data->size = i; } @@ -154,7 +156,7 @@ namespace fc { return *this; } protected: - data* _data; + detail::data* _data; }; template @@ -164,7 +166,7 @@ namespace fc { vector_impl( vector_impl&& c):_data(c._data){c._data =nullptr; } vector_impl( const vector_impl& c):_data(nullptr) { if( c.size() ) { - _data = data::allocate( c.size() ); + _data = detail::data::allocate( c.size() ); auto i = begin(); auto ci = c.begin(); auto ce = c.end(); @@ -194,6 +196,8 @@ namespace fc { const T& back()const { return (&_data->first)[-1+_data->size]; } T& front() { return (&_data->first)[0]; } const T& front()const { return (&_data->first)[0]; } + const T* data()const { return (&_data->first); } + T* data() { return (&_data->first); } iterator begin() { return _data ? &front() : 0;} const_iterator begin()const { return _data ? &front() : 0;} @@ -225,7 +229,7 @@ namespace fc { if( nullptr != this->_data && i <= this->_data->capacity ) return; - auto _ndata = data::allocate( i ); + auto _ndata = detail::data::allocate( i ); auto nc = &_ndata->first; auto c = this->begin(); auto e = this->end(); @@ -319,7 +323,7 @@ namespace fc { return *this; } private: - data* _data; + detail::data* _data; }; } diff --git a/src/base64.cpp b/src/base64.cpp new file mode 100644 index 0000000..15f4711 --- /dev/null +++ b/src/base64.cpp @@ -0,0 +1,138 @@ +#include +#include +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +namespace fc { + +inline const fc::string& base64_chars() +{ + static const fc::string m_base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return m_base64_chars; +} + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +fc::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); + +fc::string base64_encode( const fc::string& enc ) { + char const* s = enc.c_str(); + return base64_encode( (unsigned char const*)s, enc.size() ); +} +fc::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + + fc::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars()[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars()[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + + +fc::string base64_decode(fc::string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + fc::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars().find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars().find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} + +} // namespace fc + diff --git a/src/ip.cpp b/src/ip.cpp index 549ac7a..6e7c24a 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -12,6 +12,10 @@ namespace fc { namespace ip { _ip = boost::asio::ip::address_v4::from_string(s.c_str()).to_ulong(); } + bool operator==( const address& a, const address& b ) { + return uint32_t(a) == uint32_t(b); + } + address& address::operator=( const fc::string& s ) { _ip = boost::asio::ip::address_v4::from_string(s.c_str()).to_ulong(); return *this; @@ -20,6 +24,9 @@ namespace fc { namespace ip { address::operator fc::string()const { return boost::asio::ip::address_v4(_ip).to_string().c_str(); } + address::operator uint32_t()const { + return _ip; + } endpoint::endpoint() @@ -27,6 +34,9 @@ namespace fc { namespace ip { endpoint::endpoint(const address& a, uint16_t p) :_port(p),_ip(a){} + bool operator==( const endpoint& a, const endpoint& b ) { + return a._port == b._port && a._ip == b._ip; + } uint16_t endpoint::port()const { return _port; } const address& endpoint::get_address()const { return _ip; } diff --git a/src/pke.cpp b/src/pke.cpp new file mode 100644 index 0000000..9cc4460 --- /dev/null +++ b/src/pke.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { + RSA* get_pub( const char* key, uint32_t key_size, uint32_t pe ) + { + RSA* rsa = RSA_new(); + rsa->n = BN_bin2bn( (unsigned char*)key, key_size, NULL ); + rsa->e = BN_new(); + BN_set_word(rsa->e, pe ); + return rsa; + } + RSA* get_priv( const fc::vector& d, uint32_t /*key_size*/, uint32_t /*pe*/ ) + { + BIO* mem = (BIO*)BIO_new_mem_buf( (void*)&d.front(), d.size() ); + RSA* rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL ); + BIO_free(mem); + return rsa; + } + + bool verify_data( const char* key, uint32_t key_size, uint32_t pe, const sha1& digest, const char* sig ) + { + RSA* pub = get_pub( key,key_size,pe); + bool v = RSA_verify( NID_sha1, (const uint8_t*)digest.data(), 20, (uint8_t*)sig, key_size, pub ); + RSA_free(pub); + return v; + } + bool sign_data( const fc::vector& key, uint32_t key_size, uint32_t pe, const sha1& digest, char* sig ) + { + RSA* priv = get_priv( key,key_size,pe); + if( !priv ) { + generic_exception g(fc::generic_exception("Error loading private key: " + fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + FC_THROW(g); + } + uint32_t slen = 0; + if( 1 != RSA_sign( NID_sha1, (uint8_t*)digest.data(), sizeof(digest), (unsigned char*)sig, &slen, priv ) ) + { + RSA_free(priv); + generic_exception g(fc::generic_exception("Error signing data: " + fc::string(ERR_error_string( ERR_get_error(),NULL))) ); + FC_THROW(g); + + } + RSA_free(priv); + return true; + } + + bool public_encrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) + { + RSA* pub = get_pub( key,key_size/8,pe); + out.resize(RSA_size(pub)); + int rtn = RSA_public_encrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), pub, RSA_PKCS1_OAEP_PADDING ); + RSA_free(pub); + if( rtn >= 0 ) + { + out.resize(rtn); + return true; + } + out.resize(0); + FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); + return false; + } + bool public_decrypt( const char* key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) + { + RSA* pub = get_pub( key,key_size/8,pe); + out.resize(RSA_size(pub)); + int rtn = RSA_public_decrypt( RSA_size(pub), (unsigned char*)&in.front(), (unsigned char*)&out.front(), pub, RSA_PKCS1_OAEP_PADDING ); + RSA_free(pub); + if( rtn >= 0 ) + { + out.resize(rtn); + return true; + } + out.resize(0); + FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); + return false;; + } + bool private_encrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) + { + RSA* priv = get_priv( key,key_size/8,pe); + int rtn = RSA_private_encrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), priv, RSA_PKCS1_OAEP_PADDING ); + RSA_free(priv); + if( rtn >= 0 ) + { + out.resize(rtn); + return true; + } + out.resize(0); + return false;; + } + bool private_decrypt( const fc::vector& key, uint32_t key_size, uint32_t pe, const fc::vector& in, fc::vector& out ) + { + + RSA* priv = get_priv( key,key_size/8,pe); + out.resize(RSA_size(priv)); + int rtn = RSA_private_decrypt( in.size(), (unsigned char*)&in.front(), (unsigned char*)&out.front(), priv, RSA_PKCS1_OAEP_PADDING ); + RSA_free(priv); + if( rtn >= 0 ) + { + out.resize(rtn); + return true; + } + out.resize(0); + FC_THROW( fc::generic_exception( ERR_error_string( ERR_get_error(), NULL ) ) ); + return false; + } + + bool generate_keys( char* pubkey, fc::vector& privkey, uint32_t key_size, uint32_t pe ) + { + static bool init = true; + if( init ) { ERR_load_crypto_strings(); init = false; } + + RSA* rsa = RSA_generate_key( key_size, pe, NULL, NULL ); + BN_bn2bin( rsa->n, (unsigned char*)pubkey ); + + BIO *mem = BIO_new(BIO_s_mem()); + int e = PEM_write_bio_RSAPrivateKey(mem, rsa, NULL, NULL, 0, NULL, NULL ); + if( e != 1 ) + { + BIO_free(mem); + RSA_free(rsa); + FC_THROW(generic_exception("Error writing PrivateKey") ); + } + + char* dat; + uint32_t l = BIO_get_mem_data( mem, &dat ); + privkey.resize(l); + memcpy( &privkey.front(), dat, l ); + + BIO_free(mem); + RSA_free(rsa); + return true; + } +} diff --git a/src/sha1.cpp b/src/sha1.cpp index 91cd406..114b069 100644 --- a/src/sha1.cpp +++ b/src/sha1.cpp @@ -23,6 +23,7 @@ namespace fc { SHA_CTX ctx; }; + sha1::encoder::~encoder() {} sha1::encoder::encoder() { reset(); } @@ -72,6 +73,9 @@ namespace fc { bool operator > ( const fc::sha1& h1, const fc::sha1& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) > 0; } + bool operator < ( const fc::sha1& h1, const fc::sha1& h2 ) { + return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) < 0; + } bool operator != ( const fc::sha1& h1, const fc::sha1& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) != 0; } diff --git a/src/string.cpp b/src/string.cpp index 169ed86..4145736 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -56,6 +56,7 @@ namespace fc { void string::reserve(uint64_t r) { reinterpret_cast(this)->reserve(r); } uint64_t string::size()const { return reinterpret_cast(this)->size(); } + uint64_t string::find(char c, uint64_t p)const { return reinterpret_cast(this)->find(c,p); } void string::clear() { return reinterpret_cast(this)->clear(); } void string::resize( uint64_t s ) { reinterpret_cast(this)->resize(s); } diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp new file mode 100644 index 0000000..c178151 --- /dev/null +++ b/src/udp_socket.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include + + +namespace fc { + + class udp_socket::impl { + public: + impl():_sock( fc::asio::default_io_service() ){} + + boost::asio::ip::udp::socket _sock; + }; + + boost::asio::ip::udp::endpoint to_asio_ep( const fc::ip::endpoint& e ) { + return boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4(e.get_address()), e.port() ); + } + fc::ip::endpoint to_fc_ep( const boost::asio::ip::udp::endpoint& e ) { + return fc::ip::endpoint( e.address().to_v4().to_ulong(), e.port() ); + } + + udp_socket::udp_socket() { + } + udp_socket::~udp_socket() { + } + + size_t udp_socket::send_to( const char* b, size_t l, const ip::endpoint& to ) { + try { + return my->_sock.send_to( boost::asio::buffer(b, l), to_asio_ep(to) ); + } catch( const boost::system::system_error& e ) { + if( e.code() == boost::asio::error::would_block ) { + promise::ptr p(new promise("udp_socket::send_to")); + my->_sock.async_send_to( boost::asio::buffer(b,l), to_asio_ep(to), + [=]( const boost::system::error_code& ec, size_t bt ) { + if( !ec ) p->set_value(bt); + else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + }); + return p->wait(); + } + throw; + } + } + void udp_socket::open() { + my->_sock.open( boost::asio::ip::udp::v4() ); + my->_sock.non_blocking(true); + } + void udp_socket::set_receive_buffer_size( size_t s ) { + my->_sock.set_option(boost::asio::socket_base::receive_buffer_size(s) ); + } + void udp_socket::bind( const fc::ip::endpoint& e ) { + my->_sock.bind( to_asio_ep(e) ); + } + size_t udp_socket::receive_from( char* b, size_t l, fc::ip::endpoint& _from ) { + try { + boost::asio::ip::udp::endpoint from; + size_t r = my->_sock.receive_from( boost::asio::buffer(b, l), from ); + _from = to_fc_ep(from); + return r; + } catch( const boost::system::system_error& e ) { + if( e.code() == boost::asio::error::would_block ) { + boost::asio::ip::udp::endpoint from; + promise::ptr p(new promise("udp_socket::send_to")); + my->_sock.async_receive_from( boost::asio::buffer(b,l), from, + [=]( const boost::system::error_code& ec, size_t bt ) { + if( !ec ) p->set_value(bt); + else p->set_exception( fc::copy_exception( boost::system::system_error(ec) ) ); + }); + auto r = p->wait(); + _from = to_fc_ep(from); + return r; + } + throw; + } + } + void udp_socket::close() { + my->_sock->cancel(); + my->_sock.close(); + } + +}