From a3c14a8d4280054e9d6b26be38467fca9ccfad1d Mon Sep 17 00:00:00 2001 From: Michael Morrison Date: Sat, 1 Feb 2014 09:47:16 -0600 Subject: [PATCH] Switch minecraftping type to use core TCP support, move SRV resolving into core --- games/minecraft.js | 25 +----- games/minecraftping.js | 188 ++++++++++++++++++----------------------- 2 files changed, 81 insertions(+), 132 deletions(-) diff --git a/games/minecraft.js b/games/minecraft.js index 8414013..61083b1 100644 --- a/games/minecraft.js +++ b/games/minecraft.js @@ -6,29 +6,6 @@ module.exports = require('./protocols/gamespy3').extend({ this.pretty = 'Minecraft'; this.maxAttempts = 2; this.options.port = 25565; - }, - parseDns: function(host,c) { - var self = this; - var _super = this._super; - function fallback(h) { _super.call(self,h,c); } - - dns.resolve('_minecraft._tcp.'+host, 'SRV', function(err,addresses) { - if(err) return fallback(host); - if(addresses.length >= 1) { - var line = addresses[0]; - self.options.port = line.port; - var srvhost = line.name; - - if(srvhost.match(/\d+\.\d+\.\d+\.\d+/)) { - self.options.address = srvhost; - c(); - } else { - // resolve yet again - fallback(srvhost); - } - return; - } - return fallback(host); - }); + this.srvRecord = '_minecraft._tcp'; } }); diff --git a/games/minecraftping.js b/games/minecraftping.js index d97e244..349146d 100644 --- a/games/minecraftping.js +++ b/games/minecraftping.js @@ -1,6 +1,5 @@ -var dns = require('dns'), - net = require('net'), - varint = require('varint'); +var varint = require('varint'), + async = require('async'); function varIntBuffer(num) { return new Buffer(varint.encode(num)); @@ -11,117 +10,90 @@ module.exports = require('./protocols/core').extend({ this._super(); this.pretty = 'Minecraft'; this.options.port = 25565; - }, - parseDns: function(host,c) { - var self = this; - var _super = this._super; - function fallback(h) { _super.call(self,h,c); } - - dns.resolve('_minecraft._tcp.'+host, 'SRV', function(err,addresses) { - if(err) return fallback(host); - if(addresses.length >= 1) { - var line = addresses[0]; - self.options.port = line.port; - var srvhost = line.name; - - if(srvhost.match(/\d+\.\d+\.\d+\.\d+/)) { - self.options.address = srvhost; - c(); - } else { - // resolve yet again - fallback(srvhost); - } - return; - } - return fallback(host); - }); - }, - reset: function() { - this._super(); - if(this.socket) { - this.socket.destroy(); - delete this.socket; - } + this.srvRecord = '_minecraft._tcp'; }, run: function(state) { var self = this; - - var socket = this.socket = net.connect( - this.options.port, - this.options.address, - function() { + var receivedData; - var portBuf = new Buffer(2); - portBuf.writeUInt16BE(self.options.port,0); - - var addressBuf = new Buffer(self.options.address,'utf8'); + async.series([ + function(c) { + // build and send handshake and status TCP packet - var bufs = [ - varIntBuffer(4), - varIntBuffer(addressBuf.length), - addressBuf, - portBuf, - varIntBuffer(1) - ]; - self.sendPacket(0,Buffer.concat(bufs)); - self.sendPacket(0); - }); - socket.setTimeout(10000); - socket.setNoDelay(true); - - var received = new Buffer(0); - var expectedBytes = 0; - socket.on('data', function(data) { - received = Buffer.concat([received,data]); - if(expectedBytes) { - if(received.length >= expectedBytes) { - self.allReceived(received,state); + var portBuf = new Buffer(2); + portBuf.writeUInt16BE(self.options.port,0); + + var addressBuf = new Buffer(self.options.address,'utf8'); + + var bufs = [ + varIntBuffer(4), + varIntBuffer(addressBuf.length), + addressBuf, + portBuf, + varIntBuffer(1) + ]; + + function buildPacket(id,data) { + if(!data) data = new Buffer(0); + var idBuffer = varIntBuffer(id); + return Buffer.concat([ + varIntBuffer(data.length+idBuffer.length), + idBuffer, + data + ]); } - } else if(received.length > 10) { - expectedBytes = varint.decode(received); - received = received.slice(varint.decode.bytesRead); - } - }); - }, - sendPacket: function(id,data) { - if(!data) data = new Buffer(0); - var idBuffer = varIntBuffer(id); - var out = Buffer.concat([ - varIntBuffer(data.length+idBuffer.length), - idBuffer, - data - ]); - this.socket.write(out); - }, - allReceived: function(received,state) { - var packetId = varint.decode(received); - received = received.slice(varint.decode.bytesRead); - - var strLen = varint.decode(received); - received = received.slice(varint.decode.bytesRead); + + var outBuffer = Buffer.concat([ + buildPacket(0,Buffer.concat(bufs)), + buildPacket(0) + ]); + + self.tcpSend(outBuffer, function(data) { + if(data.length < 10) return false; + var expected = varint.decode(data); + data = data.slice(varint.decode.bytesRead); + if(data.length < expected) return false; + receivedData = data; + c(); + }); + }, + function(c) { + // parse response - var str = received.toString('utf8'); - var json; - try { - json = JSON.parse(str); - delete json.favicon; - } catch(e) { - return this.fatal('Invalid JSON'); - } - - state.raw.version = json.version.name; - state.maxplayers = json.players.max; - state.raw.description = json.description.text; - for(var i = 0; i < json.players.sample.length; i++) { - state.players.push({ - id: json.players.sample[i].id, - name: json.players.sample[i].name - }); - } - while(state.players.length < json.players.online) { - state.players.push({}); - } - - this.finish(state); + var data = receivedData; + var packetId = varint.decode(data); + data = data.slice(varint.decode.bytesRead); + + var strLen = varint.decode(data); + data = data.slice(varint.decode.bytesRead); + + var str = data.toString('utf8'); + var json; + try { + json = JSON.parse(str); + delete json.favicon; + if(self.debug) console.log(json); + } catch(e) { + return self.fatal('Invalid JSON'); + } + + state.raw.version = json.version.name; + state.maxplayers = json.players.max; + state.raw.description = json.description.text; + if(json.players.sample) { + for(var i = 0; i < json.players.sample.length; i++) { + state.players.push({ + id: json.players.sample[i].id, + name: json.players.sample[i].name + }); + } + } + while(state.players.length < json.players.online) { + state.players.push({}); + } + + self.finish(state); + } + ]); } });