super-truite Posted April 29, 2020 Posted April 29, 2020 I would like to be able to use the remote console in code in order to be able to input commands to my server in a web interface or desktop applications (to use server input MCU's for instane). I see it was already done by coconut here: I am able to use the remote console using the .exe and I can send messags to my Dserver, but I am not able to send and recieve messages from the tcp socket in my favorite langage (python). The issue might be because of the message formatting. In the readme of the remote console, there is this explanation: "Commands, which are sended to server, and responces, recieved from the serverver are nested into packets. Every packet should have a structure as follows: | length of data | data | | | | The string containing command or responce |00000000| | two bytes | length of string |one byte| So, in fact, the whole packet consists of two bytes, representing the length of data, and the data, which is a C-string (just chars, bytes), terminated with 0-byte. One command/responce is nested in one packet. So as you can see, the maximum packet data lendth is 64K (two bytes for data length)." What I do is the following: 1) convert my command string (for instancea log in command : ""auth admin pasword") to bytes 2) compute the length of the converted string and convert it to bytes 3) combine the converted length + converted command + 0-byte Is that corect ? I have seen this code from coconut: https://bitbucket.org/johdex/commander/src/default/Commander/Commander/RemoteConsole.fs But it seems I am unable to reproduce the packet formatting. Here is my attempt in python: cmd = 'auth admin pasword' cmd = bytes(cmd) length = bytes([len(cmd)]) packet = length + cmd + b'\x00' when I send this I never receive a response and my call is left hanging. Dserver sees a connexion though. import socket # connect to socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('192.168.0.14', 8991)) # packet formatting cmd = 'auth admin password' cmd = bytes(cmd) length = bytes([len(cmd)]) packet = length + cmd + b'\x00' # sending packet s.sendall(packet) # get data back (hangs :( ) data = s.recv(2048) s.close() print('Received', repr(data)) Other potential issue: the size of the packet received ? Any ideas ? @coconut ? ? Alternative way of doing things I would accept: using console calls if there is a way to use RconClient.exe in command line.
coconut Posted April 30, 2020 Posted April 30, 2020 On 4/29/2020 at 11:25 AM, super-truite said: length = bytes([len(cmd)]) Check how many bytes that gives you. It should be two. I suspect you are getting 4.
super-truite Posted April 30, 2020 Author Posted April 30, 2020 thx, I made progress! it's not hanging anymore, the length was indeed wrong and the struct module is great to simplify things. I did not manage yet to control my serverinput MCU's but I am on the right path.
super-truite Posted May 1, 2020 Author Posted May 1, 2020 I am always getting STATUS=10 as a response. This is not documented in the readme (stops at STATUS=9)? Any idea ? I guess it is still a packaging issue for the messages. my packing/unpacking functions in python 3 : def pack_message(msg): msg = msg.encode('ASCII') packet = struct.pack("H{0}sx".format(len(msg)), len(msg), msg) return packet def unpack_message(data): dataformat = "H{0}sx".format(struct.unpack("h", data[0:2])[0]-1) data = struct.unpack(dataformat, data) return data packet format: unsigned int + len(msg)-bytes string () + pad byte The data I receive seems to not follow the format described in the readme: the length is the length of the string + 1. Full code: import socket import struct HOST = '192.168.0.14' PORT = 8991 def pack_message(msg): msg = msg.encode('ASCII') packet = struct.pack("H{0}sx".format(len(msg)), len(msg), msg) return packet def unpack_message(data): dataformat = "H{0}sx".format(struct.unpack("h", data[0:2])[0]-1) data = struct.unpack(dataformat, data) return data class RemoteConsoleClient(): def __init__(self, host, port): self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.host = host self.port = port self.connect() def connect(self): try: self.client.connect((self.host, self.port)) print('connected to:', self.host, self.port) except socket.error as e: print(e) def send(self, msg): try: packet = pack_message(msg) self.client.send(packet) data = self.client.recv(4096) return unpack_message(data) except socket.error as e: print(e) remoteconsole = RemoteConsoleClient(HOST, PORT) auth = remoteconsole.send('auth admin password') print(auth) server_input = remoteconsole.send('serverinput start') print(server_input) results of the print commands: connected to: 192.168.0.14 8991 (10, b'STATUS=10') [WinError 10053] Une connexion établie a été abandonnée par un logiciel de votre ordinateur hôte None STATUS=10 is the response to the auth command and the Winerror 10053 comes from the serverinput command which fails because of the failed authentification probably 1
super-truite Posted May 1, 2020 Author Posted May 1, 2020 (edited) Got it working, I was not sending the good header (it's the length of the message + 1 and not only the length of the message). Working python 3 code: import socket import struct HOST = '192.168.0.14' PORT = 8991 def pack_message(msg): msg = msg.encode('ASCII') packet = struct.pack("H{0}sx".format(len(msg)), len(msg)+1, msg) return packet def unpack_message(data): dataformat = "H{0}sx".format(struct.unpack("h", data[0:2])[0]-1) data = struct.unpack(dataformat, data) return data class RemoteConsoleClient(): def __init__(self, host, port): self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.host = host self.port = port self.connect() def connect(self): try: self.client.connect((self.host, self.port)) print('connected to:', self.host, self.port) except socket.error as e: print(e) def send(self, msg): try: packet = pack_message(msg) self.client.send(packet) data = self.client.recv(4096) return unpack_message(data)[1].decode() except socket.error as e: print(e) remoteconsole = RemoteConsoleClient(HOST, PORT) auth = remoteconsole.send('auth admin password') print('Response: ', auth) server_input = remoteconsole.send('serverinput start') print('Response: ', server_input) Output: connected to: 192.168.0.14 8991 Response: STATUS=1 Response: STATUS=1 ? Thanks again lads ! Edit: used the tool wireshark to understand what packets goes in and out of the rconclient.exe. Great tool Edited May 1, 2020 by super-truite 1
ITAF_LittleMadz77 Posted March 30, 2021 Posted March 30, 2021 Guys this doesn't work for me. I'm sorry I'm not a python guy. I have this error, beside error 6. dataformat = "H{0}sx".format(struct.unpack("h", data[0:2])[0]-1) Any help would be greatly appreciated Regards Maurizio
super-truite Posted April 1, 2021 Author Posted April 1, 2021 (edited) error 6 is linked to bad authentification. Did you modify the login/pwd in my example? Change admin/password in this line: auth = remoteconsole.send('auth admin password') You can find some working code in my discord bot project : https://github.com/Super-truite/il2_discord_bot Edited April 1, 2021 by super-truite
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now