forked from boostorg/beast
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.
280 lines
6.8 KiB
C++
280 lines
6.8 KiB
C++
//
|
|
// 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
|