Compare commits
	
		
			4 Commits
		
	
	
		
			v7.5.5
			...
			feature/se
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 1ac02fdc0e | ||
|  | 687956358d | ||
|  | 1a42c92325 | ||
|  | 6bb00b6788 | 
| @@ -1 +1 @@ | ||||
| docker/Dockerfile.fedora | ||||
| docker/Dockerfile.ubuntu_xenial | ||||
| @@ -30,7 +30,9 @@ namespace ix | ||||
|         _host(host), | ||||
|         _backlog(backlog), | ||||
|         _maxConnections(maxConnections), | ||||
|         _serverFd(-1), | ||||
|         _stop(false), | ||||
|         _stopGc(false), | ||||
|         _connectionStateFactory(&ConnectionState::createConnectionState) | ||||
|     { | ||||
|  | ||||
| @@ -124,11 +126,17 @@ namespace ix | ||||
|  | ||||
|     void SocketServer::start() | ||||
|     { | ||||
|         if (_thread.joinable()) return; // we've already been started | ||||
|  | ||||
|         if (!_thread.joinable()) | ||||
|         { | ||||
|             _thread = std::thread(&SocketServer::run, this); | ||||
|         } | ||||
|  | ||||
|         if (!_gcThread.joinable()) | ||||
|         { | ||||
|             _gcThread = std::thread(&SocketServer::runGC, this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void SocketServer::wait() | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(_conditionVariableMutex); | ||||
| @@ -142,21 +150,21 @@ namespace ix | ||||
|  | ||||
|     void SocketServer::stop() | ||||
|     { | ||||
|         while (true) | ||||
|         // Stop accepting connections, and close the 'accept' thread | ||||
|         if (_thread.joinable()) | ||||
|         { | ||||
|             if (closeTerminatedThreads()) break; | ||||
|  | ||||
|             // wait 10ms and try again later. | ||||
|             // we could have a timeout, but if we exit of here | ||||
|             // we leaked threads, it is quite bad. | ||||
|             std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||||
|         } | ||||
|  | ||||
|         if (!_thread.joinable()) return; // nothing to do | ||||
|  | ||||
|             _stop = true; | ||||
|             _thread.join(); | ||||
|             _stop = false; | ||||
|         } | ||||
|  | ||||
|         // Join all threads and make sure that all connections are terminated | ||||
|         if (_gcThread.joinable()) | ||||
|         { | ||||
|             _stopGc = true; | ||||
|             _gcThread.join(); | ||||
|             _stopGc = false; | ||||
|         } | ||||
|  | ||||
|         _conditionVariable.notify_one(); | ||||
|         Socket::closeSocket(_serverFd); | ||||
| @@ -175,7 +183,7 @@ namespace ix | ||||
|     // field becomes true, and we can use that to know that we can join that thread | ||||
|     // and remove it from our _connectionsThreads data structure (a list). | ||||
|     // | ||||
|     bool SocketServer::closeTerminatedThreads() | ||||
|     void SocketServer::closeTerminatedThreads() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_connectionsThreadsMutex); | ||||
|         auto it = _connectionsThreads.begin(); | ||||
| @@ -195,8 +203,6 @@ namespace ix | ||||
|             if (thread.joinable()) thread.join(); | ||||
|             it = _connectionsThreads.erase(it); | ||||
|         } | ||||
|  | ||||
|         return _connectionsThreads.empty(); | ||||
|     } | ||||
|  | ||||
|     void SocketServer::run() | ||||
| @@ -208,12 +214,6 @@ namespace ix | ||||
|         { | ||||
|             if (_stop) return; | ||||
|  | ||||
|             // Garbage collection to shutdown/join threads for closed connections. | ||||
|             // We could run this in its own thread, so that we dont need to accept | ||||
|             // a new connection to close a thread. | ||||
|             // We could also use a condition variable to be notify when we need to do this | ||||
|             closeTerminatedThreads(); | ||||
|  | ||||
|             // Use select to check whether a new connection is in progress | ||||
|             fd_set rfds; | ||||
|             struct timeval timeout; | ||||
| @@ -290,5 +290,30 @@ namespace ix | ||||
|                                 connectionState))); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     size_t SocketServer::getConnectionsThreadsCount() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(_connectionsThreadsMutex); | ||||
|         return _connectionsThreads.size(); | ||||
|     } | ||||
|  | ||||
|     void SocketServer::runGC() | ||||
|     { | ||||
|         for (;;) | ||||
|         { | ||||
|             // Garbage collection to shutdown/join threads for closed connections. | ||||
|             closeTerminatedThreads(); | ||||
|  | ||||
|             // We quit this thread if all connections are closed and we received | ||||
|             // a stop request by setting _stopGc to true. | ||||
|             if (_stopGc && getConnectionsThreadsCount() == 0) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             // Sleep a little bit then keep cleaning up | ||||
|             std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -74,6 +74,12 @@ namespace ix | ||||
|         // background thread to wait for incoming connections | ||||
|         std::atomic<bool> _stop; | ||||
|         std::thread _thread; | ||||
|         void run(); | ||||
|  | ||||
|         // background thread to cleanup (join) terminated threads | ||||
|         std::atomic<bool> _stopGc; | ||||
|         std::thread _gcThread; | ||||
|         void runGC(); | ||||
|  | ||||
|         // the list of (connectionState, threads) for each connections | ||||
|         ConnectionThreads _connectionsThreads; | ||||
| @@ -87,13 +93,12 @@ namespace ix | ||||
|         // the factory to create ConnectionState objects | ||||
|         ConnectionStateFactory _connectionStateFactory; | ||||
|  | ||||
|         // Methods | ||||
|         void run(); | ||||
|         virtual void handleConnection(int fd, | ||||
|                                       std::shared_ptr<ConnectionState> connectionState) = 0; | ||||
|         virtual size_t getConnectedClientsCount() = 0; | ||||
|  | ||||
|         // Returns true if all connection threads are joined | ||||
|         bool closeTerminatedThreads(); | ||||
|         void closeTerminatedThreads(); | ||||
|         size_t getConnectionsThreadsCount(); | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -212,9 +212,10 @@ namespace ix | ||||
|         return getReadyState() == ReadyState::Closing; | ||||
|     } | ||||
|  | ||||
|     void WebSocket::close() | ||||
|     void WebSocket::close(uint16_t code, | ||||
|                           const std::string& reason) | ||||
|     { | ||||
|         _ws.close(); | ||||
|         _ws.close(code, reason); | ||||
|     } | ||||
|  | ||||
|     void WebSocket::checkConnection(bool firstConnectionAttempt) | ||||
|   | ||||
| @@ -112,7 +112,11 @@ namespace ix | ||||
|         WebSocketSendInfo sendText(const std::string& text, | ||||
|                                    const OnProgressCallback& onProgressCallback = nullptr); | ||||
|         WebSocketSendInfo ping(const std::string& text); | ||||
|         void close(); | ||||
|  | ||||
|         // A close frame can provide a code and a reason | ||||
|         // FIXME: use constants | ||||
|         void close(uint16_t code = 1000, | ||||
|                    const std::string& reason = "Normal closure"); | ||||
|  | ||||
|         void setOnMessageCallback(const OnMessageCallback& callback); | ||||
|         static void setTrafficTrackerCallback(const OnTrafficTrackerCallback& callback); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ project (ixwebsocket_unittest) | ||||
|  | ||||
| set (CMAKE_CXX_STANDARD 14) | ||||
|  | ||||
| if (NOT WIN32) | ||||
| if (UNIX) | ||||
|   set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../third_party/sanitizers-cmake/cmake" ${CMAKE_MODULE_PATH}) | ||||
|   find_package(Sanitizers) | ||||
|   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") | ||||
| @@ -38,19 +38,22 @@ set (SOURCES | ||||
|   IXWebSocketPingTest.cpp | ||||
|   IXWebSocketTestConnectionDisconnection.cpp | ||||
|   IXUrlParserTest.cpp | ||||
|   IXWebSocketServerTest.cpp | ||||
|   IXWebSocketPingTest.cpp | ||||
| ) | ||||
|  | ||||
| # Some unittest don't work on windows yet | ||||
| if (NOT WIN32) | ||||
| if (UNIX) | ||||
|   list(APPEND SOURCES | ||||
|     IXWebSocketPingTimeoutTest.cpp | ||||
|     # IXWebSocketPingTimeoutTest.cpp # This test isn't reliable # (multiple platforms), disabling in master | ||||
|     # IXWebSocketCloseTest.cpp       #  | ||||
|     cmd_websocket_chat.cpp | ||||
|   ) | ||||
| endif() | ||||
|  | ||||
| add_executable(ixwebsocket_unittest ${SOURCES}) | ||||
|  | ||||
| if (NOT WIN32) | ||||
| if (UNIX) | ||||
|   add_sanitizers(ixwebsocket_unittest) | ||||
| endif() | ||||
|  | ||||
|   | ||||
							
								
								
									
										407
									
								
								test/IXWebSocketCloseTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								test/IXWebSocketCloseTest.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,407 @@ | ||||
| /* | ||||
|  *  IXWebSocketCloseTest.cpp | ||||
|  *  Author: Alexandre Konieczny | ||||
|  *  Copyright (c) 2019 Machine Zone. All rights reserved. | ||||
|  */ | ||||
|  | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| #include <queue> | ||||
| #include <ixwebsocket/IXWebSocket.h> | ||||
| #include <ixwebsocket/IXWebSocketServer.h> | ||||
|  | ||||
| #include "IXTest.h" | ||||
|  | ||||
| #include "catch.hpp" | ||||
|  | ||||
| using namespace ix; | ||||
|  | ||||
| namespace | ||||
| { | ||||
|     class WebSocketClient | ||||
|     { | ||||
|         public: | ||||
|             WebSocketClient(int port); | ||||
|  | ||||
|             void subscribe(const std::string& channel); | ||||
|             void start(); | ||||
|             void stop(); | ||||
|             void stop(uint16_t code, const std::string& reason); | ||||
|             bool isReady() const; | ||||
|             void sendMessage(const std::string& text); | ||||
|  | ||||
|             uint16_t getCloseCode(); | ||||
|             const std::string& getCloseReason(); | ||||
|             bool getCloseRemote(); | ||||
|  | ||||
|         private: | ||||
|             ix::WebSocket _webSocket; | ||||
|             int _port; | ||||
|  | ||||
|             mutable std::mutex _mutexCloseData; | ||||
|             uint16_t _closeCode; | ||||
|             std::string _closeReason; | ||||
|             bool _closeRemote; | ||||
|     }; | ||||
|  | ||||
|     WebSocketClient::WebSocketClient(int port) | ||||
|         : _port(port) | ||||
|         , _closeCode(0) | ||||
|         , _closeReason(std::string("")) | ||||
|         , _closeRemote(false) | ||||
|     { | ||||
|         ; | ||||
|     } | ||||
|  | ||||
|     bool WebSocketClient::isReady() const | ||||
|     { | ||||
|         return _webSocket.getReadyState() == ix::ReadyState::Open; | ||||
|     } | ||||
|  | ||||
|     uint16_t WebSocketClient::getCloseCode() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lck(_mutexCloseData); | ||||
|          | ||||
|         return _closeCode; | ||||
|     } | ||||
|  | ||||
|     const std::string& WebSocketClient::getCloseReason() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lck(_mutexCloseData); | ||||
|  | ||||
|         return _closeReason; | ||||
|     } | ||||
|  | ||||
|     bool WebSocketClient::getCloseRemote() | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lck(_mutexCloseData); | ||||
|          | ||||
|         return _closeRemote; | ||||
|     } | ||||
|  | ||||
|     void WebSocketClient::stop() | ||||
|     { | ||||
|         _webSocket.stop(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketClient::stop(uint16_t code, const std::string& reason) | ||||
|     { | ||||
|         _webSocket.close(code, reason); | ||||
|         _webSocket.stop(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketClient::start() | ||||
|     { | ||||
|         std::string url; | ||||
|         { | ||||
|             std::stringstream ss; | ||||
|             ss << "ws://localhost:" | ||||
|                << _port | ||||
|                << "/"; | ||||
|  | ||||
|             url = ss.str(); | ||||
|         } | ||||
|  | ||||
|         _webSocket.setUrl(url); | ||||
|  | ||||
|         std::stringstream ss; | ||||
|         log(std::string("Connecting to url: ") + url); | ||||
|  | ||||
|         _webSocket.setOnMessageCallback( | ||||
|             [this](ix::WebSocketMessageType messageType, | ||||
|                const std::string& str, | ||||
|                size_t wireSize, | ||||
|                const ix::WebSocketErrorInfo& error, | ||||
|                const ix::WebSocketOpenInfo& openInfo, | ||||
|                    const ix::WebSocketCloseInfo& closeInfo) | ||||
|             { | ||||
|                 std::stringstream ss; | ||||
|                 if (messageType == ix::WebSocketMessageType::Open) | ||||
|                 { | ||||
|                     log("client connected"); | ||||
|  | ||||
|                     _webSocket.disableAutomaticReconnection(); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocketMessageType::Close) | ||||
|                 { | ||||
|                     log("client disconnected"); | ||||
|  | ||||
|                     std::lock_guard<std::mutex> lck(_mutexCloseData); | ||||
|                      | ||||
|                     _closeCode = closeInfo.code; | ||||
|                     _closeReason = std::string(closeInfo.reason); | ||||
|                     _closeRemote = closeInfo.remote; | ||||
|                      | ||||
|                     _webSocket.disableAutomaticReconnection(); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocketMessageType::Error) | ||||
|                 { | ||||
|                     ss << "Error ! " << error.reason; | ||||
|                     log(ss.str()); | ||||
|  | ||||
|                     _webSocket.disableAutomaticReconnection(); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocketMessageType::Pong) | ||||
|                 { | ||||
|                     ss << "Received pong message " << str; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocketMessageType::Ping) | ||||
|                 { | ||||
|                     ss << "Received ping message " << str; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else if (messageType == ix::WebSocketMessageType::Message) | ||||
|                 { | ||||
|                     ss << "Received message " << str; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     ss << "Invalid ix::WebSocketMessageType"; | ||||
|                     log(ss.str()); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         _webSocket.start(); | ||||
|     } | ||||
|  | ||||
|     void WebSocketClient::sendMessage(const std::string& text) | ||||
|     { | ||||
|         _webSocket.send(text); | ||||
|     } | ||||
|  | ||||
|     bool startServer(ix::WebSocketServer& server, | ||||
|                      uint16_t& receivedCloseCode, | ||||
|                      std::string& receivedCloseReason, | ||||
|                      bool& receivedCloseRemote, | ||||
|                      std::mutex& mutexWrite) | ||||
|     { | ||||
|         // A dev/null server | ||||
|         server.setOnConnectionCallback( | ||||
|             [&server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](std::shared_ptr<ix::WebSocket> webSocket, | ||||
|                                              std::shared_ptr<ConnectionState> connectionState) | ||||
|             { | ||||
|                 webSocket->setOnMessageCallback( | ||||
|                     [webSocket, connectionState, &server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](ix::WebSocketMessageType messageType, | ||||
|                        const std::string& str, | ||||
|                        size_t wireSize, | ||||
|                        const ix::WebSocketErrorInfo& error, | ||||
|                        const ix::WebSocketOpenInfo& openInfo, | ||||
|                        const ix::WebSocketCloseInfo& closeInfo) | ||||
|                     { | ||||
|                         if (messageType == ix::WebSocketMessageType::Open) | ||||
|                         { | ||||
|                             Logger() << "New server connection"; | ||||
|                             Logger() << "id: " << connectionState->getId(); | ||||
|                             Logger() << "Uri: " << openInfo.uri; | ||||
|                             Logger() << "Headers:"; | ||||
|                             for (auto it : openInfo.headers) | ||||
|                             { | ||||
|                                 Logger() << it.first << ": " << it.second; | ||||
|                             } | ||||
|                         } | ||||
|                         else if (messageType == ix::WebSocketMessageType::Close) | ||||
|                         { | ||||
|                             log("Server closed connection"); | ||||
|  | ||||
|                             //Logger() << closeInfo.code; | ||||
|                             //Logger() << closeInfo.reason; | ||||
|                             //Logger() << closeInfo.remote; | ||||
|  | ||||
|                             std::lock_guard<std::mutex> lck(mutexWrite); | ||||
|                              | ||||
|                             receivedCloseCode = closeInfo.code; | ||||
|                             receivedCloseReason = std::string(closeInfo.reason); | ||||
|                             receivedCloseRemote = closeInfo.remote; | ||||
|                         } | ||||
|                     } | ||||
|                 ); | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         auto res = server.listen(); | ||||
|         if (!res.first) | ||||
|         { | ||||
|             log(res.second); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         server.start(); | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Websocket_client_close_default", "[close]") | ||||
| { | ||||
|     SECTION("Make sure that close code and reason was used and sent to server.") | ||||
|     { | ||||
|         ix::setupWebSocketTrafficTrackerCallback(); | ||||
|  | ||||
|         int port = getFreePort(); | ||||
|         ix::WebSocketServer server(port); | ||||
|          | ||||
|         uint16_t serverReceivedCloseCode(0); | ||||
|         bool serverReceivedCloseRemote(false); | ||||
|         std::string serverReceivedCloseReason(""); | ||||
|         std::mutex mutexWrite; | ||||
|  | ||||
|         REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); | ||||
|  | ||||
|         std::string session = ix::generateSessionId(); | ||||
|         WebSocketClient webSocketClient(port); | ||||
|  | ||||
|         webSocketClient.start(); | ||||
|  | ||||
|         // Wait for all chat instance to be ready | ||||
|         while (true) | ||||
|         { | ||||
|             if (webSocketClient.isReady()) break; | ||||
|             ix::msleep(10); | ||||
|         } | ||||
|  | ||||
|         REQUIRE(server.getClients().size() == 1); | ||||
|  | ||||
|         ix::msleep(100); | ||||
|  | ||||
|         webSocketClient.stop(); | ||||
|  | ||||
|         ix::msleep(200); | ||||
|  | ||||
|         // ensure client close is the same as values given | ||||
|         REQUIRE(webSocketClient.getCloseCode() == 1000); | ||||
|         REQUIRE(webSocketClient.getCloseReason() == "Normal closure"); | ||||
|         REQUIRE(webSocketClient.getCloseRemote() == false); | ||||
|  | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lck(mutexWrite); | ||||
|              | ||||
|             // Here we read the code/reason received by the server, and ensure that remote is true | ||||
|             REQUIRE(serverReceivedCloseCode == 1000); | ||||
|             REQUIRE(serverReceivedCloseReason == "Normal closure"); | ||||
|             REQUIRE(serverReceivedCloseRemote == true); | ||||
|         } | ||||
|  | ||||
|         // Give us 1000ms for the server to notice that clients went away | ||||
|         ix::msleep(1000); | ||||
|         REQUIRE(server.getClients().size() == 0); | ||||
|  | ||||
|         ix::reportWebSocketTraffic(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Websocket_client_close_params_given", "[close]") | ||||
| { | ||||
|     SECTION("Make sure that close code and reason was used and sent to server.") | ||||
|     { | ||||
|         ix::setupWebSocketTrafficTrackerCallback(); | ||||
|  | ||||
|         int port = getFreePort(); | ||||
|         ix::WebSocketServer server(port); | ||||
|          | ||||
|         uint16_t serverReceivedCloseCode(0); | ||||
|         bool serverReceivedCloseRemote(false); | ||||
|         std::string serverReceivedCloseReason(""); | ||||
|         std::mutex mutexWrite; | ||||
|  | ||||
|         REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); | ||||
|  | ||||
|         std::string session = ix::generateSessionId(); | ||||
|         WebSocketClient webSocketClient(port); | ||||
|  | ||||
|         webSocketClient.start(); | ||||
|  | ||||
|         // Wait for all chat instance to be ready | ||||
|         while (true) | ||||
|         { | ||||
|             if (webSocketClient.isReady()) break; | ||||
|             ix::msleep(10); | ||||
|         } | ||||
|  | ||||
|         REQUIRE(server.getClients().size() == 1); | ||||
|  | ||||
|         ix::msleep(100); | ||||
|  | ||||
|         webSocketClient.stop(4000, "My reason"); | ||||
|  | ||||
|         ix::msleep(500); | ||||
|  | ||||
|         // ensure client close is the same as values given | ||||
|         REQUIRE(webSocketClient.getCloseCode() == 4000); | ||||
|         REQUIRE(webSocketClient.getCloseReason() == "My reason"); | ||||
|         REQUIRE(webSocketClient.getCloseRemote() == false); | ||||
|  | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lck(mutexWrite); | ||||
|              | ||||
|             // Here we read the code/reason received by the server, and ensure that remote is true | ||||
|             REQUIRE(serverReceivedCloseCode == 4000); | ||||
|             REQUIRE(serverReceivedCloseReason == "My reason"); | ||||
|             REQUIRE(serverReceivedCloseRemote == true); | ||||
|         } | ||||
|  | ||||
|         // Give us 1000ms for the server to notice that clients went away | ||||
|         ix::msleep(1000); | ||||
|         REQUIRE(server.getClients().size() == 0); | ||||
|  | ||||
|         ix::reportWebSocketTraffic(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Websocket_server_close", "[close]") | ||||
| { | ||||
|     SECTION("Make sure that close code and reason was read from server.") | ||||
|     { | ||||
|         ix::setupWebSocketTrafficTrackerCallback(); | ||||
|  | ||||
|         int port = getFreePort(); | ||||
|         ix::WebSocketServer server(port); | ||||
|          | ||||
|         uint16_t serverReceivedCloseCode(0); | ||||
|         bool serverReceivedCloseRemote(false); | ||||
|         std::string serverReceivedCloseReason(""); | ||||
|         std::mutex mutexWrite; | ||||
|  | ||||
|         REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); | ||||
|  | ||||
|         std::string session = ix::generateSessionId(); | ||||
|         WebSocketClient webSocketClient(port); | ||||
|  | ||||
|         webSocketClient.start(); | ||||
|  | ||||
|         // Wait for all chat instance to be ready | ||||
|         while (true) | ||||
|         { | ||||
|             if (webSocketClient.isReady()) break; | ||||
|             ix::msleep(10); | ||||
|         } | ||||
|  | ||||
|         REQUIRE(server.getClients().size() == 1); | ||||
|  | ||||
|         ix::msleep(200); | ||||
|  | ||||
|         server.stop(); | ||||
|  | ||||
|         ix::msleep(500); | ||||
|  | ||||
|         // ensure client close is the same as values given | ||||
|         REQUIRE(webSocketClient.getCloseCode() == 1000); | ||||
|         REQUIRE(webSocketClient.getCloseReason() == "Normal closure"); | ||||
|         REQUIRE(webSocketClient.getCloseRemote() == true); | ||||
|  | ||||
|         { | ||||
|             std::lock_guard<std::mutex> lck(mutexWrite); | ||||
|              | ||||
|             // Here we read the code/reason received by the server, and ensure that remote is true | ||||
|             REQUIRE(serverReceivedCloseCode == 1000); | ||||
|             REQUIRE(serverReceivedCloseReason == "Normal closure"); | ||||
|             REQUIRE(serverReceivedCloseRemote == false); | ||||
|         } | ||||
|  | ||||
|         // Give us 1000ms for the server to notice that clients went away | ||||
|         ix::msleep(1000); | ||||
|         REQUIRE(server.getClients().size() == 0); | ||||
|  | ||||
|         ix::reportWebSocketTraffic(); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user