Iapetus-11 / aio-mc-rcon

An asynchronous RCON client/wrapper for Minecraft Java Edition
MIT License
38 stars 4 forks source link

Fix response read on long messages #4

Closed bengardner closed 2 years ago

bengardner commented 2 years ago

When running the "help" command, the read only returned 2916 of 2940 bytes. Any response larger than the MTU could be truncated. This change assembles the replies in an array and joins them when done.

Iapetus-11 commented 2 years ago

Does your change fix the issue? I don't see how this would fix it but I tested your changes and they seem to work fine.

bengardner commented 2 years ago

Yes, the change fixes the issue.

It doesn't occur when connecting from the machine that is running the server, but did for me when I ran the script from a different Linux box. It also doesn't occur for responses that are smaller than the MTU (~1400 bytes). It is a timing issue.

The question is: does the OS receive all packets for the response before the application calls the read() system call. The response to the "help" command is split into 3 packets in my setup, as my MTU is 1500, leaving 1458 bytes of payload. The first two packets are processed by the time the recv() system call copies the data from the kernel. The 3rd packet arrives later.

The read() function returns up to the number of bytes specified. It has no way of knowing if all the expected bytes have been received. You have to do that at the application layer.

This is the sequence at the low level when this happens: 1) Send "help" command to the server. 2) App waits for data to arrive on the socket via select/poll/epoll, etc. 3) First packet of the response arrives. 4) The app is notified that data is available. 5) Second packet of the response arrives and the data is added to the socket. 6) The app calls the recv() function to retrieve data from the socket (reads 2916/2940 bytes in my case) 7) Third packet of the response arrives at the OS level 8) App checks received data and sees that it is short and doesn't end with '\0\0'

The above sequence may be aggravated by the Nagle algo that holds back the 3rd frame until a timeout or more data is available to send. But that is on the server and you couldn't do anything about it.

In general, when sending frames over a stream, you have to have logic that collects the data and assembles the frame before processing it.

Iapetus-11 commented 2 years ago

Interesting, thank you for explaining that to me.