From 052abf06adc003b0de29ddb4ee2e121b6eb70ac5 Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Mon, 7 Jan 2013 12:22:16 -0600 Subject: [PATCH] Updates asio socket components to new styles --- websocketpp/transport/asio/security/base.hpp | 43 +++-- websocketpp/transport/asio/security/none.hpp | 132 +++++++++++-- websocketpp/transport/asio/security/tls.hpp | 185 ++++++++++++++++--- 3 files changed, 308 insertions(+), 52 deletions(-) diff --git a/websocketpp/transport/asio/security/base.hpp b/websocketpp/transport/asio/security/base.hpp index 299aac4ac3..1e094d1b58 100644 --- a/websocketpp/transport/asio/security/base.hpp +++ b/websocketpp/transport/asio/security/base.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Peter Thorson. All rights reserved. + * Copyright (c) 2013, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,8 +25,8 @@ * */ -#ifndef WEBSOCKETPP_TRANSPORT_SECURITY_BASE_HPP -#define WEBSOCKETPP_TRANSPORT_SECURITY_BASE_HPP +#ifndef WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP +#define WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP #include #include @@ -41,10 +41,11 @@ namespace websocketpp { namespace transport { -namespace security { +namespace asio { +namespace socket { /** - * The transport::security::* classes are a set of security/socket related + * The transport::asio::socket::* classes are a set of security/socket related * policies and support code for the ASIO transport types. */ @@ -53,7 +54,11 @@ namespace error { /// Catch-all error for security policy errors that don't fit in other /// categories security = 1, - + + /// Catch-all error for socket component errors that don't fit in other + /// categories + socket, + /// A function was called in a state that it was illegal to do so. invalid_state, @@ -65,20 +70,25 @@ namespace error { tls_handshake_timeout, /// pass_through from underlying library - pass_through + pass_through, + + /// Required tls_init handler not present + missing_tls_init_handler }; } // namespace error -class security_category : public lib::error_category { +class socket_category : public lib::error_category { public: const char *name() const _WEBSOCKETPP_NOEXCEPT_TOKEN_ { - return "websocketpp.transport.asio.security"; + return "websocketpp.transport.asio.socket"; } std::string message(int value) const { switch(value) { case error::security: return "Security policy error"; + case error::socket: + return "Socket component error"; case error::invalid_state: return "Invalid state"; case error::invalid_tls_context: @@ -87,27 +97,28 @@ public: return "TLS handshake timed out"; case error::pass_through: return "Pass through from underlying library"; + case error::missing_tls_init_handler: + return "Required tls_init handler not present."; default: return "Unknown"; } } }; -const lib::error_category& get_security_category() { - static security_category instance; +const lib::error_category& get_socket_category() { + static socket_category instance; return instance; } -//static const security_category error_category; - lib::error_code make_error(error::value e) { - return lib::error_code(static_cast(e), get_security_category()); + return lib::error_code(static_cast(e), get_socket_category()); } typedef lib::function init_handler; -} // namespace security +} // namespace socket +} // namespace asio } // namespace transport } // namespace websocketpp -#endif // WEBSOCKETPP_TRANSPORT_SECURITY_BASE_HPP +#endif // WEBSOCKETPP_TRANSPORT_ASIO_SOCKET_BASE_HPP diff --git a/websocketpp/transport/asio/security/none.hpp b/websocketpp/transport/asio/security/none.hpp index 72010a8ad7..c53ddf29f0 100644 --- a/websocketpp/transport/asio/security/none.hpp +++ b/websocketpp/transport/asio/security/none.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Peter Thorson. All rights reserved. + * Copyright (c) 2013, Peter Thorson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,13 +37,30 @@ namespace websocketpp { namespace transport { -namespace security { +namespace asio { +namespace basic_socket { -class none { +typedef lib::function + socket_init_handler; + +/// Basic Boost ASIO connection socket component +/** + * transport::asio::basic_socket::connection impliments a connection socket + * component using Boost ASIO ip::tcp::socket. + */ +class connection { public: - typedef lib::shared_ptr socket_ptr; + /// Type of this connection socket component + typedef connection type; + /// Type of a shared pointer to this connection socket component + typedef lib::shared_ptr ptr; + + /// Type of a pointer to the ASIO io_service being used typedef boost::asio::io_service* io_service_ptr; + /// Type of a shared pointer to the socket being used. + typedef lib::shared_ptr socket_ptr; + // TODO: clean up these types class handler_interface { public: virtual void on_socket_init(boost::asio::ip::tcp::socket& socket) {}; @@ -51,15 +68,31 @@ public: typedef lib::shared_ptr handler_ptr; - explicit none() : m_state(UNINITIALIZED) - { - std::cout << "transport::security::none constructor" << std::endl; + explicit connection() : m_state(UNINITIALIZED) { + std::cout << "transport::asio::basic_socket::connection constructor" + << std::endl; } + /// Check whether or not this connection is secure + /** + * @return Wether or not this connection is secure + */ bool is_secure() const { return false; } + /// Set the socket initialization handler + /** + * The socket initialization handler is called after the socket object is + * created but before it is used. This gives the application a chance to + * set any ASIO socket options it needs. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + /// Retrieve a pointer to the underlying socket /** * This is used internally. It can also be used to set socket options, etc @@ -87,7 +120,7 @@ protected: */ lib::error_code init_asio (io_service_ptr service, bool is_server) { if (m_state != UNINITIALIZED) { - return make_error(error::invalid_state); + return socket::make_error(socket::error::invalid_state); } m_socket.reset(new boost::asio::ip::tcp::socket(*service)); @@ -100,11 +133,13 @@ protected: /// Initialize security policy for reading void init(init_handler callback) { if (m_state != READY) { - callback(make_error(error::invalid_state)); + callback(socket::make_error(socket::error::invalid_state)); return; } - m_handler->on_socket_init(*m_socket); + if (m_socket_init_handler) { + m_socket_init_handler(m_hdl,*m_socket); + } m_state = READING; @@ -114,6 +149,17 @@ protected: void set_handler(handler_ptr new_handler) { m_handler = new_handler; } + + /// Sets the connection handle + /** + * The connection handle is passed to any handlers to identify the + * connection + * + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) { + m_hdl = hdl; + } void shutdown() { boost::system::error_code ec; @@ -128,12 +174,70 @@ private: READING = 2 }; - socket_ptr m_socket; - state m_state; - handler_ptr m_handler; + socket_ptr m_socket; + state m_state; + handler_ptr m_handler; + + connection_hdl m_hdl; + socket_init_handler m_socket_init_handler; }; -} // namespace security +/// Basic ASIO endpoint socket component +/** + * transport::asio::basic_socket::endpoint impliments an endpoint socket + * component that uses Boost ASIO's ip::tcp::socket. + */ +class endpoint { +public: + /// The type of this endpoint socket component + typedef endpoint type; + + /// The type of the corresponding connection socket component + typedef connection socket_con_type; + /// The type of a shared pointer to the corresponding connection socket + /// component. + typedef typename socket_con_type::ptr socket_con_ptr; + + explicit endpoint() { + std::cout << "transport::asio::basic_socket::endpoint constructor" + << std::endl; + } + + /// Checks whether the endpoint creates secure connections + /** + * @return Wether or not the endpoint creates secure connections + */ + bool is_secure() const { + return false; + } + + /// Set socket init handler + /** + * The socket init handler is called after a connection's socket is created + * but before it is used. This gives the end application an opportunity to + * set asio socket specific parameters. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + +protected: + /// Initialize a connection + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. + */ + void init(socket_con_ptr scon) { + scon->set_socket_init_handler(m_socket_init_handler); + } +private: + socket_init_handler m_socket_init_handler; +}; + +} // namespace basic_socket +} // namespace asio } // namespace transport } // namespace websocketpp diff --git a/websocketpp/transport/asio/security/tls.hpp b/websocketpp/transport/asio/security/tls.hpp index 29735cefe2..621c751c7e 100644 --- a/websocketpp/transport/asio/security/tls.hpp +++ b/websocketpp/transport/asio/security/tls.hpp @@ -29,6 +29,9 @@ #define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP #include +#include +#include +#include #include #include @@ -39,16 +42,35 @@ namespace websocketpp { namespace transport { -namespace security { +namespace asio { +namespace tls_socket { -class tls { +typedef lib::function::lowest_layer_type&)> socket_init_handler; +typedef lib::function(connection_hdl)> + tls_init_handler; + +/// TLS enabled Boost ASIO connection socket component +/** + * transport::asio::tls_socket::connection impliments a secure connection socket + * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. + */ +class connection { public: - typedef tls type; - + /// Type of this connection socket component + typedef connection type; + /// Type of a shared pointer to this connection socket component + typedef lib::shared_ptr ptr; + + /// Type of the ASIO socket being used typedef boost::asio::ssl::stream socket_type; - typedef boost::asio::io_service* io_service_ptr; + /// Type of a shared pointer to the ASIO socket being used typedef lib::shared_ptr socket_ptr; + /// Type of a pointer to the ASIO io_service being used + typedef boost::asio::io_service* io_service_ptr; + /// Type of a shared pointer to the ASIO TLS context being used typedef lib::shared_ptr context_ptr; + /// Type of a shared pointer to the ASIO timer being used typedef lib::shared_ptr timer_ptr; typedef boost::system::error_code boost_error; @@ -62,11 +84,15 @@ public: typedef lib::shared_ptr handler_ptr; - explicit tls() - { - std::cout << "transport::security::tls constructor" << std::endl; + explicit connection() { + std::cout << "transport::asio::tls_socket::connection constructor" + << std::endl; } + /// Check whether or not this connection is secure + /** + * @return Wether or not this connection is secure + */ bool is_secure() const { return true; } @@ -86,6 +112,31 @@ public: socket_type& get_socket() { return *m_socket; } + + /// Set the socket initialization handler + /** + * The socket initialization handler is called after the socket object is + * created but before it is used. This gives the application a chance to + * set any ASIO socket options it needs. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + + /// Set TLS init handler + /** + * The tls init handler is called when needed to request a TLS context for + * the library to use. A TLS init handler must be set and it must return a + * valid TLS context in order for this endpoint to be able to initialize + * TLS connections + * + * @param h The new tls_init_handler + */ + void set_tls_init_handler(tls_init_handler h) { + m_tls_init_handler = h; + } protected: /// Perform one time initializations /** @@ -97,10 +148,13 @@ protected: * @param is_server Whether or not the endpoint is a server or not. */ lib::error_code init_asio (io_service_ptr service, bool is_server) { - m_context = m_handler->on_tls_init(); + if (!m_tls_init_handler) { + return socket::make_error(socket::error::missing_tls_init_handler); + } + m_context = m_tls_init_handler(m_hdl); if (!m_context) { - return make_error(error::invalid_tls_context); + return socket::make_error(socket::error::invalid_tls_context); } m_socket.reset(new socket_type(*service,*m_context)); @@ -118,8 +172,10 @@ protected: /// Initialize security policy for reading void init(init_handler callback) { - m_handler->on_socket_init(get_raw_socket()); - + if (m_socket_init_handler) { + m_socket_init_handler(m_hdl,get_raw_socket()); + } + // register timeout m_timer->expires_from_now(boost::posix_time::milliseconds(5000)); // TEMP @@ -144,6 +200,17 @@ protected: ); } + /// Sets the connection handle + /** + * The connection handle is passed to any handlers to identify the + * connection + * + * @param hdl The new handle + */ + void set_handle(connection_hdl hdl) { + m_hdl = hdl; + } + void handle_timeout(init_handler callback, const boost::system::error_code& error) { @@ -155,11 +222,11 @@ protected: // Some other ASIO error, pass it through // TODO: make this error pass through better - callback(make_error(error::pass_through)); + callback(socket::make_error(socket::error::pass_through)); return; } - callback(make_error(error::tls_handshake_timeout)); + callback(socket::make_error(socket::error::tls_handshake_timeout)); } void handle_init(init_handler callback, const @@ -170,7 +237,7 @@ protected: if (error) { // TODO: make this error pass through better - callback(make_error(error::pass_through)); + callback(socket::make_error(socket::error::pass_through)); return; } @@ -196,15 +263,89 @@ private: } } - io_service_ptr m_io_service; - context_ptr m_context; - socket_ptr m_socket; - timer_ptr m_timer; - bool m_is_server; - handler_ptr m_handler; + io_service_ptr m_io_service; + context_ptr m_context; + socket_ptr m_socket; + timer_ptr m_timer; + bool m_is_server; + handler_ptr m_handler; + + connection_hdl m_hdl; + socket_init_handler m_socket_init_handler; + tls_init_handler m_tls_init_handler; }; -} // namespace security +/// TLS enabled Boost ASIO endpoint socket component +/** + * transport::asio::tls_socket::endpoint impliments a secure endpoint socket + * component that uses Boost ASIO's ssl::stream to wrap an ip::tcp::socket. + */ +class endpoint { +public: + /// The type of this endpoint socket component + typedef endpoint type; + + /// The type of the corresponding connection socket component + typedef connection socket_con_type; + /// The type of a shared pointer to the corresponding connection socket + /// component. + typedef typename socket_con_type::ptr socket_con_ptr; + + explicit endpoint() { + std::cout << "transport::asio::tls_socket::endpoint constructor" + << std::endl; + } + + /// Checks whether the endpoint creates secure connections + /** + * @return Wether or not the endpoint creates secure connections + */ + bool is_secure() const { + return true; + } + + /// Set socket init handler + /** + * The socket init handler is called after a connection's socket is created + * but before it is used. This gives the end application an opportunity to + * set asio socket specific parameters. + * + * @param h The new socket_init_handler + */ + void set_socket_init_handler(socket_init_handler h) { + m_socket_init_handler = h; + } + + /// Set TLS init handler + /** + * The tls init handler is called when needed to request a TLS context for + * the library to use. A TLS init handler must be set and it must return a + * valid TLS context in order for this endpoint to be able to initialize + * TLS connections + * + * @param h The new tls_init_handler + */ + void set_tls_init_handler(tls_init_handler h) { + m_tls_init_handler = h; + } +protected: + /// Initialize a connection + /** + * Called by the transport after a new connection is created to initialize + * the socket component of the connection. + */ + void init(socket_con_ptr scon) { + scon->set_socket_init_handler(m_socket_init_handler); + scon->set_tls_init_handler(m_tls_init_handler); + } + +private: + socket_init_handler m_socket_init_handler; + tls_init_handler m_tls_init_handler; +}; + +} // namespace tls_socket +} // namespace asio } // namespace transport } // namespace websocketpp