/* * Copyright (c) 2009-2010 by Bjoern Kolbeck, Zuse Institute Berlin * 2012 by Michael Berlin, Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ #ifndef CPP_INCLUDE_RPC_CLIENT_CONNECTION_H_ #define CPP_INCLUDE_RPC_CLIENT_CONNECTION_H_ #include #include #include #include #include #include #include #include "pbrpc/RPC.pb.h" #include "rpc/abstract_socket_channel.h" #include "rpc/client_request.h" #include "rpc/record_marker.h" #include "rpc/ssl_options.h" #if (BOOST_VERSION / 100000 > 1) || (BOOST_VERSION / 100 % 1000 > 35) #include #else #include #endif namespace xtreemfs { namespace rpc { // Boost introduced unordered_map in version 1.36 but we need to support // older versions for Debian 5. // TODO(bjko): Remove this typedef when support for Debian 5 is dropped. #if (BOOST_VERSION / 100000 > 1) || (BOOST_VERSION / 100 % 1000 > 35) typedef boost::unordered_map request_map; #else typedef std::map request_map; #endif /** Created by xtreemfs::rpc::Client for every connection. * * This class contains the per-connection data. * * @remarks Special care has to be taken regarding the boost::asio callback * functions. In particular, every callback must not access members * when the error_code equals asio::error::operation_aborted. * Additionally, no further actions must be taken when * connection_state_ is set to CLOSED. */ class ClientConnection { public: struct PendingRequest { PendingRequest(uint32_t call_id, ClientRequest* rq) : call_id(call_id), rq(rq) {} uint32_t call_id; ClientRequest* rq; }; ClientConnection(const std::string& server_name, const std::string& port, boost::asio::io_service& service, request_map *request_table, int32_t connect_timeout_s, int32_t max_reconnect_interval_s #ifdef HAS_OPENSSL ,bool use_gridssl, boost::asio::ssl::context* ssl_context #endif // HAS_OPENSSL ); virtual ~ClientConnection(); void DoProcess(); void AddRequest(ClientRequest *request); void Close(const std::string& error); void SendError(xtreemfs::pbrpc::POSIXErrno posix_errno, const std::string& error_message); void Reset(); boost::posix_time::ptime last_used() const { return last_used_; } std::string GetServerAddress() const { return server_name_ + ":" + server_port_; } private: enum State { CONNECTING, IDLE, ACTIVE, CLOSED, WAIT_FOR_RECONNECT }; RecordMarker *receive_marker_; char *receive_hdr_, *receive_msg_, *receive_data_; char *receive_marker_buffer_; State connection_state_; /** Queue of requests which have not been sent out yet. */ std::queue requests_; ClientRequest* current_request_; const std::string server_name_; const std::string server_port_; boost::asio::io_service &service_; boost::asio::ip::tcp::resolver resolver_; AbstractSocketChannel* socket_; boost::asio::ip::tcp::endpoint* endpoint_; /** Points to the Client's request_table_. */ request_map* request_table_; boost::asio::deadline_timer timer_; const int32_t connect_timeout_s_; const int32_t max_reconnect_interval_s_; boost::posix_time::ptime next_reconnect_at_; boost::posix_time::ptime last_connect_was_at_; int32_t reconnect_interval_s_; boost::posix_time::ptime last_used_; #ifdef HAS_OPENSSL bool use_gridssl_; boost::asio::ssl::context* ssl_context_; #endif // HAS_OPENSSL /** Deletes "socket". * * @remark Ownership of "socket" is transferred. */ void static DelayedSocketDeletionHandler(AbstractSocketChannel* socket); void Connect(); void SendRequest(); void ReceiveRequest(); void PostResolve(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); void PostConnect(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); void OnConnectTimeout(const boost::system::error_code& err); void PostReadMessage(const boost::system::error_code& err); void PostReadRecordMarker(const boost::system::error_code& err); void PostWrite(const boost::system::error_code& err, std::size_t bytes_written); void DeleteInternalBuffers(); void CreateChannel(); }; } // namespace rpc } // namespace xtreemfs #endif // CPP_INCLUDE_RPC_CLIENT_CONNECTION_H_