parent
b7726bf68f
commit
a5666789b0
|
@ -20,8 +20,6 @@ import ../../../switch,
|
|||
../../../peerid
|
||||
import core
|
||||
|
||||
export core
|
||||
|
||||
logScope:
|
||||
topics = "libp2p autonat"
|
||||
|
||||
|
|
|
@ -17,9 +17,12 @@ import chronos, metrics
|
|||
import ../../../switch
|
||||
import ../../../wire
|
||||
import client
|
||||
from core import NetworkReachability, AutonatUnreachableError
|
||||
import ../../../utils/heartbeat
|
||||
import ../../../crypto/crypto
|
||||
|
||||
export options, core.NetworkReachability
|
||||
|
||||
logScope:
|
||||
topics = "libp2p autonatservice"
|
||||
|
||||
|
@ -30,7 +33,7 @@ type
|
|||
newConnectedPeerHandler: PeerEventHandler
|
||||
addressMapper: AddressMapper
|
||||
scheduleHandle: Future[void]
|
||||
networkReachability: NetworkReachability
|
||||
networkReachability*: NetworkReachability
|
||||
confidence: Option[float]
|
||||
answers: Deque[NetworkReachability]
|
||||
autonatClient: AutonatClient
|
||||
|
@ -71,9 +74,6 @@ proc new*(
|
|||
dialTimeout: dialTimeout,
|
||||
enableAddressMapper: enableAddressMapper)
|
||||
|
||||
proc networkReachability*(self: AutonatService): NetworkReachability {.inline.} =
|
||||
return self.networkReachability
|
||||
|
||||
proc callHandler(self: AutonatService) {.async.} =
|
||||
if not isNil(self.statusAndConfidenceHandler):
|
||||
await self.statusAndConfidenceHandler(self.networkReachability, self.confidence)
|
||||
|
|
|
@ -23,6 +23,8 @@ import ../../protocol,
|
|||
../../../switch,
|
||||
../../../utils/future
|
||||
|
||||
export DcutrError
|
||||
|
||||
type
|
||||
DcutrClient* = ref object
|
||||
connectTimeout: Duration
|
||||
|
|
|
@ -23,6 +23,7 @@ import ../../protocol,
|
|||
../../../switch,
|
||||
../../../utils/future
|
||||
|
||||
export DcutrError
|
||||
export chronicles
|
||||
|
||||
type Dcutr* = ref object of LPProtocol
|
||||
|
|
|
@ -101,7 +101,7 @@ proc createReserveResponse(
|
|||
status: some(Ok))
|
||||
return ok(msg)
|
||||
|
||||
proc isRelayed(conn: Connection): bool =
|
||||
proc isRelayed*(conn: Connection): bool =
|
||||
var wrappedConn = conn
|
||||
while not isNil(wrappedConn):
|
||||
if wrappedConn of RelayConnection:
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# Nim-LibP2P
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import std/[tables, sequtils]
|
||||
|
||||
import chronos, chronicles
|
||||
|
||||
import ../switch, ../wire
|
||||
import ../protocols/rendezvous
|
||||
import ../services/autorelayservice
|
||||
import ../discovery/[rendezvousinterface, discoverymngr]
|
||||
import ../protocols/connectivity/relay/relay
|
||||
import ../protocols/connectivity/autonat/service
|
||||
import ../protocols/connectivity/dcutr/[client, server]
|
||||
|
||||
|
||||
logScope:
|
||||
topics = "libp2p hpservice"
|
||||
|
||||
type
|
||||
HPService* = ref object of Service
|
||||
newConnectedPeerHandler: PeerEventHandler
|
||||
onNewStatusHandler: StatusAndConfidenceHandler
|
||||
autoRelayService: AutoRelayService
|
||||
autonatService: AutonatService
|
||||
isPublicIPAddrProc: IsPublicIPAddrProc
|
||||
|
||||
IsPublicIPAddrProc* = proc(ta: TransportAddress): bool {.gcsafe, raises: [Defect].}
|
||||
|
||||
proc new*(T: typedesc[HPService], autonatService: AutonatService, autoRelayService: AutoRelayService,
|
||||
isPublicIPAddrProc: IsPublicIPAddrProc = isGlobal): T =
|
||||
return T(autonatService: autonatService, autoRelayService: autoRelayService, isPublicIPAddrProc: isPublicIPAddrProc)
|
||||
|
||||
proc tryStartingDirectConn(self: HPService, switch: Switch, peerId: PeerId): Future[bool] {.async.} =
|
||||
await sleepAsync(500.milliseconds) # wait for AddressBook to be populated
|
||||
for address in switch.peerStore[AddressBook][peerId]:
|
||||
try:
|
||||
let ta = initTAddress(address)
|
||||
if ta.isOk() and self.isPublicIPAddrProc(ta.get()):
|
||||
await switch.connect(peerId, @[address], true, false)
|
||||
debug "Direct connection created."
|
||||
return true
|
||||
except CatchableError as err:
|
||||
debug "Failed to create direct connection.", err = err.msg
|
||||
continue
|
||||
return false
|
||||
|
||||
method setup*(self: HPService, switch: Switch): Future[bool] {.async.} =
|
||||
var hasBeenSetup = await procCall Service(self).setup(switch)
|
||||
hasBeenSetup = hasBeenSetup and await self.autonatService.setup(switch)
|
||||
|
||||
if hasBeenSetup:
|
||||
let dcutrProto = Dcutr.new(switch)
|
||||
switch.mount(dcutrProto)
|
||||
|
||||
self.newConnectedPeerHandler = proc (peerId: PeerId, event: PeerEvent): Future[void] {.async.} =
|
||||
try:
|
||||
let conn = switch.connManager.selectMuxer(peerId).connection
|
||||
if isRelayed(conn) and conn.transportDir == Direction.In:
|
||||
if await self.tryStartingDirectConn(switch, peerId):
|
||||
await conn.close()
|
||||
return
|
||||
let dcutrClient = DcutrClient.new()
|
||||
var natAddrs = switch.peerStore.getMostObservedProtosAndPorts()
|
||||
if natAddrs.len == 0:
|
||||
natAddrs = switch.peerInfo.listenAddrs.mapIt(switch.peerStore.guessDialableAddr(it))
|
||||
await dcutrClient.startSync(switch, peerId, natAddrs)
|
||||
await sleepAsync(2000.milliseconds) # grace period before closing relayed connection
|
||||
await conn.close()
|
||||
except CatchableError as err:
|
||||
debug "Hole punching failed during dcutr", err = err.msg
|
||||
|
||||
switch.connManager.addPeerEventHandler(self.newConnectedPeerHandler, PeerEventKind.Joined)
|
||||
|
||||
self.onNewStatusHandler = proc (networkReachability: NetworkReachability, confidence: Option[float]) {.gcsafe, async.} =
|
||||
if networkReachability == NetworkReachability.NotReachable:
|
||||
discard await self.autoRelayService.setup(switch)
|
||||
elif networkReachability == NetworkReachability.Reachable:
|
||||
discard await self.autoRelayService.stop(switch)
|
||||
|
||||
# We do it here instead of in the AutonatService because this is useful only when hole punching.
|
||||
for t in switch.transports:
|
||||
t.networkReachability = networkReachability
|
||||
|
||||
self.autonatService.statusAndConfidenceHandler(self.onNewStatusHandler)
|
||||
return hasBeenSetup
|
||||
|
||||
method run*(self: HPService, switch: Switch) {.async, public.} =
|
||||
await self.autonatService.run(switch)
|
||||
|
||||
method stop*(self: HPService, switch: Switch): Future[bool] {.async, public.} =
|
||||
discard await self.autonatService.stop(switch)
|
||||
if not isNil(self.newConnectedPeerHandler):
|
||||
switch.connManager.removePeerEventHandler(self.newConnectedPeerHandler, PeerEventKind.Joined)
|
|
@ -71,7 +71,7 @@ proc initTAddress*(ma: MultiAddress): MaResult[TransportAddress] =
|
|||
res.port = Port(fromBytesBE(uint16, pbuf))
|
||||
ok(res)
|
||||
else:
|
||||
err("MultiAddress must be wire address (tcp, udp or unix)")
|
||||
err("MultiAddress must be wire address (tcp, udp or unix): " & $ma)
|
||||
|
||||
proc connect*(
|
||||
ma: MultiAddress,
|
||||
|
|
|
@ -19,6 +19,7 @@ import ../../libp2p/[protocols/connectivity/autonat/client,
|
|||
peerid,
|
||||
multiaddress,
|
||||
switch]
|
||||
from ../../libp2p/protocols/connectivity/autonat/core import NetworkReachability, AutonatUnreachableError, AutonatError
|
||||
|
||||
type
|
||||
AutonatClientStub* = ref object of AutonatClient
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# Nim-LibP2P
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import chronos
|
||||
import ../../libp2p/[peerid, multiaddress, switch]
|
||||
|
||||
type
|
||||
SwitchStub* = ref object of Switch
|
||||
switch*: Switch
|
||||
connectStub*: proc(): Future[void] {.async.}
|
||||
|
||||
method connect*(
|
||||
self: SwitchStub,
|
||||
peerId: PeerId,
|
||||
addrs: seq[MultiAddress],
|
||||
forceDial = false,
|
||||
reuseConnection = true,
|
||||
upgradeDir = Direction.Out) {.async.} =
|
||||
if (self.connectStub != nil):
|
||||
await self.connectStub()
|
||||
else:
|
||||
await self.switch.connect(peerId, addrs, forceDial, reuseConnection, upgradeDir)
|
||||
|
||||
proc new*(T: typedesc[SwitchStub], switch: Switch, connectStub: proc (): Future[void] {.async.} = nil): T =
|
||||
return SwitchStub(
|
||||
switch: switch,
|
||||
peerInfo: switch.peerInfo,
|
||||
ms: switch.ms,
|
||||
transports: switch.transports,
|
||||
connManager: switch.connManager,
|
||||
peerStore: switch.peerStore,
|
||||
dialer: switch.dialer,
|
||||
nameResolver: switch.nameResolver,
|
||||
services: switch.services,
|
||||
connectStub: connectStub)
|
|
@ -1,3 +1,12 @@
|
|||
# Nim-LibP2P
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
|
|
|
@ -51,7 +51,7 @@ suite "Autonat Service":
|
|||
let switch3 = createSwitch()
|
||||
let switch4 = createSwitch()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
await switch1.start()
|
||||
await switch2.start()
|
||||
|
@ -64,7 +64,7 @@ suite "Autonat Service":
|
|||
|
||||
await autonatClientStub.finished
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
||||
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
||||
|
||||
await allFuturesThrowing(
|
||||
|
@ -86,7 +86,7 @@ suite "Autonat Service":
|
|||
if not awaiter.finished:
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -101,7 +101,7 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
||||
|
||||
check switch1.peerInfo.addrs == switch1.peerInfo.listenAddrs.mapIt(switch1.peerStore.guessDialableAddr(it))
|
||||
|
@ -131,7 +131,7 @@ suite "Autonat Service":
|
|||
autonatClientStub.answer = Reachable
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -146,12 +146,12 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
||||
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
||||
|
||||
await autonatClientStub.finished
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
||||
|
||||
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
||||
|
@ -172,7 +172,7 @@ suite "Autonat Service":
|
|||
if not awaiter.finished:
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -187,7 +187,7 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||
|
||||
await allFuturesThrowing(
|
||||
|
@ -213,7 +213,7 @@ suite "Autonat Service":
|
|||
autonatClientStub.answer = Unknown
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -228,12 +228,12 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
||||
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
||||
|
||||
await autonatClientStub.finished
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
||||
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
||||
|
||||
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
||||
|
@ -264,7 +264,7 @@ suite "Autonat Service":
|
|||
if not awaiter.finished:
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -275,7 +275,7 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||
|
||||
await allFuturesThrowing(
|
||||
|
@ -304,8 +304,8 @@ suite "Autonat Service":
|
|||
if not awaiter2.finished:
|
||||
awaiter2.complete()
|
||||
|
||||
check autonatService1.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService2.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService1.networkReachability == NetworkReachability.Unknown
|
||||
check autonatService2.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
||||
autonatService2.statusAndConfidenceHandler(statusAndConfidenceHandler2)
|
||||
|
@ -321,8 +321,8 @@ suite "Autonat Service":
|
|||
await awaiter1
|
||||
await awaiter2
|
||||
|
||||
check autonatService1.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService2.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService1.networkReachability == NetworkReachability.Reachable
|
||||
check autonatService2.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||
|
||||
await allFuturesThrowing(
|
||||
|
@ -342,7 +342,7 @@ suite "Autonat Service":
|
|||
if not awaiter1.finished:
|
||||
awaiter1.complete()
|
||||
|
||||
check autonatService1.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService1.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
||||
|
||||
|
@ -360,7 +360,7 @@ suite "Autonat Service":
|
|||
|
||||
await awaiter1
|
||||
|
||||
check autonatService1.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService1.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||
|
||||
# Make sure remote peer can't create a connection to us
|
||||
|
@ -385,7 +385,7 @@ suite "Autonat Service":
|
|||
if not awaiter.finished:
|
||||
awaiter.complete()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
@ -407,7 +407,7 @@ suite "Autonat Service":
|
|||
await autonatService.run(switch1)
|
||||
await awaiter
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
||||
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||
|
||||
await allFuturesThrowing(
|
||||
|
@ -422,7 +422,7 @@ suite "Autonat Service":
|
|||
proc statusAndConfidenceHandler(networkReachability: NetworkReachability, confidence: Option[float]) {.gcsafe, async.} =
|
||||
fail()
|
||||
|
||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
||||
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||
|
||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||
|
||||
|
|
|
@ -16,36 +16,7 @@ from ../libp2p/protocols/connectivity/autonat/core import NetworkReachability
|
|||
import ../libp2p/builders
|
||||
import ../libp2p/utils/future
|
||||
import ./helpers
|
||||
|
||||
type
|
||||
SwitchStub* = ref object of Switch
|
||||
switch: Switch
|
||||
connectStub*: proc(): Future[void] {.async.}
|
||||
|
||||
proc new*(T: typedesc[SwitchStub], switch: Switch, connectStub: proc (): Future[void] {.async.} = nil): T =
|
||||
return SwitchStub(
|
||||
switch: switch,
|
||||
peerInfo: switch.peerInfo,
|
||||
ms: switch.ms,
|
||||
transports: switch.transports,
|
||||
connManager: switch.connManager,
|
||||
peerStore: switch.peerStore,
|
||||
dialer: switch.dialer,
|
||||
nameResolver: switch.nameResolver,
|
||||
services: switch.services,
|
||||
connectStub: connectStub)
|
||||
|
||||
method connect*(
|
||||
self: SwitchStub,
|
||||
peerId: PeerId,
|
||||
addrs: seq[MultiAddress],
|
||||
forceDial = false,
|
||||
reuseConnection = true,
|
||||
upgradeDir = Direction.Out) {.async.} =
|
||||
if (self.connectStub != nil):
|
||||
await self.connectStub()
|
||||
else:
|
||||
await self.switch.connect(peerId, addrs, forceDial, reuseConnection, upgradeDir)
|
||||
import ./stubs/switchstub
|
||||
|
||||
suite "Dcutr":
|
||||
teardown:
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
# Nim-LibP2P
|
||||
# Copyright (c) 2022 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
{.used.}
|
||||
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import chronos
|
||||
|
||||
import unittest2
|
||||
import ./helpers
|
||||
import ./stubs/switchstub
|
||||
import ../libp2p/[builders,
|
||||
switch,
|
||||
services/hpservice,
|
||||
services/autorelayservice]
|
||||
import ../libp2p/protocols/connectivity/relay/[relay, client]
|
||||
import ../libp2p/protocols/connectivity/autonat/[service]
|
||||
import ../libp2p/wire
|
||||
import stubs/autonatclientstub
|
||||
|
||||
proc isPublicAddrIPAddrMock(ta: TransportAddress): bool =
|
||||
return true
|
||||
|
||||
proc createSwitch(r: Relay = nil, hpService: Service = nil): Switch {.raises: [LPError, Defect].} =
|
||||
var builder = SwitchBuilder.new()
|
||||
.withRng(newRng())
|
||||
.withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ])
|
||||
.withTcpTransport()
|
||||
.withMplex()
|
||||
.withAutonat()
|
||||
.withNoise()
|
||||
|
||||
if hpService != nil:
|
||||
builder = builder.withServices(@[hpService])
|
||||
|
||||
if r != nil:
|
||||
builder = builder.withCircuitRelay(r)
|
||||
|
||||
return builder.build()
|
||||
|
||||
proc buildRelayMA(switchRelay: Switch, switchClient: Switch): MultiAddress =
|
||||
MultiAddress.init($switchRelay.peerInfo.addrs[0] & "/p2p/" &
|
||||
$switchRelay.peerInfo.peerId & "/p2p-circuit/p2p/" &
|
||||
$switchClient.peerInfo.peerId).get()
|
||||
|
||||
suite "Hole Punching":
|
||||
teardown:
|
||||
checkTrackers()
|
||||
|
||||
asyncTest "Direct connection must work when peer address is public":
|
||||
let autonatClientStub = AutonatClientStub.new(expectedDials = 1)
|
||||
autonatClientStub.answer = NotReachable
|
||||
let autonatService = AutonatService.new(autonatClientStub, newRng(), maxQueueSize = 1)
|
||||
|
||||
let relayClient = RelayClient.new()
|
||||
let privatePeerRelayAddr = newFuture[seq[MultiAddress]]()
|
||||
|
||||
let publicPeerSwitch = createSwitch(RelayClient.new())
|
||||
proc checkMA(address: seq[MultiAddress]) =
|
||||
if not privatePeerRelayAddr.completed():
|
||||
privatePeerRelayAddr.complete(address)
|
||||
|
||||
let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng())
|
||||
|
||||
let hpservice = HPService.new(autonatService, autoRelayService, isPublicAddrIPAddrMock)
|
||||
|
||||
let privatePeerSwitch = createSwitch(relayClient, hpservice)
|
||||
let switchRelay = createSwitch(Relay.new())
|
||||
|
||||
await allFutures(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start())
|
||||
|
||||
await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs)
|
||||
|
||||
await publicPeerSwitch.connect(privatePeerSwitch.peerInfo.peerId, (await privatePeerRelayAddr))
|
||||
|
||||
checkExpiring:
|
||||
privatePeerSwitch.connManager.connCount(publicPeerSwitch.peerInfo.peerId) == 1 and
|
||||
not isRelayed(privatePeerSwitch.connManager.selectMuxer(publicPeerSwitch.peerInfo.peerId).connection)
|
||||
|
||||
await allFuturesThrowing(
|
||||
privatePeerSwitch.stop(), publicPeerSwitch.stop(), switchRelay.stop())
|
||||
|
||||
proc holePunchingTest(connectStub: proc (): Future[void] {.async.},
|
||||
isPublicIPAddrProc: IsPublicIPAddrProc,
|
||||
answer: Answer) {.async.} =
|
||||
# There's no check in this test cause it can't test hole punching locally. It exists just to be sure the rest of
|
||||
# the code works properly.
|
||||
|
||||
let autonatClientStub1 = AutonatClientStub.new(expectedDials = 1)
|
||||
autonatClientStub1.answer = NotReachable
|
||||
let autonatService1 = AutonatService.new(autonatClientStub1, newRng(), maxQueueSize = 1)
|
||||
|
||||
let autonatClientStub2 = AutonatClientStub.new(expectedDials = 1)
|
||||
autonatClientStub2.answer = answer
|
||||
let autonatService2 = AutonatService.new(autonatClientStub2, newRng(), maxQueueSize = 1)
|
||||
|
||||
let relayClient1 = RelayClient.new()
|
||||
let relayClient2 = RelayClient.new()
|
||||
let privatePeerRelayAddr1 = newFuture[seq[MultiAddress]]()
|
||||
|
||||
proc checkMA(address: seq[MultiAddress]) =
|
||||
if not privatePeerRelayAddr1.completed():
|
||||
privatePeerRelayAddr1.complete(address)
|
||||
|
||||
let autoRelayService1 = AutoRelayService.new(1, relayClient1, checkMA, newRng())
|
||||
let autoRelayService2 = AutoRelayService.new(1, relayClient2, nil, newRng())
|
||||
|
||||
let hpservice1 = HPService.new(autonatService1, autoRelayService1, isPublicIPAddrProc)
|
||||
let hpservice2 = HPService.new(autonatService2, autoRelayService2)
|
||||
|
||||
let privatePeerSwitch1 = SwitchStub.new(createSwitch(relayClient1, hpservice1))
|
||||
let privatePeerSwitch2 = createSwitch(relayClient2, hpservice2)
|
||||
let switchRelay = createSwitch(Relay.new())
|
||||
let switchAux = createSwitch()
|
||||
let switchAux2 = createSwitch()
|
||||
let switchAux3 = createSwitch()
|
||||
let switchAux4 = createSwitch()
|
||||
|
||||
var awaiter = newFuture[void]()
|
||||
|
||||
await allFutures(
|
||||
switchRelay.start(), privatePeerSwitch1.start(), privatePeerSwitch2.start(),
|
||||
switchAux.start(), switchAux2.start(), switchAux3.start(), switchAux4.start()
|
||||
)
|
||||
|
||||
await privatePeerSwitch1.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs)
|
||||
await privatePeerSwitch2.connect(switchAux.peerInfo.peerId, switchAux.peerInfo.addrs)
|
||||
|
||||
await sleepAsync(200.millis)
|
||||
|
||||
await privatePeerSwitch1.connect(switchAux2.peerInfo.peerId, switchAux2.peerInfo.addrs)
|
||||
await privatePeerSwitch1.connect(switchAux3.peerInfo.peerId, switchAux3.peerInfo.addrs)
|
||||
await privatePeerSwitch1.connect(switchAux4.peerInfo.peerId, switchAux4.peerInfo.addrs)
|
||||
|
||||
await privatePeerSwitch2.connect(switchAux2.peerInfo.peerId, switchAux2.peerInfo.addrs)
|
||||
await privatePeerSwitch2.connect(switchAux3.peerInfo.peerId, switchAux3.peerInfo.addrs)
|
||||
await privatePeerSwitch2.connect(switchAux4.peerInfo.peerId, switchAux4.peerInfo.addrs)
|
||||
|
||||
privatePeerSwitch1.connectStub = connectStub
|
||||
await privatePeerSwitch2.connect(privatePeerSwitch1.peerInfo.peerId, (await privatePeerRelayAddr1))
|
||||
|
||||
await sleepAsync(200.millis)
|
||||
|
||||
await allFuturesThrowing(
|
||||
privatePeerSwitch1.stop(), privatePeerSwitch2.stop(), switchRelay.stop(),
|
||||
switchAux.stop(), switchAux2.stop(), switchAux3.stop(), switchAux4.stop())
|
||||
|
||||
asyncTest "Hole punching when peers addresses are private":
|
||||
await holePunchingTest(nil, isGlobal, NotReachable)
|
||||
|
||||
asyncTest "Hole punching when there is an error during unilateral direct connection":
|
||||
|
||||
proc connectStub(): Future[void] {.async.} =
|
||||
raise newException(CatchableError, "error")
|
||||
|
||||
await holePunchingTest(connectStub, isPublicAddrIPAddrMock, Reachable)
|
||||
|
|
@ -44,4 +44,5 @@ import testtcptransport,
|
|||
testautonat,
|
||||
testautonatservice,
|
||||
testautorelay,
|
||||
testdcutr
|
||||
testdcutr,
|
||||
testhpservice
|
||||
|
|
Loading…
Reference in New Issue