|         | 
     1 #include "rconsession.h" | 
|         | 
     2  | 
|         | 
     3 // ------------------------------------------------------------------------------------------------- | 
|         | 
     4 // | 
|         | 
     5 RCONSession::RCONSession() : | 
|         | 
     6 	m_state (RCON_DISCONNECTED), | 
|         | 
     7 	m_lastPing (0) | 
|         | 
     8 { | 
|         | 
     9 	if (not m_socket.set_blocking (false)) | 
|         | 
    10 	{ | 
|         | 
    11 		// TODO: find a better way to deal with errors | 
|         | 
    12 		fprintf (stderr, "unable to set socket as non-blocking: %s\n", | 
|         | 
    13 			m_socket.error_string().chars()); | 
|         | 
    14 	} | 
|         | 
    15 } | 
|         | 
    16  | 
|         | 
    17 // ------------------------------------------------------------------------------------------------- | 
|         | 
    18 // | 
|         | 
    19 RCONSession::~RCONSession() {} | 
|         | 
    20  | 
|         | 
    21 // ------------------------------------------------------------------------------------------------- | 
|         | 
    22 // | 
|         | 
    23 METHOD | 
|         | 
    24 RCONSession::connect (IPAddress address) -> void | 
|         | 
    25 { | 
|         | 
    26 	m_address = address; | 
|         | 
    27 	m_state = RCON_CONNECTING; | 
|         | 
    28 } | 
|         | 
    29  | 
|         | 
    30 // ------------------------------------------------------------------------------------------------- | 
|         | 
    31 // | 
|         | 
    32 METHOD | 
|         | 
    33 RCONSession::disconnect() -> void | 
|         | 
    34 { | 
|         | 
    35 	if (m_state == RCON_CONNECTED) | 
|         | 
    36 	{ | 
|         | 
    37 		// Say goodbye to remote | 
|         | 
    38 		Bytestream packet; | 
|         | 
    39 		packet.write_byte (CLRC_DISCONNECT); | 
|         | 
    40 		this->send (packet); | 
|         | 
    41 	} | 
|         | 
    42  | 
|         | 
    43 	m_state = RCON_DISCONNECTED; | 
|         | 
    44 } | 
|         | 
    45  | 
|         | 
    46 // ------------------------------------------------------------------------------------------------- | 
|         | 
    47 // | 
|         | 
    48 METHOD | 
|         | 
    49 RCONSession::send (const Bytestream& packet) -> void | 
|         | 
    50 { | 
|         | 
    51 	m_socket.send (m_address, packet); | 
|         | 
    52 } | 
|         | 
    53  | 
|         | 
    54 // ------------------------------------------------------------------------------------------------- | 
|         | 
    55 // | 
|         | 
    56 METHOD | 
|         | 
    57 RCONSession::tick() -> void | 
|         | 
    58 { | 
|         | 
    59 	time_t now; | 
|         | 
    60 	time (&now); | 
|         | 
    61  | 
|         | 
    62 	if (m_lastPing < now) | 
|         | 
    63 	{ | 
|         | 
    64 		if (m_state == RCON_CONNECTING) | 
|         | 
    65 		{ | 
|         | 
    66 			send_hello(); | 
|         | 
    67 		} | 
|         | 
    68 		else if (m_state == RCON_AUTHENTICATING) | 
|         | 
    69 		{ | 
|         | 
    70 			send_password(); | 
|         | 
    71 		} | 
|         | 
    72 		else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) | 
|         | 
    73 		{ | 
|         | 
    74 			Bytestream packet; | 
|         | 
    75 			packet.write_byte (CLRC_PONG); | 
|         | 
    76 			send (packet); | 
|         | 
    77 			bump_last_ping(); | 
|         | 
    78 		} | 
|         | 
    79 	} | 
|         | 
    80  | 
|         | 
    81 	for (Datagram datagram; m_socket.read (datagram);) | 
|         | 
    82 		handle_packet (datagram.data, datagram.from); | 
|         | 
    83 } | 
|         | 
    84  | 
|         | 
    85 // ------------------------------------------------------------------------------------------------- | 
|         | 
    86 // | 
|         | 
    87 METHOD | 
|         | 
    88 RCONSession::handle_packet (Bytestream& packet, const IPAddress& from) -> void | 
