Skip to content

Commit

Permalink
Made addon client and server exchange OOB messages on user cancel
Browse files Browse the repository at this point in the history
this is needed to fix issue #2203
  • Loading branch information
loonycyborg committed Dec 1, 2017
1 parent 044d715 commit 55c70a1
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 4 deletions.
7 changes: 7 additions & 0 deletions src/campaign_server/campaign_server.cpp
Expand Up @@ -231,6 +231,13 @@ void server::handle_new_client(socket_ptr socket)
);
}

void server::handle_out_of_band(socket_ptr socket, char data)
{
socket->cancel();
socket->send(boost::asio::buffer(&data, 1), boost::asio::socket_base::message_out_of_band);
handle_new_client(socket);
}

void server::handle_request(socket_ptr socket, std::shared_ptr<simple_wml::document> doc)
{
config data;
Expand Down
1 change: 1 addition & 0 deletions src/campaign_server/campaign_server.hpp
Expand Up @@ -100,6 +100,7 @@ class server : public server_base
boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;

void handle_new_client(socket_ptr socket);
void handle_out_of_band(socket_ptr socket, char data);
void handle_request(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);

#ifndef _WIN32
Expand Down
31 changes: 27 additions & 4 deletions src/network_asio.cpp
Expand Up @@ -36,6 +36,7 @@ connection::connection(const std::string& host, const std::string& service)
, resolver_(io_service_)
, socket_(io_service_)
, done_(false)
, canceled_(false)
, write_buf_()
, read_buf_()
, handshake_response_()
Expand Down Expand Up @@ -139,11 +140,33 @@ void connection::cancel()
if(ec) {
WRN_NW << "Failed to cancel network operations: " << ec.message() << std::endl;
}
bytes_to_write_ = 0;
bytes_written_ = 0;
bytes_to_read_ = 0;
bytes_read_ = 0;

// send a message to server out-of-band so it would cancel transfer
socket_.send(boost::asio::buffer(&bytes_read_, 1), boost::asio::socket_base::message_out_of_band);

// drop data that server sent before canceling
canceled_ = true;
#define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
typedef boost::asio::detail::socket_option::boolean<
BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_OOBINLINE)>
out_of_band_inline;
out_of_band_inline option(true);
socket_.set_option(option);

// TODO: this should be made async but changes to dialogs needed
std::unique_ptr<char[]> buf { new char[1024] };
while(canceled_) {
socket_.receive(boost::asio::buffer(buf.get(), 1024), boost::asio::socket_base::message_peek);
if(socket_.at_mark()) {
canceled_ = false;
}
socket_.receive(boost::asio::buffer(buf.get(), 1024));
}
}
bytes_to_write_ = 0;
bytes_written_ = 0;
bytes_to_read_ = 0;
bytes_read_ = 0;
}

std::size_t connection::is_write_complete(const boost::system::error_code& ec, std::size_t bytes_transferred)
Expand Down
1 change: 1 addition & 0 deletions src/network_asio.hpp
Expand Up @@ -131,6 +131,7 @@ class connection
socket socket_;

bool done_;
bool canceled_;

std::unique_ptr<boost::asio::streambuf> write_buf_;
std::unique_ptr<boost::asio::streambuf> read_buf_;
Expand Down
5 changes: 5 additions & 0 deletions src/server/server.cpp
Expand Up @@ -514,6 +514,11 @@ void server::handle_new_client(socket_ptr socket)
);
}

void server::handle_out_of_band(socket_ptr, char)
{

}

void server::handle_version(socket_ptr socket)
{
async_receive_doc(socket,
Expand Down
1 change: 1 addition & 0 deletions src/server/server.hpp
Expand Up @@ -37,6 +37,7 @@ class server : public server_base

private:
void handle_new_client(socket_ptr socket);
void handle_out_of_band(socket_ptr socket, char);

void handle_version(socket_ptr socket);
void read_version(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);
Expand Down
28 changes: 28 additions & 0 deletions src/server/server_base.cpp
Expand Up @@ -120,6 +120,34 @@ void server_base::handle_handshake(const boost::system::error_code& error, socke
[=](const boost::system::error_code& error, size_t)
{ if(!check_error(error, socket)) this->handle_new_client(socket); }
);

read_oob_data(socket);
}

void server_base::read_oob_data(socket_ptr socket)
{
boost::shared_array<char> buf { new char[1] };
socket_weak_ptr socket_weak { socket };
socket->async_receive(boost::asio::buffer(buf.get(), 1), boost::asio::socket_base::message_out_of_band,
[=](const boost::system::error_code& error, std::size_t)
{ this->handle_oob_data(error, socket_weak, buf); }
);
}

void server_base::handle_oob_data(const boost::system::error_code& error, socket_weak_ptr socket, boost::shared_array<char> buf)
{
if(socket.expired())
return;
if(error) {
if(error.value() != boost::system::errc::invalid_argument) {
ERR_SERVER << client_address(socket.lock()) << "\terror reading out-of-band data: " << error.message() << std::endl;
}
return;
} else {
handle_out_of_band(socket.lock(), buf.get()[0]);
}

read_oob_data(socket.lock());
}

#ifndef _WIN32
Expand Down
5 changes: 5 additions & 0 deletions src/server/server_base.hpp
Expand Up @@ -26,6 +26,7 @@
#include <boost/shared_array.hpp>

typedef std::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
typedef std::weak_ptr<boost::asio::ip::tcp::socket> socket_weak_ptr;

struct server_shutdown : public game::error
{
Expand Down Expand Up @@ -55,7 +56,11 @@ class server_base
void serverside_handshake(socket_ptr socket);
void handle_handshake(const boost::system::error_code& error, socket_ptr socket, boost::shared_array<char> buf);

void read_oob_data(socket_ptr socket);
void handle_oob_data(const boost::system::error_code& error, socket_weak_ptr socket, boost::shared_array<char> buf);

virtual void handle_new_client(socket_ptr socket) = 0;
virtual void handle_out_of_band(socket_ptr socket, char) = 0;

virtual bool accepting_connections() const { return true; }
virtual std::string is_ip_banned(const std::string&) const { return std::string(); }
Expand Down

0 comments on commit 55c70a1

Please sign in to comment.