adding ssl support to websocket
This commit is contained in:
parent
e99b4ffea5
commit
fb62b6421c
3 changed files with 283 additions and 7 deletions
|
|
@ -9,6 +9,7 @@
|
|||
namespace fc { namespace http {
|
||||
namespace detail {
|
||||
class websocket_server_impl;
|
||||
class websocket_tls_server_impl;
|
||||
class websocket_client_impl;
|
||||
} // namespace detail;
|
||||
|
||||
|
|
@ -19,16 +20,19 @@ namespace fc { namespace http {
|
|||
virtual void send_message( const std::string& message ) = 0;
|
||||
virtual void close( int64_t code, const std::string& reason ){};
|
||||
void on_message( const std::string& message ) { _on_message(message); }
|
||||
string on_http( const std::string& message ) { return _on_http(message); }
|
||||
|
||||
void on_message_handler( const std::function<void(const std::string&)>& h ) { _on_message = h; }
|
||||
void on_http_handler( const std::function<std::string(const std::string&)>& h ) { _on_http = h; }
|
||||
|
||||
void set_session_data( fc::any d ){ _session_data = std::move(d); }
|
||||
fc::any& get_session_data() { return _session_data; }
|
||||
|
||||
fc::signal<void()> closed;
|
||||
private:
|
||||
fc::any _session_data;
|
||||
std::function<void(const std::string&)> _on_message;
|
||||
fc::any _session_data;
|
||||
std::function<void(const std::string&)> _on_message;
|
||||
std::function<string(const std::string&)> _on_http;
|
||||
};
|
||||
typedef std::shared_ptr<websocket_connection> websocket_connection_ptr;
|
||||
|
||||
|
|
@ -50,6 +54,24 @@ namespace fc { namespace http {
|
|||
std::unique_ptr<detail::websocket_server_impl> my;
|
||||
};
|
||||
|
||||
|
||||
class websocket_tls_server
|
||||
{
|
||||
public:
|
||||
websocket_tls_server( const std::string& server_pem = std::string(),
|
||||
const std::string& ssl_password = std::string());
|
||||
~websocket_tls_server();
|
||||
|
||||
void on_connection( const on_connection_handler& handler);
|
||||
void listen( uint16_t port );
|
||||
void listen( const fc::ip::endpoint& ep );
|
||||
void start_accept();
|
||||
|
||||
private:
|
||||
friend class detail::websocket_tls_server_impl;
|
||||
std::unique_ptr<detail::websocket_tls_server_impl> my;
|
||||
};
|
||||
|
||||
class websocket_client
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ namespace fc { namespace rpc {
|
|||
return this->receive_call( 0, method_name, args );
|
||||
});
|
||||
|
||||
_connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg); } );
|
||||
_connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg,true); } );
|
||||
_connection.on_http_handler( [&]( const std::string& msg ){ return on_message(msg,false); } );
|
||||
_connection.closed.connect( [this](){ closed(); } );
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ namespace fc { namespace rpc {
|
|||
|
||||
|
||||
protected:
|
||||
void on_message( const std::string& message )
|
||||
std::string on_message( const std::string& message, bool send_message = true )
|
||||
{
|
||||
try {
|
||||
auto var = fc::json::from_string(message);
|
||||
|
|
@ -78,14 +79,21 @@ namespace fc { namespace rpc {
|
|||
auto result = _rpc_state.local_call( call.method, call.params );
|
||||
if( call.id )
|
||||
{
|
||||
_connection.send_message( fc::json::to_string( response( *call.id, result ) ) );
|
||||
auto reply = fc::json::to_string( response( *call.id, result ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
catch ( const fc::exception& e )
|
||||
{
|
||||
if( call.id )
|
||||
{
|
||||
_connection.send_message( fc::json::to_string( response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) ) );
|
||||
auto reply = fc::json::to_string( response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) );
|
||||
if( send_message )
|
||||
_connection.send_message( reply );
|
||||
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +104,9 @@ namespace fc { namespace rpc {
|
|||
}
|
||||
} catch ( const fc::exception& e ) {
|
||||
wdump((e.to_detail_string()));
|
||||
return e.to_detail_string();
|
||||
}
|
||||
return string();
|
||||
}
|
||||
fc::http::websocket_connection& _connection;
|
||||
fc::rpc::state _rpc_state;
|
||||
|
|
|
|||
|
|
@ -57,12 +57,87 @@ namespace fc { namespace http {
|
|||
|
||||
static const long timeout_open_handshake = 0;
|
||||
};
|
||||
struct asio_tls_with_stub_log : public websocketpp::config::asio_tls {
|
||||
|
||||
typedef asio_with_stub_log type;
|
||||
typedef asio_tls base;
|
||||
|
||||
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;
|
||||
|
||||
/// Custom Logging policies
|
||||
/*typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::elevel> elog_type;
|
||||
typedef websocketpp::log::syslog<concurrency_type,
|
||||
websocketpp::log::alevel> alog_type;
|
||||
*/
|
||||
//typedef base::alog_type alog_type;
|
||||
//typedef base::elog_type elog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_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 websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
|
||||
static const long timeout_open_handshake = 0;
|
||||
};
|
||||
struct asio_tls_stub_log : public websocketpp::config::asio_tls {
|
||||
typedef asio_tls_stub_log type;
|
||||
typedef asio_tls base;
|
||||
|
||||
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 base::alog_type alog_type;
|
||||
//typedef base::elog_type elog_type;
|
||||
typedef websocketpp::log::stub elog_type;
|
||||
typedef websocketpp::log::stub alog_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 websocketpp::transport::asio::tls_socket::endpoint socket_type;
|
||||
};
|
||||
|
||||
typedef websocketpp::transport::asio::endpoint<transport_config>
|
||||
transport_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using websocketpp::connection_hdl;
|
||||
typedef websocketpp::server<asio_with_stub_log> websocket_server_type;
|
||||
typedef websocketpp::server<asio_with_stub_log> websocket_server_type;
|
||||
typedef websocketpp::server<asio_tls_stub_log> websocket_tls_server_type;
|
||||
|
||||
template<typename T>
|
||||
class websocket_connection_impl : public websocket_connection
|
||||
|
|
@ -90,12 +165,15 @@ namespace fc { namespace http {
|
|||
T _ws_connection;
|
||||
};
|
||||
|
||||
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
|
||||
|
||||
class websocket_server_impl
|
||||
{
|
||||
public:
|
||||
websocket_server_impl()
|
||||
:_server_thread( fc::thread::current() )
|
||||
{
|
||||
|
||||
_server.clear_access_channels( websocketpp::log::alevel::all );
|
||||
_server.init_asio(&fc::asio::default_io_service());
|
||||
_server.set_reuse_addr(true);
|
||||
|
|
@ -113,6 +191,24 @@ namespace fc { namespace http {
|
|||
current_con->second->on_message( msg->get_payload() );
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_http_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
|
||||
auto current_con = std::make_shared<websocket_connection_impl<websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
_on_connection( current_con );
|
||||
|
||||
auto con = _server.get_con_from_hdl(hdl);
|
||||
wdump(("server")(con->get_request_body()));
|
||||
auto response = current_con->on_http( con->get_request_body() );
|
||||
|
||||
con->set_body( response );
|
||||
con->set_status( websocketpp::http::status_code::ok );
|
||||
current_con->closed();
|
||||
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_close_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
_connections[hdl]->closed();
|
||||
|
|
@ -148,6 +244,121 @@ namespace fc { namespace http {
|
|||
fc::promise<void>::ptr _closed;
|
||||
};
|
||||
|
||||
class websocket_tls_server_impl
|
||||
{
|
||||
public:
|
||||
websocket_tls_server_impl( const string& server_pem, const string& ssl_password )
|
||||
:_server_thread( fc::thread::current() )
|
||||
{
|
||||
//if( server_pem.size() )
|
||||
{
|
||||
_server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr {
|
||||
context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tlsv1);
|
||||
try {
|
||||
ctx->set_options(boost::asio::ssl::context::default_workarounds |
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::no_sslv3 |
|
||||
boost::asio::ssl::context::single_dh_use);
|
||||
ctx->set_password_callback([=](std::size_t max_length, boost::asio::ssl::context::password_purpose){ return ssl_password;});
|
||||
ctx->use_certificate_chain_file(server_pem);
|
||||
ctx->use_private_key_file(server_pem, boost::asio::ssl::context::pem);
|
||||
} catch (std::exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
return ctx;
|
||||
});
|
||||
}
|
||||
|
||||
_server.clear_access_channels( websocketpp::log::alevel::all );
|
||||
_server.init_asio(&fc::asio::default_io_service());
|
||||
_server.set_reuse_addr(true);
|
||||
_server.set_open_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
auto new_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
_on_connection( _connections[hdl] = new_con );
|
||||
}).wait();
|
||||
});
|
||||
_server.set_message_handler( [&]( connection_hdl hdl, websocket_server_type::message_ptr msg ){
|
||||
_server_thread.async( [&](){
|
||||
auto current_con = _connections.find(hdl);
|
||||
assert( current_con != _connections.end() );
|
||||
wdump(("server")(msg->get_payload()));
|
||||
current_con->second->on_message( msg->get_payload() );
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_http_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
|
||||
auto current_con = std::make_shared<websocket_connection_impl<websocket_tls_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl) );
|
||||
try{
|
||||
_on_connection( current_con );
|
||||
|
||||
auto con = _server.get_con_from_hdl(hdl);
|
||||
wdump(("server")(con->get_request_body()));
|
||||
auto response = current_con->on_http( con->get_request_body() );
|
||||
|
||||
con->set_body( response );
|
||||
con->set_status( websocketpp::http::status_code::ok );
|
||||
} catch ( const fc::exception& e )
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
}
|
||||
current_con->closed();
|
||||
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_close_handler( [&]( connection_hdl hdl ){
|
||||
_server_thread.async( [&](){
|
||||
_connections[hdl]->closed();
|
||||
_connections.erase( hdl );
|
||||
}).wait();
|
||||
});
|
||||
|
||||
_server.set_fail_handler( [&]( connection_hdl hdl ){
|
||||
if( _server.is_listening() )
|
||||
{
|
||||
_server_thread.async( [&](){
|
||||
if( _connections.find(hdl) != _connections.end() )
|
||||
{
|
||||
_connections[hdl]->closed();
|
||||
_connections.erase( hdl );
|
||||
}
|
||||
}).wait();
|
||||
}
|
||||
});
|
||||
}
|
||||
~websocket_tls_server_impl()
|
||||
{
|
||||
if( _server.is_listening() )
|
||||
_server.stop_listening();
|
||||
auto cpy_con = _connections;
|
||||
for( auto item : cpy_con )
|
||||
_server.close( item.first, 0, "server exit" );
|
||||
}
|
||||
|
||||
typedef std::map<connection_hdl, websocket_connection_ptr,std::owner_less<connection_hdl> > con_map;
|
||||
|
||||
con_map _connections;
|
||||
fc::thread& _server_thread;
|
||||
websocket_tls_server_type _server;
|
||||
on_connection_handler _on_connection;
|
||||
fc::promise<void>::ptr _closed;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef websocketpp::client<asio_with_stub_log> websocket_client_type;
|
||||
typedef websocket_client_type::connection_ptr websocket_client_connection_type;
|
||||
|
||||
|
|
@ -220,6 +431,39 @@ namespace fc { namespace http {
|
|||
my->_server.start_accept();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {}
|
||||
websocket_tls_server::~websocket_tls_server(){}
|
||||
|
||||
void websocket_tls_server::on_connection( const on_connection_handler& handler )
|
||||
{
|
||||
my->_on_connection = handler;
|
||||
}
|
||||
|
||||
void websocket_tls_server::listen( uint16_t port )
|
||||
{
|
||||
my->_server.listen(port);
|
||||
}
|
||||
void websocket_tls_server::listen( const fc::ip::endpoint& ep )
|
||||
{
|
||||
my->_server.listen( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4(uint32_t(ep.get_address())),ep.port()) );
|
||||
}
|
||||
|
||||
void websocket_tls_server::start_accept() {
|
||||
my->_server.start_accept();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
websocket_client::websocket_client():my( new detail::websocket_client_impl() ) {}
|
||||
websocket_client::~websocket_client(){ }
|
||||
websocket_connection_ptr websocket_client::connect( const std::string& uri )
|
||||
|
|
|
|||
Loading…
Reference in a new issue