improved simple_wml error exception handling and error logging

This commit is contained in:
Gunter Labes 2009-08-26 01:38:55 +00:00
parent da6efafc48
commit 31fa18d219
3 changed files with 74 additions and 61 deletions

View file

@ -35,6 +35,8 @@ static lg::log_domain log_server("server");
#define WRN_GAME LOG_STREAM(warn, log_server)
#define LOG_GAME LOG_STREAM(info, log_server)
#define DBG_GAME LOG_STREAM(debug, log_server)
static lg::log_domain log_config("config");
#define WRN_CONFIG LOG_STREAM(warn, log_config)
namespace wesnothd {
int game::id_num = 1;
@ -79,18 +81,13 @@ game::game(player_map& players, const network::connection host,
game::~game()
{
try {
save_replay();
save_replay();
user_vector users = all_game_users();
for (user_vector::const_iterator u = users.begin(); u != users.end(); ++u) {
remove_player(*u, false, true);
}
clear_history();
} catch (...) {
LOG_GAME << "Caught unknown error while destructing game:\t\""
<< name_ << "\" (" << id_ << ")\n";
user_vector users = all_game_users();
for (user_vector::const_iterator u = users.begin(); u != users.end(); ++u) {
remove_player(*u, false, true);
}
clear_history();
}
bool game::allow_observers() const {
@ -1213,12 +1210,17 @@ void game::send_history(const network::connection sock) const
delete *i;
}
simple_wml::document* doc = new simple_wml::document(buf.c_str(), simple_wml::INIT_STATIC);
const simple_wml::string_span& data = doc->output_compressed();
doc->compress();
network::send_raw_data(data.begin(), data.size(), sock,"game_history");
history_.clear();
history_.push_back(doc);
try {
simple_wml::document* doc = new simple_wml::document(buf.c_str(), simple_wml::INIT_STATIC);
const simple_wml::string_span& data = doc->output_compressed();
doc->compress();
network::send_raw_data(data.begin(), data.size(), sock,"game_history");
history_.clear();
history_.push_back(doc);
} catch (simple_wml::error& e) {
WRN_CONFIG << "simple_wml error: " << e.message << std::endl;
}
}
static bool is_invalid_filename_char(char c) {
@ -1260,16 +1262,21 @@ void game::save_replay() {
name << " (" << id_ << ").gz";
std::string replay_data_str = replay_data.str();
simple_wml::document replay(replay_data_str.c_str(), simple_wml::INIT_STATIC);
try {
simple_wml::document replay(replay_data_str.c_str(), simple_wml::INIT_STATIC);
std::string filename(name.str());
std::replace(filename.begin(), filename.end(), ' ', '_');
filename.erase(std::remove_if(filename.begin(), filename.end(), is_invalid_filename_char), filename.end());
DBG_GAME << "saving replay: " << filename << std::endl;
scoped_ostream os(ostream_file(replay_save_path_ + filename));
(*os) << replay.output_compressed();
if (!os->good()) {
LOG_GAME << "Could not save replay! (" << filename << ")\n";
std::string filename(name.str());
std::replace(filename.begin(), filename.end(), ' ', '_');
filename.erase(std::remove_if(filename.begin(), filename.end(), is_invalid_filename_char), filename.end());
DBG_GAME << "saving replay: " << filename << std::endl;
scoped_ostream os(ostream_file(replay_save_path_ + filename));
(*os) << replay.output_compressed();
if (!os->good()) {
ERR_GAME << "Could not save replay! (" << filename << ")\n";
}
} catch (simple_wml::error& e) {
WRN_CONFIG << "simple_wml error: " << e.message << std::endl;
}
}

View file

@ -685,7 +685,7 @@ void server::run() {
metrics_.service_request();
if(buf.empty()) {
std::cerr << "received empty packet\n";
WRN_SERVER << "received empty packet\n";
continue;
}
@ -702,6 +702,7 @@ void server::run() {
data_ptr->take_ownership_of_buffer(buf_ptr);
} catch (simple_wml::error& e) {
WRN_CONFIG << "simple_wml error in received data: " << e.message << std::endl;
send_error(sock, ("Invalid WML received: " + e.message).c_str());
delete [] buf_ptr;
continue;
@ -729,8 +730,6 @@ void server::run() {
metrics_.no_requests();
} catch(config::error& e) {
WRN_CONFIG << "Warning: error in received data: " << e.message << "\n";
} catch(simple_wml::error& e) {
WRN_CONFIG << "Warning: error in received data: " << e.message << "\n";
} catch(network::error& e) {
@ -1187,7 +1186,7 @@ void server::process_query(const network::connection sock,
<< "\tIP: "<< network::ip_address(sock)
<< "\tnick: "<< pl->second.name() << std::endl;
response << process_command(command.to_string(), pl->second.name());
LOG_SERVER << response.str();
LOG_SERVER << response.str() << std::endl;
}
} else if (command == "help" || command.empty()) {
response << help_msg;
@ -2081,8 +2080,8 @@ void server::process_data_game(const network::connection sock,
return;
// Everything below should only be processed if the game is already intialized.
} else if (!g->level_init()) {
WRN_SERVER << "Received unknown data from: " << pl->second.name()
<< " (socket:" << sock
WRN_SERVER << network::ip_address(sock) << "\tReceived unknown data from: "
<< pl->second.name() << " (socket:" << sock
<< ") while the scenario wasn't yet initialized.\n" << data.output();
return;
// If the host is sending the next scenario data.
@ -2306,8 +2305,9 @@ void server::process_data_game(const network::connection sock,
return;
}
WRN_SERVER << "Received unknown data from: " << pl->second.name()
<< ". (socket:" << sock << ")\n" << data.output();
WRN_SERVER << network::ip_address(sock) << "\tReceived unknown data from: "
<< pl->second.name() << " (socket:" << sock << ") in game: \""
<< g->name() << "\" (" << g->id() << ")\n" << data.output();
}
void server::delete_game(std::vector<wesnothd::game*>::iterator game_it) {

View file

@ -6,6 +6,11 @@
#include "simple_wml.hpp"
#include "../log.hpp"
static lg::log_domain log_config("config");
#define ERR_SWML LOG_STREAM(err, log_config)
namespace simple_wml {
namespace {
@ -54,33 +59,33 @@ char* uncompress_buffer(const string_span& input, string_span* span)
char* compress_buffer(const char* input, string_span* span)
{
std::string in(input);
std::istringstream stream(in);
boost::iostreams::filtering_stream<boost::iostreams::input> filter;
filter.push(boost::iostreams::gzip_compressor());
filter.push(stream);
std::vector<char> buf(in.size()*2 + 80);
const int len = filter.read(&buf[0], buf.size()).gcount();
assert(len < 128*1024*1024);
if((!filter.eof() && !filter.good()) || len == static_cast<int>(buf.size())) {
throw error("failed to compress");
}
buf.resize(len);
char* small_out;
try {
small_out = new char[len];
std::string in(input);
std::istringstream stream(in);
boost::iostreams::filtering_stream<boost::iostreams::input> filter;
filter.push(boost::iostreams::gzip_compressor());
filter.push(stream);
std::vector<char> buf(in.size()*2 + 80);
const int len = filter.read(&buf[0], buf.size()).gcount();
assert(len < 128*1024*1024);
if((!filter.eof() && !filter.good()) || len == static_cast<int>(buf.size())) {
throw error("failed to compress");
}
buf.resize(len);
char* small_out = new char[len];
memcpy(small_out, &buf[0], len);
*span = string_span(small_out, len);
assert(*small_out == 31);
return small_out;
} catch (std::bad_alloc& e) {
std::cerr << "ERROR: Trying to allocate " << len << " bytes.";
ERR_SWML << "ERROR: bad_alloc caught in compress_buffer() with input: '"
<< *input << "' " << e.what() << std::endl;
throw error("Bad allocation request in compress_buffer().");
}
*span = string_span(small_out, len);
assert(*small_out == 31);
return small_out;
}
} // namespace
@ -122,7 +127,7 @@ char* string_span::duplicate() const
error::error(const char* msg)
: message(msg)
{
std::cerr << "ERROR: '" << msg << "'\n";
ERR_SWML << "ERROR: '" << msg << "'\n";
}
std::ostream& operator<<(std::ostream& o, const string_span& s)
@ -201,7 +206,7 @@ node::node(document& doc, node* parent, const char** str, int depth) :
default: {
const char* end = strchr(s, '=');
if(end == NULL) {
std::cerr << "attribute: " << s << "\n";
ERR_SWML << "attribute: " << s << "\n";
throw error("could not find '=' after attribute");
}
@ -215,7 +220,7 @@ node::node(document& doc, node* parent, const char** str, int depth) :
}
if(*s != '"') {
std::cerr << "no quotes for attribute '" << name << "'\n";
ERR_SWML << "no quotes for attribute '" << name << "'\n";
throw error("did not find quotes around attribute");
}
@ -227,7 +232,7 @@ node::node(document& doc, node* parent, const char** str, int depth) :
}
if(end == NULL) {
std::cerr << "ATTR: '" << name << "' (((" << s << ")))\n";
ERR_SWML << "ATTR: '" << name << "' (((" << s << ")))\n";
throw error("did not find end of attribute");
}
@ -250,7 +255,7 @@ node::node(document& doc, node* parent, const char** str, int depth) :
string_span value(s, end - s);
if(attr_.empty() == false && !(attr_.back().first < name)) {
std::cerr << "attributes: '" << attr_.back().first << "' < '" << name << "'\n";
ERR_SWML << "attributes: '" << attr_.back().first << "' < '" << name << "'\n";
throw error("attributes not in order");
}
@ -956,7 +961,8 @@ const char* document::output()
try {
buf = new char[buf_size];
} catch (std::bad_alloc& e) {
std::cerr << "ERROR: Trying to allocate " << buf_size << " bytes.";
ERR_SWML << "ERROR: Trying to allocate " << buf_size << " bytes. "
<< e.what() << std::endl;
throw error("Bad allocation request in output().");
}
buffers_.push_back(buf);