Squashed 'src/beast/' changes from 1ab7a2f..c00cd37

c00cd37 Set version to 1.0.0-b23
f662e36 Travis CI improvements:
b05fa33 Fix message constructor and special members
b4722cc Add copy special members
420d1c7 Better logging in async echo server
149e3a2 Add file and line number to thrown exceptions
3e88b83 Tune websocket echo server for performance

git-subtree-dir: src/beast
git-subtree-split: c00cd37b8a441a92755658014fdde97d515ec7ed
This commit is contained in:
Vinnie Falco
2017-01-17 14:50:38 -05:00
parent af4fe24939
commit 7028579170
20 changed files with 221 additions and 85 deletions

View File

@@ -1,3 +1,4 @@
sudo: false
language: cpp
env:
@@ -11,7 +12,7 @@ env:
- LCOV_ROOT=$HOME/lcov
- VALGRIND_ROOT=$HOME/valgrind-install
- BOOST_ROOT=$HOME/boost_1_61_0
- BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.gz?use_mirror=netix'
- BOOST_URL='http://sourceforge.net/projects/boost/files/boost/1.61.0/boost_1_61_0.tar.gz'
packages: &gcc5_pkgs
- gcc-5
- g++-5
@@ -30,7 +31,7 @@ packages: &gcc5_pkgs
matrix:
include:
# GCC/Coverage/Autobahn
# GCC/Coverage/Autobahn (if master or develop branch)
- compiler: gcc
env:
- GCC_VER=5
@@ -77,7 +78,7 @@ before_install:
- scripts/install-dependencies.sh
script:
- scripts/build-and-test.sh
- travis_retry scripts/build-and-test.sh
after_script:
- cat nohup.out || echo "nohup.out already deleted"

View File

@@ -1,3 +1,14 @@
1.0.0-b23
* Tune websocket echo server for performance
* Add file and line number to thrown exceptions
* Better logging in async echo server
* Add copy special members
* Fix message constructor and special members
* Travis CI improvements
--------------------------------------------------------------------------------
1.0.0-b22
* Fix broken Intellisense

View File

@@ -253,7 +253,8 @@ private:
reference
dereference(C<sizeof...(Bn)> const&) const
{
throw std::logic_error("invalid iterator");
throw detail::make_exception<std::logic_error>(
"invalid iterator", __FILE__, __LINE__);
}
template<std::size_t I>
@@ -269,7 +270,8 @@ private:
void
increment(C<sizeof...(Bn)> const&)
{
throw std::logic_error("invalid iterator");
throw detail::make_exception<std::logic_error>(
"invalid iterator", __FILE__, __LINE__);
}
template<std::size_t I>
@@ -310,7 +312,8 @@ private:
--iter<I>();
return;
}
throw std::logic_error("invalid iterator");
throw detail::make_exception<std::logic_error>(
"invalid iterator", __FILE__, __LINE__);
}
template<std::size_t I>

View File

@@ -10,6 +10,8 @@
#include <tuple>
#include <type_traits>
#include <stdexcept>
#include <string>
namespace beast {
namespace detail {
@@ -78,6 +80,18 @@ struct repeat_tuple<0, T>
using type = std::tuple<>;
};
template<class Exception>
Exception
make_exception(char const* reason, char const* file, int line)
{
char const* n = file;
for(auto p = file; *p; ++p)
if(*p == '\\' || *p == '/')
n = p + 1;
return Exception{std::string(reason) + " (" +
n + ":" + std::to_string(line) + ")"};
}
} // detail
} // beast

View File

