2015-01-02 22:45:56 +01:00
|
|
|
/**
|
|
|
|
* Working with messages.
|
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification#Message_types}
|
2015-01-16 01:08:56 +01:00
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification_v3#Message_types}
|
|
|
|
* @see {@link https://bitmessage.org/Bitmessage%20Technical%20Paper.pdf}
|
2015-01-03 15:52:27 +01:00
|
|
|
* @module bitmessage/messages
|
2015-02-12 11:36:44 +01:00
|
|
|
* @example
|
|
|
|
* var structs = require("bitmessage").structs;
|
|
|
|
* var messages = require("bitmessage").messages;
|
|
|
|
*
|
|
|
|
* // Simple encoding and decoding:
|
|
|
|
* var vermsg = messages.version.encode({
|
|
|
|
* remoteHost: "1.1.1.1",
|
|
|
|
* remotePort: 8444,
|
|
|
|
* });
|
|
|
|
* console.log(messages.version.decode(vermsg).remoteHost); // 1.1.1.1
|
|
|
|
*
|
|
|
|
* // Low-level encoding and decoding:
|
|
|
|
* var addrPayload = messages.addr.encodePayload([
|
|
|
|
* {host: "2.2.2.2", port: 28444},
|
|
|
|
* ]);
|
|
|
|
* var addrmsg = structs.message.encode("addr", addrPayload);
|
|
|
|
* var decoded = structs.message.decode(addrmsg);
|
|
|
|
* console.log(decoded.command); // addr
|
2015-02-24 19:21:42 +01:00
|
|
|
* var addr = messages.addr.decodePayload(decoded.payload);
|
|
|
|
* console.log(addr.addrs[0].host); // 2.2.2.2
|
2015-02-12 11:36:44 +01:00
|
|
|
*
|
|
|
|
* // Encode with empty payload:
|
|
|
|
* var verackmsg = structs.message.encode("verack");
|
|
|
|
* console.log(structs.message.decode(verackmsg).command); // verack
|
2015-01-02 22:45:56 +01:00
|
|
|
*/
|
2015-01-15 18:13:02 +01:00
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
var objectAssign = Object.assign || require("object-assign");
|
2015-01-22 01:00:58 +01:00
|
|
|
var assert = require("./_util").assert;
|
2015-01-15 18:13:02 +01:00
|
|
|
var structs = require("./structs");
|
2015-02-01 15:09:46 +01:00
|
|
|
var bmcrypto = require("./crypto");
|
2015-01-15 18:13:02 +01:00
|
|
|
var UserAgent = require("./user-agent");
|
2015-01-22 01:00:58 +01:00
|
|
|
var util = require("./_util");
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
var message = structs.message;
|
2015-01-22 01:00:58 +01:00
|
|
|
var ServicesBitfield = structs.ServicesBitfield;
|
2015-01-15 18:13:02 +01:00
|
|
|
|
2015-01-27 14:35:49 +01:00
|
|
|
/**
|
2015-01-28 14:31:18 +01:00
|
|
|
* Try to get command of the given encoded message.
|
2015-01-27 14:35:49 +01:00
|
|
|
* Note that this function doesn't do any validation because it is
|
2015-01-31 12:51:35 +01:00
|
|
|
* already provided by
|
|
|
|
* [message.decode]{@link module:bitmessage/structs.message.decode}
|
2015-02-09 22:56:55 +01:00
|
|
|
* routine.
|
2015-01-27 14:35:49 +01:00
|
|
|
* @param {Buffer} buf - Buffer that starts with encoded message
|
2015-01-31 12:51:35 +01:00
|
|
|
* @return {?string} Message's command if any.
|
2015-01-27 14:35:49 +01:00
|
|
|
*/
|
|
|
|
exports.getCommand = function(buf) {
|
|
|
|
if (buf.length < 16) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var command = buf.slice(4, 16);
|
|
|
|
var firstNonNull = 0;
|
|
|
|
for (var i = 11; i >=0; i--) {
|
|
|
|
if (command[i] !== 0) {
|
|
|
|
firstNonNull = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return command.slice(0, firstNonNull).toString("ascii");
|
|
|
|
};
|
|
|
|
|
2015-01-15 18:13:02 +01:00
|
|
|
/**
|
2015-01-15 22:00:27 +01:00
|
|
|
* `version` message.
|
2015-01-15 18:13:02 +01:00
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification#version}
|
|
|
|
* @namespace
|
2015-01-26 18:03:43 +01:00
|
|
|
* @static
|
2015-01-15 18:13:02 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
var version = exports.version = {
|
2015-02-11 16:16:43 +01:00
|
|
|
/**
|
|
|
|
* @typedef {Object} DecodeResult
|
2015-02-24 17:09:01 +01:00
|
|
|
* @property {number} protoVersion - Identifies protocol version being
|
|
|
|
* used by the node. Should equal 3. Nodes should disconnect if the
|
|
|
|
* remote node's version is lower but continue with the connection if
|
|
|
|
* it is higher.
|
2015-02-11 16:16:43 +01:00
|
|
|
* @property {Object} services -
|
|
|
|
* [Service]{@link module:bitmessage/structs.ServicesBitfield}
|
|
|
|
* features to be enabled for this connection
|
|
|
|
* @property {Date} time - Node time
|
|
|
|
* @property {string} remoteHost - IPv4/IPv6 address of the node
|
|
|
|
* receiving this message
|
|
|
|
* @property {number} remotePort - Port of the node receiving this
|
|
|
|
* message
|
|
|
|
* @property {number} port - Incoming port of the node sending this
|
|
|
|
* message
|
2015-02-24 17:38:03 +01:00
|
|
|
* @property {Buffer} nonce - An 8-byte random nonce used to detect
|
|
|
|
* connection to self
|
2015-02-23 19:23:53 +01:00
|
|
|
* @property {string} userAgent - [User agent]{@link
|
|
|
|
* module:bitmessage/user-agent} of the node
|
2015-02-24 16:42:57 +01:00
|
|
|
* @property {number[]} streams - Streams accepted by the node
|
2015-02-11 16:16:43 +01:00
|
|
|
* @property {number} length - Real data length
|
|
|
|
* @memberof module:bitmessage/messages.version
|
|
|
|
*/
|
|
|
|
|
2015-02-24 17:38:03 +01:00
|
|
|
/**
|
|
|
|
* Random nonce used to detect connections to self.
|
|
|
|
* @constant {Buffer}
|
|
|
|
*/
|
|
|
|
randomNonce: bmcrypto.randomBytes(8),
|
|
|
|
|
2015-01-31 12:51:35 +01:00
|
|
|
/**
|
2015-02-01 15:09:46 +01:00
|
|
|
* Decode `version` message.
|
2015-01-26 18:03:43 +01:00
|
|
|
* NOTE: `nonce` is copied.
|
|
|
|
* @param {Buffer} buf - Message
|
2015-02-11 16:16:43 +01:00
|
|
|
* @return {DecodeResult}
|
|
|
|
* [Decoded `version` structure.]{@link module:bitmessage/messages.version.DecodeResult}
|
2015-01-26 18:03:43 +01:00
|
|
|
*/
|
|
|
|
decode: function(buf) {
|
|
|
|
var decoded = message.decode(buf);
|
|
|
|
assert(decoded.command === "version", "Bad command");
|
|
|
|
return version.decodePayload(decoded.payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 18:13:02 +01:00
|
|
|
/**
|
2015-02-11 16:16:43 +01:00
|
|
|
* Decode `version` message payload.
|
|
|
|
* The same as [decode]{@link module:bitmessage/messages.version.decode}.
|
2015-01-15 18:13:02 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
decodePayload: function(buf) {
|
2015-01-15 18:13:02 +01:00
|
|
|
// 4 + 8 + 8 + 26 + 26 + 8 + (1+) + (1+)
|
2015-01-15 23:43:15 +01:00
|
|
|
assert(buf.length >= 82, "Buffer is too small");
|
|
|
|
var protoVersion = buf.readUInt32BE(0, true);
|
2015-01-19 00:05:53 +01:00
|
|
|
var services = ServicesBitfield(buf.slice(4, 12), {copy: true});
|
2015-01-15 23:43:15 +01:00
|
|
|
var time = util.readTime64BE(buf, 12);
|
2015-01-15 18:13:02 +01:00
|
|
|
var short = {short: true};
|
2015-01-15 23:43:15 +01:00
|
|
|
var addrRecv = structs.net_addr.decode(buf.slice(20, 46), short);
|
|
|
|
var addrFrom = structs.net_addr.decode(buf.slice(46, 72), short);
|
2015-01-15 18:13:02 +01:00
|
|
|
var nonce = new Buffer(8);
|
2015-01-15 23:43:15 +01:00
|
|
|
buf.copy(nonce, 0, 72, 80);
|
|
|
|
var decodedUa = UserAgent.decode(buf.slice(80));
|
2015-02-24 18:12:52 +01:00
|
|
|
assert(decodedUa.length <= 5000, "User agent is too long");
|
2015-02-24 16:42:57 +01:00
|
|
|
var decodedStreams = structs.var_int_list.decode(decodedUa.rest);
|
2015-02-24 18:12:52 +01:00
|
|
|
assert(decodedStreams.list.length <= 160000, "Too many streams");
|
2015-01-15 18:13:02 +01:00
|
|
|
return {
|
2015-02-24 17:09:01 +01:00
|
|
|
protoVersion: protoVersion,
|
2015-01-15 18:13:02 +01:00
|
|
|
services: services,
|
|
|
|
time: time,
|
|
|
|
remoteHost: addrRecv.host,
|
|
|
|
remotePort: addrRecv.port,
|
|
|
|
port: addrFrom.port,
|
|
|
|
nonce: nonce,
|
2015-01-24 13:13:21 +01:00
|
|
|
userAgent: decodedUa.str,
|
2015-02-24 16:42:57 +01:00
|
|
|
streams: decodedStreams.list,
|
2015-01-15 18:13:02 +01:00
|
|
|
// NOTE(Kagami): Real data length. It may be some gap between end
|
|
|
|
// of stream numbers list and end of payload:
|
|
|
|
// [payload..............[stream numbers]xxxx]
|
|
|
|
// We are currently ignoring that.
|
2015-02-24 16:42:57 +01:00
|
|
|
length: 80 + decodedUa.length + decodedStreams.length,
|
2015-01-15 18:13:02 +01:00
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Encode `version` message.
|
|
|
|
* @param {Object} opts - Version options
|
2015-02-11 16:16:43 +01:00
|
|
|
* @param {Object=} opts.services -
|
|
|
|
* [Service]{@link module:bitmessage/structs.ServicesBitfield}
|
|
|
|
* features to be enabled for this connection (`NODE_NETWORK` by
|
|
|
|
* default)
|
|
|
|
* @param {Date=} opts.time - Node time (current time by default)
|
|
|
|
* @param {string} opts.remoteHost - IPv4/IPv6 address of the node
|
|
|
|
* receiving this message
|
|
|
|
* @param {number} opts.remotePort - Port of the node receiving this
|
|
|
|
* message
|
|
|
|
* @param {number=} opts.port - Incoming port of the node (8444 by
|
|
|
|
* default)
|
2015-02-24 17:38:03 +01:00
|
|
|
* @param {Buffer=} opts.nonce - An 8-byte random nonce used to detect
|
|
|
|
* connection to self (unique per node.js process by default)
|
2015-02-11 16:16:43 +01:00
|
|
|
* @param {(Array|string|Buffer)=} opts.userAgent -
|
|
|
|
* [User agent]{@link module:bitmessage/user-agent} of the node
|
2015-02-24 09:47:56 +01:00
|
|
|
* (user agent of bitmessage library by default)
|
2015-02-24 16:42:57 +01:00
|
|
|
* @param {Array<number>=} opts.streams - Streams accepted by the node
|
|
|
|
* ([1] by default)
|
2015-01-26 18:03:43 +01:00
|
|
|
* @return {Buffer} Encoded message.
|
|
|
|
*/
|
|
|
|
encode: function(opts) {
|
|
|
|
var payload = version.encodePayload(opts);
|
|
|
|
return message.encode("version", payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 18:13:02 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Encode `version` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [encode]{@link module:bitmessage/messages.version.encode}.
|
2015-01-15 18:13:02 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
encodePayload: function(opts) {
|
2015-01-15 18:13:02 +01:00
|
|
|
// Deal with default options.
|
2015-01-19 00:05:53 +01:00
|
|
|
var services = opts.services ||
|
|
|
|
ServicesBitfield().set(ServicesBitfield.NODE_NETWORK);
|
2015-01-15 18:13:02 +01:00
|
|
|
var time = opts.time || new Date();
|
2015-02-24 17:38:03 +01:00
|
|
|
var nonce = opts.nonce || version.randomNonce;
|
2015-01-16 00:14:30 +01:00
|
|
|
assert(nonce.length === 8, "Bad nonce");
|
2015-02-09 15:38:10 +01:00
|
|
|
var port = opts.port || 8444;
|
2015-02-24 18:12:52 +01:00
|
|
|
var userAgent = UserAgent.encode(opts.userAgent || UserAgent.SELF);
|
|
|
|
assert(userAgent.length <= 5000, "User agent is too long");
|
2015-02-24 16:42:57 +01:00
|
|
|
var streams = opts.streams || [1];
|
2015-02-24 18:12:52 +01:00
|
|
|
assert(streams.length <= 160000, "Too many streams");
|
2015-01-15 18:13:02 +01:00
|
|
|
// Start encoding.
|
|
|
|
var protoVersion = new Buffer(4);
|
2015-01-22 01:00:58 +01:00
|
|
|
protoVersion.writeUInt32BE(util.PROTOCOL_VERSION, 0);
|
2015-01-15 18:13:02 +01:00
|
|
|
var addrRecv = structs.net_addr.encode({
|
|
|
|
services: services,
|
|
|
|
host: opts.remoteHost,
|
|
|
|
port: opts.remotePort,
|
|
|
|
short: true,
|
|
|
|
});
|
|
|
|
var addrFrom = structs.net_addr.encode({
|
|
|
|
services: services,
|
|
|
|
host: "127.0.0.1",
|
2015-02-09 15:38:10 +01:00
|
|
|
port: port,
|
2015-01-15 18:13:02 +01:00
|
|
|
short: true,
|
|
|
|
});
|
|
|
|
return Buffer.concat([
|
|
|
|
protoVersion,
|
2015-01-19 00:05:53 +01:00
|
|
|
services.buffer,
|
2015-01-15 18:13:02 +01:00
|
|
|
util.writeTime64BE(null, time),
|
|
|
|
addrRecv,
|
|
|
|
addrFrom,
|
|
|
|
nonce,
|
2015-02-24 18:12:52 +01:00
|
|
|
userAgent,
|
2015-02-24 16:42:57 +01:00
|
|
|
structs.var_int_list.encode(streams),
|
2015-01-15 18:13:02 +01:00
|
|
|
]);
|
|
|
|
},
|
|
|
|
};
|
2015-01-15 19:11:33 +01:00
|
|
|
|
|
|
|
/**
|
2015-01-15 22:00:27 +01:00
|
|
|
* `addr` message. Provide information on known nodes of the network.
|
2015-01-15 19:11:33 +01:00
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification#addr}
|
|
|
|
* @namespace
|
2015-01-26 18:03:43 +01:00
|
|
|
* @static
|
2015-01-15 19:11:33 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
var addr = exports.addr = {
|
2015-02-11 16:16:43 +01:00
|
|
|
/**
|
|
|
|
* @typedef {Object} DecodeResult
|
|
|
|
* @property {Object[]} addrs - List of
|
|
|
|
* [decoded `net_addr` structures]{@link module:bitmessage/structs.net_addr.DecodeResult}
|
|
|
|
* @property {number} length - Real data length
|
|
|
|
* @memberof module:bitmessage/messages.addr
|
|
|
|
*/
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Decode `addr` message.
|
|
|
|
* @param {Buffer} buf - Message
|
2015-02-11 16:16:43 +01:00
|
|
|
* @return {DecodeResult}
|
|
|
|
* [Decoded `addr` structure.]{@link module:bitmessage/messages.addr.DecodeResult}
|
2015-01-26 18:03:43 +01:00
|
|
|
*/
|
|
|
|
decode: function(buf) {
|
|
|
|
var decoded = message.decode(buf);
|
|
|
|
assert(decoded.command === "addr", "Bad command");
|
|
|
|
return addr.decodePayload(decoded.payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 19:11:33 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Decode `addr` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [decode]{@link module:bitmessage/messages.addr.decode}.
|
2015-01-15 19:11:33 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
decodePayload: function(buf) {
|
2015-01-15 19:11:33 +01:00
|
|
|
var decoded = structs.var_int.decode(buf);
|
|
|
|
var listLength = decoded.value;
|
2015-01-15 21:19:52 +01:00
|
|
|
assert(listLength <= 1000, "Too many address entires");
|
2015-01-15 19:11:33 +01:00
|
|
|
var length = decoded.length + listLength * 38;
|
|
|
|
assert(buf.length >= length, "Buffer is too small");
|
|
|
|
var rest = decoded.rest;
|
|
|
|
var addrs = new Array(listLength);
|
|
|
|
for (var i = 0; i < listLength; i++) {
|
|
|
|
addrs[i] = structs.net_addr.decode(rest.slice(i*38, (i+1)*38));
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
addrs: addrs,
|
|
|
|
// Real data length.
|
|
|
|
length: length,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Encode `addr` message.
|
2015-02-11 16:16:43 +01:00
|
|
|
* @param {Object[]} addrs - List of
|
|
|
|
* [net_addr encode options]{@link module:bitmessage/structs.net_addr.encode}
|
2015-01-26 18:03:43 +01:00
|
|
|
* @return {Buffer} Encoded message.
|
|
|
|
*/
|
|
|
|
encode: function(addrs) {
|
|
|
|
var payload = addr.encodePayload(addrs);
|
|
|
|
return message.encode("addr", payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 19:11:33 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Encode `addr` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [encode]{@link module:bitmessage/messages.addr.encode}.
|
2015-01-15 19:11:33 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
encodePayload: function(addrs) {
|
2015-01-15 21:19:52 +01:00
|
|
|
assert(addrs.length <= 1000, "Too many address entires");
|
2015-02-11 14:52:40 +01:00
|
|
|
var addrBufs = addrs.map(structs.net_addr.encode);
|
|
|
|
var bufs = [structs.var_int.encode(addrs.length)].concat(addrBufs);
|
|
|
|
return Buffer.concat(bufs);
|
2015-01-15 19:11:33 +01:00
|
|
|
},
|
|
|
|
};
|
2015-01-15 22:00:27 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* `inv` message. Allows a node to advertise its knowledge of one or
|
|
|
|
* more objects.
|
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification#inv}
|
|
|
|
* @namespace
|
2015-01-15 22:07:49 +01:00
|
|
|
* @static
|
2015-01-15 22:00:27 +01:00
|
|
|
*/
|
2015-01-15 22:07:49 +01:00
|
|
|
var inv = exports.inv = {
|
2015-02-11 16:16:43 +01:00
|
|
|
/**
|
|
|
|
* @typedef {Object} DecodeResult
|
|
|
|
* @property {Buffer[]} inventory - List of
|
|
|
|
* [inventory vectors]{@link module:bitmessage/structs.inv_vect}
|
|
|
|
* @property {number} length - Real data length
|
|
|
|
* @memberof module:bitmessage/messages.inv
|
|
|
|
*/
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Decode `inv` message.
|
|
|
|
* @param {Buffer} buf - Message
|
2015-02-11 16:16:43 +01:00
|
|
|
* @return {DecodeResult}
|
|
|
|
* [Decoded `inv` structure.]{@link module:bitmessage/messages.inv.DecodeResult}
|
2015-01-26 18:03:43 +01:00
|
|
|
*/
|
|
|
|
decode: function(buf) {
|
|
|
|
var decoded = message.decode(buf);
|
|
|
|
assert(decoded.command === "inv", "Bad command");
|
|
|
|
return inv.decodePayload(decoded.payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 22:00:27 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Decode `inv` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [decode]{@link module:bitmessage/messages.inv.decode}.
|
2015-01-15 22:00:27 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
decodePayload: function(buf) {
|
2015-01-15 22:00:27 +01:00
|
|
|
var decoded = structs.var_int.decode(buf);
|
|
|
|
var listLength = decoded.value;
|
|
|
|
assert(listLength <= 50000, "Too many inventory entires");
|
|
|
|
var length = decoded.length + listLength * 32;
|
|
|
|
assert(buf.length >= length, "Buffer is too small");
|
|
|
|
var rest = decoded.rest;
|
|
|
|
var inventory = new Array(listLength);
|
|
|
|
for (var i = 0; i < listLength; i++) {
|
|
|
|
inventory[i] = rest.slice(i*32, (i+1)*32);
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
inventory: inventory,
|
|
|
|
// Real data length.
|
|
|
|
length: length,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Encode `inv` message.
|
2015-02-11 16:16:43 +01:00
|
|
|
* @param {Buffer[]} inventory -
|
|
|
|
* [Inventory vector]{@link module:bitmessage/structs.inv_vect} list
|
2015-01-26 18:03:43 +01:00
|
|
|
* @return {Buffer} Encoded message.
|
|
|
|
*/
|
|
|
|
encode: function(inventory) {
|
|
|
|
var payload = inv.encodePayload(inventory);
|
|
|
|
return message.encode("inv", payload);
|
|
|
|
},
|
|
|
|
|
2015-01-15 22:00:27 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Encode `inv` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [encode]{@link module:bitmessage/messages.inv.encode}.
|
2015-01-15 22:00:27 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
encodePayload: function(inventory) {
|
2015-01-15 22:00:27 +01:00
|
|
|
assert(inventory.length <= 50000, "Too many inventory entires");
|
2015-02-11 15:53:49 +01:00
|
|
|
// TODO(Kagami): Validate vectors length.
|
2015-02-11 14:52:40 +01:00
|
|
|
var bufs = [structs.var_int.encode(inventory.length)].concat(inventory);
|
|
|
|
return Buffer.concat(bufs);
|
2015-01-15 22:00:27 +01:00
|
|
|
},
|
|
|
|
};
|
2015-01-15 22:07:49 +01:00
|
|
|
|
|
|
|
/**
|
2015-01-31 12:51:35 +01:00
|
|
|
* `getdata` message. `getdata` is used in response to an
|
|
|
|
* [inv]{@link module:bitmessage/messages.inv} message to retrieve the
|
|
|
|
* content of a specific object after filtering known elements.
|
2015-01-15 22:07:49 +01:00
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification#getdata}
|
|
|
|
* @namespace
|
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
exports.getdata = objectAssign({}, inv, {
|
2015-02-11 16:16:43 +01:00
|
|
|
/**
|
|
|
|
* @typedef {Object} DecodeResult
|
|
|
|
* @property {Buffer[]} inventory - List of
|
|
|
|
* [inventory vectors]{@link module:bitmessage/structs.inv_vect}
|
|
|
|
* @property {number} length - Real data length
|
|
|
|
* @memberof module:bitmessage/messages.getdata
|
|
|
|
*/
|
|
|
|
|
2015-01-31 12:51:35 +01:00
|
|
|
/**
|
|
|
|
* Decode `getdata` message.
|
|
|
|
* @param {Buffer} buf - Message
|
2015-02-11 16:16:43 +01:00
|
|
|
* @return {DecodeResult}
|
|
|
|
* [Decoded `getdata` structure.]{@link module:bitmessage/messages.getdata.DecodeResult}
|
2015-01-31 12:51:35 +01:00
|
|
|
* @memberof module:bitmessage/messages.getdata
|
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
decode: function(buf) {
|
|
|
|
var decoded = message.decode(buf);
|
|
|
|
assert(decoded.command === "getdata", "Bad command");
|
|
|
|
return inv.decodePayload(decoded.payload);
|
|
|
|
},
|
2015-02-11 16:16:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Decode `getdata` message payload.
|
|
|
|
* The same as [decode]{@link module:bitmessage/messages.getdata.decode}.
|
|
|
|
* @function decodePayload
|
|
|
|
* @memberof module:bitmessage/messages.getdata
|
|
|
|
*/
|
|
|
|
|
2015-01-31 12:51:35 +01:00
|
|
|
/**
|
|
|
|
* Encode `getdata` message.
|
2015-02-11 16:16:43 +01:00
|
|
|
* @param {Buffer[]} inventory -
|
|
|
|
* [Inventory vector]{@link module:bitmessage/structs.inv_vect} list
|
2015-01-31 12:51:35 +01:00
|
|
|
* @return {Buffer} Encoded message.
|
|
|
|
* @memberof module:bitmessage/messages.getdata
|
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
encode: function(inventory) {
|
|
|
|
var payload = inv.encodePayload(inventory);
|
|
|
|
return message.encode("getdata", payload);
|
|
|
|
},
|
2015-02-11 16:16:43 +01:00
|
|
|
|
2015-01-31 12:51:35 +01:00
|
|
|
/**
|
|
|
|
* Encode `getdata` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [encode]{@link module:bitmessage/messages.getdata.encode}.
|
2015-01-31 12:51:35 +01:00
|
|
|
* @function encodePayload
|
|
|
|
* @memberof module:bitmessage/messages.getdata
|
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
});
|
2015-01-16 00:14:30 +01:00
|
|
|
|
2015-01-16 01:08:56 +01:00
|
|
|
/**
|
|
|
|
* `error` message.
|
|
|
|
* @see {@link https://bitmessage.org/wiki/Protocol_specification_v3#error}
|
|
|
|
* @namespace
|
2015-01-26 18:03:43 +01:00
|
|
|
* @static
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
|
|
|
var error = exports.error = {
|
|
|
|
/**
|
|
|
|
* Just a warning.
|
2015-01-31 12:51:35 +01:00
|
|
|
* @constant {number}
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
|
|
|
WARNING: 0,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* It's an error, something was going wrong (e.g. an object got lost).
|
2015-01-31 12:51:35 +01:00
|
|
|
* @constant {number}
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
|
|
|
ERROR: 1,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* It's a fatal error. The node will drop the line for that error and
|
|
|
|
* maybe ban you for some time.
|
2015-01-31 12:51:35 +01:00
|
|
|
* @constant {number}
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
|
|
|
FATAL: 2,
|
|
|
|
|
2015-02-21 18:17:12 +01:00
|
|
|
/**
|
|
|
|
* Convert error type to a human-readable string.
|
2015-02-24 17:18:49 +01:00
|
|
|
* @param {number} type - Type of the error
|
2015-02-21 18:17:12 +01:00
|
|
|
* @return {string}
|
|
|
|
*/
|
2015-02-24 17:18:49 +01:00
|
|
|
type2str: function(type) {
|
|
|
|
switch (type) {
|
2015-02-21 18:17:12 +01:00
|
|
|
case error.WARNING: return "warning";
|
|
|
|
case error.ERROR: return "error";
|
|
|
|
case error.FATAL: return "fatal";
|
|
|
|
default: return "unknown";
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-02-11 16:16:43 +01:00
|
|
|
/**
|
|
|
|
* @typedef {Object} DecodeResult
|
2015-02-24 17:18:49 +01:00
|
|
|
* @property {number} type - Type of the error
|
2015-02-11 16:16:43 +01:00
|
|
|
* @property {number} banTime - The other node informs that it will
|
|
|
|
* not accept further connections for this number of seconds
|
|
|
|
* @property {?Buffer} vector -
|
|
|
|
* [Inventory vector]{@link module:bitmessage/structs.inv_vect}
|
|
|
|
* related to the error
|
|
|
|
* @property {string} errorText - A human-readable error description
|
|
|
|
* @property {number} length - Real data length
|
|
|
|
* @memberof module:bitmessage/messages.error
|
|
|
|
*/
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Decode `error` message.
|
|
|
|
* @param {Buffer} buf - Message
|
2015-02-11 16:16:43 +01:00
|
|
|
* @return {DecodeResult}
|
|
|
|
* [Decoded `error` structure.]{@link module:bitmessage/messages.error.DecodeResult}
|
2015-01-26 18:03:43 +01:00
|
|
|
*/
|
|
|
|
decode: function(buf) {
|
|
|
|
var decoded = message.decode(buf);
|
|
|
|
assert(decoded.command === "error", "Bad command");
|
|
|
|
return error.decodePayload(decoded.payload);
|
|
|
|
},
|
|
|
|
|
2015-01-16 01:08:56 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Decode `error` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [decode]{@link module:bitmessage/messages.error.decode}.
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
decodePayload: function(buf) {
|
2015-01-16 01:08:56 +01:00
|
|
|
assert(buf.length >= 4, "Buffer is too small");
|
2015-02-24 17:18:49 +01:00
|
|
|
var decodedType = structs.var_int.decode(buf);
|
|
|
|
var decodedBanTime = structs.var_int.decode(decodedType.rest);
|
2015-02-11 15:53:49 +01:00
|
|
|
|
|
|
|
var decodedVectorLength = structs.var_int.decode(decodedBanTime.rest);
|
|
|
|
// NOTE(Kagami): Inventory vector should be only 32-byte in size but
|
|
|
|
// currently we don't ensure it.
|
|
|
|
var vectorLength = decodedVectorLength.value;
|
|
|
|
var rest = decodedVectorLength.rest;
|
|
|
|
assert(rest.length >= vectorLength, "Buffer is too small");
|
2015-02-11 16:14:22 +01:00
|
|
|
var vector = null;
|
|
|
|
if (vectorLength) {
|
|
|
|
vector = new Buffer(vectorLength);
|
|
|
|
rest.copy(vector);
|
|
|
|
rest = rest.slice(vectorLength);
|
|
|
|
}
|
2015-02-11 15:53:49 +01:00
|
|
|
|
|
|
|
var decodedErrorText = structs.var_str.decode(rest);
|
2015-01-16 01:08:56 +01:00
|
|
|
var length = (
|
2015-02-24 17:18:49 +01:00
|
|
|
decodedType.length +
|
2015-01-16 01:08:56 +01:00
|
|
|
decodedBanTime.length +
|
2015-02-11 15:53:49 +01:00
|
|
|
decodedVectorLength.length + vectorLength +
|
2015-01-16 01:08:56 +01:00
|
|
|
decodedErrorText.length
|
|
|
|
);
|
|
|
|
return {
|
2015-02-24 17:18:49 +01:00
|
|
|
type: decodedType.value,
|
2015-01-16 01:08:56 +01:00
|
|
|
banTime: decodedBanTime.value,
|
2015-02-11 15:53:49 +01:00
|
|
|
vector: vector,
|
2015-01-16 01:08:56 +01:00
|
|
|
errorText: decodedErrorText.str,
|
|
|
|
// Real data length.
|
|
|
|
length: length,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2015-01-26 18:03:43 +01:00
|
|
|
/**
|
|
|
|
* Encode `error` message.
|
|
|
|
* @param {Object} opts - Error options
|
2015-02-24 17:18:49 +01:00
|
|
|
* @param {number=} opts.type - Type of the error
|
2015-02-11 16:16:43 +01:00
|
|
|
* ([warning]{@link module:bitmessage/messages.error.WARNING} by
|
|
|
|
* default)
|
|
|
|
* @param {number=} opts.banTime - Inform the other node, that you
|
|
|
|
* will not accept further connections for this number of seconds (0
|
|
|
|
* by default)
|
|
|
|
* @param {Buffer=} opts.vector - A 32-byte
|
|
|
|
* [inventory vector]{@link module:bitmessage/structs.inv_vect}
|
|
|
|
* related to the error (empty by default)
|
|
|
|
* @param {string} opts.errorText - A human-readable error description
|
2015-01-26 18:03:43 +01:00
|
|
|
* @return {Buffer} Encoded message.
|
|
|
|
*/
|
|
|
|
encode: function(opts) {
|
|
|
|
var payload = error.encodePayload(opts);
|
|
|
|
return message.encode("error", payload);
|
|
|
|
},
|
|
|
|
|
2015-01-16 01:08:56 +01:00
|
|
|
/**
|
2015-01-16 19:36:57 +01:00
|
|
|
* Encode `error` message payload.
|
2015-02-11 16:16:43 +01:00
|
|
|
* The same as [encode]{@link module:bitmessage/messages.error.encode}.
|
2015-01-16 01:08:56 +01:00
|
|
|
*/
|
2015-01-26 18:03:43 +01:00
|
|
|
encodePayload: function(opts) {
|
2015-02-24 17:18:49 +01:00
|
|
|
var type = opts.type || error.WARNING;
|
2015-01-16 01:08:56 +01:00
|
|
|
var banTime = opts.banTime || 0;
|
2015-02-11 15:53:49 +01:00
|
|
|
// TODO(Kagami): Validate vector length.
|
|
|
|
var vector = opts.vector || new Buffer(0);
|
2015-01-16 01:08:56 +01:00
|
|
|
return Buffer.concat([
|
2015-02-24 17:18:49 +01:00
|
|
|
structs.var_int.encode(type),
|
2015-01-16 01:08:56 +01:00
|
|
|
structs.var_int.encode(banTime),
|
2015-02-11 15:53:49 +01:00
|
|
|
structs.var_int.encode(vector.length),
|
|
|
|
vector,
|
|
|
|
structs.var_str.encode(opts.errorText),
|
2015-01-16 01:08:56 +01:00
|
|
|
]);
|
|
|
|
},
|
|
|
|
};
|