sources/network/rconsession.cpp

changeset 10
3874575d924d
child 11
cffa2777d917
--- /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;
+}

mercurial