From 5eacfe6b229677d2b851052872e8b3ee9f72112f Mon Sep 17 00:00:00 2001 From: eidheim Date: Wed, 13 May 2020 18:58:44 +0200 Subject: Fixes #145: corrected client when reading early messages from server (sent together with handshake response) --- client_ws.hpp | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/client_ws.hpp b/client_ws.hpp index b17ff5e..b5ce2d7 100644 --- a/client_ws.hpp +++ b/client_ws.hpp @@ -460,7 +460,7 @@ namespace SimpleWeb { void read_message(const std::shared_ptr &connection, std::size_t num_additional_bytes) { connection->set_timeout(); - asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > 2 ? 0 : 2 - num_additional_bytes), [this, connection](const error_code &ec, std::size_t bytes_transferred) { + asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > 2 ? 0 : 2 - num_additional_bytes), [this, connection, num_additional_bytes](const error_code &ec, std::size_t bytes_transferred) { connection->cancel_timeout(); auto lock = connection->handler_runner->continue_lock(); if(!lock) @@ -470,7 +470,7 @@ namespace SimpleWeb { this->read_message(connection, 0); return; } - std::size_t num_additional_bytes = connection->in_message->streambuf.size() - bytes_transferred; + auto updated_num_additional_bytes = num_additional_bytes > 2 ? num_additional_bytes - 2 : 0; std::array first_bytes; connection->in_message->read(reinterpret_cast(&first_bytes[0]), 2); @@ -490,14 +490,12 @@ namespace SimpleWeb { if(length == 126) { // 2 next bytes is the size of content connection->set_timeout(); - asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > 2 ? 0 : 2 - num_additional_bytes), [this, connection](const error_code &ec, std::size_t bytes_transferred) { + asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(updated_num_additional_bytes > 2 ? 0 : 2 - updated_num_additional_bytes), [this, connection, updated_num_additional_bytes](const error_code &ec, std::size_t /*bytes_transferred*/) { connection->cancel_timeout(); auto lock = connection->handler_runner->continue_lock(); if(!lock) return; if(!ec) { - std::size_t num_additional_bytes = connection->in_message->streambuf.size() - bytes_transferred; - std::array length_bytes; connection->in_message->read(reinterpret_cast(&length_bytes[0]), 2); @@ -507,7 +505,7 @@ namespace SimpleWeb { length += static_cast(length_bytes[c]) << (8 * (num_bytes - 1 - c)); connection->in_message->length = length; - this->read_message_content(connection, num_additional_bytes); + this->read_message_content(connection, updated_num_additional_bytes > 2 ? updated_num_additional_bytes - 2 : 0); } else this->connection_error(connection, ec); @@ -516,14 +514,12 @@ namespace SimpleWeb { else if(length == 127) { // 8 next bytes is the size of content connection->set_timeout(); - asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > 8 ? 0 : 8 - num_additional_bytes), [this, connection](const error_code &ec, std::size_t bytes_transferred) { + asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(updated_num_additional_bytes > 8 ? 0 : 8 - updated_num_additional_bytes), [this, connection, updated_num_additional_bytes](const error_code &ec, std::size_t /*bytes_transferred*/) { connection->cancel_timeout(); auto lock = connection->handler_runner->continue_lock(); if(!lock) return; if(!ec) { - std::size_t num_additional_bytes = connection->in_message->streambuf.size() - bytes_transferred; - std::array length_bytes; connection->in_message->read(reinterpret_cast(&length_bytes[0]), 8); @@ -533,7 +529,7 @@ namespace SimpleWeb { length += static_cast(length_bytes[c]) << (8 * (num_bytes - 1 - c)); connection->in_message->length = length; - this->read_message_content(connection, num_additional_bytes); + this->read_message_content(connection, updated_num_additional_bytes > 8 ? updated_num_additional_bytes - 8 : 0); } else this->connection_error(connection, ec); @@ -541,7 +537,7 @@ namespace SimpleWeb { } else { connection->in_message->length = length; - this->read_message_content(connection, num_additional_bytes); + this->read_message_content(connection, updated_num_additional_bytes); } } else @@ -559,15 +555,15 @@ namespace SimpleWeb { return; } connection->set_timeout(); - asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > connection->in_message->length ? 0 : connection->in_message->length - num_additional_bytes), [this, connection](const error_code &ec, std::size_t bytes_transferred) { + asio::async_read(*connection->socket, connection->in_message->streambuf, asio::transfer_exactly(num_additional_bytes > connection->in_message->length ? 0 : connection->in_message->length - num_additional_bytes), [this, connection, num_additional_bytes](const error_code &ec, std::size_t /*bytes_transferred*/) { connection->cancel_timeout(); auto lock = connection->handler_runner->continue_lock(); if(!lock) return; if(!ec) { - std::size_t num_additional_bytes = connection->in_message->streambuf.size() - bytes_transferred; + auto updated_num_additional_bytes = num_additional_bytes > connection->in_message->length ? num_additional_bytes - connection->in_message->length : 0; std::shared_ptr next_in_message; - if(num_additional_bytes > 0) { // Extract bytes that are not extra bytes in buffer (only happen when several messages are sent in upgrade response) + if(updated_num_additional_bytes > 0) { // Extract bytes that are not extra bytes in buffer (only happen when several messages are sent in upgrade response) next_in_message = connection->in_message; connection->in_message = std::shared_ptr(new InMessage(next_in_message->fin_rsv_opcode, next_in_message->length)); @@ -605,7 +601,7 @@ namespace SimpleWeb { // Next message connection->in_message = next_in_message; - this->read_message(connection, num_additional_bytes); + this->read_message(connection, updated_num_additional_bytes); } // If pong else if((connection->in_message->fin_rsv_opcode & 0x0f) == 10) { @@ -614,7 +610,7 @@ namespace SimpleWeb { // Next message connection->in_message = next_in_message; - this->read_message(connection, num_additional_bytes); + this->read_message(connection, updated_num_additional_bytes); } // If fragmented message and not final fragment else if((connection->in_message->fin_rsv_opcode & 0x80) == 0) { @@ -633,7 +629,7 @@ namespace SimpleWeb { // Next message connection->in_message = next_in_message; - this->read_message(connection, num_additional_bytes); + this->read_message(connection, updated_num_additional_bytes); } else { if(this->on_message) { @@ -655,7 +651,7 @@ namespace SimpleWeb { connection->in_message = next_in_message; // Only reset fragmented_message for non-control frames (control frames can be in between a fragmented message) connection->fragmented_in_message = nullptr; - this->read_message(connection, num_additional_bytes); + this->read_message(connection, updated_num_additional_bytes); } } else -- cgit v1.2.3 From 28dd555339f5b17c88d1d5bbc9188bda999b6176 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 26 Jun 2020 18:53:34 +0200 Subject: Do not run add_compile_options when Simple-WebSocket-Server is a sub-project --- CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a9429d..9d2d4f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,15 +5,6 @@ project (Simple-WebSocket-Server) option(USE_STANDALONE_ASIO "set ON to use standalone Asio instead of Boost.Asio" OFF) option(BUILD_TESTING "set ON to build library tests" OFF) -if(NOT MSVC) - add_compile_options(-std=c++11 -Wall -Wextra -Wsign-conversion) - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wthread-safety) - endif() -else() - add_compile_options(/W1) -endif() - add_library(simple-websocket-server INTERFACE) target_include_directories(simple-websocket-server INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -55,6 +46,15 @@ target_include_directories(simple-websocket-server INTERFACE ${OPENSSL_INCLUDE_D # If Simple-WebSocket-Server is not a sub-project: if(CMAKE_SOURCE_DIR STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + if(NOT MSVC) + add_compile_options(-std=c++11 -Wall -Wextra -Wsign-conversion) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wthread-safety) + endif() + else() + add_compile_options(/W1) + endif() + add_executable(ws_examples ws_examples.cpp) target_link_libraries(ws_examples simple-websocket-server) add_executable(wss_examples wss_examples.cpp) -- cgit v1.2.3 From 6ee2a61a64e169471a000a8c91e498728bdc8456 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sun, 28 Jun 2020 08:32:45 +0200 Subject: Added fallback to ipv4 if ipv6 is not supported --- server_ws.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/server_ws.hpp b/server_ws.hpp index e91a479..9330301 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -363,7 +363,7 @@ namespace SimpleWeb { std::unique_lock lock(start_stop_mutex); asio::ip::tcp::endpoint endpoint; - if(config.address.size() > 0) + if(!config.address.empty()) endpoint = asio::ip::tcp::endpoint(make_address(config.address), config.port); else endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v6(), config.port); @@ -375,7 +375,17 @@ namespace SimpleWeb { if(!acceptor) acceptor = std::unique_ptr(new asio::ip::tcp::acceptor(*io_service)); - acceptor->open(endpoint.protocol()); + try { + acceptor->open(endpoint.protocol()); + } + catch(const system_error &error) { + if(error.code() == asio::error::address_family_not_supported && config.address.empty()) { + endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config.port); + acceptor->open(endpoint.protocol()); + } + else + throw; + } acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address)); if(config.fast_open) { #if defined(__linux__) && defined(TCP_FASTOPEN) -- cgit v1.2.3 From 7c578dba0209d1d13aeb3945183b92d20a704fb1 Mon Sep 17 00:00:00 2001 From: Michael Maroszek Date: Tue, 28 Jul 2020 16:10:07 +0200 Subject: move endpoint initialization into constructor --- server_ws.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server_ws.hpp b/server_ws.hpp index 9330301..6674e48 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -79,7 +79,13 @@ namespace SimpleWeb { friend class SocketServer; public: - Connection(std::unique_ptr &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), closed(false) {} + Connection(std::unique_ptr &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), closed(false) { + try { + endpoint = socket->lowest_layer().remote_endpoint(); + } + catch (...) { + } + } std::string method, path, query_string, http_version; @@ -571,12 +577,6 @@ namespace SimpleWeb { if(status_code != StatusCode::information_switching_protocols) return; - try { - connection->endpoint = connection->socket->lowest_layer().remote_endpoint(); - } - catch(...) { - } - if(!ec) { connection_open(connection, regex_endpoint.second); read_message(connection, regex_endpoint.second); -- cgit v1.2.3 From af45eb04b86718eac820ba8a3e781d8044ce3de1 Mon Sep 17 00:00:00 2001 From: Michael Maroszek Date: Tue, 28 Jul 2020 16:32:44 +0200 Subject: move endpoint initialization into constructor #2 --- server_ws.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server_ws.hpp b/server_ws.hpp index 6674e48..955975c 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -121,7 +121,13 @@ namespace SimpleWeb { /// Used to call Server::upgrade. template Connection(std::shared_ptr handler_runner_, long timeout_idle, Args &&... args) noexcept - : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward(args)...)), timeout_idle(timeout_idle), closed(false) {} + : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward(args)...)), timeout_idle(timeout_idle), closed(false) { + try { + endpoint = socket->lowest_layer().remote_endpoint(); + } + catch (...) { + } + } std::shared_ptr handler_runner; -- cgit v1.2.3 From 95cefd438f06dab3ef2c501c0d1f1105121ce305 Mon Sep 17 00:00:00 2001 From: Michael Maroszek Date: Tue, 28 Jul 2020 16:38:18 +0200 Subject: move endpoint initialization further up --- server_ws.hpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/server_ws.hpp b/server_ws.hpp index 955975c..6af4384 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -79,13 +79,7 @@ namespace SimpleWeb { friend class SocketServer; public: - Connection(std::unique_ptr &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), closed(false) { - try { - endpoint = socket->lowest_layer().remote_endpoint(); - } - catch (...) { - } - } + Connection(std::unique_ptr &&socket_) noexcept : socket(std::move(socket_)), timeout_idle(0), closed(false) {} std::string method, path, query_string, http_version; @@ -121,13 +115,7 @@ namespace SimpleWeb { /// Used to call Server::upgrade. template Connection(std::shared_ptr handler_runner_, long timeout_idle, Args &&... args) noexcept - : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward(args)...)), timeout_idle(timeout_idle), closed(false) { - try { - endpoint = socket->lowest_layer().remote_endpoint(); - } - catch (...) { - } - } + : handler_runner(std::move(handler_runner_)), socket(new socket_type(std::forward(args)...)), timeout_idle(timeout_idle), closed(false) {} std::shared_ptr handler_runner; @@ -542,6 +530,12 @@ namespace SimpleWeb { } void write_handshake(const std::shared_ptr &connection) { + try { + connection->endpoint = connection->socket->lowest_layer().remote_endpoint(); + } + catch (...) { + } + for(auto ®ex_endpoint : endpoint) { regex::smatch path_match; if(regex::regex_match(connection->path, path_match, regex_endpoint.first)) { -- cgit v1.2.3 From d1d6b015172731902c88bcd2c7fe064c55605844 Mon Sep 17 00:00:00 2001 From: eidheim Date: Sat, 8 Aug 2020 10:40:44 +0200 Subject: Cleanup of Connection::remote_endpoint_address and Connection::remote_endpoint_port as suggested in !108, moved read of endpoint before on_hanshake call in write_handshake, and added Connection::local_endpoint as in commit https://gitlab.com/eidheim/Simple-Web-Server/-/commit/8e82428740c0d6b9126480f816178fc404bfd4ec. --- server_ws.hpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/server_ws.hpp b/server_ws.hpp index 6af4384..158813d 100644 --- a/server_ws.hpp +++ b/server_ws.hpp @@ -91,10 +91,20 @@ namespace SimpleWeb { return endpoint; } + asio::ip::tcp::endpoint local_endpoint() const noexcept { + try { + if(auto connection = this->connection.lock()) + return connection->socket->lowest_layer().local_endpoint(); + } + catch(...) { + } + return asio::ip::tcp::endpoint(); + } + /// Deprecated, please use remote_endpoint().address().to_string() instead. DEPRECATED std::string remote_endpoint_address() const noexcept { try { - return socket->lowest_layer().remote_endpoint().address().to_string(); + return endpoint.address().to_string(); } catch(...) { } @@ -104,7 +114,7 @@ namespace SimpleWeb { /// Deprecated, please use remote_endpoint().port() instead. DEPRECATED unsigned short remote_endpoint_port() const noexcept { try { - return socket->lowest_layer().remote_endpoint().port(); + return endpoint.port(); } catch(...) { } @@ -530,12 +540,6 @@ namespace SimpleWeb { } void write_handshake(const std::shared_ptr &connection) { - try { - connection->endpoint = connection->socket->lowest_layer().remote_endpoint(); - } - catch (...) { - } - for(auto ®ex_endpoint : endpoint) { regex::smatch path_match; if(regex::regex_match(connection->path, path_match, regex_endpoint.first)) { @@ -554,6 +558,12 @@ namespace SimpleWeb { auto sha1 = Crypto::sha1(key_it->second + ws_magic_string); response_header.emplace("Sec-WebSocket-Accept", Crypto::Base64::encode(sha1)); + try { + connection->endpoint = connection->socket->lowest_layer().remote_endpoint(); + } + catch(...) { + } + if(regex_endpoint.second.on_handshake) status_code = regex_endpoint.second.on_handshake(connection, response_header); -- cgit v1.2.3