Fri, 12 Dec 2014 00:55:51 +0200
- begin work on rcon sessions
#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; }