Support challenges in A2S_INFO (upcoming change to valve protocol) Fixes #210 (2.0.25)

This commit is contained in:
Michael Morrison 2021-02-06 00:50:06 -06:00
parent e99b3c1812
commit e4c29f9cbc
4 changed files with 46 additions and 30 deletions

View File

@ -1,3 +1,6 @@
### 2.0.25
* Support challenges in A2S_INFO (upcoming change to valve protocol)
### 2.0.24 ### 2.0.24
* Add Savage 2: A Tortured Soul (2008) * Add Savage 2: A Tortured Soul (2008)

View File

@ -24,7 +24,7 @@
], ],
"main": "lib/index.js", "main": "lib/index.js",
"author": "GameDig Contributors", "author": "GameDig Contributors",
"version": "2.0.24", "version": "2.0.25",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/gamedig/node-gamedig.git" "url": "https://github.com/gamedig/node-gamedig.git"

View File

@ -10,7 +10,6 @@ class Ffow extends Valve {
this.debugLog("Requesting ffow info ..."); this.debugLog("Requesting ffow info ...");
const b = await this.sendPacket( const b = await this.sendPacket(
0x46, 0x46,
false,
'LSQ', 'LSQ',
0x49 0x49
); );

View File

@ -38,7 +38,6 @@ class Valve extends Core {
this.debugLog("Requesting info ..."); this.debugLog("Requesting info ...");
const b = await this.sendPacket( const b = await this.sendPacket(
0x54, 0x54,
false,
'Source Engine Query\0', 'Source Engine Query\0',
this.goldsrcInfo ? 0x6D : 0x49, this.goldsrcInfo ? 0x6D : 0x49,
false false
@ -127,7 +126,6 @@ class Valve extends Core {
this.debugLog("Requesting legacy challenge key ..."); this.debugLog("Requesting legacy challenge key ...");
await this.sendPacket( await this.sendPacket(
0x57, 0x57,
false,
null, null,
0x41, 0x41,
false false
@ -141,7 +139,6 @@ class Valve extends Core {
this.debugLog("Requesting player list ..."); this.debugLog("Requesting player list ...");
const b = await this.sendPacket( const b = await this.sendPacket(
0x55, 0x55,
true,
null, null,
0x44, 0x44,
true true
@ -180,7 +177,7 @@ class Valve extends Core {
async queryRules(state) { async queryRules(state) {
state.raw.rules = {}; state.raw.rules = {};
this.debugLog("Requesting 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 if (b === null) return; // timed out - the server probably has rules disabled
const reader = this.reader(b); const reader = this.reader(b);
@ -245,33 +242,29 @@ class Valve extends Core {
**/ **/
async sendPacket( async sendPacket(
type, type,
sendChallenge,
payload, payload,
expect, expect,
allowTimeout allowTimeout
) { ) {
for (let keyRetry = 0; keyRetry < 3; keyRetry++) { for (let keyRetry = 0; keyRetry < 3; keyRetry++) {
let requestKeyChanged = false; let receivedNewChallengeKey = false;
const response = await this.sendPacketRaw( const response = await this.sendPacketRaw(
type, sendChallenge, payload, type, payload,
(payload) => { (payload) => {
const reader = this.reader(payload); const reader = this.reader(payload);
const type = reader.uint(1); 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) { if (type === 0x41) {
const key = reader.uint(4); const key = reader.uint(4);
if (this._challenge !== key) { if (this._challenge !== key) {
this.debugLog('Received new challenge key: ' + key); this.debugLog('Received new challenge key: 0x' + key.toString(16));
this._challenge = key; this._challenge = key;
if (sendChallenge) { receivedNewChallengeKey = true;
this.debugLog('Challenge key changed -- allowing query retry if needed');
requestKeyChanged = true;
}
} }
} }
if (type === expect) { if (type === expect) {
return reader.rest(); return reader.rest();
} else if (requestKeyChanged) { } else if (receivedNewChallengeKey) {
return null; return null;
} }
}, },
@ -279,7 +272,7 @@ class Valve extends Core {
if (allowTimeout) return null; if (allowTimeout) return null;
} }
); );
if (!requestKeyChanged) { if (!receivedNewChallengeKey) {
return response; return response;
} }
} }
@ -296,26 +289,47 @@ class Valve extends Core {
**/ **/
async sendPacketRaw( async sendPacketRaw(
type, type,
sendChallenge,
payload, payload,
onResponse, onResponse,
onTimeout onTimeout
) { ) {
const challengeAtBeginning = type === 0x55 || type === 0x56;
const challengeAtEnd = type === 0x54 && !!this._challenge;
if (typeof payload === 'string') payload = Buffer.from(payload, 'binary'); 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); const b = Buffer.alloc(5
b.writeInt32LE(-1, 0); + (challengeAtBeginning ? 4 : 0)
b.writeUInt8(type, 4); + (challengeAtEnd ? 4 : 0)
+ (payload ? payload.length : 0)
);
let offset = 0;
if (sendChallenge) { let challenge = this._challenge;
let challenge = this._challenge; if (!challenge) challenge = 0xffffffff;
if (!challenge) challenge = 0xffffffff;
if (this.byteorder === 'le') b.writeUInt32LE(challenge, 5); b.writeInt32LE(-1, offset);
else b.writeUInt32BE(challenge, 5); 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 = {}; const packetStorage = {};
return await this.udpSend( return await this.udpSend(
@ -353,7 +367,7 @@ class Valve extends Core {
packets[packetNum] = payload; 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"); this.debugLog(() => "Received "+Object.keys(packets).length+'/'+numPackets+" packets for this UID");
if(Object.keys(packets).length !== numPackets) return; if(Object.keys(packets).length !== numPackets) return;