--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/network/rconsession.cpp Fri Dec 12 00:55:51 2014 +0200 @@ -0,0 +1,219 @@ +#include "rconsession.h" + +// ------------------------------------------------------------------------------------------------- +// +RCONSession::RCONSession() : + m_state (RCON_DISCONNECTED), + m_lastPing (0) +{ + if (not m_socket.set_blocking (false)) + { + // TODO: find a better way to deal with errors + fprintf (stderr, "unable to set socket as non-blocking: %s\n", + m_socket.error_string().chars()); + } +} + +// ------------------------------------------------------------------------------------------------- +// +RCONSession::~RCONSession() {} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::connect (IPAddress address) -> void +{ + m_address = address; + m_state = RCON_CONNECTING; +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::disconnect() -> void +{ + if (m_state == RCON_CONNECTED) + { + // Say goodbye to remote + Bytestream packet; + packet.write_byte (CLRC_DISCONNECT); + this->send (packet); + } + + m_state = RCON_DISCONNECTED; +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::send (const Bytestream& packet) -> void +{ + m_socket.send (m_address, packet); +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::tick() -> void +{ + time_t now; + time (&now); + + if (m_lastPing < now) + { + if (m_state == RCON_CONNECTING) + { + send_hello(); + } + else if (m_state == RCON_AUTHENTICATING) + { + send_password(); + } + else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) + { + Bytestream packet; + packet.write_byte (CLRC_PONG); + send (packet); + bump_last_ping(); + } + } + + for (Datagram datagram; m_socket.read (datagram);) + handle_packet (datagram.data, datagram.from); +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::handle_packet (Bytestream& packet, const IPAddress& from) -> void +{ + print ("Handling packet of %1 bytes\n", packet.written_length()); + bool ok = true; + + while (packet.bytes_left() > 0) + { + print ("%1/%2 bytes left\n", packet.bytes_left(), packet.written_length()); + int header = packet.read_byte (&ok); + print ("recieved HEADER with %1\n", header); + + switch (ServerResponse (header)) + { + case SVRC_OLDPROTOCOL: + fprintf (stderr, "wrong version\n"); + m_state = RCON_DISCONNECTED; + break; + + case SVRC_BANNED: + fprintf (stderr, "you're banned\n"); + m_state = RCON_DISCONNECTED; + break; + + case SVRC_SALT: + { + String salt = packet.read_string(); + m_salt = salt; + m_state = RCON_AUTHENTICATING; + send_password(); + } + break; + + case SVRC_LOGGEDIN: + fprintf (stderr, "login successful\n"); + m_state = RCON_CONNECTED; + break; + + case SVRC_INVALIDPASSWORD: + fprintf (stderr, "bad password\n"); + m_state = RCON_DISCONNECTED; + break; + + case SVRC_MESSAGE: + { + String message = packet.read_string(); + print_to (stderr, "message: %1\n", message); + } + break; + + case SVRC_UPDATE: + switch (RCONUpdateType (packet.read_byte (&ok))) + { + case SVRCU_PLAYERDATA: + { + int numplayers = packet.read_byte (&ok); + Vector<String> players; + + while (numplayers--) + players << packet.read_string (&ok); + + print_to (stderr, "players: %1\n", players); + } + break; + + case SVRCU_ADMINCOUNT: + print_to (stderr, "num admins: %1\n", packet.read_byte (&ok)); + break; + + case SVRCU_MAP: + print_to (stderr, "new map: %1\n", packet.read_string (&ok)); + break; + } + + break; + } + + if (not ok) + print_to (stderr, "error while reading packet\n"); + } +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::socket() -> UDPSocket* +{ + return &m_socket; +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::send_hello() -> void +{ + print ("connecting to %1...\n", m_address.to_string (IP_WITH_PORT)); + Bytestream packet; + packet.write_byte (CLRC_BEGINCONNECTION); + packet.write_byte (RCON_PROTOCOL_VERSION); + send (packet); + bump_last_ping(); +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::send_password() -> void +{ + print ("sending password...\n"); + Bytestream packet; + packet.write_byte (CLRC_PASSWORD); + packet.write_string ((m_salt + m_password).md5()); + send (packet); + bump_last_ping(); +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::set_password (const String& password) -> void +{ + m_password = password; +} + +// ------------------------------------------------------------------------------------------------- +// +METHOD +RCONSession::bump_last_ping() -> void +{ + time_t now; + time (&now); + m_lastPing = now; +}