@@ -524,8 +524,8 @@ basic_streambuf<Allocator>::basic_streambuf(
, alloc_size_(alloc_size)
{
if(alloc_size <= 0)
throw std::invalid_argument(
"basic_streambuf: invalid alloc_size");
throw detail::make_exception<std::invalid_argument>(
"invalid alloc_size", __FILE__, __LINE__);
}
template<class Allocator>

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_IMPL_BUFFERS_ADAPTER_IPP
#define BEAST_IMPL_BUFFERS_ADAPTER_IPP
#include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstring>
@@ -413,8 +414,8 @@ buffers_adapter<MutableBufferSequence>::prepare(std::size_t n) ->
}
}
if(n > 0)
throw std::length_error(
"no space in buffers_adapter");
throw detail::make_exception<std::length_error>(
"no space", __FILE__, __LINE__);
return mutable_buffers_type{*this};
}

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_IMPL_STATIC_STREAMBUF_IPP
#define BEAST_IMPL_STATIC_STREAMBUF_IPP
#include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <cstring>
@@ -295,7 +296,8 @@ static_streambuf::prepare(std::size_t n) ->
mutable_buffers_type
{
if(n > static_cast<std::size_t>(end_ - out_))
throw std::length_error("no space in streambuf");
throw detail::make_exception<std::length_error>(
"no space in streambuf", __FILE__, __LINE__);
last_ = out_ + n;
return mutable_buffers_type{out_, n};
}

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_WEBSOCKET_STATIC_STRING_HPP
#define BEAST_WEBSOCKET_STATIC_STRING_HPP
#include <beast/core/detail/type_traits.hpp>
#include <array>
#include <cstdint>
#include <iterator>
@@ -329,7 +330,8 @@ static_string<N, CharT, Traits>::
static_string(static_string<M, CharT, Traits> const& s)
{
if(s.size() > N)
throw std::length_error("static_string overflow");
throw detail::make_exception<std::length_error>(
"static_string overflow", __FILE__, __LINE__);
n_ = s.size();
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
}
@@ -353,7 +355,8 @@ operator=(static_string<M, CharT, Traits> const& s) ->
static_string&
{
if(s.size() > N)
throw std::length_error("static_string overflow");
throw detail::make_exception<std::length_error>(
"static_string overflow", __FILE__, __LINE__);
n_ = s.size();
Traits::copy(&s_[0], &s.s_[0], n_ + 1);
return *this;
@@ -391,7 +394,8 @@ at(size_type pos) ->
reference
{
if(pos >= n_)
throw std::out_of_range("static_string::at");
throw detail::make_exception<std::out_of_range>(
"invalid pos", __FILE__, __LINE__);
return s_[pos];
}
@@ -402,7 +406,8 @@ at(size_type pos) const ->
const_reference
{
if(pos >= n_)
throw std::out_of_range("static_string::at");
throw detail::make_exception<std::out_of_range>(
"static_string::at", __FILE__, __LINE__);
return s_[pos];
}
@@ -412,7 +417,8 @@ static_string<N, CharT, Traits>::
resize(std::size_t n)
{
if(n > N)
throw std::length_error("static_string overflow");
throw detail::make_exception<std::length_error>(
"static_string overflow", __FILE__, __LINE__);
n_ = n;
s_[n_] = 0;
}
@@ -423,7 +429,8 @@ static_string<N, CharT, Traits>::
resize(std::size_t n, CharT c)
{
if(n > N)
throw std::length_error("static_string overflow");
throw detail::make_exception<std::length_error>(
"static_string overflow", __FILE__, __LINE__);
if(n > n_)
Traits::assign(&s_[n_], n - n_, c);
n_ = n;
@@ -462,7 +469,8 @@ assign(CharT const* s)
{
auto const n = Traits::length(s);
if(n > N)
throw std::out_of_range("too large");
throw detail::make_exception<std::out_of_range>(
"too large", __FILE__, __LINE__);
n_ = n;
Traits::copy(&s_[0], s, n_ + 1);
}

View File

@@ -159,6 +159,8 @@ void
prepare(message<isRequest, Body, Fields>& msg,
Options&&... options)
{
using beast::detail::make_exception;
// VFALCO TODO
static_assert(is_Body<Body>::value,
"Body requirements not met");
@@ -174,16 +176,16 @@ prepare(message<isRequest, Body, Fields>& msg,
std::forward<Options>(options)...);
if(msg.fields.exists("Connection"))
throw std::invalid_argument(
"prepare called with Connection field set");
throw make_exception<std::invalid_argument>(
"prepare called with Connection field set", __FILE__, __LINE__);
if(msg.fields.exists("Content-Length"))
throw std::invalid_argument(
"prepare called with Content-Length field set");
throw make_exception<std::invalid_argument>(
"prepare called with Content-Length field set", __FILE__, __LINE__);
if(token_list{msg.fields["Transfer-Encoding"]}.exists("chunked"))
throw std::invalid_argument(
"prepare called with Transfer-Encoding: chunked set");
throw make_exception<std::invalid_argument>(
"prepare called with Transfer-Encoding: chunked set", __FILE__, __LINE__);
if(pi.connection_value != connection::upgrade)
{
@@ -254,8 +256,8 @@ prepare(message<isRequest, Body, Fields>& msg,
// rfc7230 6.7.
if(msg.version < 11 && token_list{
msg.fields["Connection"]}.exists("upgrade"))
throw std::invalid_argument(
"invalid version for Connection: upgrade");
throw make_exception<std::invalid_argument>(
"invalid version for Connection: upgrade", __FILE__, __LINE__);
}
} // http

View File

@@ -246,6 +246,18 @@ struct message : header<isRequest, Fields>
/// Default constructor
message() = default;
/// Move constructor
message(message&&) = default;
/// Copy constructor
message(message const&) = default;
/// Move assignment
message& operator=(message&&) = default;
/// Copy assignment
message& operator=(message const&) = default;
/** Construct a message from a header.
Additional arguments, if any, are forwarded to
@@ -281,8 +293,9 @@ struct message : header<isRequest, Fields>
*/
template<class U
#if ! GENERATING_DOCS
, class = typename std::enable_if<! std::is_convertible<
typename std::decay<U>::type, base_type>::value>
, class = typename std::enable_if<
! std::is_convertible<typename
std::decay<U>::type, base_type>::value>::type
#endif
>
explicit
@@ -303,7 +316,7 @@ struct message : header<isRequest, Fields>
template<class U, class V
#if ! GENERATING_DOCS
,class = typename std::enable_if<! std::is_convertible<
typename std::decay<U>::type, base_type>::value>
typename std::decay<U>::type, base_type>::value>::type
#endif
>
message(U&& u, V&& v)

View File

@@ -16,6 +16,6 @@
//
#define BEAST_VERSION 100000
#define BEAST_VERSION_STRING "1.0.0-b22"
#define BEAST_VERSION_STRING "1.0.0-b23"
#endif

View File

@@ -20,6 +20,7 @@
#include <beast/core/prepare_buffers.hpp>
#include <beast/core/static_streambuf.hpp>
#include <beast/core/stream_concepts.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/endian/buffers.hpp>
#include <algorithm>

View File

@@ -10,6 +10,7 @@
#include <beast/websocket/rfc6455.hpp>
#include <beast/websocket/detail/decorator.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <algorithm>
#include <cstdint>
#include <functional>
@@ -186,7 +187,8 @@ struct message_type
message_type(opcode op)
{
if(op != opcode::binary && op != opcode::text)
throw std::domain_error("bad opcode");
throw beast::detail::make_exception<std::invalid_argument>(
"bad opcode", __FILE__, __LINE__);
value = op;
}
};
@@ -277,6 +279,9 @@ struct read_buffer_size
read_buffer_size(std::size_t n)
: value(n)
{
if(n < 8)
throw beast::detail::make_exception<std::invalid_argument>(
"read buffer size is too small", __FILE__, __LINE__);
}
};
#endif
@@ -356,7 +361,8 @@ struct write_buffer_size
: value(n)
{
if(n < 8)
throw std::domain_error("write buffer size is too small");
throw beast::detail::make_exception<std::invalid_argument>(
"write buffer size is too small", __FILE__, __LINE__);
}
};
#endif

