sources/network/rconsession.cpp

Fri, 12 Dec 2014 00:55:51 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Fri, 12 Dec 2014 00:55:51 +0200
changeset 10
3874575d924d
child 11
cffa2777d917
permissions
-rw-r--r--

- 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;
}

mercurial