New network subsystem: implemented the handshake...

...and started implementing reading/writing WML.
This commit is contained in:
Sergey Popov 2011-06-20 20:34:22 +00:00
parent 31ad9b2d06
commit 47d6e3b0a5
6 changed files with 137 additions and 6 deletions

View file

@ -1130,6 +1130,12 @@ namespace {
bool result = network_connect.show(disp.video());
if(!result)
return;
config cfg, response;
cfg.add_child("request_campaign_list");
connection.transfer(cfg, response);
result = network_connect.show(disp.video());
if(!result)
return;
}
const network::manager net_manager;
const network::connection sock =

View file

@ -33,7 +33,7 @@ REGISTER_DIALOG(network_transmission)
void tnetwork_transmission::pump_monitor::process(events::pump_info&)
{
connection_.poll();
if(connection_.connected() && window_) {
if(connection_.done() && window_) {
window_.get().set_retval(twindow::OK);
}
}

View file

@ -1,11 +1,13 @@
#include "network_asio.hpp"
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <iostream>
#include "network_asio.hpp"
#include "serialization/parser.hpp"
namespace network_asio {
connection::connection(const std::string& host, const std::string& service) :
resolver_(io_service_), socket_(io_service_), connected_(false)
resolver_(io_service_), socket_(io_service_), done_(false)
{
resolver_.async_resolve(
boost::asio::ip::tcp::resolver::query(host, service),
@ -45,8 +47,93 @@ void connection::handle_connect(
connect(iterator);
} else {
std::cout << "Connected!\n";
connected_ = true;
handshake();
}
}
void connection::handshake()
{
static const boost::uint32_t handshake = 0;
boost::asio::async_write(socket_,
boost::asio::buffer(reinterpret_cast<const char*>(&handshake), 4),
boost::bind(&connection::handle_write, this, _1, _2)
);
boost::asio::async_read(socket_,
boost::asio::buffer(&handshake_response_.binary, 4),
boost::bind(&connection::handle_handshake, this, _1)
);
}
void connection::handle_handshake(
const boost::system::error_code& ec
)
{
if(ec)
throw error(ec);
done_ = true;
}
void connection::transfer(const config& request, config& /*response*/)
{
io_service_.reset();
done_ = false;
std::ostream os(&write_buf_);
write_gz(os, request);
std::size_t size = write_buf_.size();
size = htonl(size);
boost::asio::write(socket_, boost::asio::buffer(reinterpret_cast<const char*>(&size), 4));
boost::asio::async_write(socket_, write_buf_, boost::bind(&connection::handle_write, this, _1, _2));
boost::asio::async_read(socket_, read_buf_,
boost::bind(&connection::is_read_complete, this, _1, _2),
boost::bind(&connection::handle_read, this, _1, _2));
}
void connection::handle_write(
const boost::system::error_code& ec,
std::size_t bytes_transferred
)
{
std::cout << "Written " << bytes_transferred << " bytes.\n";
if(ec)
throw error(ec);
}
std::size_t connection::is_read_complete(
const boost::system::error_code& ec,
std::size_t bytes_transferred
)
{
if(ec)
throw error(ec);
std::cout << "Read: " << bytes_transferred << '\n';
if(bytes_transferred < 4) {
return 4;
} else {
if(!bytes_to_read_) {
std::istream is(&read_buf_);
union { char binary[4]; boost::uint32_t num; } data_size;
is.read(data_size.binary, 4);
bytes_to_read_ = ntohl(data_size.num) + 4;
}
return bytes_to_read_.get() - bytes_transferred;
}
}
void connection::handle_read(
const boost::system::error_code& ec,
std::size_t bytes_transferred
)
{
std::cout << "Read " << bytes_transferred << " bytes.\n";
bytes_to_read_.reset();
done_ = true;
if(ec && ec != boost::asio::error::eof)
throw error(ec);
std::istream is(&read_buf_);
config cfg;
read_gz(cfg, is);
std::cout << cfg;
}
}

View file

@ -2,7 +2,9 @@
#define NETWORK_ASIO_HPP_INCLUDED
#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include "exceptions.hpp"
#include "config.hpp"
namespace network_asio {
@ -21,7 +23,10 @@ class connection
typedef boost::asio::ip::tcp::socket socket;
socket socket_;
bool connected_;
bool done_;
boost::asio::streambuf write_buf_;
boost::asio::streambuf read_buf_;
void handle_resolve(
const boost::system::error_code& ec,
@ -33,7 +38,28 @@ class connection
const boost::system::error_code& ec,
resolver::iterator iterator
);
void handshake();
void handle_handshake(
const boost::system::error_code& ec
);
union {
char binary[4];
boost::uint32_t num;
} handshake_response_;
void handle_write(
const boost::system::error_code& ec,
std::size_t bytes_transferred
);
std::size_t is_read_complete(
const boost::system::error_code& error,
std::size_t bytes_transferred
);
void handle_read(
const boost::system::error_code& ec,
std::size_t bytes_transferred
);
boost::optional<std::size_t> bytes_to_read_;
public:
/**
@ -44,6 +70,8 @@ class connection
*/
connection(const std::string& host, const std::string& service);
void transfer(const config& request, config& response);
/** Handle all pending asynchonous events and return */
std::size_t poll()
{
@ -60,7 +88,8 @@ class connection
*/
void run() { io_service_.run(); }
bool connected() const { return connected_; }
/** True if connected and no high-level operation is in progress */
bool done() const { return done_; }
};
}

View file

@ -484,3 +484,11 @@ void write(std::ostream &out, config const &cfg, unsigned int level)
write_internal(cfg, out, textdomain, level);
}
void write_gz(std::ostream &out, config const &cfg, unsigned int level)
{
boost::iostreams::filtering_stream<boost::iostreams::output> filter;
filter.push(boost::iostreams::gzip_compressor());
filter.push(out);
write(filter, cfg, level);
}

View file

@ -28,6 +28,7 @@ void read(config &cfg, std::string &in); // Throws config::error
void read_gz(config &cfg, std::istream &in);
void write(std::ostream &out, config const &cfg, unsigned int level=0);
void write_gz(std::ostream &out, config const &cfg, unsigned int level=0);
void write_key_val(std::ostream &out, const std::string &key, const config::attribute_value &value, unsigned level, std::string &textdomain);
void write_open_child(std::ostream &out, const std::string &child, unsigned int level);
void write_close_child(std::ostream &out, const std::string &child, unsigned int level);