flocore-p2p/lib/messages/index.js
2015-03-11 23:57:08 -04:00

94 lines
2.5 KiB
JavaScript

'use strict';
var bitcore = require('bitcore');
var BufferUtil = bitcore.util.buffer;
var Hash = bitcore.crypto.Hash;
function Messages(options) {
this.commands = new Messages.Commands(options);
if (!options) {
options = {};
}
// map command messages
for (var key in this.commands) {
this[key] = this.commands[key];
}
var defaultMagicNumber = bitcore.Networks.defaultNetwork.networkMagic.readUInt32LE(0);
this.magicNumber = options.magicNumber || defaultMagicNumber;
}
Messages.MINIMUM_LENGTH = 20;
Messages.PAYLOAD_START = 16;
Messages.Message = require('./message');
Messages.Commands = require('./commands');
Messages.prototype.parseMessage = function(dataBuffer) {
/* jshint maxstatements: 18 */
if (dataBuffer.length < Messages.MINIMUM_LENGTH) {
return;
}
// Search the next magic number
if (!this.discardUntilNextMessage(dataBuffer)) return;
var payloadLen = (dataBuffer.get(Messages.PAYLOAD_START)) +
(dataBuffer.get(Messages.PAYLOAD_START + 1) << 8) +
(dataBuffer.get(Messages.PAYLOAD_START + 2) << 16) +
(dataBuffer.get(Messages.PAYLOAD_START + 3) << 24);
var messageLength = 24 + payloadLen;
if (dataBuffer.length < messageLength) {
return;
}
var command = dataBuffer.slice(4, 16).toString('ascii').replace(/\0+$/, '');
var payload = dataBuffer.slice(24, messageLength);
var checksum = dataBuffer.slice(20, 24);
var checksumConfirm = Hash.sha256sha256(payload).slice(0, 4);
if (!BufferUtil.equals(checksumConfirm, checksum)) {
dataBuffer.skip(messageLength);
return;
}
dataBuffer.skip(messageLength);
return this.buildFromBuffer(command, payload);
};
Messages.prototype.discardUntilNextMessage = function(dataBuffer) {
var i = 0;
for (;;) {
// check if it's the beginning of a new message
var packageNumber = dataBuffer.slice(0, 4).readUInt32LE(0);
if (packageNumber === this.magicNumber) {
dataBuffer.skip(i);
return true;
}
// did we reach the end of the buffer?
if (i > (dataBuffer.length - 4)) {
dataBuffer.skip(i);
return false;
}
i++; // continue scanning
}
};
Messages.prototype.buildFromBuffer = function(command, payload) {
if (!this.commands[command]) {
throw new Error('Unsupported message command: ' + command);
}
return this.commands[command].fromBuffer(payload);
};
Messages.prototype.build = Messages.prototype.buildFromObject = function(command, object) {
return this.commands[command].fromObject(object);
};
module.exports = Messages;