Updates asio socket components to new styles

This commit is contained in:
Peter Thorson
2013-01-07 12:22:16 -06:00
parent e339e0f5c6
commit 052abf06ad
3 changed files with 308 additions and 52 deletions

View File

@@ -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 <websocketpp/common/memory.hpp>
#include <websocketpp/common/functional.hpp>
@@ -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<int>(e), get_security_category());
return lib::error_code(static_cast<int>(e), get_socket_category());
}
typedef lib::function<void(const lib::error_code&)> 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

View File

@@ -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<void(connection_hdl,boost::asio::ip::tcp::socket&)>
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<boost::asio::ip::tcp::socket> 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<type> 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<boost::asio::ip::tcp::socket> 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_interface> 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

View File

@@ -29,6 +29,9 @@
#define WEBSOCKETPP_TRANSPORT_SECURITY_TLS_HPP
#include <websocketpp/transport/asio/security/base.hpp>
#include <websocketpp/common/connection_hdl.hpp>
#include <websocketpp/common/functional.hpp>
#include <websocketpp/common/memory.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
@@ -39,16 +42,35 @@
namespace websocketpp {
namespace transport {
namespace security {
namespace asio {
namespace tls_socket {
class tls {
typedef lib::function<void(connection_hdl,boost::asio::ssl::stream<
boost::asio::ip::tcp::socket>::lowest_layer_type&)> socket_init_handler;
typedef lib::function<lib::shared_ptr<boost::asio::ssl::context>(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<type> ptr;
/// Type of the ASIO socket being used
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> 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_type> 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<boost::asio::ssl::context> context_ptr;
/// Type of a shared pointer to the ASIO timer being used
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
typedef boost::system::error_code boost_error;
@@ -62,11 +84,15 @@ public:
typedef lib::shared_ptr<handler_interface> 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