Files
boost_beast/test/beast/core/stream_socket.cpp
T
Vinnie Falco 6caca92f0e 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.
2018-12-30 16:49:09 -08:00

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