[WIP], adding server skeleton for remote mobile connections
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "RequestHandler.hpp"
|
||||||
|
|
||||||
|
#include "ConnectionManager.hpp"
|
||||||
|
#include "Connection.hpp"
|
||||||
|
|
||||||
|
namespace Remote {
|
||||||
|
namespace Server {
|
||||||
|
|
||||||
|
Connection::Connection(boost::asio::io_service& ioService, Connection_manager& manager, RequestHandler& handler)
|
||||||
|
: _socket(ioService),
|
||||||
|
_connectionManager(manager),
|
||||||
|
request_handler_(handler)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::asio::ip::tcp::socket&
|
||||||
|
Connection::socket()
|
||||||
|
{
|
||||||
|
return _socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Connection::start()
|
||||||
|
{
|
||||||
|
_socket.async_read_some(boost::asio::buffer(_headerBuffer),
|
||||||
|
boost::bind(&Connection::handleRead, shared_from_this(),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Connection::stop()
|
||||||
|
{
|
||||||
|
_socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Connection::handleRead(const boost::system::error_code& error, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
/* boost::asio::async_write(_socket, reply_.to_buffers(),
|
||||||
|
boost::bind(&Connection::handleWrite, shared_from_this(),
|
||||||
|
boost::asio::placeholders::error));*/
|
||||||
|
|
||||||
|
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
else if (error != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
std::cerr << "Connection::handleRead: " << error.message() << std::endl;
|
||||||
|
_connectionManager.stop(shared_from_this());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connection::handleWrite(const boost::system::error_code& e)
|
||||||
|
{
|
||||||
|
if (!e)
|
||||||
|
{
|
||||||
|
// Initiate graceful Connection closure.
|
||||||
|
boost::system::error_code ignored_ec;
|
||||||
|
_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e != boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
std::cerr << "Connection::handleWrite: " << error.message() << std::endl;
|
||||||
|
_connectionManager.stop(shared_from_this());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Server
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#ifndef REMOTE_CONNECTION_HPP
|
||||||
|
#define REMOTE_CONNECTION_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <array.hpp>
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
|
|
||||||
|
#include "reply.hpp"
|
||||||
|
#include "request.hpp"
|
||||||
|
#include "RequestHandler.hpp"
|
||||||
|
#include "request_parser.hpp"
|
||||||
|
|
||||||
|
namespace http {
|
||||||
|
namespace server {
|
||||||
|
|
||||||
|
class ConnectionManager;
|
||||||
|
|
||||||
|
/// Represents a single connection from a client.
|
||||||
|
class Connection : public boost::enable_shared_from_this<Connection>, boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::shared_ptr<connection> pointer;
|
||||||
|
|
||||||
|
/// Construct a connection with the given io_service.
|
||||||
|
Connection(boost::asio::io_service& io_service,
|
||||||
|
ConnectionManager& manager, RequestHandler& handler);
|
||||||
|
|
||||||
|
boost::asio::ip::tcp::socket& socket();
|
||||||
|
|
||||||
|
/// Start the first asynchronous operation for the connection.
|
||||||
|
void start();
|
||||||
|
|
||||||
|
/// Stop all asynchronous operations associated with the connection.
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Handle completion of a read operation.
|
||||||
|
void handleRead(const boost::system::error_code& e,
|
||||||
|
std::size_t bytes_transferred);
|
||||||
|
|
||||||
|
/// Handle completion of a write operation.
|
||||||
|
void handleWrite(const boost::system::error_code& e);
|
||||||
|
|
||||||
|
/// Socket for the connection.
|
||||||
|
boost::asio::ip::tcp::socket _socket;
|
||||||
|
|
||||||
|
/// The manager for this connection.
|
||||||
|
ConnectionManager& _ConnectionManager;
|
||||||
|
|
||||||
|
/// The handler used to process the incoming requests.
|
||||||
|
RequestHandler& _RequestHandler;
|
||||||
|
|
||||||
|
// TODO use streambuffers
|
||||||
|
|
||||||
|
/// The incoming request.
|
||||||
|
// request request_;
|
||||||
|
|
||||||
|
/// The parser for the incoming request.
|
||||||
|
// request_parser request_parser_;
|
||||||
|
|
||||||
|
/// The reply to be sent back to the client.
|
||||||
|
// reply reply_;
|
||||||
|
|
||||||
|
std::array<unsigned char, Header::size> _headerBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace server
|
||||||
|
} // namespace http
|
||||||
|
|
||||||
|
#endif // HTTP_CONNECTION_HPP
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "ConnectionManager.hpp"
|
||||||
|
|
||||||
|
namespace Remote {
|
||||||
|
|
||||||
|
namespace Server {
|
||||||
|
|
||||||
|
void
|
||||||
|
ConnectionManager::start(connection::pointer c)
|
||||||
|
{
|
||||||
|
_connections.insert(c);
|
||||||
|
c->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConnectionManager::stop(connection::pointer c)
|
||||||
|
{
|
||||||
|
_connections.erase(c);
|
||||||
|
c->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConnectionManager::stop_all()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(connection::pointer c, _connections)
|
||||||
|
{
|
||||||
|
c->stop();
|
||||||
|
}
|
||||||
|
_connections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Server
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef REMOTE_CONNECTION_MANAGER_HPP
|
||||||
|
#define REMOTE_CONNECTION_MANAGER_HPP
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
|
|
||||||
|
#include "connection.hpp"
|
||||||
|
|
||||||
|
namespace Remote {
|
||||||
|
|
||||||
|
namespace Server {
|
||||||
|
|
||||||
|
/// Manages open connections so that they may be cleanly stopped when the server
|
||||||
|
/// needs to shut down.
|
||||||
|
|
||||||
|
class ConnectionManager : boost::noncopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Add the specified connection to the manager and start it.
|
||||||
|
void start(connection::pointer c);
|
||||||
|
|
||||||
|
/// Stop the specified connection.
|
||||||
|
void stop(connection::pointer c);
|
||||||
|
|
||||||
|
/// Stop all connections.
|
||||||
|
void stop_all();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The managed connections.
|
||||||
|
std::set<connection::pointer> _connections;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Server
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef REMOTE_HEADER_HPP
|
||||||
|
#define REMOTE_HEADER_HPP
|
||||||
|
|
||||||
|
namespace Remote
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class Header
|
||||||
|
{
|
||||||
|
static const std::size_t size = 8;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef REMOTE_REQUEST_HANDLER
|
||||||
|
#define REMOTE_REQUEST_HANDLER
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RequestHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
|
||||||
|
#include "Server.hpp"
|
||||||
|
|
||||||
|
namespace Remote {
|
||||||
|
|
||||||
|
namespace Server {
|
||||||
|
|
||||||
|
server::server(boost::asio::io_service& ioService, const endpoint_type& endpoint)
|
||||||
|
: _ioService(ioService),
|
||||||
|
_acceptor(_ioService),
|
||||||
|
_connectionManager(),
|
||||||
|
_socket(io_service_),
|
||||||
|
_requestHandler(doc_root)
|
||||||
|
{
|
||||||
|
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||||
|
boost::asio::ip::tcp::resolver resolver(_ioService);
|
||||||
|
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(endpoint);
|
||||||
|
|
||||||
|
_acceptor.open(endpoint.protocol());
|
||||||
|
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||||
|
_acceptor.bind(endpoint);
|
||||||
|
_acceptor.listen();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Server::run()
|
||||||
|
{
|
||||||
|
// While the server is running, there is always at least one
|
||||||
|
// asynchronous operation outstanding: the asynchronous accept call waiting
|
||||||
|
// for new incoming connections.
|
||||||
|
async_accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Server::async_accept()
|
||||||
|
{
|
||||||
|
_acceptor.async_accept(_socket, boost::bind(&Server::handleAccept, this, boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Server::handleAccept(boost::system::error_code ec)
|
||||||
|
{
|
||||||
|
// Check whether the server was stopped before this
|
||||||
|
// completion handler had a chance to run.
|
||||||
|
if (!_acceptor.is_open())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
_connectionManager.start(std::make_shared<connection>(std::move(_socket), _connectionManager, _requestHandler));
|
||||||
|
|
||||||
|
async_accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cerr << "handleAccept: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Server::stop()
|
||||||
|
{
|
||||||
|
// The server is stopped by cancelling all outstanding asynchronous
|
||||||
|
// operations.
|
||||||
|
_acceptor.close();
|
||||||
|
_connectionManager.stop_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Server
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef REMOTE_SERVER_HPP
|
||||||
|
#define REMOTE_SERVER_HPP
|
||||||
|
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Connection.hpp"
|
||||||
|
#include "ConnectionManager.hpp"
|
||||||
|
|
||||||
|
#include "RequestHandler.hpp"
|
||||||
|
|
||||||
|
namespace Remote {
|
||||||
|
|
||||||
|
namespace Server {
|
||||||
|
|
||||||
|
class Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::string endpoint_type;
|
||||||
|
|
||||||
|
// Serve up data from the given database
|
||||||
|
Server(boost::asio::io_service& ioService,
|
||||||
|
const endpoint_type& endpoint);
|
||||||
|
|
||||||
|
// Run the server's io_service loop.
|
||||||
|
void run();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Perform an asynchronous accept operation.
|
||||||
|
void asyncAccept();
|
||||||
|
void handleAccept(boost::system::error_code ec);
|
||||||
|
|
||||||
|
boost::asio::io_service& _ioService;
|
||||||
|
|
||||||
|
/// Acceptor used to listen for incoming connections.
|
||||||
|
boost::asio::ip::tcp::acceptor _acceptor;
|
||||||
|
|
||||||
|
/// The connection manager which owns all live connections.
|
||||||
|
connection_manager _connectionManager;
|
||||||
|
|
||||||
|
/// The next socket to be accepted.
|
||||||
|
boost::asio::ip::tcp::socket _socket;
|
||||||
|
|
||||||
|
/// The handler for all incoming requests.
|
||||||
|
RequestHandler _requestHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Server
|
||||||
|
|
||||||
|
} // namespace Remote
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user