Refactor client-side wesnothd handshake process

This makes things a bit less confusing by making the worker thread handle the handshake. It also
removes the need for manually spinning the main thread to wait for the handshake.
This commit is contained in:
Charles Dang 2019-08-05 10:03:48 +11:00
parent b7234a48b2
commit 2051e7fc5b
3 changed files with 32 additions and 35 deletions

View file

@ -57,7 +57,7 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
wesnothd_connection_ptr sock(nullptr);
if(host.empty()) {
return std::make_pair(std::move(sock), config());
return std::make_pair(nullptr, config());
}
// shown_hosts is used to prevent the client being locked in a redirect loop.
@ -75,17 +75,14 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
// Initializes the connection to the server.
sock = std::make_unique<wesnothd_connection>(addr.first, addr.second);
if(!sock) {
return std::make_pair(std::move(sock), config());
return std::make_pair(nullptr, config());
}
// Start stage
gui2::dialogs::loading_screen::progress(loading_stage::connect_to_server);
// First, spin until we get a handshake from the server.
while(!sock->handshake_finished()) {
sock->poll();
SDL_Delay(1);
}
sock->wait_for_handshake();
gui2::dialogs::loading_screen::progress(loading_stage::waiting);
@ -98,7 +95,7 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
// Then, log in and wait for the lobby/game join prompt.
do {
if(!sock) {
return std::make_pair(std::move(sock), config());
return std::make_pair(nullptr, config());
}
data.clear();
@ -140,10 +137,7 @@ std::pair<wesnothd_connection_ptr, config> open_connection(std::string host)
sock = std::make_unique<wesnothd_connection>(redirect_host, redirect_port);
// Wait for new handshake.
while(!sock->handshake_finished()) {
sock->poll();
SDL_Delay(1);
}
sock->wait_for_handshake();
gui2::dialogs::loading_screen::progress(loading_stage::waiting);
continue;

View file

@ -61,7 +61,7 @@ wesnothd_connection::wesnothd_connection(const std::string& host, const std::str
, socket_(io_service_)
, last_error_()
, last_error_mutex_()
, handshake_finished_(false)
, handshake_finished_()
, read_buf_()
, handshake_response_()
, recv_queue_()
@ -76,6 +76,12 @@ wesnothd_connection::wesnothd_connection(const std::string& host, const std::str
resolver_.async_resolve(boost::asio::ip::tcp::resolver::query(host, service),
std::bind(&wesnothd_connection::handle_resolve, this, _1, _2));
// Starts the worker thread. Do this *after* the above async_resolve call or it will just exit immediately!
worker_thread_ = std::thread([this]() {
io_service_.run();
LOG_NW << "wesnothd_connection::io_service::run() returned\n";
});
LOG_NW << "Resolving hostname: " << host << '\n';
}
@ -84,13 +90,11 @@ wesnothd_connection::~wesnothd_connection()
MPTEST_LOG;
// Stop the io_service and wait for the worker thread to terminate.
if(worker_thread_) {
stop();
worker_thread_->join();
}
stop();
worker_thread_.join();
}
// main thread
// worker thread
void wesnothd_connection::handle_resolve(const error_code& ec, resolver::iterator iterator)
{
MPTEST_LOG;
@ -102,7 +106,7 @@ void wesnothd_connection::handle_resolve(const error_code& ec, resolver::iterato
connect(iterator);
}
// main thread
// worker thread
void wesnothd_connection::connect(resolver::iterator iterator)
{
MPTEST_LOG;
@ -110,7 +114,7 @@ void wesnothd_connection::connect(resolver::iterator iterator)
LOG_NW << "Connecting to " << iterator->endpoint().address() << '\n';
}
// main thread
// worker thread
void wesnothd_connection::handle_connect(const boost::system::error_code& ec, resolver::iterator iterator)
{
MPTEST_LOG;
@ -130,7 +134,7 @@ void wesnothd_connection::handle_connect(const boost::system::error_code& ec, re
}
}
// main thread
// worker thread
void wesnothd_connection::handshake()
{
MPTEST_LOG;
@ -143,7 +147,7 @@ void wesnothd_connection::handshake()
std::bind(&wesnothd_connection::handle_handshake, this, _1));
}
// main thread
// worker thread
void wesnothd_connection::handle_handshake(const error_code& ec)
{
MPTEST_LOG;
@ -152,13 +156,16 @@ void wesnothd_connection::handle_handshake(const error_code& ec)
throw system_error(ec);
}
handshake_finished_ = true;
handshake_finished_.set_value(true);
recv();
}
worker_thread_.reset(new std::thread([this]() {
io_service_.run();
LOG_NW << "wesnothd_connection::io_service::run() returned\n";
}));
// main thread
void wesnothd_connection::wait_for_handshake()
{
MPTEST_LOG;
LOG_NW << "Waiting for handshake" << std::endl;
handshake_finished_.get_future().wait();
}
// main thread
@ -366,7 +373,6 @@ void wesnothd_connection::recv()
std::size_t wesnothd_connection::poll()
{
MPTEST_LOG;
assert(!worker_thread_);
try {
return io_service_.poll();

View file

@ -36,6 +36,7 @@
#include <boost/asio.hpp>
#include <deque>
#include <future>
#include <list>
#include <thread>
#include <mutex>
@ -80,6 +81,8 @@ public:
*/
bool wait_and_receive_data(config& data);
void wait_for_handshake();
/** Handles all pending asynchornous events and returns. */
std::size_t poll();
@ -88,12 +91,6 @@ public:
// Destroys this object.
void stop();
/** True if connected and no high-level operation is in progress */
bool handshake_finished() const
{
return handshake_finished_;
}
std::size_t bytes_to_write() const
{
return bytes_to_write_;
@ -125,7 +122,7 @@ public:
}
private:
std::unique_ptr<std::thread> worker_thread_;
std::thread worker_thread_;
boost::asio::io_service io_service_;
@ -139,7 +136,7 @@ private:
std::mutex last_error_mutex_;
bool handshake_finished_;
std::promise<bool> handshake_finished_;
boost::asio::streambuf read_buf_;