diff --git a/lib/messages.js b/lib/messages.js index d7848d4..2b2e159 100644 --- a/lib/messages.js +++ b/lib/messages.js @@ -23,9 +23,9 @@ exports.version = { NONCE: new Buffer("20bde0a3355dad78", "hex"), /** - * Decode `version` payload. + * Decode `version` message payload. * NOTE: `nonce` is copied. - * @param {Buffer} buf - `version` payload + * @param {Buffer} buf - Message payload * @return {Object} Decoded `version` structure. */ decode: function(buf) { @@ -60,9 +60,9 @@ exports.version = { }, /** - * Encode `version` payload. + * Encode `version` message payload. * @param {Object} opts - Version options - * @return {Buffer} Encoded `version` payload. + * @return {Buffer} Encoded payload. */ encode: function(opts) { // Deal with default options. @@ -107,8 +107,8 @@ exports.version = { */ exports.addr = { /** - * Decode `addr` payload. - * @param {Buffer} buf - `addr` payload + * Decode `addr` message payload. + * @param {Buffer} buf - Message payload * @return {Object} Decoded `addr` structure. */ decode: function(buf) { @@ -130,9 +130,9 @@ exports.addr = { }, /** - * Encode `addr` payload. + * Encode `addr` message payload. * @param {Object[]} addrs - Network addresses - * @return {Buffer} Encoded `addr` payload. + * @return {Buffer} Encoded payload. */ encode: function(addrs) { assert(addrs.length <= 1000, "Too many address entires"); @@ -150,8 +150,8 @@ exports.addr = { */ var inv = exports.inv = { /** - * Decode `inv` payload. - * @param {Buffer} buf - `inv` payload + * Decode `inv` message payload. + * @param {Buffer} buf - Message payload * @return {Object} Decoded `inv` structure. */ decode: function(buf) { @@ -173,9 +173,9 @@ var inv = exports.inv = { }, /** - * Encode `inv` payload. + * Encode `inv` message payload. * @param {Buffer[]} inventory - Inventory vector list (encoded) - * @return {Buffer} Encoded `inv` payload. + * @return {Buffer} Encoded payload. */ encode: function(inventory) { assert(inventory.length <= 50000, "Too many inventory entires"); @@ -216,8 +216,8 @@ var error = exports.error = { FATAL: 2, /** - * Decode `error` payload. - * @param {Buffer} buf - `error` payload + * Decode `error` message payload. + * @param {Buffer} buf - Message payload * @return {Object} Decoded `error` structure. */ decode: function(buf) { @@ -243,9 +243,9 @@ var error = exports.error = { }, /** - * Encode `error` payload. + * Encode `error` message payload. * @param {Object} opts - Error options - * @return {Buffer} Encoded `error` payload. + * @return {Buffer} Encoded payload. */ encode: function(opts) { var fatal = opts.fatal || error.WARNING; @@ -264,45 +264,67 @@ var error = exports.error = { /** * `object` message. An `object` is a message which is shared throughout * a stream. It is the only message which propagates; all others are - * only between two nodes. + * only between two nodes. + * NOTE: You shouldn't use `encode` and `decode` methods directly. + * Instead, get type of the object and encode/decode it with appropriate + * function from `objects` module. * @see {@link https://bitmessage.org/wiki/Protocol_specification#object} * @namespace */ exports.object = { + // Known types. + GETPUBKEY: 0, + PUBKEY: 1, + MSG: 2, + BROADCAST: 3, + /** - * Decode `object` payload. - * NOTE: `nonce` and `payload` are copied. - * @param {Buffer} buf - `object` payload + * Returns type of the `object` message if we can parse it. Per spec + * we should still relay unknown objects. + * @param {Buffer} buf - Message payload + * @return {?number} Object type. + */ + getType: function(buf) { + // Per v3 spec object starts with nonce (8 bytes), expiresTime (8 + // bytes) and objectType (4 bytes). So we need only first 20 bytes + // to read the type. + if (buf.length >= 20) { + return buf.readUInt32BE(16, true); + } + }, + + /** + * Decode `object` message payload. + * NOTE: `nonce` is copied, `payload` references input buffer. + * @param {Buffer} buf - Message payload * @return {Object} Decoded `object` structure. */ decode: function(buf) { // 8 + 8 + 4 + (1+) + (1+) - assert(buf.length >= 22, "Buffer is too small"); + assert(buf.length >= 22, "object message payload is too small"); var nonce = new Buffer(8); buf.copy(nonce, 0, 0, 8); var expiresTime = util.readTimestamp64BE(buf.slice(8, 16)); var ttl = expiresTime - util.tnow(); assert(ttl >= -3600, "Object expired more than a hour ago"); assert(ttl <= 2430000, "expiresTime is too far in the future"); - var type = buf.readUInt32BE(16); + var type = buf.readUInt32BE(16, true); var decodedVersion = structs.var_int.decode(buf.slice(20)); var decodedStream = structs.var_int.decode(decodedVersion.rest); - var payload = new Buffer(decodedStream.rest.length); - decodedStream.rest.copy(payload); return { nonce: nonce, ttl: ttl, type: type, version: decodedVersion.value, stream: decodedStream.value, - payload: payload, + payload: decodedStream.rest, }; }, /** - * Encode `object` payload. + * Encode `object` message payload. * @param {Object} opts - Object options - * @return {Buffer} Encoded `object` payload. + * @return {Buffer} Encoded payload. */ encode: function(opts) { assert(opts.nonce.length === 8, "Bad nonce"); diff --git a/test.js b/test.js index 0764dd4..8fad570 100644 --- a/test.js +++ b/test.js @@ -410,6 +410,18 @@ describe("Message types", function() { payload: Buffer("test"), })).to.throw(Error); }); + + it("should return type of the object", function() { + var encoded = object.encode({ + nonce: Buffer(8), + ttl: 100, + type: object.BROADCAST, + version: 1, + payload: Buffer("test"), + }); + expect(object.getType(encoded)).to.equal(3); + expect(object.decode(encoded).type).to.equal(3); + }); }); });