00001 #ifndef SERIALIZATION_CONNECTION_HPP
00002 #define SERIALIZATION_CONNECTION_HPP
00003
00004 #include <boost/asio.hpp>
00005 #include <boost/archive/text_iarchive.hpp>
00006 #include <boost/archive/text_oarchive.hpp>
00007 #include <boost/bind.hpp>
00008 #include <boost/shared_ptr.hpp>
00009 #include <boost/tuple/tuple.hpp>
00010 #include <iomanip>
00011 #include <string>
00012 #include <sstream>
00013 #include <vector>
00014
00015 namespace s11n_example {
00016
00018
00024 class connection
00025 {
00026 public:
00028 connection(boost::asio::io_service& io_service)
00029 : socket_(io_service)
00030 {
00031 }
00032
00035 boost::asio::ip::tcp::socket& socket()
00036 {
00037 return socket_;
00038 }
00039
00041 template <typename T, typename Handler>
00042 void async_write(const T& t, Handler handler)
00043 {
00044
00045 std::ostringstream archive_stream;
00046 boost::archive::text_oarchive archive(archive_stream);
00047 archive << t;
00048 outbound_data_ = archive_stream.str();
00049
00050
00051 std::ostringstream header_stream;
00052 header_stream << std::setw(header_length)
00053 << std::hex << outbound_data_.size();
00054 if (!header_stream || header_stream.str().size() != header_length)
00055 {
00056
00057 boost::asio::error error(boost::asio::error::invalid_argument);
00058 socket_.io_service().post(boost::bind(handler, error));
00059 return;
00060 }
00061 outbound_header_ = header_stream.str();
00062
00063
00064
00065 std::vector<boost::asio::const_buffer> buffers;
00066 buffers.push_back(boost::asio::buffer(outbound_header_));
00067 buffers.push_back(boost::asio::buffer(outbound_data_));
00068 boost::asio::async_write(socket_, buffers, handler);
00069 }
00070
00072 template <typename T, typename Handler>
00073 void async_read(T& t, Handler handler)
00074 {
00075
00076 void (connection::*f)(const boost::asio::error&, T&, boost::tuple<Handler>)
00077 = &connection::handle_read_header<T, Handler>;
00078 boost::asio::async_read(socket_, boost::asio::buffer(inbound_header_),
00079 boost::bind(f,
00080 this, boost::asio::placeholders::error, boost::ref(t),
00081 boost::make_tuple(handler)));
00082 }
00083
00087 template <typename T, typename Handler>
00088 void handle_read_header(const boost::asio::error& e, T& t,
00089 boost::tuple<Handler> handler)
00090 {
00091 if (e)
00092 {
00093 boost::get<0>(handler)(e);
00094 }
00095 else
00096 {
00097
00098 std::istringstream is(std::string(inbound_header_, header_length));
00099 std::size_t inbound_data_size = 0;
00100 if (!(is >> std::hex >> inbound_data_size))
00101 {
00102
00103 boost::asio::error error(boost::asio::error::invalid_argument);
00104 boost::get<0>(handler)(error);
00105 return;
00106 }
00107
00108
00109 inbound_data_.resize(inbound_data_size);
00110 void (connection::*f)(const boost::asio::error&, T&, boost::tuple<Handler>)
00111 = &connection::handle_read_data<T, Handler>;
00112 boost::asio::async_read(socket_, boost::asio::buffer(inbound_data_),
00113 boost::bind(f, this,
00114 boost::asio::placeholders::error, boost::ref(t), handler));
00115 }
00116 }
00117
00119 template <typename T, typename Handler>
00120 void handle_read_data(const boost::asio::error& e, T& t,
00121 boost::tuple<Handler> handler)
00122 {
00123 if (e)
00124 {
00125 boost::get<0>(handler)(e);
00126 }
00127 else
00128 {
00129
00130 try
00131 {
00132 std::string archive_data(&inbound_data_[0], inbound_data_.size());
00133 std::istringstream archive_stream(archive_data);
00134 boost::archive::text_iarchive archive(archive_stream);
00135 archive >> t;
00136 }
00137 catch (std::exception& e)
00138 {
00139
00140 boost::asio::error error(boost::asio::error::invalid_argument);
00141 boost::get<0>(handler)(error);
00142 return;
00143 }
00144
00145
00146 boost::get<0>(handler)(e);
00147 }
00148 }
00149
00150 private:
00152 boost::asio::ip::tcp::socket socket_;
00153
00155 enum { header_length = 8 };
00156
00158 std::string outbound_header_;
00159
00161 std::string outbound_data_;
00162
00164 char inbound_header_[header_length];
00165
00167 std::vector<char> inbound_data_;
00168 };
00169
00170 typedef boost::shared_ptr<connection> connection_ptr;
00171
00172 }
00173
00174 #endif // SERIALIZATION_CONNECTION_HPP