diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 50c76500ca..709a36b443 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2532,8 +2532,6 @@ - - @@ -2550,7 +2548,7 @@ - + True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index d30891af23..f2fcb57cb9 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -3561,9 +3561,6 @@ ripple\overlay\impl - - ripple\overlay\impl - ripple\overlay\impl @@ -3588,7 +3585,7 @@ ripple\overlay - + ripple\overlay\tests diff --git a/src/ripple/overlay/impl/peer_info.h b/src/ripple/overlay/impl/peer_info.h deleted file mode 100644 index 803c343df3..0000000000 --- a/src/ripple/overlay/impl/peer_info.h +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef RIPPLE_OVERLAY_PEER_INFO_H_INCLUDED -#define RIPPLE_OVERLAY_PEER_INFO_H_INCLUDED - -#include - -namespace ripple { - -struct parsed_request -{ - int version_major; - int version_minor; -}; - - -} - -#endif diff --git a/src/ripple/overlay/tests/peer_info.test.cpp b/src/ripple/overlay/tests/peer_info.test.cpp deleted file mode 100644 index 9f387cd1d0..0000000000 --- a/src/ripple/overlay/tests/peer_info.test.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include -#include -#include -#include -#include -#include - -namespace ripple { - -class peer_info_test : public beast::unit_test::suite -{ -public: - void - run() - { - pass(); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(peer_info,overlay,ripple); - -} // ripple - diff --git a/src/ripple/overlay/tests/short_read.test.cpp b/src/ripple/overlay/tests/short_read.test.cpp new file mode 100644 index 0000000000..a241959584 --- /dev/null +++ b/src/ripple/overlay/tests/short_read.test.cpp @@ -0,0 +1,545 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +class short_read_test : public beast::unit_test::suite +{ +private: + using io_service_type = boost::asio::io_service; + using strand_type = io_service_type::strand; + using timer_type = boost::asio::basic_waitable_timer< + std::chrono::steady_clock>; + using acceptor_type = boost::asio::ip::tcp::acceptor; + using socket_type = boost::asio::ip::tcp::socket; + using stream_type = boost::asio::ssl::stream; + using error_code = boost::system::error_code; + using endpoint_type = boost::asio::ip::tcp::endpoint; + using address_type = boost::asio::ip::address; + + io_service_type io_service_; + boost::optional work_; + std::thread thread_; + std::shared_ptr context_; + + static + endpoint_type + endpoint() + { + return endpoint_type(address_type::from_string("127.0.0.1"), 9000); + } + + template + static + void + write(Streambuf& sb, std::string const& s) + { + using boost::asio::buffer; + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + boost::asio::const_buffers_1 buf(s.data(), s.size()); + sb.commit(buffer_copy(sb.prepare(buffer_size(buf)), buf)); + } + + //-------------------------------------------------------------------------- + + class Base + { + protected: + class Child + { + private: + Base& base_; + + public: + Child(Base& base) + : base_(base) + { + } + + virtual ~Child() + { + base_.remove(this); + } + + virtual void close() = 0; + }; + + private: + std::mutex mutex_; + std::condition_variable cond_; + std::map> list_; + bool closed_ = false; + + public: + ~Base() + { + // Derived class must call wait() in the destructor + assert(list_.empty()); + } + + void + add (std::shared_ptr const& child) + { + std::unique_lock lock(mutex_); + list_.emplace(child.get(), child); + } + + void + remove (Child* child) + { + std::unique_lock lock(mutex_); + list_.erase(child); + if (list_.empty()) + cond_.notify_one(); + } + + void + close() + { + std::unique_lock lock(mutex_); + if (closed_) + return; + closed_ = true; + for(auto& c : list_) + if(auto p = c.second.lock()) + p->close(); + } + + void + wait() + { + std::unique_lock lock(mutex_); + while(! list_.empty()) + cond_.wait(lock); + } + }; + + //-------------------------------------------------------------------------- + + class Server : public Base + { + private: + short_read_test& test_; + + struct Acceptor + : Child, std::enable_shared_from_this + { + Server& server_; + short_read_test& test_; + acceptor_type acceptor_; + socket_type socket_; + strand_type strand_; + + Acceptor(Server& server) + : Child(server) + , server_(server) + , test_(server_.test_) + , acceptor_(test_.io_service_, endpoint()) + , socket_(test_.io_service_) + , strand_(socket_.get_io_service()) + { + acceptor_.listen(); + } + + void + close() override + { + if(! strand_.running_in_this_thread()) + return strand_.post(std::bind(&Acceptor::close, + shared_from_this())); + acceptor_.close(); + } + + void + run() + { + acceptor_.async_accept(socket_, strand_.wrap(std::bind( + &Acceptor::on_accept, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + fail (std::string const& what, error_code ec) + { + if (acceptor_.is_open()) + { + if (ec != boost::asio::error::operation_aborted) + test_.log << what << ": " << ec.message(); + acceptor_.close(); + } + } + + void + on_accept(error_code ec) + { + if (ec) + return fail ("accept", ec); + auto const p = std::make_shared( + server_, std::move(socket_)); + server_.add(p); + p->run(); + acceptor_.async_accept(socket_, strand_.wrap(std::bind( + &Acceptor::on_accept, shared_from_this(), + beast::asio::placeholders::error))); + } + }; + + struct Connection + : Child, std::enable_shared_from_this + { + Server& server_; + short_read_test& test_; + socket_type socket_; + stream_type stream_; + strand_type strand_; + timer_type timer_; + boost::asio::streambuf buf_; + + Connection (Server& server, socket_type&& socket) + : Child(server) + , server_(server) + , test_(server_.test_) + , socket_(std::move(socket)) + , stream_(socket_, *test_.context_) + , strand_(socket_.get_io_service()) + , timer_(socket_.get_io_service()) + { + } + + void + close() override + { + if(! strand_.running_in_this_thread()) + return strand_.post(std::bind(&Connection::close, + shared_from_this())); + if (socket_.is_open()) + { + socket_.close(); + timer_.cancel(); + } + } + + void + run() + { + timer_.expires_from_now(std::chrono::seconds(3)); + timer_.async_wait(strand_.wrap(std::bind(&Connection::on_timer, + shared_from_this(), beast::asio::placeholders::error))); + stream_.async_handshake(stream_type::server, strand_.wrap( + std::bind(&Connection::on_handshake, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + fail (std::string const& what, error_code ec) + { + if (socket_.is_open()) + { + if (ec != boost::asio::error::operation_aborted) + test_.log << "[server] " << what << ": " << ec.message(); + socket_.close(); + timer_.cancel(); + } + } + + void + on_timer(error_code ec) + { + if (ec == boost::asio::error::operation_aborted) + return; + if (ec) + return fail("timer", ec); + test_.log << "[server] timeout"; + socket_.close(); + } + + void + on_handshake(error_code ec) + { + if (ec) + return fail("handshake", ec); + boost::asio::async_read_until(stream_, buf_, "\n", strand_.wrap( + std::bind(&Connection::on_read, shared_from_this(), + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred))); + } + + void + on_read(error_code ec, std::size_t bytes_transferred) + { + if (ec == boost::asio::error::eof) + return stream_.async_shutdown(strand_.wrap(std::bind( + &Connection::on_shutdown, shared_from_this(), + beast::asio::placeholders::error))); + if (ec) + return fail("read", ec); + + buf_.commit(bytes_transferred); + buf_.consume(bytes_transferred); + write(buf_, "BYE\n"); + boost::asio::async_write(stream_, buf_.data(), strand_.wrap( + std::bind(&Connection::on_write, shared_from_this(), + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred))); + } + + void + on_write(error_code ec, std::size_t bytes_transferred) + { + buf_.consume(bytes_transferred); + if (ec) + return fail("write", ec); + stream_.async_shutdown(strand_.wrap(std::bind( + &Connection::on_shutdown, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + on_shutdown(error_code ec) + { + if (ec) + return fail("shutdown", ec); + socket_.close(); + timer_.cancel(); + } + }; + + public: + Server(short_read_test& test) + : test_(test) + { + auto const p = std::make_shared(*this); + add(p); + p->run(); + } + + ~Server() + { + close(); + wait(); + } + }; + + //-------------------------------------------------------------------------- + + class Client : public Base + { + private: + short_read_test& test_; + + struct Connection + : Child, std::enable_shared_from_this + { + Client& client_; + short_read_test& test_; + socket_type socket_; + stream_type stream_; + strand_type strand_; + timer_type timer_; + boost::asio::streambuf buf_; + + Connection (Client& client) + : Child(client) + , client_(client) + , test_(client_.test_) + , socket_(test_.io_service_) + , stream_(socket_, *test_.context_) + , strand_(socket_.get_io_service()) + , timer_(socket_.get_io_service()) + { + } + + void + close() override + { + if(! strand_.running_in_this_thread()) + return strand_.post(std::bind(&Connection::close, + shared_from_this())); + if (socket_.is_open()) + { + socket_.close(); + timer_.cancel(); + } + } + + void + run() + { + timer_.expires_from_now(std::chrono::seconds(3)); + timer_.async_wait(strand_.wrap(std::bind(&Connection::on_timer, + shared_from_this(), beast::asio::placeholders::error))); + socket_.async_connect(endpoint(), strand_.wrap(std::bind( + &Connection::on_connect, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + fail (std::string const& what, error_code ec) + { + if (socket_.is_open()) + { + if (ec != boost::asio::error::operation_aborted) + test_.log << "[client] " << what << ": " << ec.message(); + socket_.close(); + timer_.cancel(); + } + } + + void + on_timer(error_code ec) + { + if (ec == boost::asio::error::operation_aborted) + return; + if (ec) + return fail("timer", ec); + test_.log << "[client] timeout"; + socket_.close(); + } + + void + on_connect(error_code ec) + { + if (ec) + return fail("connect", ec); + stream_.async_handshake(stream_type::client, strand_.wrap( + std::bind(&Connection::on_handshake, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + on_handshake(error_code ec) + { + if (ec) + return fail("handshake", ec); + write(buf_, "HELLO\n"); + +#if 1 + boost::asio::async_write(stream_, buf_.data(), strand_.wrap( + std::bind(&Connection::on_write, shared_from_this(), + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred))); +#else + stream_.async_shutdown(strand_.wrap(std::bind( + &Connection::on_shutdown, shared_from_this(), + beast::asio::placeholders::error))); +#endif + } + + void + on_write(error_code ec, std::size_t bytes_transferred) + { + buf_.consume(bytes_transferred); + if (ec) + return fail("write", ec); +#if 0 + boost::asio::async_read_until(stream_, buf_, "\n", strand_.wrap( + std::bind(&Connection::on_read, shared_from_this(), + beast::asio::placeholders::error, + beast::asio::placeholders::bytes_transferred))); +#else + stream_.async_shutdown(strand_.wrap(std::bind( + &Connection::on_shutdown, shared_from_this(), + beast::asio::placeholders::error))); +#endif + } + + void + on_read(error_code ec, std::size_t bytes_transferred) + { + if (ec) + return fail("read", ec); + buf_.commit(bytes_transferred); + stream_.async_shutdown(strand_.wrap(std::bind( + &Connection::on_shutdown, shared_from_this(), + beast::asio::placeholders::error))); + } + + void + on_shutdown(error_code ec) + { + + if (ec) + return fail("shutdown", ec); + socket_.close(); + timer_.cancel(); + } + }; + + public: + Client(short_read_test& test) + : test_(test) + { + auto const p = std::make_shared(*this); + add(p); + p->run(); + } + + ~Client() + { + close(); + wait(); + } + }; + +public: + short_read_test() + : work_(boost::in_place(std::ref(io_service_))) + , thread_(std::thread([this]() + { + beast::Thread::setCurrentThreadName("io_service"); + this->io_service_.run(); + })) + , context_(make_SSLContext()) + { + } + + ~short_read_test() + { + work_ = boost::none; + thread_.join(); + } + + void run() override + { + Server s(*this); + Client c(*this); + c.wait(); + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE_MANUAL(short_read,overlay,ripple); + +} diff --git a/src/ripple/unity/overlay.cpp b/src/ripple/unity/overlay.cpp index 16aac28616..de99c4e8af 100644 --- a/src/ripple/unity/overlay.cpp +++ b/src/ripple/unity/overlay.cpp @@ -27,5 +27,5 @@ #include #include #include -#include +#include