diff --git a/CMakeLists.txt b/CMakeLists.txt index 08c7538..e273690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ set( sources src/blowfish.cpp src/dh.cpp src/udp_socket.cpp + src/tcp_socket.cpp src/asio.cpp src/super_fast_hash.cpp src/file_mapping.cpp diff --git a/include/fc/tcp_socket.hpp b/include/fc/tcp_socket.hpp new file mode 100644 index 0000000..ad4bcf8 --- /dev/null +++ b/include/fc/tcp_socket.hpp @@ -0,0 +1,40 @@ +#ifndef _FC_TCP_SOCKET_HPP_ +#define _FC_TCP_SOCKET_HPP_ +#include +#include + +namespace fc { + namespace ip { class endpoint; } + class tcp_socket { + public: + tcp_socket(); + ~tcp_socket(); + + void connect_to( const fc::ip::endpoint& e ); + + void write( const char* buffer, size_t len ); + size_t readsome( char* buffer, size_t max ); + size_t read( char* buffer, size_t s ); + + private: + friend class tcp_server; + class impl; + fc::fwd my; + }; + + class tcp_server { + public: + tcp_server(); + ~tcp_server(); + + bool accept( tcp_socket& s ); + void listen( uint16_t port ); + + private: + class impl; + fc::fwd my; + }; + +} // namesapce fc + +#endif // _FC_TCP_SOCKET_HPP_ diff --git a/src/tcp_socket.cpp b/src/tcp_socket.cpp new file mode 100644 index 0000000..058fcd8 --- /dev/null +++ b/src/tcp_socket.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include + +namespace fc { + + class tcp_socket::impl { + public: + impl():_sock( fc::asio::default_io_service() ){} + ~impl(){ + _sock.cancel(); + } + + boost::asio::ip::tcp::socket _sock; + }; + + tcp_socket::tcp_socket(){} + + tcp_socket::~tcp_socket(){} + + + void tcp_socket::write( const char* buf, size_t len ) { + boost::system::error_code ec; + size_t w = my->_sock.write_some( boost::asio::buffer( buf, len ), ec ); + + if( w < len ) { + buf += w; + len -= w; + } + + if( ec == boost::asio::error::would_block ) { + promise::ptr p(new promise("tcp_socket::write")); + boost::asio::async_write( my->_sock, boost::asio::buffer(buf, len), + [=]( 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) ) ); + }); + p->wait(); + } else if( ec ) { + throw boost::system::system_error(ec); + } + } + size_t tcp_socket::readsome( char* buf, size_t len ) { + boost::system::error_code ec; + size_t w = my->_sock.read_some( boost::asio::buffer( buf, len ), ec ); + if( ec == boost::asio::error::would_block ) { + promise::ptr p(new promise("tcp_socket::write")); + my->_sock.async_read_some( boost::asio::buffer(buf, len), + [=]( 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(); + } else if (ec ) { + throw boost::system::system_error(ec); + } + return w; + } + size_t tcp_socket::read( char* buffer, size_t s ) { + size_t r = readsome( buffer, s ); + while( r < s ) { + r += readsome( buffer + r, s - r ); + } + return r; + } + + class tcp_server::impl { + public: + impl():_accept( fc::asio::default_io_service() ){} + ~impl(){ + _accept.cancel(); + } + + boost::asio::ip::tcp::acceptor _accept; + }; + + tcp_server::tcp_server() { + } + tcp_server::~tcp_server() { + } + + + bool tcp_server::accept( tcp_socket& s ) { + fc::promise::ptr p( + new promise("mace::cmt::asio::tcp::accept") ); + my->_accept.async_accept( s.my->_sock, + [=]( const boost::system::error_code& e ) { + p->set_value(e); + } ); + auto ec = p->wait(); + if( !ec ) s.my->_sock.non_blocking(true); + if( ec ) BOOST_THROW_EXCEPTION( boost::system::system_error(ec) ); + return true; + } + void tcp_server::listen( uint16_t port ) { + my->_accept.listen(port); + } + +} // namespace fc