werift 0.24.0 → 0.24.2
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/binary.js +2 -3
- package/lib/common/src/binary.js.map +1 -1
- package/lib/dtls/src/context/transport.d.ts +2 -2
- package/lib/dtls/src/context/transport.js +2 -2
- package/lib/dtls/src/context/transport.js.map +1 -1
- package/lib/dtls/src/socket.d.ts +3 -2
- package/lib/dtls/src/socket.js +2 -2
- package/lib/dtls/src/socket.js.map +1 -1
- package/lib/ice/src/ice.d.ts +20 -0
- package/lib/ice/src/ice.js +263 -66
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +22 -1
- package/lib/ice/src/iceBase.js +30 -1
- package/lib/ice/src/iceBase.js.map +1 -1
- package/lib/ice/src/internal/selectAddresses.d.ts +9 -0
- package/lib/ice/src/internal/selectAddresses.js +40 -0
- package/lib/ice/src/internal/selectAddresses.js.map +1 -0
- package/lib/ice/src/stun/protocol.d.ts +2 -2
- package/lib/ice/src/stun/protocol.js +17 -3
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/tcpProtocol.d.ts +2 -2
- package/lib/ice/src/stun/tcpProtocol.js +13 -3
- package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.d.ts +41 -4
- package/lib/ice/src/stun/transaction.js +193 -24
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +3 -3
- package/lib/ice/src/turn/protocol.js +31 -6
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +27 -1
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/ice/src/utils.js +2 -31
- package/lib/ice/src/utils.js.map +1 -1
- package/lib/ice-server/src/stun/attributes.js +9 -47
- package/lib/ice-server/src/stun/attributes.js.map +1 -1
- package/lib/ice-server/src/stun/ip.d.ts +12 -0
- package/lib/ice-server/src/stun/ip.js +88 -0
- package/lib/ice-server/src/stun/ip.js.map +1 -0
- package/lib/ice-server/src/stun/message.js +8 -0
- package/lib/ice-server/src/stun/message.js.map +1 -1
- package/lib/index.mjs +652 -234
- package/lib/nonstandard/index.mjs +121 -54
- package/lib/rtp/src/codec/av1.js +11 -5
- package/lib/rtp/src/codec/av1.js.map +1 -1
- package/lib/rtp/src/codec/leb128.d.ts +5 -0
- package/lib/rtp/src/codec/leb128.js +24 -0
- package/lib/rtp/src/codec/leb128.js.map +1 -0
- package/lib/rtp/src/rtp/rtx.js +4 -6
- package/lib/rtp/src/rtp/rtx.js.map +1 -1
- package/lib/rtp/src/srtp/context/context.d.ts +2 -0
- package/lib/rtp/src/srtp/context/context.js +12 -12
- package/lib/rtp/src/srtp/context/context.js.map +1 -1
- package/lib/sctp/src/param.js +31 -15
- package/lib/sctp/src/param.js.map +1 -1
- package/lib/sctp/src/sctp.js +10 -9
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.js +2 -3
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +2 -2
- package/lib/webrtc/src/sdp.js +1 -35
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/secureTransportManager.d.ts +1 -1
- package/lib/webrtc/src/secureTransportManager.js +12 -0
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.d.ts +1 -1
- package/lib/webrtc/src/transport/sctp.js +17 -16
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/package.json +1 -7
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectAddressesFromInterfaces = selectAddressesFromInterfaces;
|
|
4
|
+
const common_1 = require("../imports/common");
|
|
5
|
+
/**
|
|
6
|
+
* Interface 辞書から host 候補アドレスを選別する(package-private)。
|
|
7
|
+
* 公開 barrel (`src/index.ts`) からは export しない。
|
|
8
|
+
* テストは本 helper への依存注入で行う。
|
|
9
|
+
*/
|
|
10
|
+
function selectAddressesFromInterfaces(interfaces, family, options = {}, isLinkLocal) {
|
|
11
|
+
// https://chromium.googlesource.com/external/webrtc/+/master/rtc_base/network.cc#236
|
|
12
|
+
const costlyNetworks = ["ipsec", "tun", "utun", "tap"];
|
|
13
|
+
const banNetworks = ["vmnet", "veth"];
|
|
14
|
+
const { useLinkLocalAddress } = options;
|
|
15
|
+
const all = Object.keys(interfaces)
|
|
16
|
+
.map((nic) => {
|
|
17
|
+
for (const word of [...costlyNetworks, ...banNetworks]) {
|
|
18
|
+
if (nic.startsWith(word)) {
|
|
19
|
+
return {
|
|
20
|
+
nic,
|
|
21
|
+
addresses: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const addresses = (interfaces[nic] ?? []).filter((details) => (0, common_1.normalizeFamilyNodeV18)(details.family) === family &&
|
|
26
|
+
!details.internal &&
|
|
27
|
+
(useLinkLocalAddress ? true : !isLinkLocal(details)));
|
|
28
|
+
return {
|
|
29
|
+
nic,
|
|
30
|
+
addresses: addresses.map((address) => address.address),
|
|
31
|
+
};
|
|
32
|
+
})
|
|
33
|
+
.filter((address) => !!address);
|
|
34
|
+
// os.networkInterfaces doesn't actually return addresses in a good order.
|
|
35
|
+
// have seen instances where en0 (ethernet) is after en1 (wlan), etc.
|
|
36
|
+
// eth0 > eth1
|
|
37
|
+
all.sort((a, b) => a.nic.localeCompare(b.nic));
|
|
38
|
+
return Object.values(all).flatMap((entry) => entry.addresses);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=selectAddresses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectAddresses.js","sourceRoot":"","sources":["../../../../../ice/src/internal/selectAddresses.ts"],"names":[],"mappings":";;AAQA,sEAyCC;AAhDD,8CAA2D;AAE3D;;;;GAIG;AACH,SAAgB,6BAA6B,CAC3C,UAA8D,EAC9D,MAAc,EACd,UAEI,EAAE,EACN,WAAuD;IAEvD,qFAAqF;IACrF,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAExC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;SAChC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACX,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,cAAc,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC;YACvD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACL,GAAG;oBACH,SAAS,EAAE,EAAc;iBAC1B,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAC9C,CAAC,OAAO,EAAE,EAAE,CACV,IAAA,+BAAsB,EAAC,OAAO,CAAC,MAAM,CAAC,KAAK,MAAM;YACjD,CAAC,OAAO,CAAC,QAAQ;YACjB,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CACvD,CAAC;QACF,OAAO;YACL,GAAG;YACH,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;SACvD,CAAC;IACJ,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAElC,0EAA0E;IAC1E,qEAAqE;IACrE,cAAc;IACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAChE,CAAC","sourcesContent":["import type * as os from \"node:os\";\nimport { normalizeFamilyNodeV18 } from \"../imports/common\";\n\n/**\n * Interface 辞書から host 候補アドレスを選別する(package-private)。\n * 公開 barrel (`src/index.ts`) からは export しない。\n * テストは本 helper への依存注入で行う。\n */\nexport function selectAddressesFromInterfaces(\n interfaces: NodeJS.Dict<os.NetworkInterfaceInfo[] | undefined>,\n family: number,\n options: {\n useLinkLocalAddress?: boolean;\n } = {},\n isLinkLocal: (info: os.NetworkInterfaceInfo) => boolean,\n): string[] {\n // https://chromium.googlesource.com/external/webrtc/+/master/rtc_base/network.cc#236\n const costlyNetworks = [\"ipsec\", \"tun\", \"utun\", \"tap\"];\n const banNetworks = [\"vmnet\", \"veth\"];\n const { useLinkLocalAddress } = options;\n\n const all = Object.keys(interfaces)\n .map((nic) => {\n for (const word of [...costlyNetworks, ...banNetworks]) {\n if (nic.startsWith(word)) {\n return {\n nic,\n addresses: [] as string[],\n };\n }\n }\n const addresses = (interfaces[nic] ?? []).filter(\n (details) =>\n normalizeFamilyNodeV18(details.family) === family &&\n !details.internal &&\n (useLinkLocalAddress ? true : !isLinkLocal(details)),\n );\n return {\n nic,\n addresses: addresses.map((address) => address.address),\n };\n })\n .filter((address) => !!address);\n\n // os.networkInterfaces doesn't actually return addresses in a good order.\n // have seen instances where en0 (ethernet) is after en1 (wlan), etc.\n // eth0 > eth1\n all.sort((a, b) => a.nic.localeCompare(b.nic));\n return Object.values(all).flatMap((entry) => entry.addresses);\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Event, UdpTransport } from "../imports/common";
|
|
2
2
|
import type { Address, InterfaceAddresses } from "../../../common/src/network";
|
|
3
3
|
import type { Candidate } from "../candidate";
|
|
4
|
-
import type { Protocol } from "../types/model";
|
|
4
|
+
import type { Protocol, TransactionRequestOptions } from "../types/model";
|
|
5
5
|
import { type Message } from "./message";
|
|
6
6
|
import { Transaction } from "./transaction";
|
|
7
7
|
export declare class StunProtocol implements Protocol {
|
|
@@ -23,6 +23,6 @@ export declare class StunProtocol implements Protocol {
|
|
|
23
23
|
getExtraInfo(): Address;
|
|
24
24
|
sendStun(message: Message, addr: Address): Promise<void>;
|
|
25
25
|
sendData(data: Buffer, addr: Address): Promise<void>;
|
|
26
|
-
request(request: Message, addr: Address, integrityKey?: Buffer,
|
|
26
|
+
request(request: Message, addr: Address, integrityKey?: Buffer, retransmissionsOrOptions?: number | TransactionRequestOptions, onRequestSent?: (attempt: number) => void): Promise<[Message, readonly [string, number]]>;
|
|
27
27
|
close(): Promise<void>;
|
|
28
28
|
}
|
|
@@ -96,7 +96,15 @@ class StunProtocol {
|
|
|
96
96
|
message.messageClass === const_1.classes.ERROR) &&
|
|
97
97
|
this.transactionsKeys.includes(message.transactionIdHex)) {
|
|
98
98
|
const transaction = this.transactions[message.transactionIdHex];
|
|
99
|
-
|
|
99
|
+
// Re-parse with integrity key so unauthenticated responses are dropped.
|
|
100
|
+
const verified = transaction.integrityKey
|
|
101
|
+
? (0, message_1.parseMessage)(data, transaction.integrityKey)
|
|
102
|
+
: message;
|
|
103
|
+
if (!verified) {
|
|
104
|
+
log("STUN response failed MESSAGE-INTEGRITY check");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
transaction.responseReceived(verified, addr);
|
|
100
108
|
}
|
|
101
109
|
else if (message.messageClass === const_1.classes.REQUEST) {
|
|
102
110
|
this.onRequestReceived.execute(message, addr, data);
|
|
@@ -125,7 +133,7 @@ class StunProtocol {
|
|
|
125
133
|
}
|
|
126
134
|
await this.transport.send(data, addr);
|
|
127
135
|
}
|
|
128
|
-
async request(request, addr, integrityKey,
|
|
136
|
+
async request(request, addr, integrityKey, retransmissionsOrOptions, onRequestSent) {
|
|
129
137
|
// """
|
|
130
138
|
// Execute a STUN transaction and return the response.
|
|
131
139
|
// """
|
|
@@ -135,7 +143,13 @@ class StunProtocol {
|
|
|
135
143
|
request.addMessageIntegrity(integrityKey);
|
|
136
144
|
request.addFingerprint();
|
|
137
145
|
}
|
|
138
|
-
|
|
146
|
+
// Match DNS family to the bound socket so STUN hostname targets resolve correctly.
|
|
147
|
+
const socketType = this.transport
|
|
148
|
+
.socketType;
|
|
149
|
+
const family = socketType === "udp6" ? 6 : 4;
|
|
150
|
+
const resolvedAddr = await (0, transaction_1.resolveRequestAddress)(addr, family);
|
|
151
|
+
const options = (0, transaction_1.buildTransactionOptions)(integrityKey, retransmissionsOrOptions, onRequestSent);
|
|
152
|
+
const transaction = new transaction_1.Transaction(request, resolvedAddr, this, options);
|
|
139
153
|
this.transactions[request.transactionIdHex] = transaction;
|
|
140
154
|
try {
|
|
141
155
|
return await transaction.run();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../../../ice/src/stun/protocol.ts"],"names":[],"mappings":";;;AAAA,8CAA+D;AAM/D,mCAAkC;AAClC,uCAAuD;AACvD,+
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../../../ice/src/stun/protocol.ts"],"names":[],"mappings":";;;AAAA,8CAA+D;AAM/D,mCAAkC;AAClC,uCAAuD;AACvD,+CAIuB;AAEvB,MAAM,GAAG,GAAG,IAAA,cAAK,EAAC,gDAAgD,CAAC,CAAC;AAEpE,MAAa,YAAY;IAKvB,IAAI,gBAAgB;QAClB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC;IAQD;QAbS;;;;mBAAO,YAAY,CAAC,IAAI;WAAC;QAClC;;;;;WAAyB;QACzB;;;;mBAA+C,EAAE;WAAC;QAIlD;;;;;WAA2B;QAC3B;;;;;WAAsB;QACtB;;;;;WAAiB;QAER;;;;mBAAoB,IAAI,cAAK,EAA8B;WAAC;QAC5D;;;;mBAAiB,IAAI,cAAK,EAAY;WAAC;QAIhD;;;;mBAAiB,KAAK,EACpB,OAAgB,EAChB,SAA4B,EAC5B,kBAAuC,EACvC,EAAE;gBACF,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,CAAC,SAAS,GAAG,MAAM,qBAAY,CAAC,IAAI,CAAC,MAAM,EAAE;wBAC/C,SAAS;wBACT,kBAAkB;qBACnB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,SAAS,GAAG,MAAM,qBAAY,CAAC,IAAI,CAAC,MAAM,EAAE;wBAC/C,SAAS;wBACT,kBAAkB;qBACnB,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;oBACrC,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBACpC,CAAC,CAAC;YACJ,CAAC;WAAC;IAtBa,CAAC;IAwBR,gBAAgB,CAAC,IAAY,EAAE,IAAa;QAClD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,IAAI,CAAC,CAAC;YACnC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;oBACxB,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACpC,CAAC;gBACD,OAAO;YACT,CAAC;YACD,+CAA+C;YAC/C,IACE,CAAC,OAAO,CAAC,YAAY,KAAK,eAAO,CAAC,QAAQ;gBACxC,OAAO,CAAC,YAAY,KAAK,eAAO,CAAC,KAAK,CAAC;gBACzC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,EACxD,CAAC;gBACD,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;gBAChE,wEAAwE;gBACxE,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY;oBACvC,CAAC,CAAC,IAAA,sBAAY,EAAC,IAAI,EAAE,WAAW,CAAC,YAAY,CAAC;oBAC9C,CAAC,CAAC,OAAO,CAAC;gBACZ,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,GAAG,CAAC,8CAA8C,CAAC,CAAC;oBACpD,OAAO;gBACT,CAAC;gBACD,WAAW,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC/C,CAAC;iBAAM,IAAI,OAAO,CAAC,YAAY,KAAK,eAAO,CAAC,OAAO,EAAE,CAAC;gBACpD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,YAAY;QACV,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QACvD,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAgB,EAAE,IAAa;QAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YAC/C,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,IAAa;QACxC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,IAAa,EACb,YAAqB,EACrB,wBAA6D,EAC7D,aAAyC;QAEzC,MAAM;QACN,sDAAsD;QACtD,MAAM;QACN,IAAI,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC;YAC1D,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAExC,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC;YAC1C,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,CAAC;QAED,mFAAmF;QACnF,MAAM,UAAU,GAAI,IAAI,CAAC,SAAgD;aACtE,UAAU,CAAC;QACd,MAAM,MAAM,GAAU,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,YAAY,GAAG,MAAM,IAAA,mCAAqB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAE/D,MAAM,OAAO,GAAG,IAAA,qCAAuB,EACrC,YAAY,EACZ,wBAAwB,EACxB,aAAa,CACd,CAAC;QACF,MAAM,WAAW,GAAgB,IAAI,yBAAW,CAC9C,OAAO,EACP,YAAY,EACZ,IAAI,EACJ,OAAO,CACR,CAAC;QACF,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,GAAG,WAAW,CAAC;QAE1D,IAAI,CAAC;YACH,OAAO,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;QACjC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,CAAC;QACV,CAAC;gBAAS,CAAC;YACT,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;YACvD,WAAW,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;;AArJH,oCAsJC;AArJiB;;;;WAAO,MAAM;EAAT,CAAU","sourcesContent":["import { Event, UdpTransport, debug } from \"../imports/common\";\n\nimport type { Address, InterfaceAddresses } from \"../../../common/src/network\";\nimport type { Candidate } from \"../candidate\";\n\nimport type { Protocol, TransactionRequestOptions } from \"../types/model\";\nimport { classes } from \"./const\";\nimport { type Message, parseMessage } from \"./message\";\nimport {\n Transaction,\n buildTransactionOptions,\n resolveRequestAddress,\n} from \"./transaction\";\n\nconst log = debug(\"werift-ice : packages/ice/src/stun/protocol.ts\");\n\nexport class StunProtocol implements Protocol {\n static readonly type = \"stun\";\n readonly type = StunProtocol.type;\n transport!: UdpTransport;\n transactions: { [key: string]: Transaction } = {};\n get transactionsKeys() {\n return Object.keys(this.transactions);\n }\n localCandidate?: Candidate;\n sentMessage?: Message;\n localIp?: string;\n\n readonly onRequestReceived = new Event<[Message, Address, Buffer]>();\n readonly onDataReceived = new Event<[Buffer]>();\n\n constructor() {}\n\n connectionMade = async (\n useIpv4: boolean,\n portRange?: [number, number],\n interfaceAddresses?: InterfaceAddresses,\n ) => {\n if (useIpv4) {\n this.transport = await UdpTransport.init(\"udp4\", {\n portRange,\n interfaceAddresses,\n });\n } else {\n this.transport = await UdpTransport.init(\"udp6\", {\n portRange,\n interfaceAddresses,\n });\n }\n\n this.transport.onData = (data, addr) => {\n this.datagramReceived(data, addr);\n };\n };\n\n private datagramReceived(data: Buffer, addr: Address) {\n try {\n const message = parseMessage(data);\n if (!message) {\n if (this.localCandidate) {\n this.onDataReceived.execute(data);\n }\n return;\n }\n // log(\"parseMessage\", addr, message.toJSON());\n if (\n (message.messageClass === classes.RESPONSE ||\n message.messageClass === classes.ERROR) &&\n this.transactionsKeys.includes(message.transactionIdHex)\n ) {\n const transaction = this.transactions[message.transactionIdHex];\n // Re-parse with integrity key so unauthenticated responses are dropped.\n const verified = transaction.integrityKey\n ? parseMessage(data, transaction.integrityKey)\n : message;\n if (!verified) {\n log(\"STUN response failed MESSAGE-INTEGRITY check\");\n return;\n }\n transaction.responseReceived(verified, addr);\n } else if (message.messageClass === classes.REQUEST) {\n this.onRequestReceived.execute(message, addr, data);\n }\n } catch (error) {\n log(\"datagramReceived error\", error);\n }\n }\n\n getExtraInfo(): Address {\n const { address: host, port } = this.transport.address;\n return [host, port];\n }\n\n async sendStun(message: Message, addr: Address) {\n if (this.transport.closed) {\n return;\n }\n\n const data = message.bytes;\n await this.transport.send(data, addr).catch(() => {\n log(\"sendStun failed\", addr, message);\n });\n }\n\n async sendData(data: Buffer, addr: Address) {\n if (this.transport.closed) {\n return;\n }\n\n await this.transport.send(data, addr);\n }\n\n async request(\n request: Message,\n addr: Address,\n integrityKey?: Buffer,\n retransmissionsOrOptions?: number | TransactionRequestOptions,\n onRequestSent?: (attempt: number) => void,\n ) {\n // \"\"\"\n // Execute a STUN transaction and return the response.\n // \"\"\"\n if (this.transactionsKeys.includes(request.transactionIdHex))\n throw new Error(\"already request ed\");\n\n if (integrityKey) {\n request.addMessageIntegrity(integrityKey);\n request.addFingerprint();\n }\n\n // Match DNS family to the bound socket so STUN hostname targets resolve correctly.\n const socketType = (this.transport as unknown as { socketType?: string })\n .socketType;\n const family: 4 | 6 = socketType === \"udp6\" ? 6 : 4;\n const resolvedAddr = await resolveRequestAddress(addr, family);\n\n const options = buildTransactionOptions(\n integrityKey,\n retransmissionsOrOptions,\n onRequestSent,\n );\n const transaction: Transaction = new Transaction(\n request,\n resolvedAddr,\n this,\n options,\n );\n this.transactions[request.transactionIdHex] = transaction;\n\n try {\n return await transaction.run();\n } catch (e) {\n throw e;\n } finally {\n delete this.transactions[request.transactionIdHex];\n }\n }\n\n async close() {\n Object.values(this.transactions).forEach((transaction) => {\n transaction.cancel();\n });\n await this.transport.close();\n this.onRequestReceived.complete();\n this.onDataReceived.complete();\n }\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AddressInfo, type Socket } from "node:net";
|
|
2
2
|
import type { Candidate } from "../candidate";
|
|
3
3
|
import { type Address, Event } from "../imports/common";
|
|
4
|
-
import type { Protocol } from "../types/model";
|
|
4
|
+
import type { Protocol, TransactionRequestOptions } from "../types/model";
|
|
5
5
|
import { type Message } from "./message";
|
|
6
6
|
import { Transaction } from "./transaction";
|
|
7
7
|
type SocketEntry = {
|
|
@@ -30,7 +30,7 @@ declare abstract class BaseTcpProtocol implements Protocol {
|
|
|
30
30
|
private sendFrame;
|
|
31
31
|
sendStun(message: Message, addr: Address): Promise<void>;
|
|
32
32
|
sendData(data: Buffer, addr: Address): Promise<void>;
|
|
33
|
-
request(request: Message, addr: Address, integrityKey?: Buffer,
|
|
33
|
+
request(request: Message, addr: Address, integrityKey?: Buffer, retransmissionsOrOptions?: number | TransactionRequestOptions, onRequestSent?: (attempt: number) => void): Promise<[Message, readonly [string, number]]>;
|
|
34
34
|
pruneForSelection(remoteAddr?: Address): Promise<void>;
|
|
35
35
|
get activeSocketCount(): number;
|
|
36
36
|
get address(): AddressInfo;
|
|
@@ -146,7 +146,15 @@ class BaseTcpProtocol {
|
|
|
146
146
|
if ((message.messageClass === const_1.classes.RESPONSE ||
|
|
147
147
|
message.messageClass === const_1.classes.ERROR) &&
|
|
148
148
|
this.transactions[message.transactionIdHex]) {
|
|
149
|
-
this.transactions[message.transactionIdHex]
|
|
149
|
+
const transaction = this.transactions[message.transactionIdHex];
|
|
150
|
+
const verified = transaction.integrityKey
|
|
151
|
+
? (0, message_1.parseMessage)(data, transaction.integrityKey)
|
|
152
|
+
: message;
|
|
153
|
+
if (!verified) {
|
|
154
|
+
log("STUN response failed MESSAGE-INTEGRITY check");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
transaction.responseReceived(verified, addr);
|
|
150
158
|
}
|
|
151
159
|
else if (message.messageClass === const_1.classes.REQUEST) {
|
|
152
160
|
this.onRequestReceived.execute(message, addr, data);
|
|
@@ -174,7 +182,7 @@ class BaseTcpProtocol {
|
|
|
174
182
|
async sendData(data, addr) {
|
|
175
183
|
await this.sendFrame(data, addr);
|
|
176
184
|
}
|
|
177
|
-
async request(request, addr, integrityKey,
|
|
185
|
+
async request(request, addr, integrityKey, retransmissionsOrOptions, onRequestSent) {
|
|
178
186
|
if (this.transactions[request.transactionIdHex]) {
|
|
179
187
|
throw new Error("already requested");
|
|
180
188
|
}
|
|
@@ -182,7 +190,9 @@ class BaseTcpProtocol {
|
|
|
182
190
|
request.addMessageIntegrity(integrityKey);
|
|
183
191
|
request.addFingerprint();
|
|
184
192
|
}
|
|
185
|
-
const
|
|
193
|
+
const resolvedAddr = await (0, transaction_1.resolveRequestAddress)(addr);
|
|
194
|
+
const options = (0, transaction_1.buildTransactionOptions)(integrityKey, retransmissionsOrOptions, onRequestSent);
|
|
195
|
+
const transaction = new transaction_1.Transaction(request, resolvedAddr, this, options);
|
|
186
196
|
this.transactions[request.transactionIdHex] = transaction;
|
|
187
197
|
try {
|
|
188
198
|
return await transaction.run();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tcpProtocol.js","sourceRoot":"","sources":["../../../../../ice/src/stun/tcpProtocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AddressInfo, type Socket, connect, createServer } from \"node:net\";\n\nimport type { Candidate } from \"../candidate\";\nimport { type Address, Event, debug } from \"../imports/common\";\nimport type { Protocol } from \"../types/model\";\nimport { classes } from \"./const\";\nimport { type Message, parseMessage } from \"./message\";\nimport { encodeTcpFrame, splitTcpFrames } from \"./tcpFrame\";\nimport { Transaction } from \"./transaction\";\n\nconst log = debug(\"werift-ice:packages/ice/src/stun/tcpProtocol.ts\");\n\ntype SocketEntry = {\n socket: Socket;\n buffer: Buffer;\n remoteAddr?: Address;\n};\n\nfunction socketKey(addr: Address) {\n return `${addr[0]}:${addr[1]}`;\n}\n\nfunction addressFromSocket(socket: Socket) {\n if (!socket.remoteAddress || !socket.remotePort) {\n return;\n }\n return [socket.remoteAddress, socket.remotePort] as Address;\n}\n\nasync function waitForListening(\n server: ReturnType<typeof createServer>,\n host: string,\n port?: number,\n) {\n return await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n server.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen({\n host,\n port: port ?? 0,\n exclusive: true,\n });\n });\n}\n\nabstract class BaseTcpProtocol implements Protocol {\n static readonly type = \"tcp\";\n readonly type = BaseTcpProtocol.type;\n transactions: { [key: string]: Transaction } = {};\n localCandidate?: Candidate;\n sentMessage?: Message;\n localIp?: string;\n\n readonly onRequestReceived = new Event<[Message, Address, Buffer]>();\n readonly onDataReceived = new Event<[Buffer]>();\n\n protected readonly sockets = new Map<string, SocketEntry>();\n\n abstract connectionMade(...args: any[]): Promise<void>;\n protected abstract getSocket(addr: Address): Promise<SocketEntry>;\n\n protected rememberSocket(entry: SocketEntry) {\n const remoteAddr = entry.remoteAddr;\n if (!remoteAddr) {\n return;\n }\n\n this.sockets.set(socketKey(remoteAddr), entry);\n }\n\n protected forgetSocket(remoteAddr?: Address) {\n if (!remoteAddr) {\n return;\n }\n this.sockets.delete(socketKey(remoteAddr));\n }\n\n protected registerSocket(socket: Socket, remoteAddr?: Address) {\n const entry: SocketEntry = {\n socket,\n buffer: Buffer.alloc(0),\n remoteAddr,\n };\n\n if (remoteAddr) {\n this.rememberSocket(entry);\n }\n\n socket.on(\"data\", (data) => {\n entry.buffer = Buffer.concat([entry.buffer, data]);\n const { frames, rest } = splitTcpFrames(entry.buffer);\n entry.buffer = rest;\n\n const socketAddr = entry.remoteAddr ?? addressFromSocket(socket);\n if (!entry.remoteAddr && socketAddr) {\n entry.remoteAddr = socketAddr;\n this.rememberSocket(entry);\n }\n if (!socketAddr) {\n return;\n }\n\n for (const frame of frames) {\n if (frame.length === 0) {\n continue;\n }\n this.handleFrame(frame, socketAddr);\n }\n });\n socket.on(\"close\", () => {\n this.forgetSocket(entry.remoteAddr);\n });\n socket.on(\"error\", (error) => {\n log(\"tcp socket error\", error);\n });\n\n return entry;\n }\n\n private handleFrame(data: Buffer, addr: Address) {\n try {\n const message = parseMessage(data);\n if (!message) {\n this.onDataReceived.execute(data);\n return;\n }\n\n if (\n (message.messageClass === classes.RESPONSE ||\n message.messageClass === classes.ERROR) &&\n this.transactions[message.transactionIdHex]\n ) {\n this.transactions[message.transactionIdHex].responseReceived(\n message,\n addr,\n );\n } else if (message.messageClass === classes.REQUEST) {\n this.onRequestReceived.execute(message, addr, data);\n }\n } catch (error) {\n log(\"tcp frame parse error\", error);\n }\n }\n\n private async sendFrame(data: Buffer, addr: Address) {\n const entry = await this.getSocket(addr);\n await new Promise<void>((resolve, reject) => {\n entry.socket.write(encodeTcpFrame(data), (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n }\n\n async sendStun(message: Message, addr: Address) {\n await this.sendFrame(message.bytes, addr);\n }\n\n async sendData(data: Buffer, addr: Address) {\n await this.sendFrame(data, addr);\n }\n\n async request(\n request: Message,\n addr: Address,\n integrityKey?: Buffer,\n retransmissions?: number,\n onRequestSent?: (attempt: number) => void,\n ) {\n if (this.transactions[request.transactionIdHex]) {\n throw new Error(\"already requested\");\n }\n\n if (integrityKey) {\n request.addMessageIntegrity(integrityKey);\n request.addFingerprint();\n }\n\n const transaction = new Transaction(\n request,\n addr,\n this,\n retransmissions,\n onRequestSent,\n );\n this.transactions[request.transactionIdHex] = transaction;\n\n try {\n return await transaction.run();\n } finally {\n delete this.transactions[request.transactionIdHex];\n }\n }\n\n async pruneForSelection(remoteAddr?: Address) {\n for (const [key, entry] of this.sockets.entries()) {\n if (remoteAddr && key === socketKey(remoteAddr)) {\n continue;\n }\n entry.socket.destroy();\n this.sockets.delete(key);\n }\n }\n\n get activeSocketCount() {\n return this.sockets.size;\n }\n\n get address() {\n return {} as AddressInfo;\n }\n\n async close() {\n Object.values(this.transactions).forEach((transaction) => {\n transaction.cancel();\n });\n\n await this.pruneForSelection();\n this.onRequestReceived.complete();\n this.onDataReceived.complete();\n }\n}\n\nexport class TcpActiveProtocol extends BaseTcpProtocol {\n private readonly pendingSockets = new Map<string, Promise<SocketEntry>>();\n\n async connectionMade(localIp: string) {\n this.localIp = localIp;\n }\n\n protected async getSocket(addr: Address) {\n const key = socketKey(addr);\n const existing = this.sockets.get(key);\n if (existing) {\n return existing;\n }\n\n const pending = this.pendingSockets.get(key);\n if (pending) {\n return await pending;\n }\n\n const connecting = new Promise<SocketEntry>((resolve, reject) => {\n const socket = connect({\n host: addr[0],\n port: addr[1],\n localAddress: this.localIp,\n });\n const entry = this.registerSocket(socket, addr);\n\n const onError = (error: Error) => {\n socket.off(\"connect\", onConnect);\n reject(error);\n };\n const onConnect = () => {\n socket.off(\"error\", onError);\n resolve(entry);\n };\n\n socket.once(\"error\", onError);\n socket.once(\"connect\", onConnect);\n });\n\n this.pendingSockets.set(key, connecting);\n\n try {\n return await connecting;\n } finally {\n this.pendingSockets.delete(key);\n }\n }\n}\n\nexport class TcpPassiveProtocol extends BaseTcpProtocol {\n private server = createServer((socket) => {\n this.registerSocket(socket, addressFromSocket(socket));\n });\n\n async connectionMade(localIp: string, portRange?: [number, number]) {\n this.localIp = localIp;\n\n if (portRange) {\n let lastError: Error | undefined;\n for (let port = portRange[0]; port <= portRange[1]; port++) {\n try {\n await waitForListening(this.server, localIp, port);\n return;\n } catch (error) {\n lastError = error as Error;\n }\n }\n throw lastError ?? new Error(\"tcp port not found\");\n }\n\n await waitForListening(this.server, localIp);\n }\n\n protected async getSocket(addr: Address) {\n const entry = this.sockets.get(socketKey(addr));\n if (!entry) {\n throw new Error(\"tcp passive connection not established\");\n }\n return entry;\n }\n\n get listeningPort() {\n const address = this.server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"tcp passive protocol is not listening\");\n }\n return address.port;\n }\n\n override async close() {\n await super.close();\n await new Promise<void>((resolve) => {\n this.server.close(() => resolve());\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tcpProtocol.js","sourceRoot":"","sources":["../../../../../ice/src/stun/tcpProtocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { type AddressInfo, type Socket, connect, createServer } from \"node:net\";\n\nimport type { Candidate } from \"../candidate\";\nimport { type Address, Event, debug } from \"../imports/common\";\nimport type { Protocol, TransactionRequestOptions } from \"../types/model\";\nimport { classes } from \"./const\";\nimport { type Message, parseMessage } from \"./message\";\nimport { encodeTcpFrame, splitTcpFrames } from \"./tcpFrame\";\nimport {\n Transaction,\n buildTransactionOptions,\n resolveRequestAddress,\n} from \"./transaction\";\n\nconst log = debug(\"werift-ice:packages/ice/src/stun/tcpProtocol.ts\");\n\ntype SocketEntry = {\n socket: Socket;\n buffer: Buffer;\n remoteAddr?: Address;\n};\n\nfunction socketKey(addr: Address) {\n return `${addr[0]}:${addr[1]}`;\n}\n\nfunction addressFromSocket(socket: Socket) {\n if (!socket.remoteAddress || !socket.remotePort) {\n return;\n }\n return [socket.remoteAddress, socket.remotePort] as Address;\n}\n\nasync function waitForListening(\n server: ReturnType<typeof createServer>,\n host: string,\n port?: number,\n) {\n return await new Promise<void>((resolve, reject) => {\n const onError = (error: Error) => {\n server.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen({\n host,\n port: port ?? 0,\n exclusive: true,\n });\n });\n}\n\nabstract class BaseTcpProtocol implements Protocol {\n static readonly type = \"tcp\";\n readonly type = BaseTcpProtocol.type;\n transactions: { [key: string]: Transaction } = {};\n localCandidate?: Candidate;\n sentMessage?: Message;\n localIp?: string;\n\n readonly onRequestReceived = new Event<[Message, Address, Buffer]>();\n readonly onDataReceived = new Event<[Buffer]>();\n\n protected readonly sockets = new Map<string, SocketEntry>();\n\n abstract connectionMade(...args: any[]): Promise<void>;\n protected abstract getSocket(addr: Address): Promise<SocketEntry>;\n\n protected rememberSocket(entry: SocketEntry) {\n const remoteAddr = entry.remoteAddr;\n if (!remoteAddr) {\n return;\n }\n\n this.sockets.set(socketKey(remoteAddr), entry);\n }\n\n protected forgetSocket(remoteAddr?: Address) {\n if (!remoteAddr) {\n return;\n }\n this.sockets.delete(socketKey(remoteAddr));\n }\n\n protected registerSocket(socket: Socket, remoteAddr?: Address) {\n const entry: SocketEntry = {\n socket,\n buffer: Buffer.alloc(0),\n remoteAddr,\n };\n\n if (remoteAddr) {\n this.rememberSocket(entry);\n }\n\n socket.on(\"data\", (data) => {\n entry.buffer = Buffer.concat([entry.buffer, data]);\n const { frames, rest } = splitTcpFrames(entry.buffer);\n entry.buffer = rest;\n\n const socketAddr = entry.remoteAddr ?? addressFromSocket(socket);\n if (!entry.remoteAddr && socketAddr) {\n entry.remoteAddr = socketAddr;\n this.rememberSocket(entry);\n }\n if (!socketAddr) {\n return;\n }\n\n for (const frame of frames) {\n if (frame.length === 0) {\n continue;\n }\n this.handleFrame(frame, socketAddr);\n }\n });\n socket.on(\"close\", () => {\n this.forgetSocket(entry.remoteAddr);\n });\n socket.on(\"error\", (error) => {\n log(\"tcp socket error\", error);\n });\n\n return entry;\n }\n\n private handleFrame(data: Buffer, addr: Address) {\n try {\n const message = parseMessage(data);\n if (!message) {\n this.onDataReceived.execute(data);\n return;\n }\n\n if (\n (message.messageClass === classes.RESPONSE ||\n message.messageClass === classes.ERROR) &&\n this.transactions[message.transactionIdHex]\n ) {\n const transaction = this.transactions[message.transactionIdHex];\n const verified = transaction.integrityKey\n ? parseMessage(data, transaction.integrityKey)\n : message;\n if (!verified) {\n log(\"STUN response failed MESSAGE-INTEGRITY check\");\n return;\n }\n transaction.responseReceived(verified, addr);\n } else if (message.messageClass === classes.REQUEST) {\n this.onRequestReceived.execute(message, addr, data);\n }\n } catch (error) {\n log(\"tcp frame parse error\", error);\n }\n }\n\n private async sendFrame(data: Buffer, addr: Address) {\n const entry = await this.getSocket(addr);\n await new Promise<void>((resolve, reject) => {\n entry.socket.write(encodeTcpFrame(data), (error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n }\n\n async sendStun(message: Message, addr: Address) {\n await this.sendFrame(message.bytes, addr);\n }\n\n async sendData(data: Buffer, addr: Address) {\n await this.sendFrame(data, addr);\n }\n\n async request(\n request: Message,\n addr: Address,\n integrityKey?: Buffer,\n retransmissionsOrOptions?: number | TransactionRequestOptions,\n onRequestSent?: (attempt: number) => void,\n ) {\n if (this.transactions[request.transactionIdHex]) {\n throw new Error(\"already requested\");\n }\n\n if (integrityKey) {\n request.addMessageIntegrity(integrityKey);\n request.addFingerprint();\n }\n\n const resolvedAddr = await resolveRequestAddress(addr);\n const options = buildTransactionOptions(\n integrityKey,\n retransmissionsOrOptions,\n onRequestSent,\n );\n const transaction = new Transaction(request, resolvedAddr, this, options);\n this.transactions[request.transactionIdHex] = transaction;\n\n try {\n return await transaction.run();\n } finally {\n delete this.transactions[request.transactionIdHex];\n }\n }\n\n async pruneForSelection(remoteAddr?: Address) {\n for (const [key, entry] of this.sockets.entries()) {\n if (remoteAddr && key === socketKey(remoteAddr)) {\n continue;\n }\n entry.socket.destroy();\n this.sockets.delete(key);\n }\n }\n\n get activeSocketCount() {\n return this.sockets.size;\n }\n\n get address() {\n return {} as AddressInfo;\n }\n\n async close() {\n Object.values(this.transactions).forEach((transaction) => {\n transaction.cancel();\n });\n\n await this.pruneForSelection();\n this.onRequestReceived.complete();\n this.onDataReceived.complete();\n }\n}\n\nexport class TcpActiveProtocol extends BaseTcpProtocol {\n private readonly pendingSockets = new Map<string, Promise<SocketEntry>>();\n\n async connectionMade(localIp: string) {\n this.localIp = localIp;\n }\n\n protected async getSocket(addr: Address) {\n const key = socketKey(addr);\n const existing = this.sockets.get(key);\n if (existing) {\n return existing;\n }\n\n const pending = this.pendingSockets.get(key);\n if (pending) {\n return await pending;\n }\n\n const connecting = new Promise<SocketEntry>((resolve, reject) => {\n const socket = connect({\n host: addr[0],\n port: addr[1],\n localAddress: this.localIp,\n });\n const entry = this.registerSocket(socket, addr);\n\n const onError = (error: Error) => {\n socket.off(\"connect\", onConnect);\n reject(error);\n };\n const onConnect = () => {\n socket.off(\"error\", onError);\n resolve(entry);\n };\n\n socket.once(\"error\", onError);\n socket.once(\"connect\", onConnect);\n });\n\n this.pendingSockets.set(key, connecting);\n\n try {\n return await connecting;\n } finally {\n this.pendingSockets.delete(key);\n }\n }\n}\n\nexport class TcpPassiveProtocol extends BaseTcpProtocol {\n private server = createServer((socket) => {\n this.registerSocket(socket, addressFromSocket(socket));\n });\n\n async connectionMade(localIp: string, portRange?: [number, number]) {\n this.localIp = localIp;\n\n if (portRange) {\n let lastError: Error | undefined;\n for (let port = portRange[0]; port <= portRange[1]; port++) {\n try {\n await waitForListening(this.server, localIp, port);\n return;\n } catch (error) {\n lastError = error as Error;\n }\n }\n throw lastError ?? new Error(\"tcp port not found\");\n }\n\n await waitForListening(this.server, localIp);\n }\n\n protected async getSocket(addr: Address) {\n const entry = this.sockets.get(socketKey(addr));\n if (!entry) {\n throw new Error(\"tcp passive connection not established\");\n }\n return entry;\n }\n\n get listeningPort() {\n const address = this.server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"tcp passive protocol is not listening\");\n }\n return address.port;\n }\n\n override async close() {\n await super.close();\n await new Promise<void>((resolve) => {\n this.server.close(() => resolve());\n });\n }\n}\n"]}
|
|
@@ -1,20 +1,57 @@
|
|
|
1
1
|
import { type Address } from "../imports/common";
|
|
2
|
-
import type { Protocol } from "../types/model";
|
|
2
|
+
import type { Protocol, TransactionRequestOptions } from "../types/model";
|
|
3
3
|
import type { Message } from "./message";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a request target to a concrete IP before creating a Transaction so
|
|
6
|
+
* response source-address checks match the UDP peer address (hostname ≠ IP).
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveRequestAddress(addr: Address, family?: 0 | 4 | 6): Promise<Address>;
|
|
9
|
+
/**
|
|
10
|
+
* Normalize legacy positional args and the options-object form into one shape.
|
|
11
|
+
* Existing callers pass `(retransmissions?, onRequestSent?)`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeTransactionOptions(retransmissionsOrOptions?: number | TransactionRequestOptions, onRequestSent?: (attempt: number) => void): TransactionRequestOptions;
|
|
14
|
+
/** Compare ICE transport addresses (host, port). */
|
|
15
|
+
export declare function addressEquals(a: Address, b: Address): boolean;
|
|
4
16
|
export declare class Transaction {
|
|
5
17
|
private request;
|
|
6
18
|
private addr;
|
|
7
19
|
private protocol;
|
|
8
|
-
private retransmissions?;
|
|
9
|
-
private onRequestSent?;
|
|
10
20
|
private timeoutDelay;
|
|
11
21
|
ended: boolean;
|
|
12
22
|
private tries;
|
|
13
23
|
private readonly triesMax;
|
|
14
24
|
private readonly onResponse;
|
|
15
|
-
|
|
25
|
+
private readonly onRequestSent?;
|
|
26
|
+
private readonly signal?;
|
|
27
|
+
/** Remote address this transaction was sent to; responses must match. */
|
|
28
|
+
readonly expectedAddr: Address;
|
|
29
|
+
/**
|
|
30
|
+
* When set, protocol layers re-parse the wire response with this key so
|
|
31
|
+
* MESSAGE-INTEGRITY failures are rejected before responseReceived.
|
|
32
|
+
*/
|
|
33
|
+
readonly integrityKey?: Buffer;
|
|
34
|
+
private waitTimer?;
|
|
35
|
+
private waitResolve?;
|
|
36
|
+
private onAbort?;
|
|
37
|
+
constructor(request: Message, addr: Address, protocol: Protocol, retransmissionsOrOptions?: number | TransactionRequestOptions, onRequestSent?: (attempt: number) => void);
|
|
38
|
+
/**
|
|
39
|
+
* Accept a matching authenticated non-error response from the expected
|
|
40
|
+
* remote address. Wrong address, missing MESSAGE-INTEGRITY (when required),
|
|
41
|
+
* or non-success class is rejected without completing the transaction
|
|
42
|
+
* (wrong address / unauthenticated responses are ignored so we keep waiting).
|
|
43
|
+
*/
|
|
16
44
|
responseReceived: (message: Message, addr: Address) => void;
|
|
17
45
|
run: () => Promise<[Message, readonly [string, number]]>;
|
|
46
|
+
private attachAbortListener;
|
|
47
|
+
private failWithTimeout;
|
|
48
|
+
private clearWait;
|
|
49
|
+
private wait;
|
|
18
50
|
private retry;
|
|
19
51
|
cancel(): void;
|
|
20
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Build Transaction options for Protocol.request, folding integrityKey into
|
|
55
|
+
* options so response path can re-verify MESSAGE-INTEGRITY.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildTransactionOptions(integrityKey: Buffer | undefined, retransmissionsOrOptions?: number | TransactionRequestOptions, onRequestSent?: (attempt: number) => void): TransactionRequestOptions;
|