sources/network/rconsession.cpp

Sat, 13 Dec 2014 04:32:15 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sat, 13 Dec 2014 04:32:15 +0200
changeset 12
8d0d1b368de0
parent 11
cffa2777d917
child 13
09dcaeaa216b
permissions
-rw-r--r--

- rcon session now works! woo!

#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
		print ("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 ("Processing packet of %1 bytes\n", packet.written_length());
	bool ok = true;

	while (packet.bytes_left() > 0)
	{
		int header = packet.read_byte (&ok);
		print ("Recieved packet with header %1\n", header);

		switch (ServerResponse (header))
		{
		case SVRC_OLDPROTOCOL:
			print ("wrong version\n");
			m_state = RCON_DISCONNECTED;
			break;

		case SVRC_BANNED:
			print ("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_INVALIDPASSWORD:
			print ("bad password\n");
			m_state = RCON_DISCONNECTED;
			break;

		case SVRC_MESSAGE:
			{
				String message = packet.read_string();
				if (message.ends_with ("\n"))
					message.remove_from_end (1);
				print ("message: %1\n", message);
			}
			break;

		case SVRC_LOGGEDIN:
			print ("login successful\n");
			m_serverProtocol = packet.read_byte();
			m_hostname = packet.read_string();
			m_state = RCON_CONNECTED;

			for (int i = packet.read_byte(); i > 0; --i)
				process_server_updates (packet);

			for (int i = packet.read_byte(); i > 0; --i)
			{
				String message = packet.read_string();
				message.normalize();
				print ("--- %1\n", message);
			}

			break;

		case SVRC_UPDATE:
			process_server_updates (packet);
			break;
		}

		if (not ok)
			print ("error while reading packet\n");
	}
}

METHOD
RCONSession::process_server_updates (Bytestream& packet) -> void
{
	switch (RCONUpdateType (packet.read_byte()))
	{
	case SVRCU_PLAYERDATA:
		{
			Vector<String> players;
			for (int i = packet.read_byte(); i > 0; --i)
				players << packet.read_string();
			print ("players: %1\n", players);
		}
		break;

	case SVRCU_ADMINCOUNT:
		print ("num admins: %d1\n", packet.read_byte());
		break;

	case SVRCU_MAP:
		print ("new map: %1\n", packet.read_string());
		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 ("sending password...\n");
	Bytestream packet;
	packet.write_byte (CLRC_PASSWORD);
	print ("password: %1\nsalt: %2\nhashed password: %3\n", m_password, m_salt, (m_salt + m_password).md5());
	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;
}

mercurial