diff options
author | Shobhit Adlakha <adlakhashobhit@gmail.com> | 2019-05-08 10:23:00 -0400 |
---|---|---|
committer | Shobhit Adlakha <adlakhashobhit@gmail.com> | 2019-05-08 10:23:00 -0400 |
commit | 96f9ba68ea0ff0f73a927bf3deeca58f4a5bae99 (patch) | |
tree | 037dd682a565d67ad12e36e60f6d1ebc41b8bb03 | |
parent | 27c36487854b6725eddaddb069a5effd1b99ff7c (diff) | |
download | sdl_core-96f9ba68ea0ff0f73a927bf3deeca58f4a5bae99.tar.gz |
Separated interface and implementation for sample_websocket_server
4 files changed, 242 insertions, 204 deletions
diff --git a/src/components/transport_manager/test/CMakeLists.txt b/src/components/transport_manager/test/CMakeLists.txt index 489b35b796..f6e1212b36 100644 --- a/src/components/transport_manager/test/CMakeLists.txt +++ b/src/components/transport_manager/test/CMakeLists.txt @@ -49,6 +49,7 @@ set(EXCLUDE_PATHS if (NOT BUILD_CLOUD_APP_SUPPORT) list(APPEND EXCLUDE_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/websocket_connection_test.cc + ${CMAKE_CURRENT_SOURCE_DIR}/sample_websocket_server.cc ) endif() diff --git a/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h b/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h index 86c776bffb..141fa1ff89 100644 --- a/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h +++ b/src/components/transport_manager/test/include/transport_manager/cloud/sample_websocket_server.h @@ -54,6 +54,9 @@ #include <thread> #include <vector> +namespace sample { +namespace websocket { + namespace beast = boost::beast; // from <boost/beast.hpp> namespace http = beast::http; // from <boost/beast/http.hpp> namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp> @@ -61,34 +64,14 @@ namespace net = boost::asio; // from <boost/asio.hpp> namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp> using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> -//------------------------------------------------------------------------------ - -// Report a failure -void Fail(char const* tag, boost::system::error_code ec) { - std::cerr << tag << ": " << ec.message() << "\n"; -} - // Accepts incoming connections and launches the WSServer class WSSession : public std::enable_shared_from_this<WSSession> { private: class WSServer : public std::enable_shared_from_this<WSServer> { public: - explicit WSServer(tcp::socket&& socket) - : ws_(std::move(socket)), strand_(ws_.get_executor()) {} - - void Run() { - // Accept the websocket handshake - ws_.async_accept(boost::asio::bind_executor( - strand_, - std::bind( - &WSServer::OnAccept, shared_from_this(), std::placeholders::_1))); - } - - void OnAccept(beast::error_code ec) { - if (ec) { - return Fail("ERROR_CONNECTION_ACCEPT", ec); - } - } + explicit WSServer(tcp::socket&& socket); + void Run(); + void OnAccept(beast::error_code ec); private: websocket::stream<tcp::socket> ws_; @@ -97,71 +80,12 @@ class WSSession : public std::enable_shared_from_this<WSSession> { }; public: - WSSession(const std::string& address, uint16_t port) - : address_(address), port_(port), acceptor_(ioc_), socket_(ioc_) { - endpoint_ = {boost::asio::ip::make_address(address), port}; - boost::system::error_code error; - - // Open the acceptor - acceptor_.open(endpoint_.protocol(), error); - if (error) { - Fail("ERROR_ACCEPTOR_OPEN", error); - return; - } - - // Allow address reuse - acceptor_.set_option(boost::asio::socket_base::reuse_address(true), error); - if (error) { - Fail("ERROR_SET_OPTION", error); - return; - } - - // Bind to the server address - acceptor_.bind(endpoint_, error); - if (error) { - Fail("ERROR_BIND", error); - return; - } - - // Start listening for connections - acceptor_.listen(boost::asio::socket_base::max_listen_connections, error); - if (error) { - Fail("ERROR_LISTEN", error); - return; - } - } - - void Run() { - if (acceptor_.is_open()) { - acceptor_.async_accept( - socket_, - std::bind(&WSSession::on_accept, this, std::placeholders::_1)); - ioc_.run(); - } - } - - void Stop() { - try { - ioc_.stop(); - acceptor_.close(); - } catch (...) { - std::cerr << "Failed to close connection" << std::endl; - } - } + WSSession(const std::string& address, uint16_t port); + void Run(); + void Stop(); private: - void on_accept(boost::system::error_code ec) { - if (ec) { - Fail("ERROR_ON_ACCEPT", ec); - ioc_.stop(); - return; - } - - // Make websocket object and start - ws_ = std::make_shared<WSServer>(std::move(socket_)); - ws_->Run(); - } - + void on_accept(boost::system::error_code ec); boost::asio::io_context ioc_; const std::string& address_; uint16_t port_; @@ -175,37 +99,14 @@ class WSSession : public std::enable_shared_from_this<WSSession> { // Accepts incoming connections and launches the sessions class WSSSession : public std::enable_shared_from_this<WSSSession> { private: - // Echoes back all received WebSocket messages class WSSServer : public std::enable_shared_from_this<WSSServer> { public: // Take ownership of the socket - WSSServer(tcp::socket&& socket, ssl::context& ctx) - : wss_(std::move(socket), ctx) {} - + WSSServer(tcp::socket&& socket, ssl::context& ctx); // Start the asynchronous operation - void Run() { - // Perform the SSL handshake - wss_.next_layer().async_handshake(ssl::stream_base::server, - std::bind(&WSSServer::OnSSLHandshake, - shared_from_this(), - std::placeholders::_1)); - } - - void OnSSLHandshake(beast::error_code ec) { - if (ec) { - return Fail("ERROR_SSL_HANDSHAKE", ec); - } - - // Accept the websocket handshake - wss_.async_accept(std::bind( - &WSSServer::OnAccept, shared_from_this(), std::placeholders::_1)); - } - - void OnAccept(beast::error_code ec) { - if (ec) { - return Fail("ERROR_ON_ACCEPT", ec); - } - } + void Run(); + void OnSSLHandshake(beast::error_code ec); + void OnAccept(beast::error_code ec); private: websocket::stream<ssl::stream<tcp::socket> > wss_; @@ -216,95 +117,14 @@ class WSSSession : public std::enable_shared_from_this<WSSSession> { WSSSession(const std::string& address, uint16_t port, const std::string& certificate, - const std::string& private_key) - : acceptor_(ioc_), socket_(ioc_), ctx_(ssl::context::sslv23_server) { - beast::error_code ec; - endpoint_ = {boost::asio::ip::make_address(address), port}; - - // Load the certificate - ctx_.use_certificate( - boost::asio::buffer(certificate.c_str(), certificate.size()), - ssl::context::file_format::pem, - ec); - if (ec) { - Fail("ERROR_USE_CERTIFICATE", ec); - return; - } - - // Load the private key - ctx_.use_rsa_private_key( - boost::asio::buffer(private_key.c_str(), private_key.size()), - ssl::context::file_format::pem, - ec); - if (ec) { - Fail("ERROR_USE_RSA_PRIVATE_KEY", ec); - return; - } - - // Open the acceptor - acceptor_.open(endpoint_.protocol(), ec); - if (ec) { - Fail("EEROR_ACCEPTOR_OPEN", ec); - return; - } - - // Allow address reuse - acceptor_.set_option(net::socket_base::reuse_address(true), ec); - if (ec) { - Fail("ERROR_SET_OPTION", ec); - return; - } - - // Bind to the server address - acceptor_.bind(endpoint_, ec); - if (ec) { - Fail("ERROR_BIND", ec); - return; - } - - // Start listening for connections - acceptor_.listen(net::socket_base::max_listen_connections, ec); - if (ec) { - Fail("ERROR_LISTEN", ec); - return; - } - } - + const std::string& private_key); // Start accepting incoming connections - void Run() { - do_accept(); - } - - void Stop() { - try { - ioc_.stop(); - acceptor_.close(); - } catch (...) { - std::cerr << "Failed to close connection" << std::endl; - } - } + void Run(); + void Stop(); private: - void do_accept() { - if (acceptor_.is_open()) { - acceptor_.async_accept(socket_, - std::bind(&WSSSession::on_accept, - shared_from_this(), - std::placeholders::_1)); - ioc_.run(); - } - } - - void on_accept(boost::system::error_code ec) { - if (ec) { - Fail("ERROR_ON_ACCEPT", ec); - ioc_.stop(); - return; - } - // Create the session and run it - wss_ = std::make_shared<WSSServer>(std::move(socket_), ctx_); - wss_->Run(); - } + void do_accept(); + void on_accept(boost::system::error_code ec); private: boost::asio::io_context ioc_; @@ -315,4 +135,7 @@ class WSSSession : public std::enable_shared_from_this<WSSSession> { std::shared_ptr<WSSServer> wss_; }; +} // namespace websocket +} // namespace sample + #endif // SRC_COMPONENTS_TRANSPORT_MANAGER_TEST_INCLUDE_TRANSPORT_MANAGER_CLOUD_SAMPLE_WEBSOCKET_SERVER_H_
\ No newline at end of file diff --git a/src/components/transport_manager/test/sample_websocket_server.cc b/src/components/transport_manager/test/sample_websocket_server.cc new file mode 100644 index 0000000000..ae15d46b62 --- /dev/null +++ b/src/components/transport_manager/test/sample_websocket_server.cc @@ -0,0 +1,213 @@ +#include "transport_manager/cloud/sample_websocket_server.h" + +namespace { +// Report a failure +void Fail(char const* tag, boost::system::error_code ec) { + std::cerr << tag << ": " << ec.message() << "\n"; +} +} // namespace + +namespace sample { +namespace websocket { + +WSSession::WSServer::WSServer(tcp::socket&& socket) + : ws_(std::move(socket)), strand_(ws_.get_executor()) {} + +void WSSession::WSServer::Run() { + // Accept the websocket handshake + ws_.async_accept(boost::asio::bind_executor( + strand_, + std::bind( + &WSServer::OnAccept, shared_from_this(), std::placeholders::_1))); +} + +void WSSession::WSServer::OnAccept(beast::error_code ec) { + if (ec) { + return Fail("ERROR_CONNECTION_ACCEPT", ec); + } +} + +WSSession::WSSession(const std::string& address, uint16_t port) + : address_(address), port_(port), acceptor_(ioc_), socket_(ioc_) { + endpoint_ = {boost::asio::ip::make_address(address), port}; + boost::system::error_code error; + + // Open the acceptor + acceptor_.open(endpoint_.protocol(), error); + if (error) { + Fail("ERROR_ACCEPTOR_OPEN", error); + return; + } + + // Allow address reuse + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), error); + if (error) { + Fail("ERROR_SET_OPTION", error); + return; + } + + // Bind to the server address + acceptor_.bind(endpoint_, error); + if (error) { + Fail("ERROR_BIND", error); + return; + } + + // Start listening for connections + acceptor_.listen(boost::asio::socket_base::max_listen_connections, error); + if (error) { + Fail("ERROR_LISTEN", error); + return; + } +} + +void WSSession::Run() { + if (acceptor_.is_open()) { + acceptor_.async_accept( + socket_, std::bind(&WSSession::on_accept, this, std::placeholders::_1)); + ioc_.run(); + } +} + +void WSSession::Stop() { + try { + ioc_.stop(); + acceptor_.close(); + } catch (...) { + std::cerr << "Failed to close connection" << std::endl; + } +} + +void WSSession::on_accept(boost::system::error_code ec) { + if (ec) { + Fail("ERROR_ON_ACCEPT", ec); + ioc_.stop(); + return; + } + + // Make websocket object and start + ws_ = std::make_shared<WSServer>(std::move(socket_)); + ws_->Run(); +} + +WSSSession::WSSServer::WSSServer(tcp::socket&& socket, ssl::context& ctx) + : wss_(std::move(socket), ctx) {} + +void WSSSession::WSSServer::Run() { + // Perform the SSL handshake + wss_.next_layer().async_handshake(ssl::stream_base::server, + std::bind(&WSSServer::OnSSLHandshake, + shared_from_this(), + std::placeholders::_1)); +} + +void WSSSession::WSSServer::OnSSLHandshake(beast::error_code ec) { + if (ec) { + return Fail("ERROR_SSL_HANDSHAKE", ec); + } + + // Accept the websocket handshake + wss_.async_accept(std::bind( + &WSSServer::OnAccept, shared_from_this(), std::placeholders::_1)); +} + +void WSSSession::WSSServer::OnAccept(beast::error_code ec) { + if (ec) { + return Fail("ERROR_ON_ACCEPT", ec); + } +} + +WSSSession::WSSSession(const std::string& address, + uint16_t port, + const std::string& certificate, + const std::string& private_key) + : acceptor_(ioc_), socket_(ioc_), ctx_(ssl::context::sslv23_server) { + beast::error_code ec; + endpoint_ = {boost::asio::ip::make_address(address), port}; + + // Load the certificate + ctx_.use_certificate( + boost::asio::buffer(certificate.c_str(), certificate.size()), + ssl::context::file_format::pem, + ec); + if (ec) { + Fail("ERROR_USE_CERTIFICATE", ec); + return; + } + + // Load the private key + ctx_.use_rsa_private_key( + boost::asio::buffer(private_key.c_str(), private_key.size()), + ssl::context::file_format::pem, + ec); + if (ec) { + Fail("ERROR_USE_RSA_PRIVATE_KEY", ec); + return; + } + + // Open the acceptor + acceptor_.open(endpoint_.protocol(), ec); + if (ec) { + Fail("EEROR_ACCEPTOR_OPEN", ec); + return; + } + + // Allow address reuse + acceptor_.set_option(net::socket_base::reuse_address(true), ec); + if (ec) { + Fail("ERROR_SET_OPTION", ec); + return; + } + + // Bind to the server address + acceptor_.bind(endpoint_, ec); + if (ec) { + Fail("ERROR_BIND", ec); + return; + } + + // Start listening for connections + acceptor_.listen(net::socket_base::max_listen_connections, ec); + if (ec) { + Fail("ERROR_LISTEN", ec); + return; + } +} + +// Start accepting incoming connections +void WSSSession::Run() { + do_accept(); +} + +void WSSSession::Stop() { + try { + ioc_.stop(); + acceptor_.close(); + } catch (...) { + std::cerr << "Failed to close connection" << std::endl; + } +} + +void WSSSession::do_accept() { + if (acceptor_.is_open()) { + acceptor_.async_accept( + socket_, + std::bind( + &WSSSession::on_accept, shared_from_this(), std::placeholders::_1)); + ioc_.run(); + } +} + +void WSSSession::on_accept(boost::system::error_code ec) { + if (ec) { + Fail("ERROR_ON_ACCEPT", ec); + ioc_.stop(); + return; + } + // Create the session and run it + wss_ = std::make_shared<WSSServer>(std::move(socket_), ctx_); + wss_->Run(); +} + +} // namespace websocket +} // namespace sample
\ No newline at end of file diff --git a/src/components/transport_manager/test/websocket_connection_test.cc b/src/components/transport_manager/test/websocket_connection_test.cc index 774b477795..2b458a7427 100644 --- a/src/components/transport_manager/test/websocket_connection_test.cc +++ b/src/components/transport_manager/test/websocket_connection_test.cc @@ -49,6 +49,7 @@ using ::testing::NiceMock; using ::testing::Return; using namespace ::transport_manager; using namespace ::transport_manager::transport_adapter; +namespace websocket = sample::websocket; class WebsocketConnectionTest : public ::testing::Test { public: @@ -84,13 +85,13 @@ class WebsocketConnectionTest : public ::testing::Test { } void StartWSServer() { - ws_session = std::make_shared<WSSession>(kHost, kPort); + ws_session = std::make_shared<websocket::WSSession>(kHost, kPort); ws_session->Run(); } void StartWSSServer() { - wss_session = - std::make_shared<WSSSession>(kHost, kPort, kCertificate, kPrivateKey); + wss_session = std::make_shared<websocket::WSSSession>( + kHost, kPort, kCertificate, kPrivateKey); wss_session->Run(); } @@ -111,8 +112,8 @@ class WebsocketConnectionTest : public ::testing::Test { std::string dev_id; std::string uniq_id; int app_handle; - std::shared_ptr<WSSession> ws_session; - std::shared_ptr<WSSSession> wss_session; + std::shared_ptr<websocket::WSSession> ws_session; + std::shared_ptr<websocket::WSSSession> wss_session; std::string kHost = "127.0.0.1"; uint16_t kPort = 8080; // Sample certificate for localhost |