libp2p 2.9.0 → 2.10.0-a02cb0461
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +13 -17
- package/dist/index.min.js.map +4 -4
- package/dist/src/address-manager/dns-mappings.d.ts.map +1 -1
- package/dist/src/address-manager/dns-mappings.js +2 -3
- package/dist/src/address-manager/dns-mappings.js.map +1 -1
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +1 -3
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/address-manager/ip-mappings.js +1 -1
- package/dist/src/address-manager/ip-mappings.js.map +1 -1
- package/dist/src/address-manager/observed-addresses.d.ts.map +1 -1
- package/dist/src/address-manager/observed-addresses.js +1 -3
- package/dist/src/address-manager/observed-addresses.js.map +1 -1
- package/dist/src/address-manager/transport-addresses.d.ts.map +1 -1
- package/dist/src/address-manager/transport-addresses.js +1 -3
- package/dist/src/address-manager/transport-addresses.js.map +1 -1
- package/dist/src/config/connection-gater.browser.js +1 -1
- package/dist/src/config/connection-gater.browser.js.map +1 -1
- package/dist/src/config.js +1 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/address-sorter.d.ts.map +1 -1
- package/dist/src/connection-manager/address-sorter.js +1 -2
- package/dist/src/connection-manager/address-sorter.js.map +1 -1
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
- package/dist/src/connection-manager/connection-pruner.js +1 -2
- package/dist/src/connection-manager/connection-pruner.js.map +1 -1
- package/dist/src/connection-manager/constants.defaults.d.ts +4 -0
- package/dist/src/connection-manager/constants.defaults.d.ts.map +1 -1
- package/dist/src/connection-manager/constants.defaults.js +4 -0
- package/dist/src/connection-manager/constants.defaults.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +2 -2
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +11 -23
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +10 -2
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +29 -19
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/reconnect-queue.js +1 -1
- package/dist/src/connection-manager/reconnect-queue.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts +28 -0
- package/dist/src/connection-manager/utils.d.ts.map +1 -1
- package/dist/src/connection-manager/utils.js +78 -0
- package/dist/src/connection-manager/utils.js.map +1 -1
- package/dist/src/connection-monitor.d.ts +1 -1
- package/dist/src/connection-monitor.d.ts.map +1 -1
- package/dist/src/connection-monitor.js +2 -3
- package/dist/src/connection-monitor.js.map +1 -1
- package/dist/src/connection.d.ts +62 -0
- package/dist/src/connection.d.ts.map +1 -0
- package/dist/src/connection.js +239 -0
- package/dist/src/connection.js.map +1 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +2 -2
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +3 -3
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/peer-routing.js +1 -1
- package/dist/src/peer-routing.js.map +1 -1
- package/dist/src/random-walk.d.ts.map +1 -1
- package/dist/src/random-walk.js +13 -3
- package/dist/src/random-walk.js.map +1 -1
- package/dist/src/registrar.d.ts +3 -3
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +50 -41
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/transport-manager.js +15 -2
- package/dist/src/transport-manager.js.map +1 -1
- package/dist/src/upgrader.d.ts +27 -25
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +95 -335
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/utils.d.ts +3 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +25 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/package.json +26 -30
- package/src/address-manager/dns-mappings.ts +2 -3
- package/src/address-manager/index.ts +2 -4
- package/src/address-manager/ip-mappings.ts +1 -1
- package/src/address-manager/observed-addresses.ts +1 -3
- package/src/address-manager/transport-addresses.ts +1 -3
- package/src/config/connection-gater.browser.ts +1 -1
- package/src/config.ts +1 -1
- package/src/connection-manager/address-sorter.ts +1 -2
- package/src/connection-manager/connection-pruner.ts +1 -2
- package/src/connection-manager/constants.defaults.ts +5 -0
- package/src/connection-manager/dial-queue.ts +12 -27
- package/src/connection-manager/index.ts +44 -21
- package/src/connection-manager/reconnect-queue.ts +1 -1
- package/src/connection-manager/utils.ts +104 -0
- package/src/connection-monitor.ts +3 -4
- package/src/connection.ts +316 -0
- package/src/index.ts +2 -2
- package/src/libp2p.ts +3 -4
- package/src/peer-routing.ts +1 -1
- package/src/random-walk.ts +13 -3
- package/src/registrar.ts +67 -54
- package/src/transport-manager.ts +18 -2
- package/src/upgrader.ts +141 -420
- package/src/utils.ts +31 -0
- package/src/version.ts +1 -1
- package/dist/src/connection/index.d.ts +0 -84
- package/dist/src/connection/index.d.ts.map +0 -1
- package/dist/src/connection/index.js +0 -144
- package/dist/src/connection/index.js.map +0 -1
- package/dist/typedoc-urls.json +0 -24
- package/src/connection/index.ts +0 -199
package/src/upgrader.ts
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
import { InvalidMultiaddrError,
|
|
1
|
+
import { InvalidMultiaddrError, InvalidPeerIdError } from '@libp2p/interface'
|
|
2
2
|
import * as mss from '@libp2p/multistream-select'
|
|
3
3
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
4
|
-
import { trackedMap } from '@libp2p/utils
|
|
4
|
+
import { trackedMap } from '@libp2p/utils'
|
|
5
5
|
import { anySignal } from 'any-signal'
|
|
6
6
|
import { setMaxListeners } from 'main-event'
|
|
7
7
|
import { CustomProgressEvent } from 'progress-events'
|
|
8
8
|
import { raceSignal } from 'race-signal'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { PROTOCOL_NEGOTIATION_TIMEOUT, INBOUND_UPGRADE_TIMEOUT, CONNECTION_CLOSE_TIMEOUT } from './connection-manager/constants.js'
|
|
10
|
+
import { createConnection } from './connection.js'
|
|
11
11
|
import { ConnectionDeniedError, ConnectionInterceptedError, EncryptionFailedError, MuxerUnavailableError } from './errors.js'
|
|
12
|
-
import {
|
|
13
|
-
import type { Libp2pEvents, AbortOptions, ComponentLogger, MultiaddrConnection, Connection, Stream, ConnectionProtector, NewStreamOptions, ConnectionEncrypter, SecuredConnection, ConnectionGater, Metrics, PeerId, PeerStore, StreamMuxer, StreamMuxerFactory, Upgrader as UpgraderInterface, UpgraderOptions, ConnectionLimits, SecureConnectionOptions, CounterGroup, ClearableSignal } from '@libp2p/interface'
|
|
12
|
+
import type { Libp2pEvents, AbortOptions, ComponentLogger, MultiaddrConnection, Connection, ConnectionProtector, ConnectionEncrypter, ConnectionGater, Metrics, PeerId, PeerStore, StreamMuxerFactory, Upgrader as UpgraderInterface, UpgraderOptions, ConnectionLimits, CounterGroup, ClearableSignal, MessageStream, SecuredConnection, StreamMuxer, UpgraderWithoutEncryptionOptions, SecureConnectionOptions } from '@libp2p/interface'
|
|
14
13
|
import type { ConnectionManager, Registrar } from '@libp2p/interface-internal'
|
|
15
14
|
import type { TypedEventTarget } from 'main-event'
|
|
16
15
|
|
|
17
16
|
interface CreateConnectionOptions {
|
|
17
|
+
id: string
|
|
18
18
|
cryptoProtocol: string
|
|
19
19
|
direction: 'inbound' | 'outbound'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The raw underlying connection
|
|
23
|
+
*/
|
|
20
24
|
maConn: MultiaddrConnection
|
|
21
|
-
upgradedConn: MultiaddrConnection
|
|
22
|
-
remotePeer: PeerId
|
|
23
|
-
muxerFactory?: StreamMuxerFactory
|
|
24
|
-
limits?: ConnectionLimits
|
|
25
|
-
}
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
26
|
+
/**
|
|
27
|
+
* The encrypted, multiplexed connection
|
|
28
|
+
*/
|
|
29
|
+
stream: MessageStream
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
remotePeer: PeerId
|
|
32
|
+
muxer?: StreamMuxer
|
|
33
|
+
limits?: ConnectionLimits
|
|
34
|
+
closeTimeout?: number
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export interface UpgraderInit {
|
|
@@ -60,48 +60,13 @@ export interface UpgraderInit {
|
|
|
60
60
|
* @default 2000
|
|
61
61
|
*/
|
|
62
62
|
outboundStreamProtocolNegotiationTimeout?: number
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function findIncomingStreamLimit (protocol: string, registrar: Registrar): number | undefined {
|
|
66
|
-
try {
|
|
67
|
-
const { options } = registrar.getHandler(protocol)
|
|
68
|
-
|
|
69
|
-
return options.maxInboundStreams
|
|
70
|
-
} catch (err: any) {
|
|
71
|
-
if (err.name !== 'UnhandledProtocolError') {
|
|
72
|
-
throw err
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
63
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (options.maxOutboundStreams != null) {
|
|
84
|
-
return options.maxOutboundStreams
|
|
85
|
-
}
|
|
86
|
-
} catch (err: any) {
|
|
87
|
-
if (err.name !== 'UnhandledProtocolError') {
|
|
88
|
-
throw err
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return options.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function countStreams (protocol: string, direction: 'inbound' | 'outbound', connection: Connection): number {
|
|
96
|
-
let streamCount = 0
|
|
97
|
-
|
|
98
|
-
connection.streams.forEach(stream => {
|
|
99
|
-
if (stream.direction === direction && stream.protocol === protocol) {
|
|
100
|
-
streamCount++
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
return streamCount
|
|
64
|
+
/**
|
|
65
|
+
* How long to wait before closing a connection
|
|
66
|
+
*
|
|
67
|
+
* @default 1_000
|
|
68
|
+
*/
|
|
69
|
+
connectionCloseTimeout?: number
|
|
105
70
|
}
|
|
106
71
|
|
|
107
72
|
export interface UpgraderComponents {
|
|
@@ -116,6 +81,10 @@ export interface UpgraderComponents {
|
|
|
116
81
|
logger: ComponentLogger
|
|
117
82
|
}
|
|
118
83
|
|
|
84
|
+
interface EncryptedConnection extends SecuredConnection {
|
|
85
|
+
protocol: string
|
|
86
|
+
}
|
|
87
|
+
|
|
119
88
|
type ConnectionDeniedType = keyof Pick<ConnectionGater, 'denyOutboundConnection' | 'denyInboundEncryptedConnection' | 'denyOutboundEncryptedConnection' | 'denyInboundUpgradedConnection' | 'denyOutboundUpgradedConnection'>
|
|
120
89
|
|
|
121
90
|
export class Upgrader implements UpgraderInterface {
|
|
@@ -133,6 +102,8 @@ export class Upgrader implements UpgraderInterface {
|
|
|
133
102
|
outboundErrors?: CounterGroup
|
|
134
103
|
}
|
|
135
104
|
|
|
105
|
+
private readonly connectionCloseTimeout?: number
|
|
106
|
+
|
|
136
107
|
constructor (components: UpgraderComponents, init: UpgraderInit) {
|
|
137
108
|
this.components = components
|
|
138
109
|
this.connectionEncrypters = trackedMap({
|
|
@@ -156,6 +127,7 @@ export class Upgrader implements UpgraderInterface {
|
|
|
156
127
|
this.inboundUpgradeTimeout = init.inboundUpgradeTimeout ?? INBOUND_UPGRADE_TIMEOUT
|
|
157
128
|
this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
|
|
158
129
|
this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
|
|
130
|
+
this.connectionCloseTimeout = init.connectionCloseTimeout ?? CONNECTION_CLOSE_TIMEOUT
|
|
159
131
|
this.events = components.events
|
|
160
132
|
this.metrics = {
|
|
161
133
|
dials: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_total'),
|
|
@@ -196,7 +168,9 @@ export class Upgrader implements UpgraderInterface {
|
|
|
196
168
|
/**
|
|
197
169
|
* Upgrades an inbound connection
|
|
198
170
|
*/
|
|
199
|
-
async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<void>
|
|
171
|
+
async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<void>
|
|
172
|
+
async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise<void>
|
|
173
|
+
async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<void> {
|
|
200
174
|
let accepted = false
|
|
201
175
|
|
|
202
176
|
// always apply upgrade timeout for incoming upgrades
|
|
@@ -207,7 +181,7 @@ export class Upgrader implements UpgraderInterface {
|
|
|
207
181
|
inbound: true
|
|
208
182
|
})
|
|
209
183
|
|
|
210
|
-
accepted =
|
|
184
|
+
accepted = this.components.connectionManager.acceptIncomingConnection(maConn)
|
|
211
185
|
|
|
212
186
|
if (!accepted) {
|
|
213
187
|
throw new ConnectionDeniedError('Connection denied')
|
|
@@ -240,7 +214,9 @@ export class Upgrader implements UpgraderInterface {
|
|
|
240
214
|
/**
|
|
241
215
|
* Upgrades an outbound connection
|
|
242
216
|
*/
|
|
243
|
-
async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<Connection>
|
|
217
|
+
async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<Connection>
|
|
218
|
+
async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise<Connection>
|
|
219
|
+
async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<Connection> {
|
|
244
220
|
try {
|
|
245
221
|
this.metrics.dials?.increment({
|
|
246
222
|
outbound: true
|
|
@@ -274,62 +250,64 @@ export class Upgrader implements UpgraderInterface {
|
|
|
274
250
|
}
|
|
275
251
|
}
|
|
276
252
|
|
|
277
|
-
private async _performUpgrade (maConn: MultiaddrConnection, direction: 'inbound' | 'outbound', opts: UpgraderOptions): Promise<Connection> {
|
|
278
|
-
let
|
|
253
|
+
private async _performUpgrade (maConn: MultiaddrConnection, direction: 'inbound' | 'outbound', opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<Connection> {
|
|
254
|
+
let stream: MessageStream = maConn
|
|
279
255
|
let remotePeer: PeerId
|
|
280
|
-
let upgradedConn: MultiaddrConnection
|
|
281
256
|
let muxerFactory: StreamMuxerFactory | undefined
|
|
257
|
+
let muxer: StreamMuxer | undefined
|
|
282
258
|
let cryptoProtocol
|
|
283
259
|
|
|
260
|
+
const id = `${(parseInt(String(Math.random() * 1e9))).toString(36)}${Date.now()}`
|
|
261
|
+
maConn.log = maConn.log.newScope(`${direction}:${id}`)
|
|
262
|
+
|
|
284
263
|
this.components.metrics?.trackMultiaddrConnection(maConn)
|
|
285
264
|
|
|
286
265
|
maConn.log.trace('starting the %s connection upgrade', direction)
|
|
287
266
|
|
|
288
267
|
// Protect
|
|
289
|
-
let protectedConn = maConn
|
|
290
|
-
|
|
291
268
|
if (opts?.skipProtection !== true) {
|
|
292
269
|
const protector = this.components.connectionProtector
|
|
293
270
|
|
|
294
271
|
if (protector != null) {
|
|
295
272
|
maConn.log('protecting the %s connection', direction)
|
|
296
|
-
|
|
273
|
+
stream = await protector.protect(stream, opts)
|
|
297
274
|
}
|
|
298
275
|
}
|
|
299
276
|
|
|
300
277
|
try {
|
|
301
278
|
// Encrypt the connection
|
|
302
|
-
|
|
303
|
-
|
|
279
|
+
if (isEncryptionSkipped(opts)) {
|
|
280
|
+
if (opts.remotePeer == null) {
|
|
281
|
+
throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
cryptoProtocol = 'native'
|
|
285
|
+
remotePeer = opts.remotePeer
|
|
286
|
+
} else {
|
|
287
|
+
const peerIdString = maConn.remoteAddr.getPeerId()
|
|
288
|
+
let remotePeerFromMultiaddr: PeerId | undefined
|
|
289
|
+
|
|
290
|
+
if (peerIdString != null) {
|
|
291
|
+
remotePeerFromMultiaddr = peerIdFromString(peerIdString)
|
|
292
|
+
}
|
|
293
|
+
|
|
304
294
|
opts?.onProgress?.(new CustomProgressEvent(`upgrader:encrypt-${direction}-connection`));
|
|
305
295
|
|
|
306
296
|
({
|
|
307
|
-
|
|
297
|
+
connection: stream,
|
|
308
298
|
remotePeer,
|
|
309
299
|
protocol: cryptoProtocol,
|
|
310
300
|
streamMuxer: muxerFactory
|
|
311
301
|
} = await (direction === 'inbound'
|
|
312
|
-
? this._encryptInbound(
|
|
313
|
-
|
|
302
|
+
? this._encryptInbound(stream, {
|
|
303
|
+
...opts,
|
|
304
|
+
remotePeer: remotePeerFromMultiaddr
|
|
305
|
+
})
|
|
306
|
+
: this._encryptOutbound(stream, {
|
|
307
|
+
...opts,
|
|
308
|
+
remotePeer: remotePeerFromMultiaddr
|
|
309
|
+
})
|
|
314
310
|
))
|
|
315
|
-
|
|
316
|
-
const maConn: MultiaddrConnection = {
|
|
317
|
-
...protectedConn,
|
|
318
|
-
...encryptedConn
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn)
|
|
322
|
-
} else {
|
|
323
|
-
const idStr = maConn.remoteAddr.getPeerId()
|
|
324
|
-
|
|
325
|
-
if (idStr == null) {
|
|
326
|
-
throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const remotePeerId = peerIdFromString(idStr)
|
|
330
|
-
|
|
331
|
-
cryptoProtocol = 'native'
|
|
332
|
-
remotePeer = remotePeerId
|
|
333
311
|
}
|
|
334
312
|
|
|
335
313
|
// this can happen if we dial a multiaddr without a peer id, we only find
|
|
@@ -340,353 +318,98 @@ export class Upgrader implements UpgraderInterface {
|
|
|
340
318
|
throw err
|
|
341
319
|
}
|
|
342
320
|
|
|
343
|
-
|
|
321
|
+
// stream.pause()
|
|
322
|
+
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn)
|
|
323
|
+
// stream.resume()
|
|
324
|
+
|
|
344
325
|
if (opts?.muxerFactory != null) {
|
|
345
326
|
muxerFactory = opts.muxerFactory
|
|
346
327
|
} else if (muxerFactory == null && this.streamMuxers.size > 0) {
|
|
347
328
|
opts?.onProgress?.(new CustomProgressEvent(`upgrader:multiplex-${direction}-connection`))
|
|
348
329
|
|
|
349
330
|
// Multiplex the connection
|
|
350
|
-
|
|
351
|
-
? this._multiplexInbound(
|
|
352
|
-
|
|
353
|
-
...encryptedConn
|
|
354
|
-
}, this.streamMuxers, opts)
|
|
355
|
-
: this._multiplexOutbound({
|
|
356
|
-
...protectedConn,
|
|
357
|
-
...encryptedConn
|
|
358
|
-
}, this.streamMuxers, opts))
|
|
359
|
-
muxerFactory = multiplexed.muxerFactory
|
|
360
|
-
upgradedConn = multiplexed.stream
|
|
331
|
+
muxerFactory = await (direction === 'inbound'
|
|
332
|
+
? this._multiplexInbound(stream, this.streamMuxers, opts)
|
|
333
|
+
: this._multiplexOutbound(stream, this.streamMuxers, opts))
|
|
361
334
|
}
|
|
362
335
|
} catch (err: any) {
|
|
363
|
-
maConn.log.error('failed to upgrade
|
|
336
|
+
maConn.log.error('failed to upgrade %s connection %s %a - %e', direction, direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err)
|
|
364
337
|
throw err
|
|
365
338
|
}
|
|
366
339
|
|
|
367
|
-
|
|
340
|
+
// create the connection muxer if one is configured
|
|
341
|
+
if (muxerFactory != null) {
|
|
342
|
+
maConn.log('create muxer %s', muxerFactory.protocol)
|
|
343
|
+
muxer = muxerFactory.createStreamMuxer(stream)
|
|
344
|
+
}
|
|
368
345
|
|
|
369
|
-
|
|
346
|
+
// stream.pause()
|
|
347
|
+
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn)
|
|
370
348
|
|
|
371
|
-
|
|
349
|
+
const conn = this._createConnection({
|
|
350
|
+
id,
|
|
372
351
|
cryptoProtocol,
|
|
373
352
|
direction,
|
|
374
353
|
maConn,
|
|
375
|
-
|
|
376
|
-
|
|
354
|
+
stream,
|
|
355
|
+
muxer,
|
|
377
356
|
remotePeer,
|
|
378
|
-
limits: opts?.limits
|
|
357
|
+
limits: opts?.limits,
|
|
358
|
+
closeTimeout: this.connectionCloseTimeout
|
|
379
359
|
})
|
|
360
|
+
|
|
361
|
+
conn.log('successfully upgraded connection')
|
|
362
|
+
|
|
363
|
+
// stream.resume()
|
|
364
|
+
|
|
365
|
+
return conn
|
|
380
366
|
}
|
|
381
367
|
|
|
382
368
|
/**
|
|
383
369
|
* A convenience method for generating a new `Connection`
|
|
384
370
|
*/
|
|
385
371
|
_createConnection (opts: CreateConnectionOptions): Connection {
|
|
386
|
-
const {
|
|
387
|
-
cryptoProtocol,
|
|
388
|
-
direction,
|
|
389
|
-
maConn,
|
|
390
|
-
upgradedConn,
|
|
391
|
-
remotePeer,
|
|
392
|
-
muxerFactory,
|
|
393
|
-
limits
|
|
394
|
-
} = opts
|
|
395
|
-
|
|
396
|
-
let muxer: StreamMuxer | undefined
|
|
397
|
-
let newStream: ((multicodecs: string[], options?: AbortOptions) => Promise<Stream>) | undefined
|
|
398
|
-
let connection: Connection // eslint-disable-line prefer-const
|
|
399
|
-
|
|
400
|
-
if (muxerFactory != null) {
|
|
401
|
-
// Create the muxer
|
|
402
|
-
muxer = muxerFactory.createStreamMuxer({
|
|
403
|
-
direction,
|
|
404
|
-
// Run anytime a remote stream is created
|
|
405
|
-
onIncomingStream: muxedStream => {
|
|
406
|
-
if (connection == null) {
|
|
407
|
-
return
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout)
|
|
411
|
-
setMaxListeners(Infinity, signal)
|
|
412
|
-
|
|
413
|
-
void Promise.resolve()
|
|
414
|
-
.then(async () => {
|
|
415
|
-
const protocols = this.components.registrar.getProtocols()
|
|
416
|
-
|
|
417
|
-
const { stream, protocol } = await mss.handle(muxedStream, protocols, {
|
|
418
|
-
signal,
|
|
419
|
-
log: muxedStream.log,
|
|
420
|
-
yieldBytes: false
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
if (connection == null) {
|
|
424
|
-
return
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
connection.log('incoming stream opened on %s', protocol)
|
|
428
|
-
|
|
429
|
-
const incomingLimit = findIncomingStreamLimit(protocol, this.components.registrar)
|
|
430
|
-
const streamCount = countStreams(protocol, 'inbound', connection)
|
|
431
|
-
|
|
432
|
-
if (streamCount === incomingLimit) {
|
|
433
|
-
const err = new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${protocol}" - limit ${incomingLimit}`)
|
|
434
|
-
muxedStream.abort(err)
|
|
435
|
-
|
|
436
|
-
throw err
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// after the handshake the returned stream can have early data so override
|
|
440
|
-
// the source/sink
|
|
441
|
-
muxedStream.source = stream.source
|
|
442
|
-
muxedStream.sink = stream.sink
|
|
443
|
-
muxedStream.protocol = protocol
|
|
444
|
-
|
|
445
|
-
// allow closing the write end of a not-yet-negotiated stream
|
|
446
|
-
if (stream.closeWrite != null) {
|
|
447
|
-
muxedStream.closeWrite = stream.closeWrite
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// allow closing the read end of a not-yet-negotiated stream
|
|
451
|
-
if (stream.closeRead != null) {
|
|
452
|
-
muxedStream.closeRead = stream.closeRead
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
// make sure we don't try to negotiate a stream we are closing
|
|
456
|
-
if (stream.close != null) {
|
|
457
|
-
muxedStream.close = stream.close
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
461
|
-
// the peer store should ensure that the peer is registered with that protocol
|
|
462
|
-
await this.components.peerStore.merge(remotePeer, {
|
|
463
|
-
protocols: [protocol]
|
|
464
|
-
}, {
|
|
465
|
-
signal
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
this.components.metrics?.trackProtocolStream(muxedStream, connection)
|
|
469
|
-
|
|
470
|
-
this._onStream({ connection, stream: muxedStream, protocol })
|
|
471
|
-
})
|
|
472
|
-
.catch(async err => {
|
|
473
|
-
connection.log.error('error handling incoming stream id %s - %e', muxedStream.id, err)
|
|
474
|
-
|
|
475
|
-
if (muxedStream.timeline.close == null) {
|
|
476
|
-
await muxedStream.close({
|
|
477
|
-
signal
|
|
478
|
-
})
|
|
479
|
-
.catch(err => muxedStream.abort(err))
|
|
480
|
-
}
|
|
481
|
-
})
|
|
482
|
-
}
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
newStream = async (protocols: string[], options: NewStreamOptions = {}): Promise<Stream> => {
|
|
486
|
-
if (muxer == null) {
|
|
487
|
-
throw new MuxerUnavailableError('Connection is not multiplexed')
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
connection.log.trace('starting new stream for protocols %s', protocols)
|
|
491
|
-
const muxedStream = await muxer.newStream()
|
|
492
|
-
connection.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols)
|
|
493
|
-
|
|
494
|
-
try {
|
|
495
|
-
if (options.signal == null) {
|
|
496
|
-
muxedStream.log('no abort signal was passed while trying to negotiate protocols %s falling back to default timeout', protocols)
|
|
497
|
-
|
|
498
|
-
const signal = AbortSignal.timeout(this.outboundStreamProtocolNegotiationTimeout)
|
|
499
|
-
setMaxListeners(Infinity, signal)
|
|
500
|
-
|
|
501
|
-
options = {
|
|
502
|
-
...options,
|
|
503
|
-
signal
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
muxedStream.log.trace('selecting protocol from protocols %s', protocols)
|
|
508
|
-
|
|
509
|
-
const {
|
|
510
|
-
stream,
|
|
511
|
-
protocol
|
|
512
|
-
} = await mss.select(muxedStream, protocols, {
|
|
513
|
-
...options,
|
|
514
|
-
log: muxedStream.log,
|
|
515
|
-
yieldBytes: true
|
|
516
|
-
})
|
|
517
|
-
|
|
518
|
-
muxedStream.log.trace('selected protocol %s', protocol)
|
|
519
|
-
|
|
520
|
-
const outgoingLimit = findOutgoingStreamLimit(protocol, this.components.registrar, options)
|
|
521
|
-
const streamCount = countStreams(protocol, 'outbound', connection)
|
|
522
|
-
|
|
523
|
-
if (streamCount >= outgoingLimit) {
|
|
524
|
-
const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${protocol}" - ${streamCount}/${outgoingLimit}`)
|
|
525
|
-
muxedStream.abort(err)
|
|
526
|
-
|
|
527
|
-
throw err
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
531
|
-
// the peer store should ensure that the peer is registered with that protocol
|
|
532
|
-
await this.components.peerStore.merge(remotePeer, {
|
|
533
|
-
protocols: [protocol]
|
|
534
|
-
})
|
|
535
|
-
|
|
536
|
-
// after the handshake the returned stream can have early data so override
|
|
537
|
-
// the source/sink
|
|
538
|
-
muxedStream.source = stream.source
|
|
539
|
-
muxedStream.sink = stream.sink
|
|
540
|
-
muxedStream.protocol = protocol
|
|
541
|
-
|
|
542
|
-
// allow closing the write end of a not-yet-negotiated stream
|
|
543
|
-
if (stream.closeWrite != null) {
|
|
544
|
-
muxedStream.closeWrite = stream.closeWrite
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// allow closing the read end of a not-yet-negotiated stream
|
|
548
|
-
if (stream.closeRead != null) {
|
|
549
|
-
muxedStream.closeRead = stream.closeRead
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// make sure we don't try to negotiate a stream we are closing
|
|
553
|
-
if (stream.close != null) {
|
|
554
|
-
muxedStream.close = stream.close
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
this.components.metrics?.trackProtocolStream(muxedStream, connection)
|
|
558
|
-
|
|
559
|
-
return muxedStream
|
|
560
|
-
} catch (err: any) {
|
|
561
|
-
connection.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', direction === 'inbound' ? 'from' : 'to', opts.maConn.remoteAddr, protocols, err)
|
|
562
|
-
|
|
563
|
-
if (muxedStream.timeline.close == null) {
|
|
564
|
-
muxedStream.abort(err)
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
throw err
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
// Pipe all data through the muxer
|
|
572
|
-
void Promise.all([
|
|
573
|
-
muxer.sink(upgradedConn.source),
|
|
574
|
-
upgradedConn.sink(muxer.source)
|
|
575
|
-
]).catch(err => {
|
|
576
|
-
connection.log.error('error piping data through muxer - %e', err)
|
|
577
|
-
})
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
const _timeline = maConn.timeline
|
|
581
|
-
maConn.timeline = new Proxy(_timeline, {
|
|
582
|
-
set: (...args) => {
|
|
583
|
-
if (args[1] === 'close' && args[2] != null && _timeline.close == null) {
|
|
584
|
-
// Wait for close to finish before notifying of the closure
|
|
585
|
-
(async () => {
|
|
586
|
-
try {
|
|
587
|
-
if (connection.status === 'open') {
|
|
588
|
-
await connection.close()
|
|
589
|
-
}
|
|
590
|
-
} catch (err: any) {
|
|
591
|
-
connection.log.error('error closing connection after timeline close %e', err)
|
|
592
|
-
} finally {
|
|
593
|
-
this.events.safeDispatchEvent('connection:close', {
|
|
594
|
-
detail: connection
|
|
595
|
-
})
|
|
596
|
-
}
|
|
597
|
-
})().catch(err => {
|
|
598
|
-
connection.log.error('error thrown while dispatching connection:close event %e', err)
|
|
599
|
-
})
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
return Reflect.set(...args)
|
|
603
|
-
}
|
|
604
|
-
})
|
|
605
|
-
maConn.timeline.upgraded = Date.now()
|
|
606
|
-
|
|
607
|
-
const errConnectionNotMultiplexed = (): any => {
|
|
608
|
-
throw new MuxerUnavailableError('Connection is not multiplexed')
|
|
609
|
-
}
|
|
610
|
-
|
|
611
372
|
// Create the connection
|
|
612
|
-
connection = createConnection({
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
timeline: maConn.timeline,
|
|
618
|
-
multiplexer: muxer?.protocol,
|
|
619
|
-
encryption: cryptoProtocol,
|
|
620
|
-
limits,
|
|
621
|
-
logger: this.components.logger,
|
|
622
|
-
newStream: newStream ?? errConnectionNotMultiplexed,
|
|
623
|
-
getStreams: () => {
|
|
624
|
-
return muxer?.streams ?? []
|
|
625
|
-
},
|
|
626
|
-
close: async (options?: AbortOptions) => {
|
|
627
|
-
// ensure remaining streams are closed gracefully
|
|
628
|
-
await muxer?.close(options)
|
|
629
|
-
|
|
630
|
-
// close the underlying transport
|
|
631
|
-
await maConn.close(options)
|
|
632
|
-
},
|
|
633
|
-
abort: (err) => {
|
|
634
|
-
maConn.abort(err)
|
|
373
|
+
const connection = createConnection(this.components, {
|
|
374
|
+
...opts,
|
|
375
|
+
outboundStreamProtocolNegotiationTimeout: this.outboundStreamProtocolNegotiationTimeout,
|
|
376
|
+
inboundStreamProtocolNegotiationTimeout: this.inboundStreamProtocolNegotiationTimeout
|
|
377
|
+
})
|
|
635
378
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
379
|
+
connection.addEventListener('close', () => {
|
|
380
|
+
this.events.safeDispatchEvent('connection:close', {
|
|
381
|
+
detail: connection
|
|
382
|
+
})
|
|
639
383
|
})
|
|
640
384
|
|
|
641
385
|
this.events.safeDispatchEvent('connection:open', {
|
|
642
386
|
detail: connection
|
|
643
387
|
})
|
|
644
388
|
|
|
645
|
-
// @ts-expect-error nah
|
|
646
|
-
connection.__maConnTimeline = _timeline
|
|
647
|
-
|
|
648
389
|
return connection
|
|
649
390
|
}
|
|
650
391
|
|
|
651
|
-
/**
|
|
652
|
-
* Routes incoming streams to the correct handler
|
|
653
|
-
*/
|
|
654
|
-
_onStream (opts: OnStreamOptions): void {
|
|
655
|
-
const { connection, stream, protocol } = opts
|
|
656
|
-
const { handler, options } = this.components.registrar.getHandler(protocol)
|
|
657
|
-
|
|
658
|
-
if (connection.limits != null && options.runOnLimitedConnection !== true) {
|
|
659
|
-
throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
handler({ connection, stream })
|
|
663
|
-
}
|
|
664
|
-
|
|
665
392
|
/**
|
|
666
393
|
* Attempts to encrypt the incoming `connection` with the provided `cryptos`
|
|
667
394
|
*/
|
|
668
|
-
async _encryptInbound (connection:
|
|
395
|
+
async _encryptInbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<EncryptedConnection> {
|
|
669
396
|
const protocols = Array.from(this.connectionEncrypters.keys())
|
|
670
397
|
|
|
671
398
|
try {
|
|
672
|
-
const
|
|
673
|
-
...options,
|
|
674
|
-
log: connection.log
|
|
675
|
-
})
|
|
399
|
+
const protocol = await mss.handle(connection, protocols, options)
|
|
676
400
|
const encrypter = this.connectionEncrypters.get(protocol)
|
|
677
401
|
|
|
678
402
|
if (encrypter == null) {
|
|
679
403
|
throw new EncryptionFailedError(`no crypto module found for ${protocol}`)
|
|
680
404
|
}
|
|
681
405
|
|
|
682
|
-
connection.log('encrypting inbound connection
|
|
406
|
+
connection.log('encrypting inbound connection using %s', protocol)
|
|
683
407
|
|
|
684
408
|
return {
|
|
685
|
-
...await encrypter.secureInbound(
|
|
409
|
+
...await encrypter.secureInbound(connection, options),
|
|
686
410
|
protocol
|
|
687
411
|
}
|
|
688
412
|
} catch (err: any) {
|
|
689
|
-
connection.log.error('encrypting inbound connection from %a failed', connection.remoteAddr, err)
|
|
690
413
|
throw new EncryptionFailedError(err.message)
|
|
691
414
|
}
|
|
692
415
|
}
|
|
@@ -695,31 +418,26 @@ export class Upgrader implements UpgraderInterface {
|
|
|
695
418
|
* Attempts to encrypt the given `connection` with the provided connection encrypters.
|
|
696
419
|
* The first `ConnectionEncrypter` module to succeed will be used
|
|
697
420
|
*/
|
|
698
|
-
async _encryptOutbound (connection:
|
|
421
|
+
async _encryptOutbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<EncryptedConnection> {
|
|
699
422
|
const protocols = Array.from(this.connectionEncrypters.keys())
|
|
700
423
|
|
|
701
424
|
try {
|
|
702
425
|
connection.log.trace('selecting encrypter from %s', protocols)
|
|
703
426
|
|
|
704
|
-
const
|
|
705
|
-
...options,
|
|
706
|
-
log: connection.log,
|
|
707
|
-
yieldBytes: true
|
|
708
|
-
})
|
|
427
|
+
const protocol = await mss.select(connection, protocols, options)
|
|
709
428
|
const encrypter = this.connectionEncrypters.get(protocol)
|
|
710
429
|
|
|
711
430
|
if (encrypter == null) {
|
|
712
431
|
throw new EncryptionFailedError(`no crypto module found for ${protocol}`)
|
|
713
432
|
}
|
|
714
433
|
|
|
715
|
-
connection.log('encrypting outbound connection
|
|
434
|
+
connection.log('encrypting outbound connection using %s', protocol)
|
|
716
435
|
|
|
717
436
|
return {
|
|
718
|
-
...await encrypter.secureOutbound(
|
|
437
|
+
...await encrypter.secureOutbound(connection, options),
|
|
719
438
|
protocol
|
|
720
439
|
}
|
|
721
440
|
} catch (err: any) {
|
|
722
|
-
connection.log.error('encrypting outbound connection to %a failed', connection.remoteAddr, err)
|
|
723
441
|
throw new EncryptionFailedError(err.message)
|
|
724
442
|
}
|
|
725
443
|
}
|
|
@@ -728,27 +446,23 @@ export class Upgrader implements UpgraderInterface {
|
|
|
728
446
|
* Selects one of the given muxers via multistream-select. That
|
|
729
447
|
* muxer will be used for all future streams on the connection.
|
|
730
448
|
*/
|
|
731
|
-
async _multiplexOutbound (
|
|
449
|
+
async _multiplexOutbound (maConn: MessageStream, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<StreamMuxerFactory> {
|
|
732
450
|
const protocols = Array.from(muxers.keys())
|
|
733
|
-
|
|
734
|
-
try {
|
|
735
|
-
connection.log.trace('selecting stream muxer from %s', protocols)
|
|
451
|
+
maConn.log('outbound selecting muxer %s', protocols)
|
|
736
452
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
} = await mss.select(connection, protocols, {
|
|
741
|
-
...options,
|
|
742
|
-
log: connection.log,
|
|
743
|
-
yieldBytes: true
|
|
744
|
-
})
|
|
745
|
-
|
|
746
|
-
connection.log('selected %s as muxer protocol', protocol)
|
|
453
|
+
try {
|
|
454
|
+
maConn.log.trace('selecting stream muxer from %s', protocols)
|
|
455
|
+
const protocol = await mss.select(maConn, protocols, options)
|
|
747
456
|
const muxerFactory = muxers.get(protocol)
|
|
748
457
|
|
|
749
|
-
|
|
458
|
+
if (muxerFactory == null) {
|
|
459
|
+
throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`)
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
maConn.log('selected %s as muxer protocol', protocol)
|
|
463
|
+
return muxerFactory
|
|
750
464
|
} catch (err: any) {
|
|
751
|
-
|
|
465
|
+
maConn.log.error('error multiplexing outbound connection', err)
|
|
752
466
|
throw new MuxerUnavailableError(String(err))
|
|
753
467
|
}
|
|
754
468
|
}
|
|
@@ -757,20 +471,23 @@ export class Upgrader implements UpgraderInterface {
|
|
|
757
471
|
* Registers support for one of the given muxers via multistream-select. The
|
|
758
472
|
* selected muxer will be used for all future streams on the connection.
|
|
759
473
|
*/
|
|
760
|
-
async _multiplexInbound (
|
|
474
|
+
async _multiplexInbound (maConn: MessageStream, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<StreamMuxerFactory> {
|
|
761
475
|
const protocols = Array.from(muxers.keys())
|
|
762
|
-
|
|
476
|
+
maConn.log('inbound handling muxers %s', protocols)
|
|
763
477
|
try {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
log: connection.log
|
|
767
|
-
})
|
|
478
|
+
maConn.log.trace('selecting stream muxer from %s', protocols)
|
|
479
|
+
const protocol = await mss.handle(maConn, protocols, options)
|
|
768
480
|
const muxerFactory = muxers.get(protocol)
|
|
769
481
|
|
|
770
|
-
|
|
482
|
+
if (muxerFactory == null) {
|
|
483
|
+
throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
maConn.log('selected %s as muxer protocol', protocol)
|
|
487
|
+
return muxerFactory
|
|
771
488
|
} catch (err: any) {
|
|
772
|
-
|
|
773
|
-
throw
|
|
489
|
+
maConn.log.error('error multiplexing inbound connection', err)
|
|
490
|
+
throw err
|
|
774
491
|
}
|
|
775
492
|
}
|
|
776
493
|
|
|
@@ -782,3 +499,7 @@ export class Upgrader implements UpgraderInterface {
|
|
|
782
499
|
return this.streamMuxers
|
|
783
500
|
}
|
|
784
501
|
}
|
|
502
|
+
|
|
503
|
+
function isEncryptionSkipped (opts?: any): opts is UpgraderWithoutEncryptionOptions {
|
|
504
|
+
return opts.skipEncryption === true
|
|
505
|
+
}
|