diff --git a/lib/connect.js b/lib/connect.js index c34a0248..a9649b5d 100644 --- a/lib/connect.js +++ b/lib/connect.js @@ -29,6 +29,7 @@ const { module.exports = function connect (dht, publicKey, opts = {}) { const pool = opts.pool || null + if (pool && pool.has(publicKey)) return pool.get(publicKey) const keyPair = opts.keyPair || dht.defaultKeyPair @@ -284,16 +285,22 @@ async function holepunch (c, opts) { } async function findAndConnect (c, opts) { + let attempts = 0 + let closestNodes = (opts.relayAddresses && opts.relayAddresses.length) ? opts.relayAddresses : null + + if (c.dht._persistent) { // check if we know the route ourself... + const route = c.dht._router.get(c.target) + if (route && route.relay !== null) closestNodes = [{ host: route.relay.host, port: route.relay.port }] + } + // 2 is how many parallel connect attempts we want to do, we can make this configurable const sem = new Semaphore(2) - let attempts = 0 const signal = sem.signal.bind(sem) - - let closestNodes = (opts.relayAddresses && opts.relayAddresses.length) ? opts.relayAddresses : null + const tries = closestNodes !== null ? 2 : 1 try { - for (let i = 0; i < 2 && !isDone(c) && !c.connect; i++) { - c.query = c.dht.findPeer(c.target, { hash: false, session: c.session, closestNodes, onlyClosestNodes: !!closestNodes }) + for (let i = 0; i < tries && !isDone(c) && !c.connect; i++) { + c.query = c.dht.findPeer(c.target, { hash: false, session: c.session, closestNodes, onlyClosestNodes: closestNodes !== null }) for await (const data of c.query) { await sem.wait() diff --git a/test/announces.js b/test/announces.js index 1ee7cae1..077d01b8 100644 --- a/test/announces.js +++ b/test/announces.js @@ -111,15 +111,50 @@ test('server announces relay addrs', async function (t) { await b.findNode(b.id).finished() const server = await a.createServer().listen() - - const nodes = await toArray(b.findPeer(server.publicKey)) + const q = b.findPeer(server.publicKey) + const nodes = await toArray(q) for (const addr of server.relayAddresses) { let found = false + for (const node of nodes) { found = node.from.port === addr.port && node.from.host === addr.host if (found) break } + + if (!found) { + const { host, port } = b.remoteAddress() + found = port === addr.port && host === addr.host + } + + if (!found) { + const { host, port } = a.remoteAddress() + found = port === addr.port && host === addr.host + } + t.ok(found, 'found addr') } }) + +test('connect when we relay ourself', async function (t) { + const testnet = await swarm(t) + + const server = await testnet.nodes[1].createServer(function (sock) { + sock.resume() + sock.end() + }).listen() + + const addr = server.relayAddresses[server.relayAddresses.length - 1] + + for (const node of testnet.nodes) { + const { host, port } = node.remoteAddress() + if (addr.port === port && addr.host === host) { + const sock = node.connect(server.publicKey) + await sock.opened + t.pass('worked') + sock.end() + await new Promise(resolve => sock.once('close', resolve)) + break + } + } +})