|         | 
    89 { | 
|         | 
    90 	print ("Handling packet of %1 bytes\n", packet.written_length()); | 
|         | 
    91 	bool ok = true; | 
|         | 
    92  | 
|         | 
    93 	while (packet.bytes_left() > 0) | 
|         | 
    94 	{ | 
|         | 
    95 		print ("%1/%2 bytes left\n", packet.bytes_left(), packet.written_length()); | 
|         | 
    96 		int header = packet.read_byte (&ok); | 
|         | 
    97 		print ("recieved HEADER with %1\n", header); | 
|         | 
    98  | 
|         | 
    99 		switch (ServerResponse (header)) | 
|         | 
   100 		{ | 
|         | 
   101 		case SVRC_OLDPROTOCOL: | 
|         | 
   102 			fprintf (stderr, "wrong version\n"); | 
|         | 
   103 			m_state = RCON_DISCONNECTED; | 
|         | 
   104 			break; | 
|         | 
   105  | 
|         | 
   106 		case SVRC_BANNED: | 
|         | 
   107 			fprintf (stderr, "you're banned\n"); | 
|         | 
   108 			m_state = RCON_DISCONNECTED; | 
|         | 
   109 			break; | 
|         | 
   110  | 
|         | 
   111 		case SVRC_SALT: | 
|         | 
   112 			{ | 
|         | 
   113 				String salt = packet.read_string(); | 
|         | 
   114 				m_salt = salt; | 
|         | 
   115 				m_state = RCON_AUTHENTICATING; | 
|         | 
   116 				send_password(); | 
|         | 
   117 			} | 
|         | 
   118 			break; | 
|         | 
   119  | 
|         | 
   120 		case SVRC_LOGGEDIN: | 
|         | 
   121 			fprintf (stderr, "login successful\n"); | 
|         | 
   122 			m_state = RCON_CONNECTED; | 
|         | 
   123 			break; | 
|         | 
   124  | 
|         | 
   125 		case SVRC_INVALIDPASSWORD: | 
|         | 
   126 			fprintf (stderr, "bad password\n"); | 
|         | 
   127 			m_state = RCON_DISCONNECTED; | 
|         | 
   128 			break; | 
|         | 
   129  | 
|         | 
   130 		case SVRC_MESSAGE: | 
|         | 
   131 			{ | 
|         | 
   132 				String message = packet.read_string(); | 
|         | 
   133 				print_to (stderr, "message: %1\n", message); | 
|         | 
   134 			} | 
|         | 
   135 			break; | 
|         | 
   136  | 
|         | 
   137 		case SVRC_UPDATE: | 
|         | 
   138 			switch (RCONUpdateType (packet.read_byte (&ok))) | 
|         | 
   139 			{ | 
|         | 
   140 			case SVRCU_PLAYERDATA: | 
|         | 
   141 				{ | 
|         | 
   142 					int numplayers = packet.read_byte (&ok); | 
|         | 
   143 					Vector<String> players; | 
|         | 
   144  | 
|         | 
   145 					while (numplayers--) | 
|         | 
   146 						players << packet.read_string (&ok); | 
|         | 
   147  | 
|         | 
   148 					print_to (stderr, "players: %1\n", players); | 
|         | 
   149 				} | 
|         | 
   150 				break; | 
|         | 
   151  | 
|         | 
   152 			case SVRCU_ADMINCOUNT: | 
|         | 
   153 				print_to (stderr, "num admins: %1\n", packet.read_byte (&ok)); | 
|         | 
   154 				break; | 
|         | 
   155  | 
|         | 
   156 			case SVRCU_MAP: | 
|         | 
   157 				print_to (stderr, "new map: %1\n", packet.read_string (&ok)); | 
|         | 
   158 				break; | 
|         | 
   159 			} | 
|         | 
   160  | 
|         | 
   161 			break; | 
|         | 
   162 		} | 
|         | 
   163  | 
|         | 
   164 		if (not ok) | 
|         | 
   165 			print_to (stderr, "error while reading packet\n"); | 
|         | 
   166 	} | 
|         | 
   167 } | 
|         | 
   168  | 
|         | 
   169 // ------------------------------------------------------------------------------------------------- | 
|         | 
   170 // | 
|         | 
   171 METHOD | 
|         | 
   172 RCONSession::socket() -> UDPSocket* | 
|         | 
   173 { | 
|         | 
   174 	return &m_socket; | 
|         | 
   175 } | 
|         | 
   176  | 
|         | 
   177 // ------------------------------------------------------------------------------------------------- | 
|         | 
   178 // | 
|         | 
   179 METHOD | 
|         | 
   180 RCONSession::send_hello() -> void | 
|         | 
   181 { | 
|         | 
   182 	print ("connecting to %1...\n", m_address.to_string (IP_WITH_PORT)); | 
|         | 
   183 	Bytestream packet; | 
|         | 
   184 	packet.write_byte (CLRC_BEGINCONNECTION); | 
|         | 
   185 	packet.write_byte (RCON_PROTOCOL_VERSION); | 
|         | 
   186 	send (packet); | 
|         | 
   187 	bump_last_ping(); | 
|         | 
   188 } | 
|         | 
   189  | 
|         | 
   190 // ------------------------------------------------------------------------------------------------- | 
|         | 
   191 // | 
|         | 
   192 METHOD | 
|         | 
   193 RCONSession::send_password() -> void | 
|         | 
   194 { | 
|         | 
   195 	print ("sending password...\n"); | 
|         | 
   196 	Bytestream packet; | 
|         | 
   197 	packet.write_byte (CLRC_PASSWORD); | 
|         | 
   198 	packet.write_string ((m_salt + m_password).md5()); | 
|         | 
   199 	send (packet); | 
|         | 
   200 	bump_last_ping(); | 
|         | 
   201 } | 
|         | 
   202  | 
|         | 
   203 // ------------------------------------------------------------------------------------------------- | 
|         | 
   204 // | 
|         | 
   205 METHOD | 
|         | 
   206 RCONSession::set_password (const String& password) -> void | 
|         | 
   207 { | 
|         | 
   208 	m_password = password; | 
|         | 
   209 } | 
|         | 
   210  | 
|         | 
   211 // ------------------------------------------------------------------------------------------------- | 
|         | 
   212 // | 
|         | 
   213 METHOD | 
|         | 
   214 RCONSession::bump_last_ping() -> void | 
|         | 
   215 { | 
|         | 
   216 	time_t now; | 
|         | 
   217 	time (&now); | 
|         | 
   218 	m_lastPing = now; | 
|         | 
   219 } |