Conflict with cyberrt's asio dependency when using ASIO_STANDALONE
FRAOTIAC opened this issue · comments
Description
I'm using foxglove-websocket in my project and found that it depends on a standalone ASIO library, so I had to set add_definitions(-DASIO_STANDALONE) in CMake. However, this seems to cause a conflict with the asio dependency in my project's cyberrt, resulting in a "Segmentation fault (core dumped)" error when I run my project.
- Version:
CMake version: 3.21
foxglove-websocket version: 1.0.0
ASIO version: 1.10.8 - Platform:
Ubuntu 18.04
Steps To Reproduce
I have created a minimal project to reproduce the issue and packaged the environment into a Docker container for easier reproduction. The Docker image is hosted on Docker Hub and can be pulled and run directly.
docker pull lucycat/foxglove_websocketpp_cyber_asio_conflict:0.1
docker run -it --ipc=host --network host lucycat/foxglove_websocketpp_cyber_asio_conflict:0.1 /bin/bash
// in docker
cd ~/ReproduceAsioConflict
mkdir -p build && cd build && rm -rf *
source /usr/local/setup.bash
cmake .. && make -j
./writer &
./asio_conflict_test
Expected Behavior
You'll find that it either hangs indefinitely or exits abruptly with a "Segmentation fault" error message. I hope you can help me resolve this issue, thank you!
Additionally, the source code used to reproduce this issue is also available on GitHub at this repository: https://github.com/FRAOTIAC/ReproduceAsioConflict. You can examine the code or clone the repository for further investigation.
However, this seems to cause a conflict with the asio dependency in my project's cyberrt, resulting in a "Segmentation fault (core dumped)" error when I run my project.
Are you sure that the segfault is caused by asio
? Best way to find out is to load the core file into gdb
or to run the entire program with gdb
.
There was similar issue in Apollo repo: ApolloAuto/apollo#14963 .
My solution was to patch foxglove websocket and swap to boost version of asio in source code. Something like this (FG websocket version is also 1.0):
diff --git a/cpp/foxglove-websocket/include/foxglove/websocket/websocket_logging.hpp b/cpp/foxglove-websocket/include/foxglove/websocket/websocket_logging.hpp
index 22e463b..2e6b8ef 100644
--- a/cpp/foxglove-websocket/include/foxglove/websocket/websocket_logging.hpp
+++ b/cpp/foxglove-websocket/include/foxglove/websocket/websocket_logging.hpp
@@ -1,6 +1,7 @@
#pragma once
-#include <asio/ip/address.hpp>
+#include <boost/asio/ip/address.hpp>
+// #include <asio/ip/address.hpp>
#include <websocketpp/logger/levels.hpp>
#include <functional>
@@ -11,7 +12,7 @@ namespace foxglove {
using LogCallback = std::function<void(WebSocketLogLevel, char const*)>;
-inline std::string IPAddressToString(const asio::ip::address& addr) {
+inline std::string IPAddressToString(const boost::asio::ip::address& addr) {
if (addr.is_v6()) {
return "[" + addr.to_string() + "]";
}
diff --git a/cpp/foxglove-websocket/include/foxglove/websocket/websocket_server.hpp b/cpp/foxglove-websocket/include/foxglove/websocket/websocket_server.hpp
index 66660ca..e109f91 100644
--- a/cpp/foxglove-websocket/include/foxglove/websocket/websocket_server.hpp
+++ b/cpp/foxglove-websocket/include/foxglove/websocket/websocket_server.hpp
@@ -215,6 +215,7 @@ inline Server<ServerConfiguration>::Server(std::string name, LogCallback logger,
_server.get_elog().set_callback(_logger);
std::error_code ec;
+
_server.init_asio(ec);
if (ec) {
throw std::runtime_error("Failed to initialize websocket server: " + ec.message());
@@ -239,7 +240,7 @@ inline Server<ServerConfiguration>::~Server() {}
template <typename ServerConfiguration>
inline void Server<ServerConfiguration>::socketInit(ConnHandle hdl) {
- std::error_code ec;
+ boost::system::error_code ec;
_server.get_con_from_hdl(hdl)->get_raw_socket().set_option(Tcp::no_delay(true), ec);
if (ec) {
_server.get_elog().write(RECOVERABLE, "Failed to set TCP_NODELAY: " + ec.message());
@@ -465,9 +466,9 @@ inline void Server<ServerConfiguration>::start(const std::string& host, uint16_t
throw std::runtime_error("Server already started");
}
- std::error_code ec;
+ websocketpp::lib::error_code ec;
- _server.listen(host, std::to_string(port), ec);
+ _server.listen(port, ec);
if (ec) {
throw std::runtime_error("Failed to listen on port " + std::to_string(port) + ": " +
ec.message());
@@ -488,9 +489,10 @@ inline void Server<ServerConfiguration>::start(const std::string& host, uint16_t
throw std::runtime_error("WebSocket server failed to listen on port " + std::to_string(port));
}
- auto endpoint = _server.get_local_endpoint(ec);
- if (ec) {
- throw std::runtime_error("Failed to resolve the local endpoint: " + ec.message());
+ boost::system::error_code ec2;
+ auto endpoint = _server.get_local_endpoint(ec2);
+ if (ec2) {
+ throw std::runtime_error("Failed to resolve the local endpoint: " + ec2.message());
}
const std::string protocol = _options.useTls ? "wss" : "ws";
@@ -1138,7 +1140,7 @@ inline void Server<ServerConfiguration>::sendServiceResponse(ConnHandle clientHa
template <typename ServerConfiguration>
inline uint16_t Server<ServerConfiguration>::getPort() {
- std::error_code ec;
+ boost::system::error_code ec;
auto endpoint = _server.get_local_endpoint(ec);
if (ec) {
throw std::runtime_error("Server not listening on any port. Has it been started before?");
@achim-k Thanks for your suggestion, I did try using gdb, and it did point to asio and raw lock in the code, but was unable to pinpoint the exact problem. However, I've noticed that my project runs perfectly fine without integrating foxglove-websocket, and the foxglove-websocket also fine without cyberrt. Notice that cyberrt have a pre-built fastrtps that include a thirdparty asio, that seems to imply that the issue might be rooted in the ASIO version conflict.
@IvDmNe Thank you so much for your help, IvDmNe! Following your advice, I've made adjustments to my code and it has successfully solved the issue. I think this could be beneficial to other users of this library who may face a similar problem. Would you consider creating a pull request to merge this change? Thanks again, your suggestion was invaluable!
@FRAOTIAC I don't think my solution is suitable for pulling to this repo ;) . It requires Boost library, which is already used in Apollo project but not used here. And in one of recent commits it is stated that asio headers from weboscketpp library are added. Yeah, maybe I should have suggest you to look at it before applying path to the repo ;)
I have made some changes in foxglove/ros-foxglove-bridge#247 which allow building the server with boost asio. The main C++ changes are currently made in the https://github.com/foxglove/ros-foxglove-bridge repo and then copied in this repo here. Once this PR got merged, I'll copy over the source code and adapt the conan recipe to allow choosing the asio version