net: refactor host management.
This commit is contained in:
parent
dc58c99ba2
commit
761b6d6636
@ -150,7 +150,7 @@ WSProxy.prototype._handleConnect = function _handleConnect(ws, port, host, nonce
|
||||
}
|
||||
|
||||
socket.on('connect', function() {
|
||||
ws.emit('tcp connect');
|
||||
ws.emit('tcp connect', socket.remoteAddress, socket.remotePort);
|
||||
});
|
||||
|
||||
socket.on('data', function(data) {
|
||||
|
||||
@ -9,4 +9,5 @@ exports.Parser = require('./parser');
|
||||
exports.Peer = require('./peer');
|
||||
exports.Pool = require('./pool');
|
||||
exports.tcp = require('./tcp');
|
||||
exports.dns = require('./dns');
|
||||
exports.time = require('./time');
|
||||
|
||||
212
lib/net/peer.js
212
lib/net/peer.js
@ -29,6 +29,7 @@ var errors = require('../btc/errors');
|
||||
var List = require('../utils/list');
|
||||
var packetTypes = packets.types;
|
||||
var VerifyResult = errors.VerifyResult;
|
||||
var IP = require('../utils/ip');
|
||||
|
||||
/**
|
||||
* Represents a remote peer.
|
||||
@ -72,9 +73,9 @@ var VerifyResult = errors.VerifyResult;
|
||||
* @emits Peer#ack
|
||||
*/
|
||||
|
||||
function Peer(pool, addr, socket) {
|
||||
function Peer(pool) {
|
||||
if (!(this instanceof Peer))
|
||||
return new Peer(pool, addr, socket);
|
||||
return new Peer(pool);
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
@ -142,16 +143,13 @@ function Peer(pool, addr, socket) {
|
||||
this.queueBlock = new List();
|
||||
this.queueTX = new List();
|
||||
|
||||
this.uid = 0;
|
||||
this.id = Peer.uid++;
|
||||
|
||||
this.setMaxListeners(10000);
|
||||
|
||||
assert(addr, 'Host required.');
|
||||
|
||||
this.host = addr.host;
|
||||
this.port = addr.port;
|
||||
this.hostname = addr.hostname;
|
||||
this.host = '0.0.0.0';
|
||||
this.port = 0;
|
||||
this.hostname = '0.0.0.0:0';
|
||||
|
||||
if (this.options.bip151) {
|
||||
this.bip151 = new BIP151();
|
||||
@ -169,16 +167,6 @@ function Peer(pool, addr, socket) {
|
||||
this.parser = new Parser(this);
|
||||
this.framer = new Framer(this);
|
||||
|
||||
if (!socket) {
|
||||
this.socket = this.connect(this.port, this.host);
|
||||
this.outbound = true;
|
||||
} else {
|
||||
this.socket = socket;
|
||||
this.ts = util.now();
|
||||
this.connected = true;
|
||||
this.pending = false;
|
||||
}
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
@ -200,7 +188,59 @@ Peer.uid = 0;
|
||||
Peer.prototype._init = function init() {
|
||||
var self = this;
|
||||
|
||||
this.parser.on('packet', co(function* (packet) {
|
||||
try {
|
||||
yield self._onPacket(packet);
|
||||
} catch (e) {
|
||||
self.destroy();
|
||||
self.error(e);
|
||||
}
|
||||
}));
|
||||
|
||||
this.parser.on('error', function(err) {
|
||||
self.error(err);
|
||||
self.reject(null, 'malformed', 'error parsing message', 10);
|
||||
});
|
||||
|
||||
if (this.bip151) {
|
||||
this.bip151.on('error', function(err) {
|
||||
self.reject(null, 'malformed', 'error parsing message', 10);
|
||||
self.error(err);
|
||||
});
|
||||
this.bip151.on('rekey', function() {
|
||||
self.logger.debug('Rekeying with peer (%s).', self.hostname);
|
||||
self.send(self.bip151.toRekey());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set peer host, port, and hostname.
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
*/
|
||||
|
||||
Peer.prototype.setHost = function setHost(host, port) {
|
||||
assert(typeof host === 'string');
|
||||
assert(typeof port === 'number');
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.hostname = IP.hostname(host, port);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind to socket.
|
||||
* @param {net.Socket} socket
|
||||
*/
|
||||
|
||||
Peer.prototype.bind = function bind(socket) {
|
||||
var self = this;
|
||||
|
||||
assert(!this.socket);
|
||||
this.socket = socket;
|
||||
|
||||
this.socket.once('error', function(err) {
|
||||
self.destroy();
|
||||
self.error(err);
|
||||
|
||||
switch (err.code) {
|
||||
@ -219,6 +259,7 @@ Peer.prototype._init = function init() {
|
||||
});
|
||||
|
||||
this.socket.once('close', function() {
|
||||
self.destroy();
|
||||
self.error('socket hangup');
|
||||
});
|
||||
|
||||
@ -232,39 +273,32 @@ Peer.prototype._init = function init() {
|
||||
|
||||
self.parser.feed(chunk);
|
||||
});
|
||||
};
|
||||
|
||||
this.parser.on('packet', co(function* (packet) {
|
||||
try {
|
||||
yield self._onPacket(packet);
|
||||
} catch (e) {
|
||||
self.error(e);
|
||||
}
|
||||
}));
|
||||
/**
|
||||
* Accept an inbound socket.
|
||||
* @param {net.Socket} socket
|
||||
*/
|
||||
|
||||
this.parser.on('error', function(err) {
|
||||
self.error(err, true);
|
||||
self.reject(null, 'malformed', 'error parsing message', 10);
|
||||
});
|
||||
Peer.prototype.accept = function accept(socket) {
|
||||
var host = IP.normalize(socket.remoteAddress);
|
||||
var port = socket.remotePort;
|
||||
|
||||
if (this.bip151) {
|
||||
this.bip151.on('error', function(err) {
|
||||
self.reject(null, 'malformed', 'error parsing message', 10);
|
||||
self.error(err, true);
|
||||
});
|
||||
this.bip151.on('rekey', function() {
|
||||
self.logger.debug('Rekeying with peer (%s).', self.hostname);
|
||||
self.send(self.bip151.toRekey());
|
||||
});
|
||||
}
|
||||
assert(!this.socket);
|
||||
|
||||
this.open();
|
||||
this.bind(socket);
|
||||
this.setHost(host, port);
|
||||
this.ts = util.now();
|
||||
this.outbound = false;
|
||||
this.connected = true;
|
||||
this.pending = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the socket and begin connecting. This method
|
||||
* will use `options.createSocket` if provided.
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
* @param {String} host
|
||||
* @returns {net.Socket}
|
||||
*/
|
||||
|
||||
@ -280,45 +314,61 @@ Peer.prototype.connect = function connect(port, host) {
|
||||
else
|
||||
socket = tcp.connect(port, host, proxy);
|
||||
|
||||
this.bind(socket);
|
||||
this.setHost(host, port);
|
||||
this.outbound = true;
|
||||
|
||||
this.logger.debug('Connecting to %s.', this.hostname);
|
||||
|
||||
socket.once('connect', function() {
|
||||
self.logger.info('Connected to %s.', self.hostname);
|
||||
});
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Open and initialize the peer.
|
||||
* Open and perform initial handshake.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Peer.prototype.open = co(function* open() {
|
||||
try {
|
||||
yield this._connect();
|
||||
yield this._stallify();
|
||||
yield this._bip151();
|
||||
yield this._bip150();
|
||||
yield this._handshake();
|
||||
yield this._finalize();
|
||||
} catch (e) {
|
||||
this.error(e);
|
||||
return;
|
||||
}
|
||||
yield this._wait();
|
||||
yield this._stallify();
|
||||
yield this._bip151();
|
||||
yield this._bip150();
|
||||
yield this._handshake();
|
||||
yield this._finalize();
|
||||
|
||||
assert(!this.destroyed);
|
||||
if (this.destroyed)
|
||||
throw new Error('Peer was destroyed.');
|
||||
|
||||
clearTimeout(this.connectTimeout);
|
||||
this.connectTimeout = null;
|
||||
|
||||
// Finally we can let the pool know
|
||||
// that this peer is ready to go.
|
||||
this.emit('open');
|
||||
});
|
||||
|
||||
/**
|
||||
* Open and perform initial handshake (without rejection).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Peer.prototype.tryOpen = co(function* tryOpen() {
|
||||
try {
|
||||
yield this.open();
|
||||
} catch (e) {
|
||||
this.destroy();
|
||||
this.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Wait for connection.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._connect = function _connect() {
|
||||
Peer.prototype._wait = function _wait() {
|
||||
var self = this;
|
||||
|
||||
if (this.connected) {
|
||||
@ -332,9 +382,6 @@ Peer.prototype._connect = function _connect() {
|
||||
self.connected = true;
|
||||
self.emit('connect');
|
||||
|
||||
clearTimeout(self.connectTimeout);
|
||||
self.connectTimeout = null;
|
||||
|
||||
resolve();
|
||||
});
|
||||
|
||||
@ -380,7 +427,7 @@ Peer.prototype._bip151 = co(function* _bip151() {
|
||||
try {
|
||||
yield this.bip151.wait(3000);
|
||||
} catch (err) {
|
||||
this.error(err, true);
|
||||
this.error(err);
|
||||
}
|
||||
|
||||
assert(this.bip151.completed);
|
||||
@ -463,7 +510,7 @@ Peer.prototype._handshake = co(function* _handshake() {
|
||||
* @private
|
||||
*/
|
||||
|
||||
Peer.prototype._finalize = function _finalize() {
|
||||
Peer.prototype._finalize = co(function* _finalize() {
|
||||
var self = this;
|
||||
|
||||
// Setup the ping interval.
|
||||
@ -506,9 +553,7 @@ Peer.prototype._finalize = function _finalize() {
|
||||
|
||||
// Start syncing the chain.
|
||||
this.sync();
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Test whether the peer is the loader peer.
|
||||
@ -857,6 +902,7 @@ Peer.prototype.needsDrain = function needsDrain(size) {
|
||||
var self = this;
|
||||
|
||||
if (this.maybeStall()) {
|
||||
this.destroy();
|
||||
this.error('Peer stalled (drain).');
|
||||
return;
|
||||
}
|
||||
@ -869,6 +915,7 @@ Peer.prototype.needsDrain = function needsDrain(size) {
|
||||
'Peer is not reading: %s buffered (%s).',
|
||||
util.mb(this.drainSize),
|
||||
this.hostname);
|
||||
this.destroy();
|
||||
this.error('Peer stalled (drain).');
|
||||
return;
|
||||
}
|
||||
@ -887,6 +934,7 @@ Peer.prototype.maybeStall = function maybeStall() {
|
||||
return false;
|
||||
|
||||
this.drainSize = 0;
|
||||
this.destroy();
|
||||
this.error('Peer stalled.');
|
||||
|
||||
return true;
|
||||
@ -933,7 +981,7 @@ Peer.prototype.sendRaw = function sendRaw(cmd, body, checksum) {
|
||||
* @param {...String|Error} err
|
||||
*/
|
||||
|
||||
Peer.prototype.error = function error(err, keep) {
|
||||
Peer.prototype.error = function error(err) {
|
||||
var i, args, msg;
|
||||
|
||||
if (this.destroyed)
|
||||
@ -954,9 +1002,6 @@ Peer.prototype.error = function error(err, keep) {
|
||||
|
||||
err.message += ' (' + this.hostname + ')';
|
||||
|
||||
if (!keep)
|
||||
this.destroy();
|
||||
|
||||
this.emit('error', err);
|
||||
};
|
||||
|
||||
@ -1021,18 +1066,16 @@ Peer.prototype.response = function response(cmd, payload) {
|
||||
|
||||
/**
|
||||
* Send `getdata` to peer.
|
||||
* @param {InvItem[]} items
|
||||
* @param {LoadRequest[]} items
|
||||
*/
|
||||
|
||||
Peer.prototype.getData = function getData(items) {
|
||||
var data = new Array(items.length);
|
||||
var inv = [];
|
||||
var i, item;
|
||||
|
||||
for (i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
|
||||
if (item.toInv)
|
||||
item = item.toInv();
|
||||
item = item.toInv();
|
||||
|
||||
if (this.options.compact
|
||||
&& this.compactMode
|
||||
@ -1041,10 +1084,10 @@ Peer.prototype.getData = function getData(items) {
|
||||
item.type = constants.inv.CMPCT_BLOCK;
|
||||
}
|
||||
|
||||
data[i] = item;
|
||||
inv.push(item);
|
||||
}
|
||||
|
||||
this.send(new packets.GetDataPacket(data));
|
||||
this.send(new packets.GetDataPacket(inv));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1878,13 +1921,13 @@ Peer.prototype._handleAddr = co(function* _handleAddr(packet) {
|
||||
if (addr.ts <= 100000000 || addr.ts > now + 10 * 60)
|
||||
addr.ts = now - 5 * 24 * 60 * 60;
|
||||
|
||||
this.addrFilter.add(addr.host, 'ascii');
|
||||
this.addrFilter.add(addr.hostname, 'ascii');
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
'Received %d addrs (hosts=%d, peers=%d) (%s).',
|
||||
addrs.length,
|
||||
this.pool.hosts.items.length,
|
||||
this.pool.hosts.size(),
|
||||
this.pool.peers.size(),
|
||||
this.hostname);
|
||||
|
||||
@ -1962,13 +2005,8 @@ Peer.prototype._handleGetAddr = co(function* _handleGetAddr(packet) {
|
||||
|
||||
this.sentAddr = true;
|
||||
|
||||
for (i = 0; i < this.pool.hosts.items.length; i++) {
|
||||
addr = this.pool.hosts.items[i];
|
||||
|
||||
if (!addr.isIP())
|
||||
continue;
|
||||
|
||||
if (!this.addrFilter.added(addr.host, 'ascii'))
|
||||
for (addr = this.pool.hosts.head(); addr; addr = addr.next) {
|
||||
if (!this.addrFilter.added(addr.hostname, 'ascii'))
|
||||
continue;
|
||||
|
||||
items.push(addr);
|
||||
@ -2721,11 +2759,13 @@ function RequestEntry(peer, cmd, resolve, reject) {
|
||||
this.cmd = cmd;
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
this.id = peer.uid++;
|
||||
this.id = RequestEntry.uid++;
|
||||
this.onTimeout = this._onTimeout.bind(this);
|
||||
this.timeout = setTimeout(this.onTimeout, this.peer.requestTimeout);
|
||||
}
|
||||
|
||||
RequestEntry.uid = 0;
|
||||
|
||||
RequestEntry.prototype._onTimeout = function _onTimeout() {
|
||||
var queue = this.peer.requestMap[this.cmd];
|
||||
|
||||
|
||||
435
lib/net/pool.js
435
lib/net/pool.js
@ -30,6 +30,7 @@ var request = require('../http/request');
|
||||
var VerifyError = errors.VerifyError;
|
||||
var VerifyResult = errors.VerifyResult;
|
||||
var List = require('../utils/list');
|
||||
var dns = require('./dns');
|
||||
|
||||
/**
|
||||
* A pool of peers for handling all network activity.
|
||||
@ -288,6 +289,26 @@ Pool.prototype._init = function _init() {
|
||||
self.emit('full');
|
||||
self.logger.info('Chain is fully synced (height=%d).', self.chain.height);
|
||||
});
|
||||
|
||||
if (!this.options.selfish && !this.options.spv) {
|
||||
if (this.mempool) {
|
||||
this.mempool.on('tx', function(tx) {
|
||||
self.announceTX(tx);
|
||||
});
|
||||
}
|
||||
|
||||
// Normally we would also broadcast
|
||||
// competing chains, but we want to
|
||||
// avoid getting banned if an evil
|
||||
// miner sends us an invalid competing
|
||||
// chain that we can't connect and
|
||||
// verify yet.
|
||||
this.chain.on('block', function(block) {
|
||||
if (!self.chain.synced)
|
||||
return;
|
||||
self.announceBlock(block);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -297,18 +318,7 @@ Pool.prototype._init = function _init() {
|
||||
*/
|
||||
|
||||
Pool.prototype._open = co(function* _open() {
|
||||
var ip, key;
|
||||
|
||||
try {
|
||||
ip = yield this.getIP();
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
}
|
||||
|
||||
if (ip) {
|
||||
this.address.setHost(ip);
|
||||
this.logger.info('External IP found: %s.', ip);
|
||||
}
|
||||
var key;
|
||||
|
||||
if (this.mempool)
|
||||
yield this.mempool.open();
|
||||
@ -362,42 +372,53 @@ Pool.prototype._close = co(function* close() {
|
||||
|
||||
/**
|
||||
* Connect to the network.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Pool.prototype.connect = function connect() {
|
||||
var self = this;
|
||||
Pool.prototype.connect = co(function* connect() {
|
||||
var unlock = yield this.locker.lock();
|
||||
try {
|
||||
return yield this._connect();
|
||||
} finally {
|
||||
unlock();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Connect to the network (no lock).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
Pool.prototype._connect = co(function* connect() {
|
||||
var ip;
|
||||
|
||||
assert(this.loaded, 'Pool is not loaded.');
|
||||
|
||||
if (this.connected)
|
||||
return;
|
||||
|
||||
if (!this.options.selfish && !this.options.spv) {
|
||||
if (this.mempool) {
|
||||
this.mempool.on('tx', function(tx) {
|
||||
self.announceTX(tx);
|
||||
});
|
||||
}
|
||||
|
||||
// Normally we would also broadcast
|
||||
// competing chains, but we want to
|
||||
// avoid getting banned if an evil
|
||||
// miner sends us an invalid competing
|
||||
// chain that we can't connect and
|
||||
// verify yet.
|
||||
this.chain.on('block', function(block) {
|
||||
if (!self.chain.synced)
|
||||
return;
|
||||
self.announceBlock(block);
|
||||
});
|
||||
try {
|
||||
ip = yield this.getIP();
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
}
|
||||
|
||||
assert(this.hosts.seeds.length !== 0, 'No seeds available.');
|
||||
if (ip) {
|
||||
this.address.setHost(ip);
|
||||
this.logger.info('External IP found: %s.', ip);
|
||||
}
|
||||
|
||||
yield this.hosts.discover();
|
||||
|
||||
if (this.hosts.size() === 0)
|
||||
throw new Error('No hosts available. Do you have an internet connection?');
|
||||
|
||||
this.logger.info('Resolved %d hosts from DNS seeds.', this.hosts.size());
|
||||
|
||||
this.addLoader();
|
||||
|
||||
this.connected = true;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Start listening on a server socket.
|
||||
@ -483,12 +504,6 @@ Pool.prototype._handleLeech = function _handleLeech(socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hosts.isIgnored(addr)) {
|
||||
this.logger.debug('Ignoring leech (%s).', addr.hostname);
|
||||
socket.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Some kind of weird port collision
|
||||
// between inbound ports and outbound ports.
|
||||
if (this.peers.get(addr)) {
|
||||
@ -497,7 +512,7 @@ Pool.prototype._handleLeech = function _handleLeech(socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addLeech(addr, socket);
|
||||
this.addInbound(socket);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -604,7 +619,11 @@ Pool.prototype.addLoader = function addLoader() {
|
||||
return;
|
||||
}
|
||||
|
||||
addr = this.getLoaderHost();
|
||||
addr = this.hosts.getHost();
|
||||
|
||||
if (this.peers.get(addr))
|
||||
return;
|
||||
|
||||
peer = this.peers.get(addr);
|
||||
|
||||
if (peer) {
|
||||
@ -617,7 +636,7 @@ Pool.prototype.addLoader = function addLoader() {
|
||||
this.startInterval();
|
||||
}
|
||||
|
||||
peer = this.createPeer(addr);
|
||||
peer = this.createPeer(addr.port, addr.host);
|
||||
|
||||
this.logger.info('Added loader peer (%s).', peer.hostname);
|
||||
|
||||
@ -663,13 +682,13 @@ Pool.prototype.setLoader = function setLoader(peer) {
|
||||
* Start the blockchain sync.
|
||||
*/
|
||||
|
||||
Pool.prototype.startSync = function startSync() {
|
||||
Pool.prototype.startSync = co(function* startSync() {
|
||||
this.syncing = true;
|
||||
|
||||
this.startInterval();
|
||||
this.startTimeout();
|
||||
|
||||
this.connect();
|
||||
yield this.connect();
|
||||
|
||||
if (!this.peers.load) {
|
||||
this.addLoader();
|
||||
@ -677,7 +696,7 @@ Pool.prototype.startSync = function startSync() {
|
||||
}
|
||||
|
||||
this.sync();
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Send a sync to each peer.
|
||||
@ -714,7 +733,7 @@ Pool.prototype.forceSync = function forceSync() {
|
||||
* Stop the blockchain sync.
|
||||
*/
|
||||
|
||||
Pool.prototype.stopSync = function stopSync() {
|
||||
Pool.prototype.stopSync = co(function* stopSync() {
|
||||
var peer;
|
||||
|
||||
if (!this.syncing)
|
||||
@ -733,7 +752,7 @@ Pool.prototype.stopSync = function stopSync() {
|
||||
continue;
|
||||
peer.syncSent = false;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle `headers` packet from a given peer.
|
||||
@ -940,10 +959,7 @@ Pool.prototype.__handleInv = co(function* _handleInv(hashes, peer) {
|
||||
*/
|
||||
|
||||
Pool.prototype._handleBlock = co(function* _handleBlock(block, peer) {
|
||||
var requested;
|
||||
|
||||
// Fulfill the load request.
|
||||
requested = this.fulfill(block);
|
||||
var requested = this.fulfill(block);
|
||||
|
||||
// Someone is sending us blocks without
|
||||
// us requesting them.
|
||||
@ -1034,20 +1050,59 @@ Pool.prototype.sendMempool = function sendMempool() {
|
||||
Pool.prototype.sendAlert = function sendAlert(alert) {
|
||||
var peer;
|
||||
|
||||
for (peer = this.peers.head(); peer; peer = peer.next)
|
||||
for (peer = this.peers.head(); peer; peer = peer.next) {
|
||||
if (peer.pending)
|
||||
continue;
|
||||
peer.sendAlert(alert);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a base peer with no special purpose.
|
||||
* @private
|
||||
* @param {Object} options
|
||||
* @param {Number} port
|
||||
* @param {String} host
|
||||
* @returns {Peer}
|
||||
*/
|
||||
|
||||
Pool.prototype.createPeer = function createPeer(addr, socket) {
|
||||
Pool.prototype.createPeer = function createPeer(port, host) {
|
||||
var self = this;
|
||||
var peer = new Peer(this);
|
||||
|
||||
this.bindPeer(peer);
|
||||
|
||||
peer.connect(port, host);
|
||||
peer.tryOpen();
|
||||
|
||||
return peer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept an inbound socket.
|
||||
* @private
|
||||
* @param {net.Socket} socket
|
||||
* @returns {Peer}
|
||||
*/
|
||||
|
||||
Pool.prototype.acceptPeer = function acceptPeer(socket) {
|
||||
var self = this;
|
||||
var peer = new Peer(this);
|
||||
|
||||
this.bindPeer(peer);
|
||||
|
||||
peer.accept(socket);
|
||||
peer.tryOpen();
|
||||
|
||||
return peer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Bind to peer events.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Pool.prototype.bindPeer = function bindPeer(peer) {
|
||||
var self = this;
|
||||
var peer = new Peer(this, addr, socket);
|
||||
|
||||
peer.once('open', function() {
|
||||
if (!peer.outbound)
|
||||
@ -1263,8 +1318,6 @@ Pool.prototype.createPeer = function createPeer(addr, socket) {
|
||||
self.emit('error', e);
|
||||
}
|
||||
}));
|
||||
|
||||
return peer;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1349,10 +1402,8 @@ Pool.prototype.hasReject = function hasReject(hash) {
|
||||
*/
|
||||
|
||||
Pool.prototype._handleTX = co(function* _handleTX(tx, peer) {
|
||||
var i, requested, missing;
|
||||
|
||||
// Fulfill the load request.
|
||||
requested = this.fulfill(tx);
|
||||
var requested = this.fulfill(tx);
|
||||
var i, missing;
|
||||
|
||||
if (!requested) {
|
||||
peer.invFilter.add(tx.hash());
|
||||
@ -1379,14 +1430,16 @@ Pool.prototype._handleTX = co(function* _handleTX(tx, peer) {
|
||||
try {
|
||||
missing = yield this.mempool.addTX(tx);
|
||||
} catch (err) {
|
||||
if (err.type === 'VerifyError') {
|
||||
if (err.score !== -1)
|
||||
peer.reject(tx, err.code, err.reason, err.score);
|
||||
}
|
||||
if (err.type === 'VerifyError')
|
||||
peer.reject(tx, err.code, err.reason, err.score);
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (this.options.requestMissing && missing) {
|
||||
if (missing) {
|
||||
this.logger.debug(
|
||||
'Requesting %d missing transactions (%s).',
|
||||
missing.length, peer.hostname);
|
||||
|
||||
try {
|
||||
for (i = 0; i < missing.length; i++)
|
||||
this.getTX(peer, missing[i]);
|
||||
@ -1399,19 +1452,19 @@ Pool.prototype._handleTX = co(function* _handleTX(tx, peer) {
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a leech peer from an existing socket.
|
||||
* Create an inbound peer from an existing socket.
|
||||
* @private
|
||||
* @param {net.Socket} socket
|
||||
*/
|
||||
|
||||
Pool.prototype.addLeech = function addLeech(addr, socket) {
|
||||
Pool.prototype.addInbound = function addInbound(socket) {
|
||||
var self = this;
|
||||
var peer;
|
||||
|
||||
if (!this.loaded)
|
||||
return socket.destroy();
|
||||
|
||||
peer = this.createPeer(addr, socket);
|
||||
peer = this.acceptPeer(socket);
|
||||
|
||||
this.logger.info('Added leech peer (%s).', peer.hostname);
|
||||
|
||||
@ -1423,12 +1476,12 @@ Pool.prototype.addLeech = function addLeech(addr, socket) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a outbound non-loader peer. These primarily
|
||||
* Create an outbound non-loader peer. These primarily
|
||||
* exist for transaction relaying.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Pool.prototype.addPeer = function addPeer() {
|
||||
Pool.prototype.addOutbound = function addOutbound() {
|
||||
var self = this;
|
||||
var peer, addr;
|
||||
|
||||
@ -1444,10 +1497,10 @@ Pool.prototype.addPeer = function addPeer() {
|
||||
|
||||
addr = this.hosts.getHost();
|
||||
|
||||
if (!addr)
|
||||
if (this.peers.get(addr))
|
||||
return;
|
||||
|
||||
peer = this.createPeer(addr);
|
||||
peer = this.createPeer(addr.port, addr.host);
|
||||
|
||||
this.peers.add(peer);
|
||||
|
||||
@ -1469,7 +1522,7 @@ Pool.prototype.fillPeers = function fillPeers() {
|
||||
this.maxOutbound);
|
||||
|
||||
for (i = 0; i < this.maxOutbound - 1; i++)
|
||||
this.addPeer();
|
||||
this.addOutbound();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1829,18 +1882,6 @@ Pool.prototype.setFeeRate = function setFeeRate(rate) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate a new loader host.
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
Pool.prototype.getLoaderHost = function getLoaderHost() {
|
||||
if (!this.connected && this.options.preferredSeed)
|
||||
return this.hosts.seeds[0];
|
||||
|
||||
return this.hosts.getLoaderHost();
|
||||
};
|
||||
|
||||
/**
|
||||
* Increase peer's ban score.
|
||||
* @param {Peer} peer
|
||||
@ -1909,16 +1950,6 @@ Pool.prototype.ignore = function ignore(addr) {
|
||||
peer.destroy();
|
||||
};
|
||||
|
||||
/**
|
||||
* Test whether the host is ignored.
|
||||
* @param {NetworkAddress} addr
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
|
||||
Pool.prototype.isIgnored = function isIgnored(addr) {
|
||||
return this.hosts.isIgnored(addr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to retrieve external IP from icanhazip.com.
|
||||
* @returns {Promise}
|
||||
@ -1981,7 +2012,7 @@ Pool.prototype.getIP2 = co(function* getIP2() {
|
||||
*/
|
||||
|
||||
function PeerList(pool) {
|
||||
this.pool = pool;
|
||||
this.logger = pool.logger;
|
||||
this.map = {};
|
||||
this.list = new List();
|
||||
this.load = null;
|
||||
@ -2028,7 +2059,7 @@ PeerList.prototype.remove = function remove(peer) {
|
||||
delete this.map[peer.hostname];
|
||||
|
||||
if (peer.isLoader()) {
|
||||
this.pool.logger.info('Removed loader peer (%s).', peer.hostname);
|
||||
this.logger.info('Removed loader peer (%s).', peer.hostname);
|
||||
this.load = null;
|
||||
}
|
||||
|
||||
@ -2071,26 +2102,57 @@ PeerList.prototype.destroy = function destroy() {
|
||||
*/
|
||||
|
||||
function HostList(pool) {
|
||||
this.pool = pool;
|
||||
this.network = pool.network;
|
||||
this.logger = pool.logger;
|
||||
this.maxOutbound = pool.maxOutbound;
|
||||
this.list = new List();
|
||||
this.seeds = [];
|
||||
this.items = [];
|
||||
this.map = {};
|
||||
|
||||
// Ignored hosts
|
||||
this.ignored = {};
|
||||
|
||||
// Misbehaving hosts
|
||||
this.misbehaving = {};
|
||||
|
||||
this.setSeeds(this.pool.network.seeds);
|
||||
this.setSeeds(this.network.seeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get head element.
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
HostList.prototype.head = function head() {
|
||||
return this.list.head;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get tail element.
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
HostList.prototype.tail = function tail() {
|
||||
return this.list.tail;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get list size.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
HostList.prototype.size = function size() {
|
||||
return this.list.size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset host list.
|
||||
*/
|
||||
|
||||
HostList.prototype.reset = function reset() {
|
||||
this.map = {};
|
||||
this.list.reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear misbehaving and ignored.
|
||||
*/
|
||||
|
||||
HostList.prototype.clear = function clear() {
|
||||
this.ignored = {};
|
||||
this.misbehaving = {};
|
||||
};
|
||||
|
||||
@ -2099,71 +2161,11 @@ HostList.prototype.clear = function clear() {
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
HostList.prototype.getLoaderHost = function getLoaderHost() {
|
||||
var addr = this.getRandom(this.seeds);
|
||||
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
addr = this.getRandom(this.items);
|
||||
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
this.pool.logger.warning('All seeds banned or ignored. Clearing...');
|
||||
this.clear();
|
||||
|
||||
return this.getRandom(this.seeds);
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocate a new host which is not currently being used.
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
HostList.prototype.getHost = function getHost() {
|
||||
var addr = this.getRandom(this.seeds, true);
|
||||
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
return this.getRandom(this.items, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a random host from collection of hosts.
|
||||
* @param {NetworkAddress[]} hosts
|
||||
* @param {Boolean} unique
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
HostList.prototype.getRandom = function getRandom(hosts, unique) {
|
||||
var index = Math.random() * hosts.length | 0;
|
||||
var last = -1;
|
||||
var i, addr;
|
||||
|
||||
for (i = 0; i < hosts.length; i++) {
|
||||
addr = hosts[i];
|
||||
|
||||
if (this.isMisbehaving(addr))
|
||||
continue;
|
||||
|
||||
if (this.isIgnored(addr))
|
||||
continue;
|
||||
|
||||
if (unique && this.pool.peers.get(addr))
|
||||
continue;
|
||||
|
||||
if (i >= index)
|
||||
return addr;
|
||||
|
||||
last = i;
|
||||
}
|
||||
|
||||
if (last === -1)
|
||||
return;
|
||||
|
||||
return hosts[last];
|
||||
var addr = this.list.shift();
|
||||
assert(addr, 'No address available.');
|
||||
this.list.push(addr);
|
||||
return addr;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2173,14 +2175,13 @@ HostList.prototype.getRandom = function getRandom(hosts, unique) {
|
||||
*/
|
||||
|
||||
HostList.prototype.add = function add(addr) {
|
||||
if (this.items.length > 500)
|
||||
if (this.list.size > 500)
|
||||
return;
|
||||
|
||||
if (this.map[addr.hostname])
|
||||
return;
|
||||
|
||||
util.binaryInsert(this.items, addr, compare);
|
||||
|
||||
assert(this.list.unshift(addr));
|
||||
this.map[addr.hostname] = addr;
|
||||
|
||||
return addr;
|
||||
@ -2198,15 +2199,14 @@ HostList.prototype.remove = function remove(addr) {
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
util.binaryRemove(this.items, item, compare);
|
||||
|
||||
assert(this.list.remove(item));
|
||||
delete this.map[item.hostname];
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* Increase peer's ban score.
|
||||
* Mark a peer as misbehaving.
|
||||
* @param {NetworkAddress} addr
|
||||
*/
|
||||
|
||||
@ -2222,7 +2222,6 @@ HostList.prototype.ban = function ban(addr) {
|
||||
|
||||
HostList.prototype.unban = function unban(addr) {
|
||||
delete this.misbehaving[addr.host];
|
||||
delete this.ignored[addr.host];
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2251,18 +2250,12 @@ HostList.prototype.isMisbehaving = function isMisbehaving(addr) {
|
||||
*/
|
||||
|
||||
HostList.prototype.ignore = function ignore(addr) {
|
||||
if (!this.remove(addr))
|
||||
this.ignored[addr.host] = true;
|
||||
};
|
||||
var item = this.map[addr.hostname];
|
||||
|
||||
/**
|
||||
* Test whether the host/peer is ignored.
|
||||
* @param {NetworkAddress} addr
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
HostList.prototype.isIgnored = function isIgnored(addr) {
|
||||
return this.ignored[addr.host] === true;
|
||||
this.list.remove(item);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -2271,14 +2264,13 @@ HostList.prototype.isIgnored = function isIgnored(addr) {
|
||||
*/
|
||||
|
||||
HostList.prototype.setSeeds = function setSeeds(seeds) {
|
||||
var i, hostname, seed;
|
||||
var i, seed;
|
||||
|
||||
this.seeds.length = 0;
|
||||
|
||||
for (i = 0; i < seeds.length; i++) {
|
||||
hostname = seeds[i];
|
||||
seed = NetworkAddress.fromHostname(hostname, this.pool.network);
|
||||
this.seeds.push(seed);
|
||||
seed = seeds[i];
|
||||
this.addSeed(seed);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2288,10 +2280,58 @@ HostList.prototype.setSeeds = function setSeeds(seeds) {
|
||||
*/
|
||||
|
||||
HostList.prototype.addSeed = function addSeed(hostname) {
|
||||
var seed = NetworkAddress.fromHostname(hostname, this.pool.network);
|
||||
this.seeds.unshift(seed);
|
||||
var addr = IP.parseHost(hostname, this.network.port);
|
||||
this.seeds.push(addr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Populate from seed.
|
||||
* @param {String} seed
|
||||
*/
|
||||
|
||||
HostList.prototype.discover = co(function* discover() {
|
||||
var i, seed;
|
||||
|
||||
for (i = 0; i < this.seeds.length; i++) {
|
||||
seed = this.seeds[i];
|
||||
|
||||
yield this.populate(seed);
|
||||
|
||||
if (this.list.size >= this.maxOutbound)
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Populate from seed.
|
||||
* @param {String} seed
|
||||
*/
|
||||
|
||||
HostList.prototype.populate = co(function* populate(seed) {
|
||||
var i, addr, hosts, host;
|
||||
|
||||
if (seed.version !== -1) {
|
||||
addr = NetworkAddress.fromHost(seed.host, seed.port, this.network);
|
||||
this.add(addr);
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.info('Resolving hosts from seed: %s.', seed.host);
|
||||
|
||||
try {
|
||||
hosts = yield dns.resolve(seed.host);
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < hosts.length; i++) {
|
||||
host = hosts[i];
|
||||
addr = NetworkAddress.fromHost(host, seed.port, this.network);
|
||||
this.add(addr);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Represents an in-flight block or transaction.
|
||||
* @exports LoadRequest
|
||||
@ -2438,10 +2478,9 @@ function BroadcastItem(pool, msg) {
|
||||
item = msg.toInv();
|
||||
|
||||
this.pool = pool;
|
||||
this.msg = msg;
|
||||
|
||||
this.hash = item.hash;
|
||||
this.type = item.type;
|
||||
this.msg = msg;
|
||||
this.callback = [];
|
||||
|
||||
this.prev = null;
|
||||
|
||||
@ -6,6 +6,7 @@ var BufferWriter = require('../utils/writer');
|
||||
var assert = require('assert');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var IOClient = require('socket.io-client');
|
||||
var IP = require('../utils/ip');
|
||||
|
||||
function ProxySocket(uri) {
|
||||
if (!(this instanceof ProxySocket))
|
||||
@ -53,9 +54,11 @@ ProxySocket.prototype._init = function _init() {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
this.socket.on('tcp connect', function() {
|
||||
this.socket.on('tcp connect', function(addr, port) {
|
||||
if (self.closed)
|
||||
return;
|
||||
self.remoteAddress = addr;
|
||||
self.remotePort = port;
|
||||
self.emit('connect');
|
||||
});
|
||||
|
||||
|
||||
@ -23,7 +23,6 @@ var BufferReader = require('../utils/reader');
|
||||
* @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
|
||||
@ -34,25 +33,19 @@ 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';
|
||||
|
||||
this.prev = null;
|
||||
this.next = null;
|
||||
|
||||
if (options)
|
||||
this.fromOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Globally incremented unique id.
|
||||
* @private
|
||||
* @type {Number}
|
||||
*/
|
||||
|
||||
NetworkAddress.uid = 0;
|
||||
|
||||
/**
|
||||
* Inject properties from options object.
|
||||
* @private
|
||||
@ -60,15 +53,12 @@ NetworkAddress.uid = 0;
|
||||
*/
|
||||
|
||||
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);
|
||||
assert(IP.version(options.host) !== -1);
|
||||
|
||||
this.host = host;
|
||||
this.host = IP.normalize(options.host);
|
||||
this.port = options.port;
|
||||
|
||||
if (options.services) {
|
||||
@ -96,15 +86,6 @@ 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}
|
||||
@ -162,17 +143,41 @@ NetworkAddress.prototype.setPort = function setPort(port) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Inspect the network address.
|
||||
* @returns {Object}
|
||||
* Inject properties from host, port, and network.
|
||||
* @private
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
* @param {(Network|NetworkType)?} network
|
||||
*/
|
||||
|
||||
NetworkAddress.prototype.inspect = function inspect() {
|
||||
return '<NetworkAddress:'
|
||||
+ ' id=' + this.id
|
||||
+ ' hostname=' + IP.hostname(this.host, this.port)
|
||||
+ ' services=' + this.services.toString(2)
|
||||
+ ' date=' + util.date(this.ts)
|
||||
+ '>';
|
||||
NetworkAddress.prototype.fromHost = function fromHost(host, port, network) {
|
||||
network = Network.get(network);
|
||||
|
||||
assert(IP.version(host) !== -1);
|
||||
|
||||
this.host = host;
|
||||
this.port = port || network.port;
|
||||
this.services = constants.services.NETWORK
|
||||
| constants.services.BLOOM
|
||||
| constants.services.WITNESS;
|
||||
this.ts = network.now();
|
||||
|
||||
this.hostname = IP.hostname(this.host, this.port);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate a network address
|
||||
* from a host and port.
|
||||
* @param {String} host
|
||||
* @param {Number} port
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {NetworkAddress}
|
||||
*/
|
||||
|
||||
NetworkAddress.fromHost = function fromHost(host, port, network) {
|
||||
return new NetworkAddress().fromHost(host, port, network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -183,20 +188,10 @@ NetworkAddress.prototype.inspect = function inspect() {
|
||||
*/
|
||||
|
||||
NetworkAddress.prototype.fromHostname = function fromHostname(hostname, network) {
|
||||
var address = IP.parseHost(hostname);
|
||||
|
||||
var addr;
|
||||
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 = network.now();
|
||||
|
||||
this.hostname = IP.hostname(this.host, this.port);
|
||||
|
||||
return this;
|
||||
addr = IP.parseHost(hostname, network.port);
|
||||
return this.fromHost(addr.host, addr.port, network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -218,21 +213,11 @@ NetworkAddress.fromHostname = function fromHostname(hostname, network) {
|
||||
*/
|
||||
|
||||
NetworkAddress.prototype.fromSocket = function fromSocket(socket, network) {
|
||||
assert(typeof socket.remoteAddress === 'string');
|
||||
assert(typeof socket.remotePort === 'number');
|
||||
|
||||
network = Network.get(network);
|
||||
|
||||
this.host = IP.normalize(socket.remoteAddress);
|
||||
this.port = socket.remotePort;
|
||||
this.services = constants.services.NETWORK
|
||||
| constants.services.BLOOM
|
||||
| constants.services.WITNESS;
|
||||
this.ts = network.now();
|
||||
|
||||
this.hostname = IP.hostname(this.host, this.port);
|
||||
|
||||
return this;
|
||||
var host = socket.remoteAddress;
|
||||
var port = socket.remotePort;
|
||||
assert(typeof host === 'string');
|
||||
assert(typeof port === 'number');
|
||||
return this.fromHost(IP.normalize(host), port, network);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -336,6 +321,20 @@ NetworkAddress.prototype.toRaw = function toRaw(full) {
|
||||
return this.toWriter(new StaticWriter(size), full).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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=' + util.date(this.ts)
|
||||
+ '>';
|
||||
};
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
@ -15,16 +15,17 @@ var assert = require('assert');
|
||||
* @example
|
||||
* IP.parseHost('127.0.0.1:3000');
|
||||
* @param {String} addr
|
||||
* @param {Number?} fallback - Fallback port.
|
||||
* @returns {Object} Contains `host` and `port`.
|
||||
*/
|
||||
|
||||
exports.parseHost = function parseHost(addr) {
|
||||
var parts, host, port;
|
||||
exports.parseHost = function parseHost(addr, fallback) {
|
||||
var port = fallback || 0;
|
||||
var parts, host, version;
|
||||
|
||||
assert(addr);
|
||||
|
||||
if (typeof addr === 'object')
|
||||
return addr;
|
||||
assert(typeof addr === 'string');
|
||||
assert(addr.length > 0);
|
||||
assert(typeof port === 'number');
|
||||
|
||||
if (addr[0] === '[') {
|
||||
addr = addr.substring(1);
|
||||
@ -35,15 +36,20 @@ exports.parseHost = function parseHost(addr) {
|
||||
}
|
||||
|
||||
host = parts[0];
|
||||
port = +parts[1] || 0;
|
||||
assert(host.length > 0, 'Bad host.');
|
||||
|
||||
if (exports.version(host) !== -1)
|
||||
if (parts.length === 2) {
|
||||
port = parts[1];
|
||||
assert(/^\d+$/.test(port), 'Bad port.');
|
||||
port = parseInt(port, 10);
|
||||
}
|
||||
|
||||
version = exports.version(host);
|
||||
|
||||
if (version !== -1)
|
||||
host = exports.normalize(host);
|
||||
|
||||
return {
|
||||
host: host,
|
||||
port: port
|
||||
};
|
||||
return new Address(host, port, version);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -54,11 +60,22 @@ exports.parseHost = function parseHost(addr) {
|
||||
*/
|
||||
|
||||
exports.hostname = function hostname(host, port) {
|
||||
var version = exports.version(host);
|
||||
var version
|
||||
|
||||
assert(typeof host === 'string');
|
||||
assert(host.length > 0);
|
||||
assert(typeof port === 'number');
|
||||
|
||||
assert(!/[\[\]]/.test(host), 'Bad host.');
|
||||
|
||||
version = exports.version(host);
|
||||
|
||||
if (version !== -1)
|
||||
host = exports.normalize(host);
|
||||
|
||||
if (version === 6)
|
||||
host = '[' + host + ']';
|
||||
|
||||
return host + ':' + port;
|
||||
};
|
||||
|
||||
@ -69,8 +86,7 @@ exports.hostname = function hostname(host, port) {
|
||||
*/
|
||||
|
||||
exports.version = function version(ip) {
|
||||
if (typeof ip !== 'string')
|
||||
return -1;
|
||||
assert(typeof ip === 'string');
|
||||
|
||||
if (IP.isV4Format(ip))
|
||||
return 4;
|
||||
@ -113,14 +129,6 @@ exports.isMapped = function isMapped(ip) {
|
||||
exports.toBuffer = function toBuffer(ip) {
|
||||
var out;
|
||||
|
||||
if (Buffer.isBuffer(ip)) {
|
||||
assert(ip.length === 16);
|
||||
return ip;
|
||||
}
|
||||
|
||||
if (!ip)
|
||||
return toBuffer('0.0.0.0');
|
||||
|
||||
assert(typeof ip === 'string');
|
||||
assert(exports.version(ip) !== -1);
|
||||
|
||||
@ -148,14 +156,6 @@ exports.toBuffer = function toBuffer(ip) {
|
||||
*/
|
||||
|
||||
exports.toString = function toString(ip) {
|
||||
if (typeof ip === 'string') {
|
||||
assert(exports.version(ip) !== -1);
|
||||
return ip;
|
||||
}
|
||||
|
||||
if (!ip)
|
||||
return '0.0.0.0';
|
||||
|
||||
assert(Buffer.isBuffer(ip));
|
||||
assert(ip.length === 16);
|
||||
|
||||
@ -183,6 +183,17 @@ exports.normalize = function normalize(ip) {
|
||||
return exports.toString(exports.toBuffer(ip));
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
function Address(host, port, version) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose IP functions.
|
||||
*/
|
||||
|
||||
@ -78,6 +78,7 @@
|
||||
"./lib/db/backends": "./lib/db/backends-browser.js",
|
||||
"./lib/hd/wordlist": "./lib/hd/wordlist-browser.js",
|
||||
"./lib/net/tcp": "./lib/net/tcp-browser.js",
|
||||
"./lib/net/dns": "./lib/net/dns-browser.js",
|
||||
"./lib/blockchain/layout": "./lib/blockchain/layout-browser.js",
|
||||
"./lib/wallet/layout": "./lib/wallet/layout-browser.js",
|
||||
"fs": "./browser/empty.js",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user