def connect(self): try: self.address = socket.gethostbyname(self.address) self.header = MSG_PREFIX + encode_bytes( *map(int, self.address.split('.'))) + encode_bytes( self.port & 0xFF, self.port >> 8 & 0xFF) self.socket = self.socket_cls(socket.AF_INET, socket.SOCK_DGRAM) self.socket.settimeout(self.timeout) return self except socket.error as e: raise ConnectionError(e)
def send_request(self, opcode, extras=b'', return_response=True): ip_address = encode_bytes(*[(int(n)) for n in self.address.split('.')]) port_number = encode_bytes(self.port & 0xFF, self.port >> 8 & 0xFF) body = MSG_PREFIX \ + ip_address \ + port_number \ + opcode \ + extras self.socket.sendto(body, (self.address, self.port)) if return_response: return self.receive()
def send_rcon_command(self, command, args=tuple(), fetch_response=True): """ Send any command to the server leading whitespace is stripped from the response :param command: the comand to send :param args: tuple or list of arguments to be appended to the command. Can be also a string or an int if only one argument is expected. :param fetch_response: Whether to receive response from server. Set this to False if you're not expecting a response; WARNING: If there is a response and you don't fetch it, it may be output as a response of your next command. :return list of lines responded from the server or None if fetch_response == False """ command = build_rcon_command(command, args) command_length = encode_bytes( len(command) & 0xFF, len(command) >> 8 & 0xFF) payload = self.rcon_password_bytes + command_length + command self.send_request(OPCODE_RCON, extras=payload, return_response=False) if fetch_response: result = [] while True: response = self.receive() if response is None: break line = decode_string(response, 0, 2) if line: result.append(line.lstrip()) else: break if len(result) == 1 and result[0] == 'Invalid RCON password.': raise InvalidRconPassword return result
def rcon_password_bytes(self): """ password prefixed with its encoded length """ if not self.rcon_password: raise RconError('Rcon password was not provided') pass_len = len(self.rcon_password) return encode_bytes(pass_len & 0xFF, pass_len >> 8 & 0xFF) + bytes( self.rcon_password, ENCODING)
def test_encode(self): expected = bytes(chr(127) + chr(0) + chr(0) + chr(1), 'utf-8') self.assertEqual(expected, utils.encode_bytes(127, 0, 0, 1))