View File

@@ -37,6 +37,7 @@
#include <beast/zlib/zlib.hpp>
#include <beast/zlib/detail/ranges.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <cstdint>
@@ -893,14 +894,19 @@ doReset(
if(windowBits == 8)
windowBits = 9;
using beast::detail::make_exception;
if(level < 0 || level > 9)
throw std::invalid_argument{"invalid level"};
throw make_exception<std::invalid_argument>(
"invalid level", __FILE__, __LINE__);
if(windowBits < 8 || windowBits > 15)
throw std::invalid_argument{"invalid windowBits"};
throw make_exception<std::invalid_argument>(
"invalid windowBits", __FILE__, __LINE__);
if(memLevel < 1 || memLevel > MAX_MEM_LEVEL)
throw std::invalid_argument{"invalid memLevel"};
throw make_exception<std::invalid_argument>(
"invalid memLevel", __FILE__, __LINE__);
w_bits_ = windowBits;

View File

@@ -40,6 +40,7 @@
#include <beast/zlib/detail/bitstream.hpp>
#include <beast/zlib/detail/ranges.hpp>
#include <beast/zlib/detail/window.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <algorithm>
#include <array>
#include <cstdint>
@@ -232,7 +233,8 @@ inflate_stream::
doReset(int windowBits)
{
if(windowBits < 8 || windowBits > 15)
throw std::domain_error("windowBits out of range");
throw beast::detail::make_exception<std::domain_error>(
"windowBits out of range", __FILE__, __LINE__);
w_.reset(windowBits);
bi_.flush();
@@ -706,7 +708,8 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
case SYNC:
default:
throw std::logic_error("stream error");
throw beast::detail::make_exception<std::logic_error>(
"stream error", __FILE__, __LINE__);
}
}
}
@@ -932,8 +935,8 @@ inflate_table(
auto const not_enough = []
{
throw std::logic_error(
"insufficient output size when inflating tables");
throw beast::detail::make_exception<std::logic_error>(
"insufficient output size when inflating tables", __FILE__, __LINE__);
};
// check available table space

View File

@@ -40,6 +40,9 @@ elif [[ $(uname -s) == "Linux" ]]; then
if ((${num_proc_units} < ${num_jobs})); then
num_jobs=$num_proc_units
fi
if [[ "${TRAVIS}" == "true" && ${NUM_PROCESSORS:=2} > ${num_jobs} ]]; then
num_jobs=$NUM_PROCESSORS
fi
fi
echo "using toolset: $CC"
@@ -99,10 +102,10 @@ function run_autobahn_test_suite {
# We need to wait a while so wstest can connect!
sleep 5
# Show the output (if any) as it is generated
tail -f nohup.out &
cd scripts && wstest -m fuzzingclient
cd ..
# Show the output
cat nohup.out
rm nohup.out
# Show what jobs are running
jobs
@@ -110,6 +113,7 @@ function run_autobahn_test_suite {
sleep 5
# Kill it gracefully
kill -INT %1
kill -INT %2
# Wait for all the jobs to finish
wait
# Parse the test results, with python>=2.5<3 script
@@ -135,9 +139,10 @@ if [[ $VARIANT == "coverage" ]]; then
# Perform test
if [[ $MAIN_BRANCH == "1" ]]; then
run_tests_with_valgrind
run_autobahn_test_suite
# skip slow autobahn tests
#run_autobahn_test_suite
else
echo "skipping autobahn tests for feature branch build"
echo "skipping autobahn/valgrind tests for feature branch build"
run_tests
fi

View File

@@ -278,6 +278,19 @@ public:
BEAST_EXPECT(m2.fields.exists("h"));
}
void
testSpecialMembers()
{
response<string_body> r1;
response<string_body> r2{r1};
response<string_body> r3{std::move(r2)};
r2 = r3;
r1 = std::move(r2);
[r1]()
{
}();
}
void run() override
{
testMessage();
@@ -285,6 +298,7 @@ public:
testFreeFunctions();
testPrepare();
testSwap();
testSpecialMembers();
}
};

View File

@@ -1416,7 +1416,10 @@ public:
yield_to_mf(ep, &stream_test::testAsyncClient);
}
{
async_echo_server server(true, any, 4);
error_code ec;
async_echo_server server{nullptr, 4};
server.open(true, any, ec);
BEAST_EXPECTS(! ec, ec.message());
auto const ep = server.local_endpoint();
testSyncClient(ep);
testAsyncWriteFrame(ep);

View File

@@ -18,6 +18,8 @@
#include <memory>
#include <thread>
#include <ostream>
namespace beast {
namespace websocket {
@@ -31,38 +33,24 @@ public:
using socket_type = boost::asio::ip::tcp::socket;
private:
bool log_ = false;
std::ostream* log_;
boost::asio::io_service ios_;
socket_type sock_;
boost::asio::ip::tcp::acceptor acceptor_;
std::vector<std::thread> thread_;
boost::optional<boost::asio::io_service::work> work_;
public:
async_echo_server(bool server,
endpoint_type const& ep, std::size_t threads)
: sock_(ios_)
async_echo_server(async_echo_server const&) = delete;
async_echo_server& operator=(async_echo_server const&) = delete;
async_echo_server(std::ostream* log,
std::size_t threads)
: log_(log)
, sock_(ios_)
, acceptor_(ios_)
, work_(ios_)
{
if(server)
{
error_code ec;
acceptor_.open(ep.protocol(), ec);
maybe_throw(ec, "open");
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
maybe_throw(ec, "bind");
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
maybe_throw(ec, "listen");
acceptor_.async_accept(sock_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
else
{
Peer{log_, std::move(sock_), ep};
}
thread_.reserve(threads);
for(std::size_t i = 0; i < threads; ++i)
thread_.emplace_back(
@@ -71,6 +59,7 @@ public:
~async_echo_server()
{
work_ = boost::none;
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
@@ -78,6 +67,46 @@ public:
t.join();
}
void
open(bool server,
endpoint_type const& ep, error_code& ec)
{
if(server)
{
acceptor_.open(ep.protocol(), ec);
if(ec)
{
if(log_)
(*log_) << "open: " << ec.message() << std::endl;
return;
}
acceptor_.set_option(
boost::asio::socket_base::reuse_address{true});
acceptor_.bind(ep, ec);
if(ec)
{
if(log_)
(*log_) << "bind: " << ec.message() << std::endl;
return;
}
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
if(ec)
{
if(log_)
(*log_) << "listen: " << ec.message() << std::endl;
return;
}
acceptor_.async_accept(sock_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
}
else
{
Peer{*this, std::move(sock_), ep};
}
}
endpoint_type
local_endpoint() const
{
@@ -89,7 +118,7 @@ private:
{
struct data
{
bool log;
async_echo_server& server;
int state = 0;
boost::optional<endpoint_type> ep;
stream<socket_type> ws;
@@ -98,8 +127,9 @@ private:
beast::streambuf db;
int id;
data(bool log_, socket_type&& sock_)
: log(log_)
data(async_echo_server& server_,
socket_type&& sock_)
: server(server_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
, id([]
@@ -110,9 +140,9 @@ private:
{
}
data(bool log_, socket_type&& sock_,
endpoint_type const& ep_)
: log(log_)
data(async_echo_server& server_,
socket_type&& sock_, endpoint_type const& ep_)
: server(server_)
, ep(ep_)
, ws(std::move(sock_))
, strand(ws.get_io_service())
@@ -152,14 +182,17 @@ private:
template<class... Args>
explicit
Peer(bool log, socket_type&& sock, Args&&... args)
: d_(std::make_shared<data>(log,
Peer(async_echo_server& server,
socket_type&& sock, Args&&... args)
: d_(std::make_shared<data>(server,
std::forward<socket_type>(sock),
std::forward<Args>(args)...))
{
auto& d = *d_;
d.ws.set_option(decorate(identity{}));
d.ws.set_option(read_message_max(64 * 1024 * 1024));
d.ws.set_option(auto_fragment{false});
//d.ws.set_option(write_buffer_size{64 * 1024});
run();
}
@@ -289,10 +322,10 @@ private:
fail(error_code ec, std::string what)
{
auto& d = *d_;
if(d.log)
if(d.server.log_)
{
if(ec != error::closed)
std::cerr << "#" << d_->id << " " <<
(*d.server.log_) << "#" << d.id << " " <<
what << ": " << ec.message() << std::endl;
}
}
@@ -302,7 +335,7 @@ private:
fail(error_code ec, std::string what)
{
if(log_)
std::cerr << what << ": " <<
(*log_) << what << ": " <<
ec.message() << std::endl;
}
@@ -328,7 +361,7 @@ private:
acceptor_.async_accept(sock_,
std::bind(&async_echo_server::on_accept, this,
beast::asio::placeholders::error));
Peer{false, std::move(sock)};
Peer{*this, std::move(sock)};
}
};

View File

@@ -8,17 +8,27 @@
#include "websocket_async_echo_server.hpp"
#include "websocket_sync_echo_server.hpp"
#include <beast/test/sig_wait.hpp>
#include <iostream>
int main()
{
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
beast::websocket::async_echo_server s1(true, endpoint_type{
address_type::from_string("127.0.0.1"), 6000 }, 4);
try
{
boost::system::error_code ec;
beast::websocket::async_echo_server s1{nullptr, 1};
s1.open(true, endpoint_type{
address_type::from_string("127.0.0.1"), 6000 }, ec);
beast::websocket::sync_echo_server s2(true, endpoint_type{
address_type::from_string("127.0.0.1"), 6001 });
beast::websocket::sync_echo_server s2(true, endpoint_type{
address_type::from_string("127.0.0.1"), 6001 });
beast::test::sig_wait();
beast::test::sig_wait();
}
catch(std::exception const& e)
{
std::cout << "Error: " << e.what() << std::endl;
}
}