TCP bootstrap

This commit is contained in:
Kagami Hiiragi 2015-02-05 22:55:36 +03:00
parent 84ab3ec3a0
commit 40d40c55aa
3 changed files with 76 additions and 6 deletions

View File

@ -8,6 +8,7 @@
var inherits = require("inherits");
var net = require("net");
var dns = require("dns");
var assert = require("../_util").assert;
var PPromise = require("../platform").Promise;
var BaseTransport = require("./base").BaseTransport;
@ -22,9 +23,8 @@ var sockIdCounter = 0;
function Transport(opts) {
Transport.super_.call(this);
opts = opts || {};
if (opts.seeds) {
this.seeds = opts.seeds;
}
this.seeds = opts.seeds || [];
this.dnsSeeds = opts.dnsSeeds || [];
if (opts.client) {
this._setupClient(opts.client);
}
@ -62,9 +62,47 @@ Transport.prototype._setupClient = function(client) {
});
};
function resolveDnsSeed(seed) {
var host = seed[0];
var port = seed[1];
var nodes = [];
// NOTE(Kagami):
// 1) Node's `getaddrinfo` (`dns.lookup`) returns only one address so
// we can't use it.
// 2) Node's `dig host any` (`dns.resolve`) doesn't return type of the
// record! So we resolve twice for A and AAAA.
// 3) We ignore any errors here, promise's result is always a list.
return new PPromise(function(resolve) {
dns.resolve4(host, function(err, nodes4) {
if (!err) {
nodes4.forEach(function(n) {
nodes.push([n, port]);
});
}
dns.resolve6(host, function(err, nodes6) {
if (!err) {
nodes6.forEach(function(n) {
nodes.push([n, port]);
});
}
resolve(nodes);
});
});
});
}
Transport.prototype.bootstrap = function() {
// TODO(Kagami): Think how to set up DNS/IP nodes. Do we need to
// hardcode them?
var promises = this.dnsSeeds.map(resolveDnsSeed);
var hardcodedNodes = this.seeds;
// FIXME(Kagami): Filter incorrect/private IP range nodes?
// See also: <https://github.com/Bitmessage/PyBitmessage/issues/768>.
return PPromise.all(promises).then(function(dnsNodes) {
// Add hardcoded nodes to the end of list because DNS nodes should
// be more up-to-date.
// Flatten array of array of arrays.
dnsNodes = Array.prototype.concat.apply([], dnsNodes);
return dnsNodes.concat(hardcodedNodes);
});
};
Transport.prototype.connect = function() {
@ -92,6 +130,7 @@ Transport.prototype.listen = function() {
var transport = new self.constructor({
client: sock,
seeds: this.seeds,
dnsSeeds: this.dnsSeeds,
});
self.emit("connection", transport);
});

View File

@ -1,3 +1,5 @@
var expect = require("chai").expect;
var bitmessage = require("../lib");
var structs = bitmessage.structs;
var message = structs.message;
@ -18,6 +20,35 @@ if (!process.browser) {
setTimeout(done, 1000);
});
it("should return nothing on bootstrap by default", function() {
return tcp.bootstrap().then(function(nodes) {
expect(nodes).to.be.empty;
});
});
it("should resolve DNS seeds on bootstrap", function() {
var tcp2 = new TcpTransport({
dnsSeeds: [["bootstrap8444.bitmessage.org", 8444]],
});
return tcp2.bootstrap().then(function(nodes) {
expect(nodes).to.be.not.empty;
expect(nodes[0][1]).to.be.equal(8444);
});
});
it("should return hardcoded seeds on bootstrap", function() {
var tcp3 = new TcpTransport({
seeds: [["1.1.1.1", 8080]],
dnsSeeds: [["bootstrap8444.bitmessage.org", 8444]],
});
return tcp3.bootstrap().then(function(nodes) {
expect(nodes).to.have.length.at.least(2);
expect(nodes[0][1]).to.be.equal(8444);
expect(nodes[nodes.length - 1][0]).to.equal("1.1.1.1");
expect(nodes[nodes.length - 1][1]).to.equal(8080);
});
});
it("should allow to interconnect two nodes", function(done) {
tcp.connect(22333, "127.0.0.1");
tcp.on("open", function() {

View File

@ -30,7 +30,7 @@ module.exports = function() {
} catch(e) {
console.log(e.stack);
}
if (err) console.log(err.stack);
if (err && err.stack) console.log(err.stack);
if (doExit) process.exit(1);
};
}