From 9f64ad8d89b13a12b3c28f4e61518d3df14a3cb9 Mon Sep 17 00:00:00 2001 From: Tom Ritchford Date: Mon, 2 Feb 2015 19:31:32 -0500 Subject: [PATCH] Add WebSocket 04 interface. * New WebSocket04 traits class implements strategies. * New "websocket_version" configuration setting selects between 0.2 and 0.4. --- Builds/VisualStudio2013/RippleD.vcxproj | 137 ++++++++- .../VisualStudio2013/RippleD.vcxproj.filters | 266 +++++++++++++++++- SConstruct | 7 +- src/ripple/app/main/Application.cpp | 2 +- .../unity/{websocket.cpp => websocket02.cpp} | 0 src/ripple/unity/websocket04.cpp | 29 ++ src/ripple/websocket/Config04.h | 74 +++++ src/ripple/websocket/MakeServer.cpp | 12 +- src/ripple/websocket/MakeServer.h | 3 + src/ripple/websocket/Server.h | 4 +- src/ripple/websocket/WebSocket04.cpp | 152 ++++++++++ src/ripple/websocket/WebSocket04.h | 106 +++++++ 12 files changed, 782 insertions(+), 10 deletions(-) rename src/ripple/unity/{websocket.cpp => websocket02.cpp} (100%) create mode 100644 src/ripple/unity/websocket04.cpp create mode 100644 src/ripple/websocket/Config04.h create mode 100644 src/ripple/websocket/WebSocket04.cpp create mode 100644 src/ripple/websocket/WebSocket04.h diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 1da6538a3c..d19d7a9755 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -3460,7 +3460,11 @@ - + + + + ..\..\src\websocketpp;%(AdditionalIncludeDirectories) + ..\..\src\websocketpp;%(AdditionalIncludeDirectories) @@ -3495,10 +3499,14 @@ + + + + True @@ -3516,6 +3524,11 @@ + + True + + + True @@ -4123,6 +4136,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 6a63e49557..0717201e16 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -535,6 +535,72 @@ {575659AE-C11F-C7F6-CEA1-3F2FBB560918} + + {EE7AC8C9-27EB-C05E-C986-EECB0174B997} + + + {82EA1B18-1B3C-A058-A29E-551E0E3BDA99} + + + {29A5E69F-AA78-79AB-F509-A1A1EFBE725A} + + + {5A5A5554-4F81-E30A-5762-36685DB6B830} + + + {07669BB9-CC76-88EA-A896-DB6DDDEC5775} + + + {B025F0D4-8F1C-603C-7CB9-2811262B7D34} + + + {59B59211-4F8B-987B-68C9-C1DF65402F54} + + + {C4D65117-C601-4C4A-28C8-A2C6335827A4} + + + {1E03BC08-90C7-A797-7110-F73E444EC993} + + + {7941142B-9703-B8C4-5A99-DAC5E77AECBD} + + + {54043FA6-EB94-D644-DFB4-BFBC1E08AA88} + + + {11160D17-D0E6-A183-A6FA-B456917DF5BA} + + + {62EC8D39-1586-9F85-3B81-9C8A38F9397C} + + + {F631E25B-C7E3-C49F-CC36-8B6A4139B913} + + + {35BD193C-5B38-B7D6-A741-F1AF2040BF79} + + + {2743C174-DF30-DFAE-07AA-87B2463B627A} + + + {13533400-6F24-4CB2-D7C1-2B60F50CB4D8} + + + {07010CA1-64FF-FF0E-8A88-42E38AA0D2C6} + + + {1AEC5C0F-E62A-57D6-AE10-5A10DCF0D7B9} + + + {E65629D4-E694-40E7-9D58-94BFA058BF4C} + + + {1F7DCF89-909D-C1BD-AC32-CD1B77BE213B} + + + {82587170-78E0-AB92-82E6-5EDBA57322E4} + {96CE200F-2670-323E-3B37-B90DBC0EDA11} @@ -4173,7 +4239,10 @@ ripple\unity - + + ripple\unity + + ripple\unity @@ -4218,12 +4287,18 @@ ripple\websocket + + ripple\websocket + ripple\websocket ripple\websocket + + ripple\websocket + ripple\websocket @@ -4245,6 +4320,12 @@ ripple\websocket + + ripple\websocket + + + ripple\websocket + rocksdb2\db @@ -4995,6 +5076,189 @@ snappy\snappy + + websocketpp\websocketpp\base64 + + + websocketpp\websocketpp + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\common + + + websocketpp\websocketpp\concurrency + + + websocketpp\websocketpp\config + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp\extensions + + + websocketpp\websocketpp\extensions\permessage_deflate + + + websocketpp\websocketpp + + + websocketpp\websocketpp\http + + + websocketpp\websocketpp\http\impl + + + websocketpp\websocketpp\http\impl + + + websocketpp\websocketpp\http\impl + + + websocketpp\websocketpp\http + + + websocketpp\websocketpp\http + + + websocketpp\websocketpp\http + + + websocketpp\websocketpp\impl + + + websocketpp\websocketpp\impl + + + websocketpp\websocketpp\impl + + + websocketpp\websocketpp\logger + + + websocketpp\websocketpp\logger + + + websocketpp\websocketpp\message_buffer + + + websocketpp\websocketpp\message_buffer + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\processors + + + websocketpp\websocketpp\random + + + websocketpp\websocketpp\roles + + + websocketpp\websocketpp + + + websocketpp\websocketpp\sha1 + + + websocketpp\websocketpp\transport\asio + + + websocketpp\websocketpp\transport\asio + + + websocketpp\websocketpp\transport\asio + + + websocketpp\websocketpp\transport\asio\security + + + websocketpp\websocketpp\transport\asio\security + + + websocketpp\websocketpp\transport\base + + + websocketpp\websocketpp\transport\base + + + websocketpp\websocketpp\transport\iostream + + + websocketpp\websocketpp\transport\iostream + + + websocketpp\websocketpp\transport\iostream + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp + + + websocketpp\websocketpp + websocketpp_02\src\base64 diff --git a/SConstruct b/SConstruct index f088e6eb63..ce3586ac05 100644 --- a/SConstruct +++ b/SConstruct @@ -673,7 +673,7 @@ for tu_style in ['classic', 'unity']: 'src/ripple/unity/rpcx.cpp', 'src/ripple/unity/server.cpp', 'src/ripple/unity/validators.cpp', - 'src/ripple/unity/websocket.cpp' + 'src/ripple/unity/websocket02.cpp' ) object_builder.add_source_files( @@ -712,6 +712,11 @@ for tu_style in ['classic', 'unity']: ] ) + object_builder.add_source_files( + 'src/ripple/unity/websocket04.cpp', + CPPPATH='src/websocketpp', + ) + if toolchain == "clang" and Beast.system.osx: object_builder.add_source_files('src/ripple/unity/beastobjc.mm') diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index f401c4747d..0d28efbd8d 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -810,7 +810,7 @@ public: if (! port.websockets()) continue; auto server = websocket::makeServer ( - {port, *m_resourceManager, getOPs(), m_journal, + {port, *m_resourceManager, getOPs(), m_journal, getConfig(), *m_collectorManager}); if (!server) { diff --git a/src/ripple/unity/websocket.cpp b/src/ripple/unity/websocket02.cpp similarity index 100% rename from src/ripple/unity/websocket.cpp rename to src/ripple/unity/websocket02.cpp diff --git a/src/ripple/unity/websocket04.cpp b/src/ripple/unity/websocket04.cpp new file mode 100644 index 0000000000..13764a19dd --- /dev/null +++ b/src/ripple/unity/websocket04.cpp @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +#ifdef _MSC_VER +# ifndef _WEBSOCKETPP_CONSTEXPR_TOKEN_ +# define _WEBSOCKETPP_CONSTEXPR_TOKEN_ +# endif +#endif +#define _WEBSOCKETPP_CPP11_STL_ + +#include diff --git a/src/ripple/websocket/Config04.h b/src/ripple/websocket/Config04.h new file mode 100644 index 0000000000..1ded954cbd --- /dev/null +++ b/src/ripple/websocket/Config04.h @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLED_RIPPLE_WEBSOCKET_CONFIG04_H +#define RIPPLED_RIPPLE_WEBSOCKET_CONFIG04_H + + +#include +#include + +#include +#include +#include + +namespace ripple { +namespace websocket { + +/** This is a config traits class, copied from + websocketpp/websocketpp/config/asio_no_tls.hpp*/ + +using ConfigBase04 = websocketpp::config::core; + +struct Config04 : ConfigBase04 { + typedef ConfigBase04 base; + typedef Config04 type; + typedef base::concurrency_type concurrency_type; + + typedef base::request_type request_type; + typedef base::response_type response_type; + + typedef base::message_type message_type; + typedef base::con_msg_manager_type con_msg_manager_type; + typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; + + typedef Logger alog_type; + typedef Logger elog_type; + + typedef base::rng_type rng_type; + + struct transport_config : public base::transport_config { + typedef type::concurrency_type concurrency_type; + typedef type::alog_type alog_type; + typedef type::elog_type elog_type; + typedef type::request_type request_type; + typedef type::response_type response_type; + // typedef AutoSocket + typedef websocketpp::transport::asio::basic_socket::endpoint + socket_type; + }; + + typedef websocketpp::transport::asio::endpoint + transport_type; +}; + +} // websocket +} // ripple + +#endif diff --git a/src/ripple/websocket/MakeServer.cpp b/src/ripple/websocket/MakeServer.cpp index 679503a42d..37ac73ca6b 100644 --- a/src/ripple/websocket/MakeServer.cpp +++ b/src/ripple/websocket/MakeServer.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include @@ -26,13 +27,16 @@ namespace websocket { std::unique_ptr makeServer (ServerDescription const& desc) { - static std::string const version = "0.2"; + auto version = get ( + desc.config["server"], "websocket_version"); + if (version.empty()) + version = WebSocket02::versionName(); + WriteLog (lsWARNING, WebSocket) << "Websocket version " << version; if (version == WebSocket02::versionName()) return makeServer02 (desc); - - assert (false); - return {}; + assert (version == "04"); + return makeServer04 (desc); } } // websocket diff --git a/src/ripple/websocket/MakeServer.h b/src/ripple/websocket/MakeServer.h index 062e7cd02b..9275f6807f 100644 --- a/src/ripple/websocket/MakeServer.h +++ b/src/ripple/websocket/MakeServer.h @@ -28,6 +28,8 @@ namespace beast { class Stoppable; } namespace ripple { +class BasicConfig; + namespace Resource { class Manager; } namespace websocket { @@ -38,6 +40,7 @@ struct ServerDescription Resource::Manager& resourceManager; InfoSub::Source& source; beast::Journal& journal; + BasicConfig const& config; CollectorManager& collectorManager; }; diff --git a/src/ripple/websocket/Server.h b/src/ripple/websocket/Server.h index 7af371328e..239a3acf2c 100644 --- a/src/ripple/websocket/Server.h +++ b/src/ripple/websocket/Server.h @@ -35,8 +35,8 @@ class Server { private: // TODO: why is this recursive? - using LockType = typename std::recursive_mutex; - using ScopedLockType = typename std::lock_guard ; + using LockType = std::recursive_mutex; + using ScopedLockType = std::lock_guard ; ServerDescription desc_; LockType m_endpointLock; diff --git a/src/ripple/websocket/WebSocket04.cpp b/src/ripple/websocket/WebSocket04.cpp new file mode 100644 index 0000000000..cce1b4b2f0 --- /dev/null +++ b/src/ripple/websocket/WebSocket04.cpp @@ -0,0 +1,152 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +#include + +namespace ripple { +namespace websocket { + +char const* WebSocket04::versionName() +{ + return "websocketpp 0.40"; +} + +void WebSocket04::handleDisconnect (Connection& connection) +{ + connection.close (websocketpp::close::status::protocol_error, + "overload"); +} + +void WebSocket04::closeTooSlowClient ( + Connection& connection, + unsigned int timeout, + std::string const& message) +{ + connection.close ( + websocketpp::close::status::value (timeout), message); +} + +bool WebSocket04::isTextMessage (Message const& message) +{ + return message.get_opcode () == websocketpp::frame::opcode::text; +} + +using HandlerPtr04 = WebSocket04::HandlerPtr; +using EndpointPtr04 = WebSocket04::EndpointPtr; + +HandlerPtr04 WebSocket04::makeHandler (ServerDescription const& desc) +{ + return std::make_shared > (desc); +} + +EndpointPtr04 WebSocket04::makeEndpoint (HandlerPtr&& handler) +{ + auto endpoint = std::make_shared (std::move (handler)); + + endpoint->set_open_handler ( + [endpoint] (websocketpp::connection_hdl hdl) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_open (conn); + }); + + endpoint->set_close_handler ( + [endpoint] (websocketpp::connection_hdl hdl) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_close (conn); + }); + + endpoint->set_fail_handler ( + [endpoint] (websocketpp::connection_hdl hdl) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_fail (conn); + }); + + endpoint->set_pong_handler ( + [endpoint] (websocketpp::connection_hdl hdl, std::string data) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_pong (conn, data); + }); + + endpoint->set_http_handler ( + [endpoint] (websocketpp::connection_hdl hdl) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->http (conn); + }); + + endpoint->set_message_handler ( + [endpoint] (websocketpp::connection_hdl hdl, + MessagePtr msg) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_message (conn, msg); + }); + + endpoint->set_send_empty_handler ( + [endpoint] (websocketpp::connection_hdl hdl) { + if (auto conn = endpoint->get_con_from_hdl(hdl)) + endpoint->handler()->on_send_empty (conn); + }); + + endpoint->init_asio(); + + return endpoint; +} + +template <> +void ConnectionImpl ::setPingTimer () +{ + if (auto con = m_connection.lock ()) + { + auto t = boost::posix_time::seconds (getConfig ().WEBSOCKET_PING_FREQ); + auto ms = t.total_milliseconds(); + con->set_timer ( + ms, + [this] (WebSocket04::ErrorCode const& e) + { + this->pingTimer (e); + }); + } +} + +boost::asio::io_service::strand& WebSocket04::getStrand (Connection& con) +{ + return *con.get_strand(); +} + +template <> +void Server ::listen() +{ + m_endpoint->listen (desc_.port.ip, desc_.port.port); + m_endpoint->start_accept(); + auto c = m_endpoint->get_io_service ().run (); + WriteLog (lsWARNING, WebSocket) + << "Server run with: '" << c; + +} + +std::unique_ptr makeServer04 (ServerDescription const& desc) +{ + return std::make_unique > (desc); +} + +} // websocket +} // ripple diff --git a/src/ripple/websocket/WebSocket04.h b/src/ripple/websocket/WebSocket04.h new file mode 100644 index 0000000000..e241d1dbab --- /dev/null +++ b/src/ripple/websocket/WebSocket04.h @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLED_RIPPLE_WEBSOCKET_WEBSOCKET04_H +#define RIPPLED_RIPPLE_WEBSOCKET_WEBSOCKET04_H + +#include +#include + +namespace ripple { +namespace websocket { + +struct WebSocket04 +{ + using EndpointBase = websocketpp::server ; + + using Connection = EndpointBase::connection_type; + using ConnectionPtr = std::shared_ptr; + using ConnectionWeakPtr = std::weak_ptr; + using ErrorCode = std::error_code; + using Message = Connection::message_type; + using MessagePtr = Message::ptr; + + class Handler + { + public: + virtual void on_open (ConnectionPtr) = 0; + virtual void on_close (ConnectionPtr) = 0; + virtual void on_fail (ConnectionPtr) = 0; + virtual void on_pong (ConnectionPtr, std::string data) = 0; + virtual bool http (ConnectionPtr) = 0; + virtual void on_message (ConnectionPtr, MessagePtr) = 0; + // This is a new method added by Ripple. + virtual void on_send_empty (ConnectionPtr) = 0; + }; + + using HandlerPtr = std::shared_ptr; + + class Endpoint : public EndpointBase + { + public: + using ptr = std::shared_ptr; + + Endpoint (HandlerPtr handler) : handler_ (handler) + { + } + + HandlerPtr const& handler() { return handler_; } + + private: + HandlerPtr handler_; + }; + + using EndpointPtr = std::shared_ptr; + /** The name of this WebSocket version. */ + static + char const* versionName(); + + /** Handle a connection that was cut off from the other side. */ + static + void handleDisconnect (Connection&); + + /** Close a client that is too slow to respond. */ + static + void closeTooSlowClient ( + Connection&, + unsigned int timeout, + std::string const& message = "Client is too slow."); + + /** Return true if the WebSocket message is a TEXT message. */ + static + bool isTextMessage (Message const&); + + /** Create a new Handler. */ + static + HandlerPtr makeHandler (ServerDescription const&); + + /** Make a connection endpoint from a handler. */ + static + EndpointPtr makeEndpoint (HandlerPtr&&); + + /** Get the ASIO strand that this connection lives on. */ + static + boost::asio::io_service::strand& getStrand (Connection&); +}; + +} // websocket +} // ripple + +#endif