From 1aa17d517ce4e760e31d40c91d8630ccb0108423 Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 27 Mar 2014 14:06:43 +0100 Subject: [PATCH] [WIP], adding server skeleton for remote mobile connections --- remote/{proto => messages}/auth.pb.cc | 0 remote/{proto => messages}/auth.pb.h | 0 remote/{proto => messages}/collection.pb.cc | 0 remote/{proto => messages}/collection.pb.h | 0 remote/{proto => messages}/common.pb.cc | 0 remote/{proto => messages}/common.pb.h | 0 remote/{proto => messages}/media.pb.cc | 0 remote/{proto => messages}/media.pb.h | 0 remote/{proto => messages}/messages.pb.cc | 0 remote/{proto => messages}/messages.pb.h | 0 remote/server/.Connection.hpp.swp | Bin 0 -> 12288 bytes remote/server/Connection.cpp | 79 ++++++++++++++++++++ remote/server/Connection.hpp | 78 +++++++++++++++++++ remote/server/ConnectionManager.cpp | 40 ++++++++++ remote/server/ConnectionManager.hpp | 38 ++++++++++ remote/server/Header.hpp | 21 ++++++ remote/server/RequestHandler.hpp | 16 ++++ remote/server/Server.cpp | 77 +++++++++++++++++++ remote/server/Server.hpp | 56 ++++++++++++++ 19 files changed, 405 insertions(+) rename remote/{proto => messages}/auth.pb.cc (100%) rename remote/{proto => messages}/auth.pb.h (100%) rename remote/{proto => messages}/collection.pb.cc (100%) rename remote/{proto => messages}/collection.pb.h (100%) rename remote/{proto => messages}/common.pb.cc (100%) rename remote/{proto => messages}/common.pb.h (100%) rename remote/{proto => messages}/media.pb.cc (100%) rename remote/{proto => messages}/media.pb.h (100%) rename remote/{proto => messages}/messages.pb.cc (100%) rename remote/{proto => messages}/messages.pb.h (100%) create mode 100644 remote/server/.Connection.hpp.swp create mode 100644 remote/server/Connection.cpp create mode 100644 remote/server/Connection.hpp create mode 100644 remote/server/ConnectionManager.cpp create mode 100644 remote/server/ConnectionManager.hpp create mode 100644 remote/server/Header.hpp create mode 100644 remote/server/RequestHandler.hpp create mode 100644 remote/server/Server.cpp create mode 100644 remote/server/Server.hpp 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 0000000000000000000000000000000000000000..99b89596a132145056b95c8572b06dbb1008316a GIT binary patch literal 12288 zcmeI2O>Z1E7{?tXXa`6^<;sgmq$o(C)0Rqal$OxI8>gD-8d38ok0jI!S73iDpv*#ztb7#+-wzkt#Pt(UvzJAwX z&cG?)6mSYS1)Ks-0jGddz$xGq`2Q$i@(J=jmUCaVr1k1PF?O#W-OVZB6mSYS1)Ks- z0jGddz$xGqa0)mDoB~dP|DXaaCgh`Ig#30K!Q=n`_22(LKSId2;1;+JJ^>$t55QX> z1ZTk+@Hn_1{BnYj@41NyuN|Huw|V0^fjZ;39YuJOOS$jDBz( zd-aLJa8QR z=n?WYxC!>aF4zGtf&jb#&Vwm%0!)HGpxy7lYWSzqZL_KeBL+scEASku*c;(6M{LBNz^ zgN1&k#dgMH8ugf(qbr=nTm^v^@9;%0>=lnM_q$!L=JD%^?|F*n$$%E0q4nis?skut zE!0Tb;Z*a?&<=|(+h>E$C=qBnReN~5&$S72rVtheHXlcPRu)~U3NIpyWGb@lddR51 zx^=|EAwz7)w7v1l2JLHvY7}Q_r&uA*gL>X(8O{pJ;)JUi8jdzJm)t9Dte@DfG*>d> zS|1v#MzEeYJSe)xGPYg#KhV~kA}!5mDS^;58Xh&Z4m(n6gIsDMgFxg#U?O~I8C~Xv zhULBXw^g>*YL0o@ks_w$iY_Q&_$>N0vRF=_2iov72)I&Gg^`T;4CT+%o=dS1Tbd`_ z9)qQ_OBvm@eyGg3V#V258*sJx?EVVjePFl_jbfR`4pTfXTsA`4#0I>FNao<#Zp1qT zf)vNiIJ{hm9cFl7BPwRoM&`5o>)FB+Wl2Jr9%NBZ$xQb3(1Aufq!sWG(_LYDiQFxL15th`5dZ^8|*x^}YT=6oPLC#~|#Vd$vq)~o&9OgzX z441t~b15=Y)E+PIcM=f=m)p^e0G&gL(>y_VK`)QuC~o2 zs!Bev15n?5h?6UB3mCFYHL6Y0Oa!&g>>}%eHXci*HnK1*$Yt@RR~k*WMx%jDqd+D7 znA54zGHB0{Pc?c+Q#RgPjXl_mQe8F>S9w$T;0xUfXCdkAJC6i*9B&$Kk#I06k5xga7~l literal 0 HcmV?d00001 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