Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions packages/integration-tests/test/dcutr.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ describe('dcutr', () => {
})
})

// TODO: how to test this?
// TODO: how to test this? We need to simulate a firewall of some sort
describe.skip('dctur connection upgrade', () => {
beforeEach(async () => {
libp2pA = await createLibp2p(createBaseOptions({
Expand Down Expand Up @@ -162,7 +162,7 @@ describe('dcutr', () => {
}
})

it('should perform connection upgrade', async () => {
it('should perform unilateral connection upgrade', async () => {
const relayedAddress = multiaddr(`/ip4/127.0.0.1/tcp/${RELAY_PORT}/p2p/${relay.peerId}/p2p-circuit/p2p/${libp2pB.peerId}`)
const connection = await libp2pA.dial(relayedAddress)

Expand All @@ -175,5 +175,19 @@ describe('dcutr', () => {
// should have closed the relayed connection
expect(libp2pA.getConnections(libp2pB.peerId)).to.have.lengthOf(1, 'had multiple connections to remote peer')
})

it('should perform holepunch using TCP Simultaneous Connect', async () => {
const relayedAddress = multiaddr(`/ip4/127.0.0.1/tcp/${RELAY_PORT}/p2p/${relay.peerId}/p2p-circuit/p2p/${libp2pB.peerId}`)
const connection = await libp2pA.dial(relayedAddress)

// connection should be limited
expect(connection).to.have.property('limits').that.is.ok()

// wait for DCUtR TCP Simultaneous Connect upgrade
// TODO: implement me

// should have closed the relayed connection
expect(libp2pA.getConnections(libp2pB.peerId)).to.have.lengthOf(1, 'had multiple connections to remote peer')
})
})
})
12 changes: 12 additions & 0 deletions packages/interface-internal/src/connection-manager/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ export interface OpenConnectionOptions extends AbortOptions, ProgressOptions<Ope
* @default false
*/
force?: boolean

/**
* By default a newly opened outgoing connection operates in initiator mode
* during negotiation of encryption/muxing protocols using multistream-select.
*
* In some cases such as when the dialer is trying to achieve TCP Simultaneous
* Connect using the DCUtR protocol, it may wish to act in responder mode, if
* so pass `false` here.
*
* @default true
*/
initiator?: boolean
}

export interface ConnectionManager {
Expand Down
1 change: 1 addition & 0 deletions packages/interface/src/transport/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export interface UpgraderOptions<ConnectionUpgradeEvents extends ProgressEvent =
skipProtection?: boolean
muxerFactory?: StreamMuxerFactory
limits?: ConnectionLimits
initiator?: boolean
}

export type InboundConnectionUpgradeEvents =
Expand Down
9 changes: 8 additions & 1 deletion packages/libp2p/src/upgrader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,14 @@ export class DefaultUpgrader implements Upgrader {
await this.shouldBlockConnection('denyOutboundConnection', remotePeerId, maConn)
}

return await this._performUpgrade(maConn, 'outbound', opts)
let direction: 'inbound' | 'outbound' = 'outbound'

// act as the multistream-select server if we are not to be the initiator
if (opts.initiator === false) {
direction = 'inbound'
}

return await this._performUpgrade(maConn, direction, opts)
} catch (err) {
this.metrics.errors?.increment({
outbound: true
Expand Down
7 changes: 5 additions & 2 deletions packages/protocol-dcutr/src/dcutr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,13 @@ export class DefaultDCUtRService implements Startable {
// https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol

this.log('B dialing', multiaddrs)
// Upon expiry of the timer, B dials the address to A.
// Upon expiry of the timer, B dials the address to A and acts as the
// multistream-select server
const conn = await this.connectionManager.openConnection(multiaddrs, {
signal: options.signal,
priority: DCUTR_DIAL_PRIORITY
priority: DCUTR_DIAL_PRIORITY,
force: true,
initiator: false
})

this.log('DCUtR to %p succeeded to address %a, closing relayed connection', relayedConnection.remotePeer, conn.remoteAddr)
Expand Down
Loading