|
1 |
| -import { isIPv4, isIPv6 } from '@chainsafe/is-ip' |
2 |
| -import { InvalidPeerIdError, TypedEventEmitter } from '@libp2p/interface' |
| 1 | +import { isIPv4 } from '@chainsafe/is-ip' |
| 2 | +import { InvalidParametersError, InvalidPeerIdError, TypedEventEmitter } from '@libp2p/interface' |
3 | 3 | import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
|
4 | 4 | import { multiaddr, fromStringTuples } from '@multiformats/multiaddr'
|
5 | 5 | import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
|
@@ -83,53 +83,53 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
83 | 83 | }
|
84 | 84 |
|
85 | 85 | async listen (ma: Multiaddr): Promise<void> {
|
86 |
| - const { host, port } = ma.toOptions() |
87 |
| - |
88 |
| - // have to do this before any async work happens so starting two listeners |
89 |
| - // for the same port concurrently (e.g. ipv4/ipv6 both port 0) results in a |
90 |
| - // single mux listener. This is necessary because libjuice binds to all |
91 |
| - // interfaces for a given port so we we need to key on just the port number |
92 |
| - // not the host + the port number |
93 |
| - let existingServer = UDP_MUX_LISTENERS.find(s => s.port === port) |
94 |
| - |
95 |
| - // if the server has not been started yet, or the port is a wildcard port |
96 |
| - // and there is already a wildcard port for this address family, start a new |
97 |
| - // UDP mux server |
98 |
| - const wildcardPorts = port === 0 && existingServer?.port === 0 |
99 |
| - const sameAddressFamily = (existingServer?.isIPv4 === true && isIPv4(host)) || (existingServer?.isIPv6 === true && isIPv6(host)) |
100 |
| - let createdMuxServer = false |
101 |
| - |
102 |
| - if (existingServer == null || (wildcardPorts && sameAddressFamily)) { |
103 |
| - this.log('starting UDP mux server on %s:%p', host, port) |
104 |
| - existingServer = this.startUDPMuxServer(host, port) |
105 |
| - UDP_MUX_LISTENERS.push(existingServer) |
106 |
| - createdMuxServer = true |
107 |
| - } |
| 86 | + const { host, port, family } = ma.toOptions() |
| 87 | + |
| 88 | + let udpMuxServer: UDPMuxServer | undefined |
| 89 | + |
| 90 | + if (port !== 0) { |
| 91 | + // libjuice binds to all interfaces (IPv4/IPv6) for a given port so if we |
| 92 | + // want to listen on a specific port, and there's already a mux listener |
| 93 | + // for that port for the other family started by this node, we should |
| 94 | + // reuse it |
| 95 | + udpMuxServer = UDP_MUX_LISTENERS.find(s => s.port === port) |
| 96 | + |
| 97 | + // make sure the port is free for the given family |
| 98 | + if (udpMuxServer != null && ((udpMuxServer.isIPv4 && family === 4) || (udpMuxServer.isIPv6 && family === 6))) { |
| 99 | + throw new InvalidParametersError(`There is already a listener for ${host}:${port}`) |
| 100 | + } |
108 | 101 |
|
109 |
| - if (!existingServer.peerId.equals(this.components.peerId)) { |
110 |
| - // this would have to be another in-process peer so we are likely in a |
111 |
| - // testing environment |
112 |
| - throw new InvalidPeerIdError(`Another peer is already performing UDP mux on ${host}:${existingServer.port}`) |
| 102 | + // check that we own the mux server |
| 103 | + if (udpMuxServer != null && !udpMuxServer.peerId.equals(this.components.peerId)) { |
| 104 | + throw new InvalidPeerIdError(`Another peer is already performing UDP mux on ${host}:${port}`) |
| 105 | + } |
113 | 106 | }
|
114 | 107 |
|
115 |
| - this.stunServer = await existingServer.server |
116 |
| - const address = this.stunServer.address() |
| 108 | + // start the mux server if we don't have one already |
| 109 | + if (udpMuxServer == null) { |
| 110 | + this.log('starting UDP mux server on %s:%p', host, port) |
| 111 | + udpMuxServer = this.startUDPMuxServer(host, port, family) |
| 112 | + UDP_MUX_LISTENERS.push(udpMuxServer) |
| 113 | + } |
117 | 114 |
|
118 |
| - if (!createdMuxServer) { |
119 |
| - this.log('reused existing UDP mux server on %s:%p', host, address.port) |
| 115 | + if (family === 4) { |
| 116 | + udpMuxServer.isIPv4 = true |
| 117 | + } else if (family === 6) { |
| 118 | + udpMuxServer.isIPv6 = true |
120 | 119 | }
|
121 | 120 |
|
| 121 | + this.stunServer = await udpMuxServer.server |
122 | 122 | this.listeningMultiaddr = ma
|
123 | 123 | this.safeDispatchEvent('listening')
|
124 | 124 | }
|
125 | 125 |
|
126 |
| - private startUDPMuxServer (host: string, port: number): UDPMuxServer { |
| 126 | + private startUDPMuxServer (host: string, port: number, family: 4 | 6): UDPMuxServer { |
127 | 127 | return {
|
128 | 128 | peerId: this.components.peerId,
|
129 | 129 | owner: this,
|
130 | 130 | port,
|
131 |
| - isIPv4: isIPv4(host), |
132 |
| - isIPv6: isIPv6(host), |
| 131 | + isIPv4: family === 4, |
| 132 | + isIPv6: family === 6, |
133 | 133 | server: Promise.resolve()
|
134 | 134 | .then(async (): Promise<StunServer> => {
|
135 | 135 | // ensure we have a certificate
|
|
0 commit comments