From e4c29f9cbc9c8dff64ae0a6d2cfa0ad7d2b763e3 Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Sat, 6 Feb 2021 00:50:06 -0600 Subject: [PATCH] Support challenges in A2S_INFO (upcoming change to valve protocol) Fixes #210 (2.0.25) --- CHANGELOG.md | 3 ++ package.json | 2 +- protocols/ffow.js | 1 - protocols/valve.js | 70 +++++++++++++++++++++++++++------------------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b066805..94de092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 2.0.25 +* Support challenges in A2S_INFO (upcoming change to valve protocol) + ### 2.0.24 * Add Savage 2: A Tortured Soul (2008) diff --git a/package.json b/package.json index bd68f22..e1218bf 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ ], "main": "lib/index.js", "author": "GameDig Contributors", - "version": "2.0.24", + "version": "2.0.25", "repository": { "type": "git", "url": "https://github.com/gamedig/node-gamedig.git" diff --git a/protocols/ffow.js b/protocols/ffow.js index ca82d55..5960beb 100644 --- a/protocols/ffow.js +++ b/protocols/ffow.js @@ -10,7 +10,6 @@ class Ffow extends Valve { this.debugLog("Requesting ffow info ..."); const b = await this.sendPacket( 0x46, - false, 'LSQ', 0x49 ); diff --git a/protocols/valve.js b/protocols/valve.js index 56cf53c..3cc72ba 100644 --- a/protocols/valve.js +++ b/protocols/valve.js @@ -38,7 +38,6 @@ class Valve extends Core { this.debugLog("Requesting info ..."); const b = await this.sendPacket( 0x54, - false, 'Source Engine Query\0', this.goldsrcInfo ? 0x6D : 0x49, false @@ -127,7 +126,6 @@ class Valve extends Core { this.debugLog("Requesting legacy challenge key ..."); await this.sendPacket( 0x57, - false, null, 0x41, false @@ -141,7 +139,6 @@ class Valve extends Core { this.debugLog("Requesting player list ..."); const b = await this.sendPacket( 0x55, - true, null, 0x44, true @@ -180,7 +177,7 @@ class Valve extends Core { async queryRules(state) { state.raw.rules = {}; this.debugLog("Requesting rules ..."); - const b = await this.sendPacket(0x56,true,null,0x45,true); + const b = await this.sendPacket(0x56,null,0x45,true); if (b === null) return; // timed out - the server probably has rules disabled const reader = this.reader(b); @@ -245,33 +242,29 @@ class Valve extends Core { **/ async sendPacket( type, - sendChallenge, payload, expect, allowTimeout ) { for (let keyRetry = 0; keyRetry < 3; keyRetry++) { - let requestKeyChanged = false; + let receivedNewChallengeKey = false; const response = await this.sendPacketRaw( - type, sendChallenge, payload, + type, payload, (payload) => { const reader = this.reader(payload); const type = reader.uint(1); - this.debugLog(() => "Received " + type.toString(16) + " expected " + expect.toString(16)); + this.debugLog(() => "Received 0x" + type.toString(16) + " expected 0x" + expect.toString(16)); if (type === 0x41) { const key = reader.uint(4); if (this._challenge !== key) { - this.debugLog('Received new challenge key: ' + key); + this.debugLog('Received new challenge key: 0x' + key.toString(16)); this._challenge = key; - if (sendChallenge) { - this.debugLog('Challenge key changed -- allowing query retry if needed'); - requestKeyChanged = true; - } + receivedNewChallengeKey = true; } } if (type === expect) { return reader.rest(); - } else if (requestKeyChanged) { + } else if (receivedNewChallengeKey) { return null; } }, @@ -279,7 +272,7 @@ class Valve extends Core { if (allowTimeout) return null; } ); - if (!requestKeyChanged) { + if (!receivedNewChallengeKey) { return response; } } @@ -296,26 +289,47 @@ class Valve extends Core { **/ async sendPacketRaw( type, - sendChallenge, payload, onResponse, onTimeout ) { + const challengeAtBeginning = type === 0x55 || type === 0x56; + const challengeAtEnd = type === 0x54 && !!this._challenge; + if (typeof payload === 'string') payload = Buffer.from(payload, 'binary'); - const challengeLength = sendChallenge ? 4 : 0; - const payloadLength = payload ? payload.length : 0; - const b = Buffer.alloc(5 + challengeLength + payloadLength); - b.writeInt32LE(-1, 0); - b.writeUInt8(type, 4); + const b = Buffer.alloc(5 + + (challengeAtBeginning ? 4 : 0) + + (challengeAtEnd ? 4 : 0) + + (payload ? payload.length : 0) + ); + let offset = 0; - if (sendChallenge) { - let challenge = this._challenge; - if (!challenge) challenge = 0xffffffff; - if (this.byteorder === 'le') b.writeUInt32LE(challenge, 5); - else b.writeUInt32BE(challenge, 5); + let challenge = this._challenge; + if (!challenge) challenge = 0xffffffff; + + b.writeInt32LE(-1, offset); + offset += 4; + + b.writeUInt8(type, offset); + offset += 1; + + if (challengeAtBeginning) { + if (this.byteorder === 'le') b.writeUInt32LE(challenge, offset); + else b.writeUInt32BE(challenge, offset); + offset += 4; + } + + if (payload) { + payload.copy(b, offset); + offset += payload.length; + } + + if (challengeAtEnd) { + if (this.byteorder === 'le') b.writeUInt32LE(challenge, offset); + else b.writeUInt32BE(challenge, offset); + offset += 4; } - if (payloadLength) payload.copy(b, 5 + challengeLength); const packetStorage = {}; return await this.udpSend( @@ -353,7 +367,7 @@ class Valve extends Core { packets[packetNum] = payload; - this.debugLog(() => "Received partial packet uid:"+uid+" num:"+packetNum); + this.debugLog(() => "Received partial packet uid: 0x"+uid.toString(16)+" num: "+packetNum); this.debugLog(() => "Received "+Object.keys(packets).length+'/'+numPackets+" packets for this UID"); if(Object.keys(packets).length !== numPackets) return;