Skip to content

Commit

Permalink
Merge pull request #163 from jgaa/boost-1.87-fixes
Browse files Browse the repository at this point in the history
Boost 1.87 fixes 
Closes #161 #162
  • Loading branch information
jgaa authored Jan 19, 2025
2 parents 5470ee3 + ba9ddd4 commit 855349b
Show file tree
Hide file tree
Showing 32 changed files with 394 additions and 137 deletions.
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if (DEFINED ENV{RESTC_CPP_VERSION})
endif()

if (NOT DEFINED RESTC_CPP_VERSION)
set(RESTC_CPP_VERSION 0.101.1)
set(RESTC_CPP_VERSION 0.102.0)
endif()

if(NOT DEFINED RESTC_BOOST_VERSION)
Expand Down Expand Up @@ -38,6 +38,8 @@ option(RESTC_CPP_AUTORUN_UNIT_TESTS "Run Unit Tests automatically after build" O

option(RESTC_CPP_WITH_FUNCTIONALT_TESTS "Enable Functional Testing" ON)

option(RESTC_USE_LEGACY_BOOST_FIND "Use the old Boost find module" OFF)

set(GTEST_TAG "main" CACHE STRING "Gtest branch to use. Required on older Linux versions because newer gtest requure newer cmake!")
set(LOGFAULT_TAG "master" CACHE STRING "Logfault branch to use. Required on older Linux versions because newer gtest requure newer cmake!")

Expand Down Expand Up @@ -218,6 +220,7 @@ set(ACTUAL_SOURCES
src/RequestBodyStringImpl.cpp
src/RequestBodyFileImpl.cpp
src/url_encode.cpp
src/boost_compitability.cpp
${LOGGING_SRC}
)

Expand Down Expand Up @@ -248,7 +251,10 @@ endif()

if (NOT EMBEDDED_RESTC_CPP)

if(CMAKE_VERSION VERSION_GREATER "3.28")
if (RESTC_USE_LEGACY_BOOST_FIND)
unset(restc_cpp_boost_find_config)
message("Using legacy Boost find config")
elseif(CMAKE_VERSION VERSION_GREATER "3.28")
set(restc_cpp_boost_find_config CONFIG)
message("Using new Boost find config")
endif()
Expand Down
2 changes: 1 addition & 1 deletion ci/jenkins/Jenkinsfile.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pipeline {
agent { label 'main' }

environment {
RESTC_CPP_VERSION = "0.101.0"
RESTC_CPP_VERSION = "0.102.0"

// It is not possible to get the current IP number when running in the sandbox, and
// Jenkinsfiles always runs in the sandbox.
Expand Down
3 changes: 3 additions & 0 deletions examples/logip/logip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#include <boost/log/expressions.hpp>
#endif

#include <boost/exception/all.hpp>
#include <boost/exception/diagnostic_information.hpp>

#include "restc-cpp/restc-cpp.h"
#include "restc-cpp/RequestBuilder.h"
#include "restc-cpp/SerializeJson.h"
Expand Down
2 changes: 1 addition & 1 deletion include/restc-cpp/DataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class DataReader {
virtual ~DataReader() = default;

virtual bool IsEof() const = 0;
virtual boost::asio::const_buffers_1 ReadSome() = 0;
virtual boost_const_buffer ReadSome() = 0;
virtual void Finish() = 0; // Make sure there are no pending data for the current request

static ptr_t CreateIoReader(const Connection::ptr_t& conn,
Expand Down
4 changes: 2 additions & 2 deletions include/restc-cpp/DataReaderStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class DataReaderStream : public DataReader {
}

/*! Read whatever we have buffered or can get downstream */
boost::asio::const_buffers_1 ReadSome() override;
boost_const_buffer ReadSome() override;

/*! Read up to maxBytes from whatever we have buffered or can get downstream.*/
boost::asio::const_buffers_1 GetData(size_t maxBytes);
boost_const_buffer GetData(size_t maxBytes);

/*! Get one char
*
Expand Down
4 changes: 2 additions & 2 deletions include/restc-cpp/DataWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ class DataWriter {
virtual ~DataWriter() = default;

/*! Write some data */
virtual void Write(boost::asio::const_buffers_1 buffers) = 0;
virtual void Write(boost_const_buffer buffers) = 0;

/*! Write without altering the data (headers) */
virtual void WriteDirect(boost::asio::const_buffers_1 buffers) = 0;
virtual void WriteDirect(boost_const_buffer buffers) = 0;

/*! Write some data */
virtual void Write(const write_buffers_t& buffers) = 0;
Expand Down
3 changes: 2 additions & 1 deletion include/restc-cpp/RapidJsonReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <assert.h>

#include "restc-cpp/boost_compatibility.h"
#include "rapidjson/reader.h"
#include "restc-cpp/restc-cpp.h"

Expand Down Expand Up @@ -96,7 +97,7 @@ class RapidJsonReader {
const auto len = boost::asio::buffer_size(buffer);

if (len) {
ch_ = boost::asio::buffer_cast<const char*>(buffer);
ch_ = boost_buffer_cast(buffer);
end_ = ch_ + len;
} else {
ch_ = end_ = nullptr;
Expand Down
9 changes: 5 additions & 4 deletions include/restc-cpp/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <boost/system/error_code.hpp>

#include "restc-cpp/boost_compatibility.h"
#include "restc-cpp/typename.h"
#include "restc-cpp/logging.h"

Expand All @@ -34,21 +35,21 @@ class Socket

virtual const boost::asio::ip::tcp::socket& GetSocket() const = 0;

virtual std::size_t AsyncReadSome(boost::asio::mutable_buffers_1 buffers,
virtual std::size_t AsyncReadSome(boost_mutable_buffer buffers,
boost::asio::yield_context& yield) = 0;

virtual std::size_t AsyncRead(boost::asio::mutable_buffers_1 buffers,
virtual std::size_t AsyncRead(boost_mutable_buffer buffers,
boost::asio::yield_context& yield) = 0;

virtual void AsyncWrite(const boost::asio::const_buffers_1& buffers,
virtual void AsyncWrite(const boost_const_buffer& buffers,
boost::asio::yield_context& yield) = 0;

virtual void AsyncWrite(const write_buffers_t& buffers,
boost::asio::yield_context& yield) = 0;

template <typename T>
void AsyncWriteT(const T& buffer, boost::asio::yield_context& yield) {
boost::asio::const_buffers_1 b{buffer.data(), buffer.size()};
boost_const_buffer b{buffer.data(), buffer.size()};
AsyncWrite(b, yield);
}

Expand Down
217 changes: 217 additions & 0 deletions include/restc-cpp/boost_compatibility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#pragma once

#include <boost/asio.hpp>
#include <boost/version.hpp>
#include <boost/asio/ip/address_v4.hpp>

/**
* @file
* @brief Compatibility layer for handling breaking changes in Boost.Asio across versions.
*
* Boost frequently introduces breaking changes in its Asio library, with a backward
* compatibility window of about 5 years. This header helps maintain compatibility with
* multiple Boost versions, making it easier to support older versions without requiring
* extensive refactoring.
*/

#if BOOST_VERSION >= 107000
#include <boost/coroutine/exceptions.hpp>
/// Macro for catching exceptions in Boost Coroutine, ensuring required handling for `forced_unwind`.
#define RESTC_CPP_IN_COROUTINE_CATCH_ALL \
catch (boost::coroutines::detail::forced_unwind const&) { \
throw; /* required for Boost Coroutine! */ \
} catch (...)
#elif BOOST_VERSION >= 106000
#include <boost/coroutine2/detail/forced_unwind.hpp>
/// Macro for catching exceptions in Boost Coroutine, ensuring required handling for `forced_unwind`.
#define RESTC_CPP_IN_COROUTINE_CATCH_ALL \
catch (boost::coroutines::detail::forced_unwind const&) { \
throw; /* required for Boost Coroutine! */ \
} catch (...)
#else
static_assert(false, "Unsupported boost version");
catch (...)
#endif

#if BOOST_VERSION >= 108100
/// Macro for handling function signature changes in Boost 1.86 and later.
#define RESTC_CPP_SPAWN_TRAILER \
, boost::asio::detached
#else
#define RESTC_CPP_SPAWN_TRAILER
#endif


namespace restc_cpp {

#if BOOST_VERSION >= 107000
/// Type alias for constant buffer in Boost 1.70 and later.
using boost_const_buffer = boost::asio::const_buffer;
/// Type alias for mutable buffer in Boost 1.70 and later.
using boost_mutable_buffer = boost::asio::mutable_buffer;
#else
/// Type alias for constant buffer in Boost versions earlier than 1.70.
using boost_const_buffer = boost::asio::const_buffers_1;
/// Type alias for mutable buffer in Boost versions earlier than 1.70.
using boost_mutable_buffer = boost::asio::mutable_buffers_1;
#endif

#if BOOST_VERSION >= 106600
/// Type alias for IO service in Boost 1.66 and later.
using boost_io_service = boost::asio::io_context;
/// Type alias for work guard in Boost 1.66 and later.
using boost_work = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
#else
/// Type alias for IO service in Boost versions earlier than 1.66.
using boost_io_service = boost::asio::io_service;
/// Type alias for work guard in Boost versions earlier than 1.66.
using boost_work = boost::asio::io_service::work;
#endif

/**
* @brief Extracts a const char pointer from a Boost buffer.
*
* @tparam Buffer The type of the buffer.
* @param buffer The buffer to extract the pointer from.
* @return A const char pointer to the data in the buffer.
*/
template <typename Buffer>
const char* boost_buffer_cast(const Buffer& buffer) {
#if BOOST_VERSION >= 107000
return static_cast<const char*>(buffer.data());
#else
return boost::asio::buffer_cast<const char*>(buffer);
#endif
}

/**
* @brief Retrieves the size of a Boost buffer.
*
* @tparam Buffer The type of the buffer.
* @param buffer The buffer to measure.
* @return The size of the buffer in bytes.
*/
template <typename Buffer>
std::size_t boost_buffer_size(const Buffer& buffer) {
#if BOOST_VERSION >= 107000
return buffer.size();
#else
return boost::asio::buffer_size(buffer);
#endif
}

/**
* @brief Dispatches a handler to the IO service.
*
* @tparam IOService The type of the IO service.
* @tparam Handler The type of the handler.
* @param io_service The IO service to use.
* @param handler The handler to dispatch.
*/
template <typename IOService, typename Handler>
void boost_dispatch(IOService *io_service, Handler&& handler) {
#if BOOST_VERSION >= 106600
io_service->get_executor().dispatch(
std::forward<Handler>(handler),
std::allocator<void>() // Default allocator
);
#else
io_service->dispatch(std::forward<Handler>(handler));
#endif
}

/**
* @brief Wrapper for Boost resolver results for compatibility with older Boost versions.
*
* @tparam Iterator The type of the iterator used for results.
*/
template <typename Iterator>
class ResolverResultsWrapper {
public:
/**
* @brief Constructor.
* @param begin The beginning iterator of the results.
* @param end The end iterator of the results.
*/
explicit ResolverResultsWrapper(const Iterator& begin, const Iterator& end)
: begin_(begin), end_(end) {}

/**
* @brief Returns the beginning iterator of the results.
* @return The beginning iterator.
*/
Iterator begin() const { return begin_; }

/**
* @brief Returns the end iterator of the results.
* @return The end iterator.
*/
Iterator end() const { return end_; }

private:
Iterator begin_;
Iterator end_;
};

template <typename Resolver, typename YieldContext>
#if BOOST_VERSION >= 106600
/// Type alias for resolver results in Boost 1.66 and later.
using ResolverResults = boost::asio::ip::tcp::resolver::results_type;
#else
/// Type alias for resolver results in Boost versions earlier than 1.66.
using ResolverResults = ResolverResultsWrapper<boost::asio::ip::tcp::resolver::iterator>;
#endif

/**
* @brief Resolves a host and service to endpoints, with compatibility for multiple Boost versions.
*
* @tparam Resolver The type of the resolver.
* @tparam YieldContext The type of the yield context.
* @param resolver The resolver to use for the operation.
* @param host The host to resolve.
* @param service The service to resolve.
* @param yield The yield context for asynchronous operations.
* @return The resolver results, wrapped if necessary for older Boost versions.
*/
template <typename Resolver, typename YieldContext>
ResolverResults<Resolver, YieldContext> boost_resolve(
Resolver& resolver,
const std::string& host,
const std::string& service,
YieldContext yield)
{
#if BOOST_VERSION >= 107000
return resolver.async_resolve(host, service, yield);
#elif BOOST_VERSION >= 106600
return resolver.async_resolve(host, service, yield);
#else
boost::asio::ip::tcp::resolver::query query(host, service);
auto it = resolver.async_resolve(query, yield);
auto end = boost::asio::ip::tcp::resolver::iterator();
return ResolverResultsWrapper(it, end);
#endif
}

/**
* @brief Creates a Boost endpoint from an IP address and port.
* @param ip_address The IP address as a string.
* @param port The port number.
* @return A Boost TCP endpoint.
*/
boost::asio::ip::tcp::endpoint boost_create_endpoint(const std::string& ip_address, unsigned short port);

/**
* @brief Converts an IPv4 address from string format to a 32-bit unsigned integer.
* @param ip_address The IPv4 address as a string.
* @return The IPv4 address as a 32-bit unsigned integer.
*/
uint32_t boost_convert_ipv4_to_uint(const std::string& ip_address);

/**
* @brief Creates a work guard for the given IO service.
* @param ioservice The IO service to manage.
* @return A unique pointer to the work guard.
*/
std::unique_ptr<boost_work> boost_make_work(boost_io_service& ioservice);

} // namespace restc_cpp
10 changes: 9 additions & 1 deletion include/restc-cpp/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,17 @@ class ToBuffer
{
}

operator boost::asio::const_buffers_1 () const {
#if BOOST_VERSION >= 107000
// For Boost 1.70 and newer
operator boost::asio::const_buffer() const {
return {buf_.data(), buf_.size()};
}
#else
// For Boost versions older than 1.70
operator boost::asio::const_buffers_1() const {
return {buf_.c_str(), buf_.size()};
}
#endif

operator const boost::string_ref() const {
return buf_;
Expand Down
Loading

0 comments on commit 855349b

Please sign in to comment.