werift 0.22.8 → 0.23.0
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/lib/common/src/crc.d.ts +4 -0
- package/lib/common/src/crc.js +124 -0
- package/lib/common/src/crc.js.map +1 -0
- package/lib/common/src/index.d.ts +1 -0
- package/lib/common/src/index.js +1 -0
- package/lib/common/src/index.js.map +1 -1
- package/lib/dtls/src/flight/server/flight6.js +12 -2
- package/lib/dtls/src/flight/server/flight6.js.map +1 -1
- package/lib/dtls/src/server.js +6 -1
- package/lib/dtls/src/server.js.map +1 -1
- package/lib/dtls/src/socket.d.ts +1 -0
- package/lib/dtls/src/socket.js +3 -0
- package/lib/dtls/src/socket.js.map +1 -1
- package/lib/ice/src/stun/message.js +2 -10
- package/lib/ice/src/stun/message.js.map +1 -1
- package/lib/index.mjs +705 -113
- package/lib/nonstandard/index.mjs +308 -44
- package/lib/rtp/src/index.d.ts +1 -0
- package/lib/rtp/src/index.js +1 -0
- package/lib/rtp/src/index.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/ctr.d.ts +3 -3
- package/lib/rtp/src/srtp/cipher/ctr.js +25 -14
- package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/gcm.d.ts +3 -3
- package/lib/rtp/src/srtp/cipher/gcm.js +57 -20
- package/lib/rtp/src/srtp/cipher/gcm.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/index.d.ts +1 -1
- package/lib/rtp/src/srtp/cipher/index.js +1 -1
- package/lib/rtp/src/srtp/cipher/index.js.map +1 -1
- package/lib/rtp/src/srtp/context/srtp.d.ts +2 -1
- package/lib/rtp/src/srtp/context/srtp.js +22 -5
- package/lib/rtp/src/srtp/context/srtp.js.map +1 -1
- package/lib/rtp/src/srtp/error.d.ts +3 -0
- package/lib/rtp/src/srtp/error.js +11 -0
- package/lib/rtp/src/srtp/error.js.map +1 -0
- package/lib/rtp/src/srtp/packet.d.ts +5 -0
- package/lib/rtp/src/srtp/packet.js +48 -0
- package/lib/rtp/src/srtp/packet.js.map +1 -0
- package/lib/sctp/src/chunk.js +3 -6
- package/lib/sctp/src/chunk.js.map +1 -1
- package/lib/sctp/src/sctp.d.ts +19 -0
- package/lib/sctp/src/sctp.js +259 -23
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/dataChannel.d.ts +1 -0
- package/lib/webrtc/src/dataChannel.js +5 -2
- package/lib/webrtc/src/dataChannel.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +4 -1
- package/lib/webrtc/src/peerConnection.js +26 -5
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/sctpManager.d.ts +1 -1
- package/lib/webrtc/src/sctpManager.js +3 -2
- package/lib/webrtc/src/sctpManager.js.map +1 -1
- package/lib/webrtc/src/sdpManager.d.ts +1 -1
- package/lib/webrtc/src/sdpManager.js +3 -4
- package/lib/webrtc/src/sdpManager.js.map +1 -1
- package/lib/webrtc/src/secureTransportManager.js +1 -1
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transceiverManager.js +3 -2
- package/lib/webrtc/src/transceiverManager.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.d.ts +1 -0
- package/lib/webrtc/src/transport/dtls.js +117 -12
- package/lib/webrtc/src/transport/dtls.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.d.ts +9 -3
- package/lib/webrtc/src/transport/sctp.js +35 -9
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/lib/webrtc/src/utils.d.ts +2 -0
- package/lib/webrtc/src/utils.js +20 -0
- package/lib/webrtc/src/utils.js.map +1 -1
- package/package.json +1 -3
package/lib/index.mjs
CHANGED
|
@@ -229,6 +229,105 @@ var BitStream = class {
|
|
|
229
229
|
}
|
|
230
230
|
};
|
|
231
231
|
|
|
232
|
+
// ../common/src/crc.ts
|
|
233
|
+
var POLY_CRC32 = 3988292384;
|
|
234
|
+
var POLY_CRC32C = 2197175160;
|
|
235
|
+
function isBufferLike(input) {
|
|
236
|
+
return typeof input !== "string";
|
|
237
|
+
}
|
|
238
|
+
function generateCRCTable(polynomial) {
|
|
239
|
+
const table = new Array(256);
|
|
240
|
+
let c = 0;
|
|
241
|
+
for (let n = 0; n < 256; ++n) {
|
|
242
|
+
c = n;
|
|
243
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
244
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
245
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
246
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
247
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
248
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
249
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
250
|
+
c = c & 1 ? polynomial ^ c >>> 1 : c >>> 1;
|
|
251
|
+
table[n] = c;
|
|
252
|
+
}
|
|
253
|
+
return new Int32Array(table);
|
|
254
|
+
}
|
|
255
|
+
function generateSliceBy16Tables(table0) {
|
|
256
|
+
const table = new Int32Array(4096);
|
|
257
|
+
let c = 0;
|
|
258
|
+
let v = 0;
|
|
259
|
+
let n = 0;
|
|
260
|
+
for (n = 0; n < 256; ++n) table[n] = table0[n];
|
|
261
|
+
for (n = 0; n < 256; ++n) {
|
|
262
|
+
v = table0[n];
|
|
263
|
+
for (c = 256 + n; c < 4096; c += 256) {
|
|
264
|
+
v = table[c] = v >>> 8 ^ table0[v & 255];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const out = [];
|
|
268
|
+
for (n = 1; n < 16; ++n) {
|
|
269
|
+
out[n - 1] = table.subarray(n * 256, n * 256 + 256);
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
function crcGenericString(value, seed, table0) {
|
|
274
|
+
let crc = seed ^ -1;
|
|
275
|
+
let i = 0;
|
|
276
|
+
const len = value.length;
|
|
277
|
+
let c = 0;
|
|
278
|
+
let d = 0;
|
|
279
|
+
while (i < len) {
|
|
280
|
+
c = value.charCodeAt(i++);
|
|
281
|
+
if (c < 128) {
|
|
282
|
+
crc = crc >>> 8 ^ table0[(crc ^ c) & 255];
|
|
283
|
+
} else if (c < 2048) {
|
|
284
|
+
crc = crc >>> 8 ^ table0[(crc ^ (192 | c >> 6 & 31)) & 255];
|
|
285
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | c & 63)) & 255];
|
|
286
|
+
} else if (c >= 55296 && c < 57344) {
|
|
287
|
+
c = (c & 1023) + 64;
|
|
288
|
+
d = value.charCodeAt(i++) & 1023;
|
|
289
|
+
crc = crc >>> 8 ^ table0[(crc ^ (240 | c >> 8 & 7)) & 255];
|
|
290
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | c >> 2 & 63)) & 255];
|
|
291
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | d >> 6 & 15 | (c & 3) << 4)) & 255];
|
|
292
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | d & 63)) & 255];
|
|
293
|
+
} else {
|
|
294
|
+
crc = crc >>> 8 ^ table0[(crc ^ (224 | c >> 12 & 15)) & 255];
|
|
295
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | c >> 6 & 63)) & 255];
|
|
296
|
+
crc = crc >>> 8 ^ table0[(crc ^ (128 | c & 63)) & 255];
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return ~crc >>> 0;
|
|
300
|
+
}
|
|
301
|
+
function crcBuffer(value, seed, table0, tables16) {
|
|
302
|
+
const [t1, t2, t3, t4, t5, t6, t7, t8, t9, ta, tb, tc, td, te, tf] = tables16;
|
|
303
|
+
let crc = seed ^ -1;
|
|
304
|
+
let i = 0;
|
|
305
|
+
let len = value.length - 15;
|
|
306
|
+
while (i < len) {
|
|
307
|
+
crc = tf[value[i++] ^ crc & 255] ^ te[value[i++] ^ crc >>> 8 & 255] ^ td[value[i++] ^ crc >>> 16 & 255] ^ tc[value[i++] ^ crc >>> 24] ^ tb[value[i++]] ^ ta[value[i++]] ^ t9[value[i++]] ^ t8[value[i++]] ^ t7[value[i++]] ^ t6[value[i++]] ^ t5[value[i++]] ^ t4[value[i++]] ^ t3[value[i++]] ^ t2[value[i++]] ^ t1[value[i++]] ^ table0[value[i++]];
|
|
308
|
+
}
|
|
309
|
+
for (len += 15; i < len; ) {
|
|
310
|
+
crc = crc >>> 8 ^ table0[(crc ^ value[i++]) & 255];
|
|
311
|
+
}
|
|
312
|
+
return ~crc >>> 0;
|
|
313
|
+
}
|
|
314
|
+
var table32 = generateCRCTable(POLY_CRC32);
|
|
315
|
+
var tables32By16 = generateSliceBy16Tables(table32);
|
|
316
|
+
var table32c = generateCRCTable(POLY_CRC32C);
|
|
317
|
+
var tables32cBy16 = generateSliceBy16Tables(table32c);
|
|
318
|
+
function crc32(input, seed = 0) {
|
|
319
|
+
if (isBufferLike(input)) {
|
|
320
|
+
return crcBuffer(input, seed, table32, tables32By16);
|
|
321
|
+
}
|
|
322
|
+
return crcGenericString(input, seed, table32);
|
|
323
|
+
}
|
|
324
|
+
function crc32c(input, seed = 0) {
|
|
325
|
+
if (isBufferLike(input)) {
|
|
326
|
+
return crcBuffer(input, seed, table32c, tables32cBy16);
|
|
327
|
+
}
|
|
328
|
+
return crcGenericString(input, seed, table32c);
|
|
329
|
+
}
|
|
330
|
+
|
|
232
331
|
// ../common/src/number.ts
|
|
233
332
|
function uint8Add(a, b) {
|
|
234
333
|
return a + b & 255;
|
|
@@ -4547,7 +4646,12 @@ import { createHmac as createHmac3 } from "crypto";
|
|
|
4547
4646
|
import AES from "aes-js";
|
|
4548
4647
|
|
|
4549
4648
|
// ../rtp/src/srtp/cipher/ctr.ts
|
|
4550
|
-
import {
|
|
4649
|
+
import {
|
|
4650
|
+
createCipheriv as createCipheriv2,
|
|
4651
|
+
createDecipheriv as createDecipheriv2,
|
|
4652
|
+
createHmac as createHmac2,
|
|
4653
|
+
timingSafeEqual
|
|
4654
|
+
} from "crypto";
|
|
4551
4655
|
|
|
4552
4656
|
// ../rtp/src/srtp/cipher/index.ts
|
|
4553
4657
|
var CipherAesBase = class {
|
|
@@ -4560,7 +4664,7 @@ var CipherAesBase = class {
|
|
|
4560
4664
|
encryptRtp(header, payload, rolloverCounter) {
|
|
4561
4665
|
return Buffer.from([]);
|
|
4562
4666
|
}
|
|
4563
|
-
decryptRtp(cipherText, rolloverCounter) {
|
|
4667
|
+
decryptRtp(cipherText, rolloverCounter, header) {
|
|
4564
4668
|
return [];
|
|
4565
4669
|
}
|
|
4566
4670
|
encryptRTCP(rawRtcp, srtcpIndex) {
|
|
@@ -4571,6 +4675,74 @@ var CipherAesBase = class {
|
|
|
4571
4675
|
}
|
|
4572
4676
|
};
|
|
4573
4677
|
|
|
4678
|
+
// ../rtp/src/srtp/error.ts
|
|
4679
|
+
var SrtpAuthenticationError = class extends Error {
|
|
4680
|
+
constructor(message) {
|
|
4681
|
+
super(message);
|
|
4682
|
+
this.name = "SrtpAuthenticationError";
|
|
4683
|
+
}
|
|
4684
|
+
};
|
|
4685
|
+
|
|
4686
|
+
// ../rtp/src/srtp/packet.ts
|
|
4687
|
+
var minRtpHeaderSize = 12;
|
|
4688
|
+
var minRtcpPacketSize = 8;
|
|
4689
|
+
function parseSrtpRtpHeader(packet, authTagLength, message = "Failed to authenticate SRTP packet") {
|
|
4690
|
+
const authTagOffset = packet.length - authTagLength;
|
|
4691
|
+
assertAuthenticatedPacketLength(
|
|
4692
|
+
packet.length >= minRtpHeaderSize + authTagLength,
|
|
4693
|
+
message
|
|
4694
|
+
);
|
|
4695
|
+
const header = wrapAuthenticationError(
|
|
4696
|
+
() => RtpHeader.deSerialize(packet.subarray(0, authTagOffset)),
|
|
4697
|
+
message
|
|
4698
|
+
);
|
|
4699
|
+
header.paddingSize = 0;
|
|
4700
|
+
assertAuthenticatedPacketLength(
|
|
4701
|
+
header.payloadOffset >= minRtpHeaderSize && header.payloadOffset <= authTagOffset,
|
|
4702
|
+
message
|
|
4703
|
+
);
|
|
4704
|
+
return header;
|
|
4705
|
+
}
|
|
4706
|
+
function parseSrtcpHeader(packet, authTagLength, srtcpIndexSize3, message = "Failed to authenticate SRTCP packet") {
|
|
4707
|
+
assertAuthenticatedPacketLength(
|
|
4708
|
+
packet.length >= minRtcpPacketSize + authTagLength + srtcpIndexSize3,
|
|
4709
|
+
message
|
|
4710
|
+
);
|
|
4711
|
+
return wrapAuthenticationError(
|
|
4712
|
+
() => RtcpHeader.deSerialize(packet.subarray(0, RTCP_HEADER_SIZE)),
|
|
4713
|
+
message
|
|
4714
|
+
);
|
|
4715
|
+
}
|
|
4716
|
+
function assertAuthenticatedPacketLength(condition, message) {
|
|
4717
|
+
if (!condition) {
|
|
4718
|
+
throw new SrtpAuthenticationError(message);
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
function wrapAuthenticationError(parse, message) {
|
|
4722
|
+
try {
|
|
4723
|
+
return parse();
|
|
4724
|
+
} catch {
|
|
4725
|
+
throw new SrtpAuthenticationError(message);
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
function finalizeSrtpRtpHeader(header, packet, message = "Failed to authenticate SRTP packet") {
|
|
4729
|
+
if (!header.padding) {
|
|
4730
|
+
header.paddingSize = 0;
|
|
4731
|
+
return header;
|
|
4732
|
+
}
|
|
4733
|
+
assertAuthenticatedPacketLength(
|
|
4734
|
+
packet.length > header.payloadOffset,
|
|
4735
|
+
message
|
|
4736
|
+
);
|
|
4737
|
+
const paddingSize = packet[packet.length - 1];
|
|
4738
|
+
assertAuthenticatedPacketLength(
|
|
4739
|
+
paddingSize > 0 && paddingSize <= packet.length - header.payloadOffset,
|
|
4740
|
+
message
|
|
4741
|
+
);
|
|
4742
|
+
header.paddingSize = paddingSize;
|
|
4743
|
+
return header;
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4574
4746
|
// ../rtp/src/srtp/cipher/ctr.ts
|
|
4575
4747
|
var CipherAesCtr = class extends CipherAesBase {
|
|
4576
4748
|
constructor(srtpSessionKey, srtpSessionSalt, srtcpSessionKey, srtcpSessionSalt, srtpSessionAuthTag, srtcpSessionAuthTag) {
|
|
@@ -4596,10 +4768,20 @@ var CipherAesCtr = class extends CipherAesBase {
|
|
|
4596
4768
|
);
|
|
4597
4769
|
return Buffer.concat([headerBuffer, enc, authTag]);
|
|
4598
4770
|
}
|
|
4599
|
-
decryptRtp(cipherText, rolloverCounter) {
|
|
4600
|
-
const
|
|
4601
|
-
const
|
|
4602
|
-
|
|
4771
|
+
decryptRtp(cipherText, rolloverCounter, header = parseSrtpRtpHeader(cipherText, this.authTagLength)) {
|
|
4772
|
+
const authTagOffset = cipherText.length - this.authTagLength;
|
|
4773
|
+
const encryptedPacket = cipherText.subarray(0, authTagOffset);
|
|
4774
|
+
const actualAuthTag = cipherText.subarray(authTagOffset);
|
|
4775
|
+
const expectedAuthTag = this.generateSrtpAuthTag(
|
|
4776
|
+
rolloverCounter,
|
|
4777
|
+
encryptedPacket.subarray(0, header.payloadOffset),
|
|
4778
|
+
encryptedPacket.subarray(header.payloadOffset)
|
|
4779
|
+
);
|
|
4780
|
+
assertAuthTag(
|
|
4781
|
+
actualAuthTag,
|
|
4782
|
+
expectedAuthTag,
|
|
4783
|
+
"Failed to authenticate SRTP packet"
|
|
4784
|
+
);
|
|
4603
4785
|
const counter = this.generateCounter(
|
|
4604
4786
|
header.sequenceNumber,
|
|
4605
4787
|
rolloverCounter,
|
|
@@ -4611,14 +4793,16 @@ var CipherAesCtr = class extends CipherAesBase {
|
|
|
4611
4793
|
this.srtpSessionKey,
|
|
4612
4794
|
counter
|
|
4613
4795
|
);
|
|
4614
|
-
const payload =
|
|
4796
|
+
const payload = encryptedPacket.subarray(header.payloadOffset);
|
|
4615
4797
|
const buf = cipher.update(payload);
|
|
4616
4798
|
const dst = Buffer.concat([
|
|
4617
|
-
|
|
4618
|
-
buf
|
|
4619
|
-
Buffer.alloc(size - header.payloadOffset - buf.length)
|
|
4799
|
+
encryptedPacket.subarray(0, header.payloadOffset),
|
|
4800
|
+
buf
|
|
4620
4801
|
]);
|
|
4621
|
-
return [
|
|
4802
|
+
return [
|
|
4803
|
+
dst,
|
|
4804
|
+
finalizeSrtpRtpHeader(header, dst, "Failed to authenticate SRTP packet")
|
|
4805
|
+
];
|
|
4622
4806
|
}
|
|
4623
4807
|
encryptRTCP(rtcpPacket, srtcpIndex) {
|
|
4624
4808
|
let out = Buffer.from(rtcpPacket);
|
|
@@ -4640,15 +4824,29 @@ var CipherAesCtr = class extends CipherAesBase {
|
|
|
4640
4824
|
return out;
|
|
4641
4825
|
}
|
|
4642
4826
|
decryptRTCP(encrypted) {
|
|
4643
|
-
const header =
|
|
4827
|
+
const header = parseSrtcpHeader(
|
|
4828
|
+
encrypted,
|
|
4829
|
+
this.authTagLength,
|
|
4830
|
+
srtcpIndexSize
|
|
4831
|
+
);
|
|
4644
4832
|
const tailOffset = encrypted.length - (this.authTagLength + srtcpIndexSize);
|
|
4833
|
+
const authenticatedPortion = encrypted.subarray(
|
|
4834
|
+
0,
|
|
4835
|
+
encrypted.length - this.authTagLength
|
|
4836
|
+
);
|
|
4837
|
+
const actualTag = encrypted.subarray(encrypted.length - this.authTagLength);
|
|
4838
|
+
const expectedTag = this.generateSrtcpAuthTag(authenticatedPortion);
|
|
4839
|
+
assertAuthTag(
|
|
4840
|
+
actualTag,
|
|
4841
|
+
expectedTag,
|
|
4842
|
+
"Failed to authenticate SRTCP packet"
|
|
4843
|
+
);
|
|
4645
4844
|
const out = Buffer.from(encrypted).slice(0, tailOffset);
|
|
4646
|
-
const isEncrypted = encrypted[tailOffset]
|
|
4845
|
+
const isEncrypted = encrypted[tailOffset] >>> 7;
|
|
4647
4846
|
if (isEncrypted === 0) return [out, header];
|
|
4648
4847
|
let srtcpIndex = encrypted.readUInt32BE(tailOffset);
|
|
4649
4848
|
srtcpIndex &= ~(1 << 31);
|
|
4650
4849
|
const ssrc = encrypted.readUInt32BE(4);
|
|
4651
|
-
const actualTag = encrypted.subarray(encrypted.length - 10);
|
|
4652
4850
|
const counter = this.generateCounter(
|
|
4653
4851
|
srtcpIndex & 65535,
|
|
4654
4852
|
srtcpIndex >> 16,
|
|
@@ -4689,6 +4887,11 @@ var CipherAesCtr = class extends CipherAesBase {
|
|
|
4689
4887
|
}
|
|
4690
4888
|
};
|
|
4691
4889
|
var srtcpIndexSize = 4;
|
|
4890
|
+
function assertAuthTag(actual, expected, message) {
|
|
4891
|
+
if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {
|
|
4892
|
+
throw new SrtpAuthenticationError(message);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4692
4895
|
|
|
4693
4896
|
// ../rtp/src/srtp/cipher/gcm.ts
|
|
4694
4897
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3 } from "crypto";
|
|
@@ -4711,20 +4914,25 @@ var CipherAesGcm = class extends CipherAesBase {
|
|
|
4711
4914
|
const dst = Buffer.concat([hdr, enc, authTag]);
|
|
4712
4915
|
return dst;
|
|
4713
4916
|
}
|
|
4714
|
-
decryptRtp(cipherText, rolloverCounter) {
|
|
4715
|
-
const
|
|
4917
|
+
decryptRtp(cipherText, rolloverCounter, header = parseSrtpRtpHeader(cipherText, this.aeadAuthTagLen)) {
|
|
4918
|
+
const headerBuffer = cipherText.subarray(0, header.payloadOffset);
|
|
4919
|
+
const authTagOffset = cipherText.length - this.aeadAuthTagLen;
|
|
4920
|
+
const authTag = cipherText.subarray(authTagOffset);
|
|
4716
4921
|
let dst = Buffer.from([]);
|
|
4717
4922
|
dst = growBufferSize(dst, cipherText.length - this.aeadAuthTagLen);
|
|
4718
|
-
|
|
4923
|
+
headerBuffer.copy(dst);
|
|
4719
4924
|
const iv = this.rtpInitializationVector(header, rolloverCounter);
|
|
4720
|
-
const enc = cipherText.slice(
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
);
|
|
4724
|
-
const
|
|
4725
|
-
|
|
4925
|
+
const enc = cipherText.slice(header.payloadOffset, authTagOffset);
|
|
4926
|
+
const decipher = createDecipheriv3("aes-128-gcm", this.srtpSessionKey, iv);
|
|
4927
|
+
decipher.setAAD(headerBuffer);
|
|
4928
|
+
decipher.setAuthTag(authTag);
|
|
4929
|
+
const dec = decipher.update(enc);
|
|
4930
|
+
finalizeAuthenticatedDecryption(decipher, "SRTP");
|
|
4726
4931
|
dec.copy(dst, header.payloadOffset);
|
|
4727
|
-
return [
|
|
4932
|
+
return [
|
|
4933
|
+
dst,
|
|
4934
|
+
finalizeSrtpRtpHeader(header, dst, "Failed to authenticate SRTP packet")
|
|
4935
|
+
];
|
|
4728
4936
|
}
|
|
4729
4937
|
encryptRTCP(rtcpPacket, srtcpIndex) {
|
|
4730
4938
|
const ssrc = rtcpPacket.readUInt32BE(4);
|
|
@@ -4745,19 +4953,38 @@ var CipherAesGcm = class extends CipherAesBase {
|
|
|
4745
4953
|
return dst;
|
|
4746
4954
|
}
|
|
4747
4955
|
decryptRTCP(encrypted) {
|
|
4748
|
-
const header =
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4956
|
+
const header = parseSrtcpHeader(
|
|
4957
|
+
encrypted,
|
|
4958
|
+
this.aeadAuthTagLen,
|
|
4959
|
+
srtcpIndexSize2
|
|
4960
|
+
);
|
|
4961
|
+
const srtcpIndexOffset = encrypted.length - srtcpIndexSize2;
|
|
4962
|
+
const authTagOffset = srtcpIndexOffset - this.aeadAuthTagLen;
|
|
4752
4963
|
const ssrc = encrypted.readUInt32BE(4);
|
|
4753
|
-
|
|
4754
|
-
|
|
4964
|
+
const encodedSrtcpIndex = encrypted.readUInt32BE(srtcpIndexOffset);
|
|
4965
|
+
const isEncrypted = encodedSrtcpIndex >>> 31 === 1;
|
|
4966
|
+
const srtcpIndex = encodedSrtcpIndex & ~(rtcpEncryptionFlag << 24);
|
|
4755
4967
|
const iv = this.rtcpInitializationVector(ssrc, srtcpIndex);
|
|
4756
|
-
const aad =
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4968
|
+
const aad = isEncrypted ? Buffer.concat([
|
|
4969
|
+
encrypted.subarray(0, 8),
|
|
4970
|
+
encrypted.subarray(srtcpIndexOffset)
|
|
4971
|
+
]) : Buffer.concat([
|
|
4972
|
+
encrypted.subarray(0, authTagOffset),
|
|
4973
|
+
encrypted.subarray(srtcpIndexOffset)
|
|
4974
|
+
]);
|
|
4975
|
+
const cipherText = isEncrypted ? encrypted.slice(8, authTagOffset) : Buffer.alloc(0);
|
|
4976
|
+
const dst = isEncrypted ? Buffer.alloc(authTagOffset) : Buffer.from(encrypted.subarray(0, authTagOffset));
|
|
4977
|
+
if (isEncrypted) {
|
|
4978
|
+
encrypted.slice(0, 8).copy(dst);
|
|
4979
|
+
}
|
|
4980
|
+
const decipher = createDecipheriv3("aes-128-gcm", this.srtcpSessionKey, iv);
|
|
4981
|
+
decipher.setAAD(aad);
|
|
4982
|
+
decipher.setAuthTag(encrypted.subarray(authTagOffset, srtcpIndexOffset));
|
|
4983
|
+
const dec = decipher.update(cipherText);
|
|
4984
|
+
finalizeAuthenticatedDecryption(decipher, "SRTCP");
|
|
4985
|
+
if (isEncrypted) {
|
|
4986
|
+
dec.copy(dst, 8);
|
|
4987
|
+
}
|
|
4761
4988
|
return [dst, header];
|
|
4762
4989
|
}
|
|
4763
4990
|
// https://tools.ietf.org/html/rfc7714#section-8.1
|
|
@@ -4793,6 +5020,15 @@ var CipherAesGcm = class extends CipherAesBase {
|
|
|
4793
5020
|
};
|
|
4794
5021
|
var srtcpIndexSize2 = 4;
|
|
4795
5022
|
var rtcpEncryptionFlag = 128;
|
|
5023
|
+
function finalizeAuthenticatedDecryption(decipher, packetType) {
|
|
5024
|
+
try {
|
|
5025
|
+
decipher.final();
|
|
5026
|
+
} catch {
|
|
5027
|
+
throw new SrtpAuthenticationError(
|
|
5028
|
+
`Failed to authenticate ${packetType} packet`
|
|
5029
|
+
);
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
4796
5032
|
|
|
4797
5033
|
// ../rtp/src/srtp/context/context.ts
|
|
4798
5034
|
var Context = class {
|
|
@@ -5050,12 +5286,29 @@ var SrtpContext2 = class extends Context {
|
|
|
5050
5286
|
return enc;
|
|
5051
5287
|
}
|
|
5052
5288
|
decryptRtp(cipherText) {
|
|
5053
|
-
const header =
|
|
5054
|
-
const
|
|
5055
|
-
|
|
5056
|
-
|
|
5289
|
+
const header = parseSrtpRtpHeader(cipherText, this.rtpAuthTagLength);
|
|
5290
|
+
const existingState = this.srtpSSRCStates[header.ssrc];
|
|
5291
|
+
const nextState = existingState ? { ...existingState } : {
|
|
5292
|
+
ssrc: header.ssrc,
|
|
5293
|
+
rolloverCounter: 0,
|
|
5294
|
+
lastSequenceNumber: 0
|
|
5295
|
+
};
|
|
5296
|
+
this.updateRolloverCount(header.sequenceNumber, nextState);
|
|
5297
|
+
const dec = this.cipher.decryptRtp(
|
|
5298
|
+
cipherText,
|
|
5299
|
+
nextState.rolloverCounter,
|
|
5300
|
+
header
|
|
5301
|
+
);
|
|
5302
|
+
if (existingState) {
|
|
5303
|
+
Object.assign(existingState, nextState);
|
|
5304
|
+
} else {
|
|
5305
|
+
this.srtpSSRCStates[header.ssrc] = nextState;
|
|
5306
|
+
}
|
|
5057
5307
|
return dec;
|
|
5058
5308
|
}
|
|
5309
|
+
get rtpAuthTagLength() {
|
|
5310
|
+
return this.profile === ProtectionProfileAeadAes128Gcm ? 16 : 10;
|
|
5311
|
+
}
|
|
5059
5312
|
};
|
|
5060
5313
|
|
|
5061
5314
|
// ../rtp/src/srtp/srtp.ts
|
|
@@ -5797,6 +6050,9 @@ var DtlsSocket = class {
|
|
|
5797
6050
|
this.sessionType === SessionType.CLIENT
|
|
5798
6051
|
);
|
|
5799
6052
|
}
|
|
6053
|
+
get remoteCertificate() {
|
|
6054
|
+
return this.cipher.remoteCertificate;
|
|
6055
|
+
}
|
|
5800
6056
|
};
|
|
5801
6057
|
|
|
5802
6058
|
// ../dtls/src/client.ts
|
|
@@ -6185,6 +6441,16 @@ handlers2[16 /* client_key_exchange_16 */] = ({ cipher, dtls }) => (message) =>
|
|
|
6185
6441
|
);
|
|
6186
6442
|
log16(dtls.sessionId, "setup cipher", cipher.cipher.summary);
|
|
6187
6443
|
};
|
|
6444
|
+
handlers2[11 /* certificate_11 */] = ({ cipher, dtls }) => (message) => {
|
|
6445
|
+
log16(dtls.sessionId, "handshake certificate", message);
|
|
6446
|
+
cipher.remoteCertificate = message.certificateList[0];
|
|
6447
|
+
};
|
|
6448
|
+
handlers2[15 /* certificate_verify_15 */] = ({ cipher, dtls }) => (message) => {
|
|
6449
|
+
if (!cipher.remoteCertificate) {
|
|
6450
|
+
throw new Error("client certificate missing before certificate verify");
|
|
6451
|
+
}
|
|
6452
|
+
log16(dtls.sessionId, "certificate_verify", message.algorithm);
|
|
6453
|
+
};
|
|
6188
6454
|
handlers2[20 /* finished_20 */] = ({ dtls }) => (message) => {
|
|
6189
6455
|
log16(dtls.sessionId, "finished", message);
|
|
6190
6456
|
};
|
|
@@ -6251,7 +6517,14 @@ var DtlsServer = class extends DtlsSocket {
|
|
|
6251
6517
|
{
|
|
6252
6518
|
await this.waitForReady(() => !!this.flight6);
|
|
6253
6519
|
this.flight6?.handleHandshake(handshake);
|
|
6254
|
-
|
|
6520
|
+
const requiredHandshakes = [
|
|
6521
|
+
16,
|
|
6522
|
+
this.options.certificateRequest && 11,
|
|
6523
|
+
this.options.certificateRequest && 15
|
|
6524
|
+
].filter((type) => typeof type === "number");
|
|
6525
|
+
await this.waitForReady(
|
|
6526
|
+
() => this.dtls.checkHandshakesExist(requiredHandshakes)
|
|
6527
|
+
);
|
|
6255
6528
|
await this.flight6?.exec();
|
|
6256
6529
|
this.connected = true;
|
|
6257
6530
|
this.onConnect.execute();
|
|
@@ -6320,7 +6593,6 @@ var methods = /* @__PURE__ */ ((methods2) => {
|
|
|
6320
6593
|
|
|
6321
6594
|
// ../ice/src/stun/message.ts
|
|
6322
6595
|
import { createHmac as createHmac4 } from "crypto";
|
|
6323
|
-
import crc32 from "buffer-crc32";
|
|
6324
6596
|
|
|
6325
6597
|
// ../ice/src/helper.ts
|
|
6326
6598
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
@@ -6330,19 +6602,6 @@ function randomString(length) {
|
|
|
6330
6602
|
function randomTransactionId() {
|
|
6331
6603
|
return randomBytes5(12);
|
|
6332
6604
|
}
|
|
6333
|
-
function bufferXor2(a, b) {
|
|
6334
|
-
if (a.length !== b.length) {
|
|
6335
|
-
throw new TypeError(
|
|
6336
|
-
"[webrtc-stun] You can not XOR buffers which length are different"
|
|
6337
|
-
);
|
|
6338
|
-
}
|
|
6339
|
-
const length = a.length;
|
|
6340
|
-
const buffer2 = Buffer.allocUnsafe(length);
|
|
6341
|
-
for (let i = 0; i < length; i++) {
|
|
6342
|
-
buffer2[i] = a[i] ^ b[i];
|
|
6343
|
-
}
|
|
6344
|
-
return buffer2;
|
|
6345
|
-
}
|
|
6346
6605
|
var PQueue = class {
|
|
6347
6606
|
queue = [];
|
|
6348
6607
|
wait = new Event();
|
|
@@ -6676,11 +6935,7 @@ function messageFingerprint(data) {
|
|
|
6676
6935
|
data,
|
|
6677
6936
|
data.length - HEADER_LENGTH + FINGERPRINT_LENGTH
|
|
6678
6937
|
);
|
|
6679
|
-
|
|
6680
|
-
const xorBuf = Buffer.alloc(4);
|
|
6681
|
-
xorBuf.writeInt32BE(FINGERPRINT_XOR, 0);
|
|
6682
|
-
const fingerprint2 = bufferXor2(crc32Buf, xorBuf);
|
|
6683
|
-
return fingerprint2.readUInt32BE(0);
|
|
6938
|
+
return (crc32(checkData) ^ FINGERPRINT_XOR) >>> 0;
|
|
6684
6939
|
}
|
|
6685
6940
|
function messageIntegrity(data, key) {
|
|
6686
6941
|
const checkData = setBodyLength(
|
|
@@ -8519,6 +8774,9 @@ var EventTarget = class extends EventEmitter {
|
|
|
8519
8774
|
|
|
8520
8775
|
// src/dataChannel.ts
|
|
8521
8776
|
var log23 = debug("werift:packages/webrtc/src/dataChannel.ts");
|
|
8777
|
+
function getDataChannelMessageSize(data) {
|
|
8778
|
+
return Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data);
|
|
8779
|
+
}
|
|
8522
8780
|
var RTCDataChannel = class extends EventTarget {
|
|
8523
8781
|
constructor(sctp, parameters, sendOpen = true) {
|
|
8524
8782
|
super();
|
|
@@ -8624,10 +8882,9 @@ var RTCDataChannel = class extends EventTarget {
|
|
|
8624
8882
|
}
|
|
8625
8883
|
}
|
|
8626
8884
|
send(data) {
|
|
8627
|
-
const size =
|
|
8885
|
+
const size = this.sctp.datachannelSend(this, data);
|
|
8628
8886
|
this.messagesSent++;
|
|
8629
8887
|
this.bytesSent += size;
|
|
8630
|
-
this.sctp.datachannelSend(this, data);
|
|
8631
8888
|
}
|
|
8632
8889
|
close() {
|
|
8633
8890
|
this.sctp.dataChannelClose(this);
|
|
@@ -9082,6 +9339,24 @@ function fingerprint(file, hashName) {
|
|
|
9082
9339
|
const hash2 = createHash4(hashName).update(file).digest("hex");
|
|
9083
9340
|
return colon(upper(hash2));
|
|
9084
9341
|
}
|
|
9342
|
+
var fingerprintHashAlgorithms = {
|
|
9343
|
+
sha1: "sha1",
|
|
9344
|
+
"sha-1": "sha1",
|
|
9345
|
+
sha224: "sha224",
|
|
9346
|
+
"sha-224": "sha224",
|
|
9347
|
+
sha256: "sha256",
|
|
9348
|
+
"sha-256": "sha256",
|
|
9349
|
+
sha384: "sha384",
|
|
9350
|
+
"sha-384": "sha384",
|
|
9351
|
+
sha512: "sha512",
|
|
9352
|
+
"sha-512": "sha512"
|
|
9353
|
+
};
|
|
9354
|
+
function normalizeFingerprintAlgorithm(algorithm) {
|
|
9355
|
+
return fingerprintHashAlgorithms[algorithm.trim().toLowerCase()];
|
|
9356
|
+
}
|
|
9357
|
+
function normalizeFingerprintValue(value) {
|
|
9358
|
+
return value.replace(/[^0-9a-f]/gi, "").toLowerCase();
|
|
9359
|
+
}
|
|
9085
9360
|
function isDtls(buf) {
|
|
9086
9361
|
const firstByte = buf[0];
|
|
9087
9362
|
return firstByte > 19 && firstByte < 64;
|
|
@@ -9538,13 +9813,18 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9538
9813
|
return this.localCertificatePromise;
|
|
9539
9814
|
}
|
|
9540
9815
|
setRemoteParams(remoteParameters) {
|
|
9541
|
-
|
|
9816
|
+
const fingerprints = deduplicateFingerprints([
|
|
9817
|
+
...this.remoteParameters?.fingerprints ?? [],
|
|
9818
|
+
...remoteParameters.fingerprints
|
|
9819
|
+
]);
|
|
9820
|
+
const role = remoteParameters.role === "auto" && this.remoteParameters?.role ? this.remoteParameters.role : remoteParameters.role;
|
|
9821
|
+
this.remoteParameters = new RTCDtlsParameters(fingerprints, role);
|
|
9542
9822
|
}
|
|
9543
9823
|
async start() {
|
|
9544
9824
|
if (this.state !== "new") {
|
|
9545
9825
|
throw new Error("state must be new");
|
|
9546
9826
|
}
|
|
9547
|
-
if (this.remoteParameters
|
|
9827
|
+
if (!this.remoteParameters || this.remoteParameters.fingerprints.length === 0) {
|
|
9548
9828
|
throw new Error("remote fingerprint not exist");
|
|
9549
9829
|
}
|
|
9550
9830
|
if (this.role === "auto") {
|
|
@@ -9563,8 +9843,8 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9563
9843
|
signatureHash: this.localCertificate?.signatureHash,
|
|
9564
9844
|
transport: createIceTransport(this.iceTransport.connection),
|
|
9565
9845
|
srtpProfiles: this.srtpProfiles,
|
|
9566
|
-
extendedMasterSecret: true
|
|
9567
|
-
|
|
9846
|
+
extendedMasterSecret: true,
|
|
9847
|
+
certificateRequest: true
|
|
9568
9848
|
});
|
|
9569
9849
|
} else {
|
|
9570
9850
|
this.dtls = new DtlsClient({
|
|
@@ -9583,7 +9863,9 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9583
9863
|
this.dataReceiver(buf);
|
|
9584
9864
|
});
|
|
9585
9865
|
this.dtls.onClose.subscribe(() => {
|
|
9586
|
-
this.
|
|
9866
|
+
if (this.state !== "failed") {
|
|
9867
|
+
this.setState("closed");
|
|
9868
|
+
}
|
|
9587
9869
|
});
|
|
9588
9870
|
this.dtls.onConnect.once(r);
|
|
9589
9871
|
this.dtls.onError.once((error) => {
|
|
@@ -9600,16 +9882,70 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9600
9882
|
});
|
|
9601
9883
|
}
|
|
9602
9884
|
});
|
|
9885
|
+
try {
|
|
9886
|
+
this.verifyRemoteCertificateFingerprint();
|
|
9887
|
+
} catch (error) {
|
|
9888
|
+
this.setState("failed");
|
|
9889
|
+
this.dtls?.close();
|
|
9890
|
+
throw error;
|
|
9891
|
+
}
|
|
9603
9892
|
if (this.srtpProfiles.length > 0) {
|
|
9604
9893
|
this.startSrtp();
|
|
9605
9894
|
}
|
|
9606
|
-
this.dtls.onConnect.subscribe(() => {
|
|
9607
|
-
this.updateSrtpSession();
|
|
9608
|
-
this.setState("connected");
|
|
9609
|
-
});
|
|
9610
9895
|
this.setState("connected");
|
|
9611
9896
|
log27("dtls connected");
|
|
9612
9897
|
}
|
|
9898
|
+
verifyRemoteCertificateFingerprint() {
|
|
9899
|
+
if (!this.remoteParameters || this.remoteParameters.fingerprints.length === 0) {
|
|
9900
|
+
throw new Error("remote fingerprint not exist");
|
|
9901
|
+
}
|
|
9902
|
+
const remoteCertificate = this.dtls?.remoteCertificate;
|
|
9903
|
+
if (!remoteCertificate) {
|
|
9904
|
+
throw new Error("remote certificate not available");
|
|
9905
|
+
}
|
|
9906
|
+
const supportedFingerprints = this.remoteParameters.fingerprints.flatMap(
|
|
9907
|
+
({ algorithm, value }) => {
|
|
9908
|
+
const normalizedAlgorithm = normalizeFingerprintAlgorithm(algorithm);
|
|
9909
|
+
if (!normalizedAlgorithm) {
|
|
9910
|
+
return [];
|
|
9911
|
+
}
|
|
9912
|
+
const normalizedValue = normalizeFingerprintValue(value);
|
|
9913
|
+
if (!normalizedValue) {
|
|
9914
|
+
throw new Error("remote fingerprint value is empty");
|
|
9915
|
+
}
|
|
9916
|
+
return [{ normalizedAlgorithm, normalizedValue }];
|
|
9917
|
+
}
|
|
9918
|
+
);
|
|
9919
|
+
if (supportedFingerprints.length === 0) {
|
|
9920
|
+
throw new Error("no supported remote fingerprint algorithms");
|
|
9921
|
+
}
|
|
9922
|
+
const preferredAlgorithm = selectPreferredFingerprintAlgorithm(
|
|
9923
|
+
supportedFingerprints
|
|
9924
|
+
);
|
|
9925
|
+
const expectedFingerprints = supportedFingerprints.filter(
|
|
9926
|
+
({ normalizedAlgorithm }) => normalizedAlgorithm === preferredAlgorithm
|
|
9927
|
+
);
|
|
9928
|
+
const actualFingerprints = expectedFingerprints.reduce(
|
|
9929
|
+
(acc, { normalizedAlgorithm }) => {
|
|
9930
|
+
if (!acc.has(normalizedAlgorithm)) {
|
|
9931
|
+
acc.set(
|
|
9932
|
+
normalizedAlgorithm,
|
|
9933
|
+
normalizeFingerprintValue(
|
|
9934
|
+
fingerprint(remoteCertificate, normalizedAlgorithm)
|
|
9935
|
+
)
|
|
9936
|
+
);
|
|
9937
|
+
}
|
|
9938
|
+
return acc;
|
|
9939
|
+
},
|
|
9940
|
+
/* @__PURE__ */ new Map()
|
|
9941
|
+
);
|
|
9942
|
+
const matched = expectedFingerprints.some(
|
|
9943
|
+
({ normalizedAlgorithm, normalizedValue }) => actualFingerprints.get(normalizedAlgorithm) === normalizedValue
|
|
9944
|
+
);
|
|
9945
|
+
if (!matched) {
|
|
9946
|
+
throw new Error("remote certificate fingerprint mismatch");
|
|
9947
|
+
}
|
|
9948
|
+
}
|
|
9613
9949
|
updateSrtpSession() {
|
|
9614
9950
|
if (!this.dtls) throw new Error();
|
|
9615
9951
|
const profile = this.dtls.srtp.srtpProfile;
|
|
@@ -9642,8 +9978,23 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9642
9978
|
this.bytesReceived += data.length;
|
|
9643
9979
|
this.packetsReceived++;
|
|
9644
9980
|
if (isRtcp(data)) {
|
|
9645
|
-
|
|
9646
|
-
|
|
9981
|
+
let dec;
|
|
9982
|
+
try {
|
|
9983
|
+
dec = this.srtcp.decrypt(data);
|
|
9984
|
+
} catch (error) {
|
|
9985
|
+
if (error instanceof SrtpAuthenticationError) {
|
|
9986
|
+
log27("dropping invalid SRTCP packet", error);
|
|
9987
|
+
return;
|
|
9988
|
+
}
|
|
9989
|
+
throw error;
|
|
9990
|
+
}
|
|
9991
|
+
let rtcpPackets;
|
|
9992
|
+
try {
|
|
9993
|
+
rtcpPackets = RtcpPacketConverter.deSerialize(dec);
|
|
9994
|
+
} catch (error) {
|
|
9995
|
+
log27("dropping malformed SRTCP packet", error);
|
|
9996
|
+
return;
|
|
9997
|
+
}
|
|
9647
9998
|
for (const rtcp of rtcpPackets) {
|
|
9648
9999
|
try {
|
|
9649
10000
|
this.onRtcp.execute(rtcp);
|
|
@@ -9652,8 +10003,23 @@ var RTCDtlsTransport = class _RTCDtlsTransport {
|
|
|
9652
10003
|
}
|
|
9653
10004
|
}
|
|
9654
10005
|
} else {
|
|
9655
|
-
|
|
9656
|
-
|
|
10006
|
+
let dec;
|
|
10007
|
+
try {
|
|
10008
|
+
dec = this.srtp.decrypt(data);
|
|
10009
|
+
} catch (error) {
|
|
10010
|
+
if (error instanceof SrtpAuthenticationError) {
|
|
10011
|
+
log27("dropping invalid SRTP packet", error);
|
|
10012
|
+
return;
|
|
10013
|
+
}
|
|
10014
|
+
throw error;
|
|
10015
|
+
}
|
|
10016
|
+
let rtp;
|
|
10017
|
+
try {
|
|
10018
|
+
rtp = RtpPacket.deSerialize(dec);
|
|
10019
|
+
} catch (error) {
|
|
10020
|
+
log27("dropping malformed SRTP packet", error);
|
|
10021
|
+
return;
|
|
10022
|
+
}
|
|
9657
10023
|
try {
|
|
9658
10024
|
this.onRtp.execute(rtp);
|
|
9659
10025
|
} catch (error) {
|
|
@@ -9806,6 +10172,31 @@ var RTCDtlsParameters = class {
|
|
|
9806
10172
|
this.role = role;
|
|
9807
10173
|
}
|
|
9808
10174
|
};
|
|
10175
|
+
var deduplicateFingerprints = (fingerprints) => {
|
|
10176
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10177
|
+
return fingerprints.filter(({ algorithm, value }) => {
|
|
10178
|
+
const key = `${normalizeFingerprintAlgorithm(algorithm) ?? algorithm.trim().toLowerCase()}:${normalizeFingerprintValue(value)}`;
|
|
10179
|
+
if (seen.has(key)) {
|
|
10180
|
+
return false;
|
|
10181
|
+
}
|
|
10182
|
+
seen.add(key);
|
|
10183
|
+
return true;
|
|
10184
|
+
});
|
|
10185
|
+
};
|
|
10186
|
+
var preferredFingerprintAlgorithms = [
|
|
10187
|
+
"sha512",
|
|
10188
|
+
"sha384",
|
|
10189
|
+
"sha256",
|
|
10190
|
+
"sha224",
|
|
10191
|
+
"sha1"
|
|
10192
|
+
];
|
|
10193
|
+
var selectPreferredFingerprintAlgorithm = (fingerprints) => {
|
|
10194
|
+
return preferredFingerprintAlgorithms.find(
|
|
10195
|
+
(algorithm) => fingerprints.some(
|
|
10196
|
+
({ normalizedAlgorithm }) => normalizedAlgorithm === algorithm
|
|
10197
|
+
)
|
|
10198
|
+
) ?? fingerprints[0].normalizedAlgorithm;
|
|
10199
|
+
};
|
|
9809
10200
|
var IceTransport = class {
|
|
9810
10201
|
constructor(ice) {
|
|
9811
10202
|
this.ice = ice;
|
|
@@ -10173,7 +10564,6 @@ import { createHmac as createHmac5, randomBytes as randomBytes7 } from "crypto";
|
|
|
10173
10564
|
import { jspack as jspack5 } from "@shinyoshiaki/jspack";
|
|
10174
10565
|
|
|
10175
10566
|
// ../sctp/src/chunk.ts
|
|
10176
|
-
import crc32c from "turbo-crc32/crc32c.js";
|
|
10177
10567
|
var Chunk = class _Chunk {
|
|
10178
10568
|
constructor(flags = 0, _body = Buffer.from("")) {
|
|
10179
10569
|
this.flags = flags;
|
|
@@ -10737,6 +11127,8 @@ var SCTP_RTO_INITIAL = 3;
|
|
|
10737
11127
|
var SCTP_RTO_MIN = 1;
|
|
10738
11128
|
var SCTP_RTO_MAX = 60;
|
|
10739
11129
|
var SCTP_TSN_MODULO = 2 ** 32;
|
|
11130
|
+
var SCTP_SACK_DELAY_MS = 200;
|
|
11131
|
+
var SCTP_HEARTBEAT_INTERVAL = 30;
|
|
10740
11132
|
var RECONFIG_MAX_STREAMS = 135;
|
|
10741
11133
|
var SCTP_STATE_COOKIE = 7;
|
|
10742
11134
|
var SCTP_SUPPORTED_CHUNK_EXT = 32776;
|
|
@@ -10768,6 +11160,8 @@ var SCTP = class _SCTP {
|
|
|
10768
11160
|
started = false;
|
|
10769
11161
|
state = "new";
|
|
10770
11162
|
isServer = true;
|
|
11163
|
+
isStopping = false;
|
|
11164
|
+
isClosed = false;
|
|
10771
11165
|
hmacKey = randomBytes7(16);
|
|
10772
11166
|
localPartialReliability = true;
|
|
10773
11167
|
localPort;
|
|
@@ -10779,6 +11173,10 @@ var SCTP = class _SCTP {
|
|
|
10779
11173
|
// inbound
|
|
10780
11174
|
advertisedRwnd = 1024 * 1024;
|
|
10781
11175
|
// Receiver Window
|
|
11176
|
+
peerAdvertisedRwnd = this.advertisedRwnd;
|
|
11177
|
+
get peerRwnd() {
|
|
11178
|
+
return Math.max(0, this.peerAdvertisedRwnd - this.flightSize);
|
|
11179
|
+
}
|
|
10782
11180
|
inboundStreams = {};
|
|
10783
11181
|
_inboundStreamsCount = 0;
|
|
10784
11182
|
_inboundStreamsMax = MAX_STREAMS;
|
|
@@ -10787,6 +11185,9 @@ var SCTP = class _SCTP {
|
|
|
10787
11185
|
sackDuplicates = [];
|
|
10788
11186
|
sackMisOrdered = /* @__PURE__ */ new Set();
|
|
10789
11187
|
sackNeeded = false;
|
|
11188
|
+
sackPacketCount = 0;
|
|
11189
|
+
sackHasNewDataInPacket = false;
|
|
11190
|
+
sackImmediate = false;
|
|
10790
11191
|
sackTimeout;
|
|
10791
11192
|
// # outbound
|
|
10792
11193
|
cwnd = 3 * USERDATA_MAX_LENGTH;
|
|
@@ -10805,6 +11206,8 @@ var SCTP = class _SCTP {
|
|
|
10805
11206
|
// acknowledgement
|
|
10806
11207
|
partialBytesAcked = 0;
|
|
10807
11208
|
sentQueue = [];
|
|
11209
|
+
transmitting = false;
|
|
11210
|
+
transmitRequested = false;
|
|
10808
11211
|
// # reconfiguration
|
|
10809
11212
|
/**初期TSNと同じ値に初期化される単調に増加する数です. これは、新しいre-configuration requestパラメーターを送信するたびに1ずつ増加します */
|
|
10810
11213
|
reconfigRequestSeq = this.localTsn;
|
|
@@ -10830,8 +11233,13 @@ var SCTP = class _SCTP {
|
|
|
10830
11233
|
/**Re-configuration Timer */
|
|
10831
11234
|
timerReconfigHandle;
|
|
10832
11235
|
timerReconfigFailures = 0;
|
|
11236
|
+
timerHeartbeatHandle;
|
|
11237
|
+
heartbeatInterval = SCTP_HEARTBEAT_INTERVAL;
|
|
10833
11238
|
// etc
|
|
10834
11239
|
ssthresh;
|
|
11240
|
+
get isStopped() {
|
|
11241
|
+
return this.isStopping || this.isClosed;
|
|
11242
|
+
}
|
|
10835
11243
|
get maxChannels() {
|
|
10836
11244
|
if (this._inboundStreamsCount > 0) {
|
|
10837
11245
|
return Math.min(this._inboundStreamsCount, this._outboundStreamsCount);
|
|
@@ -10850,6 +11258,7 @@ var SCTP = class _SCTP {
|
|
|
10850
11258
|
}
|
|
10851
11259
|
// call from dtls transport
|
|
10852
11260
|
async handleData(data) {
|
|
11261
|
+
if (this.isStopped) return;
|
|
10853
11262
|
let expectedTag;
|
|
10854
11263
|
const [, , verificationTag, chunks] = parsePacket2(data);
|
|
10855
11264
|
const initChunk = chunks.filter((v) => v.type === InitChunk.type).length;
|
|
@@ -10864,17 +11273,41 @@ var SCTP = class _SCTP {
|
|
|
10864
11273
|
if (verificationTag !== expectedTag) {
|
|
10865
11274
|
return;
|
|
10866
11275
|
}
|
|
11276
|
+
this.sackHasNewDataInPacket = false;
|
|
10867
11277
|
for (const chunk of chunks) {
|
|
10868
11278
|
await this.receiveChunk(chunk);
|
|
10869
11279
|
}
|
|
10870
11280
|
if (this.sackNeeded) {
|
|
11281
|
+
if (this.sackHasNewDataInPacket) {
|
|
11282
|
+
this.sackPacketCount++;
|
|
11283
|
+
}
|
|
11284
|
+
if (this.sackPacketCount >= 2) {
|
|
11285
|
+
this.sackImmediate = true;
|
|
11286
|
+
}
|
|
11287
|
+
await this.scheduleSack();
|
|
11288
|
+
}
|
|
11289
|
+
}
|
|
11290
|
+
async scheduleSack() {
|
|
11291
|
+
if (this.isStopped) return;
|
|
11292
|
+
if (!this.sackNeeded) return;
|
|
11293
|
+
if (this.sackImmediate) {
|
|
11294
|
+
if (this.sackTimeout) {
|
|
11295
|
+
clearTimeout(this.sackTimeout);
|
|
11296
|
+
this.sackTimeout = void 0;
|
|
11297
|
+
}
|
|
10871
11298
|
await this.sendSack();
|
|
11299
|
+
return;
|
|
10872
11300
|
}
|
|
11301
|
+
if (this.sackTimeout) return;
|
|
11302
|
+
this.sackTimeout = setTimeout(() => {
|
|
11303
|
+
this.sackTimeout = void 0;
|
|
11304
|
+
this.sendSack().catch((err5) => {
|
|
11305
|
+
log29("send delayed sack failed", err5.message);
|
|
11306
|
+
});
|
|
11307
|
+
}, SCTP_SACK_DELAY_MS);
|
|
10873
11308
|
}
|
|
10874
11309
|
async sendSack() {
|
|
10875
|
-
if (this.
|
|
10876
|
-
await new Promise((r) => this.sackTimeout = setImmediate(r));
|
|
10877
|
-
this.sackTimeout = void 0;
|
|
11310
|
+
if (this.isStopped) return;
|
|
10878
11311
|
if (!this.sackNeeded) return;
|
|
10879
11312
|
const gaps = [];
|
|
10880
11313
|
let gapNext;
|
|
@@ -10897,6 +11330,8 @@ var SCTP = class _SCTP {
|
|
|
10897
11330
|
});
|
|
10898
11331
|
this.sackDuplicates = [];
|
|
10899
11332
|
this.sackNeeded = false;
|
|
11333
|
+
this.sackPacketCount = 0;
|
|
11334
|
+
this.sackImmediate = false;
|
|
10900
11335
|
}
|
|
10901
11336
|
async receiveChunk(chunk) {
|
|
10902
11337
|
switch (chunk.type) {
|
|
@@ -10914,6 +11349,7 @@ var SCTP = class _SCTP {
|
|
|
10914
11349
|
this.reconfigResponseSeq = tsnMinusOne(init.initialTsn);
|
|
10915
11350
|
this.remoteVerificationTag = init.initiateTag;
|
|
10916
11351
|
this.ssthresh = init.advertisedRwnd;
|
|
11352
|
+
this.peerAdvertisedRwnd = init.advertisedRwnd;
|
|
10917
11353
|
this.getExtensions(init.params);
|
|
10918
11354
|
this._inboundStreamsCount = Math.min(
|
|
10919
11355
|
init.outboundStreams,
|
|
@@ -10952,6 +11388,7 @@ var SCTP = class _SCTP {
|
|
|
10952
11388
|
this.reconfigResponseSeq = tsnMinusOne(initAck.initialTsn);
|
|
10953
11389
|
this.remoteVerificationTag = initAck.initiateTag;
|
|
10954
11390
|
this.ssthresh = initAck.advertisedRwnd;
|
|
11391
|
+
this.peerAdvertisedRwnd = initAck.advertisedRwnd;
|
|
10955
11392
|
this.getExtensions(initAck.params);
|
|
10956
11393
|
this._inboundStreamsCount = Math.min(
|
|
10957
11394
|
initAck.outboundStreams,
|
|
@@ -11149,7 +11586,18 @@ var SCTP = class _SCTP {
|
|
|
11149
11586
|
}
|
|
11150
11587
|
receiveDataChunk(chunk) {
|
|
11151
11588
|
this.sackNeeded = true;
|
|
11152
|
-
if (this.markReceived(chunk.tsn))
|
|
11589
|
+
if (this.markReceived(chunk.tsn)) {
|
|
11590
|
+
this.sackImmediate = true;
|
|
11591
|
+
return;
|
|
11592
|
+
}
|
|
11593
|
+
this.sackHasNewDataInPacket = true;
|
|
11594
|
+
this.sackImmediate = true;
|
|
11595
|
+
if ((chunk.flags & SCTP_DATA_LAST_FRAG) === 0) {
|
|
11596
|
+
this.sackImmediate = true;
|
|
11597
|
+
}
|
|
11598
|
+
if (this.sackMisOrdered.size > 0) {
|
|
11599
|
+
this.sackImmediate = true;
|
|
11600
|
+
}
|
|
11153
11601
|
const inboundStream = this.getInboundStream(chunk.streamId);
|
|
11154
11602
|
inboundStream.addChunk(chunk);
|
|
11155
11603
|
this.advertisedRwnd -= chunk.userData.length;
|
|
@@ -11248,12 +11696,14 @@ var SCTP = class _SCTP {
|
|
|
11248
11696
|
} else if (done > 0) {
|
|
11249
11697
|
this.timer3Restart();
|
|
11250
11698
|
}
|
|
11699
|
+
this.peerAdvertisedRwnd = chunk.advertisedRwnd;
|
|
11251
11700
|
this.updateAdvancedPeerAckPoint();
|
|
11252
11701
|
await this.onSackReceived();
|
|
11253
11702
|
await this.transmit();
|
|
11254
11703
|
}
|
|
11255
11704
|
receiveForwardTsnChunk(chunk) {
|
|
11256
11705
|
this.sackNeeded = true;
|
|
11706
|
+
this.sackImmediate = true;
|
|
11257
11707
|
if (uint32Gte(this.lastReceivedTsn, chunk.cumulativeTsn)) {
|
|
11258
11708
|
return;
|
|
11259
11709
|
}
|
|
@@ -11360,17 +11810,29 @@ var SCTP = class _SCTP {
|
|
|
11360
11810
|
if (ordered) {
|
|
11361
11811
|
this.outboundStreamSeq[streamId] = uint16Add(streamSeqNum, 1);
|
|
11362
11812
|
}
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
if (this.outboundQueue.length) {
|
|
11367
|
-
await this.flush.asPromise();
|
|
11368
|
-
} else {
|
|
11369
|
-
await new Promise((r) => setImmediate(r));
|
|
11370
|
-
}
|
|
11813
|
+
await this.transmit();
|
|
11814
|
+
while (this.outboundQueue.length) {
|
|
11815
|
+
await this.flush.asPromise();
|
|
11371
11816
|
}
|
|
11372
11817
|
};
|
|
11373
11818
|
async transmit() {
|
|
11819
|
+
if (this.isStopped) return;
|
|
11820
|
+
if (this.transmitting) {
|
|
11821
|
+
this.transmitRequested = true;
|
|
11822
|
+
return;
|
|
11823
|
+
}
|
|
11824
|
+
this.transmitting = true;
|
|
11825
|
+
try {
|
|
11826
|
+
do {
|
|
11827
|
+
this.transmitRequested = false;
|
|
11828
|
+
await this.transmitOnce();
|
|
11829
|
+
} while (this.transmitRequested);
|
|
11830
|
+
} finally {
|
|
11831
|
+
this.transmitting = false;
|
|
11832
|
+
}
|
|
11833
|
+
}
|
|
11834
|
+
async transmitOnce() {
|
|
11835
|
+
if (this.isStopped) return;
|
|
11374
11836
|
if (this.forwardTsnChunk) {
|
|
11375
11837
|
await this.sendChunk(this.forwardTsnChunk).catch((err5) => {
|
|
11376
11838
|
log29("send forwardTsn failed", err5.message);
|
|
@@ -11388,7 +11850,7 @@ var SCTP = class _SCTP {
|
|
|
11388
11850
|
if (this.fastRecoveryTransmit) {
|
|
11389
11851
|
this.fastRecoveryTransmit = false;
|
|
11390
11852
|
} else if (this.flightSize >= cwnd) {
|
|
11391
|
-
|
|
11853
|
+
break;
|
|
11392
11854
|
}
|
|
11393
11855
|
this.flightSizeIncrease(dataChunk);
|
|
11394
11856
|
dataChunk.misses = 0;
|
|
@@ -11403,9 +11865,13 @@ var SCTP = class _SCTP {
|
|
|
11403
11865
|
}
|
|
11404
11866
|
retransmitEarliest = false;
|
|
11405
11867
|
}
|
|
11406
|
-
while (this.outboundQueue.length > 0) {
|
|
11868
|
+
while (this.outboundQueue.length > 0 && this.flightSize < cwnd && this.peerRwnd > 0) {
|
|
11407
11869
|
const chunk = this.outboundQueue.shift();
|
|
11408
|
-
if (!chunk)
|
|
11870
|
+
if (!chunk) break;
|
|
11871
|
+
if (chunk.bookSize > this.peerRwnd && this.flightSize > 0) {
|
|
11872
|
+
this.outboundQueue.unshift(chunk);
|
|
11873
|
+
break;
|
|
11874
|
+
}
|
|
11409
11875
|
this.sentQueue.push(chunk);
|
|
11410
11876
|
this.flightSizeIncrease(chunk);
|
|
11411
11877
|
chunk.sentCount++;
|
|
@@ -11417,7 +11883,9 @@ var SCTP = class _SCTP {
|
|
|
11417
11883
|
this.timer3Start();
|
|
11418
11884
|
}
|
|
11419
11885
|
}
|
|
11420
|
-
this.outboundQueue
|
|
11886
|
+
if (!this.outboundQueue.length) {
|
|
11887
|
+
this.outboundQueue = [];
|
|
11888
|
+
}
|
|
11421
11889
|
this.flush.execute();
|
|
11422
11890
|
}
|
|
11423
11891
|
async transmitReconfigRequest() {
|
|
@@ -11470,16 +11938,19 @@ var SCTP = class _SCTP {
|
|
|
11470
11938
|
this.timer1Handle = setTimeout(this.timer1Expired, this.rto * 1e3);
|
|
11471
11939
|
}
|
|
11472
11940
|
timer1Expired = () => {
|
|
11941
|
+
if (this.isStopped) return;
|
|
11473
11942
|
this.timer1Failures++;
|
|
11474
11943
|
this.timer1Handle = void 0;
|
|
11475
11944
|
if (this.timer1Failures > SCTP_MAX_INIT_RETRANS) {
|
|
11476
11945
|
this.setState(1 /* CLOSED */);
|
|
11477
11946
|
} else {
|
|
11478
11947
|
setImmediate(() => {
|
|
11948
|
+
if (this.isStopped) return;
|
|
11479
11949
|
this.sendChunk(this.timer1Chunk).catch((err5) => {
|
|
11480
11950
|
log29("send timer1 chunk failed", err5.message);
|
|
11481
11951
|
});
|
|
11482
11952
|
});
|
|
11953
|
+
if (this.isStopped) return;
|
|
11483
11954
|
this.timer1Handle = setTimeout(this.timer1Expired, this.rto * 1e3);
|
|
11484
11955
|
}
|
|
11485
11956
|
};
|
|
@@ -11498,16 +11969,19 @@ var SCTP = class _SCTP {
|
|
|
11498
11969
|
this.timer2Handle = setTimeout(this.timer2Expired, this.rto * 1e3);
|
|
11499
11970
|
}
|
|
11500
11971
|
timer2Expired = () => {
|
|
11972
|
+
if (this.isStopped) return;
|
|
11501
11973
|
this.timer2Failures++;
|
|
11502
11974
|
this.timer2Handle = void 0;
|
|
11503
11975
|
if (this.timer2Failures > SCTP_MAX_ASSOCIATION_RETRANS) {
|
|
11504
11976
|
this.setState(1 /* CLOSED */);
|
|
11505
11977
|
} else {
|
|
11506
11978
|
setImmediate(() => {
|
|
11979
|
+
if (this.isStopped) return;
|
|
11507
11980
|
this.sendChunk(this.timer2Chunk).catch((err5) => {
|
|
11508
11981
|
log29("send timer2Chunk failed", err5.message);
|
|
11509
11982
|
});
|
|
11510
11983
|
});
|
|
11984
|
+
if (this.isStopped) return;
|
|
11511
11985
|
this.timer2Handle = setTimeout(this.timer2Expired, this.rto * 1e3);
|
|
11512
11986
|
}
|
|
11513
11987
|
};
|
|
@@ -11520,14 +11994,17 @@ var SCTP = class _SCTP {
|
|
|
11520
11994
|
}
|
|
11521
11995
|
/**t3 is wait for data sack */
|
|
11522
11996
|
timer3Start() {
|
|
11997
|
+
if (this.isStopped) return;
|
|
11523
11998
|
if (this.timer3Handle) throw new Error();
|
|
11524
11999
|
this.timer3Handle = setTimeout(this.timer3Expired, this.rto * 1e3);
|
|
11525
12000
|
}
|
|
11526
12001
|
timer3Restart() {
|
|
12002
|
+
if (this.isStopped) return;
|
|
11527
12003
|
this.timer3Cancel();
|
|
11528
|
-
this.timer3Handle = setTimeout(this.timer3Expired, this.rto);
|
|
12004
|
+
this.timer3Handle = setTimeout(this.timer3Expired, this.rto * 1e3);
|
|
11529
12005
|
}
|
|
11530
12006
|
timer3Expired = () => {
|
|
12007
|
+
if (this.isStopped) return;
|
|
11531
12008
|
this.timer3Handle = void 0;
|
|
11532
12009
|
this.sentQueue.forEach((chunk) => {
|
|
11533
12010
|
if (!this.maybeAbandon(chunk)) {
|
|
@@ -11553,6 +12030,7 @@ var SCTP = class _SCTP {
|
|
|
11553
12030
|
}
|
|
11554
12031
|
/**Re-configuration Timer */
|
|
11555
12032
|
timerReconfigHandleStart() {
|
|
12033
|
+
if (this.isStopped) return;
|
|
11556
12034
|
if (this.timerReconfigHandle) return;
|
|
11557
12035
|
log29("timerReconfigHandleStart", { rto: this.rto });
|
|
11558
12036
|
this.timerReconfigFailures = 0;
|
|
@@ -11562,6 +12040,7 @@ var SCTP = class _SCTP {
|
|
|
11562
12040
|
);
|
|
11563
12041
|
}
|
|
11564
12042
|
timerReconfigHandleExpired = async () => {
|
|
12043
|
+
if (this.isStopped) return;
|
|
11565
12044
|
this.timerReconfigFailures++;
|
|
11566
12045
|
this.rto = Math.ceil(this.rto * 1.5);
|
|
11567
12046
|
if (this.timerReconfigFailures > SCTP_MAX_ASSOCIATION_RETRANS) {
|
|
@@ -11571,6 +12050,7 @@ var SCTP = class _SCTP {
|
|
|
11571
12050
|
} else if (this.reconfigRequest) {
|
|
11572
12051
|
log29("timerReconfigHandleExpired", this.timerReconfigFailures, this.rto);
|
|
11573
12052
|
await this.sendReconfigParam(this.reconfigRequest);
|
|
12053
|
+
if (this.isStopped) return;
|
|
11574
12054
|
this.timerReconfigHandle = setTimeout(
|
|
11575
12055
|
this.timerReconfigHandleExpired,
|
|
11576
12056
|
this.rto * 1e3
|
|
@@ -11585,6 +12065,47 @@ var SCTP = class _SCTP {
|
|
|
11585
12065
|
this.timerReconfigFailures = 0;
|
|
11586
12066
|
}
|
|
11587
12067
|
}
|
|
12068
|
+
heartbeatStart() {
|
|
12069
|
+
if (this.timerHeartbeatHandle || this.associationState !== 4 /* ESTABLISHED */) {
|
|
12070
|
+
return;
|
|
12071
|
+
}
|
|
12072
|
+
this.timerHeartbeatHandle = setTimeout(
|
|
12073
|
+
this.timerHeartbeatExpired,
|
|
12074
|
+
(this.rto + this.heartbeatInterval) * 1e3
|
|
12075
|
+
);
|
|
12076
|
+
}
|
|
12077
|
+
heartbeatRestart() {
|
|
12078
|
+
this.heartbeatCancel();
|
|
12079
|
+
this.heartbeatStart();
|
|
12080
|
+
}
|
|
12081
|
+
heartbeatCancel() {
|
|
12082
|
+
if (this.timerHeartbeatHandle) {
|
|
12083
|
+
clearTimeout(this.timerHeartbeatHandle);
|
|
12084
|
+
this.timerHeartbeatHandle = void 0;
|
|
12085
|
+
}
|
|
12086
|
+
}
|
|
12087
|
+
timerHeartbeatExpired = async () => {
|
|
12088
|
+
this.timerHeartbeatHandle = void 0;
|
|
12089
|
+
if (this.associationState !== 4 /* ESTABLISHED */) return;
|
|
12090
|
+
if (this.flightSize === 0 && this.outboundQueue.length === 0) {
|
|
12091
|
+
const heartbeat = new HeartbeatChunk();
|
|
12092
|
+
heartbeat.params.push([
|
|
12093
|
+
1,
|
|
12094
|
+
Buffer.from(jspack5.Pack("!L", [Math.floor(Date.now() / 1e3)]))
|
|
12095
|
+
]);
|
|
12096
|
+
await this.sendChunk(heartbeat).catch((err5) => {
|
|
12097
|
+
log29("send heartbeat failed", err5.message);
|
|
12098
|
+
});
|
|
12099
|
+
}
|
|
12100
|
+
this.heartbeatStart();
|
|
12101
|
+
};
|
|
12102
|
+
setHeartbeatInterval(interval) {
|
|
12103
|
+
if (interval <= 0) {
|
|
12104
|
+
throw new Error("heartbeat interval must be > 0");
|
|
12105
|
+
}
|
|
12106
|
+
this.heartbeatInterval = interval;
|
|
12107
|
+
this.heartbeatRestart();
|
|
12108
|
+
}
|
|
11588
12109
|
updateAdvancedPeerAckPoint() {
|
|
11589
12110
|
if (uint32Gt(this.lastSackedTsn, this.advancedPeerAckTsn)) {
|
|
11590
12111
|
this.advancedPeerAckTsn = this.lastSackedTsn;
|
|
@@ -11696,12 +12217,21 @@ var SCTP = class _SCTP {
|
|
|
11696
12217
|
this.associationState = state;
|
|
11697
12218
|
}
|
|
11698
12219
|
if (state === 4 /* ESTABLISHED */) {
|
|
12220
|
+
this.isStopping = false;
|
|
12221
|
+
this.isClosed = false;
|
|
11699
12222
|
this.setConnectionState("connected");
|
|
12223
|
+
this.heartbeatStart();
|
|
11700
12224
|
} else if (state === 1 /* CLOSED */) {
|
|
12225
|
+
this.isClosed = true;
|
|
11701
12226
|
this.timer1Cancel();
|
|
11702
12227
|
this.timer2Cancel();
|
|
11703
12228
|
this.timer3Cancel();
|
|
11704
12229
|
this.timerReconfigCancel();
|
|
12230
|
+
this.heartbeatCancel();
|
|
12231
|
+
if (this.sackTimeout) {
|
|
12232
|
+
clearTimeout(this.sackTimeout);
|
|
12233
|
+
this.sackTimeout = void 0;
|
|
12234
|
+
}
|
|
11705
12235
|
this.setConnectionState("closed");
|
|
11706
12236
|
this.removeAllListeners();
|
|
11707
12237
|
}
|
|
@@ -11712,6 +12242,16 @@ var SCTP = class _SCTP {
|
|
|
11712
12242
|
this.stateChanged[state].execute();
|
|
11713
12243
|
}
|
|
11714
12244
|
async stop() {
|
|
12245
|
+
if (this.isStopped) {
|
|
12246
|
+
this.setState(1 /* CLOSED */);
|
|
12247
|
+
return;
|
|
12248
|
+
}
|
|
12249
|
+
this.isStopping = true;
|
|
12250
|
+
this.transport.onData = void 0;
|
|
12251
|
+
if (this.sackTimeout) {
|
|
12252
|
+
clearTimeout(this.sackTimeout);
|
|
12253
|
+
this.sackTimeout = void 0;
|
|
12254
|
+
}
|
|
11715
12255
|
if (this.associationState !== 1 /* CLOSED */) {
|
|
11716
12256
|
await this.abort();
|
|
11717
12257
|
}
|
|
@@ -11720,6 +12260,8 @@ var SCTP = class _SCTP {
|
|
|
11720
12260
|
clearTimeout(this.timer2Handle);
|
|
11721
12261
|
clearTimeout(this.timer3Handle);
|
|
11722
12262
|
clearTimeout(this.timerReconfigHandle);
|
|
12263
|
+
clearTimeout(this.timerHeartbeatHandle);
|
|
12264
|
+
clearTimeout(this.sackTimeout);
|
|
11723
12265
|
}
|
|
11724
12266
|
async abort() {
|
|
11725
12267
|
const abort = new AbortChunk();
|
|
@@ -11832,9 +12374,11 @@ function tsnPlusOne(a) {
|
|
|
11832
12374
|
|
|
11833
12375
|
// src/transport/sctp.ts
|
|
11834
12376
|
var log30 = debug("werift:packages/webrtc/src/transport/sctp.ts");
|
|
11835
|
-
var
|
|
11836
|
-
|
|
12377
|
+
var DEFAULT_MAX_MESSAGE_SIZE = 65536;
|
|
12378
|
+
var RTCSctpTransport = class _RTCSctpTransport {
|
|
12379
|
+
constructor(port = 5e3, maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE) {
|
|
11837
12380
|
this.port = port;
|
|
12381
|
+
this.maxMessageSize = maxMessageSize;
|
|
11838
12382
|
}
|
|
11839
12383
|
dtlsTransport;
|
|
11840
12384
|
sctp;
|
|
@@ -11844,6 +12388,7 @@ var RTCSctpTransport = class {
|
|
|
11844
12388
|
mLineIndex;
|
|
11845
12389
|
bundled = false;
|
|
11846
12390
|
dataChannels = {};
|
|
12391
|
+
remoteMaxMessageSize = DEFAULT_MAX_MESSAGE_SIZE;
|
|
11847
12392
|
dataChannelQueue = [];
|
|
11848
12393
|
dataChannelId;
|
|
11849
12394
|
eventDisposer = [];
|
|
@@ -12045,7 +12590,6 @@ var RTCSctpTransport = class {
|
|
|
12045
12590
|
}
|
|
12046
12591
|
async dataChannelFlush() {
|
|
12047
12592
|
if (this.sctp.associationState != 4 /* ESTABLISHED */) return;
|
|
12048
|
-
if (this.sctp.outboundQueue.length > 0) return;
|
|
12049
12593
|
while (this.dataChannelQueue.length > 0) {
|
|
12050
12594
|
const [channel, protocol, userData] = this.dataChannelQueue.shift();
|
|
12051
12595
|
let streamId = channel.id;
|
|
@@ -12073,18 +12617,35 @@ var RTCSctpTransport = class {
|
|
|
12073
12617
|
}
|
|
12074
12618
|
this.dataChannelQueue = [];
|
|
12075
12619
|
}
|
|
12620
|
+
assertSendableMessageSize(size) {
|
|
12621
|
+
if (this.remoteMaxMessageSize !== 0 && size > this.remoteMaxMessageSize) {
|
|
12622
|
+
throw new Error(
|
|
12623
|
+
`max-message-size exceeded: ${size} > ${this.remoteMaxMessageSize}`
|
|
12624
|
+
);
|
|
12625
|
+
}
|
|
12626
|
+
}
|
|
12076
12627
|
datachannelSend = (channel, data) => {
|
|
12077
|
-
|
|
12628
|
+
const userData = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
12629
|
+
const size = getDataChannelMessageSize(data);
|
|
12630
|
+
this.assertSendableMessageSize(size);
|
|
12631
|
+
channel.addBufferedAmount(size);
|
|
12078
12632
|
this.dataChannelQueue.push(
|
|
12079
|
-
typeof data === "string" ? [channel, WEBRTC_STRING,
|
|
12633
|
+
typeof data === "string" ? [channel, WEBRTC_STRING, userData] : [channel, WEBRTC_BINARY, userData]
|
|
12080
12634
|
);
|
|
12081
12635
|
if (this.sctp.associationState !== 4 /* ESTABLISHED */) {
|
|
12082
12636
|
log30("sctp not established", this.sctp.associationState);
|
|
12083
12637
|
}
|
|
12084
12638
|
this.dataChannelFlush();
|
|
12639
|
+
return size;
|
|
12085
12640
|
};
|
|
12086
|
-
|
|
12087
|
-
return
|
|
12641
|
+
getCapabilities() {
|
|
12642
|
+
return _RTCSctpTransport.getCapabilities(this.maxMessageSize);
|
|
12643
|
+
}
|
|
12644
|
+
static getCapabilities(maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE) {
|
|
12645
|
+
return new RTCSctpCapabilities2(maxMessageSize);
|
|
12646
|
+
}
|
|
12647
|
+
setRemoteMaxMessageSize(maxMessageSize) {
|
|
12648
|
+
this.remoteMaxMessageSize = maxMessageSize ?? DEFAULT_MAX_MESSAGE_SIZE;
|
|
12088
12649
|
}
|
|
12089
12650
|
setRemotePort(port) {
|
|
12090
12651
|
this.sctp.setRemotePort(port);
|
|
@@ -13775,8 +14336,8 @@ var SctpTransportManager = class {
|
|
|
13775
14336
|
onDataChannel = new Event();
|
|
13776
14337
|
constructor() {
|
|
13777
14338
|
}
|
|
13778
|
-
createSctpTransport() {
|
|
13779
|
-
const sctp = new RTCSctpTransport();
|
|
14339
|
+
createSctpTransport(maxMessageSize) {
|
|
14340
|
+
const sctp = new RTCSctpTransport(5e3, maxMessageSize);
|
|
13780
14341
|
sctp.mid = void 0;
|
|
13781
14342
|
sctp.onDataChannel.subscribe((channel) => {
|
|
13782
14343
|
this.dataChannelsOpened++;
|
|
@@ -13834,6 +14395,9 @@ var SctpTransportManager = class {
|
|
|
13834
14395
|
if (!this.sctpTransport) {
|
|
13835
14396
|
return;
|
|
13836
14397
|
}
|
|
14398
|
+
this.sctpTransport.setRemoteMaxMessageSize(
|
|
14399
|
+
remoteMedia.sctpCapabilities?.maxMessageSize
|
|
14400
|
+
);
|
|
13837
14401
|
this.sctpRemotePort = remoteMedia.sctpPort;
|
|
13838
14402
|
if (!this.sctpRemotePort) {
|
|
13839
14403
|
throw new Error("sctpRemotePort not exist");
|
|
@@ -13974,7 +14538,7 @@ var SDPManager = class {
|
|
|
13974
14538
|
);
|
|
13975
14539
|
media.sctpPort = sctp.port;
|
|
13976
14540
|
media.rtp.muxId = sctp.mid;
|
|
13977
|
-
media.sctpCapabilities =
|
|
14541
|
+
media.sctpCapabilities = sctp.getCapabilities();
|
|
13978
14542
|
this.addTransportDescription(media, sctp.dtlsTransport);
|
|
13979
14543
|
return media;
|
|
13980
14544
|
}
|
|
@@ -14112,7 +14676,7 @@ var SDPManager = class {
|
|
|
14112
14676
|
description.media.push(this.createMediaDescriptionForSctp(sctpTransport));
|
|
14113
14677
|
}
|
|
14114
14678
|
if (this.bundlePolicy !== "disable") {
|
|
14115
|
-
const mids = description.media.map((m) => m.
|
|
14679
|
+
const mids = description.media.map((m) => m.rtp.muxId).filter((v) => v);
|
|
14116
14680
|
if (mids.length) {
|
|
14117
14681
|
const bundle = new GroupDescription("BUNDLE", mids);
|
|
14118
14682
|
description.group.push(bundle);
|
|
@@ -14182,7 +14746,7 @@ var SDPManager = class {
|
|
|
14182
14746
|
if (this.bundlePolicy !== "disable") {
|
|
14183
14747
|
const bundle = new GroupDescription("BUNDLE", []);
|
|
14184
14748
|
for (const media of description.media) {
|
|
14185
|
-
if (media.
|
|
14749
|
+
if (media.rtp.muxId) {
|
|
14186
14750
|
bundle.items.push(media.rtp.muxId);
|
|
14187
14751
|
}
|
|
14188
14752
|
}
|
|
@@ -14307,7 +14871,9 @@ var SecureTransportManager = class {
|
|
|
14307
14871
|
);
|
|
14308
14872
|
}
|
|
14309
14873
|
createTransport() {
|
|
14310
|
-
const
|
|
14874
|
+
const existing = this.iceTransports.find(
|
|
14875
|
+
(transport) => transport.state !== "closed"
|
|
14876
|
+
);
|
|
14311
14877
|
const iceGatherer = new RTCIceGatherer({
|
|
14312
14878
|
...parseIceServers(this.config.iceServers),
|
|
14313
14879
|
forceTurn: this.config.iceTransportPolicy === "relay",
|
|
@@ -14562,6 +15128,7 @@ var RTCPeerConnection = class extends EventTarget {
|
|
|
14562
15128
|
secureManager;
|
|
14563
15129
|
isClosed = false;
|
|
14564
15130
|
shouldNegotiationneeded = false;
|
|
15131
|
+
remoteBundleNegotiated = false;
|
|
14565
15132
|
iceGatheringStateChange = new Event();
|
|
14566
15133
|
iceConnectionStateChange = new Event();
|
|
14567
15134
|
signalingStateChange = new Event();
|
|
@@ -14711,6 +15278,12 @@ var RTCPeerConnection = class extends EventTarget {
|
|
|
14711
15278
|
if (min === max) throw new Error("should not be same value");
|
|
14712
15279
|
if (min >= max) throw new Error("The min must be less than max");
|
|
14713
15280
|
}
|
|
15281
|
+
if (!Number.isInteger(this.config.maxMessageSize) || this.config.maxMessageSize < 0) {
|
|
15282
|
+
throw new Error("maxMessageSize must be a non-negative integer");
|
|
15283
|
+
}
|
|
15284
|
+
if (this.sctpManager?.sctpTransport) {
|
|
15285
|
+
this.sctpManager.sctpTransport.maxMessageSize = this.config.maxMessageSize;
|
|
15286
|
+
}
|
|
14714
15287
|
for (const [i, codecParams] of enumerate2([
|
|
14715
15288
|
...this.config.codecs.audio || [],
|
|
14716
15289
|
...this.config.codecs.video || []
|
|
@@ -14767,7 +15340,9 @@ var RTCPeerConnection = class extends EventTarget {
|
|
|
14767
15340
|
return description.toJSON();
|
|
14768
15341
|
}
|
|
14769
15342
|
createSctpTransport() {
|
|
14770
|
-
const sctp = this.sctpManager.createSctpTransport(
|
|
15343
|
+
const sctp = this.sctpManager.createSctpTransport(
|
|
15344
|
+
this.config.maxMessageSize
|
|
15345
|
+
);
|
|
14771
15346
|
const dtlsTransport = this.findOrCreateTransport();
|
|
14772
15347
|
sctp.setDtlsTransport(dtlsTransport);
|
|
14773
15348
|
return sctp;
|
|
@@ -14804,10 +15379,13 @@ var RTCPeerConnection = class extends EventTarget {
|
|
|
14804
15379
|
});
|
|
14805
15380
|
};
|
|
14806
15381
|
findOrCreateTransport() {
|
|
14807
|
-
const
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
15382
|
+
const existingDtlsTransport = this.dtlsTransports.find(
|
|
15383
|
+
(transport) => transport.state !== "closed"
|
|
15384
|
+
);
|
|
15385
|
+
const existing = existingDtlsTransport?.iceTransport;
|
|
15386
|
+
if (this.sdpManager.bundlePolicy === "max-bundle" || this.sdpManager.bundlePolicy !== "disable" && (this.remoteIsBundled || this.remoteBundleNegotiated)) {
|
|
15387
|
+
if (existingDtlsTransport) {
|
|
15388
|
+
return existingDtlsTransport;
|
|
14811
15389
|
}
|
|
14812
15390
|
}
|
|
14813
15391
|
const dtlsTransport = this.secureManager.createTransport();
|
|
@@ -14979,6 +15557,11 @@ var RTCPeerConnection = class extends EventTarget {
|
|
|
14979
15557
|
sessionDescription,
|
|
14980
15558
|
this.signalingState
|
|
14981
15559
|
);
|
|
15560
|
+
if (remoteSdp.group.some(
|
|
15561
|
+
(group) => group.semantic === "BUNDLE" && group.items.length > 0
|
|
15562
|
+
)) {
|
|
15563
|
+
this.remoteBundleNegotiated = true;
|
|
15564
|
+
}
|
|
14982
15565
|
let bundleTransport;
|
|
14983
15566
|
const matchTransceiverWithMedia = (transceiver, media) => transceiver.kind === media.kind && [void 0, media.rtp.muxId].includes(transceiver.mid);
|
|
14984
15567
|
let transports = remoteSdp.media.map((remoteMedia, i) => {
|
|
@@ -15196,7 +15779,8 @@ function generateDefaultPeerConfig() {
|
|
|
15196
15779
|
bundlePolicy: "max-compat",
|
|
15197
15780
|
debug: {},
|
|
15198
15781
|
midSuffix: false,
|
|
15199
|
-
forceTurnTCP: false
|
|
15782
|
+
forceTurnTCP: false,
|
|
15783
|
+
maxMessageSize: DEFAULT_MAX_MESSAGE_SIZE
|
|
15200
15784
|
};
|
|
15201
15785
|
}
|
|
15202
15786
|
var defaultPeerConfig = generateDefaultPeerConfig();
|
|
@@ -15249,14 +15833,15 @@ var TransceiverManager = class {
|
|
|
15249
15833
|
newTransceiver.options = options;
|
|
15250
15834
|
this.router.registerRtpSender(newTransceiver.sender);
|
|
15251
15835
|
const inactiveTransceiverIndex = this.transceivers.findIndex(
|
|
15252
|
-
(t) => t.currentDirection === "inactive"
|
|
15836
|
+
(t) => t.currentDirection === "inactive" && !t.usedForSender
|
|
15253
15837
|
);
|
|
15254
15838
|
const inactiveTransceiver = this.transceivers.find(
|
|
15255
|
-
(t) => t.currentDirection === "inactive"
|
|
15839
|
+
(t) => t.currentDirection === "inactive" && !t.usedForSender
|
|
15256
15840
|
);
|
|
15257
15841
|
if (inactiveTransceiverIndex > -1 && inactiveTransceiver) {
|
|
15258
15842
|
this.replaceTransceiver(newTransceiver, inactiveTransceiverIndex);
|
|
15259
15843
|
newTransceiver.mLineIndex = inactiveTransceiver.mLineIndex;
|
|
15844
|
+
newTransceiver.mid = inactiveTransceiver.mid;
|
|
15260
15845
|
inactiveTransceiver.setCurrentDirection(void 0);
|
|
15261
15846
|
} else {
|
|
15262
15847
|
this.pushTransceiver(newTransceiver);
|
|
@@ -15543,6 +16128,7 @@ export {
|
|
|
15543
16128
|
Connection,
|
|
15544
16129
|
ConnectionStates,
|
|
15545
16130
|
CurveType,
|
|
16131
|
+
DEFAULT_MAX_MESSAGE_SIZE,
|
|
15546
16132
|
DePacketizerBase,
|
|
15547
16133
|
Directions,
|
|
15548
16134
|
DtlsClient,
|
|
@@ -15646,6 +16232,7 @@ export {
|
|
|
15646
16232
|
SourceDescriptionChunk,
|
|
15647
16233
|
SourceDescriptionItem,
|
|
15648
16234
|
SrtcpSession,
|
|
16235
|
+
SrtpAuthenticationError,
|
|
15649
16236
|
SrtpContext,
|
|
15650
16237
|
SrtpSession,
|
|
15651
16238
|
SsrcDescription,
|
|
@@ -15680,6 +16267,8 @@ export {
|
|
|
15680
16267
|
codecParametersFromString,
|
|
15681
16268
|
codecParametersToString,
|
|
15682
16269
|
compactNtp,
|
|
16270
|
+
crc32,
|
|
16271
|
+
crc32c,
|
|
15683
16272
|
createBufferWriter,
|
|
15684
16273
|
createSelfSignedCertificate,
|
|
15685
16274
|
createStunOverTurnClient,
|
|
@@ -15702,6 +16291,7 @@ export {
|
|
|
15702
16291
|
fingerprint,
|
|
15703
16292
|
generateStatsId,
|
|
15704
16293
|
getBit,
|
|
16294
|
+
getDataChannelMessageSize,
|
|
15705
16295
|
getGlobalIp,
|
|
15706
16296
|
getHostAddresses,
|
|
15707
16297
|
getStatsTimestamp,
|
|
@@ -15720,6 +16310,8 @@ export {
|
|
|
15720
16310
|
milliTime,
|
|
15721
16311
|
nodeIpAddress,
|
|
15722
16312
|
normalizeFamilyNodeV18,
|
|
16313
|
+
normalizeFingerprintAlgorithm,
|
|
16314
|
+
normalizeFingerprintValue,
|
|
15723
16315
|
ntpTime,
|
|
15724
16316
|
ntpTime2Sec,
|
|
15725
16317
|
paddingBits,
|