parent
b7726bf68f
commit
a5666789b0
|
@ -20,8 +20,6 @@ import ../../../switch,
|
||||||
../../../peerid
|
../../../peerid
|
||||||
import core
|
import core
|
||||||
|
|
||||||
export core
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "libp2p autonat"
|
topics = "libp2p autonat"
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,12 @@ import chronos, metrics
|
||||||
import ../../../switch
|
import ../../../switch
|
||||||
import ../../../wire
|
import ../../../wire
|
||||||
import client
|
import client
|
||||||
|
from core import NetworkReachability, AutonatUnreachableError
|
||||||
import ../../../utils/heartbeat
|
import ../../../utils/heartbeat
|
||||||
import ../../../crypto/crypto
|
import ../../../crypto/crypto
|
||||||
|
|
||||||
|
export options, core.NetworkReachability
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "libp2p autonatservice"
|
topics = "libp2p autonatservice"
|
||||||
|
|
||||||
|
@ -30,7 +33,7 @@ type
|
||||||
newConnectedPeerHandler: PeerEventHandler
|
newConnectedPeerHandler: PeerEventHandler
|
||||||
addressMapper: AddressMapper
|
addressMapper: AddressMapper
|
||||||
scheduleHandle: Future[void]
|
scheduleHandle: Future[void]
|
||||||
networkReachability: NetworkReachability
|
networkReachability*: NetworkReachability
|
||||||
confidence: Option[float]
|
confidence: Option[float]
|
||||||
answers: Deque[NetworkReachability]
|
answers: Deque[NetworkReachability]
|
||||||
autonatClient: AutonatClient
|
autonatClient: AutonatClient
|
||||||
|
@ -71,9 +74,6 @@ proc new*(
|
||||||
dialTimeout: dialTimeout,
|
dialTimeout: dialTimeout,
|
||||||
enableAddressMapper: enableAddressMapper)
|
enableAddressMapper: enableAddressMapper)
|
||||||
|
|
||||||
proc networkReachability*(self: AutonatService): NetworkReachability {.inline.} =
|
|
||||||
return self.networkReachability
|
|
||||||
|
|
||||||
proc callHandler(self: AutonatService) {.async.} =
|
proc callHandler(self: AutonatService) {.async.} =
|
||||||
if not isNil(self.statusAndConfidenceHandler):
|
if not isNil(self.statusAndConfidenceHandler):
|
||||||
await self.statusAndConfidenceHandler(self.networkReachability, self.confidence)
|
await self.statusAndConfidenceHandler(self.networkReachability, self.confidence)
|
||||||
|
|
|
@ -23,6 +23,8 @@ import ../../protocol,
|
||||||
../../../switch,
|
../../../switch,
|
||||||
../../../utils/future
|
../../../utils/future
|
||||||
|
|
||||||
|
export DcutrError
|
||||||
|
|
||||||
type
|
type
|
||||||
DcutrClient* = ref object
|
DcutrClient* = ref object
|
||||||
connectTimeout: Duration
|
connectTimeout: Duration
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ../../protocol,
|
||||||
../../../switch,
|
../../../switch,
|
||||||
../../../utils/future
|
../../../utils/future
|
||||||
|
|
||||||
|
export DcutrError
|
||||||
export chronicles
|
export chronicles
|
||||||
|
|
||||||
type Dcutr* = ref object of LPProtocol
|
type Dcutr* = ref object of LPProtocol
|
||||||
|
|
|
@ -101,7 +101,7 @@ proc createReserveResponse(
|
||||||
status: some(Ok))
|
status: some(Ok))
|
||||||
return ok(msg)
|
return ok(msg)
|
||||||
|
|
||||||
proc isRelayed(conn: Connection): bool =
|
proc isRelayed*(conn: Connection): bool =
|
||||||
var wrappedConn = conn
|
var wrappedConn = conn
|
||||||
while not isNil(wrappedConn):
|
while not isNil(wrappedConn):
|
||||||
if wrappedConn of RelayConnection:
|
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))
|
res.port = Port(fromBytesBE(uint16, pbuf))
|
||||||
ok(res)
|
ok(res)
|
||||||
else:
|
else:
|
||||||
err("MultiAddress must be wire address (tcp, udp or unix)")
|
err("MultiAddress must be wire address (tcp, udp or unix): " & $ma)
|
||||||
|
|
||||||
proc connect*(
|
proc connect*(
|
||||||
ma: MultiAddress,
|
ma: MultiAddress,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ../../libp2p/[protocols/connectivity/autonat/client,
|
||||||
peerid,
|
peerid,
|
||||||
multiaddress,
|
multiaddress,
|
||||||
switch]
|
switch]
|
||||||
|
from ../../libp2p/protocols/connectivity/autonat/core import NetworkReachability, AutonatUnreachableError, AutonatError
|
||||||
|
|
||||||
type
|
type
|
||||||
AutonatClientStub* = ref object of AutonatClient
|
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.}
|
{.used.}
|
||||||
|
|
||||||
when (NimMajor, NimMinor) < (1, 4):
|
when (NimMajor, NimMinor) < (1, 4):
|
||||||
|
|
|
@ -51,7 +51,7 @@ suite "Autonat Service":
|
||||||
let switch3 = createSwitch()
|
let switch3 = createSwitch()
|
||||||
let switch4 = createSwitch()
|
let switch4 = createSwitch()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
await switch1.start()
|
await switch1.start()
|
||||||
await switch2.start()
|
await switch2.start()
|
||||||
|
@ -64,7 +64,7 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await autonatClientStub.finished
|
await autonatClientStub.finished
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
||||||
|
|
||||||
await allFuturesThrowing(
|
await allFuturesThrowing(
|
||||||
|
@ -86,7 +86,7 @@ suite "Autonat Service":
|
||||||
if not awaiter.finished:
|
if not awaiter.finished:
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
||||||
|
|
||||||
check switch1.peerInfo.addrs == switch1.peerInfo.listenAddrs.mapIt(switch1.peerStore.guessDialableAddr(it))
|
check switch1.peerInfo.addrs == switch1.peerInfo.listenAddrs.mapIt(switch1.peerStore.guessDialableAddr(it))
|
||||||
|
@ -131,7 +131,7 @@ suite "Autonat Service":
|
||||||
autonatClientStub.answer = Reachable
|
autonatClientStub.answer = Reachable
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -146,12 +146,12 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 0.3
|
||||||
|
|
||||||
await autonatClientStub.finished
|
await autonatClientStub.finished
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 0.3
|
||||||
|
|
||||||
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
||||||
|
@ -172,7 +172,7 @@ suite "Autonat Service":
|
||||||
if not awaiter.finished:
|
if not awaiter.finished:
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||||
|
|
||||||
await allFuturesThrowing(
|
await allFuturesThrowing(
|
||||||
|
@ -213,7 +213,7 @@ suite "Autonat Service":
|
||||||
autonatClientStub.answer = Unknown
|
autonatClientStub.answer = Unknown
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -228,12 +228,12 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
||||||
|
|
||||||
await autonatClientStub.finished
|
await autonatClientStub.finished
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.NotReachable
|
check autonatService.networkReachability == NetworkReachability.NotReachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
check libp2p_autonat_reachability_confidence.value(["NotReachable"]) == 1/3
|
||||||
|
|
||||||
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
await allFuturesThrowing(switch1.stop(), switch2.stop(), switch3.stop(), switch4.stop())
|
||||||
|
@ -264,7 +264,7 @@ suite "Autonat Service":
|
||||||
if not awaiter.finished:
|
if not awaiter.finished:
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||||
|
|
||||||
await allFuturesThrowing(
|
await allFuturesThrowing(
|
||||||
|
@ -304,8 +304,8 @@ suite "Autonat Service":
|
||||||
if not awaiter2.finished:
|
if not awaiter2.finished:
|
||||||
awaiter2.complete()
|
awaiter2.complete()
|
||||||
|
|
||||||
check autonatService1.networkReachability() == NetworkReachability.Unknown
|
check autonatService1.networkReachability == NetworkReachability.Unknown
|
||||||
check autonatService2.networkReachability() == NetworkReachability.Unknown
|
check autonatService2.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
||||||
autonatService2.statusAndConfidenceHandler(statusAndConfidenceHandler2)
|
autonatService2.statusAndConfidenceHandler(statusAndConfidenceHandler2)
|
||||||
|
@ -321,8 +321,8 @@ suite "Autonat Service":
|
||||||
await awaiter1
|
await awaiter1
|
||||||
await awaiter2
|
await awaiter2
|
||||||
|
|
||||||
check autonatService1.networkReachability() == NetworkReachability.Reachable
|
check autonatService1.networkReachability == NetworkReachability.Reachable
|
||||||
check autonatService2.networkReachability() == NetworkReachability.Reachable
|
check autonatService2.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||||
|
|
||||||
await allFuturesThrowing(
|
await allFuturesThrowing(
|
||||||
|
@ -342,7 +342,7 @@ suite "Autonat Service":
|
||||||
if not awaiter1.finished:
|
if not awaiter1.finished:
|
||||||
awaiter1.complete()
|
awaiter1.complete()
|
||||||
|
|
||||||
check autonatService1.networkReachability() == NetworkReachability.Unknown
|
check autonatService1.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
autonatService1.statusAndConfidenceHandler(statusAndConfidenceHandler1)
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ suite "Autonat Service":
|
||||||
|
|
||||||
await awaiter1
|
await awaiter1
|
||||||
|
|
||||||
check autonatService1.networkReachability() == NetworkReachability.Reachable
|
check autonatService1.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||||
|
|
||||||
# Make sure remote peer can't create a connection to us
|
# Make sure remote peer can't create a connection to us
|
||||||
|
@ -385,7 +385,7 @@ suite "Autonat Service":
|
||||||
if not awaiter.finished:
|
if not awaiter.finished:
|
||||||
awaiter.complete()
|
awaiter.complete()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ suite "Autonat Service":
|
||||||
await autonatService.run(switch1)
|
await autonatService.run(switch1)
|
||||||
await awaiter
|
await awaiter
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Reachable
|
check autonatService.networkReachability == NetworkReachability.Reachable
|
||||||
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
check libp2p_autonat_reachability_confidence.value(["Reachable"]) == 1
|
||||||
|
|
||||||
await allFuturesThrowing(
|
await allFuturesThrowing(
|
||||||
|
@ -422,7 +422,7 @@ suite "Autonat Service":
|
||||||
proc statusAndConfidenceHandler(networkReachability: NetworkReachability, confidence: Option[float]) {.gcsafe, async.} =
|
proc statusAndConfidenceHandler(networkReachability: NetworkReachability, confidence: Option[float]) {.gcsafe, async.} =
|
||||||
fail()
|
fail()
|
||||||
|
|
||||||
check autonatService.networkReachability() == NetworkReachability.Unknown
|
check autonatService.networkReachability == NetworkReachability.Unknown
|
||||||
|
|
||||||
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler)
|
||||||
|
|
||||||
|
|
|
@ -16,36 +16,7 @@ from ../libp2p/protocols/connectivity/autonat/core import NetworkReachability
|
||||||
import ../libp2p/builders
|
import ../libp2p/builders
|
||||||
import ../libp2p/utils/future
|
import ../libp2p/utils/future
|
||||||
import ./helpers
|
import ./helpers
|
||||||
|
import ./stubs/switchstub
|
||||||
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)
|
|
||||||
|
|
||||||
suite "Dcutr":
|
suite "Dcutr":
|
||||||
teardown:
|
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,
|
testautonat,
|
||||||
testautonatservice,
|
testautonatservice,
|
||||||
testautorelay,
|
testautorelay,
|
||||||
testdcutr
|
testdcutr,
|
||||||
|
testhpservice
|
||||||
|
|
Loading…
Reference in New Issue