From 682e84e5f4217f529ec18847bb98b6bc775a4645 Mon Sep 17 00:00:00 2001 From: Rad Date: Tue, 3 Mar 2026 01:26:37 +0100 Subject: [PATCH] Enhance UdpSocket error handling and usability - Introduced a new `quarantine_socket` function to centralize error handling for socket operations, improving code clarity and maintainability. - Updated error handling in `UdpSocket` methods to utilize `quarantine_socket`, ensuring consistent logging and socket management across setup, send, and receive operations. - Added a `cancel` method to `UdpSocket` to safely cancel socket operations when the socket is not usable, enhancing robustness in error scenarios. - Introduced a `m_socket_usable` flag to track socket state, preventing operations on unusable sockets and improving overall stability. --- src/slic3r/Utils/Bonjour.cpp | 46 ++++++++++++++++++++++++++++++++---- src/slic3r/Utils/Bonjour.hpp | 3 ++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/slic3r/Utils/Bonjour.cpp b/src/slic3r/Utils/Bonjour.cpp index 53ddcdf5f4..a8f9ae8dbe 100644 --- a/src/slic3r/Utils/Bonjour.cpp +++ b/src/slic3r/Utils/Bonjour.cpp @@ -19,6 +19,26 @@ namespace endian = boost::endian; namespace asio = boost::asio; using boost::asio::ip::udp; +namespace { + +void quarantine_socket(udp::socket& socket, bool& socket_usable, const char* action, const std::exception& e) +{ +#ifdef __APPLE__ + socket_usable = false; + boost::system::error_code ec; + socket.cancel(ec); + socket.close(ec); + BOOST_LOG_TRIVIAL(error) << action << ": " << e.what(); +#else + (void) socket; + (void) socket_usable; + (void) action; + BOOST_LOG_TRIVIAL(error) << e.what(); +#endif +} + +} + namespace Slic3r { @@ -649,7 +669,7 @@ UdpSocket::UdpSocket( Bonjour::ReplyFn replyfn, const asio::ip::address& multica BOOST_LOG_TRIVIAL(info) << "Socket created. Multicast: " << multicast_address << ". Interface: " << interface_address; } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << e.what(); + quarantine_socket(socket, m_socket_usable, "UdpSocket setup failed", e); } } @@ -673,7 +693,7 @@ UdpSocket::UdpSocket( Bonjour::ReplyFn replyfn, const asio::ip::address& multica BOOST_LOG_TRIVIAL(info) << "Socket created. Multicast: " << multicast_address; } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << e.what(); + quarantine_socket(socket, m_socket_usable, "UdpSocket setup failed", e); } } @@ -695,8 +715,20 @@ UdpSocket::~UdpSocket() } } +void UdpSocket::cancel() +{ + if (!m_socket_usable) + return; + + boost::system::error_code ec; + socket.cancel(ec); +} + void UdpSocket::send() { + if (!m_socket_usable) + return; + try { for (const auto& request : requests) socket.send_to(asio::buffer(request.m_data), mcast_endpoint); @@ -705,12 +737,15 @@ void UdpSocket::send() async_receive(); } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << e.what(); + quarantine_socket(socket, m_socket_usable, "UdpSocket send failed", e); } } void UdpSocket::async_receive() { + if (!m_socket_usable) + return; + try { // our session to hold the buffer + endpoint auto session = create_session(); @@ -719,12 +754,15 @@ void UdpSocket::async_receive() , boost::bind(&UdpSocket::receive_handler, this, session, asio::placeholders::error, asio::placeholders::bytes_transferred)); } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << e.what(); + quarantine_socket(socket, m_socket_usable, "UdpSocket receive setup failed", e); } } void UdpSocket::receive_handler(SharedSession session, const boost::system::error_code& error, size_t bytes) { + if (!m_socket_usable) + return; + // let io_service to handle the datagram on session // from boost documentation io_service::post: // The io_service guarantees that the handler will only be called in a thread in which the run(), run_one(), poll() or poll_one() member functions is currently being invoked. diff --git a/src/slic3r/Utils/Bonjour.hpp b/src/slic3r/Utils/Bonjour.hpp index 8d30c7b3a2..92cd79fbac 100644 --- a/src/slic3r/Utils/Bonjour.hpp +++ b/src/slic3r/Utils/Bonjour.hpp @@ -161,7 +161,7 @@ public: void send(); void async_receive(); - void cancel() { socket.cancel(); } + void cancel(); protected: void receive_handler(SharedSession session, const boost::system::error_code& error, size_t bytes); virtual SharedSession create_session() const = 0; @@ -172,6 +172,7 @@ protected: boost::asio::ip::udp::endpoint mcast_endpoint; std::shared_ptr< boost::asio::io_service > io_service; std::vector requests; + bool m_socket_usable { true }; }; class LookupSocket : public UdpSocket