Skip to content

Commit a7ab9a4

Browse files
authored
fix: use getThinWaistAddresss function (#3047)
Instead of every tcp/udp transport calculating thin waist addresses, use the function in `@libp2p/utils` instead.
1 parent 757577d commit a7ab9a4

File tree

16 files changed

+141
-254
lines changed

16 files changed

+141
-254
lines changed

packages/transport-tcp/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
"dependencies": {
6363
"@libp2p/interface": "^2.7.0",
6464
"@libp2p/utils": "^6.5.8",
65-
"@multiformats/mafmt": "^12.1.6",
6665
"@multiformats/multiaddr": "^12.3.3",
66+
"@multiformats/multiaddr-matcher": "^1.6.0",
6767
"@types/sinon": "^17.0.3",
6868
"p-defer": "^4.0.1",
6969
"p-event": "^6.0.1",
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
// p2p multi-address code
2-
export const CODE_P2P = 421
3-
export const CODE_CIRCUIT = 290
4-
export const CODE_UNIX = 400
5-
61
// Time to wait for a connection to close gracefully before destroying it manually
72
export const CLOSE_TIMEOUT = 500
83

94
// Close the socket if there is no activity after this long in ms
10-
export const SOCKET_TIMEOUT = 2 * 60000 // 2 mins
5+
export const SOCKET_TIMEOUT = 2 * 60_000 // 2 mins

packages/transport-tcp/src/listener.ts

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import net from 'net'
22
import { AlreadyStartedError, InvalidParametersError, NotStartedError, TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
3+
import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
4+
import { multiaddr } from '@multiformats/multiaddr'
35
import { pEvent } from 'p-event'
4-
import { CODE_P2P } from './constants.js'
56
import { toMultiaddrConnection } from './socket-to-conn.js'
6-
import {
7-
getMultiaddrs,
8-
multiaddrToNetConfig,
9-
type NetConfig
10-
} from './utils.js'
7+
import { multiaddrToNetConfig } from './utils.js'
118
import type { TCPCreateListenerOptions } from './index.js'
9+
import type { NetConfig } from './utils.js'
1210
import type { ComponentLogger, Logger, MultiaddrConnection, CounterGroup, MetricGroup, Metrics, Listener, ListenerEvents, Upgrader } from '@libp2p/interface'
1311
import type { Multiaddr } from '@multiformats/multiaddr'
1412

@@ -61,7 +59,6 @@ enum TCPListenerStatusCode {
6159
type Status = { code: TCPListenerStatusCode.INACTIVE } | {
6260
code: Exclude<TCPListenerStatusCode, TCPListenerStatusCode.INACTIVE>
6361
listeningAddr: Multiaddr
64-
peerId: string | null
6562
netConfig: NetConfig
6663
}
6764

@@ -247,31 +244,20 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
247244
return []
248245
}
249246

250-
let addrs: Multiaddr[] = []
251247
const address = this.server.address()
252-
const { listeningAddr, peerId } = this.status
253248

254249
if (address == null) {
255250
return []
256251
}
257252

258253
if (typeof address === 'string') {
259-
addrs = [listeningAddr]
260-
} else {
261-
try {
262-
// Because TCP will only return the IPv6 version
263-
// we need to capture from the passed multiaddr
264-
if (listeningAddr.toString().startsWith('/ip4')) {
265-
addrs = addrs.concat(getMultiaddrs('ip4', address.address, address.port))
266-
} else if (address.family === 'IPv6') {
267-
addrs = addrs.concat(getMultiaddrs('ip6', address.address, address.port))
268-
}
269-
} catch (err) {
270-
this.log.error('could not turn %s:%s into multiaddr', address.address, address.port, err)
271-
}
254+
return [
255+
// TODO: wrap with encodeURIComponent https://github.com/multiformats/multiaddr/pull/174
256+
multiaddr(`/unix/${address}`)
257+
]
272258
}
273259

274-
return addrs.map(ma => peerId != null ? ma.encapsulate(`/p2p/${peerId}`) : ma)
260+
return getThinWaistAddresses(this.status.listeningAddr, address.port)
275261
}
276262

277263
updateAnnounceAddrs (): void {
@@ -283,16 +269,11 @@ export class TCPListener extends TypedEventEmitter<ListenerEvents> implements Li
283269
throw new AlreadyStartedError('server is already listening')
284270
}
285271

286-
const peerId = ma.getPeerId()
287-
const listeningAddr = peerId == null ? ma.decapsulateCode(CODE_P2P) : ma
288-
const { backlog } = this.context
289-
290272
try {
291273
this.status = {
292274
code: TCPListenerStatusCode.ACTIVE,
293-
listeningAddr,
294-
peerId,
295-
netConfig: multiaddrToNetConfig(listeningAddr, { backlog })
275+
listeningAddr: ma,
276+
netConfig: multiaddrToNetConfig(ma, this.context)
296277
}
297278

298279
await this.resume()

packages/transport-tcp/src/tcp.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929

3030
import net from 'net'
3131
import { AbortError, TimeoutError, serviceCapabilities, transportSymbol } from '@libp2p/interface'
32-
import * as mafmt from '@multiformats/mafmt'
32+
import { TCP as TCPMatcher } from '@multiformats/multiaddr-matcher'
3333
import { CustomProgressEvent } from 'progress-events'
34-
import { CODE_CIRCUIT, CODE_P2P, CODE_UNIX } from './constants.js'
3534
import { TCPListener } from './listener.js'
3635
import { toMultiaddrConnection } from './socket-to-conn.js'
3736
import { multiaddrToNetConfig } from './utils.js'
@@ -204,19 +203,7 @@ export class TCP implements Transport<TCPDialEvents> {
204203
* Takes a list of `Multiaddr`s and returns only valid TCP addresses
205204
*/
206205
listenFilter (multiaddrs: Multiaddr[]): Multiaddr[] {
207-
multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
208-
209-
return multiaddrs.filter(ma => {
210-
if (ma.protoCodes().includes(CODE_CIRCUIT)) {
211-
return false
212-
}
213-
214-
if (ma.protoCodes().includes(CODE_UNIX)) {
215-
return true
216-
}
217-
218-
return mafmt.TCP.matches(ma.decapsulateCode(CODE_P2P))
219-
})
206+
return multiaddrs.filter(ma => TCPMatcher.exactMatch(ma) || ma.toString().startsWith('/unix/'))
220207
}
221208

222209
/**

packages/transport-tcp/src/utils.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import os from 'os'
22
import path from 'path'
3-
import { multiaddr } from '@multiformats/multiaddr'
43
import type { Multiaddr } from '@multiformats/multiaddr'
54
import type { ListenOptions, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net'
65

7-
const ProtoFamily = { ip4: 'IPv4', ip6: 'IPv6' }
8-
96
export type NetConfig = ListenOptions | (IpcSocketConnectOpts & TcpSocketConnectOpts)
107

118
export function multiaddrToNetConfig (addr: Multiaddr, config: NetConfig = {}): NetConfig {
@@ -30,30 +27,3 @@ export function multiaddrToNetConfig (addr: Multiaddr, config: NetConfig = {}):
3027
ipv6Only: options.family === 6
3128
}
3229
}
33-
34-
export function getMultiaddrs (proto: 'ip4' | 'ip6', ip: string, port: number): Multiaddr[] {
35-
const toMa = (ip: string): Multiaddr => multiaddr(`/${proto}/${ip}/tcp/${port}`)
36-
return (isAnyAddr(ip) ? getNetworkAddrs(ProtoFamily[proto]) : [ip]).map(toMa)
37-
}
38-
39-
export function isAnyAddr (ip: string): boolean {
40-
return ['0.0.0.0', '::'].includes(ip)
41-
}
42-
43-
const networks = os.networkInterfaces()
44-
45-
function getNetworkAddrs (family: string): string[] {
46-
const addresses: string[] = []
47-
48-
for (const [, netAddrs] of Object.entries(networks)) {
49-
if (netAddrs != null) {
50-
for (const netAddr of netAddrs) {
51-
if (netAddr.family === family) {
52-
addresses.push(netAddr.address)
53-
}
54-
}
55-
}
56-
}
57-
58-
return addresses
59-
}

packages/transport-tcp/test/filter.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ describe('filter addrs', () => {
3232
expect(valid.length).to.equal(5)
3333
expect(valid[0]).to.deep.equal(ma1)
3434
expect(valid[1]).to.deep.equal(ma4)
35+
expect(valid[2]).to.deep.equal(ma7)
36+
expect(valid[3]).to.deep.equal(ma8)
3537
expect(valid[4]).to.deep.equal(ma9)
3638
})
3739

packages/transport-tcp/test/listen-dial.spec.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,6 @@ describe('listen', () => {
150150
expect(multiaddrs.length > 0).to.equal(true)
151151
expect(multiaddrs[0].toOptions().host).to.not.equal('::')
152152
})
153-
154-
it('getAddrs preserves IPFS Id', async () => {
155-
const mh = multiaddr('/ip4/127.0.0.1/tcp/9090/ipfs/Qmb6owHp6eaWArVbcJJbQSyifyJBttMMjYV76N2hMbf5Vw')
156-
listener = transport.createListener({
157-
upgrader
158-
})
159-
await listener.listen(mh)
160-
161-
const multiaddrs = listener.getAddrs()
162-
expect(multiaddrs.length).to.equal(1)
163-
expect(multiaddrs[0]).to.deep.equal(mh)
164-
})
165153
})
166154

167155
describe('dial', () => {

packages/transport-webrtc/src/private-to-public/listener.ts

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { networkInterfaces } from 'node:os'
21
import { isIPv4, isIPv6 } from '@chainsafe/is-ip'
32
import { InvalidPeerIdError, TypedEventEmitter } from '@libp2p/interface'
4-
import { multiaddr, protocols, fromStringTuples } from '@multiformats/multiaddr'
5-
import { IP4, WebRTCDirect } from '@multiformats/multiaddr-matcher'
3+
import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
4+
import { multiaddr, fromStringTuples } from '@multiformats/multiaddr'
5+
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
66
import { Crypto } from '@peculiar/webcrypto'
77
import getPort from 'get-port'
88
import pWaitFor from 'p-wait-for'
@@ -40,10 +40,6 @@ export interface WebRTCListenerMetrics {
4040
listenerEvents: CounterGroup
4141
}
4242

43-
const UDP_PROTOCOL = protocols('udp')
44-
const IP4_PROTOCOL = protocols('ip4')
45-
const IP6_PROTOCOL = protocols('ip6')
46-
4743
interface UDPMuxServer {
4844
server: Promise<StunServer>
4945
isIPv4: boolean
@@ -56,8 +52,9 @@ interface UDPMuxServer {
5652
let UDP_MUX_LISTENERS: UDPMuxServer[] = []
5753

5854
export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> implements Listener {
59-
private readonly multiaddrs: Multiaddr[]
55+
private listeningMultiaddr?: Multiaddr
6056
private certificate?: TransportCertificate
57+
private stunServer?: StunServer
6158
private readonly connections: Map<string, DirectRTCPeerConnection>
6259
private readonly log: Logger
6360
private readonly init: WebRTCDirectListenerInit
@@ -70,7 +67,6 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
7067

7168
this.init = init
7269
this.components = components
73-
this.multiaddrs = []
7470
this.connections = new Map()
7571
this.log = components.logger.forComponent('libp2p:webrtc-direct:listener')
7672
this.certificate = init.certificates?.[0]
@@ -87,24 +83,7 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
8783
}
8884

8985
async listen (ma: Multiaddr): Promise<void> {
90-
const parts = ma.stringTuples()
91-
const ipVersion = IP4.matches(ma) ? 4 : 6
92-
const host = parts
93-
.filter(([code]) => code === IP4_PROTOCOL.code)
94-
.pop()?.[1] ?? parts
95-
.filter(([code]) => code === IP6_PROTOCOL.code)
96-
.pop()?.[1]
97-
98-
if (host == null) {
99-
throw new Error('IP4/6 host must be specified in webrtc-direct multiaddr')
100-
}
101-
const port = parseInt(parts
102-
.filter(([code, value]) => code === UDP_PROTOCOL.code)
103-
.pop()?.[1] ?? '')
104-
105-
if (isNaN(port)) {
106-
throw new Error('UDP port must be specified in webrtc-direct multiaddr')
107-
}
86+
const { host, port } = ma.toOptions()
10887

10988
// have to do this before any async work happens so starting two listeners
11089
// for the same port concurrently (e.g. ipv4/ipv6 both port 0) results in a
@@ -133,17 +112,14 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
133112
throw new InvalidPeerIdError(`Another peer is already performing UDP mux on ${host}:${existingServer.port}`)
134113
}
135114

136-
const server = await existingServer.server
137-
const address = server.address()
115+
this.stunServer = await existingServer.server
116+
const address = this.stunServer.address()
138117

139118
if (!createdMuxServer) {
140119
this.log('reused existing UDP mux server on %s:%p', host, address.port)
141120
}
142121

143-
getNetworkAddresses(host, address.port, ipVersion).forEach((ma) => {
144-
this.multiaddrs.push(multiaddr(`${ma}/webrtc-direct/certhash/${this.certificate?.certhash}`))
145-
})
146-
122+
this.listeningMultiaddr = ma
147123
this.safeDispatchEvent('listening')
148124
}
149125

@@ -247,7 +223,15 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
247223
}
248224

249225
getAddrs (): Multiaddr[] {
250-
return this.multiaddrs
226+
if (this.stunServer == null) {
227+
return []
228+
}
229+
230+
const address = this.stunServer.address()
231+
232+
return getThinWaistAddresses(this.listeningMultiaddr, address.port).map(ma => {
233+
return ma.encapsulate(`/webrtc-direct/certhash/${this.certificate?.certhash}`)
234+
})
251235
}
252236

253237
updateAnnounceAddrs (multiaddrs: Multiaddr[]): void {
@@ -309,32 +293,3 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
309293
this.safeDispatchEvent('close')
310294
}
311295
}
312-
313-
function getNetworkAddresses (host: string, port: number, version: 4 | 6): string[] {
314-
if (host === '0.0.0.0' || host === '::') {
315-
// return all ip4 interfaces
316-
return Object.entries(networkInterfaces())
317-
.flatMap(([_, addresses]) => addresses)
318-
.map(address => address?.address)
319-
.filter(address => {
320-
if (address == null) {
321-
return false
322-
}
323-
324-
if (version === 4) {
325-
return isIPv4(address)
326-
}
327-
328-
if (version === 6) {
329-
return isIPv6(address)
330-
}
331-
332-
return false
333-
})
334-
.map(address => `/ip${version}/${address}/udp/${port}`)
335-
}
336-
337-
return [
338-
`/ip${version}/${host}/udp/${port}`
339-
]
340-
}

0 commit comments

Comments
 (0)