fcoin/lib/primitives/netaddress.js
2016-10-02 23:24:11 -07:00

313 lines
6.8 KiB
JavaScript

/*!
* netaddress.js - network address object for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
module.exports = NetworkAddress;
var constants = require('../protocol/constants');
var Network = require('../protocol/network');
var time = require('../net/timedata');
var utils = require('../utils/utils');
var IP = require('../utils/ip');
var assert = require('assert');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
/**
* Represents a network address.
* @exports NetworkAddress
* @constructor
* @param {Object} options
* @param {Number?} options.ts - Timestamp.
* @param {Number?} options.services - Service bits.
* @param {String?} options.host - IP address (IPv6 or IPv4).
* @param {Number?} options.port - Port.
* @property {Number} id
* @property {Host} host
* @property {Number} port
* @property {Number} services
* @property {Number} ts
*/
function NetworkAddress(options) {
if (!(this instanceof NetworkAddress))
return new NetworkAddress(options);
this.id = NetworkAddress.uid++;
this.host = '0.0.0.0';
this.port = 0;
this.services = 0;
this.ts = 0;
this.hostname = '0.0.0.0:0';
if (options)
this.fromOptions(options);
}
/**
* Globally incremented unique id.
* @private
* @type {Number}
*/
NetworkAddress.uid = 0;
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
NetworkAddress.prototype.fromOptions = function fromOptions(options) {
var host = options.host;
assert(typeof options.host === 'string');
assert(typeof options.port === 'number');
if (IP.version(host) !== -1)
host = IP.normalize(host);
this.host = host;
this.port = options.port;
if (options.services) {
assert(typeof options.services === 'number');
this.services = options.services;
}
if (options.ts) {
assert(typeof options.ts === 'number');
this.ts = options.ts;
}
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate network address from options.
* @param {Object} options
* @returns {NetworkAddress}
*/
NetworkAddress.fromOptions = function fromOptions(options) {
return new NetworkAddress().fromOptions(options);
};
/**
* Test whether the `host` field is an ip address.
* @returns {Boolean}
*/
NetworkAddress.prototype.isIP = function isIP() {
return IP.version(this.host) !== -1;
};
/**
* Test whether the NETWORK service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasNetwork = function hasNetwork() {
return (this.services & constants.services.NETWORK) !== 0;
};
/**
* Test whether the BLOOM service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasBloom = function hasBloom() {
return (this.services & constants.services.BLOOM) !== 0;
};
/**
* Test whether the GETUTXO service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasUTXO = function hasUTXO() {
return (this.services & constants.services.GETUTXO) !== 0;
};
/**
* Test whether the WITNESS service bit is set.
* @returns {Boolean}
*/
NetworkAddress.prototype.hasWitness = function hasWitness() {
return (this.services & constants.services.WITNESS) !== 0;
};
/**
* Set host.
* @param {String} host
*/
NetworkAddress.prototype.setHost = function setHost(host) {
this.host = host;
this.hostname = IP.hostname(host, this.port);
};
/**
* Set port.
* @param {Number} port
*/
NetworkAddress.prototype.setPort = function setPort(port) {
this.port = port;
this.hostname = IP.hostname(this.host, port);
};
/**
* Inspect the network address.
* @returns {Object}
*/
NetworkAddress.prototype.inspect = function inspect() {
return '<NetworkAddress:'
+ ' id=' + this.id
+ ' hostname=' + IP.hostname(this.host, this.port)
+ ' services=' + this.services.toString(2)
+ ' date=' + utils.date(this.ts)
+ '>';
};
/**
* Inject properties from hostname and network.
* @private
* @param {String} hostname
* @param {(Network|NetworkType)?} network
*/
NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) {
var address = IP.parseHost(hostname);
network = Network.get(network);
this.host = address.host;
this.port = address.port || network.port;
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = time.now();
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate a network address
* from a hostname (i.e. 127.0.0.1:8333).
* @param {String} hostname
* @param {(Network|NetworkType)?} network
* @returns {NetworkAddress}
*/
NetworkAddress.fromHostname = function fromHostname(hostname, network) {
return new NetworkAddress().fromHostname(hostname, network);
};
/**
* Inject properties from socket.
* @private
* @param {net.Socket} socket
*/
NetworkAddress.prototype.fromSocket = function fromSocket(socket) {
assert(typeof socket.remoteAddress === 'string');
assert(typeof socket.remotePort === 'number');
this.host = IP.normalize(socket.remoteAddress);
this.port = socket.remotePort;
this.services = constants.services.NETWORK
| constants.services.BLOOM
| constants.services.WITNESS;
this.ts = time.now();
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Instantiate a network address
* from a socket.
* @param {net.Socket} socket
* @returns {NetworkAddress}
*/
NetworkAddress.fromSocket = function fromSocket(hostname) {
return new NetworkAddress().fromSocket(hostname);
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} data
* @param {Boolean?} full - Include timestamp.
*/
NetworkAddress.prototype.fromRaw = function fromRaw(data, full) {
var p = BufferReader(data);
var now = time.now();
// only version >= 31402
this.ts = full ? p.readU32() : 0;
this.services = p.readU53();
this.host = IP.toString(p.readBytes(16));
this.port = p.readU16BE();
if (this.ts <= 100000000 || this.ts > now + 10 * 60)
this.ts = now - 5 * 24 * 60 * 60;
this.hostname = IP.hostname(this.host, this.port);
return this;
};
/**
* Insantiate a network address from serialized data.
* @param {Buffer} data
* @param {Boolean?} full - Include timestamp.
* @returns {NetworkAddress}
*/
NetworkAddress.fromRaw = function fromRaw(data, full) {
return new NetworkAddress().fromRaw(data, full);
};
/**
* Serialize network address.
* @param {Boolean} full - Include timestamp.
* @returns {Buffer}
*/
NetworkAddress.prototype.toRaw = function toRaw(full, writer) {
var p = BufferWriter(writer);
if (full)
p.writeU32(this.ts);
p.writeU64(this.services);
p.writeBytes(IP.toBuffer(this.host));
p.writeU16BE(this.port);
if (!writer)
p = p.render();
return p;
};
/*
* Expose
*/
module.exports = NetworkAddress;