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
5 changes: 5 additions & 0 deletions packages/upnp-nat/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
export const DEFAULT_INITIAL_GATEWAY_SEARCH_INTERVAL = 5_000
export const DEFAULT_INITIAL_GATEWAY_SEARCH_TIMEOUT = 5_000
export const DEFAULT_INITIAL_GATEWAY_SEARCH_MESSAGE_INTERVAL = 1_000

export const DEFAULT_GATEWAY_SEARCH_TIMEOUT = 60_000
export const DEFAULT_GATEWAY_SEARCH_INTERVAL = 300_000
export const DEFAULT_GATEWAY_SEARCH_MESSAGE_INTERVAL = 10_000
55 changes: 40 additions & 15 deletions packages/upnp-nat/src/gateway-finder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TypedEventEmitter, start, stop } from '@libp2p/interface'
import { repeatingTask } from '@libp2p/utils/repeating-task'
import { DEFAULT_GATEWAY_SEARCH_INTERVAL, DEFAULT_GATEWAY_SEARCH_TIMEOUT } from './constants.js'
import { DEFAULT_GATEWAY_SEARCH_INTERVAL, DEFAULT_GATEWAY_SEARCH_MESSAGE_INTERVAL, DEFAULT_GATEWAY_SEARCH_TIMEOUT, DEFAULT_INITIAL_GATEWAY_SEARCH_INTERVAL, DEFAULT_INITIAL_GATEWAY_SEARCH_MESSAGE_INTERVAL, DEFAULT_INITIAL_GATEWAY_SEARCH_TIMEOUT } from './constants.js'
import type { Gateway, UPnPNAT } from '@achingbrain/nat-port-mapper'
import type { ComponentLogger, Logger } from '@libp2p/interface'
import type { RepeatingTask } from '@libp2p/utils/repeating-task'
Expand All @@ -11,6 +11,12 @@ export interface GatewayFinderComponents {

export interface GatewayFinderInit {
portMappingClient: UPnPNAT
initialSearchInterval?: number
initialSearchTimeout?: number
initialSearchMessageInterval?: number
searchInterval?: number
searchTimeout?: number
searchMessageInterval?: number
}

export interface GatewayFinderEvents {
Expand All @@ -34,25 +40,44 @@ export class GatewayFinder extends TypedEventEmitter<GatewayFinderEvents> {

// every five minutes, search for network gateways for one minute
this.findGateways = repeatingTask(async (options) => {
for await (const gateway of this.portMappingClient.findGateways({
...options,
searchInterval: 10000
})) {
if (this.gateways.some(g => {
return g.id === gateway.id && g.family === gateway.family
try {
const searchMessageInterval = this.gateways.length > 0
? init.searchMessageInterval ?? DEFAULT_GATEWAY_SEARCH_MESSAGE_INTERVAL
: init.initialSearchMessageInterval ?? DEFAULT_INITIAL_GATEWAY_SEARCH_MESSAGE_INTERVAL

this.log('begin gateway search, sending M-SEARCH every %dms', searchMessageInterval)

for await (const gateway of this.portMappingClient.findGateways({
...options,
searchInterval: searchMessageInterval
})) {
// already seen this gateway
continue
if (this.gateways.some(g => {
return g.id === gateway.id && g.family === gateway.family
})) {
// already seen this gateway
continue
}

this.gateways.push(gateway)
this.safeDispatchEvent('gateway', {
detail: gateway
})

// we've found a gateway, wait for longer before searching again
const searchInterval = init.searchTimeout ?? DEFAULT_GATEWAY_SEARCH_INTERVAL
const searchTimeout = init.searchTimeout ?? DEFAULT_GATEWAY_SEARCH_TIMEOUT
this.log('switching gateway search to every %dms, timing out after %dms', searchInterval, searchTimeout)
this.findGateways.setInterval(searchInterval)
this.findGateways.setTimeout(searchTimeout)
}

this.gateways.push(gateway)
this.safeDispatchEvent('gateway', {
detail: gateway
})
this.log('gateway search finished, found %d gateways', this.gateways.length)
} catch (err) {
this.log.error('gateway search errored - %e', err)
}
}, DEFAULT_GATEWAY_SEARCH_INTERVAL, {
}, init.initialSearchInterval ?? DEFAULT_INITIAL_GATEWAY_SEARCH_INTERVAL, {
runImmediately: true,
timeout: DEFAULT_GATEWAY_SEARCH_TIMEOUT
timeout: init.initialSearchTimeout ?? DEFAULT_INITIAL_GATEWAY_SEARCH_TIMEOUT
})
}

Expand Down
68 changes: 68 additions & 0 deletions packages/upnp-nat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,74 @@ export interface UPnPNATInit {
* @default false
*/
autoConfirmAddress?: boolean

/**
* How often to search for network gateways in ms.
*
* This interval is used before a gateway has been found on the network, after
* that it switches to `gatewaySearchInterval` which lowers the frequency of
* the search.
*
* @default 5_000
*/
initialGatewaySearchInterval?: number

/**
* How often to send the `M-SEARCH` SSDP message during a gateway search in
* ms.
*
* Some routers are flaky and may not respond to every query so decreasing
* this will increase the number of search messages sent before the timeout.
*
* This interval is used before a gateway has been found on the network, after
* that it switches to `gatewaySearchMessageInterval` which lowers the
* frequency of search messages sent.
*
* @default 1_000
*/
initialGatewaySearchMessageInterval?: number

/**
* How long to search for gateways for before giving up in ms.
*
* This timeout is used before a gateway has been found on the network, after
* that it switches to `gatewaySearchTimeout` which increases the timeout to
* give gateways more time to respond.
*
* @default 5_000
*/
initialGatewaySearchTimeout?: number

/**
* How often to search for network gateways in ms.
*
* This interval is used after a gateway has been found on the network.
*
* @default 300_000
*/
gatewaySearchInterval?: number

/**
* How often to send the `M-SEARCH` SSDP message during a gateway search in
* ms.
*
* Some routers are flaky and may not respond to every query so decreasing
* this will increase the number of search messages sent before the timeout.
*
* This interval is used after a gateway has been found on the network.
*
* @default 10_000
*/
gatewaySearchMessageInterval?: number

/**
* How long to search for gateways for before giving up in ms.
*
* This timeout is used after a gateway has been found on the network.
*
* @default 60_000
*/
gatewaySearchTimeout?: number
}

export interface UPnPNATComponents {
Expand Down
8 changes: 7 additions & 1 deletion packages/upnp-nat/src/upnp-nat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ export class UPnPNAT implements Startable, UPnPNATInterface {

// trigger update when we discovery gateways on the network
this.gatewayFinder = new GatewayFinder(components, {
portMappingClient: this.portMappingClient
portMappingClient: this.portMappingClient,
initialSearchInterval: init.initialGatewaySearchInterval,
initialSearchTimeout: init.initialGatewaySearchTimeout,
initialSearchMessageInterval: init.initialGatewaySearchMessageInterval,
searchInterval: init.gatewaySearchInterval,
searchTimeout: init.gatewaySearchTimeout,
searchMessageInterval: init.gatewaySearchMessageInterval
})

this.onGatewayDiscovered = this.onGatewayDiscovered.bind(this)
Expand Down
Loading