Skip to content

Commit

Permalink
🐛 Add challenge retries for A2S_PLAYER requests
Browse files Browse the repository at this point in the history
  • Loading branch information
GiyoMoon committed Feb 12, 2022
1 parent bccbdad commit ee5c856
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 35 deletions.
33 changes: 17 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "steam-server-query",
"version": "1.1.2",
"version": "1.1.3",
"description": "Module which implements the Master Server Query Protocol and Game Server Queries.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand All @@ -26,7 +26,7 @@
},
"homepage": "https://github.com/GiyoMoon/steam-server-query#readme",
"devDependencies": {
"@types/node": "^17.0.5",
"typescript": "^4.5.4"
"@types/node": "^17.0.17",
"typescript": "^4.5.5"
}
}
50 changes: 34 additions & 16 deletions src/gameServer/gameServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class GameServerQuery {
}

// If the server replied with a challenge, grab challenge number and send request again
if (resultBuffer.compare(Buffer.from([0xFF, 0xFF, 0xFF, 0xFF, 0x41]), 0, 5, 0, 5) === 0) {
if (this._isChallengeResponse(resultBuffer)) {
resultBuffer = resultBuffer.slice(5);
const challenge = resultBuffer;
try {
Expand All @@ -93,26 +93,40 @@ class GameServerQuery {
}

public async player(): Promise<PlayerResponse> {
let challengeResultBuffer: Buffer;
try {
challengeResultBuffer = await this._promiseSocket.send(this._buildPacket(Buffer.from([0x55])), this._host, this._port);
} catch (err: any) {
this._promiseSocket.closeSocket();
throw new Error(err);
}
let resultBuffer: Buffer;
let gotPlayerResponse = false;
let challengeTries = 0;

const challenge = challengeResultBuffer.slice(5);
do {
let challengeResultBuffer: Buffer;
try {
challengeResultBuffer = await this._promiseSocket.send(this._buildPacket(Buffer.from([0x55])), this._host, this._port);
} catch (err: any) {
this._promiseSocket.closeSocket();
throw new Error(err);
}

let resultBuffer: Buffer;
try {
resultBuffer = await this._promiseSocket.send(this._buildPacket(Buffer.from([0x55]), challenge), this._host, this._port);
} catch (err: any) {
this._promiseSocket.closeSocket();
throw new Error(err);
}
const challenge = challengeResultBuffer.slice(5);
try {
resultBuffer = await this._promiseSocket.send(this._buildPacket(Buffer.from([0x55]), challenge), this._host, this._port);
} catch (err: any) {
this._promiseSocket.closeSocket();
throw new Error(err);
}

if (!this._isChallengeResponse(resultBuffer)) {
gotPlayerResponse = true;
}

challengeTries++;
} while (!gotPlayerResponse && challengeTries < 5);

this._promiseSocket.closeSocket();

if (this._isChallengeResponse(resultBuffer)) {
throw new Error('Server kept sending challenge responses.');
}

const parsedPlayerBuffer = this._parsePlayerBuffer(resultBuffer);
return parsedPlayerBuffer;
}
Expand Down Expand Up @@ -177,6 +191,10 @@ class GameServerQuery {
return packet;
}

private _isChallengeResponse(buffer: Buffer) {
return buffer.compare(Buffer.from([0xFF, 0xFF, 0xFF, 0xFF, 0x41]), 0, 5, 0, 5) === 0;
}

private _parseInfoBuffer(buffer: Buffer): InfoResponse {
const infoResponse: Partial<InfoResponse> = {};
buffer = buffer.slice(5);
Expand Down

0 comments on commit ee5c856

Please sign in to comment.