Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server on MacOS is not sending ADMIN_PACKET_SERVER_WELCOME packet #8525

Closed
iTKerry opened this issue Jan 8, 2021 · 4 comments
Closed

Server on MacOS is not sending ADMIN_PACKET_SERVER_WELCOME packet #8525

iTKerry opened this issue Jan 8, 2021 · 4 comments

Comments

@iTKerry
Copy link

iTKerry commented Jan 8, 2021

Version of OpenTTD

1.10.3

Expected result

After sending ADMIN_PACKET_ADMIN_JOIN to server there should be 2 responses:

  1. ADMIN_PACKET_SERVER_PROTOCOL
  2. ADMIN_PACKET_SERVER_WELCOME

Actual result

I received only ADMIN_PACKET_SERVER_PROTOCOL without ADMIN_PACKET_SERVER_WELCOME.

Steps to reproduce

Send ADMIN_PACKET_ADMIN_JOIN to server.

Comments

Same code works on Windows 10 (latest revision).
I'm using sockets to communicate with sever.
I've tried two different implementations with C# and F#, both works on windows and none on MacOS.
If you need my code, than here it is: https://github.com/iTKerry/better-ttd/blob/main/src/BetterTTD.FOAN.Actors/Actors.fs

@glx22
Copy link
Contributor

glx22 commented Jan 8, 2021

The code responsible for sending these packets is

/** Send the protocol version to the admin. */
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
{
Packet *p = new Packet(ADMIN_PACKET_SERVER_PROTOCOL);
/* announce the protocol version */
p->Send_uint8(NETWORK_GAME_ADMIN_VERSION);
for (int i = 0; i < ADMIN_UPDATE_END; i++) {
p->Send_bool (true);
p->Send_uint16(i);
p->Send_uint16(_admin_update_type_frequencies[i]);
}
p->Send_bool(false);
this->SendPacket(p);
return this->SendWelcome();
}
/** Send a welcome message to the admin. */
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
{
Packet *p = new Packet(ADMIN_PACKET_SERVER_WELCOME);
p->Send_string(_settings_client.network.server_name);
p->Send_string(GetNetworkRevisionString());
p->Send_bool (_network_dedicated);
p->Send_string(_network_game_info.map_name);
p->Send_uint32(_settings_game.game_creation.generation_seed);
p->Send_uint8 (_settings_game.game_creation.landscape);
p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
p->Send_uint16(MapSizeX());
p->Send_uint16(MapSizeY());
this->SendPacket(p);
return NETWORK_RECV_STATUS_OKAY;
}

and doesn't depend on the platform.
Both packets are queued and should be sent sooner or later.

@TrueBrain
Copy link
Member

TrueBrain commented Jan 8, 2021

Important to note, although most of the time these packets will be received in a single TCP packet, this one will not. It will most likely be a single TCP packet containing two OpenTTD packets. I know this can be a bit confusing, so let me try to explain a bit:

TCP sends packets when ever it feels like is a good moment. Depending on the OS, the rules are a bit different, but think of it like this: if the packet is (almost) full (so called MTU) or 20ms has elapsed, send out this packet. OSes do this, as it is much better for speed to send a single big packet, a bit delayed, over a lot of small packets.

OpenTTD mostly sends out packets one at the time, with a good delay between each. As such, it is pretty common that a single OpenTTD packet is in a single TCP packet. But in this case, both packets are send at nearly the same time. In result, that most likely are being put in a single TCP packet, and send to the other side.

OS difference here is huge, and I only paint you an abstract picture here (so for the nitpickers reading this: there is a lot of nuance to this story, I am well aware :D). If I would be to guess, Windows sends 2 TCP packets where MacOS sends one, and you are noticing this difference.

I would suspect that in your client you simple do: on TCP receive, read OpenTTD packet, wait for next TCP packet. But in reality you have to loop over the TCP packets, checking if there is more than one OpenTTD packet in there. In fact, it is possible that 1 OpenTTD packet can be over multiple TCP packets.

I hope I explained this well enough for you to understand, as it is not really easy to explain in text, I noticed while writing this :) And I hope I am guessing right here :P

As I don't speak C# or F#, I could not validate this in your client .. but in pseudo code:

buffer = ""

while running
    new_buffer = read from TCP
    buffer = buffer + new_buffer
    size = read OpenTTD packet size (peek)
    while size < length of buffer
        read OpenTTD packet
        buffer = buffer[size : <end of buffer>]

        if length of buffer > 2
            size = read OpenTTD packet size (peek)

Again, I can be completely wrong, so possibly it is good to first validate if this is happening: check after reading an OpenTTD packet if the data buffer you get from the socket was bigger than what you just handled.

Hopefully this helps you :)

For reference, this is how we do it in C++: https://github.com/OpenTTD/OpenTTD/blob/master/src/network/core/tcp.cpp#L145

@TrueBrain
Copy link
Member

Found this, might help you out:

https://github.com/Xaroth/libottdadmin2/blob/master/libottdadmin2/client/common.py#L42

Maybe it helps to see how others solved it, instead of my psuedo-code :)

@iTKerry
Copy link
Author

iTKerry commented Jan 14, 2021

@TrueBrain @glx22 thank you so much for help!
My code doesn't work on MacOS because of a weird issue related to socket.Read(buf) function related to .NET issue. So, I assume this issue can be closed.

Once again, great thanks! Love this community so much <3

@iTKerry iTKerry closed this as completed Jan 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants