-
Weird Conversion Error
I am trying to compile the example code located here libs/beast/example/http/server/small/http_server_small.cpp - 1.70.0 but I am getting an error right out of the box that I am unsure how to fix.
The error occurs on this line below
Code:
// The timer for putting a deadline on connection processing.
net::basic_waitable_timer<std::chrono::steady_clock> deadline_{
socket_.get_executor(), std::chrono::seconds(60)}; <-- error occurs here
// Error
Code:
error: could not convert ‘{((http_connection*)this)->http_connection::socket_.boost::asio::basic_stream_socket<boost::asio::ip::tcp>::<anonymous>.boost::asio::basic_socket<boost::asio::ip::tcp>::get_executor(), std::chrono::duration<long int>(60)}’ from ‘<brace-enclosed initializer list>’ to ‘boost::asio::basic_waitable_timer<std::chrono::_V2::steady_clock>’
Full Error
Code:
-------------- Build: Debug in TestBoostAsioBeast (compiler: GNU GCC Compiler)---------------
g++ -Wall -fexceptions -g -Iinclude -c "/home/code/TestBoostAsioBeast/main.cpp" -o obj/Debug/main.o
/home/code/TestBoostAsioBeast/main.cpp:94:57: error: could not convert ‘{((http_connection*)this)->http_connection::socket_.boost::asio::basic_stream_socket<boost::asio::ip::tcp>::<anonymous>.boost::asio::basic_socket<boost::asio::ip::tcp>::get_executor(), std::chrono::duration<long int>(60)}’ from ‘<brace-enclosed initializer list>’ to ‘boost::asio::basic_waitable_timer<std::chrono::_V2::steady_clock>’
socket_.get_executor(), std::chrono::seconds(60)};
^
/home/code/TestBoostAsioBeast/main.cpp: In function ‘time_t ConvertStringToTimeTWithTimezone(std::__cxx11::string)’:
/home/code/TestBoostAsioBeast/main.cpp:820:12: warning: unused variable ‘tCurrentTime2’ [-Wunused-variable]
time_t tCurrentTime2 = mktime(&tmTime);
^~~~~~~~~~~~~
/home/code/TestBoostAsioBeast/main.cpp: In function ‘int main()’:
/home/code/TestBoostAsioBeast/main.cpp:1053:18: error: ‘do_session’ was not declared in this scope
&do_session,
^~~~~~~~~~
/home/code/TestBoostAsioBeast/main.cpp:1055:26: error: no matching function for call to ‘std::thread::thread(<brace-enclosed initializer list>)’
doc_root)}.detach();
^
In file included from /usr/include/c++/7/future:39:0,
from /usr/local/include/boost/asio/detail/future.hpp:20,
from /usr/local/include/boost/asio/packaged_task.hpp:19,
from /usr/local/include/boost/asio.hpp:101,
from /home/code/TestBoostAsioBeast/main.cpp:17:
/usr/include/c++/7/thread:118:7: note: candidate: template<class _Callable, class ... _Args> std::thread::thread(_Callable&&, _Args&& ...)
thread(_Callable&& __f, _Args&&... __args)
^~~~~~
/usr/include/c++/7/thread:118:7: note: template argument deduction/substitution failed:
/usr/include/c++/7/thread:113:5: note: candidate: std::thread::thread(std::thread&&)
thread(thread&& __t) noexcept
^~~~~~
/usr/include/c++/7/thread:113:5: note: conversion of argument 1 would be ill-formed:
/usr/include/c++/7/thread:106:5: note: candidate: std::thread::thread()
thread() noexcept = default;
^~~~~~
/usr/include/c++/7/thread:106:5: note: candidate expects 0 arguments, 1 provided
Process terminated with status 1 (0 minute(s), 3 second(s))
3 error(s), 1 warning(s) (0 minute(s), 3 second(s))
Full Code
Code:
//
// Copyright (c) 2017 Christopher M. Kohlhoff (chris at kohlhoff 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: GitHub - boostorg/beast: HTTP and WebSocket built on Boost.Asio in C++11
//
//------------------------------------------------------------------------------
//
// Example: HTTP server, small
//
//------------------------------------------------------------------------------
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio.hpp>
#include <chrono>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <memory>
#include <string>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace my_program_state
{
std::size_t
request_count()
{
static std::size_t count = 0;
return ++count;
}
std::time_t
now()
{
return std::time(0);
}
}
class http_connection : public std::enable_shared_from_this<http_connection>
{
public:
http_connection(tcp::socket socket)
: socket_(std::move(socket))
{
}
// Initiate the asynchronous operations associated with the connection.
void
start()
{
read_request();
check_deadline();
}
private:
// The socket for the currently connected client.
tcp::socket socket_;
// The buffer for performing reads.
beast::flat_buffer buffer_{8192};
// The request message.
http::request<http::dynamic_body> request_;
// The response message.
http::response<http::dynamic_body> response_;
// The timer for putting a deadline on connection processing.
net::basic_waitable_timer<std::chrono::steady_clock> deadline_{
socket_.get_executor(), std::chrono::seconds(60)};
// Asynchronously receive a complete request message.
void
read_request()
{
auto self = shared_from_this();
http::async_read(
socket_,
buffer_,
request_,
[self](beast::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if(!ec)
self->process_request();
});
}
// Determine what needs to be done with the request message.
void
process_request()
{
response_.version(request_.version());
response_.keep_alive(false);
switch(request_.method())
{
case http::verb::get:
response_.result(http::status::ok);
response_.set(http::field::server, "Beast");
create_response();
break;
default:
// We return responses indicating an error if
// we do not recognize the request method.
response_.result(http::status::bad_request);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body())
<< "Invalid request-method '"
<< std::string(request_.method_string())
<< "'";
break;
}
write_response();
}
// Construct a response message based on the program state.
void
create_response()
{
if(request_.target() == "/count")
{
response_.set(http::field::content_type, "text/html");
beast::ostream(response_.body())
<< "<html>\n"
<< "<head><title>Request count</title></head>\n"
<< "<body>\n"
<< "<h1>Request count</h1>\n"
<< "<p>There have been "
<< my_program_state::request_count()
<< " requests so far.</p>\n"
<< "</body>\n"
<< "</html>\n";
}
else if(request_.target() == "/time")
{
response_.set(http::field::content_type, "text/html");
beast::ostream(response_.body())
<< "<html>\n"
<< "<head><title>Current time</title></head>\n"
<< "<body>\n"
<< "<h1>Current time</h1>\n"
<< "<p>The current time is "
<< my_program_state::now()
<< " seconds since the epoch.</p>\n"
<< "</body>\n"
<< "</html>\n";
}
else
{
response_.result(http::status::not_found);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body()) << "File not found\r\n";
}
}
// Asynchronously transmit the response message.
void
write_response()
{
auto self = shared_from_this();
response_.set(http::field::content_length, response_.body().size());
http::async_write(
socket_,
response_,
[self](beast::error_code ec, std::size_t)
{
self->socket_.shutdown(tcp::socket::shutdown_send, ec);
self->deadline_.cancel();
});
}
// Check whether we have spent enough time on this connection.
void
check_deadline()
{
auto self = shared_from_this();
deadline_.async_wait(
[self](beast::error_code ec)
{
if(!ec)
{
// Close socket to cancel any outstanding operation.
self->socket_.close(ec);
}
});
}
};
// "Loop" forever accepting new connections.
void
http_server(tcp::acceptor& acceptor, tcp::socket& socket)
{
acceptor.async_accept(socket,
[&](beast::error_code ec)
{
if(!ec)
std::make_shared<http_connection>(std::move(socket))->start();
http_server(acceptor, socket);
});
}
int
main(int argc, char* argv[])
{
try
{
// Check command line arguments.
if(argc != 3)
{
std::cerr << "Usage: " << argv[0] << " <address> <port>\n";
std::cerr << " For IPv4, try:\n";
std::cerr << " receiver 0.0.0.0 80\n";
std::cerr << " For IPv6, try:\n";
std::cerr << " receiver 0::0 80\n";
return EXIT_FAILURE;
}
auto const address = net::ip::make_address(argv[1]);
unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
net::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}};
tcp::socket socket{ioc};
http_server(acceptor, socket);
ioc.run();
}
catch(std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
}
Thanks for any help you can provide!
-
Best I can tell from a quick look is that asio underwent changes and there are a few notes on their github indicating they changed asio.
There were lots of discussions about how things are constructed/initialized, as this line does, which broke older code examples.
I tried with 1.69 & 1.68, but this example issues the same or similar error.
It would appear the example may be outdated (even if it came with 1.7). The github discussion (boost) indicates that for a while the builds were broken in 1.7 (possibly older ones too) and they "fixed" it, but the fix does not apply to older example builds, but of new ways to instantiate/open objects.
In other words, they changed the API a bit (it seems).
This may work with an older version of boost, but more recent that 1.61 (the oldest I have, which does not have beast). So, you could try the first version were beast was added and work forward with a few versions if you prefer, otherwise you'll probably have to find a more current example (or fix this one - by starting it over through a tutorial/study of asio).
Asio is worth the trouble, and it is (or has) been considered for submission to the C++ standard library around C++20, but that may be the problem - they may be dressing it up and dealing with "issues" related to that submission (I'm guessing).