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/dist/src/upgrader.js
CHANGED
|
@@ -1,50 +1,14 @@
|
|
|
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 { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from './registrar.js';
|
|
13
|
-
function findIncomingStreamLimit(protocol, registrar) {
|
|
14
|
-
try {
|
|
15
|
-
const { options } = registrar.getHandler(protocol);
|
|
16
|
-
return options.maxInboundStreams;
|
|
17
|
-
}
|
|
18
|
-
catch (err) {
|
|
19
|
-
if (err.name !== 'UnhandledProtocolError') {
|
|
20
|
-
throw err;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return DEFAULT_MAX_INBOUND_STREAMS;
|
|
24
|
-
}
|
|
25
|
-
function findOutgoingStreamLimit(protocol, registrar, options = {}) {
|
|
26
|
-
try {
|
|
27
|
-
const { options } = registrar.getHandler(protocol);
|
|
28
|
-
if (options.maxOutboundStreams != null) {
|
|
29
|
-
return options.maxOutboundStreams;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
if (err.name !== 'UnhandledProtocolError') {
|
|
34
|
-
throw err;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return options.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS;
|
|
38
|
-
}
|
|
39
|
-
function countStreams(protocol, direction, connection) {
|
|
40
|
-
let streamCount = 0;
|
|
41
|
-
connection.streams.forEach(stream => {
|
|
42
|
-
if (stream.direction === direction && stream.protocol === protocol) {
|
|
43
|
-
streamCount++;
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
return streamCount;
|
|
47
|
-
}
|
|
48
12
|
export class Upgrader {
|
|
49
13
|
components;
|
|
50
14
|
connectionEncrypters;
|
|
@@ -54,6 +18,7 @@ export class Upgrader {
|
|
|
54
18
|
outboundStreamProtocolNegotiationTimeout;
|
|
55
19
|
events;
|
|
56
20
|
metrics;
|
|
21
|
+
connectionCloseTimeout;
|
|
57
22
|
constructor(components, init) {
|
|
58
23
|
this.components = components;
|
|
59
24
|
this.connectionEncrypters = trackedMap({
|
|
@@ -73,6 +38,7 @@ export class Upgrader {
|
|
|
73
38
|
this.inboundUpgradeTimeout = init.inboundUpgradeTimeout ?? INBOUND_UPGRADE_TIMEOUT;
|
|
74
39
|
this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT;
|
|
75
40
|
this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT;
|
|
41
|
+
this.connectionCloseTimeout = init.connectionCloseTimeout ?? CONNECTION_CLOSE_TIMEOUT;
|
|
76
42
|
this.events = components.events;
|
|
77
43
|
this.metrics = {
|
|
78
44
|
dials: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_total'),
|
|
@@ -100,9 +66,6 @@ export class Upgrader {
|
|
|
100
66
|
setMaxListeners(Infinity, output);
|
|
101
67
|
return output;
|
|
102
68
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Upgrades an inbound connection
|
|
105
|
-
*/
|
|
106
69
|
async upgradeInbound(maConn, opts) {
|
|
107
70
|
let accepted = false;
|
|
108
71
|
// always apply upgrade timeout for incoming upgrades
|
|
@@ -111,7 +74,7 @@ export class Upgrader {
|
|
|
111
74
|
this.metrics.dials?.increment({
|
|
112
75
|
inbound: true
|
|
113
76
|
});
|
|
114
|
-
accepted =
|
|
77
|
+
accepted = this.components.connectionManager.acceptIncomingConnection(maConn);
|
|
115
78
|
if (!accepted) {
|
|
116
79
|
throw new ConnectionDeniedError('Connection denied');
|
|
117
80
|
}
|
|
@@ -137,9 +100,6 @@ export class Upgrader {
|
|
|
137
100
|
}
|
|
138
101
|
}
|
|
139
102
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Upgrades an outbound connection
|
|
142
|
-
*/
|
|
143
103
|
async upgradeOutbound(maConn, opts) {
|
|
144
104
|
try {
|
|
145
105
|
this.metrics.dials?.increment({
|
|
@@ -169,49 +129,53 @@ export class Upgrader {
|
|
|
169
129
|
}
|
|
170
130
|
}
|
|
171
131
|
async _performUpgrade(maConn, direction, opts) {
|
|
172
|
-
let
|
|
132
|
+
let stream = maConn;
|
|
173
133
|
let remotePeer;
|
|
174
|
-
let upgradedConn;
|
|
175
134
|
let muxerFactory;
|
|
135
|
+
let muxer;
|
|
176
136
|
let cryptoProtocol;
|
|
137
|
+
const id = `${(parseInt(String(Math.random() * 1e9))).toString(36)}${Date.now()}`;
|
|
138
|
+
maConn.log = maConn.log.newScope(`${direction}:${id}`);
|
|
177
139
|
this.components.metrics?.trackMultiaddrConnection(maConn);
|
|
178
140
|
maConn.log.trace('starting the %s connection upgrade', direction);
|
|
179
141
|
// Protect
|
|
180
|
-
let protectedConn = maConn;
|
|
181
142
|
if (opts?.skipProtection !== true) {
|
|
182
143
|
const protector = this.components.connectionProtector;
|
|
183
144
|
if (protector != null) {
|
|
184
145
|
maConn.log('protecting the %s connection', direction);
|
|
185
|
-
|
|
146
|
+
stream = await protector.protect(stream, opts);
|
|
186
147
|
}
|
|
187
148
|
}
|
|
188
149
|
try {
|
|
189
150
|
// Encrypt the connection
|
|
190
|
-
|
|
191
|
-
|
|
151
|
+
if (isEncryptionSkipped(opts)) {
|
|
152
|
+
if (opts.remotePeer == null) {
|
|
153
|
+
throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`);
|
|
154
|
+
}
|
|
155
|
+
cryptoProtocol = 'native';
|
|
156
|
+
remotePeer = opts.remotePeer;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
const peerIdString = maConn.remoteAddr.getPeerId();
|
|
160
|
+
let remotePeerFromMultiaddr;
|
|
161
|
+
if (peerIdString != null) {
|
|
162
|
+
remotePeerFromMultiaddr = peerIdFromString(peerIdString);
|
|
163
|
+
}
|
|
192
164
|
opts?.onProgress?.(new CustomProgressEvent(`upgrader:encrypt-${direction}-connection`));
|
|
193
165
|
({
|
|
194
|
-
|
|
166
|
+
connection: stream,
|
|
195
167
|
remotePeer,
|
|
196
168
|
protocol: cryptoProtocol,
|
|
197
169
|
streamMuxer: muxerFactory
|
|
198
170
|
} = await (direction === 'inbound'
|
|
199
|
-
? this._encryptInbound(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
else {
|
|
208
|
-
const idStr = maConn.remoteAddr.getPeerId();
|
|
209
|
-
if (idStr == null) {
|
|
210
|
-
throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`);
|
|
211
|
-
}
|
|
212
|
-
const remotePeerId = peerIdFromString(idStr);
|
|
213
|
-
cryptoProtocol = 'native';
|
|
214
|
-
remotePeer = remotePeerId;
|
|
171
|
+
? this._encryptInbound(stream, {
|
|
172
|
+
...opts,
|
|
173
|
+
remotePeer: remotePeerFromMultiaddr
|
|
174
|
+
})
|
|
175
|
+
: this._encryptOutbound(stream, {
|
|
176
|
+
...opts,
|
|
177
|
+
remotePeer: remotePeerFromMultiaddr
|
|
178
|
+
})));
|
|
215
179
|
}
|
|
216
180
|
// this can happen if we dial a multiaddr without a peer id, we only find
|
|
217
181
|
// out the identity of the remote after the connection is encrypted
|
|
@@ -220,287 +184,84 @@ export class Upgrader {
|
|
|
220
184
|
maConn.abort(err);
|
|
221
185
|
throw err;
|
|
222
186
|
}
|
|
223
|
-
|
|
187
|
+
// stream.pause()
|
|
188
|
+
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn);
|
|
189
|
+
// stream.resume()
|
|
224
190
|
if (opts?.muxerFactory != null) {
|
|
225
191
|
muxerFactory = opts.muxerFactory;
|
|
226
192
|
}
|
|
227
193
|
else if (muxerFactory == null && this.streamMuxers.size > 0) {
|
|
228
194
|
opts?.onProgress?.(new CustomProgressEvent(`upgrader:multiplex-${direction}-connection`));
|
|
229
195
|
// Multiplex the connection
|
|
230
|
-
|
|
231
|
-
? this._multiplexInbound(
|
|
232
|
-
|
|
233
|
-
...encryptedConn
|
|
234
|
-
}, this.streamMuxers, opts)
|
|
235
|
-
: this._multiplexOutbound({
|
|
236
|
-
...protectedConn,
|
|
237
|
-
...encryptedConn
|
|
238
|
-
}, this.streamMuxers, opts));
|
|
239
|
-
muxerFactory = multiplexed.muxerFactory;
|
|
240
|
-
upgradedConn = multiplexed.stream;
|
|
196
|
+
muxerFactory = await (direction === 'inbound'
|
|
197
|
+
? this._multiplexInbound(stream, this.streamMuxers, opts)
|
|
198
|
+
: this._multiplexOutbound(stream, this.streamMuxers, opts));
|
|
241
199
|
}
|
|
242
200
|
}
|
|
243
201
|
catch (err) {
|
|
244
|
-
maConn.log.error('failed to upgrade
|
|
202
|
+
maConn.log.error('failed to upgrade %s connection %s %a - %e', direction, direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err);
|
|
245
203
|
throw err;
|
|
246
204
|
}
|
|
205
|
+
// create the connection muxer if one is configured
|
|
206
|
+
if (muxerFactory != null) {
|
|
207
|
+
maConn.log('create muxer %s', muxerFactory.protocol);
|
|
208
|
+
muxer = muxerFactory.createStreamMuxer(stream);
|
|
209
|
+
}
|
|
210
|
+
// stream.pause()
|
|
247
211
|
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn);
|
|
248
|
-
|
|
249
|
-
|
|
212
|
+
const conn = this._createConnection({
|
|
213
|
+
id,
|
|
250
214
|
cryptoProtocol,
|
|
251
215
|
direction,
|
|
252
216
|
maConn,
|
|
253
|
-
|
|
254
|
-
|
|
217
|
+
stream,
|
|
218
|
+
muxer,
|
|
255
219
|
remotePeer,
|
|
256
|
-
limits: opts?.limits
|
|
220
|
+
limits: opts?.limits,
|
|
221
|
+
closeTimeout: this.connectionCloseTimeout
|
|
257
222
|
});
|
|
223
|
+
conn.log('successfully upgraded connection');
|
|
224
|
+
// stream.resume()
|
|
225
|
+
return conn;
|
|
258
226
|
}
|
|
259
227
|
/**
|
|
260
228
|
* A convenience method for generating a new `Connection`
|
|
261
229
|
*/
|
|
262
230
|
_createConnection(opts) {
|
|
263
|
-
const { cryptoProtocol, direction, maConn, upgradedConn, remotePeer, muxerFactory, limits } = opts;
|
|
264
|
-
let muxer;
|
|
265
|
-
let newStream;
|
|
266
|
-
let connection; // eslint-disable-line prefer-const
|
|
267
|
-
if (muxerFactory != null) {
|
|
268
|
-
// Create the muxer
|
|
269
|
-
muxer = muxerFactory.createStreamMuxer({
|
|
270
|
-
direction,
|
|
271
|
-
// Run anytime a remote stream is created
|
|
272
|
-
onIncomingStream: muxedStream => {
|
|
273
|
-
if (connection == null) {
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout);
|
|
277
|
-
setMaxListeners(Infinity, signal);
|
|
278
|
-
void Promise.resolve()
|
|
279
|
-
.then(async () => {
|
|
280
|
-
const protocols = this.components.registrar.getProtocols();
|
|
281
|
-
const { stream, protocol } = await mss.handle(muxedStream, protocols, {
|
|
282
|
-
signal,
|
|
283
|
-
log: muxedStream.log,
|
|
284
|
-
yieldBytes: false
|
|
285
|
-
});
|
|
286
|
-
if (connection == null) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
connection.log('incoming stream opened on %s', protocol);
|
|
290
|
-
const incomingLimit = findIncomingStreamLimit(protocol, this.components.registrar);
|
|
291
|
-
const streamCount = countStreams(protocol, 'inbound', connection);
|
|
292
|
-
if (streamCount === incomingLimit) {
|
|
293
|
-
const err = new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${protocol}" - limit ${incomingLimit}`);
|
|
294
|
-
muxedStream.abort(err);
|
|
295
|
-
throw err;
|
|
296
|
-
}
|
|
297
|
-
// after the handshake the returned stream can have early data so override
|
|
298
|
-
// the source/sink
|
|
299
|
-
muxedStream.source = stream.source;
|
|
300
|
-
muxedStream.sink = stream.sink;
|
|
301
|
-
muxedStream.protocol = protocol;
|
|
302
|
-
// allow closing the write end of a not-yet-negotiated stream
|
|
303
|
-
if (stream.closeWrite != null) {
|
|
304
|
-
muxedStream.closeWrite = stream.closeWrite;
|
|
305
|
-
}
|
|
306
|
-
// allow closing the read end of a not-yet-negotiated stream
|
|
307
|
-
if (stream.closeRead != null) {
|
|
308
|
-
muxedStream.closeRead = stream.closeRead;
|
|
309
|
-
}
|
|
310
|
-
// make sure we don't try to negotiate a stream we are closing
|
|
311
|
-
if (stream.close != null) {
|
|
312
|
-
muxedStream.close = stream.close;
|
|
313
|
-
}
|
|
314
|
-
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
315
|
-
// the peer store should ensure that the peer is registered with that protocol
|
|
316
|
-
await this.components.peerStore.merge(remotePeer, {
|
|
317
|
-
protocols: [protocol]
|
|
318
|
-
}, {
|
|
319
|
-
signal
|
|
320
|
-
});
|
|
321
|
-
this.components.metrics?.trackProtocolStream(muxedStream, connection);
|
|
322
|
-
this._onStream({ connection, stream: muxedStream, protocol });
|
|
323
|
-
})
|
|
324
|
-
.catch(async (err) => {
|
|
325
|
-
connection.log.error('error handling incoming stream id %s - %e', muxedStream.id, err);
|
|
326
|
-
if (muxedStream.timeline.close == null) {
|
|
327
|
-
await muxedStream.close({
|
|
328
|
-
signal
|
|
329
|
-
})
|
|
330
|
-
.catch(err => muxedStream.abort(err));
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
newStream = async (protocols, options = {}) => {
|
|
336
|
-
if (muxer == null) {
|
|
337
|
-
throw new MuxerUnavailableError('Connection is not multiplexed');
|
|
338
|
-
}
|
|
339
|
-
connection.log.trace('starting new stream for protocols %s', protocols);
|
|
340
|
-
const muxedStream = await muxer.newStream();
|
|
341
|
-
connection.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols);
|
|
342
|
-
try {
|
|
343
|
-
if (options.signal == null) {
|
|
344
|
-
muxedStream.log('no abort signal was passed while trying to negotiate protocols %s falling back to default timeout', protocols);
|
|
345
|
-
const signal = AbortSignal.timeout(this.outboundStreamProtocolNegotiationTimeout);
|
|
346
|
-
setMaxListeners(Infinity, signal);
|
|
347
|
-
options = {
|
|
348
|
-
...options,
|
|
349
|
-
signal
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
muxedStream.log.trace('selecting protocol from protocols %s', protocols);
|
|
353
|
-
const { stream, protocol } = await mss.select(muxedStream, protocols, {
|
|
354
|
-
...options,
|
|
355
|
-
log: muxedStream.log,
|
|
356
|
-
yieldBytes: true
|
|
357
|
-
});
|
|
358
|
-
muxedStream.log.trace('selected protocol %s', protocol);
|
|
359
|
-
const outgoingLimit = findOutgoingStreamLimit(protocol, this.components.registrar, options);
|
|
360
|
-
const streamCount = countStreams(protocol, 'outbound', connection);
|
|
361
|
-
if (streamCount >= outgoingLimit) {
|
|
362
|
-
const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${protocol}" - ${streamCount}/${outgoingLimit}`);
|
|
363
|
-
muxedStream.abort(err);
|
|
364
|
-
throw err;
|
|
365
|
-
}
|
|
366
|
-
// If a protocol stream has been successfully negotiated and is to be passed to the application,
|
|
367
|
-
// the peer store should ensure that the peer is registered with that protocol
|
|
368
|
-
await this.components.peerStore.merge(remotePeer, {
|
|
369
|
-
protocols: [protocol]
|
|
370
|
-
});
|
|
371
|
-
// after the handshake the returned stream can have early data so override
|
|
372
|
-
// the source/sink
|
|
373
|
-
muxedStream.source = stream.source;
|
|
374
|
-
muxedStream.sink = stream.sink;
|
|
375
|
-
muxedStream.protocol = protocol;
|
|
376
|
-
// allow closing the write end of a not-yet-negotiated stream
|
|
377
|
-
if (stream.closeWrite != null) {
|
|
378
|
-
muxedStream.closeWrite = stream.closeWrite;
|
|
379
|
-
}
|
|
380
|
-
// allow closing the read end of a not-yet-negotiated stream
|
|
381
|
-
if (stream.closeRead != null) {
|
|
382
|
-
muxedStream.closeRead = stream.closeRead;
|
|
383
|
-
}
|
|
384
|
-
// make sure we don't try to negotiate a stream we are closing
|
|
385
|
-
if (stream.close != null) {
|
|
386
|
-
muxedStream.close = stream.close;
|
|
387
|
-
}
|
|
388
|
-
this.components.metrics?.trackProtocolStream(muxedStream, connection);
|
|
389
|
-
return muxedStream;
|
|
390
|
-
}
|
|
391
|
-
catch (err) {
|
|
392
|
-
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);
|
|
393
|
-
if (muxedStream.timeline.close == null) {
|
|
394
|
-
muxedStream.abort(err);
|
|
395
|
-
}
|
|
396
|
-
throw err;
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
// Pipe all data through the muxer
|
|
400
|
-
void Promise.all([
|
|
401
|
-
muxer.sink(upgradedConn.source),
|
|
402
|
-
upgradedConn.sink(muxer.source)
|
|
403
|
-
]).catch(err => {
|
|
404
|
-
connection.log.error('error piping data through muxer - %e', err);
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
const _timeline = maConn.timeline;
|
|
408
|
-
maConn.timeline = new Proxy(_timeline, {
|
|
409
|
-
set: (...args) => {
|
|
410
|
-
if (args[1] === 'close' && args[2] != null && _timeline.close == null) {
|
|
411
|
-
// Wait for close to finish before notifying of the closure
|
|
412
|
-
(async () => {
|
|
413
|
-
try {
|
|
414
|
-
if (connection.status === 'open') {
|
|
415
|
-
await connection.close();
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
catch (err) {
|
|
419
|
-
connection.log.error('error closing connection after timeline close %e', err);
|
|
420
|
-
}
|
|
421
|
-
finally {
|
|
422
|
-
this.events.safeDispatchEvent('connection:close', {
|
|
423
|
-
detail: connection
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
})().catch(err => {
|
|
427
|
-
connection.log.error('error thrown while dispatching connection:close event %e', err);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
return Reflect.set(...args);
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
maConn.timeline.upgraded = Date.now();
|
|
434
|
-
const errConnectionNotMultiplexed = () => {
|
|
435
|
-
throw new MuxerUnavailableError('Connection is not multiplexed');
|
|
436
|
-
};
|
|
437
231
|
// Create the connection
|
|
438
|
-
connection = createConnection({
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
logger: this.components.logger,
|
|
448
|
-
newStream: newStream ?? errConnectionNotMultiplexed,
|
|
449
|
-
getStreams: () => {
|
|
450
|
-
return muxer?.streams ?? [];
|
|
451
|
-
},
|
|
452
|
-
close: async (options) => {
|
|
453
|
-
// ensure remaining streams are closed gracefully
|
|
454
|
-
await muxer?.close(options);
|
|
455
|
-
// close the underlying transport
|
|
456
|
-
await maConn.close(options);
|
|
457
|
-
},
|
|
458
|
-
abort: (err) => {
|
|
459
|
-
maConn.abort(err);
|
|
460
|
-
// ensure remaining streams are aborted
|
|
461
|
-
muxer?.abort(err);
|
|
462
|
-
}
|
|
232
|
+
const connection = createConnection(this.components, {
|
|
233
|
+
...opts,
|
|
234
|
+
outboundStreamProtocolNegotiationTimeout: this.outboundStreamProtocolNegotiationTimeout,
|
|
235
|
+
inboundStreamProtocolNegotiationTimeout: this.inboundStreamProtocolNegotiationTimeout
|
|
236
|
+
});
|
|
237
|
+
connection.addEventListener('close', () => {
|
|
238
|
+
this.events.safeDispatchEvent('connection:close', {
|
|
239
|
+
detail: connection
|
|
240
|
+
});
|
|
463
241
|
});
|
|
464
242
|
this.events.safeDispatchEvent('connection:open', {
|
|
465
243
|
detail: connection
|
|
466
244
|
});
|
|
467
|
-
// @ts-expect-error nah
|
|
468
|
-
connection.__maConnTimeline = _timeline;
|
|
469
245
|
return connection;
|
|
470
246
|
}
|
|
471
|
-
/**
|
|
472
|
-
* Routes incoming streams to the correct handler
|
|
473
|
-
*/
|
|
474
|
-
_onStream(opts) {
|
|
475
|
-
const { connection, stream, protocol } = opts;
|
|
476
|
-
const { handler, options } = this.components.registrar.getHandler(protocol);
|
|
477
|
-
if (connection.limits != null && options.runOnLimitedConnection !== true) {
|
|
478
|
-
throw new LimitedConnectionError('Cannot open protocol stream on limited connection');
|
|
479
|
-
}
|
|
480
|
-
handler({ connection, stream });
|
|
481
|
-
}
|
|
482
247
|
/**
|
|
483
248
|
* Attempts to encrypt the incoming `connection` with the provided `cryptos`
|
|
484
249
|
*/
|
|
485
250
|
async _encryptInbound(connection, options) {
|
|
486
251
|
const protocols = Array.from(this.connectionEncrypters.keys());
|
|
487
252
|
try {
|
|
488
|
-
const
|
|
489
|
-
...options,
|
|
490
|
-
log: connection.log
|
|
491
|
-
});
|
|
253
|
+
const protocol = await mss.handle(connection, protocols, options);
|
|
492
254
|
const encrypter = this.connectionEncrypters.get(protocol);
|
|
493
255
|
if (encrypter == null) {
|
|
494
256
|
throw new EncryptionFailedError(`no crypto module found for ${protocol}`);
|
|
495
257
|
}
|
|
496
|
-
connection.log('encrypting inbound connection
|
|
258
|
+
connection.log('encrypting inbound connection using %s', protocol);
|
|
497
259
|
return {
|
|
498
|
-
...await encrypter.secureInbound(
|
|
260
|
+
...await encrypter.secureInbound(connection, options),
|
|
499
261
|
protocol
|
|
500
262
|
};
|
|
501
263
|
}
|
|
502
264
|
catch (err) {
|
|
503
|
-
connection.log.error('encrypting inbound connection from %a failed', connection.remoteAddr, err);
|
|
504
265
|
throw new EncryptionFailedError(err.message);
|
|
505
266
|
}
|
|
506
267
|
}
|
|
@@ -512,23 +273,18 @@ export class Upgrader {
|
|
|
512
273
|
const protocols = Array.from(this.connectionEncrypters.keys());
|
|
513
274
|
try {
|
|
514
275
|
connection.log.trace('selecting encrypter from %s', protocols);
|
|
515
|
-
const
|
|
516
|
-
...options,
|
|
517
|
-
log: connection.log,
|
|
518
|
-
yieldBytes: true
|
|
519
|
-
});
|
|
276
|
+
const protocol = await mss.select(connection, protocols, options);
|
|
520
277
|
const encrypter = this.connectionEncrypters.get(protocol);
|
|
521
278
|
if (encrypter == null) {
|
|
522
279
|
throw new EncryptionFailedError(`no crypto module found for ${protocol}`);
|
|
523
280
|
}
|
|
524
|
-
connection.log('encrypting outbound connection
|
|
281
|
+
connection.log('encrypting outbound connection using %s', protocol);
|
|
525
282
|
return {
|
|
526
|
-
...await encrypter.secureOutbound(
|
|
283
|
+
...await encrypter.secureOutbound(connection, options),
|
|
527
284
|
protocol
|
|
528
285
|
};
|
|
529
286
|
}
|
|
530
287
|
catch (err) {
|
|
531
|
-
connection.log.error('encrypting outbound connection to %a failed', connection.remoteAddr, err);
|
|
532
288
|
throw new EncryptionFailedError(err.message);
|
|
533
289
|
}
|
|
534
290
|
}
|
|
@@ -536,22 +292,21 @@ export class Upgrader {
|
|
|
536
292
|
* Selects one of the given muxers via multistream-select. That
|
|
537
293
|
* muxer will be used for all future streams on the connection.
|
|
538
294
|
*/
|
|
539
|
-
async _multiplexOutbound(
|
|
295
|
+
async _multiplexOutbound(maConn, muxers, options) {
|
|
540
296
|
const protocols = Array.from(muxers.keys());
|
|
541
|
-
|
|
297
|
+
maConn.log('outbound selecting muxer %s', protocols);
|
|
542
298
|
try {
|
|
543
|
-
|
|
544
|
-
const
|
|
545
|
-
...options,
|
|
546
|
-
log: connection.log,
|
|
547
|
-
yieldBytes: true
|
|
548
|
-
});
|
|
549
|
-
connection.log('selected %s as muxer protocol', protocol);
|
|
299
|
+
maConn.log.trace('selecting stream muxer from %s', protocols);
|
|
300
|
+
const protocol = await mss.select(maConn, protocols, options);
|
|
550
301
|
const muxerFactory = muxers.get(protocol);
|
|
551
|
-
|
|
302
|
+
if (muxerFactory == null) {
|
|
303
|
+
throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`);
|
|
304
|
+
}
|
|
305
|
+
maConn.log('selected %s as muxer protocol', protocol);
|
|
306
|
+
return muxerFactory;
|
|
552
307
|
}
|
|
553
308
|
catch (err) {
|
|
554
|
-
|
|
309
|
+
maConn.log.error('error multiplexing outbound connection', err);
|
|
555
310
|
throw new MuxerUnavailableError(String(err));
|
|
556
311
|
}
|
|
557
312
|
}
|
|
@@ -559,20 +314,22 @@ export class Upgrader {
|
|
|
559
314
|
* Registers support for one of the given muxers via multistream-select. The
|
|
560
315
|
* selected muxer will be used for all future streams on the connection.
|
|
561
316
|
*/
|
|
562
|
-
async _multiplexInbound(
|
|
317
|
+
async _multiplexInbound(maConn, muxers, options) {
|
|
563
318
|
const protocols = Array.from(muxers.keys());
|
|
564
|
-
|
|
319
|
+
maConn.log('inbound handling muxers %s', protocols);
|
|
565
320
|
try {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
log: connection.log
|
|
569
|
-
});
|
|
321
|
+
maConn.log.trace('selecting stream muxer from %s', protocols);
|
|
322
|
+
const protocol = await mss.handle(maConn, protocols, options);
|
|
570
323
|
const muxerFactory = muxers.get(protocol);
|
|
571
|
-
|
|
324
|
+
if (muxerFactory == null) {
|
|
325
|
+
throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`);
|
|
326
|
+
}
|
|
327
|
+
maConn.log('selected %s as muxer protocol', protocol);
|
|
328
|
+
return muxerFactory;
|
|
572
329
|
}
|
|
573
330
|
catch (err) {
|
|
574
|
-
|
|
575
|
-
throw
|
|
331
|
+
maConn.log.error('error multiplexing inbound connection', err);
|
|
332
|
+
throw err;
|
|
576
333
|
}
|
|
577
334
|
}
|
|
578
335
|
getConnectionEncrypters() {
|
|
@@ -582,4 +339,7 @@ export class Upgrader {
|
|
|
582
339
|
return this.streamMuxers;
|
|
583
340
|
}
|
|
584
341
|
}
|
|
342
|
+
function isEncryptionSkipped(opts) {
|
|
343
|
+
return opts.skipEncryption === true;
|
|
344
|
+
}
|
|
585
345
|
//# sourceMappingURL=upgrader.js.map
|