diff --git a/remote/proto/auth.pb.cc b/remote/messages/auth.pb.cc similarity index 100% rename from remote/proto/auth.pb.cc rename to remote/messages/auth.pb.cc diff --git a/remote/proto/auth.pb.h b/remote/messages/auth.pb.h similarity index 100% rename from remote/proto/auth.pb.h rename to remote/messages/auth.pb.h diff --git a/remote/proto/collection.pb.cc b/remote/messages/collection.pb.cc similarity index 100% rename from remote/proto/collection.pb.cc rename to remote/messages/collection.pb.cc diff --git a/remote/proto/collection.pb.h b/remote/messages/collection.pb.h similarity index 100% rename from remote/proto/collection.pb.h rename to remote/messages/collection.pb.h diff --git a/remote/proto/common.pb.cc b/remote/messages/common.pb.cc similarity index 100% rename from remote/proto/common.pb.cc rename to remote/messages/common.pb.cc diff --git a/remote/proto/common.pb.h b/remote/messages/common.pb.h similarity index 100% rename from remote/proto/common.pb.h rename to remote/messages/common.pb.h diff --git a/remote/proto/media.pb.cc b/remote/messages/media.pb.cc similarity index 100% rename from remote/proto/media.pb.cc rename to remote/messages/media.pb.cc diff --git a/remote/proto/media.pb.h b/remote/messages/media.pb.h similarity index 100% rename from remote/proto/media.pb.h rename to remote/messages/media.pb.h diff --git a/remote/proto/messages.pb.cc b/remote/messages/messages.pb.cc similarity index 100% rename from remote/proto/messages.pb.cc rename to remote/messages/messages.pb.cc diff --git a/remote/proto/messages.pb.h b/remote/messages/messages.pb.h similarity index 100% rename from remote/proto/messages.pb.h rename to remote/messages/messages.pb.h diff --git a/remote/server/.Connection.hpp.swp b/remote/server/.Connection.hpp.swp new file mode 100644 index 00000000..99b89596 Binary files /dev/null and b/remote/server/.Connection.hpp.swp differ diff --git a/remote/server/Connection.cpp b/remote/server/Connection.cpp new file mode 100644 index 00000000..5af03cbb --- /dev/null +++ b/remote/server/Connection.cpp @@ -0,0 +1,79 @@ + +#include +#include + +#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 diff --git a/remote/server/Connection.hpp b/remote/server/Connection.hpp new file mode 100644 index 00000000..d45134e9 --- /dev/null +++ b/remote/server/Connection.hpp @@ -0,0 +1,78 @@ +#ifndef REMOTE_CONNECTION_HPP +#define REMOTE_CONNECTION_HPP + +#include +#include + +#include +#include + +#include + +#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, boost::noncopyable +{ + public: + + typedef std::shared_ptr 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 _headerBuffer; +}; + + +} // namespace server +} // namespace http + +#endif // HTTP_CONNECTION_HPP + + diff --git a/remote/server/ConnectionManager.cpp b/remote/server/ConnectionManager.cpp new file mode 100644 index 00000000..e6a8ffd7 --- /dev/null +++ b/remote/server/ConnectionManager.cpp @@ -0,0 +1,40 @@ + +#include +#include + +#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 + + diff --git a/remote/server/ConnectionManager.hpp b/remote/server/ConnectionManager.hpp new file mode 100644 index 00000000..1624639f --- /dev/null +++ b/remote/server/ConnectionManager.hpp @@ -0,0 +1,38 @@ +#ifndef REMOTE_CONNECTION_MANAGER_HPP +#define REMOTE_CONNECTION_MANAGER_HPP + +#include + +#include + +#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 _connections; +}; + +} // namespace Server + +} // namespace Remote + +#endif diff --git a/remote/server/Header.hpp b/remote/server/Header.hpp new file mode 100644 index 00000000..da68b0f9 --- /dev/null +++ b/remote/server/Header.hpp @@ -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 + diff --git a/remote/server/RequestHandler.hpp b/remote/server/RequestHandler.hpp new file mode 100644 index 00000000..c4d54963 --- /dev/null +++ b/remote/server/RequestHandler.hpp @@ -0,0 +1,16 @@ +#ifndef REMOTE_REQUEST_HANDLER +#define REMOTE_REQUEST_HANDLER + + + +class RequestHandler +{ + + + + + +}; + +#endif + diff --git a/remote/server/Server.cpp b/remote/server/Server.cpp new file mode 100644 index 00000000..2f600b73 --- /dev/null +++ b/remote/server/Server.cpp @@ -0,0 +1,77 @@ + +#include + +#include + +#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(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 diff --git a/remote/server/Server.hpp b/remote/server/Server.hpp new file mode 100644 index 00000000..2939112b --- /dev/null +++ b/remote/server/Server.hpp @@ -0,0 +1,56 @@ +#ifndef REMOTE_SERVER_HPP +#define REMOTE_SERVER_HPP + +#include + +#include + +#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