servers: implement consistent error handling policy for coro_* functions

- coro_ read function returns empty unique_ptr on error
- coro_ write functions close socket on error
- caller does need only to handle empty unique_ptr from reads, generally
  with immediate return
This commit is contained in:
loonycyborg 2022-10-04 22:06:56 +03:00
parent f308614328
commit d0d9dfaf04
No known key found for this signature in database
GPG key ID: 6E8233FAB8F26D61
4 changed files with 27 additions and 31 deletions

View file

@ -1153,11 +1153,9 @@ void server::handle_request_campaign(const server::request& req)
LOG_CS << req << "Sending add-on '" << name << "' version: " << from << " -> " << to << " (delta)\n";
if(utils::visit([this, &req, &doc](auto && sock) {
boost::system::error_code ec;
coro_send_doc(sock, doc, req.yield[ec]);
return check_error(ec, sock);
}, req.sock)) return;
utils::visit([this, &req, &doc](auto && sock) {
coro_send_doc(sock, doc, req.yield);
}, req.sock);
full_pack_path.clear();
}
@ -1173,11 +1171,9 @@ void server::handle_request_campaign(const server::request& req)
}
LOG_CS << req << "Sending add-on '" << name << "' version: " << to << " size: " << full_pack_size / 1024 << " KiB\n";
if(utils::visit([this, &req, &full_pack_path](auto&& socket) {
boost::system::error_code ec;
coro_send_file(socket, full_pack_path, req.yield[ec]);
return check_error(ec, socket);
}, req.sock)) return;
utils::visit([this, &req, &full_pack_path](auto&& socket) {
coro_send_file(socket, full_pack_path, req.yield);
}, req.sock);
}
// Clients doing upgrades or some other specific thing shouldn't bump
@ -1229,11 +1225,9 @@ void server::handle_request_campaign_hash(const server::request& req)
}
LOG_CS << req << "Sending add-on hash index for '" << req.cfg["name"] << "' size: " << file_size / 1024 << " KiB\n";
if(utils::visit([this, &path, &req](auto&& socket) {
boost::system::error_code ec;
coro_send_file(socket, path, req.yield[ec]);
return check_error(ec, socket);
}, req.sock)) return;
utils::visit([this, &path, &req](auto&& socket) {
coro_send_file(socket, path, req.yield);
}, req.sock);
}
}

View file

@ -347,7 +347,10 @@ template<class SocketPtr> void coro_send_file_userspace(SocketPtr socket, const
boost::system::error_code ec;
async_write(*socket, boost::asio::buffer(data_size.buf), yield[ec]);
if(check_error(ec, socket)) return;
if(check_error(ec, socket)) {
socket->lowest_layer().close();
return;
}
auto ifs { filesystem::istream_file(filename) };
ifs->seekg(0);
@ -355,7 +358,10 @@ template<class SocketPtr> void coro_send_file_userspace(SocketPtr socket, const
char buf[16384];
ifs->read(buf, sizeof(buf));
async_write(*socket, boost::asio::buffer(buf, ifs->gcount()), yield[ec]);
if(check_error(ec, socket)) return;
if(check_error(ec, socket)) {
socket->lowest_layer().close();
return;
}
}
}

View file

@ -104,6 +104,7 @@ public:
* Receive WML document from a coroutine
* @param socket
* @param yield The function will suspend on read operation using this yield context
* @return unique_ptr with doc deceived. In case of error empty unique_ptr
*/
template<class SocketPtr> std::unique_ptr<simple_wml::document> coro_receive_doc(SocketPtr socket, boost::asio::yield_context yield);

View file

@ -683,13 +683,10 @@ void server::handle_new_client(tls_socket_ptr socket)
template<class SocketPtr>
void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
{
boost::system::error_code ec;
coro_send_doc(socket, version_query_response_, yield);
coro_send_doc(socket, version_query_response_, yield[ec]);
if(check_error(ec, socket)) return;
auto doc { coro_receive_doc(socket, yield[ec]) };
if(check_error(ec, socket) || !doc) return;
auto doc { coro_receive_doc(socket, yield) };
if(!doc) return;
std::string client_version, client_source;
if(const simple_wml::node* const version = doc->child("version")) {
@ -706,8 +703,7 @@ void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
if(accepted_it != accepted_versions_.end()) {
LOG_SERVER << log_address(socket) << "\tplayer joined using accepted version " << client_version
<< ":\ttelling them to log in.\n";
coro_send_doc(socket, login_response_, yield[ec]);
if(check_error(ec, socket)) return;
coro_send_doc(socket, login_response_, yield);
} else {
simple_wml::document response;
@ -748,8 +744,8 @@ void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
bool registered, is_moderator;
while(true) {
auto login_response { coro_receive_doc(socket, yield[ec]) };
if(check_error(ec, socket) || !login_response) return;
auto login_response { coro_receive_doc(socket, yield) };
if(!login_response) return;
if(const simple_wml::node* const login = login_response->child("login")) {
username = (*login)["username"].to_string();
@ -765,8 +761,7 @@ void server::login_client(boost::asio::yield_context yield, SocketPtr socket)
simple_wml::document join_lobby_response;
join_lobby_response.root().add_child("join_lobby").set_attr("is_moderator", is_moderator ? "yes" : "no");
join_lobby_response.root().child("join_lobby")->set_attr_dup("profile_url_prefix", "https://r.wesnoth.org/u");
coro_send_doc(socket, join_lobby_response, yield[ec]);
if(check_error(ec, socket)) return;
coro_send_doc(socket, join_lobby_response, yield);
simple_wml::node& player_cfg = games_and_users_list_.root().add_child("user");
wesnothd::player new_player(
@ -1100,8 +1095,8 @@ template<class SocketPtr> void server::handle_player(boost::asio::yield_context
while(true) {
boost::system::error_code ec;
auto doc { coro_receive_doc(socket, yield[ec]) };
if(check_error(ec, socket) || !doc) return;
auto doc { coro_receive_doc(socket, yield) };
if(!doc) return;
// DBG_SERVER << client_address(socket) << "\tWML received:\n" << doc->output() << std::endl;
if(doc->child("refresh_lobby")) {