Remote protocol now over SSL
This commit is contained in:
@@ -37,6 +37,16 @@ AC_CHECK_LIB([avformat],
|
|||||||
,
|
,
|
||||||
[AC_MSG_ERROR([libavformat not found!])])
|
[AC_MSG_ERROR([libavformat not found!])])
|
||||||
|
|
||||||
|
AC_CHECK_LIB([ssl],
|
||||||
|
[SSL_CTX_new],
|
||||||
|
,
|
||||||
|
[AC_MSG_ERROR([libssl not found!])])
|
||||||
|
|
||||||
|
AC_CHECK_LIB([crypto],
|
||||||
|
[ASN1_STRING_to_UTF8],
|
||||||
|
,
|
||||||
|
[AC_MSG_ERROR([libcrypto not found!])])
|
||||||
|
|
||||||
AC_CHECK_LIB([boost_system],
|
AC_CHECK_LIB([boost_system],
|
||||||
[main],
|
[main],
|
||||||
,
|
,
|
||||||
|
|||||||
@@ -15,26 +15,49 @@
|
|||||||
namespace Remote {
|
namespace Remote {
|
||||||
namespace Server {
|
namespace Server {
|
||||||
|
|
||||||
Connection::Connection(boost::asio::ip::tcp::socket socket,
|
Connection::Connection(boost::asio::io_service& ioService,
|
||||||
|
boost::asio::ssl::context& context,
|
||||||
ConnectionManager& manager,
|
ConnectionManager& manager,
|
||||||
RequestHandler& handler)
|
RequestHandler& handler)
|
||||||
: _closing(false),
|
: _closing(false),
|
||||||
_socket(std::move(socket)),
|
_socket(ioService, context),
|
||||||
_connectionManager(manager),
|
_connectionManager(manager),
|
||||||
_requestHandler(handler)
|
_requestHandler(handler)
|
||||||
{
|
{
|
||||||
std::cout << "Server::Connection::Connection, Creating connection" << std::endl;
|
std::cout << "Server::Connection::Connection, Creating connection" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket&
|
|
||||||
Connection::socket()
|
|
||||||
{
|
|
||||||
return _socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Connection::start()
|
Connection::start()
|
||||||
{
|
{
|
||||||
|
std::cout << "Starting connection..." << std::endl;
|
||||||
|
_socket.async_handshake(boost::asio::ssl::stream_base::server,
|
||||||
|
boost::bind(&Connection::handleHandshake, this,
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Connection::handleHandshake(const boost::system::error_code& error)
|
||||||
|
{
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
std::cout << "Handshake successfully performed... Now reading messages" << std::endl;
|
||||||
|
readMsg();
|
||||||
|
}
|
||||||
|
else if (error != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
std::cerr << "Connection::handleHandshake: " << error.message() << std::endl;
|
||||||
|
_connectionManager.stop(shared_from_this());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cerr << "Handshake error: " << error.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Connection::readMsg()
|
||||||
|
{
|
||||||
|
// Read a header first
|
||||||
boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(Remote::Header::size);
|
boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(Remote::Header::size);
|
||||||
|
|
||||||
boost::asio::async_read(_socket,
|
boost::asio::async_read(_socket,
|
||||||
@@ -50,13 +73,19 @@ Connection::stop()
|
|||||||
{
|
{
|
||||||
if (!_closing)
|
if (!_closing)
|
||||||
{
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
|
||||||
_closing = true;
|
_closing = true;
|
||||||
std::cout << "Server::Connection::stop, Stopping connection " << this << std::endl;
|
std::cout << "Server::Connection::stop, Stopping connection " << this << std::endl;
|
||||||
_socket.close();
|
_socket.shutdown(ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
std::cerr << "Error while shutting down connection " << this << ": " << ec.message() << std::endl;
|
||||||
|
|
||||||
std::cout << "Server::Connection::stop, connection stopped " << this << std::endl;
|
std::cout << "Server::Connection::stop, connection stopped " << this << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "Close in progress..." << std::endl;
|
std::cout << "Stop: close already in progress..." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -83,7 +112,7 @@ Connection::handleReadHeader(const boost::system::error_code& error, std::size_t
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now read the real message
|
// Now read the real message payload
|
||||||
boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(header.getDataSize());
|
boost::asio::streambuf::mutable_buffers_type bufs = _inputStreamBuf.prepare(header.getDataSize());
|
||||||
|
|
||||||
boost::asio::async_read(_socket,
|
boost::asio::async_read(_socket,
|
||||||
@@ -178,7 +207,9 @@ Connection::handleReadMsg(const boost::system::error_code& error, std::size_t by
|
|||||||
_connectionManager.stop(shared_from_this());
|
_connectionManager.stop(shared_from_this());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
start();
|
|
||||||
|
// All good here, read another message
|
||||||
|
readMsg();
|
||||||
|
|
||||||
// Initiate graceful Connection closure.
|
// Initiate graceful Connection closure.
|
||||||
// boost::system::error_code ignored_ec;
|
// boost::system::error_code ignored_ec;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
#include "RequestHandler.hpp"
|
#include "RequestHandler.hpp"
|
||||||
|
|
||||||
@@ -20,16 +21,18 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||||
|
|
||||||
Connection(const Connection&) = delete;
|
Connection(const Connection&) = delete;
|
||||||
Connection& operator=(const Connection&) = delete;
|
Connection& operator=(const Connection&) = delete;
|
||||||
|
|
||||||
typedef std::shared_ptr<Connection> pointer;
|
typedef std::shared_ptr<Connection> pointer;
|
||||||
|
|
||||||
/// Construct a connection with the given io_service.
|
/// Construct a connection with the given io_service.
|
||||||
explicit Connection(boost::asio::ip::tcp::socket socket,
|
explicit Connection(boost::asio::io_service& ioService, boost::asio::ssl::context& context,
|
||||||
ConnectionManager& manager, RequestHandler& handler);
|
ConnectionManager& manager, RequestHandler& handler);
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& socket();
|
ssl_socket::lowest_layer_type& getSocket() {return _socket.lowest_layer();}
|
||||||
|
|
||||||
/// Start the first asynchronous operation for the connection.
|
/// Start the first asynchronous operation for the connection.
|
||||||
void start();
|
void start();
|
||||||
@@ -40,6 +43,12 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
private:
|
private:
|
||||||
bool _closing;
|
bool _closing;
|
||||||
|
|
||||||
|
/// Read a new message on the the connection
|
||||||
|
void readMsg();
|
||||||
|
|
||||||
|
/// Handle completion of ssl handshake
|
||||||
|
void handleHandshake(const boost::system::error_code& error);
|
||||||
|
|
||||||
/// Handle completion of a read operation.
|
/// Handle completion of a read operation.
|
||||||
void handleReadHeader(const boost::system::error_code& e,
|
void handleReadHeader(const boost::system::error_code& e,
|
||||||
std::size_t bytes_transferred);
|
std::size_t bytes_transferred);
|
||||||
@@ -48,7 +57,7 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
std::size_t bytes_transferred);
|
std::size_t bytes_transferred);
|
||||||
|
|
||||||
/// Socket for the connection.
|
/// Socket for the connection.
|
||||||
boost::asio::ip::tcp::socket _socket;
|
ssl_socket _socket;
|
||||||
|
|
||||||
/// The manager for this connection.
|
/// The manager for this connection.
|
||||||
ConnectionManager& _connectionManager;
|
ConnectionManager& _connectionManager;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/asio/placeholders.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
#include "Server.hpp"
|
#include "Server.hpp"
|
||||||
@@ -13,9 +14,18 @@ Server::Server(boost::asio::io_service& ioService, const endpoint_type& bindEndp
|
|||||||
_ioService(ioService),
|
_ioService(ioService),
|
||||||
_acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/),
|
_acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/),
|
||||||
_connectionManager(),
|
_connectionManager(),
|
||||||
_socket(_ioService),
|
_context(boost::asio::ssl::context::tlsv1_server),
|
||||||
_requestHandler(dbPath)
|
_requestHandler(dbPath)
|
||||||
{
|
{
|
||||||
|
_context.set_options( boost::asio::ssl::context::default_workarounds // TODO check this thing
|
||||||
|
| boost::asio::ssl::context::single_dh_use
|
||||||
|
| boost::asio::ssl::context::no_sslv2
|
||||||
|
| boost::asio::ssl::context::no_sslv3
|
||||||
|
);
|
||||||
|
// context_.set_password_callback(boost::bind(&server::get_password, this));
|
||||||
|
_context.use_certificate_chain_file("cert.pem"); // TODO parametrize
|
||||||
|
_context.use_private_key_file("privkey.pem", boost::asio::ssl::context::pem); // TODO parametrize
|
||||||
|
_context.use_tmp_dh_file("dh2048.pem"); // TODO parametrize
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -30,12 +40,16 @@ Server::run()
|
|||||||
void
|
void
|
||||||
Server::asyncAccept()
|
Server::asyncAccept()
|
||||||
{
|
{
|
||||||
_acceptor.async_accept(_socket, boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
|
std::shared_ptr<Connection> newConnection = std::make_shared<Connection>(_ioService, _context, _connectionManager, _requestHandler);
|
||||||
|
|
||||||
|
_acceptor.async_accept(newConnection->getSocket(),
|
||||||
|
boost::bind(&Server::handleAccept, this, newConnection, boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Server::handleAccept(boost::system::error_code ec)
|
Server::handleAccept(std::shared_ptr<Connection> newConnection, boost::system::error_code ec)
|
||||||
{
|
{
|
||||||
|
std::cout << "Server::handleAccept..." << std::endl;
|
||||||
// Check whether the server was stopped before this
|
// Check whether the server was stopped before this
|
||||||
// completion handler had a chance to run.
|
// completion handler had a chance to run.
|
||||||
if (!_acceptor.is_open())
|
if (!_acceptor.is_open())
|
||||||
@@ -45,8 +59,10 @@ Server::handleAccept(boost::system::error_code ec)
|
|||||||
|
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
_connectionManager.start(std::make_shared<Connection>(std::move(_socket), _connectionManager, _requestHandler));
|
_connectionManager.start(newConnection);
|
||||||
|
|
||||||
|
// Accept another connection
|
||||||
|
// TODO: add some limit?
|
||||||
asyncAccept();
|
asyncAccept();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#define REMOTE_SERVER_HPP
|
#define REMOTE_SERVER_HPP
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include "Connection.hpp"
|
#include "Connection.hpp"
|
||||||
@@ -32,7 +34,7 @@ class Server
|
|||||||
private:
|
private:
|
||||||
/// Perform an asynchronous accept operation.
|
/// Perform an asynchronous accept operation.
|
||||||
void asyncAccept();
|
void asyncAccept();
|
||||||
void handleAccept(boost::system::error_code ec);
|
void handleAccept(std::shared_ptr<Connection> newConnection, boost::system::error_code ec);
|
||||||
|
|
||||||
boost::asio::io_service& _ioService;
|
boost::asio::io_service& _ioService;
|
||||||
|
|
||||||
@@ -42,8 +44,7 @@ class Server
|
|||||||
/// The connection manager which owns all live connections.
|
/// The connection manager which owns all live connections.
|
||||||
ConnectionManager _connectionManager;
|
ConnectionManager _connectionManager;
|
||||||
|
|
||||||
/// The next socket to be accepted.
|
boost::asio::ssl::context _context;
|
||||||
boost::asio::ip::tcp::socket _socket;
|
|
||||||
|
|
||||||
/// The handler for all incoming requests.
|
/// The handler for all incoming requests.
|
||||||
RequestHandler _requestHandler;
|
RequestHandler _requestHandler;
|
||||||
|
|||||||
+32
-46
@@ -11,8 +11,6 @@
|
|||||||
#include "remote/messages/Header.hpp"
|
#include "remote/messages/Header.hpp"
|
||||||
#include "remote/messages/messages.pb.h"
|
#include "remote/messages/messages.pb.h"
|
||||||
|
|
||||||
#include "av/Common.hpp"
|
|
||||||
|
|
||||||
#include "TestDatabase.hpp"
|
#include "TestDatabase.hpp"
|
||||||
|
|
||||||
struct GenreInfo
|
struct GenreInfo
|
||||||
@@ -80,44 +78,22 @@ struct Cover
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Ugly class for testing purposes
|
// Ugly class for testing purposes
|
||||||
class TestServer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestServer(boost::asio::ip::tcp::endpoint endpoint)
|
|
||||||
: _db(TestDatabase::create()),
|
|
||||||
_server(_ioService, endpoint, _db->getPath()),
|
|
||||||
_thread( boost::bind(&TestServer::threadEntry, this))
|
|
||||||
{
|
|
||||||
_server.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
~TestServer()
|
|
||||||
{
|
|
||||||
_server.stop();
|
|
||||||
_thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void threadEntry(void)
|
|
||||||
{
|
|
||||||
_ioService.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::asio::io_service _ioService;
|
|
||||||
std::unique_ptr<DatabaseHandler> _db;
|
|
||||||
Remote::Server::Server _server;
|
|
||||||
std::thread _thread;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestClient
|
class TestClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestClient(boost::asio::ip::tcp::endpoint endpoint)
|
TestClient(boost::asio::ip::tcp::endpoint endpoint)
|
||||||
:_socket(_ioService)
|
: _context(boost::asio::ssl::context::sslv23), // be large on this
|
||||||
|
_socket(_ioService, _context)
|
||||||
{
|
{
|
||||||
_socket.connect(endpoint);
|
boost::asio::ip::tcp::resolver resolver(_ioService);
|
||||||
|
|
||||||
|
_socket.set_verify_mode(boost::asio::ssl::verify_peer);
|
||||||
|
_socket.set_verify_callback(boost::bind(&TestClient::verifyCertificate, this, _1, _2));
|
||||||
|
|
||||||
|
boost::asio::connect(_socket.lowest_layer(), resolver.resolve(endpoint));
|
||||||
|
|
||||||
|
_socket.handshake(boost::asio::ssl::stream_base::client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getArtists(std::vector<ArtistInfo>& artists)
|
void getArtists(std::vector<ArtistInfo>& artists)
|
||||||
@@ -433,6 +409,19 @@ class TestClient
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool verifyCertificate(bool preverified, boost::asio::ssl::verify_context& ctx)
|
||||||
|
{
|
||||||
|
// In this example we will simply print the certificate's subject name.
|
||||||
|
std::array<char, 256> subject_name;
|
||||||
|
|
||||||
|
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(cert), subject_name.data(), subject_name.size());
|
||||||
|
|
||||||
|
std::cout << "Verifying '" << std::string(subject_name.data()) << "', preverified = " << std::boolalpha << preverified << std::endl;
|
||||||
|
|
||||||
|
return true; // preverified;
|
||||||
|
}
|
||||||
|
|
||||||
void mediaAudioPrepare(uint64_t audioId)
|
void mediaAudioPrepare(uint64_t audioId)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -646,11 +635,14 @@ class TestClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::io_service _ioService;
|
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||||
boost::asio::ip::tcp::socket _socket;
|
|
||||||
|
|
||||||
boost::asio::streambuf _inputStreamBuf;
|
boost::asio::io_service _ioService;
|
||||||
boost::asio::streambuf _outputStreamBuf;
|
boost::asio::ssl::context _context;
|
||||||
|
ssl_socket _socket;
|
||||||
|
|
||||||
|
boost::asio::streambuf _inputStreamBuf;
|
||||||
|
boost::asio::streambuf _outputStreamBuf;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -658,19 +650,13 @@ class TestClient
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
// lib init
|
|
||||||
Av::AvInit();
|
|
||||||
Transcode::AvConvTranscoder::init();
|
|
||||||
|
|
||||||
bool extendedTests = true;
|
bool extendedTests = true;
|
||||||
|
|
||||||
// Runs in its own thread
|
std::cout << "Running test... extendedTests = " << std::boolalpha << extendedTests << std::endl;
|
||||||
// Listen on any
|
|
||||||
TestServer testServer( boost::asio::ip::tcp::endpoint( boost::asio::ip::tcp::v4(), 5081));
|
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
// connect to loopback
|
// connect to loopback
|
||||||
TestClient client( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4::loopback(), 5081));
|
TestClient client( boost::asio::ip::tcp::endpoint( boost::asio::ip::address_v4::loopback(), 5080));
|
||||||
|
|
||||||
// ****** Artists *********
|
// ****** Artists *********
|
||||||
std::vector<ArtistInfo> artists;
|
std::vector<ArtistInfo> artists;
|
||||||
|
|||||||
Reference in New Issue
Block a user