Added network bandwidth usage statistics collection code for server

This commit is contained in:
Pauli Nieminen 2008-06-21 17:27:21 +00:00
parent 4aa84be8ec
commit cd49b14af2
6 changed files with 352 additions and 70 deletions

View file

@ -25,6 +25,8 @@
#include "network_worker.hpp"
#include "thread.hpp"
#include "filesystem.hpp"
#include "SDL_net.h"
#include <algorithm>
@ -32,6 +34,7 @@
#include <cerrno>
#include <queue>
#include <iostream>
#include <iomanip>
#include <set>
#include <vector>
#include <ctime>
@ -625,11 +628,19 @@ void queue_disconnect(network::connection sock)
disconnection_queue.push_back(sock);
}
connection receive_data(config& cfg, connection connection_num, unsigned int timeout)
connection receive_data(config& cfg, connection connection_num, unsigned int timeout
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* bandwidth_in
#endif
)
{
unsigned int start_ticks = SDL_GetTicks();
while(true) {
const connection res = receive_data(cfg,connection_num);
const connection res = receive_data(cfg,connection_num
#ifdef BANDWIDTH_MONITOR
,(bool*)0 , bandwidth_in
#endif
);
if(res != 0) {
return res;
}
@ -647,7 +658,11 @@ connection receive_data(config& cfg, connection connection_num, unsigned int tim
return 0;
}
connection receive_data(config& cfg, connection connection_num, bool* gzipped)
connection receive_data(config& cfg, connection connection_num, bool* gzipped
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* bandwidth_in
#endif
)
{
if(!socket_set) {
return 0;
@ -702,7 +717,18 @@ connection receive_data(config& cfg, connection connection_num, bool* gzipped)
TCPsocket sock = connection_num == 0 ? 0 : get_socket(connection_num);
TCPsocket s = sock;
sock = network_worker_pool::get_received_data(sock,cfg, gzipped);
#ifdef BANDWIDTH_MONITOR
bandwidth_in_ptr temp;
if (!bandwidth_in)
{
bandwidth_in = &temp;
}
#endif
sock = network_worker_pool::get_received_data(sock,cfg, gzipped
#ifdef BANDWIDTH_MONITOR
, *bandwidth_in
#endif
);
if (sock == NULL) {
if (!is_server() && last_ping != 0 && ping_timeout != 0)
{
@ -746,7 +772,11 @@ connection receive_data(config& cfg, connection connection_num, bool* gzipped)
return result;
}
connection receive_data(std::vector<char>& buf)
connection receive_data(std::vector<char>& buf
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* bandwidth_in
#endif
)
{
if(!socket_set) {
return 0;
@ -804,6 +834,18 @@ connection receive_data(std::vector<char>& buf)
return 0;
}
#ifdef BANDWIDTH_MONITOR
{
bandwidth_in_ptr temp;
if (!bandwidth_in)
{
bandwidth_in = &temp;
}
const int headers = 5;
bandwidth_in->reset(new network::bandwidth_in(buf.size() + headers));
}
#endif
SDLNet_TCP_AddSocket(socket_set,sock);
connection result = 0;
@ -818,8 +860,137 @@ connection receive_data(std::vector<char>& buf)
waiting_sockets.insert(result);
return result;
}
#ifdef BANDWIDTH_MONITOR
struct bandwidth_stats {
int out_packets;
int out_bytes;
int in_packets;
int in_bytes;
int day;
const static size_t type_width = 16;
const static size_t packet_width = 7;
const static size_t bytes_width = 10;
bandwidth_stats& operator+=(const bandwidth_stats& a)
{
out_packets += a.out_packets;
out_bytes += a.out_bytes;
in_packets += a.in_packets;
in_bytes += a.in_bytes;
void send_file(const std::string& filename, connection connection_num)
return *this;
}
};
typedef std::map<const std::string, bandwidth_stats> bandwidth_map;
typedef std::vector<bandwidth_map> hour_stats_vector;
hour_stats_vector hour_stats(24);
static bandwidth_map::iterator add_bandwidth_entry(const std::string packet_type)
{
time_t now = time(0);
struct tm * timeinfo = localtime(&now);
int hour = timeinfo->tm_hour;
int day = timeinfo->tm_mday;
assert(hour < 24 && hour >= 0);
std::pair<bandwidth_map::iterator,bool> insertion = hour_stats[hour].insert(std::make_pair(packet_type, bandwidth_stats()));
if (!insertion.second && day != inserted->second.day)
{
// clear previuos day stats
hour[hour].clear();
//insert again to cleared map
insertion = hour_stats[hour].insert(std::make_pair(packet_type, bandwidth_stats()));
}
bandwidth_map::iterator inserted = insertion.first;
inserted->second.day = day;
return inserted;
}
typedef boost::shared_ptr<bandwidth_stats> bandwidth_stats_ptr;
struct bandwidth_stats_output {
bandwidth_stats_output(std::stringstream& ss) : ss_(ss), totals_(new bandwidth_stats())
{}
void operator()(const bandwidth_map::value_type& stats)
{
// name
ss_ << " " << std::setw(bandwidth_stats::type_width) << stats.first << "| "
<< std::setw(bandwidth_stats::packet_width)<< stats.second.out_packets << "| "
<< std::setw(bandwidth_stats::bytes_width) << stats.second.out_bytes/1024 << "| "
<< std::setw(bandwidth_stats::packet_width)<< stats.second.in_packets << "| "
<< std::setw(bandwidth_stats::bytes_width) << stats.second.in_bytes/1024 << "\n";
*totals_ += stats.second;
}
void output_totals()
{
(*this)(std::make_pair(std::string("total"), *totals_));
}
private:
std::stringstream& ss_;
bandwidth_stats_ptr totals_;
};
std::string get_bandwidth_stats_all()
{
std::string result;
for (int hour = 0; hour < 24; ++hour)
{
result += get_bandwidth_stats(hour);
}
return result;
}
std::string get_bandwidth_stats()
{
time_t now = time(0);
struct tm * timeinfo = localtime(&now);
int hour = timeinfo->tm_hour - 1;
if (hour < 0)
hour = 23;
return get_bandwidth_stats(hour);
}
std::string get_bandwidth_stats(int hour)
{
assert(hour < 24 && hour >= 0);
std::stringstream ss;
ss << "Hour stat starting from " << hour << "\n " << std::left << std::setw(bandwidth_stats::type_width) << "Type of packet" << "| "
<< std::setw(bandwidth_stats::packet_width)<< "out #" << "| "
<< std::setw(bandwidth_stats::bytes_width) << "out kb" << "| "
<< std::setw(bandwidth_stats::packet_width)<< "in #" << "| "
<< std::setw(bandwidth_stats::bytes_width) << "in kb" << "\n";
bandwidth_stats_output outputer(ss);
std::for_each(hour_stats[hour].begin(), hour_stats[hour].end(), outputer);
outputer.output_totals();
return ss.str();
}
void add_bandwidth_out(const std::string packet_type, size_t len)
{
bandwidth_map::iterator itor = add_bandwidth_entry(packet_type);
itor->second.out_bytes += len;
++(itor->second.out_packets);
}
void add_bandwidth_in(const std::string packet_type, size_t len)
{
bandwidth_map::iterator itor = add_bandwidth_entry(packet_type);
itor->second.in_bytes += len;
++(itor->second.in_packets);
}
bandwidth_in::~bandwidth_in()
{
add_bandwidth_in(type_, len_);
}
#endif
void send_file(const std::string& filename, connection connection_num, const std::string packet_type
)
{
assert(connection_num > 0);
if(bad_sockets.count(connection_num) || bad_sockets.count(0)) {
@ -833,6 +1004,10 @@ void send_file(const std::string& filename, connection connection_num)
return;
}
#ifdef BANDWIDTH_MONITOR
const int packet_headers = 5;
add_bandwidth_out(packet_type, file_size(filename) + packet_headers);
#endif
network_worker_pool::queue_file(info->second.sock, filename);
}
@ -840,7 +1015,8 @@ void send_file(const std::string& filename, connection connection_num)
//! @todo Note the gzipped parameter should be removed later, we want to send
//! all data gzipped. This can be done once the campaign server is also updated
//! to work with gzipped data.
void send_data(const config& cfg, connection connection_num, const bool gzipped)
void send_data(const config& cfg, connection connection_num, const bool gzipped, const std::string packet_type
)
{
DBG_NW << "in send_data()...\n";
@ -858,7 +1034,11 @@ void send_data(const config& cfg, connection connection_num, const bool gzipped)
for(sockets_list::const_iterator i = sockets.begin();
i != sockets.end(); ++i) {
DBG_NW << "server socket: " << server_socket << "\ncurrent socket: " << *i << "\n";
send_data(cfg,*i, gzipped);
send_data(cfg,*i, gzipped
#ifdef BANDWIDTH_MONITOR
, packet_type
#endif
);
}
return;
}
@ -871,10 +1051,15 @@ void send_data(const config& cfg, connection connection_num, const bool gzipped)
}
LOG_NW << "SENDING to: " << connection_num << ": " << cfg;
network_worker_pool::queue_data(info->second.sock, cfg, gzipped);
network_worker_pool::queue_data(info->second.sock, cfg, gzipped
#ifdef BANDWIDTH_MONITOR
, packet_type
#endif
);
}
void send_raw_data(const char* buf, int len, connection connection_num)
void send_raw_data(const char* buf, int len, connection connection_num, const std::string packet_type
)
{
if(len == 0) {
return;
@ -887,7 +1072,8 @@ void send_raw_data(const char* buf, int len, connection connection_num)
if(!connection_num) {
for(sockets_list::const_iterator i = sockets.begin();
i != sockets.end(); ++i) {
send_raw_data(buf, len, connection_num);
send_raw_data(buf, len, connection_num, packet_type
);
}
return;
}
@ -898,6 +1084,10 @@ void send_raw_data(const char* buf, int len, connection connection_num)
<< "\tnot found in connection_map. Not sending...\n";
return;
}
#ifdef BANDWIDTH_MONITOR
const int packet_headers = 5;
add_bandwidth_out(packet_type, len + packet_headers);
#endif
network_worker_pool::queue_raw_data(info->second.sock, buf, len);
}
@ -908,14 +1098,19 @@ void process_send_queue(connection, size_t)
}
//! @todo Note the gzipped parameter should be removed later.
void send_data_all_except(const config& cfg, connection connection_num, const bool gzipped)
void send_data_all_except(const config& cfg, connection connection_num, const bool gzipped, const std::string packet_type
)
{
for(sockets_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) {
if(*i == connection_num) {
continue;
}
send_data(cfg,*i, gzipped);
send_data(cfg,*i, gzipped
#ifdef BANDWIDTH_MONITOR
, packet_type
#endif
);
}
}

View file

@ -17,6 +17,10 @@
#ifndef NETWORK_HPP_INCLUDED
#define NETWORK_HPP_INCLUDED
/**
* Enable bandwidth stats
**/
//#define BANDWIDTH_MONITOR
class config;
@ -25,6 +29,8 @@ class config;
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
namespace threading
{
class waiter;
@ -121,6 +127,35 @@ bool disconnect(connection connection_num=0, bool force=false);
//! on the given connection (and presumably then the handling of the error
//! will include closing the connection).
void queue_disconnect(connection connection_num);
#ifdef BANDWIDTH_MONITOR
std::string get_bandwidth_stats();
std::string get_bandwidth_stats_all();
std::string get_bandwidth_stats(int hour);
void add_bandwidth_out(const std::string packet_type, size_t len);
void add_bandwidth_in(const std::string packet_type, size_t len);
struct bandwidth_in {
bandwidth_in(int len) : len_(len), type_("unknown") {}
~bandwidth_in();
// {
// network::add_bandwidth_in(type_, len_);
// }
void set_type(const std::string& type)
{
type_ = type;
}
private:
int len_;
std::string type_;
};
typedef boost::shared_ptr<bandwidth_in> bandwidth_in_ptr;
#endif
//! Function to receive data from either a certain connection,
//! or all connections if connection_num is 0.
@ -129,18 +164,30 @@ void queue_disconnect(connection connection_num);
//! Returns the connection that data was received from,
//! or 0 if timeout occurred.
//! Throws error if an error occurred.
connection receive_data(config& cfg, connection connection_num=0, bool* gzipped = 0);
connection receive_data(config& cfg, connection connection_num, unsigned int timeout);
connection receive_data(std::vector<char>& buf);
connection receive_data(config& cfg, connection connection_num=0, bool* gzipped = 0
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* b = 0
#endif
);
connection receive_data(config& cfg, connection connection_num, unsigned int timeout
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* b = 0
#endif
);
connection receive_data(std::vector<char>& buf
#ifdef BANDWIDTH_MONITOR
, bandwidth_in_ptr* = 0
#endif
);
void send_file(const std::string&, connection);
void send_file(const std::string&, connection, const std::string packet_type = "unknown");
//! Function to send data down a given connection,
//! or broadcast to all peers if connection_num is 0.
//! Throws error.
void send_data(const config& cfg, connection connection_num /*= 0*/, const bool gzipped);
void send_data(const config& cfg, connection connection_num /*= 0*/, const bool gzipped, const std::string packet_type = "unknown");
void send_raw_data(const char* buf, int len, connection connection_num);
void send_raw_data(const char* buf, int len, connection connection_num, const std::string packet_type = "unknown");
//! Function to send any data that is in a connection's send_queue,
//! up to a maximum of 'max_size' bytes --
@ -148,7 +195,8 @@ void send_raw_data(const char* buf, int len, connection connection_num);
void process_send_queue(connection connection_num=0, size_t max_size=0);
//! Function to send data to all peers except 'connection_num'.
void send_data_all_except(const config& cfg, connection connection_num, const bool gzipped);
void send_data_all_except(const config& cfg, connection connection_num, const bool gzipped, const std::string packet_type = "unknown"
);
//! Function to get the remote ip address of a socket.
std::string ip_address(connection connection_num);

View file

@ -806,7 +806,11 @@ void receive_data(TCPsocket sock)
}
}
TCPsocket get_received_data(TCPsocket sock, config& cfg, bool* gzipped)
TCPsocket get_received_data(TCPsocket sock, config& cfg, bool* gzipped
#ifdef BANDWIDTH_MONITOR
,network::bandwidth_in_ptr& bandwidth_in
#endif
)
{
assert(!raw_data_only);
const threading::lock lock_received(*received_mutex);
@ -837,6 +841,9 @@ TCPsocket get_received_data(TCPsocket sock, config& cfg, bool* gzipped)
if (gzipped)
*gzipped = buf->gzipped;
received_data_queue.erase(itor);
#ifdef BANDWIDTH_MONITOR
bandwidth_in.reset(new network::bandwidth_in((*itor)->raw_buffer.size()));
#endif
delete buf;
return res;
}
@ -890,13 +897,20 @@ void queue_raw_data(TCPsocket sock, const char* buf, int len)
queue_buffer(sock, queued_buf);
}
void queue_data(TCPsocket sock,const config& buf, const bool gzipped)
void queue_data(TCPsocket sock,const config& buf, const bool gzipped
#ifdef BANDWIDTH_MONITOR
, const std::string& packet_type
#endif
)
{
DBG_NW << "queuing data...\n";
buffer* queued_buf = new buffer(sock);
output_to_buffer(sock, buf, queued_buf->stream, gzipped);
queued_buf->gzipped = gzipped;
#ifdef BANDWIDTH_MONITOR
network::add_bandwidth_out(packet_type, queued_buf->stream.str().size());
#endif
queue_buffer(sock, queued_buf);
}

