mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-26 17:51:51 +00:00
added better error handling in network connection code
This commit is contained in:
parent
d1c8b49df4
commit
265e902ed5
@ -128,6 +128,9 @@ network_controlled="Network Player"
|
||||
remote_host="Choose host to connect to"
|
||||
connection_failed="Could not connect to the remote host"
|
||||
connection_timeout="Connection timed out"
|
||||
awaiting_connections="Waiting for players to connect"
|
||||
position_taken="Filled"
|
||||
position_vacant="Available"
|
||||
|
||||
host_game="Host Multiplayer Game"
|
||||
join_game="Join Networked Multiplayer Game"
|
||||
|
16
src/menu.cpp
16
src/menu.cpp
@ -447,7 +447,8 @@ int show_dialog(display& disp, SDL_Surface* image,
|
||||
const std::vector<std::string>* menu_items_ptr,
|
||||
const std::vector<unit>* units_ptr,
|
||||
const std::string& text_widget_label,
|
||||
std::string* text_widget_text)
|
||||
std::string* text_widget_text,
|
||||
dialog_action* action)
|
||||
{
|
||||
if(disp.update_locked())
|
||||
return -1;
|
||||
@ -547,6 +548,12 @@ int show_dialog(display& disp, SDL_Surface* image,
|
||||
button_list = thebuttons;
|
||||
break;
|
||||
}
|
||||
|
||||
case CANCEL_ONLY: {
|
||||
static const std::string thebuttons[] = { "cancel_button", "" };
|
||||
button_list = thebuttons;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int button_height_padding = 10;
|
||||
@ -829,6 +836,13 @@ int show_dialog(display& disp, SDL_Surface* image,
|
||||
}
|
||||
}
|
||||
|
||||
if(action != NULL) {
|
||||
const int act = action->do_action();
|
||||
if(act != dialog_action::CONTINUE_DIALOG) {
|
||||
return act;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Delay(20);
|
||||
}
|
||||
|
||||
|
15
src/menu.hpp
15
src/menu.hpp
@ -32,7 +32,17 @@ void draw_solid_tinted_rectangle(int x, int y, int w, int h,
|
||||
int r, int g, int b,
|
||||
double alpha, SDL_Surface* target);
|
||||
|
||||
enum DIALOG_TYPE { MESSAGE, OK_ONLY, YES_NO, OK_CANCEL };
|
||||
class dialog_action
|
||||
{
|
||||
public:
|
||||
virtual ~dialog_action() {}
|
||||
|
||||
virtual int do_action() = 0;
|
||||
|
||||
enum { CONTINUE_DIALOG=-2 };
|
||||
};
|
||||
|
||||
enum DIALOG_TYPE { MESSAGE, OK_ONLY, YES_NO, OK_CANCEL, CANCEL_ONLY };
|
||||
|
||||
//if a menu is given, then returns -1 if the dialog was cancelled, and the
|
||||
//index of the selection otherwise. If no menu is given, returns the index
|
||||
@ -43,7 +53,8 @@ int show_dialog(display& screen, SDL_Surface* image,
|
||||
const std::vector<std::string>* menu_items=NULL,
|
||||
const std::vector<unit>* units=NULL,
|
||||
const std::string& text_widget_label="",
|
||||
std::string* text_widget_text=NULL
|
||||
std::string* text_widget_text=NULL,
|
||||
dialog_action* action=NULL
|
||||
);
|
||||
|
||||
enum TITLE_RESULT { TUTORIAL, NEW_CAMPAIGN, MULTIPLAYER, LOAD_GAME, QUIT_GAME,
|
||||
|
@ -26,94 +26,151 @@
|
||||
|
||||
namespace {
|
||||
|
||||
bool accept_network_connections(config& players)
|
||||
class connection_acceptor : public gui::dialog_action
|
||||
{
|
||||
log_scope("accept network connections");
|
||||
typedef std::map<config*,network::connection> positions_map;
|
||||
positions_map positions;
|
||||
public:
|
||||
|
||||
typedef std::map<config*,network::connection> positions_map;
|
||||
|
||||
connection_acceptor(config& players);
|
||||
int do_action();
|
||||
|
||||
bool is_complete() const;
|
||||
|
||||
std::vector<std::string> get_positions_status() const;
|
||||
|
||||
enum { CONNECTIONS_PART_FILLED=1, CONNECTIONS_FILLED=2 };
|
||||
|
||||
private:
|
||||
positions_map positions_;
|
||||
config& players_;
|
||||
std::vector<config*>& sides_;
|
||||
};
|
||||
|
||||
connection_acceptor::connection_acceptor(config& players)
|
||||
: players_(players), sides_(players.children["side"])
|
||||
{
|
||||
std::vector<config*>& sides = players.children["side"];
|
||||
for(std::vector<config*>::const_iterator i = sides.begin();
|
||||
i != sides.end(); ++i) {
|
||||
if((*i)->values["controller"] == "network") {
|
||||
positions[*i] = 0;
|
||||
positions_[*i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(positions.empty())
|
||||
return true;
|
||||
int connection_acceptor::do_action()
|
||||
{
|
||||
network::connection sock = network::accept_connection();
|
||||
if(sock) {
|
||||
std::cerr << "Received connection\n";
|
||||
network::send_data(players_,sock);
|
||||
}
|
||||
|
||||
std::cerr << "waiting for connections...\n";
|
||||
for(;;) {
|
||||
network::connection sock = network::accept_connection();
|
||||
if(sock) {
|
||||
std::cerr << "Received connection\n";
|
||||
network::send_data(players,sock);
|
||||
}
|
||||
config cfg;
|
||||
sock = network::receive_data(cfg);
|
||||
if(sock) {
|
||||
const int side_taken = atoi(cfg.values["side"].c_str())-1;
|
||||
if(side_taken >= 0 && side_taken < int(sides_.size())) {
|
||||
positions_map::iterator pos = positions_.find(sides_[side_taken]);
|
||||
if(pos != positions_.end()) {
|
||||
if(!pos->second) {
|
||||
std::cerr << "client has taken a valid position\n";
|
||||
|
||||
config cfg;
|
||||
sock = network::receive_data(cfg);
|
||||
if(sock) {
|
||||
const int side_taken = atoi(cfg.values["side"].c_str())-1;
|
||||
if(side_taken >= 0 && side_taken < int(sides.size())) {
|
||||
positions_map::iterator pos = positions.find(sides[side_taken]);
|
||||
if(pos != positions.end()) {
|
||||
if(!pos->second) {
|
||||
std::cerr << "client has taken a valid position\n";
|
||||
//broadcast to everyone the new game status
|
||||
pos->first->values["taken"] = "yes";
|
||||
positions_[sides_[side_taken]] = sock;
|
||||
network::send_data(players_);
|
||||
|
||||
//broadcast to everyone the new game status
|
||||
pos->first->values["taken"] = "yes";
|
||||
positions[sides[side_taken]] = sock;
|
||||
network::send_data(players);
|
||||
std::cerr << "sent player data\n";
|
||||
|
||||
std::cerr << "sent player data\n";
|
||||
//send a reply telling the client they have secured
|
||||
//the side they asked for
|
||||
std::stringstream side;
|
||||
side << (side_taken+1);
|
||||
config reply;
|
||||
reply.values["side_secured"] = side.str();
|
||||
std::cerr << "going to send data...\n";
|
||||
network::send_data(reply,sock);
|
||||
|
||||
//send a reply telling the client they have secured
|
||||
//the side they asked for
|
||||
std::stringstream side;
|
||||
side << (side_taken+1);
|
||||
config reply;
|
||||
reply.values["side_secured"] = side.str();
|
||||
std::cerr << "going to send data...\n";
|
||||
network::send_data(reply,sock);
|
||||
|
||||
//see if all positions are now filled
|
||||
bool unclaimed = false;
|
||||
for(positions_map::const_iterator p = positions.begin();
|
||||
p != positions.end(); ++p) {
|
||||
if(!p->second) {
|
||||
unclaimed = true;
|
||||
break;
|
||||
}
|
||||
//see if all positions are now filled
|
||||
bool unclaimed = false;
|
||||
for(positions_map::const_iterator p = positions_.begin();
|
||||
p != positions_.end(); ++p) {
|
||||
if(!p->second) {
|
||||
unclaimed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!unclaimed) {
|
||||
std::cerr << "starting game now...\n";
|
||||
config start_game;
|
||||
start_game.children["start_game"].
|
||||
push_back(new config());
|
||||
network::send_data(start_game);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
config response;
|
||||
response.values["failed"] = "yes";
|
||||
network::send_data(response,sock);
|
||||
if(!unclaimed) {
|
||||
std::cerr << "starting game now...\n";
|
||||
config start_game;
|
||||
start_game.children["start_game"].
|
||||
push_back(new config());
|
||||
network::send_data(start_game);
|
||||
return CONNECTIONS_FILLED;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "tried to take illegal side: " << side_taken
|
||||
<< "\n";
|
||||
config response;
|
||||
response.values["failed"] = "yes";
|
||||
network::send_data(response,sock);
|
||||
}
|
||||
} else {
|
||||
std::cerr << "tried to take unknown side: " << side_taken
|
||||
std::cerr << "tried to take illegal side: " << side_taken
|
||||
<< "\n";
|
||||
}
|
||||
} else {
|
||||
std::cerr << "tried to take unknown side: " << side_taken
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
std::cerr << "pump\n";
|
||||
pump_events();
|
||||
SDL_Delay(50);
|
||||
return CONNECTIONS_PART_FILLED;
|
||||
}
|
||||
|
||||
return CONTINUE_DIALOG;
|
||||
}
|
||||
|
||||
bool connection_acceptor::is_complete() const
|
||||
{
|
||||
for(positions_map::const_iterator i = positions_.begin();
|
||||
i != positions_.end(); ++i) {
|
||||
if(!i->second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> connection_acceptor::get_positions_status() const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
for(positions_map::const_iterator i = positions_.begin();
|
||||
i != positions_.end(); ++i) {
|
||||
result.push_back(i->first->values["name"] + "," +
|
||||
(i->second ? ("@" + string_table["position_taken"]) :
|
||||
string_table["position_vacant"]));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool accept_network_connections(display& disp, config& players)
|
||||
{
|
||||
connection_acceptor acceptor(players);
|
||||
|
||||
while(acceptor.is_complete() == false) {
|
||||
const std::vector<std::string>& items = acceptor.get_positions_status();
|
||||
const int res = gui::show_dialog(disp,NULL,"",
|
||||
string_table["awaiting_connections"],
|
||||
gui::CANCEL_ONLY,&items,NULL,"",NULL,&acceptor);
|
||||
if(res == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -337,7 +394,7 @@ void play_multiplayer(display& disp, game_data& units_data, config& cfg,
|
||||
const network::manager net_manager;
|
||||
const network::server_manager server_man;
|
||||
|
||||
const bool network_state = accept_network_connections(level);
|
||||
const bool network_state = accept_network_connections(disp,level);
|
||||
if(network_state == false)
|
||||
return;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
SDLNet_SocketSet socket_set = SDLNet_AllocSocketSet(64);
|
||||
SDLNet_SocketSet socket_set = 0;
|
||||
typedef std::vector<network::connection> sockets_list;
|
||||
sockets_list sockets;
|
||||
|
||||
@ -25,6 +25,8 @@ manager::manager()
|
||||
if(SDLNet_Init() == -1) {
|
||||
throw error(SDL_GetError());
|
||||
}
|
||||
|
||||
socket_set = SDLNet_AllocSocketSet(64);
|
||||
}
|
||||
|
||||
manager::~manager()
|
||||
@ -148,9 +150,8 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
|
||||
if(len == 0) {
|
||||
break;
|
||||
} else if(len < 0) {
|
||||
disconnect(*i);
|
||||
throw error(std::string("error receiving data: ") +
|
||||
SDLNet_GetError());
|
||||
SDLNet_GetError(),*i);
|
||||
}
|
||||
|
||||
buffer.resize(buffer.size()+1);
|
||||
@ -162,8 +163,7 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
|
||||
}
|
||||
|
||||
if(buffer == "") {
|
||||
disconnect(*i);
|
||||
throw error("error receiving data");
|
||||
throw error("error receiving data",*i);
|
||||
}
|
||||
|
||||
std::cerr << "received: " << buffer << "\n";
|
||||
@ -222,8 +222,7 @@ void send_data(config& cfg, connection connection_num)
|
||||
|
||||
if(res < int(value.size()+1)) {
|
||||
std::cerr << "sending data failed: " << res << "/" << value.size() << ": " << SDL_GetError() << "\n";
|
||||
disconnect(connection_num);
|
||||
throw error("Could not send data over socket");
|
||||
throw error("Could not send data over socket",connection_num);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,11 @@ void send_data(config& cfg, connection connection_num=0);
|
||||
|
||||
struct error
|
||||
{
|
||||
error(const std::string& msg) : message(msg) {}
|
||||
error(const std::string& msg, connection sock=0) : message(msg) {}
|
||||
std::string message;
|
||||
connection socket;
|
||||
|
||||
void disconnect() { if(socket) { network::disconnect(socket); } }
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user