Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a workaround to mingw / libstdc++ issue 68307 #479

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion websocketpp/transport/asio/endpoint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,69 @@ namespace websocketpp {
namespace transport {
namespace asio {

/***
* In current versions of libstdc++, the error_constants.h code associated to mingw32
* does not define certain standard enum values for `std::errc`. (In C++11 standard,
* sections 19.5.2, 19.5.3.) Asio uses these for lib::asio::errc when it is compiled
* as a stand-alone library, so because of the libstdc++ defect, code below referring
* to lib::asio::errc::operation_canceled fails to compile on mingw.
*
* This workaround detects the defect using SFINAE and returns 'false' for the check
* if operation_canceled is not defined, instead of failing to compile.
*
* If upstream patches this later by defining those enum values, then the workaround
* will stop having any effect.
*
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68307
*/
namespace _workaround_gcc_libstdcpp_issue_68307_missing_values {
/***
* Same as std::enable_if, but don't want to introduce dependency on <type_traits>
* since that's C++11 only
*/
template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

/***
* Metafunction to test "operation_canceled" value
*/
template <typename T, typename ENABLE=void>
struct op_canceled_helper {
template <typename U>
static inline bool is_op_canceled(const U & u) { return false; }
};

template <typename T>
struct op_canceled_helper<T, enable_if<T::operation_canceled == T::operation_canceled, void> > {
template<typename U>
static inline bool is_op_canceled(const U & u) { return u == T::operation_canceled; }
};

/***
* This function is intended to be a drop-in replacement for
* (asio_ec == lib::asio::errc::operation_canceled)
*
* except that if lib::asio::errc::operation_canceled does not exist, it returns false,
* instead of failing to compile.
*
* When using boost and not asio standalone, then lib::asio::errc is a namespace, not an enum class.
* So the template code will fail to compile and we need to block it from being instantiated, with this
* ifdef. When using boost the standard library symbol definitions aren't relevant afaik.
*/
#ifdef ASIO_STANDALONE
static inline bool is_op_canceled(const lib::asio::error_code & asio_ec) {
return op_canceled_helper<lib::asio::errc, void>::is_op_canceled(asio_ec);
}
#else
static inline bool is_op_canceled(const lib::asio::error_code & asio_ec) {
return asio_ec == lib::asio::errc::operation_canceled;
}
#endif
} // namespace _workaround

/// Asio based endpoint transport component
/**
* transport::asio::endpoint implements an endpoint transport component using
Expand Down Expand Up @@ -761,7 +824,8 @@ class endpoint : public config::socket_type {
m_alog->write(log::alevel::devel, "asio::handle_accept");

if (asio_ec) {
if (asio_ec == lib::asio::errc::operation_canceled) {
// if (asio_ec == lib::asio::errc::operation_canceled) {
if (_workaround_gcc_libstdcpp_issue_68307_missing_values::is_op_canceled(asio_ec)) {
ret_ec = make_error_code(websocketpp::error::operation_canceled);
} else {
log_err(log::elevel::info,"asio handle_accept",asio_ec);
Expand Down