I am trying to make a REASON API server that will accept requests from another application, but the problem is that after the first connection to it, it shuts down with the error -1073741819. When I went through it with the debugger, I found out that the error is called buffer_ "An unhandled exception was caused: a violation of read access.this was 0xffffffffffffffffff.", but I do not know how to solve this problem
cpp.file
-------------------
#include "Server.h"
using namespace boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = boost::asio::ip::tcp;
Server::Server(boost::asio::io_service& io_service, int port)
: acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
socket_(io_service) {
StartAccept();
}
void Server::StartAccept() {
acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
if (!ec) {
std::cout << "Client connected" << std::endl;
ReadRequest();
}
else {
std::cerr << "Client error: " << ec.message() << std::endl;
}
});
}
void Server::ReadRequest() {
buffer_.consume(buffer_.size());
buffer_.prepare(1024);
beast::http::async_read(socket_, buffer_, request_,
[this](boost::system::error_code ec, size_t bytes_transferred) {
if (!ec) {
ProcessRequest();
}
else {
std::cerr << "Error ReadRequest: " << ec.message() << std::endl;
}
});
}
void Server::ProcessRequest(){
if (request_.method() == http::verb::get) {
http::response<http::string_body> response(http::status::ok, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Hello, World";
response.prepare_payload();
WriteResponse(response);
}
else {
http::response<http::string_body> response(http::status::bad_request, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Invalide request!";
response.prepare_payload();
WriteResponse(response);
}
}
void Server::WriteResponse(boost::beast::http::response<boost::beast::http::string_body>& response_){
http::async_write(socket_, response_,
[this](boost::system::error_code ec, size_t byte) {
if (ec) {
std::cerr << "Error WriteResponse: " << ec.message() << std::endl;
}
StartAccept();
});
}
h.file
---------------
#include <iostream>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <string>
class Server {
public:
Server(boost::asio::io_service& io_service, int port);
private:
void StartAccept();
void ReadRequest();
void ProcessRequest();
void WriteResponse(boost::beast::http::response <boost::beast::http::string_body>& response_);
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ip::tcp::socket socket_;
boost::beast::flat_buffer buffer_;
boost::beast::http::request<boost::beast::http::string_body> request_;
};
The error originates in serializing the response.
You can tell by the assert happening in debug mode:
Client connected sotest:
intrusive/detail/hook_traits.hpp:63: static boost::intrusive::bhtraits_b ase<T, NodePtr, Tag, Type>::pointer boost::intrusive::bhtraits_base<T, NodePtr, Tag, Type>::to_value_ptr(node_ptr) [with T = boost::beast::http::basic_fields<std::allocator<char> >::element; NodePtr = boost::intrusive::list_node<v oid*>*; Tag = boost::intrusive::dft_tag; unsigned int Type = 1; pointer = boost::beast::http::basic_fields<std::all ocator<char> >::element*; node_ptr = boost::intrusive::list_node<void*>*]: Assertion '!!p' failed.
gdb tells us the place:
#0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737345820608) at ./nptl/pthread_kill.c:44
#1 __pthread_kill_internal (signo=6, threadid=140737345820608) at ./nptl/pthread_kill.c:78
#2 __GI___pthread_kill (threadid=140737345820608, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3 0x00007ffff793f476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4 0x00007ffff79257f3 in __GI_abort () at ./stdlib/abort.c:79
#5 0x00007ffff792571b in __assert_fail_base (fmt=0x7ffff7ada130 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x555555598094 "!!p", file=0x55555559cd90 "/home/sehe/cu...
#6 0x00007ffff7936e96 in __GI___assert_fail (assertion=0x555555598094 "!!p", file=0x55555559cd90 "/home/sehe/custom/superboost/boost/intrusive/detail/hook_traits.hpp", line=63...
#7 0x0000555555563c11 in boost::intrusive::bhtraits_base<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node<void*>*, boost::intrusiv...
#8 boost::intrusive::list_iterator<boost::intrusive::bhtraits<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node_traits<void*>, (boo...
#9 boost::intrusive::list_iterator<boost::intrusive::bhtraits<boost::beast::http::basic_fields<std::allocator<char> >::element, boost::intrusive::list_node_traits<void*>, (boo...
#10 boost::beast::http::basic_fields<std::allocator<char> >::writer::field_iterator::operator* (this=0x7fffffffd5c0) at /home/sehe/custom/superboost/boost/beast/http/impl/field...
#11 boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buffer, boost::beast::http::basic_fields<std::allocator<char> >::wri...
#12 0x0000555555590cba in boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buffer, boost::beast::http::basic_fields<std::...
#13 boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buf...
#14 boost::mp11::detail::mp_with_index_impl_<4ul>::call<0ul, boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_...
#15 boost::mp11::mp_with_index<4ul, boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::cons...
#16 boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_buffer, boost::asio::const_buf...
#17 boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buffer, boost::asio::const_b...
#18 boost::asio::detail::buffer_size<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::c...
#19 boost::asio::buffer_size<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boost::beast::buffers_cat_view<boost::asio::const_buf...
#20 0x0000555555593cc3 in boost::beast::detail::buffer_bytes_impl::operator()<boost::beast::buffers_suffix<boost::beast::buffers_cat_view<boost::beast::detail::buffers_ref<boos...
#21 boost::beast::http::serializer<false, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char> >, boost::beast::http::basic_fields<std::allo...
#22 0x000055555556eec7 in boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_msg_op<Server::WriteResponse(boost::b...
#23 0x000055555556f476 in boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_msg_op<S...
#24 boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail::write_m...
#25 boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::det...
#26 0x0000555555585b50 in boost::asio::detail::executor_function::operator() (this=<synthetic pointer>) at /home/sehe/custom/superboost/boost/asio/detail/executor_function.hpp:...
#27 boost::asio::io_context::basic_executor_type<std::allocator<void>, 4ul>::execute<boost::asio::detail::executor_function> (this=0x7fffffffdd70, f=...) at /home/sehe/custom/s...
#28 0x000055555556497a in boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::binder2<boost::beast::http::detail::write...
#29 boost::asio::detail::work_dispatcher<boost::asio::detail::binder2<boost::beast::http::detail::write_some_op<boost::beast::http::detail::write_op<boost::beast::http::detail:...
#30 0x0000555555566511 in boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::binder2<boost::beast::http::detail::write_s...
#31 0x0000555555585a60 in boost::asio::detail::executor_function::operator() (this=<synthetic pointer>) at /home/sehe/custom/superboost/boost/asio/detail/executor_function.hpp:...
#32 boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::allocator<void>, boost::asio::detail::scheduler_operation>::do_complete (owner=0x555555de6000,...
#33 0x00005555555678d7 in boost::asio::detail::scheduler_operation::complete (bytes_transferred=0, ec=..., owner=0x555555de6000, this=0x555555df4000) at /home/sehe/custom/super...
#34 boost::asio::detail::scheduler::do_run_one (ec=..., this_thread=..., lock=..., this=0x555555de6000) at /home/sehe/custom/superboost/boost/asio/detail/impl/scheduler.ipp:493...
#35 boost::asio::detail::scheduler::run (this=0x555555de6000, ec=...) at /home/sehe/custom/superboost/boost/asio/detail/impl/scheduler.ipp:210
#36 0x000055555555fe55 in boost::asio::io_context::run (this=0x7fffffffdf60) at /home/sehe/custom/superboost/boost/asio/impl/io_context.ipp:64
#37 main () at /home/sehe/Projects/stackoverflow/test.cpp:93
The reason is that the response is passed by reference to an async operation. Fix it e.g. by making it a member or using the type-erasing message_generator
utility
Showing the latter:
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
#include <string>
class Server {
public:
Server(boost::asio::io_service& io_service, int port);
private:
using Request = boost::beast::http::request<boost::beast::http::string_body>;
using Response = boost::beast::http::message_generator;
void StartAccept();
void ReadRequest();
Response ProcessRequest();
void WriteResponse(Response);
boost::asio::ip::tcp::acceptor acceptor_;
boost::asio::ip::tcp::socket socket_;
boost::beast::flat_buffer buffer_;
Request request_;
};
// #include "Server.h"
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = boost::asio::ip::tcp;
Server::Server(boost::asio::io_service& io_service, int port)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
, socket_(io_service) {
StartAccept();
}
void Server::StartAccept() {
acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
if (!ec) {
std::cout << "Client connected" << std::endl;
ReadRequest();
} else {
std::cerr << "Client error: " << ec.message() << std::endl;
}
});
}
void Server::ReadRequest() {
buffer_.consume(buffer_.size());
buffer_.prepare(1024);
beast::http::async_read( //
socket_, buffer_, request_, [this](boost::system::error_code ec, size_t /*bytes_transferred*/) {
if (!ec) {
WriteResponse(ProcessRequest());
} else {
std::cerr << "Error ReadRequest: " << ec.message() << std::endl;
}
});
}
Server::Response Server::ProcessRequest() {
if (request_.method() == http::verb::get) {
http::response<http::string_body> response(http::status::ok, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Hello, World";
response.prepare_payload();
return response;
} else {
http::response<http::string_body> response(http::status::bad_request, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Invalid request!";
response.prepare_payload();
return response;
}
}
void Server::WriteResponse(Response res) {
beast::async_write(socket_, std::move(res), [this](boost::system::error_code ec, size_t /*byte*/) {
if (ec) {
std::cerr << "Error WriteResponse: " << ec.message() << std::endl;
}
StartAccept();
});
}
int main() {
boost::asio::io_service ios;
Server s(ios, 8989);
ios.run();
}
The output of test:
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp
./a.out&
sleep 1; curl "http://127.0.0.1:8989/test"
being
Hello, World
I suggest looking at the Beast async http server examples for more good practices!
Also showing concurrent connections separating Server
from Session
and in the process reducing the includes in the header file:
File server.h
// server.h
#pragma once
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
class Server {
public:
Server(boost::asio::any_io_executor ex, uint16_t port);
private:
void StartAccept();
boost::asio::ip::tcp::acceptor acceptor_;
struct Session;
};
File server.cpp
#include "server.h"
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <iostream>
namespace beast = boost::beast;
namespace http = beast::http;
using tcp = boost::asio::ip::tcp;
using error_code = beast::error_code;
struct Server::Session : std::enable_shared_from_this<Session> {
Session(tcp::socket s) : socket_(std::move(s)) {}
void Start() { ReadRequest(); }
private:
using Request = http::request<http::string_body>;
using Response = http::message_generator;
void ReadRequest() {
beast::http::async_read( //
socket_, buffer_, request_,
[this, self = shared_from_this()](error_code ec, size_t /*bytes_transferred*/) {
if (!ec) {
WriteResponse(ProcessRequest());
} else {
std::cerr << "Error ReadRequest: " << ec.message() << std::endl;
}
});
}
Response ProcessRequest() {
if (request_.method() == http::verb::get) {
http::response<http::string_body> response(http::status::ok, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Hello, World";
response.prepare_payload();
return response;
} else {
http::response<http::string_body> response(http::status::bad_request, request_.version());
response.set(http::field::server, "Boost Beast Server");
response.set(http::field::content_type, "text/plain");
response.keep_alive(request_.keep_alive());
response.body() = "Invalid request!";
response.prepare_payload();
return response;
}
}
void WriteResponse(Response res) {
beast::async_write(socket_, std::move(res),
[self = shared_from_this()](error_code ec, size_t /*byte*/) {
if (ec) {
std::cerr << "Error WriteResponse: " << ec.message() << std::endl;
}
});
}
tcp::socket socket_;
beast::flat_buffer buffer_;
Request request_;
};
Server::Server(boost::asio::any_io_executor ex, uint16_t port)
: acceptor_(ex, tcp::endpoint(tcp::v4(), port)) {
StartAccept();
}
void Server::StartAccept() {
acceptor_.async_accept([this](error_code ec, tcp::socket s) {
if (!ec) {
std::cout << "Client accepted: " << s.remote_endpoint() << std::endl;
std::make_shared<Session>(std::move(s))->Start();
} else {
std::cerr << "Accept error: " << ec.message() << std::endl;
}
StartAccept();
});
}
int main() {
boost::asio::io_context ioc;
Server s(ioc.get_executor(), 7878);
ioc.run();
}