From c8c2a6a3a12a0870f07e1ef216fe77359eaa0942 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 12 Nov 2015 16:56:06 -0500 Subject: [PATCH 1/3] add a workaround to mingw / libstdc++ issue 68307 This is a workaround to some standard non-conformance defect in libstdc++ headers for mingw. Although the C++11 standard requires that `std::errc::operation_canceled` is an enumerator value of `std::errc` in ``, and asio library uses std::errc when compiled as standalone, mingw apparently doesn't use all the std::errc signals, and doesn't define any of the enumerators that it doesn't use. Presumably mingw instead packs these signals into some different error codes or something, it's not entirely clear. Regardless, even if there are some low-level issues in mingw implementations of sockets, websocketpp is a bit higher level library and one would think that we should be able to try to run websocketpp over any given sockets implementation and at least get it to compile. This patch is a polyfill so that if for whatever reason the host system fails to define this error code symbol, websocketpp will just return false whenever testing if an error code matches it, as a form of special support for mingw. (Or any other toolchain that happens to have a similar bug -- there is no ifdef going on here.) In preliminary tests, websocketpp examples seem to work fine with this patch when compiled with the mingw-w64 toolchain from ubuntu trusty repo, with Asio standalone and C++11 standard, when running in wine on my machine. --- websocketpp/transport/asio/endpoint.hpp | 53 ++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index 4e278d41c..c442dfd4d 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -44,6 +44,56 @@ 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 uses an acceptable substitute + * if the needed value is missing. ( ECANCELED from ) + * + * 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 + * since that's C++11 only + */ + template + struct enable_if {}; + + template + struct enable_if { typedef T type; }; + + /*** + * Metafunction to test "operation_canceled" value + */ + template + struct op_canceled_helper { + template + static inline bool is_op_canceled(const U & u) { return false; } + }; + + template + struct op_canceled_helper> { + template + 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. + */ + static inline bool is_op_canceled(const lib::asio::error_code & asio_ec) { + return op_canceled_helper::is_op_canceled(asio_ec); + } +} // namespace _workaround + /// Asio based endpoint transport component /** * transport::asio::endpoint implements an endpoint transport component using @@ -761,7 +811,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); From 2c715555f5740c01a5071281ea6d42c317ca25ea Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 12 Nov 2015 19:10:47 -0500 Subject: [PATCH 2/3] fix compilation when not using asio_standalone, fix code comments --- websocketpp/transport/asio/endpoint.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index c442dfd4d..8f83b4052 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -51,8 +51,11 @@ namespace asio { * 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 uses an acceptable substitute - * if the needed value is missing. ( ECANCELED from ) + * 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 */ @@ -88,10 +91,20 @@ namespace _workaround_gcc_libstdcpp_issue_68307_missing_values { * * 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::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 From a47c37e1e209bfbd7f4f8fbf77652b929989c939 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 12 Nov 2015 19:23:23 -0500 Subject: [PATCH 3/3] fixup C++98 compilation (>> vs. > >) --- websocketpp/transport/asio/endpoint.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp index 8f83b4052..e84bd1c7d 100644 --- a/websocketpp/transport/asio/endpoint.hpp +++ b/websocketpp/transport/asio/endpoint.hpp @@ -80,7 +80,7 @@ namespace _workaround_gcc_libstdcpp_issue_68307_missing_values { }; template - struct op_canceled_helper> { + struct op_canceled_helper > { template static inline bool is_op_canceled(const U & u) { return u == T::operation_canceled; } };