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