Tue, 16 Dec 2014 04:08:31 +0200
Added tag 1.0 for changeset 5e968dc8d552
#include "rconsession.h" #include "../interface.h" // ------------------------------------------------------------------------------------------------- // RCONSession::RCONSession() : m_state (RCON_DISCONNECTED), m_lastPing (0), m_numAdmins (0) { if (not m_socket.set_blocking (false)) { print_to (stderr, "unable to set socket as non-blocking: %s\n", m_socket.error_string().chars()); exit (EXIT_FAILURE); } } // ------------------------------------------------------------------------------------------------- // RCONSession::~RCONSession() {} // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::connect (IPAddress address) -> void { m_address = address; m_state = RCON_CONNECTING; Interface::update_statusbar(); send_hello(); } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::disconnect() -> void { if (m_state > RCON_CONNECTING) { // Say goodbye to remote Bytestream packet; packet.write_byte (CLRC_DISCONNECT); this->send (packet); print ("Disconnected from %1\n", m_address.to_string (IP_WITH_PORT)); Interface::update_statusbar(); } m_state = RCON_DISCONNECTED; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::send (const Bytestream& packet) -> void { m_socket.send (m_address, packet); } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::tick() -> void { if (m_state == RCON_DISCONNECTED) return; 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 { if (from != m_address) return; try { while (packet.bytes_left() > 0) { int header = packet.read_byte(); switch (ServerResponse (header)) { case SVRC_OLDPROTOCOL: print ("Your RCON client is using outdated protocol.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_BANNED: print ("You have been banned from the server.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_SALT: m_salt = packet.read_string(); m_state = RCON_AUTHENTICATING; send_password(); break; case SVRC_INVALIDPASSWORD: print ("Password incorrect.\n"); m_state = RCON_DISCONNECTED; break; case SVRC_MESSAGE: { String message = packet.read_string(); message.normalize(); print ("%1\n", message); } break; case SVRC_LOGGEDIN: print ("Login successful!\n"); m_serverProtocol = packet.read_byte(); m_hostname = packet.read_string(); Interface::set_title (m_hostname); m_state = RCON_CONNECTED; for (int i = packet.read_byte(); i > 0; --i) process_server_updates (packet); print ("Previous messages:\n"); for (int i = packet.read_byte(); i > 0; --i) { String message = packet.read_string(); message.normalize(); print ("--- %1\n", message); } print ("End of previous messages.\n"); break; case SVRC_UPDATE: process_server_updates (packet); break; } } } catch (std::exception& e) { print ("error while reading packet: %1\n", e.what()); } } METHOD RCONSession::process_server_updates (Bytestream& packet) -> void { switch (RCONUpdateType (packet.read_byte())) { case SVRCU_PLAYERDATA: { StringList players; for (int i = packet.read_byte(); i > 0; --i) players << packet.read_string(); Interface::set_player_names (players); } break; case SVRCU_ADMINCOUNT: m_numAdmins = packet.read_byte(); Interface::update_statusbar(); break; case SVRCU_MAP: m_level = packet.read_string(); Interface::update_statusbar(); break; } } // ------------------------------------------------------------------------------------------------- // 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 ("Authenticating...\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; } // ------------------------------------------------------------------------------------------------- // STATIC METHOD RCONSession::get_session() -> RCONSession* { static RCONSession session; return &session; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::is_active() const -> bool { return state() != RCON_DISCONNECTED; } // ------------------------------------------------------------------------------------------------- // Returns true if the message was successfully sent. // METHOD RCONSession::send_command (const String& message) -> bool { if (m_state != RCON_CONNECTED or message.is_empty()) return false; Bytestream packet; packet.write_byte (CLRC_COMMAND); packet.write_string (message); send (packet); bump_last_ping(); return true; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::state() const -> RCONSessionState { return m_state; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::address() const -> const IPAddress& { return m_address; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::num_admins() const -> int { return m_numAdmins; } // ------------------------------------------------------------------------------------------------- // METHOD RCONSession::level() const -> const String& { return m_level; }