@blockcast/mmt-container 2.0.0 → 2.0.1-main.f22764ad18fb
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/README.md +1 -1
- package/dist/browser-runtime.js +45 -12
- package/dist/browser-runtime.js.map +2 -2
- package/dist/delivery-catalog.js +3 -0
- package/dist/delivery-catalog.js.map +2 -2
- package/dist/mmtp-container-parser.no-modules.js +19 -10
- package/dist/mmtp-container-parser.no-modules.js.map +2 -2
- package/dist/multicast-manager.js +45 -12
- package/dist/multicast-manager.js.map +2 -2
- package/dist/multicast-transport.d.ts +8 -1
- package/dist/multicast-transport.d.ts.map +1 -1
- package/dist/multicast-transport.js +93 -2
- package/dist/multicast-transport.js.map +4 -4
- package/dist/no-modules.js +19 -10
- package/dist/no-modules.js.map +2 -2
- package/package.json +5 -5
- package/src/multicast-transport.ts +43 -4
|
@@ -33,6 +33,12 @@ export interface MulticastTransportConfig {
|
|
|
33
33
|
* are "MHM2" passes ahead of the packet_id read and the allow-list, and is
|
|
34
34
|
* never counted toward a packet_id. On an unprotected join it is an
|
|
35
35
|
* unparseable MMTP packet, as before.
|
|
36
|
+
*
|
|
37
|
+
* A protected join admits only datagrams whose reported sender is the
|
|
38
|
+
* flow's S (`sourceAddress`, or `senderAddress` on ASM), compared as IP
|
|
39
|
+
* addresses, before anything hashes them (multicast-02 7.2.7). A datagram
|
|
40
|
+
* with no reported sender is dropped, and a join that cannot report one
|
|
41
|
+
* (no S, or an ATSC 3.0 tuner) is declined `invalid-request`.
|
|
36
42
|
*/
|
|
37
43
|
protected?: boolean;
|
|
38
44
|
}
|
|
@@ -131,7 +137,8 @@ export interface MulticastTransportStats {
|
|
|
131
137
|
* one (G, port, packet_id); the first sender whose packet is accepted owns
|
|
132
138
|
* the sub-flow until the next join, and every other sender is dropped here,
|
|
133
139
|
* before any gap, duplicate or FEC ledger sees it. A join or a silence
|
|
134
|
-
* failback releases the lock.
|
|
140
|
+
* failback releases the lock. On a protected join it also counts every
|
|
141
|
+
* datagram whose sender is not the flow's S, or is not reported.
|
|
135
142
|
*/
|
|
136
143
|
packetsDroppedForeignSender: number;
|
|
137
144
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multicast-transport.d.ts","sourceRoot":"","sources":["../src/multicast-transport.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAE5B,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"multicast-transport.d.ts","sourceRoot":"","sources":["../src/multicast-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -1263,6 +1263,9 @@ var AMTGatewayManager = class {
|
|
|
1263
1263
|
*/
|
|
1264
1264
|
async subscribe(config) {
|
|
1265
1265
|
const { key } = config;
|
|
1266
|
+
if (config.protected) {
|
|
1267
|
+
throw new Error("AMTGatewayManager refuses a protected join: it reports no per-datagram sender (multicast-02 7.2.7)");
|
|
1268
|
+
}
|
|
1266
1269
|
const keyStr = this.getKeyString(key);
|
|
1267
1270
|
if (this.subscriptions.has(keyStr)) {
|
|
1268
1271
|
console.log(`[AMT] Reusing existing subscription to ${keyStr}`);
|
|
@@ -1437,6 +1440,73 @@ var FEC_BLOCK_PROFILES2 = Object.freeze([
|
|
|
1437
1440
|
"iso-ssbg1-v1"
|
|
1438
1441
|
]);
|
|
1439
1442
|
|
|
1443
|
+
// ../mmt-base/dist/ip-address.js
|
|
1444
|
+
var DEC_OCTET = /^(?:0|[1-9]\d{0,2})$/;
|
|
1445
|
+
var H16 = /^[0-9A-Fa-f]{1,4}$/;
|
|
1446
|
+
function parseIpv4(text2) {
|
|
1447
|
+
const fields = text2.split(".");
|
|
1448
|
+
if (fields.length !== 4)
|
|
1449
|
+
return void 0;
|
|
1450
|
+
const octets = [];
|
|
1451
|
+
for (const field of fields) {
|
|
1452
|
+
if (!DEC_OCTET.test(field))
|
|
1453
|
+
return void 0;
|
|
1454
|
+
const value = Number(field);
|
|
1455
|
+
if (value > 255)
|
|
1456
|
+
return void 0;
|
|
1457
|
+
octets.push(value);
|
|
1458
|
+
}
|
|
1459
|
+
return octets;
|
|
1460
|
+
}
|
|
1461
|
+
function parseIpv6(text2) {
|
|
1462
|
+
const halves = text2.split("::");
|
|
1463
|
+
if (halves.length > 2)
|
|
1464
|
+
return void 0;
|
|
1465
|
+
const groupsOf = (part) => part === "" ? [] : part.split(":");
|
|
1466
|
+
const left = groupsOf(halves[0]);
|
|
1467
|
+
const right = halves.length === 2 ? groupsOf(halves[1]) : [];
|
|
1468
|
+
const words = [];
|
|
1469
|
+
const all = [...left, ...right];
|
|
1470
|
+
const last = halves.length === 2 && right.length === 0 ? -1 : all.length - 1;
|
|
1471
|
+
for (let index = 0; index < all.length; index++) {
|
|
1472
|
+
const group = all[index];
|
|
1473
|
+
if (index === last && group.includes(".")) {
|
|
1474
|
+
const v4 = parseIpv4(group);
|
|
1475
|
+
if (!v4)
|
|
1476
|
+
return void 0;
|
|
1477
|
+
words.push([v4[0] << 8 | v4[1], v4[2] << 8 | v4[3]]);
|
|
1478
|
+
} else if (H16.test(group)) {
|
|
1479
|
+
words.push([Number.parseInt(group, 16)]);
|
|
1480
|
+
} else {
|
|
1481
|
+
return void 0;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
const leftWords = words.slice(0, left.length).flat();
|
|
1485
|
+
const rightWords = words.slice(left.length).flat();
|
|
1486
|
+
const missing = 8 - leftWords.length - rightWords.length;
|
|
1487
|
+
if (halves.length === 2 ? missing < 1 : missing !== 0)
|
|
1488
|
+
return void 0;
|
|
1489
|
+
const out = new Uint8Array(16);
|
|
1490
|
+
[...leftWords, ...new Array(missing).fill(0), ...rightWords].forEach((word, index) => {
|
|
1491
|
+
out[index * 2] = word >> 8;
|
|
1492
|
+
out[index * 2 + 1] = word & 255;
|
|
1493
|
+
});
|
|
1494
|
+
return out;
|
|
1495
|
+
}
|
|
1496
|
+
function parseIpAddressLiteral2(text2) {
|
|
1497
|
+
if (typeof text2 !== "string")
|
|
1498
|
+
return void 0;
|
|
1499
|
+
if (text2.includes(":"))
|
|
1500
|
+
return parseIpv6(text2);
|
|
1501
|
+
const v4 = parseIpv4(text2);
|
|
1502
|
+
return v4 ? Uint8Array.from(v4) : void 0;
|
|
1503
|
+
}
|
|
1504
|
+
function sameIpAddress(a, b) {
|
|
1505
|
+
const x = parseIpAddressLiteral2(a);
|
|
1506
|
+
const y = parseIpAddressLiteral2(b);
|
|
1507
|
+
return x !== void 0 && y !== void 0 && x.length === y.length && x.every((octet, index) => octet === y[index]);
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1440
1510
|
// ../mmt-base/dist/fec-bindings.js
|
|
1441
1511
|
var RUNTIME_FEC_RECEIVER2 = Object.freeze({
|
|
1442
1512
|
schemes: Object.freeze(["raptorq", "reed-solomon"]),
|
|
@@ -1557,6 +1627,10 @@ var MulticastTransport = class {
|
|
|
1557
1627
|
#acceptedBytesByPacketId = /* @__PURE__ */ new Map();
|
|
1558
1628
|
#packetIds = null;
|
|
1559
1629
|
#protected = false;
|
|
1630
|
+
// A protected join's S, and the last sender spelling that matched it, so a
|
|
1631
|
+
// matching sender parses once per spelling rather than per datagram.
|
|
1632
|
+
#protectedSource = void 0;
|
|
1633
|
+
#matchedSource = void 0;
|
|
1560
1634
|
// The sender S this join's accepted packets came from, once known; see
|
|
1561
1635
|
// packetsDroppedForeignSender. Cleared by every join and by a silence
|
|
1562
1636
|
// failback, so a replacement publisher is not locked out.
|
|
@@ -1608,6 +1682,11 @@ var MulticastTransport = class {
|
|
|
1608
1682
|
return this.#declined(generation, "unavailable");
|
|
1609
1683
|
}
|
|
1610
1684
|
let failure = "invalid-request";
|
|
1685
|
+
const protectedSource = config.protected === true ? config.sourceAddress ?? config.senderAddress : void 0;
|
|
1686
|
+
if (config.protected === true && (protectedSource === void 0 || config.atsc3)) {
|
|
1687
|
+
console.warn("[MulticastTransport] protected join refused: the path reports no per-datagram sender to check against S");
|
|
1688
|
+
return this.#declined(generation, "invalid-request");
|
|
1689
|
+
}
|
|
1611
1690
|
try {
|
|
1612
1691
|
const packetIds = config.packetIds?.length ? new Set(config.packetIds) : null;
|
|
1613
1692
|
console.log(
|
|
@@ -1643,7 +1722,7 @@ var MulticastTransport = class {
|
|
|
1643
1722
|
this.#subscription = subscription;
|
|
1644
1723
|
const live = () => !this.#disposed && generation === this.#joinGeneration;
|
|
1645
1724
|
const anySource = !config.sourceAddress && !config.senderAddress && !config.atsc3;
|
|
1646
|
-
const packetListener = !anySource && subscriptionDeliversPacketBatches(subscription) ? {
|
|
1725
|
+
const packetListener = !anySource && protectedSource === void 0 && subscriptionDeliversPacketBatches(subscription) ? {
|
|
1647
1726
|
type: "packets",
|
|
1648
1727
|
listener: (event) => {
|
|
1649
1728
|
if (!live()) return;
|
|
@@ -1659,6 +1738,8 @@ var MulticastTransport = class {
|
|
|
1659
1738
|
this.#packetListener = packetListener;
|
|
1660
1739
|
this.#packetIds = packetIds;
|
|
1661
1740
|
this.#protected = config.protected === true;
|
|
1741
|
+
this.#protectedSource = protectedSource;
|
|
1742
|
+
this.#matchedSource = void 0;
|
|
1662
1743
|
this.#providerFilter = {
|
|
1663
1744
|
acknowledged: packetIds,
|
|
1664
1745
|
sent: 0,
|
|
@@ -2118,13 +2199,23 @@ var MulticastTransport = class {
|
|
|
2118
2199
|
this.#delivery = void 0;
|
|
2119
2200
|
this.#packetIds = null;
|
|
2120
2201
|
this.#protected = false;
|
|
2202
|
+
this.#protectedSource = void 0;
|
|
2203
|
+
this.#matchedSource = void 0;
|
|
2121
2204
|
this.#providerFilter = null;
|
|
2122
2205
|
this.#context = void 0;
|
|
2123
2206
|
this.#withdrawnPacketIds.clear();
|
|
2124
2207
|
}
|
|
2125
2208
|
/** The ingress filter; an accepted packet is counted here, once. */
|
|
2126
2209
|
#acceptPacket(packet, sourceAddress) {
|
|
2127
|
-
const
|
|
2210
|
+
const source = this.#protectedSource;
|
|
2211
|
+
if (source !== void 0 && (sourceAddress === void 0 || sourceAddress !== this.#matchedSource)) {
|
|
2212
|
+
if (sourceAddress === void 0 || !sameIpAddress(sourceAddress, source)) {
|
|
2213
|
+
this.#stats.packetsDroppedForeignSender++;
|
|
2214
|
+
return false;
|
|
2215
|
+
}
|
|
2216
|
+
this.#matchedSource = sourceAddress;
|
|
2217
|
+
}
|
|
2218
|
+
const owner = source === void 0 ? this.#lockedTo?.() ?? this.#sender : void 0;
|
|
2128
2219
|
if (sourceAddress !== void 0 && owner !== void 0 && sourceAddress !== owner) {
|
|
2129
2220
|
this.#stats.packetsDroppedForeignSender++;
|
|
2130
2221
|
return false;
|