Austinb / GameQ

A PHP Gameserver Status Query Library
https://austinb.github.io/GameQ/
GNU Lesser General Public License v3.0
404 stars 134 forks source link

MTA Query not returning correct values when 350+ players #534

Closed luisbustalu closed 4 years ago

luisbustalu commented 4 years ago

Hello!

In the last month our playerbase increased in one of our MTA servers, and we noticed that our Server Status was showing that server offline when it was online. After a few days, we concluded that it only happens when server reach around 330 - 350 players.

What we obtain when we reach that quantity of players: Array ( [158.69.121.110:22003] => Array ( [gq_address] => 158.69.121.110 [gq_dedicated] => [gq_gametype] => [gq_hostname] => [gq_joinlink] => mtasa://158.69.121.110:22003/ [gq_mapname] => [gq_maxplayers] => [gq_mod] => [gq_name] => Multi Theft Auto [gq_numplayers] => [gq_online] => [gq_password] => [gq_port_client] => 22003 [gq_port_query] => 22126 [gq_protocol] => ase [gq_transport] => udp [gq_type] => mta [players] => Array ( ) [teams] => Array ( ) ) ) Live preview: https://proyectomila.net/server_info/roleplay.php

I think this is a bug, hope you guys can help me to fix it. Greetings!

Austinb commented 4 years ago

What time of day is the server at this larger player count? It is possible there is a limit in the ASE protocol once the player count reaches a certain limit.

luisbustalu commented 4 years ago

From around 16:00 to 00:00, everyday (GMT-4:00). When it happens, you can check that the server is online in Game-State https://www.game-state.com/158.69.121.110:22003/

If you need anything else, don't hesitate to ask for it. Thanks for helping!

luisbustalu commented 4 years ago

I'll let here the returned JSON so you don't have to wait until the server reachs that amount of people.

Array
(
    [158.69.121.110:22003] => Array
        (
            [gq_address] => 158.69.121.110
            [gq_dedicated] => 
            [gq_gametype] => 
            [gq_hostname] => 
            [gq_joinlink] => mtasa://158.69.121.110:22003/
            [gq_mapname] => 
            [gq_maxplayers] => 
            [gq_mod] => 
            [gq_name] => Multi Theft Auto
            [gq_numplayers] => 
            [gq_online] => 
            [gq_password] => 
            [gq_port_client] => 22003
            [gq_port_query] => 22126
            [gq_protocol] => ase
            [gq_transport] => udp
            [gq_type] => mta
            [players] => Array
                (
                )

            [teams] => Array
                (
                )

        )

)

Hope you can give it a look. Thanks!

Austinb commented 4 years ago

@zAnonimo So the issue right now is the data is being cut off probably due to the data being outside the bounds of the allowed packet length. I will do some testing and see if I can make ASE return all of the data if all of it is being sent by the server.

Austinb commented 4 years ago

@zAnonimo Found the issue and will push up a change shortly. I am not sure the repercussions for the change so you will need to pull from master as this will not release for awhile to allow for proper testing in the wild. Please feel free to reach out with new issues as you come across them.

I appreciate your patience.

Austinb commented 4 years ago

See e7279aa0fee4c3ccebb71aad91eb5ed0323fc340 for the change and let me know if it fixes your issue. This change may also fix other random query failures due to the server response being larger than 8k.

luisbustalu commented 4 years ago

Happy to see you checked it out, @Austinb. I updated the changed file manually on my side. Unfortunately it keeps returning the same nil JSON after updating it. Live preview is the same link as before. Maybe is a ASE protocol limit? Just throwing some ideas. Hope you can check it, thanks a lot!

Austinb commented 4 years ago

The following code works for me and returns a proper MTA response:

$gq->addServer([
    'type' => 'mta',
    'host' => '158.69.121.110:22003',
]);

You can try to enable debug and see if there is any other error being thrown. Otherwise it maybe the server itself blocking your query requests. I would try other MTA servers from https://www.game-state.com/index.php?game=mta and see if you are able to query any of them successfully. If not your host maybe blocking the outbound or the responses.

luisbustalu commented 4 years ago

Thanks, once again @Austinb. I tried the same for 3 different populated MTA servers, same nil JSON returned. After that, I enabled Debug option as requested, and at least I get some errors now. I hope this can be useful for you.

This is what I get:

Fatal error: Uncaught GameQ\Exception\Protocol: Unable to read length=13 from buffer. Bad protocol format or return? in REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/Buffer.php:133 Stack trace:

#0 REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/Buffer.php(254): GameQ\Buffer->read(13)
#1 REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/Protocols/Ase.php(189): GameQ\Buffer->readPascalString(13, true)
#2 REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/Protocols/Ase.php(134): GameQ\Protocols\Ase->processPlayersAndTeams(Object(GameQ\Buffer), Object(GameQ\Result))
#3 REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/GameQ.php(585): GameQ\Protocols\Ase->processResponse()
#4 REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/GameQ.php(357): GameQ\GameQ->doParseResponse(Object(GameQ\Server))
#5 REDACTED/public_html/ in REDACTED/public_html/server_info/vendor/austinb/gameq/src/GameQ/GameQ.php on line 592
PurpleTape commented 4 years ago

Hello!

I have the same problem, but not only for servers with 350+ players. I took the first 75 servers from the site mta-servers dot ru and tried to get information about them (in the list of selected servers there are servers with a large number of players and empty servers without players).

As a result, I was able to get information about only 16 servers. Information about other servers turned out to be empty. When I turned on the debug mod, I got the same error as @zAnonimo

How can I find a solution to the problem? Thank you.

Code (used latest version): https://pastebin.com/8YTYPbNb

Result (ex players list): https://pastebin.com/Sjv61XX2

Austinb commented 4 years ago

The errors you all are getting are likely due to an empty response returned by the server and the ASE protocol not handling it properly. My guess is there is a firewall that is setup to close the connection instantly to prevent a response. Likely to prevent DOS of the host.

If you dump out the $this->packets_response before any of the work happens you will see an empty array. Usually a server will respond or timeout but not respond with an empty result. Adding some checks but will still error out when debug is enabled just with more information this time.

PurpleTape commented 4 years ago

Thanks for the answer.

How then do monitoring sites collect information without such problems?

Austinb commented 4 years ago

Probably have exceptions for the servers doing the querying allowing them to connect. Found a forum post for GT at https://www.gametracker.com/forums/forum.php?site=1&thread=108247 and one from MTA query site - https://www.game-state.com/forum/viewtopic.php?f=7&t=2420. I would recommend only adding servers you or people you know control and allow you to query.

luisbustalu commented 4 years ago

I don't think that's the issue. The problem still happens when I use localhost/127.0.0.1 as IP to query the server (my web and gameservers are hosted in the same dedicated server), the same debug errors appears. As far as I remember, my machine allows any type of connection that comes from the machine itself. Also, we never did an exception or tweak for Game-State to query our servers. I hope this info can help a lil bit. Once again, thanks a lot for working on this project!!

Austinb commented 4 years ago

You will need to provide the raw output from the server response in the processResponse function in the Ase class and the error coming out of GameQ. Without being able to query it there is nothing that can be done to help. Also make sure you pull down from the master on branch v3.

print_r($this->packets_response)

If it is empty something is causing the connection to be closed or the server to respond with an empty response. You can also use Wireshark or other similar networking programs to see the raw connection action that happens behind the scenes in PHP's socket handling.

Austinb commented 4 years ago

Also can you change the query port on the server side for MTA? If so the default port math will only try the default. You will have to specify the specific server query port using the query_port option. I know other game server types have this ability and without knowing the query port you are out of luck getting any information.

PurpleTape commented 4 years ago

I found a repository (https://github.com/multitheftauto/mtasa-blue/) with the source code of the MTA server. Some analysis showed that the ASE port +123 is set strictly in the code and cannot be changed.

I also found the source code for implementing the ASE protocol (https://github.com/multitheftauto/mtasa-blue/blob/master/Server/mods/deathmatch/logic/ASE.cpp). GameQ follows this implementation, so the problem is not here.

After that, I downloaded the MTA server (from https://www.mtasa.com/) and tried to send the packages myself through fsockopen. I sent a package with the contents of "s". At the same time, I watched the MTA server through Wireshark and the MTA server received a packet with "s", sending information about self in response. However, I was not able to read this answer in the php file and received a timeout error.

However, when I checked the method above some other MTA servers, some servers returned information packets and the php successfully received them. And some returned a similar timout error.

After that, I added the address of the MTA server that is running on my computer in server monitoring. And server monitoring was able to successfully get information about my server. Through Wireshark, I watched which packets came to me and it turned out that server monitoring similarly uses ASE protocol to get information about my server.

Thus, either I missed something, or the problem is somewhere outside of my understanding of network protocols...

luisbustalu commented 4 years ago

You will need to provide the raw output from the server response in the processResponse function in the Ase class and the error coming out of GameQ. Without being able to query it there is nothing that can be done to help. Also make sure you pull down from the master on branch v3.

print_r($this->packets_response)

If it is empty something is causing the connection to be closed or the server to respond with an empty response. You can also use Wireshark or other similar networking programs to see the raw connection action that happens behind the scenes in PHP's socket handling.

I tried this with my populated server and a empty one (only one player). Both didn't return anything using the function you provided me, but the empty one does a proper response using $this->process(); so I think it should return some packets using packets_response, right?

Also can you change the query port on the server side for MTA? If so the default port math will only try the default. You will have to specify the specific server query port using the query_port option. I know other game server types have this ability and without knowing the query port you are out of luck getting any information.

Query port in MTA is hardcoded, it uses the main port to calculate the query port.

PurpleTape commented 4 years ago

Hello again!

I eventually discovered that incoming UDP connections were blocked on my GameQ server. So I removed this block and the problem disappeared.

But one thing remains a mystery to me: if it interfered with the full-fledged work, then why did the answer from some MTA servers still return successfully, but from some did not return?

Thanks for answers. Best wishes!

Austinb commented 4 years ago

Its possible only a specific ranger of returning UDP ports are open. If the responses come back on those ports you are fine but if not then they are dropped by the firewall/router. Could explain the randomness as to why it was working sometimes.

If you have another issues please open up a new issue. I am going to close this one.