diff --git a/CMakeLists.txt b/CMakeLists.txt index 73e7353..2071ec1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.24) -project(native_streaming VERSION 1.0.14 LANGUAGES CXX) +project(native_streaming VERSION 1.0.15 LANGUAGES CXX) if (NOT CMAKE_MESSAGE_CONTEXT) set(CMAKE_MESSAGE_CONTEXT ${PROJECT_NAME}) diff --git a/changelog b/changelog index 089f3ae..5823d90 100644 --- a/changelog +++ b/changelog @@ -48,3 +48,6 @@ ## v1.0.14 - Fix missing include + +## v1.0.15 + - Fix issue with retrieving connection endpoint name on server app resuming in debug mode diff --git a/include/native_streaming/client.hpp b/include/native_streaming/client.hpp index 9b7e88c..f3a5291 100644 --- a/include/native_streaming/client.hpp +++ b/include/native_streaming/client.hpp @@ -68,8 +68,9 @@ class Client : public std::enable_shared_from_this /// @brief creates a connection Session using provided web-socket stream object /// @param wsStream web-socket stream object which provides as a R/W interface for connection + /// @param endpointAddress string with the address in the format IP:port of the connection endpoint associated with the session /// @return pointer to created Session object - std::shared_ptr createSession(std::shared_ptr wsStream); + std::shared_ptr createSession(std::shared_ptr wsStream, const std::string& endpointAddress); /// async operations handler std::shared_ptr ioContextPtr; diff --git a/include/native_streaming/server.hpp b/include/native_streaming/server.hpp index 0f4000b..58679be 100644 --- a/include/native_streaming/server.hpp +++ b/include/native_streaming/server.hpp @@ -83,8 +83,11 @@ class Server : public std::enable_shared_from_this /// @brief creates a connection Session using provided web-socket stream object /// @param wsStream web-socket stream object which provides as a R/W interface for connection /// @param user context, usualy a pointer to the authenticated user object + /// @param endpointAddress string with the address in the format IP:port of the connection endpoint associated with the session /// @return pointer to created Session object - std::shared_ptr createSession(std::shared_ptr wsStream, const std::shared_ptr& userContext); + std::shared_ptr createSession(std::shared_ptr wsStream, + const std::shared_ptr& userContext, + const std::string& endpointAddress); /// async operations handler std::shared_ptr ioContextPtr; diff --git a/include/native_streaming/session.hpp b/include/native_streaming/session.hpp index ea7fd47..c880108 100644 --- a/include/native_streaming/session.hpp +++ b/include/native_streaming/session.hpp @@ -36,7 +36,8 @@ class Session : public std::enable_shared_from_this std::shared_ptr wsStream, std::shared_ptr userContext, boost::beast::role_type role, - LogCallback logCallback); + LogCallback logCallback, + const std::string& endpointAddress); ~Session(); Session(const Session&) = delete; @@ -122,6 +123,9 @@ class Session : public std::enable_shared_from_this /// @brief interval of sending the websocket pongs std::chrono::milliseconds heartbeatPeriod; + + /// @brief string with the address in the format IP:port of the connection endpoint associated with the session + std::string endpointAddress; }; END_NAMESPACE_NATIVE_STREAMING diff --git a/src/client.cpp b/src/client.cpp index 7c59fba..7d7fc3d 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -156,13 +156,25 @@ void Client::onUpgradeConnection(const boost::system::error_code& ec, std::share return; } - onNewSessionCallback(createSession(wsStream)); + std::string endpointAddress; + try + { + auto remoteEp = wsStream->next_layer().socket().remote_endpoint(); + endpointAddress = remoteEp.address().to_string() + ":" + std::to_string(remoteEp.port()); + } + catch (const std::exception& e) + { + NS_LOG_E("Websocket connection aborted - cannot get connection endpoint: {}", e.what()); + return; + } + + onNewSessionCallback(createSession(wsStream, endpointAddress)); } -std::shared_ptr Client::createSession(std::shared_ptr wsStream) +std::shared_ptr Client::createSession(std::shared_ptr wsStream, const std::string& endpointAddress) { websocketStream.reset(); - return std::make_shared(ioContextPtr, wsStream, nullptr, boost::beast::role_type::client, logCallback); + return std::make_shared(ioContextPtr, wsStream, nullptr, boost::beast::role_type::client, logCallback, endpointAddress); } END_NAMESPACE_NATIVE_STREAMING diff --git a/src/server.cpp b/src/server.cpp index a70950c..54e37fe 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -201,21 +201,46 @@ void Server::onUpgradeConnection(const boost::system::error_code& ec, std::shared_ptr wsStream, const std::shared_ptr& userContext) { - std::string id = wsStream->next_layer().socket().remote_endpoint().address().to_string() + ":" + - std::to_string(wsStream->next_layer().socket().remote_endpoint().port()); if (ec) { - NS_LOG_E("Client {} - websocket connection failed: {}", id, ec.message()); + NS_LOG_E("Connection failed to upgrade to websocket: {}", ec.message()); return; } - NS_LOG_I("Client {} - websocket connection accepted", id); - onNewSessionCallback(createSession(wsStream, userContext)); + // Pausing the server app with a debugger causes incoming re-/connection attempts to be rejected on the client side, + // but they remain queued on the server side. When the server resumes, it processes these connections, + // inevitably failing due to the sockets being in an invalid state. Although the socket appears open, + // it throws an exception when attempting to retrieve the endpoint address. + // To handle this, first verify the socket state and then safely attempt to retrieve the endpoint name. + std::string endpointAddress; + if (!(wsStream->is_open() && wsStream->next_layer().socket().is_open())) + { + NS_LOG_W("Websocket connection aborted: the socket is already closed"); + return; + } + else + { + try + { + auto remoteEp = wsStream->next_layer().socket().remote_endpoint(); + endpointAddress = remoteEp.address().to_string() + ":" + std::to_string(remoteEp.port()); + } + catch (const std::exception& e) + { + NS_LOG_W("Websocket connection aborted - cannot get connection endpoint: {}", e.what()); + return; + } + } + + NS_LOG_I("Client {} - websocket connection accepted", endpointAddress); + onNewSessionCallback(createSession(wsStream, userContext, endpointAddress)); } -std::shared_ptr Server::createSession(std::shared_ptr wsStream, const std::shared_ptr& userContext) +std::shared_ptr Server::createSession(std::shared_ptr wsStream, + const std::shared_ptr& userContext, + const std::string& endpointAddress) { - return std::make_shared(ioContextPtr, wsStream, userContext, boost::beast::role_type::server, logCallback); + return std::make_shared(ioContextPtr, wsStream, userContext, boost::beast::role_type::server, logCallback, endpointAddress); } END_NAMESPACE_NATIVE_STREAMING diff --git a/src/session.cpp b/src/session.cpp index 10b3239..a501b9f 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -9,7 +9,8 @@ Session::Session(std::shared_ptr ioContextPtr, std::shared_ptr wsStream, std::shared_ptr userContext, boost::beast::role_type role, - LogCallback logCallback) + LogCallback logCallback, + const std::string& endpointAddress) : role(role) , logCallback(logCallback) , ioContextPtr(ioContextPtr) @@ -19,6 +20,7 @@ Session::Session(std::shared_ptr ioContextPtr, , userContext(userContext) , heartbeatTimer(std::make_shared(*ioContextPtr.get())) , heartbeatPeriod(defaultHeartbeatPeriod) + , endpointAddress(endpointAddress) { setOptions(); } @@ -173,9 +175,7 @@ std::shared_ptr Session::getUserContext() std::string Session::getEndpointAddress() { - std::string address = wsStream->next_layer().socket().remote_endpoint().address().to_string(); - address += std::string(":") + std::to_string(wsStream->next_layer().socket().remote_endpoint().port()); - return address; + return endpointAddress; } void Session::setWriteTimedOutHandler(OnSessionErrorCallback writeTaskTimeoutHandler)