View file

@ -51,13 +51,21 @@ void set_raw_data_only();
//! Function to asynchronously received data to the given socket.
void receive_data(TCPsocket sock);
TCPsocket get_received_data(TCPsocket sock, config& cfg, bool* gzipped = 0);
TCPsocket get_received_data(TCPsocket sock, config& cfg, bool* gzipped
#ifdef BANDWIDTH_MONITOR
, network::bandwidth_in_ptr&
#endif
);
TCPsocket get_received_data(std::vector<char>& buf);
void queue_file(TCPsocket sock, const std::string&);
void queue_raw_data(TCPsocket sock, const char* buf, int len);
void queue_data(TCPsocket sock, const config& buf, const bool gzipped);
void queue_data(TCPsocket sock, const config& buf, const bool gzipped
#ifdef BANDWIDTH_MONITOR
, const std::string& packet_type
#endif
);
bool is_locked(const TCPsocket sock);
bool close_socket(TCPsocket sock, bool force=false);
TCPsocket detect_error();

View file

@ -214,7 +214,7 @@ bool game::take_side(const player_map::const_iterator user)
// Tell the host which side the new player should take.
simple_wml::string_span data = cfg.output_compressed();
network::send_raw_data(data.begin(), data.size(), owner_);
network::send_raw_data(data.begin(), data.size(), owner_, "game");
DBG_GAME << "take_side: took side " << side_num << " because the name matched\n";
DBG_GAME << debug_player_info();
return true;
@ -236,7 +236,7 @@ bool game::take_side(const player_map::const_iterator user)
cfg.root().set_attr_dup("side", (**side)["side"]);
// Tell the host which side the new player should take.
simple_wml::string_span data = cfg.output_compressed();
network::send_raw_data(data.begin(), data.size(), owner_);
network::send_raw_data(data.begin(), data.size(), owner_, "game");
DBG_GAME << "take_side: took the first free network side which was " << side_num << "\n";
DBG_GAME << debug_player_info();
return true;
@ -469,7 +469,7 @@ void game::transfer_ai_sides() {
drop.root().set_attr("side_drop", side_drop.c_str());
drop.root().set_attr("controller", "ai");
const simple_wml::string_span data = drop.output_compressed();
network::send_raw_data(data.begin(), data.size(), owner_);
network::send_raw_data(data.begin(), data.size(), owner_, "game");
sides_[side] = owner_;
}
if (ai_transfer) {
@ -488,7 +488,7 @@ void game::notify_new_host(){
cfg_host_transfer.set_attr("name", owner_name.c_str());
cfg_host_transfer.set_attr("value", "1");
const simple_wml::string_span data = cfg.output_compressed();
network::send_raw_data(data.begin(), data.size(), owner_);
network::send_raw_data(data.begin(), data.size(), owner_,"game");
send_and_record_server_message((owner_name
+ " has been chosen as the new host.").c_str());
}
@ -612,7 +612,7 @@ network::connection game::kick_member(const simple_wml::node& kick,
// Tell the user to leave the game.
static simple_wml::document leave_game("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
static const simple_wml::string_span leave_game_data = leave_game.output_compressed();
network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first);
network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first,"game");
remove_player(user->first);
return user->first;
}
@ -653,7 +653,7 @@ network::connection game::ban_user(const simple_wml::node& ban,
//tell the user to leave the game.
static simple_wml::document leave_game("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
static const simple_wml::string_span leave_game_data = leave_game.output_compressed();
network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first);
network::send_raw_data(leave_game_data.begin(), leave_game_data.size(), user->first,"game");
remove_player(user->first);
return user->first;
}
@ -900,12 +900,12 @@ void game::add_player(const network::connection player, bool observer) {
// Send the user the game data.
//std::cerr << "SENDING LEVEL {{{" << level_.output() << "}}}\n";
simple_wml::string_span level_data = level_.output_compressed();
network::send_raw_data(level_data.begin(), level_data.size(), player);
network::send_raw_data(level_data.begin(), level_data.size(), player,"game");
if(started_) {
//tell this player that the game has started
static simple_wml::document start_game_doc("[start_game]\n[/start_game]\n", simple_wml::INIT_COMPRESSED);
static const simple_wml::string_span start_game = start_game_doc.output_compressed();
network::send_raw_data(start_game.begin(), start_game.size(), player);
network::send_raw_data(start_game.begin(), start_game.size(), player,"game");
// Send observer join of all the observers in the game to the new player
// only once the game started. The client forgets about it anyway
// otherwise.
@ -1043,7 +1043,7 @@ void game::load_next_scenario(const player_map::const_iterator user) const {
simple_wml::document cfg_scenario;
level_.root().copy_into(cfg_scenario.root().add_child("next_scenario"));
simple_wml::string_span data = cfg_scenario.output_compressed();
network::send_raw_data(data.begin(), data.size(), user->first);
network::send_raw_data(data.begin(), data.size(), user->first, "game");
// Send the player the history of the game to-date.
send_history(user->first);
// Send observer join of all the observers in the game to the user.
@ -1056,7 +1056,7 @@ void game::send_data(simple_wml::document& data, const network::connection exclu
const user_vector& users = all_game_users();
for(user_vector::const_iterator i = users.begin(); i != users.end(); ++i) {
if (*i != exclude) {
network::send_raw_data(s.begin(), s.size(), *i);
network::send_raw_data(s.begin(), s.size(), *i, "user_diff");
}
}
}
@ -1064,7 +1064,7 @@ void game::send_data(simple_wml::document& data, const network::connection exclu
void game::send_to_one(simple_wml::document& data, const network::connection sock) const
{
simple_wml::string_span s = data.output_compressed();
network::send_raw_data(s.begin(), s.size(), sock);
network::send_raw_data(s.begin(), s.size(), sock,"game");
}
void game::send_data_team(simple_wml::document& data,
@ -1074,7 +1074,7 @@ void game::send_data_team(simple_wml::document& data,
simple_wml::string_span s = data.output_compressed();
for(user_vector::const_iterator i = players_.begin(); i != players_.end(); ++i) {
if(*i != exclude && is_on_team(team,*i)) {
network::send_raw_data(s.begin(), s.size(), *i);
network::send_raw_data(s.begin(), s.size(), *i, "game");
}
}
}
@ -1083,7 +1083,7 @@ void game::send_data_observers(simple_wml::document& data, const network::connec
simple_wml::string_span s = data.output_compressed();
for(user_vector::const_iterator i = observers_.begin(); i != observers_.end(); ++i) {
if (*i != exclude) {
network::send_raw_data(s.begin(), s.size(), *i);
network::send_raw_data(s.begin(), s.size(), *i,"game");
}
}
}
@ -1127,7 +1127,7 @@ void game::send_observerjoins(const network::connection sock) const {
} else {
// Send to the (new) user.
const simple_wml::string_span& data = cfg.output_compressed();
network::send_raw_data(data.begin(), data.size(), sock);
network::send_raw_data(data.begin(), data.size(), sock,"game");
}
}
}
@ -1163,7 +1163,7 @@ void game::send_history(const network::connection sock) const
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);
network::send_raw_data(data.begin(), data.size(), sock,"game_history");
history_.clear();
history_.push_back(doc);
}

View file

@ -113,10 +113,10 @@ namespace {
// we take profiling info on every n requests
int request_sample_frequency = 1;
void send_doc(simple_wml::document& doc, network::connection connection)
void send_doc(simple_wml::document& doc, network::connection connection, std::string type = "unknown")
{
simple_wml::string_span s = doc.output_compressed();
network::send_raw_data(s.begin(), s.size(), connection);
network::send_raw_data(s.begin(), s.size(), connection, type);
}
void make_add_diff(const simple_wml::node& src, const char* gamelist,
@ -322,7 +322,7 @@ void server::send_error(network::connection sock, const char* msg) const
simple_wml::document doc;
doc.root().add_child("error").set_attr("message", msg);
simple_wml::string_span output = doc.output_compressed();
network::send_raw_data(output.begin(), output.size(), sock);
network::send_raw_data(output.begin(), output.size(), sock, "error");
}
void server::send_error_dup(network::connection sock, const std::string& msg) const
@ -330,7 +330,7 @@ void server::send_error_dup(network::connection sock, const std::string& msg) co
simple_wml::document doc;
doc.root().add_child("error").set_attr_dup("message", msg.c_str());
simple_wml::string_span output = doc.output_compressed();
network::send_raw_data(output.begin(), output.size(), sock);
network::send_raw_data(output.begin(), output.size(), sock, "error");
}
config server::read_config() const {
@ -489,7 +489,7 @@ void server::run() {
for (player_map::const_iterator i = players_.begin();
i != players_.end(); ++i)
{
network::send_data(ping, i->first, true);
network::send_data(ping, i->first, true, "ping");
}
last_ping_ = now;
}
@ -510,7 +510,7 @@ void server::run() {
} else {
DBG_SERVER << ip << "\tnew connection accepted. (socket: "
<< sock << ")\n";
send_doc(version_query_response_, sock);
send_doc(version_query_response_, sock,"command");
not_logged_in_.add_player(sock, true);
}
}
@ -518,7 +518,14 @@ void server::run() {
static int sample_counter = 0;
std::vector<char> buf;
while ((sock = network::receive_data(buf)) != network::null_connection) {
#ifdef BANDWIDTH_MONITOR
network::bandwidth_in_ptr bandwidth_type;
#endif
while ((sock = network::receive_data(buf
#ifdef BANDWIDTH_MONITOR
, &bandwidth_type
#endif
)) != network::null_connection) {
metrics_.service_request();
if(buf.empty()) {
@ -553,6 +560,9 @@ void server::run() {
process_data(sock, data);
#ifdef BANDWIDTH_MONITOR
bandwidth_type->set_type("command");
#endif
if(sample) {
const clock_t after_processing = get_cpu_time(sample);
metrics_.record_sample(data.root().first_child(),
@ -693,7 +703,7 @@ void server::process_login(const network::connection sock,
LOG_SERVER << network::ip_address(sock)
<< "\tplayer joined using accepted version " << version_str
<< ":\ttelling them to log in.\n";
send_doc(login_response_, sock);
send_doc(login_response_, sock, "command");
return;
}
std::map<std::string,config>::const_iterator config_it;
@ -711,7 +721,7 @@ void server::process_login(const network::connection sock,
<< ":" << config_it->second["port"] << "\n";
config response;
response.add_child("redirect",config_it->second);
network::send_data(response, sock, true);
network::send_data(response, sock, true, "redirect");
return;
}
// Check if it's a version we should start a proxy for.
@ -743,7 +753,7 @@ void server::process_login(const network::connection sock,
ERR_SERVER << "ERROR: This server doesn't accept any versions at all.\n";
response["version"] = "null";
}
network::send_data(response, sock, true);
network::send_data(response, sock, true, "error");
return;
}
@ -786,7 +796,7 @@ void server::process_login(const network::connection sock,
}
}
send_doc(join_lobby_response_, sock);
send_doc(join_lobby_response_, sock, "join_lobby");
simple_wml::node& player_cfg = games_and_users_list_.root().add_child("user");
const player new_player(username, player_cfg, default_max_messages_,
@ -797,7 +807,7 @@ void server::process_login(const network::connection sock,
lobby_.add_player(sock, true);
// Send the new player the entire list of games and players
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
if (motd_ != "") {
lobby_.send_server_message(motd_.c_str(), sock);
@ -839,7 +849,7 @@ void server::process_query(const network::connection sock,
} else if (command == "status") {
response << process_command(command.to_string() + " " + pl->second.name());
} else if (command == "status " + pl->second.name() || command == "metrics"
|| command == "motd" || command == "wml" || command == "netstats") {
|| command == "motd" || command == "wml" || command == "netstats" || command == "netstats all") {
response << process_command(command.to_string());
} else if (command == admin_passwd_) {
LOG_SERVER << "New Admin recognized:" << "\tIP: "
@ -922,6 +932,12 @@ std::string server::process_command(const std::string& query) {
out << "Network stats:\nPending send buffers: "
<< stats.npending_sends << "\nBytes in buffers: "
<< stats.nbytes_pending_sends << "\n";
#ifdef BANDWIDTH_MONITOR
if (parameters == "all")
out << network::get_bandwidth_stats_all();
else
out << network::get_bandwidth_stats(); // stats from previuos hour
#endif
} else if (command == "msg" || command == "lobbymsg") {
if (parameters == "") {
return "You must type a message.";
@ -1079,7 +1095,7 @@ void server::process_whisper(const network::connection sock,
"message=\"Invalid number of arguments\"\n"
"sender=\"server\"\n"
"[/message]\n", simple_wml::INIT_COMPRESSED);
send_doc(data, sock);
send_doc(data, sock, "error");
return;
}
const player_map::const_iterator pl = players_.find(sock);
@ -1109,7 +1125,7 @@ void server::process_whisper(const network::connection sock,
simple_wml::document cwhisper;
whisper.copy_into(cwhisper.root().add_child("whisper"));
send_doc(cwhisper, i->first);
send_doc(cwhisper, i->first, "command");
return;
}
@ -1123,7 +1139,7 @@ void server::process_whisper(const network::connection sock,
}
msg.set_attr("sender", "server");
send_doc(data, sock);
send_doc(data, sock, "error");
}
void server::process_data_lobby(const network::connection sock,
@ -1140,9 +1156,9 @@ void server::process_data_lobby(const network::connection sock,
if (data.root().child("create_game")) {
if (graceful_restart) {
static simple_wml::document leave_game_doc("[leave_game]\n[/leave_game]\n", simple_wml::INIT_COMPRESSED);
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock,"command");
lobby_.send_server_message("This server is shutting down. You aren't allowed to make new games. Please reconnect to the new server.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
}
const std::string game_name = (*data.root().child("create_game"))["name"].to_string();
@ -1180,41 +1196,41 @@ void server::process_data_lobby(const network::connection sock,
if (g == games_.end()) {
WRN_SERVER << network::ip_address(sock) << "\t" << pl->second.name()
<< "\tattempted to join unknown game:\t" << game_id << ".\n";
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock, "command");
lobby_.send_server_message("Attempt to join unknown game.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
} else if ((*g)->player_is_banned(sock)) {
DBG_SERVER << network::ip_address(sock) << "\tReject banned player: "
<< pl->second.name() << "\tfrom game:\t\"" << (*g)->name()
<< "\" (" << game_id << ").\n";
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock, "command");
lobby_.send_server_message("You are banned from this game.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
} else if(!observer && !(*g)->password_matches(password)) {
WRN_SERVER << network::ip_address(sock) << "\t" << pl->second.name()
<< "\tattempted to join game:\t\"" << (*g)->name() << "\" ("
<< game_id << ") with bad password\n";
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock, "command");
lobby_.send_server_message("Incorrect password.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
} else if (observer && !(*g)->allow_observers()) {
WRN_SERVER << network::ip_address(sock) << "\t" << pl->second.name()
<< "\tattempted to observe game:\t\"" << (*g)->name() << "\" ("
<< game_id << ") which doesn't allow observers.\n";
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock, "command");
lobby_.send_server_message("Attempt to observe a game that doesn't allow observers.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
} else if (!(*g)->level_init()) {
WRN_SERVER << network::ip_address(sock) << "\t" << pl->second.name()
<< "\tattempted to join uninitialized game:\t\"" << (*g)->name()
<< "\" (" << game_id << ").\n";
send_doc(leave_game_doc, sock);
send_doc(leave_game_doc, sock, "command");
lobby_.send_server_message("Attempt to observe a game that doesn't allow observers.", sock);
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
return;
}
LOG_SERVER << network::ip_address(sock) << "\t" << pl->second.name()
@ -1244,7 +1260,7 @@ void server::process_data_lobby(const network::connection sock,
// Player requests update of lobby content,
// for example when cancelling the create game dialog
if (data.child("refresh_lobby")) {
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
}
}
@ -1502,7 +1518,7 @@ void server::process_data_game(const network::connection sock,
}
// Send the player who has quit the gamelist.
send_doc(games_and_users_list_, sock);
send_doc(games_and_users_list_, sock, "lobby_list");
}
return;
// If this is data describing side changes by the host.
@ -1555,7 +1571,7 @@ void server::process_data_game(const network::connection sock,
update_game_in_lobby(g, user);
}
// Send the removed user the lobby game list.
send_doc(games_and_users_list_, user);
send_doc(games_and_users_list_, user, "lobby_list");
// FIXME: should also send a user diff to the lobby
// to mark this player as available for others
}
@ -1677,6 +1693,7 @@ int main(int argc, char** argv) {
std::string config_file;
#ifndef FIFODIR
# warning "No FIFODIR set"
# define FIFODIR "/var/run/wesnothd"
#endif
std::string fifo_path = std::string(FIFODIR) + "/socket";