Skip to content
Browse files

Generate a better idToken.

Only first 4 bits of each byte is used so we ended up
with duplicate responses if there were a lot of consecutive
requests done.
Now it masks of anything but the last 4 bits so that
we have a correct token to match against.
Closes #4
  • Loading branch information...
1 parent a2d232c commit a03c175faadf7938a67d8e779f22a46b92ecce10 @kmpm committed Aug 13, 2013
Showing with 134 additions and 138 deletions.
  1. +24 −10 mcquery.js
  2. +2 −2 package.json
  3. +0 −112 test/base-test.js
  4. +108 −14 test/test.js
View
34 mcquery.js
@@ -230,8 +230,10 @@ var Query = module.exports = function Query(host, port){
*/
function generateToken(){
counter +=1;
- if(counter>50000) counter = 0; //just not let it get to big
- return 10000 + counter;
+ //just not let it get to big. 32 bit int is max.
+ if(counter>999999) counter = 0;
+ //the protocol only uses the first 4 bits in every byte so mask.
+ return (10000 + counter) & 0x0F0F0F0F;
}
@@ -245,15 +247,21 @@ function makePacket(type, challengeToken, idToken, payloadBuffer){
var pLength = typeof(payloadBuffer)==='undefined'? 0 : payloadBuffer.length;
var sLength = typeof(challengeToken) !== 'number' ? 0: 4;
var b = new Buffer(7 + sLength+pLength);
- b.writeUInt8(0xFE, 0);
- b.writeUInt8(0xFD, 1);
- b.writeUInt8(type, 2);
- b.writeUInt32BE(idToken, 3);
- if(sLength>0){
- b.writeUInt32BE(challengeToken, 7);
+ try {
+ b.writeUInt8(0xFE, 0);
+ b.writeUInt8(0xFD, 1);
+ b.writeUInt8(type, 2);
+ b.writeUInt32BE(idToken, 3);
+ if(sLength>0){
+ b.writeUInt32BE(challengeToken, 7);
+ }
+ if(pLength>0){
+ payloadBuffer.copy(b, 7+sLength +1);
+ }
}
- if(pLength>0){
- payloadBuffer.copy(b, 7+sLength +1);
+ catch(err){
+ log.error("type=%s, challengeToken=%s, idToken=%s", type, challengeToken, idToken);
+ throw err;
}
return b;
}
@@ -268,12 +276,15 @@ function readPacket(data){
type:data.readUInt8(0),
idToken:data.readUInt32BE(1),
};
+ log.debug("response=%j", res);
+
data = data.slice(5);
if(res.type===CHALLENGE_TYPE){
res.challengeToken=parseInt(data.toString());
}
else if(res.type===STAT_TYPE){
var r = readString(data);
+ log.debug("data=%j", r);
if(r.text !== 'splitnum'){
//basic stat
res.MOTD = r.text;
@@ -296,6 +307,7 @@ function readPacket(data){
else {
var offset=r.offset;
res.splitnum = r.text;
+ //add key_val_start to response. It's the start byte of the response
res.key_val_start = data.readUInt16LE(offset);offset+=2;
var key;
var value;
@@ -306,6 +318,8 @@ function readPacket(data){
value = r.text;
res[key]=value;
}
+
+ //add key_val_ed to response. It's the end byte of the response
res.key_val_end = data.readUInt16LE(offset);offset+=2;
r = readString(data, offset); offset=r.offset;
View
4 package.json
@@ -15,8 +15,8 @@
"url" : "http://github.com/kmpm/node-mcquery.git"
},
"devDependencies": {
- "vows": "*",
"mocha": "*",
- "async": "*"
+ "should": "*",
+ "nimble": "*"
}
}
View
112 test/base-test.js
@@ -1,112 +0,0 @@
-/*!
- * Copyright © 2011-2012 Peter Magnusson.
- * All rights reserved.
- */
-var vows = require('vows'),
- assert = require('assert'),
- fs = require('fs'),
- path = require('path');
-
-var f = path.resolve('./config.json');
-
-if(fs.existsSync(f)){
- var config = require(f);
-}
-else {
- config={host:'localhost', port:25565};
-}
-var Query = require('../mcquery');
-
-var TEST_HOST=config.host;
-var TEST_PORT=config.port;
-var global_query = new Query(TEST_HOST, TEST_PORT);
-
-vows.describe('GS4 Query').addBatch({
- 'connect':{
- topic:function(){
- global_query.connect(this.callback);
- },
- 'does not return error':function(err, session){
- assert.isNull(err);
- },
- 'returns a session object':function(err, session){
- assert.isObject(session);
- },
- 'session object':{
- topic:function(session){
- return session;
- },
- 'has challengeToken':function(session){
- assert.include(session, 'challengeToken');
- assert.isNumber(session.challengeToken);
- //have never seen a lower value then 20000
- assert.isTrue(session.challengeToken>20000);
- },
- /*'has host':function(session){
- assert.include(session, 'host');
- assert.isString(session.host);
- assert.equal(session.host, TEST_HOST);
- },
- 'has port':function(session){
- assert.include(session, 'port');
- assert.isNumber(session.port);
- assert.equal(session.port, TEST_PORT);
- },
- 'has sessionToken':function(session){
- assert.include(session, 'sessionToken');
- assert.isNumber(session.sessionToken);
- }*/
- },//topic session object
- 'basic_stat':{
- topic:function(session){
- //var query = new Query(TEST_HOST, TEST_PORT);
- global_query.basic_stat(this.callback);
- },
- 'does not return error':function(err, stat){
- assert.isNull(err);
- },
- 'returns a stat object':function(err, stat){
- assert.isObject(stat);
- assert.include(stat, 'MOTD');
- assert.include(stat, 'gametype');
- assert.include(stat, 'map');
- assert.include(stat, 'numplayers');
- assert.isNumber(stat.numplayers);
- assert.include(stat, 'maxplayers');
- assert.isNumber(stat.maxplayers);
- assert.include(stat, 'hostport');
- assert.isNumber(stat.hostport);
- assert.include(stat, 'hostip');
- //console.log(stat);
- }
- },//topic basic_stat
- 'full_stat':{
- topic:function(){
- //var query=new Query(TEST_HOST, TEST_PORT);
- var callback= this.callback;
- //start a new session, we are async!
- //query.connect(function(err, session){
- global_query.full_stat(callback);
- //});
- },
- 'does not return error':function(err, stat){
- assert.isNull(err);
- },
- 'returns a full stat object':function(err, stat){
- assert.isObject(stat);
- var props = ['splitnum', 'key_val_start'
- , 'hostname', 'gametype'
- , 'game_id', 'version'
- , 'plugins', 'map'
- , 'numplayers', 'maxplayers'
- , 'hostport', 'hostip'
- , 'key_val_end', 'player_'];
- for(var i=0; i<props.length;i++){
- assert.include(stat, props[i]);
- }
- assert.isArray(stat.player_);
- }
- }//topic full_stat
- }//topic startSession
-
-}).export(module);
View
122 test/test.js
@@ -1,35 +1,129 @@
/*global describe it before after */
-var assert = require('assert');
+var assert = require('assert')
+ , should = require('should')
+ , flow = require('nimble')
+ , util = require('util');
-var server ={
+var server_missing ={
host: 'srv8.streamcraft.net',
port: 33334
};
+var server_existing = {
+ host: 'mc.craftyn.com', //'srv1.streamcraft.net',
+ port: 25565, //11111
+}
+
var Query = require('../mcquery');
-var global_query = new Query('srv1.streamcraft.net', 11111);
+var global_query = new Query(server_existing.host, server_existing.port );
+var global_session;
describe('mcquery', function() {
- describe('after connection', function(){
+ after(function(done){
+ //global_query.close();
+ console.log("closing");
+ done();
+ });
+
+ it('should connect', function(done){
+ global_query.connect(function(err, session){
+ should.not.exist(err);
+ should.exist(session);
+ global_session=session;
+ done();
+ });
+ });
+
+ it('should have a proper session', function(){
+ should.exist(global_session);
+ global_session.should.be.instanceOf(Query);
+ global_session.should.have.property('challengeToken');
+ global_session.challengeToken.should.be.within(1, 0XFFFFFFFF);
+ });
+
+ it('should have a correct idToken', function(){
+ should.exist(global_session);
+ global_session.should.have.property('idToken');
+ global_session.challengeToken.should.be.within(1, 0XFFFFFFFF);
+ //test masking
+ global_session.idToken.should.equal(global_session.idToken & 0x0F0F0F0F);
+ });
+
+ describe('.basic_stat(err, result)', function(){
+ var result, err;
before(function(done){
- this.timeout(5000);
- global_query.connect(function(err, session){
- assert.isNull(err);
- });
+ should.exist(global_session);
+ global_query.basic_stat(function(er, res){
+ err = er;
+ result = res;
+ done();
+ });
});
- after(function(done){
- global_query.close;
- });
-
- it('basic_stat should work', function(done){
- global_query.basic_stat(done);
+ it('err should be null', function(){
+ should.not.exist(err);
});
+
+ it('result should be correct', function(){
+ should.exist(result);
+ result.should.have.property('MOTD');
+ result.should.have.property('gametype');
+ result.should.have.property('map');
+ result.should.have.property('numplayers');
+ result.numplayers.should.be.within(0, 1024);
+ result.should.have.property('maxplayers');
+ result.maxplayers.should.be.within(0,1024);
+
+ result.should.have.property('hostport');
+ result.hostport.should.be.within(1, 65535);
+ result.should.have.property('hostip');
+ })
+ });
+
+
+ describe('.full_stat(err, result)', function(){
+ var err, result;
+ before(function(done){
+ global_query.full_stat(function(er, stat){
+ err = er;
+ result = stat;
+ done();
+ })
+ });
+
+ it('err should be null', function(){
+ should.not.exist(err);
+ });
+
+ it('result should be correct', function(){
+ should.exist(result);
+ var props = [
+ 'hostname',
+ 'gametype',
+ 'numplayers',
+ 'maxplayers',
+ 'hostport',
+ 'hostip',
+ 'splitnum',
+ 'key_val_start', //bonus
+ 'game_id',
+ 'version',
+ 'plugins', 'map',
+ 'player_',
+ 'key_val_end', //bonus
+ ];
+ for(var i=0; i<props.length;i++){
+ result.should.have.property(props[i]);
+ }
+ result.player_.should.be.instanceOf(Array);
+
+ });
});
+
});

0 comments on commit a03c175

Please sign in to comment.
Something went wrong with that request. Please try again.