added new server commands to kick, ban, view status
This commit is contained in:
parent
42cd7927e6
commit
b2c1ce5239
3 changed files with 134 additions and 9 deletions
|
@ -21,7 +21,8 @@ namespace {
|
|||
//the same, so it's all seamless to the user
|
||||
struct connection_details {
|
||||
connection_details(TCPsocket sock, const std::string& host, int port)
|
||||
: sock(sock), host(host), port(port), remote_handle(0)
|
||||
: sock(sock), host(host), port(port), remote_handle(0),
|
||||
connected_at(SDL_GetTicks()), sent(0), received(0)
|
||||
{}
|
||||
|
||||
TCPsocket sock;
|
||||
|
@ -31,6 +32,9 @@ struct connection_details {
|
|||
//the remote handle is the handle assigned to this connection by the remote host.
|
||||
//is 0 before a handle has been assigned.
|
||||
int remote_handle;
|
||||
|
||||
int connected_at;
|
||||
int sent, received;
|
||||
};
|
||||
|
||||
typedef std::map<network::connection,connection_details> connection_map;
|
||||
|
@ -110,6 +114,16 @@ std::set<network::connection> bad_sockets;
|
|||
|
||||
namespace network {
|
||||
|
||||
connection_stats::connection_stats(int sent, int received, int connected_at)
|
||||
: bytes_sent(sent), bytes_received(received), time_connected(SDL_GetTicks() - connected_at)
|
||||
{}
|
||||
|
||||
connection_stats get_connection_stats(connection connection_num)
|
||||
{
|
||||
connection_details& details = get_connection_details(connection_num);
|
||||
return connection_stats(details.sent,details.received,details.connected_at);
|
||||
}
|
||||
|
||||
const connection null_connection = 0;
|
||||
|
||||
error::error(const std::string& msg, connection sock) : message(msg), socket(sock)
|
||||
|
@ -385,7 +399,8 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
|
|||
}
|
||||
|
||||
for(sockets_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) {
|
||||
const TCPsocket sock = get_socket(*i);
|
||||
connection_details& details = get_connection_details(*i);
|
||||
const TCPsocket sock = details.sock;
|
||||
if(SDLNet_SocketReady(sock)) {
|
||||
|
||||
//see if this socket is still waiting for it to be assigned its remote handle
|
||||
|
@ -413,6 +428,8 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
|
|||
throw error("Remote host disconnected",*i);
|
||||
}
|
||||
|
||||
details.received += len;
|
||||
|
||||
len = SDLNet_Read32(num_buf);
|
||||
|
||||
std::cerr << "received packet length: " << len << "\n";
|
||||
|
@ -443,6 +460,8 @@ connection receive_data(config& cfg, connection connection_num, int timeout)
|
|||
throw error("remote host disconnected",*i);
|
||||
}
|
||||
|
||||
details.received += nbytes;
|
||||
|
||||
buf.upto += nbytes;
|
||||
std::cerr << "received " << nbytes << "=" << buf.upto << "/" << buf.buf.size() << "\n";
|
||||
|
||||
|
@ -568,7 +587,8 @@ void process_send_queue(connection connection_num, size_t max_size)
|
|||
max_size = 8;
|
||||
}
|
||||
|
||||
const TCPsocket sock = get_socket(connection_num);
|
||||
connection_details& details = get_connection_details(connection_num);
|
||||
const TCPsocket sock = details.sock;
|
||||
|
||||
std::pair<send_queue_map::iterator,send_queue_map::iterator> itor = send_queue.equal_range(connection_num);
|
||||
if(itor.first != itor.second) {
|
||||
|
@ -591,6 +611,7 @@ void process_send_queue(connection connection_num, size_t max_size)
|
|||
std::cerr << "sent.\n";
|
||||
|
||||
upto += res;
|
||||
details.sent += res;
|
||||
|
||||
//if we've now sent the entire item, erase it from the send queue
|
||||
if(upto == buf.size()) {
|
||||
|
|
|
@ -107,6 +107,16 @@ std::string ip_address(connection connection_num);
|
|||
//function to see the number of bytes being processed on the current socket
|
||||
std::pair<int,int> current_transfer_stats();
|
||||
|
||||
struct connection_stats
|
||||
{
|
||||
connection_stats(int sent, int received, int connected_at);
|
||||
|
||||
int bytes_sent, bytes_received;
|
||||
int time_connected;
|
||||
};
|
||||
|
||||
connection_stats get_connection_stats(connection connection_num);
|
||||
|
||||
struct error
|
||||
{
|
||||
error(const std::string& msg="", connection sock=0);
|
||||
|
|
|
@ -86,6 +86,10 @@ private:
|
|||
time_t last_stats_;
|
||||
|
||||
input_stream& input_;
|
||||
|
||||
bool is_ip_banned(const std::string& ip);
|
||||
std::string ban_ip(const std::string& mask);
|
||||
std::vector<std::string> bans_;
|
||||
};
|
||||
|
||||
server::server(int port, input_stream& input) : net_manager_(), server_(port), not_logged_in_(players_), lobby_players_(players_), last_stats_(time(NULL)), input_(input)
|
||||
|
@ -94,6 +98,34 @@ server::server(int port, input_stream& input) : net_manager_(), server_(port), n
|
|||
login_response_["version"] = game_config::version;
|
||||
}
|
||||
|
||||
bool server::is_ip_banned(const std::string& ip)
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator i = bans_.begin(); i != bans_.end(); ++i) {
|
||||
std::cerr << "comparing for ban '" << *i << "' vs '" << ip << "'\n";
|
||||
const std::string::const_iterator itor = std::mismatch(i->begin(),i->end(),ip.c_str()).first;
|
||||
if(itor == i->end() && i->size() == ip.size() || itor != i->end() && *itor == '*') {
|
||||
std::cerr << "is banned\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::cerr << "not banned\n";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string server::ban_ip(const std::string& mask)
|
||||
{
|
||||
const std::string::const_iterator asterisk = std::find(mask.begin(),mask.end(),'*');
|
||||
if(asterisk != mask.end() && asterisk != mask.end()-1) {
|
||||
return "'*' may only appear at the end of the mask";
|
||||
}
|
||||
|
||||
bans_.push_back(mask);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
config server::sync_initial_response()
|
||||
{
|
||||
config res;
|
||||
|
@ -124,19 +156,77 @@ void server::process_command(const std::string& cmd)
|
|||
const std::string command(cmd.begin(),i);
|
||||
if(command == "msg") {
|
||||
if(i == cmd.end()) {
|
||||
std::cerr << "you must type a message\n";
|
||||
std::cout << "you must type a message" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string msg(i+1,cmd.end());
|
||||
lobby_players_.send_data(construct_server_message(msg,lobby_players_));
|
||||
const std::string msg(i+1,cmd.end()); lobby_players_.send_data(construct_server_message(msg,lobby_players_));
|
||||
for(std::vector<game>::iterator g = games_.begin(); g != games_.end(); ++g) {
|
||||
g->send_data(construct_server_message(msg,*g));
|
||||
}
|
||||
|
||||
std::cerr << "message '" << msg << "' relayed to players\n";
|
||||
std::cout << "message '" << msg << "' relayed to players\n";
|
||||
} else if(command == "status") {
|
||||
std::cout << "STATUS REPORT\n---\n";
|
||||
for(player_map::const_iterator i = players_.begin(); i != players_.end(); ++i) {
|
||||
const network::connection_stats& stats = network::get_connection_stats(i->first);
|
||||
const int time_connected = stats.time_connected/1000;
|
||||
const int seconds = time_connected%60;
|
||||
const int minutes = (time_connected/60)%60;
|
||||
const int hours = time_connected/(60*60);
|
||||
std::cout << "'" << i->second.name() << "' @ " << network::ip_address(i->first) << " connected for " << hours << ":" << minutes << ":" << seconds << " sent " << stats.bytes_sent << " bytes, received " << stats.bytes_received << " bytes\n";
|
||||
}
|
||||
|
||||
std::cout << "---" << std::endl;
|
||||
} else if(command == "ban") {
|
||||
|
||||
if(i == cmd.end()) {
|
||||
std::cout << "BAN LIST\n---\n";
|
||||
for(std::vector<std::string>::const_iterator i = bans_.begin(); i != bans_.end(); ++i) {
|
||||
std::cout << *i << "\n";
|
||||
}
|
||||
std::cout << "---" << std::endl;
|
||||
} else {
|
||||
const std::string mask(i+1,cmd.end());
|
||||
const std::string& diagnostic = ban_ip(mask);
|
||||
if(diagnostic != "") {
|
||||
std::cout << "Could not ban '" << mask << "': " << diagnostic << std::endl;
|
||||
} else {
|
||||
std::cout << "Set ban on '" << mask << "'\n";
|
||||
}
|
||||
}
|
||||
} else if(command == "unban") {
|
||||
if(i == cmd.end()) {
|
||||
std::cout << "You must enter a mask to unban" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string mask(i+1,cmd.end());
|
||||
|
||||
const std::vector<std::string>::iterator itor = std::remove(bans_.begin(),bans_.end(),mask);
|
||||
if(itor == bans_.end()) {
|
||||
std::cout << "there is no ban on '" << mask << "'" << std::endl;
|
||||
} else {
|
||||
bans_.erase(itor,bans_.end());
|
||||
std::cout << "ban removed on '" << mask << "'" << std::endl;
|
||||
}
|
||||
|
||||
} else if(command == "kick") {
|
||||
if(i == cmd.end()) {
|
||||
std::cout << "you must enter a nick to kick\n";
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string nick(i+1,cmd.end());
|
||||
|
||||
for(player_map::const_iterator j = players_.begin(); j != players_.end(); ++j) {
|
||||
if(j->second.name() == nick) {
|
||||
std::cout << "kicking nick '" << j->second.name() << "'\n";
|
||||
throw network::error("",j->first);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "command '" << command << "' is not recognized\n";
|
||||
std::cout << "command '" << command << "' is not recognized" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +259,11 @@ void server::run()
|
|||
network::process_send_queue();
|
||||
|
||||
network::connection sock = network::accept_connection();
|
||||
if(sock) {
|
||||
if(sock && is_ip_banned(network::ip_address(sock))) {
|
||||
std::cerr << "rejected banned user '" << network::ip_address(sock) << "'\n";
|
||||
network::send_data(construct_error("You are banned."),sock);
|
||||
network::disconnect(sock);
|
||||
} else if(sock) {
|
||||
network::send_data(login_response_,sock);
|
||||
not_logged_in_.add_player(sock);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue