forked from boostorg/beast
New stream_socket:
This I/O object wraps an ordinary socket and provides a built-in timeout and optional bandwidth rate-limiting facility. Added class template basic_stream_socket * Meets the requirements of AsyncReadStream and AsyncWriteStream * Partially supports P1322R0: "Networking TS enhancement to enable custom I/O executors" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1322r0.html A strand or other io_context-compatible executor may be chosen to use for all asynchronous stream operations. * Supports independent timeouts on logical operations: connect, read, write, or both read and write. * Provides an option for a configurable rate limit limit on the maximum rates of reading or writing. * The previous experimental implementation, `timeout_socket` and related types, is removed. * stream_socket is an alias for basic_stream_socket which uses `net::ip::tcp` as its protocol.
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
//
|
||||
// Copyright (c) 2018 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// Official repository: https://github.com/boostorg/beast
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/beast/core/stream_socket.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <boost/beast/test/yield_to.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
|
||||
namespace boost {
|
||||
namespace beast {
|
||||
|
||||
class stream_socket_test
|
||||
: public beast::unit_test::suite
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
class server
|
||||
{
|
||||
std::ostream& log_;
|
||||
net::io_context ioc_;
|
||||
net::ip::tcp::acceptor acceptor_;
|
||||
net::ip::tcp::socket socket_;
|
||||
std::thread t_;
|
||||
|
||||
void
|
||||
fail(error_code ec, string_view what)
|
||||
{
|
||||
if(ec != net::error::operation_aborted)
|
||||
log_ << what << ": " << ec.message() << "\n";
|
||||
}
|
||||
|
||||
public:
|
||||
server(
|
||||
net::ip::tcp::endpoint ep,
|
||||
std::ostream& log)
|
||||
: log_(log)
|
||||
, ioc_(1)
|
||||
, acceptor_(ioc_)
|
||||
, socket_(ioc_)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
acceptor_.open(ep.protocol(), ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "open");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptor_.set_option(
|
||||
net::socket_base::reuse_address(true), ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "set_option");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptor_.bind(ep, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "bind");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptor_.listen(
|
||||
net::socket_base::max_listen_connections, ec);
|
||||
if(ec)
|
||||
{
|
||||
fail(ec, "listen");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptor_.async_accept(socket_,
|
||||
[this](error_code ec){ this->on_accept(ec); });
|
||||
|
||||
t_ = std::thread([this]{ ioc_.run(); });
|
||||
}
|
||||
|
||||
~server()
|
||||
{
|
||||
ioc_.stop();
|
||||
t_.join();
|
||||
}
|
||||
|
||||
private:
|
||||
class session
|
||||
: public std::enable_shared_from_this<session>
|
||||
{
|
||||
net::ip::tcp::socket socket_;
|
||||
|
||||
public:
|
||||
session(
|
||||
net::ip::tcp::socket sock,
|
||||
std::ostream&)
|
||||
: socket_(std::move(sock))
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
socket_.async_wait(
|
||||
net::socket_base::wait_read,
|
||||
std::bind(
|
||||
&session::on_read,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
on_read(error_code ec)
|
||||
{
|
||||
boost::ignore_unused(ec);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
on_accept(error_code ec)
|
||||
{
|
||||
if(! acceptor_.is_open())
|
||||
return;
|
||||
if(ec)
|
||||
fail(ec, "accept");
|
||||
else
|
||||
std::make_shared<session>(
|
||||
std::move(socket_), log_)->run();
|
||||
acceptor_.async_accept(socket_,
|
||||
[this](error_code ec)
|
||||
{
|
||||
this->on_accept(ec);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testAsync()
|
||||
{
|
||||
net::ip::tcp::endpoint ep(
|
||||
net::ip::make_address("127.0.0.1"), 8080);
|
||||
server srv(ep, log);
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
s.next_layer().connect(ep);
|
||||
char buf[32];
|
||||
error_code ec;
|
||||
s.expires_after(std::chrono::seconds(1));
|
||||
s.async_read_some(net::buffer(buf),
|
||||
[&ec](error_code ec_, std::size_t)
|
||||
{
|
||||
ec = ec_;
|
||||
});
|
||||
ioc.run();
|
||||
BEAST_EXPECTS(
|
||||
ec == error::timeout, ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testConnect()
|
||||
{
|
||||
using es_t =
|
||||
std::array<net::ip::tcp::endpoint, 2>;
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
beast::async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
pass();
|
||||
}
|
||||
|
||||
void callConnects()
|
||||
{
|
||||
using es_t =
|
||||
std::array<net::ip::tcp::endpoint, 2>;
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es_t{},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
{
|
||||
es_t es;
|
||||
net::io_context ioc;
|
||||
stream_socket s(ioc);
|
||||
async_connect(s, es.begin(), es.end(),
|
||||
[](error_code, es_t::value_type)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
[](error_code, es_t::iterator)
|
||||
{
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run()
|
||||
{
|
||||
testAsync();
|
||||
testConnect();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(beast,core,stream_socket);
|
||||
|
||||
} // beast
|
||||
} // boost
|
||||
Reference in New Issue
Block a user