werift 0.20.0 → 0.21.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.
Files changed (175) hide show
  1. package/lib/common/src/event.d.ts +45 -0
  2. package/lib/common/src/event.js +229 -0
  3. package/lib/common/src/event.js.map +1 -0
  4. package/lib/common/src/index.d.ts +1 -0
  5. package/lib/common/src/index.js +1 -0
  6. package/lib/common/src/index.js.map +1 -1
  7. package/lib/dtls/src/flight/client/flight5.js +6 -1
  8. package/lib/dtls/src/flight/client/flight5.js.map +1 -1
  9. package/lib/dtls/src/flight/server/flight2.js +5 -3
  10. package/lib/dtls/src/flight/server/flight2.js.map +1 -1
  11. package/lib/dtls/src/imports/common.d.ts +1 -0
  12. package/lib/dtls/src/imports/common.js +18 -0
  13. package/lib/dtls/src/imports/common.js.map +1 -0
  14. package/lib/dtls/src/index.d.ts +1 -1
  15. package/lib/dtls/src/index.js.map +1 -1
  16. package/lib/dtls/src/record/receive.js +1 -1
  17. package/lib/dtls/src/record/receive.js.map +1 -1
  18. package/lib/dtls/src/socket.d.ts +1 -1
  19. package/lib/dtls/src/socket.js +5 -5
  20. package/lib/dtls/src/socket.js.map +1 -1
  21. package/lib/ice/src/candidate.d.ts +3 -2
  22. package/lib/ice/src/candidate.js +19 -5
  23. package/lib/ice/src/candidate.js.map +1 -1
  24. package/lib/ice/src/helper.d.ts +6 -6
  25. package/lib/ice/src/helper.js +20 -17
  26. package/lib/ice/src/helper.js.map +1 -1
  27. package/lib/ice/src/ice.d.ts +29 -71
  28. package/lib/ice/src/ice.js +417 -417
  29. package/lib/ice/src/ice.js.map +1 -1
  30. package/lib/ice/src/iceBase.d.ts +109 -0
  31. package/lib/ice/src/iceBase.js +166 -0
  32. package/lib/ice/src/iceBase.js.map +1 -0
  33. package/lib/ice/src/imports/common.d.ts +1 -0
  34. package/lib/ice/src/imports/common.js +18 -0
  35. package/lib/ice/src/imports/common.js.map +1 -0
  36. package/lib/ice/src/index.d.ts +5 -0
  37. package/lib/ice/src/index.js +5 -0
  38. package/lib/ice/src/index.js.map +1 -1
  39. package/lib/ice/src/stun/message.d.ts +7 -0
  40. package/lib/ice/src/stun/message.js +20 -6
  41. package/lib/ice/src/stun/message.js.map +1 -1
  42. package/lib/ice/src/stun/protocol.d.ts +6 -6
  43. package/lib/ice/src/stun/protocol.js +29 -23
  44. package/lib/ice/src/stun/protocol.js.map +1 -1
  45. package/lib/ice/src/stun/transaction.js +10 -4
  46. package/lib/ice/src/stun/transaction.js.map +1 -1
  47. package/lib/ice/src/transport.d.ts +21 -4
  48. package/lib/ice/src/transport.js +115 -7
  49. package/lib/ice/src/transport.js.map +1 -1
  50. package/lib/ice/src/turn/protocol.d.ts +54 -37
  51. package/lib/ice/src/turn/protocol.js +219 -94
  52. package/lib/ice/src/turn/protocol.js.map +1 -1
  53. package/lib/ice/src/types/model.d.ts +9 -5
  54. package/lib/ice/src/types/model.js.map +1 -1
  55. package/lib/ice/src/utils.d.ts +1 -0
  56. package/lib/ice/src/utils.js +15 -16
  57. package/lib/ice/src/utils.js.map +1 -1
  58. package/lib/rtp/src/extra/container/mp4/container.d.ts +1 -1
  59. package/lib/rtp/src/extra/container/mp4/container.js +2 -5
  60. package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
  61. package/lib/rtp/src/extra/container/webm/container.d.ts +3 -1
  62. package/lib/rtp/src/extra/container/webm/container.js +8 -2
  63. package/lib/rtp/src/extra/container/webm/container.js.map +1 -1
  64. package/lib/rtp/src/extra/container/webm/ebml/id.d.ts +6 -0
  65. package/lib/rtp/src/extra/container/webm/ebml/id.js +6 -0
  66. package/lib/rtp/src/extra/container/webm/ebml/id.js.map +1 -1
  67. package/lib/rtp/src/extra/processor/depacketizer.d.ts +1 -1
  68. package/lib/rtp/src/extra/processor/depacketizer.js +2 -2
  69. package/lib/rtp/src/extra/processor/depacketizer.js.map +1 -1
  70. package/lib/rtp/src/extra/processor/mp4.d.ts +1 -1
  71. package/lib/rtp/src/extra/processor/mp4.js +2 -5
  72. package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
  73. package/lib/rtp/src/extra/processor/nack.d.ts +1 -1
  74. package/lib/rtp/src/extra/processor/nack.js +3 -3
  75. package/lib/rtp/src/extra/processor/nack.js.map +1 -1
  76. package/lib/rtp/src/extra/processor/rtcpCallback.d.ts +1 -1
  77. package/lib/rtp/src/extra/processor/rtcpCallback.js +2 -5
  78. package/lib/rtp/src/extra/processor/rtcpCallback.js.map +1 -1
  79. package/lib/rtp/src/extra/processor/rtpCallback.d.ts +1 -1
  80. package/lib/rtp/src/extra/processor/rtpCallback.js +2 -5
  81. package/lib/rtp/src/extra/processor/rtpCallback.js.map +1 -1
  82. package/lib/rtp/src/extra/processor/webm.d.ts +12 -17
  83. package/lib/rtp/src/extra/processor/webm.js +2 -5
  84. package/lib/rtp/src/extra/processor/webm.js.map +1 -1
  85. package/lib/rtp/src/extra/processor/webmCallback.d.ts +1 -10
  86. package/lib/rtp/src/extra/processor/webmCallback.js.map +1 -1
  87. package/lib/rtp/src/imports/common.d.ts +1 -0
  88. package/lib/rtp/src/imports/common.js +18 -0
  89. package/lib/rtp/src/imports/common.js.map +1 -0
  90. package/lib/rtp/src/rtp/headerExtension.d.ts +45 -3
  91. package/lib/rtp/src/rtp/headerExtension.js +15 -0
  92. package/lib/rtp/src/rtp/headerExtension.js.map +1 -1
  93. package/lib/sctp/src/helper.js +2 -5
  94. package/lib/sctp/src/helper.js.map +1 -1
  95. package/lib/sctp/src/imports/common.d.ts +1 -0
  96. package/lib/sctp/src/imports/common.js +18 -0
  97. package/lib/sctp/src/imports/common.js.map +1 -0
  98. package/lib/sctp/src/index.d.ts +1 -1
  99. package/lib/sctp/src/index.js.map +1 -1
  100. package/lib/sctp/src/sctp.d.ts +1 -1
  101. package/lib/sctp/src/sctp.js +3 -3
  102. package/lib/sctp/src/sctp.js.map +1 -1
  103. package/lib/webrtc/src/const.d.ts +2 -2
  104. package/lib/webrtc/src/const.js.map +1 -1
  105. package/lib/webrtc/src/dataChannel.d.ts +1 -1
  106. package/lib/webrtc/src/dataChannel.js +5 -5
  107. package/lib/webrtc/src/dataChannel.js.map +1 -1
  108. package/lib/webrtc/src/imports/common.d.ts +1 -0
  109. package/lib/webrtc/src/imports/common.js +18 -0
  110. package/lib/webrtc/src/imports/common.js.map +1 -0
  111. package/lib/webrtc/src/media/extension/rtpExtension.d.ts +1 -0
  112. package/lib/webrtc/src/media/extension/rtpExtension.js +6 -0
  113. package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
  114. package/lib/webrtc/src/media/receiver/nack.d.ts +1 -1
  115. package/lib/webrtc/src/media/receiver/nack.js +2 -2
  116. package/lib/webrtc/src/media/receiver/nack.js.map +1 -1
  117. package/lib/webrtc/src/media/router.d.ts +0 -3
  118. package/lib/webrtc/src/media/router.js.map +1 -1
  119. package/lib/webrtc/src/media/rtpReceiver.d.ts +3 -4
  120. package/lib/webrtc/src/media/rtpReceiver.js +4 -7
  121. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  122. package/lib/webrtc/src/media/rtpSender.d.ts +1 -1
  123. package/lib/webrtc/src/media/rtpSender.js +5 -5
  124. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  125. package/lib/webrtc/src/media/rtpTransceiver.d.ts +1 -1
  126. package/lib/webrtc/src/media/rtpTransceiver.js +2 -5
  127. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  128. package/lib/webrtc/src/media/sender/senderBWE.d.ts +1 -1
  129. package/lib/webrtc/src/media/sender/senderBWE.js +4 -7
  130. package/lib/webrtc/src/media/sender/senderBWE.js.map +1 -1
  131. package/lib/webrtc/src/media/track.d.ts +3 -3
  132. package/lib/webrtc/src/media/track.js +4 -7
  133. package/lib/webrtc/src/media/track.js.map +1 -1
  134. package/lib/webrtc/src/nonstandard/recorder/index.d.ts +3 -1
  135. package/lib/webrtc/src/nonstandard/recorder/index.js +2 -5
  136. package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
  137. package/lib/webrtc/src/nonstandard/recorder/writer/index.d.ts +1 -1
  138. package/lib/webrtc/src/nonstandard/recorder/writer/index.js.map +1 -1
  139. package/lib/webrtc/src/nonstandard/recorder/writer/webm.d.ts +1 -1
  140. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +3 -2
  141. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  142. package/lib/webrtc/src/peerConnection.d.ts +15 -8
  143. package/lib/webrtc/src/peerConnection.js +107 -93
  144. package/lib/webrtc/src/peerConnection.js.map +1 -1
  145. package/lib/webrtc/src/sdp.js +15 -3
  146. package/lib/webrtc/src/sdp.js.map +1 -1
  147. package/lib/webrtc/src/transport/dtls.d.ts +6 -6
  148. package/lib/webrtc/src/transport/dtls.js +19 -26
  149. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  150. package/lib/webrtc/src/transport/ice.d.ts +22 -11
  151. package/lib/webrtc/src/transport/ice.js +106 -38
  152. package/lib/webrtc/src/transport/ice.js.map +1 -1
  153. package/lib/webrtc/src/transport/sctp.d.ts +1 -1
  154. package/lib/webrtc/src/transport/sctp.js +2 -2
  155. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  156. package/package.json +1 -1
  157. package/src/const.ts +2 -2
  158. package/src/dataChannel.ts +1 -1
  159. package/src/imports/common.ts +1 -0
  160. package/src/media/extension/rtpExtension.ts +6 -0
  161. package/src/media/receiver/nack.ts +1 -1
  162. package/src/media/router.ts +2 -3
  163. package/src/media/rtpReceiver.ts +5 -4
  164. package/src/media/rtpSender.ts +1 -1
  165. package/src/media/rtpTransceiver.ts +1 -1
  166. package/src/media/sender/senderBWE.ts +1 -1
  167. package/src/media/track.ts +9 -4
  168. package/src/nonstandard/recorder/index.ts +4 -1
  169. package/src/nonstandard/recorder/writer/index.ts +1 -1
  170. package/src/nonstandard/recorder/writer/webm.ts +48 -44
  171. package/src/peerConnection.ts +122 -89
  172. package/src/sdp.ts +16 -3
  173. package/src/transport/dtls.ts +22 -14
  174. package/src/transport/ice.ts +83 -31
  175. package/src/transport/sctp.ts +1 -1
@@ -3,23 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CandidatePairState = exports.CandidatePair = exports.Connection = void 0;
7
- exports.validateRemoteCandidate = validateRemoteCandidate;
8
- exports.sortCandidatePairs = sortCandidatePairs;
9
- exports.candidatePairPriority = candidatePairPriority;
10
- exports.serverReflexiveCandidate = serverReflexiveCandidate;
11
- exports.validateAddress = validateAddress;
6
+ exports.Connection = void 0;
12
7
  const crypto_1 = require("crypto");
13
8
  const net_1 = require("net");
14
9
  const debug_1 = __importDefault(require("debug"));
15
10
  const int64_buffer_1 = require("int64-buffer");
16
11
  const isEqual_1 = __importDefault(require("lodash/isEqual"));
17
- const p_cancelable_1 = __importDefault(require("p-cancelable"));
18
- const rx_mini_1 = require("rx.mini");
19
12
  const promises_1 = __importDefault(require("timers/promises"));
13
+ const common_1 = require("./imports/common");
20
14
  const candidate_1 = require("./candidate");
21
15
  const lookup_1 = require("./dns/lookup");
22
16
  const helper_1 = require("./helper");
17
+ const iceBase_1 = require("./iceBase");
23
18
  const const_1 = require("./stun/const");
24
19
  const message_1 = require("./stun/message");
25
20
  const protocol_1 = require("./stun/protocol");
@@ -27,14 +22,14 @@ const protocol_2 = require("./turn/protocol");
27
22
  const utils_1 = require("./utils");
28
23
  const log = (0, debug_1.default)("werift-ice : packages/ice/src/ice.ts : log");
29
24
  class Connection {
30
- constructor(iceControlling, options) {
31
- Object.defineProperty(this, "iceControlling", {
25
+ constructor(_iceControlling, options) {
26
+ Object.defineProperty(this, "_iceControlling", {
32
27
  enumerable: true,
33
28
  configurable: true,
34
29
  writable: true,
35
- value: iceControlling
30
+ value: _iceControlling
36
31
  });
37
- Object.defineProperty(this, "localUserName", {
32
+ Object.defineProperty(this, "localUsername", {
38
33
  enumerable: true,
39
34
  configurable: true,
40
35
  writable: true,
@@ -46,23 +41,23 @@ class Connection {
46
41
  writable: true,
47
42
  value: (0, helper_1.randomString)(22)
48
43
  });
49
- Object.defineProperty(this, "remotePassword", {
44
+ Object.defineProperty(this, "remoteIsLite", {
50
45
  enumerable: true,
51
46
  configurable: true,
52
47
  writable: true,
53
- value: ""
48
+ value: false
54
49
  });
55
- Object.defineProperty(this, "remoteUsername", {
50
+ Object.defineProperty(this, "remotePassword", {
56
51
  enumerable: true,
57
52
  configurable: true,
58
53
  writable: true,
59
54
  value: ""
60
55
  });
61
- Object.defineProperty(this, "remoteIsLite", {
56
+ Object.defineProperty(this, "remoteUsername", {
62
57
  enumerable: true,
63
58
  configurable: true,
64
59
  writable: true,
65
- value: false
60
+ value: ""
66
61
  });
67
62
  Object.defineProperty(this, "checkList", {
68
63
  enumerable: true,
@@ -88,37 +83,37 @@ class Connection {
88
83
  writable: true,
89
84
  value: void 0
90
85
  });
91
- Object.defineProperty(this, "useIpv4", {
86
+ Object.defineProperty(this, "options", {
92
87
  enumerable: true,
93
88
  configurable: true,
94
89
  writable: true,
95
90
  value: void 0
96
91
  });
97
- Object.defineProperty(this, "useIpv6", {
92
+ Object.defineProperty(this, "remoteCandidatesEnd", {
98
93
  enumerable: true,
99
94
  configurable: true,
100
95
  writable: true,
101
- value: void 0
96
+ value: false
102
97
  });
103
- Object.defineProperty(this, "options", {
98
+ Object.defineProperty(this, "localCandidatesEnd", {
104
99
  enumerable: true,
105
100
  configurable: true,
106
101
  writable: true,
107
- value: void 0
102
+ value: false
108
103
  });
109
- Object.defineProperty(this, "remoteCandidatesEnd", {
104
+ Object.defineProperty(this, "generation", {
110
105
  enumerable: true,
111
106
  configurable: true,
112
107
  writable: true,
113
- value: false
108
+ value: -1
114
109
  });
115
- Object.defineProperty(this, "_localCandidatesEnd", {
110
+ Object.defineProperty(this, "userHistory", {
116
111
  enumerable: true,
117
112
  configurable: true,
118
113
  writable: true,
119
- value: false
114
+ value: {}
120
115
  });
121
- Object.defineProperty(this, "_tieBreaker", {
116
+ Object.defineProperty(this, "tieBreaker", {
122
117
  enumerable: true,
123
118
  configurable: true,
124
119
  writable: true,
@@ -136,24 +131,6 @@ class Connection {
136
131
  writable: true,
137
132
  value: void 0
138
133
  });
139
- Object.defineProperty(this, "restarted", {
140
- enumerable: true,
141
- configurable: true,
142
- writable: true,
143
- value: false
144
- });
145
- Object.defineProperty(this, "onData", {
146
- enumerable: true,
147
- configurable: true,
148
- writable: true,
149
- value: new rx_mini_1.Event()
150
- });
151
- Object.defineProperty(this, "stateChanged", {
152
- enumerable: true,
153
- configurable: true,
154
- writable: true,
155
- value: new rx_mini_1.Event()
156
- });
157
134
  Object.defineProperty(this, "_remoteCandidates", {
158
135
  enumerable: true,
159
136
  configurable: true,
@@ -191,6 +168,12 @@ class Connection {
191
168
  writable: true,
192
169
  value: []
193
170
  });
171
+ Object.defineProperty(this, "earlyChecksDone", {
172
+ enumerable: true,
173
+ configurable: true,
174
+ writable: true,
175
+ value: false
176
+ });
194
177
  Object.defineProperty(this, "localCandidatesStart", {
195
178
  enumerable: true,
196
179
  configurable: true,
@@ -215,66 +198,101 @@ class Connection {
215
198
  writable: true,
216
199
  value: void 0
217
200
  });
201
+ Object.defineProperty(this, "onData", {
202
+ enumerable: true,
203
+ configurable: true,
204
+ writable: true,
205
+ value: new common_1.Event()
206
+ });
207
+ Object.defineProperty(this, "stateChanged", {
208
+ enumerable: true,
209
+ configurable: true,
210
+ writable: true,
211
+ value: new common_1.Event()
212
+ });
213
+ Object.defineProperty(this, "onIceCandidate", {
214
+ enumerable: true,
215
+ configurable: true,
216
+ writable: true,
217
+ value: new common_1.Event()
218
+ });
218
219
  // 4.1.1.4 ? 生存確認 life check
219
220
  Object.defineProperty(this, "queryConsent", {
220
221
  enumerable: true,
221
222
  configurable: true,
222
223
  writable: true,
223
- value: () => new p_cancelable_1.default(async (r, f, onCancel) => {
224
- let failures = 0;
225
- const cancelEvent = new AbortController();
226
- onCancel(() => {
227
- failures += CONSENT_FAILURES;
228
- cancelEvent.abort();
229
- f("cancel");
230
- });
231
- // """
232
- // Periodically check consent (RFC 7675).
233
- // """
234
- try {
235
- while (!this.remoteIsLite && this.state !== "closed") {
236
- // # randomize between 0.8 and 1.2 times CONSENT_INTERVAL
237
- await promises_1.default.setTimeout(CONSENT_INTERVAL * (0.8 + 0.4 * Math.random()) * 1000, undefined, { signal: cancelEvent.signal });
238
- const pair = this.nominated;
239
- if (!pair) {
240
- break;
241
- }
242
- const request = this.buildRequest(pair, false);
243
- try {
244
- const [msg, addr] = await pair.protocol.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"), 0);
245
- failures = 0;
246
- if (this.state === "disconnected") {
247
- this.setState("connected");
224
+ value: () => {
225
+ if (this.queryConsentHandle) {
226
+ this.queryConsentHandle.resolve();
227
+ }
228
+ this.queryConsentHandle = (0, helper_1.cancelable)(async (_, __, onCancel) => {
229
+ let failures = 0;
230
+ let canceled = false;
231
+ const cancelEvent = new AbortController();
232
+ onCancel.once(() => {
233
+ canceled = true;
234
+ failures += iceBase_1.CONSENT_FAILURES;
235
+ cancelEvent.abort();
236
+ this.queryConsentHandle = undefined;
237
+ });
238
+ const { localUsername, remoteUsername, iceControlling } = this;
239
+ // """
240
+ // Periodically check consent (RFC 7675).
241
+ // """
242
+ try {
243
+ while (this.state !== "closed" && !canceled) {
244
+ // # randomize between 0.8 and 1.2 times CONSENT_INTERVAL
245
+ await promises_1.default.setTimeout(iceBase_1.CONSENT_INTERVAL * (0.8 + 0.4 * Math.random()) * 1000, undefined, { signal: cancelEvent.signal });
246
+ const nominated = this.nominated;
247
+ if (!nominated || canceled) {
248
+ break;
249
+ }
250
+ const request = this.buildRequest({
251
+ nominate: false,
252
+ localUsername,
253
+ remoteUsername,
254
+ iceControlling,
255
+ });
256
+ try {
257
+ await nominated.protocol.request(request, nominated.remoteAddr, Buffer.from(this.remotePassword, "utf8"), 0);
258
+ failures = 0;
259
+ if (this.state === "disconnected") {
260
+ this.setState("connected");
261
+ }
262
+ }
263
+ catch (error) {
264
+ if (nominated.id === this.nominated?.id) {
265
+ log("no stun response");
266
+ failures++;
267
+ this.setState("disconnected");
268
+ break;
269
+ }
270
+ }
271
+ if (failures >= iceBase_1.CONSENT_FAILURES) {
272
+ log("Consent to send expired");
273
+ this.queryConsentHandle = undefined;
274
+ this.setState("closed");
275
+ break;
248
276
  }
249
- }
250
- catch (error) {
251
- log("no stun response");
252
- failures++;
253
- this.setState("disconnected");
254
- }
255
- if (failures >= CONSENT_FAILURES) {
256
- log("Consent to send expired");
257
- this.queryConsentHandle = undefined;
258
- // 切断検知
259
- r(await this.close());
260
- return;
261
277
  }
262
278
  }
263
- }
264
- catch (error) { }
265
- })
279
+ catch (error) { }
280
+ });
281
+ }
266
282
  });
267
283
  Object.defineProperty(this, "send", {
268
284
  enumerable: true,
269
285
  configurable: true,
270
286
  writable: true,
271
287
  value: async (data) => {
272
- // """
273
- // Send a datagram on the first component.
274
- // If the connection is not established, a `ConnectionError` is raised.
275
- // :param data: The data to be sent.
276
- // """
277
- await this.sendTo(data);
288
+ const activePair = this.nominated;
289
+ if (activePair) {
290
+ await activePair.protocol.sendData(data, activePair.remoteAddr);
291
+ }
292
+ else {
293
+ // log("Cannot send data, ice not connected");
294
+ return;
295
+ }
278
296
  }
279
297
  });
280
298
  // 3. Terminology : Check
@@ -282,26 +300,42 @@ class Connection {
282
300
  enumerable: true,
283
301
  configurable: true,
284
302
  writable: true,
285
- value: (pair) => new p_cancelable_1.default(async (r, f, onCancel) => {
286
- onCancel(() => f("cancel"));
303
+ value: (pair) => (0, helper_1.cancelable)(async (r) => {
287
304
  // """
288
305
  // Starts a check.
289
306
  // """
290
307
  log("check start", pair.toJSON());
291
- this.setPairState(pair, CandidatePairState.IN_PROGRESS);
292
- const nominate = this.iceControlling && !this.remoteIsLite;
293
- const request = this.buildRequest(pair, nominate);
308
+ pair.updateState(iceBase_1.CandidatePairState.IN_PROGRESS);
294
309
  const result = {};
310
+ const { remotePassword, remoteUsername, generation } = this;
311
+ const localUsername = pair.localCandidate.ufrag ?? this.localUsername;
312
+ const nominate = this.iceControlling && !this.remoteIsLite;
313
+ const request = this.buildRequest({
314
+ nominate,
315
+ localUsername,
316
+ remoteUsername,
317
+ iceControlling: this.iceControlling,
318
+ });
295
319
  try {
296
- const [response, addr] = await pair.protocol.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"), 4);
297
- log("response", response, addr);
320
+ const [response, addr] = await pair.protocol.request(request, pair.remoteAddr, Buffer.from(remotePassword, "utf8"), 4);
321
+ log("response received", request.toJSON(), response.toJSON(), addr, {
322
+ localUsername,
323
+ remoteUsername,
324
+ remotePassword,
325
+ generation,
326
+ });
298
327
  result.response = response;
299
328
  result.addr = addr;
300
329
  }
301
330
  catch (error) {
302
331
  const exc = error;
303
332
  // 7.1.3.1. Failure Cases
304
- log("failure case", exc.response);
333
+ log("failure case", request.toJSON(), exc.response ? JSON.stringify(exc.response.toJSON(), null, 2) : error, {
334
+ localUsername,
335
+ remoteUsername,
336
+ remotePassword,
337
+ generation,
338
+ });
305
339
  if (exc.response?.getAttributeValue("ERROR-CODE")[0] === 487) {
306
340
  if (request.attributesKeys.includes("ICE-CONTROLLED")) {
307
341
  this.switchRole(true);
@@ -309,14 +343,20 @@ class Connection {
309
343
  else if (request.attributesKeys.includes("ICE-CONTROLLING")) {
310
344
  this.switchRole(false);
311
345
  }
312
- await this.checkStart(pair);
346
+ await this.checkStart(pair).awaitable;
347
+ r();
348
+ return;
349
+ }
350
+ if (exc.response?.getAttributeValue("ERROR-CODE")[0] === 401) {
351
+ log("retry 401", pair.toJSON());
352
+ await this.checkStart(pair).awaitable;
313
353
  r();
314
354
  return;
315
355
  }
316
356
  else {
317
357
  // timeout
318
- log("CandidatePairState.FAILED", pair.toJSON());
319
- this.setPairState(pair, CandidatePairState.FAILED);
358
+ log("checkStart CandidatePairState.FAILED", pair.toJSON());
359
+ pair.updateState(iceBase_1.CandidatePairState.FAILED);
320
360
  this.checkComplete(pair);
321
361
  r();
322
362
  return;
@@ -324,7 +364,7 @@ class Connection {
324
364
  }
325
365
  // # check remote address matches
326
366
  if (!(0, isEqual_1.default)(result.addr, pair.remoteAddr)) {
327
- this.setPairState(pair, CandidatePairState.FAILED);
367
+ pair.updateState(iceBase_1.CandidatePairState.FAILED);
328
368
  this.checkComplete(pair);
329
369
  r();
330
370
  return;
@@ -337,18 +377,23 @@ class Connection {
337
377
  else if (this.iceControlling && !this.nominating) {
338
378
  // # perform regular nomination
339
379
  this.nominating = true;
340
- const request = this.buildRequest(pair, true);
380
+ const request = this.buildRequest({
381
+ nominate: true,
382
+ localUsername,
383
+ remoteUsername,
384
+ iceControlling: this.iceControlling,
385
+ });
341
386
  try {
342
387
  await pair.protocol.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"));
343
388
  }
344
389
  catch (error) {
345
- this.setPairState(pair, CandidatePairState.FAILED);
390
+ pair.updateState(iceBase_1.CandidatePairState.FAILED);
346
391
  this.checkComplete(pair);
347
392
  return;
348
393
  }
349
394
  pair.nominated = true;
350
395
  }
351
- this.setPairState(pair, CandidatePairState.SUCCEEDED);
396
+ pair.updateState(iceBase_1.CandidatePairState.SUCCEEDED);
352
397
  this.checkComplete(pair);
353
398
  r();
354
399
  })
@@ -364,14 +409,71 @@ class Connection {
364
409
  }
365
410
  });
366
411
  this.options = {
367
- ...defaultOptions,
412
+ ...iceBase_1.defaultOptions,
368
413
  ...options,
369
414
  };
370
- const { stunServer, turnServer, useIpv4, useIpv6 } = this.options;
371
- this.stunServer = validateAddress(stunServer);
372
- this.turnServer = validateAddress(turnServer);
373
- this.useIpv4 = useIpv4;
374
- this.useIpv6 = useIpv6;
415
+ const { stunServer, turnServer } = this.options;
416
+ this.stunServer = (0, iceBase_1.validateAddress)(stunServer) ?? [
417
+ "stun.l.google.com",
418
+ 19302,
419
+ ];
420
+ this.turnServer = (0, iceBase_1.validateAddress)(turnServer);
421
+ this.restart();
422
+ }
423
+ get iceControlling() {
424
+ return this._iceControlling;
425
+ }
426
+ set iceControlling(value) {
427
+ if (this.generation > 0 || this.nominated) {
428
+ return;
429
+ }
430
+ this._iceControlling = value;
431
+ for (const pair of this.checkList) {
432
+ pair.iceControlling = value;
433
+ }
434
+ }
435
+ async restart() {
436
+ this.generation++;
437
+ this.localUsername = (0, helper_1.randomString)(4);
438
+ this.localPassword = (0, helper_1.randomString)(22);
439
+ if (this.options.localPasswordPrefix) {
440
+ this.localPassword =
441
+ this.options.localPasswordPrefix +
442
+ this.localPassword.slice(this.options.localPasswordPrefix.length);
443
+ }
444
+ this.userHistory[this.localUsername] = this.localPassword;
445
+ this.remoteUsername = "";
446
+ this.remotePassword = "";
447
+ this.localCandidates = [];
448
+ this._remoteCandidates = [];
449
+ this.remoteCandidatesEnd = false;
450
+ this.localCandidatesEnd = false;
451
+ this.state = "new";
452
+ this.lookup?.close?.();
453
+ this.lookup = undefined;
454
+ this.nominated = undefined;
455
+ this.nominating = false;
456
+ this.checkList = [];
457
+ this.checkListDone = false;
458
+ this.checkListState = new helper_1.PQueue();
459
+ this.earlyChecks = [];
460
+ this.earlyChecksDone = false;
461
+ this.localCandidatesStart = false;
462
+ // protocolsはincomingのearlyCheckに使うかもしれないので残す
463
+ for (const protocol of this.protocols) {
464
+ if (protocol.localCandidate) {
465
+ protocol.localCandidate.generation = this.generation;
466
+ protocol.localCandidate.ufrag = this.localUsername;
467
+ }
468
+ }
469
+ this.queryConsentHandle?.resolve?.();
470
+ this.queryConsentHandle = undefined;
471
+ this.promiseGatherCandidates = undefined;
472
+ }
473
+ resetNominatedPair() {
474
+ log("resetNominatedPair");
475
+ this.nominated = undefined;
476
+ this.nominating = false;
375
477
  }
376
478
  setRemoteParams({ iceLite, usernameFragment, password, }) {
377
479
  log("setRemoteParams", { iceLite, usernameFragment, password });
@@ -380,11 +482,11 @@ class Connection {
380
482
  this.remotePassword = password;
381
483
  }
382
484
  // 4.1.1 Gathering Candidates
383
- async gatherCandidates(cb) {
485
+ async gatherCandidates() {
384
486
  if (!this.localCandidatesStart) {
385
487
  this.localCandidatesStart = true;
386
- this.promiseGatherCandidates = new rx_mini_1.Event();
387
- let address = (0, utils_1.getHostAddresses)(this.useIpv4, this.useIpv6);
488
+ this.promiseGatherCandidates = new common_1.Event();
489
+ let address = (0, utils_1.getHostAddresses)(this.options.useIpv4, this.options.useIpv6);
388
490
  const { interfaceAddresses } = this.options;
389
491
  if (interfaceAddresses) {
390
492
  const filteredAddresses = address.filter((check) => Object.values(interfaceAddresses).includes(check));
@@ -395,18 +497,86 @@ class Connection {
395
497
  if (this.options.additionalHostAddresses) {
396
498
  address = Array.from(new Set([...this.options.additionalHostAddresses, ...address]));
397
499
  }
398
- const candidates = await this.getCandidates(address, 5, cb);
500
+ const candidates = await this.getCandidates(address, 5);
399
501
  this.localCandidates = [...this.localCandidates, ...candidates];
400
- this._localCandidatesEnd = true;
502
+ this.localCandidatesEnd = true;
401
503
  this.promiseGatherCandidates.execute();
402
504
  }
403
505
  this.setState("completed");
404
506
  }
405
- async getCandidates(addresses, timeout = 5, cb) {
507
+ ensureProtocol(protocol) {
508
+ protocol.onRequestReceived.subscribe((msg, addr, data) => {
509
+ if (msg.messageMethod !== const_1.methods.BINDING) {
510
+ this.respondError(msg, addr, protocol, [400, "Bad Request"]);
511
+ return;
512
+ }
513
+ const txUsername = msg.getAttributeValue("USERNAME");
514
+ // 相手にとってのremoteは自分にとってのlocal
515
+ const { remoteUsername: localUsername } = decodeTxUsername(txUsername);
516
+ const localPassword = this.userHistory[localUsername] ?? this.localPassword;
517
+ const { iceControlling } = this;
518
+ // 7.2.1.1. Detecting and Repairing Role Conflicts
519
+ if (iceControlling && msg.attributesKeys.includes("ICE-CONTROLLING")) {
520
+ if (this.tieBreaker >= msg.getAttributeValue("ICE-CONTROLLING")) {
521
+ this.respondError(msg, addr, protocol, [487, "Role Conflict"]);
522
+ return;
523
+ }
524
+ else {
525
+ this.switchRole(false);
526
+ }
527
+ }
528
+ else if (!iceControlling &&
529
+ msg.attributesKeys.includes("ICE-CONTROLLED")) {
530
+ if (this.tieBreaker < msg.getAttributeValue("ICE-CONTROLLED")) {
531
+ this.respondError(msg, addr, protocol, [487, "Role Conflict"]);
532
+ }
533
+ else {
534
+ this.switchRole(true);
535
+ return;
536
+ }
537
+ }
538
+ if (this.options.filterStunResponse &&
539
+ !this.options.filterStunResponse(msg, addr, protocol)) {
540
+ return;
541
+ }
542
+ // # send binding response
543
+ const response = new message_1.Message(const_1.methods.BINDING, const_1.classes.RESPONSE, msg.transactionId);
544
+ response
545
+ .setAttribute("XOR-MAPPED-ADDRESS", addr)
546
+ .addMessageIntegrity(Buffer.from(localPassword, "utf8"))
547
+ .addFingerprint();
548
+ protocol.sendStun(response, addr).catch((e) => {
549
+ log("sendStun error", e);
550
+ });
551
+ if (this.checkList.length === 0 && !this.earlyChecksDone) {
552
+ this.earlyChecks.push([msg, addr, protocol]);
553
+ }
554
+ else {
555
+ this.checkIncoming(msg, addr, protocol);
556
+ }
557
+ });
558
+ protocol.onDataReceived.subscribe((data) => {
559
+ try {
560
+ this.onData.execute(data);
561
+ }
562
+ catch (error) {
563
+ log("dataReceived", error);
564
+ }
565
+ });
566
+ }
567
+ async getCandidates(addresses, timeout = 5) {
406
568
  let candidates = [];
569
+ addresses = addresses.filter((address) => {
570
+ // ice restartで同じアドレスが追加されるのを防ぐ
571
+ if (this.protocols.find((protocol) => protocol.localIp === address)) {
572
+ return false;
573
+ }
574
+ return true;
575
+ });
407
576
  await Promise.allSettled(addresses.map(async (address) => {
408
577
  // # create transport
409
- const protocol = new protocol_1.StunProtocol(this);
578
+ const protocol = new protocol_1.StunProtocol();
579
+ this.ensureProtocol(protocol);
410
580
  try {
411
581
  await protocol.connectionMade((0, net_1.isIPv4)(address), this.options.portRange, this.options.interfaceAddresses);
412
582
  }
@@ -414,16 +584,14 @@ class Connection {
414
584
  log("protocol STUN", error);
415
585
  return;
416
586
  }
417
- protocol.localAddress = address;
587
+ protocol.localIp = address;
418
588
  this.protocols.push(protocol);
419
589
  // # add host candidate
420
590
  const candidateAddress = [address, protocol.getExtraInfo()[1]];
421
- protocol.localCandidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("host", "udp", candidateAddress[0]), 1, "udp", (0, candidate_1.candidatePriority)(1, "host"), candidateAddress[0], candidateAddress[1], "host");
591
+ protocol.localCandidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("host", "udp", candidateAddress[0]), 1, "udp", (0, candidate_1.candidatePriority)("host"), candidateAddress[0], candidateAddress[1], "host", undefined, undefined, undefined, this.generation, this.localUsername);
422
592
  this.pairLocalProtocol(protocol);
423
593
  candidates.push(protocol.localCandidate);
424
- if (cb) {
425
- cb(protocol.localCandidate);
426
- }
594
+ this.onIceCandidate.execute(protocol.localCandidate);
427
595
  }));
428
596
  let candidatePromises = [];
429
597
  // # query STUN server for server-reflexive candidates (IPv4 only)
@@ -433,9 +601,12 @@ class Connection {
433
601
  const timer = setTimeout(f, timeout * 1000);
434
602
  if (protocol.localCandidate?.host &&
435
603
  (0, net_1.isIPv4)(protocol.localCandidate?.host)) {
436
- const candidate = await serverReflexiveCandidate(protocol, stunServer).catch((error) => log("error", error));
437
- if (candidate && cb)
438
- cb(candidate);
604
+ const candidate = await (0, iceBase_1.serverReflexiveCandidate)(protocol, stunServer).catch((error) => {
605
+ log("error", error);
606
+ });
607
+ if (candidate) {
608
+ this.onIceCandidate.execute(candidate);
609
+ }
439
610
  clearTimeout(timer);
440
611
  r(candidate);
441
612
  }
@@ -451,19 +622,37 @@ class Connection {
451
622
  const { turnUsername, turnPassword } = this.options;
452
623
  if (turnServer && turnUsername && turnPassword) {
453
624
  const turnCandidate = (async () => {
454
- const protocol = await (0, protocol_2.createTurnEndpoint)(turnServer, turnUsername, turnPassword, {
625
+ const protocol = await (0, protocol_2.createStunOverTurnClient)({
626
+ address: turnServer,
627
+ username: turnUsername,
628
+ password: turnPassword,
629
+ }, {
455
630
  portRange: this.options.portRange,
456
631
  interfaceAddresses: this.options.interfaceAddresses,
632
+ transport: this.options.turnTransport === "tcp" ? "tcp" : "udp",
633
+ }).catch(async (e) => {
634
+ if (this.options.turnTransport !== "tcp") {
635
+ return await (0, protocol_2.createStunOverTurnClient)({
636
+ address: turnServer,
637
+ username: turnUsername,
638
+ password: turnPassword,
639
+ }, {
640
+ portRange: this.options.portRange,
641
+ interfaceAddresses: this.options.interfaceAddresses,
642
+ transport: "tcp",
643
+ });
644
+ }
645
+ else {
646
+ throw e;
647
+ }
457
648
  });
649
+ this.ensureProtocol(protocol);
458
650
  this.protocols.push(protocol);
459
651
  const candidateAddress = protocol.turn.relayedAddress;
460
652
  const relatedAddress = protocol.turn.mappedAddress;
461
653
  log("turn candidateAddress", candidateAddress);
462
- protocol.localCandidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("relay", "udp", candidateAddress[0]), 1, "udp", (0, candidate_1.candidatePriority)(1, "relay"), candidateAddress[0], candidateAddress[1], "relay", relatedAddress[0], relatedAddress[1]);
463
- if (cb) {
464
- cb(protocol.localCandidate);
465
- }
466
- protocol.receiver = this;
654
+ protocol.localCandidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("relay", "udp", candidateAddress[0]), 1, "udp", (0, candidate_1.candidatePriority)("relay"), candidateAddress[0], candidateAddress[1], "relay", relatedAddress[0], relatedAddress[1], undefined, this.generation, this.localUsername);
655
+ this.onIceCandidate.execute(protocol.localCandidate);
467
656
  return protocol.localCandidate;
468
657
  })().catch((error) => {
469
658
  log("query TURN server", error);
@@ -488,23 +677,32 @@ class Connection {
488
677
  // This coroutine returns if a candidate pair was successfully nominated
489
678
  // and raises an exception otherwise.
490
679
  // """
491
- log("start connect ice", this.localCandidates);
492
- if (!this._localCandidatesEnd) {
493
- if (!this.localCandidatesStart)
680
+ log("start connect ice");
681
+ if (!this.localCandidatesEnd) {
682
+ if (!this.localCandidatesStart) {
494
683
  throw new Error("Local candidates gathering was not performed");
495
- if (this.promiseGatherCandidates)
684
+ }
685
+ if (this.promiseGatherCandidates) {
496
686
  // wait for GatherCandidates finish
497
687
  await this.promiseGatherCandidates.asPromise();
688
+ }
498
689
  }
499
- if (!this.remoteUsername || !this.remotePassword)
690
+ if (!this.remoteUsername || !this.remotePassword) {
500
691
  throw new Error("Remote username or password is missing");
692
+ }
501
693
  // # 5.7.1. Forming Candidate Pairs
502
- this.remoteCandidates.forEach(this.pairRemoteCandidate);
694
+ for (const c of this.remoteCandidates) {
695
+ this.pairRemoteCandidate(c);
696
+ }
503
697
  this.sortCheckList();
504
698
  this.unfreezeInitial();
699
+ log("earlyChecks", this.localPassword, this.earlyChecks.length);
505
700
  // # handle early checks
506
- this.earlyChecks.forEach((earlyCheck) => this.checkIncoming(...earlyCheck));
701
+ for (const earlyCheck of this.earlyChecks) {
702
+ this.checkIncoming(...earlyCheck);
703
+ }
507
704
  this.earlyChecks = [];
705
+ this.earlyChecksDone = true;
508
706
  // # perform checks
509
707
  // 5.8. Scheduling Checks
510
708
  for (;;) {
@@ -515,17 +713,19 @@ class Connection {
515
713
  await promises_1.default.setTimeout(20);
516
714
  }
517
715
  // # wait for completion
518
- let res = ICE_FAILED;
519
- while (this.checkList.length > 0 && res === ICE_FAILED) {
716
+ let res = iceBase_1.ICE_FAILED;
717
+ while (this.checkList.length > 0 && res === iceBase_1.ICE_FAILED) {
520
718
  res = await this.checkListState.get();
521
719
  }
522
720
  // # cancel remaining checks
523
- this.checkList.forEach((check) => check.handle?.cancel());
524
- if (res !== ICE_COMPLETED) {
721
+ for (const check of this.checkList) {
722
+ check.handle?.resolve?.();
723
+ }
724
+ if (res !== iceBase_1.ICE_COMPLETED) {
525
725
  throw new Error("ICE negotiation failed");
526
726
  }
527
727
  // # start consent freshness tests
528
- this.queryConsentHandle = (0, helper_1.future)(this.queryConsent());
728
+ this.queryConsent();
529
729
  this.setState("connected");
530
730
  }
531
731
  unfreezeInitial() {
@@ -533,16 +733,16 @@ class Connection {
533
733
  const [firstPair] = this.checkList;
534
734
  if (!firstPair)
535
735
  return;
536
- if (firstPair.state === CandidatePairState.FROZEN) {
537
- this.setPairState(firstPair, CandidatePairState.WAITING);
736
+ if (firstPair.state === iceBase_1.CandidatePairState.FROZEN) {
737
+ firstPair.updateState(iceBase_1.CandidatePairState.WAITING);
538
738
  }
539
739
  // # unfreeze pairs with same component but different foundations
540
740
  const seenFoundations = new Set(firstPair.localCandidate.foundation);
541
741
  for (const pair of this.checkList) {
542
742
  if (pair.component === firstPair.component &&
543
743
  !seenFoundations.has(pair.localCandidate.foundation) &&
544
- pair.state === CandidatePairState.FROZEN) {
545
- this.setPairState(pair, CandidatePairState.WAITING);
744
+ pair.state === iceBase_1.CandidatePairState.FROZEN) {
745
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
546
746
  seenFoundations.add(pair.localCandidate.foundation);
547
747
  }
548
748
  }
@@ -554,21 +754,22 @@ class Connection {
554
754
  // # find the highest-priority pair that is in the waiting state
555
755
  const pair = this.checkList
556
756
  .filter((pair) => {
557
- if (this.options.forceTurn && pair.protocol.type === "stun")
757
+ if (this.options.forceTurn &&
758
+ pair.protocol.type === protocol_1.StunProtocol.type)
558
759
  return false;
559
760
  return true;
560
761
  })
561
- .find((pair) => pair.state === CandidatePairState.WAITING);
762
+ .find((pair) => pair.state === iceBase_1.CandidatePairState.WAITING);
562
763
  if (pair) {
563
- pair.handle = (0, helper_1.future)(this.checkStart(pair));
764
+ pair.handle = this.checkStart(pair);
564
765
  return true;
565
766
  }
566
767
  }
567
768
  {
568
769
  // # find the highest-priority pair that is in the frozen state
569
- const pair = this.checkList.find((pair) => pair.state === CandidatePairState.FROZEN);
770
+ const pair = this.checkList.find((pair) => pair.state === iceBase_1.CandidatePairState.FROZEN);
570
771
  if (pair) {
571
- pair.handle = (0, helper_1.future)(this.checkStart(pair));
772
+ pair.handle = this.checkStart(pair);
572
773
  return true;
573
774
  }
574
775
  }
@@ -584,19 +785,11 @@ class Connection {
584
785
  // """
585
786
  this.setState("closed");
586
787
  // # stop consent freshness tests
587
- if (this.queryConsentHandle && !this.queryConsentHandle.done()) {
588
- this.queryConsentHandle.cancel();
589
- try {
590
- await this.queryConsentHandle.promise;
591
- }
592
- catch (error) {
593
- // pass
594
- }
595
- }
788
+ this.queryConsentHandle?.resolve?.();
596
789
  // # stop check list
597
790
  if (this.checkList && !this.checkListDone) {
598
791
  this.checkListState.put(new Promise((r) => {
599
- r(ICE_FAILED);
792
+ r(iceBase_1.ICE_FAILED);
600
793
  }));
601
794
  }
602
795
  this.nominated = undefined;
@@ -607,7 +800,8 @@ class Connection {
607
800
  }
608
801
  this.protocols = [];
609
802
  this.localCandidates = [];
610
- await this.lookup?.close();
803
+ this.lookup?.close?.();
804
+ this.lookup = undefined;
611
805
  }
612
806
  setState(state) {
613
807
  this.state = state;
@@ -625,8 +819,6 @@ class Connection {
625
819
  }
626
820
  if (remoteCandidate.host.includes(".local")) {
627
821
  try {
628
- if (this.state === "closed")
629
- return;
630
822
  if (!this.lookup) {
631
823
  this.lookup = new lookup_1.MdnsLookup();
632
824
  }
@@ -638,105 +830,21 @@ class Connection {
638
830
  }
639
831
  }
640
832
  try {
641
- validateRemoteCandidate(remoteCandidate);
833
+ (0, iceBase_1.validateRemoteCandidate)(remoteCandidate);
642
834
  }
643
835
  catch (error) {
644
836
  return;
645
837
  }
646
838
  log("addRemoteCandidate", remoteCandidate);
647
- this.remoteCandidates.push(remoteCandidate);
839
+ this._remoteCandidates.push(remoteCandidate);
648
840
  this.pairRemoteCandidate(remoteCandidate);
649
841
  this.sortCheckList();
650
842
  }
651
- async sendTo(data) {
652
- // """
653
- // Send a datagram on the specified component.
654
- // If the connection is not established, a `ConnectionError` is raised.
655
- // :param data: The data to be sent.
656
- // :param component: The component on which to send the data.
657
- // """
658
- const activePair = this.nominated;
659
- if (activePair) {
660
- await activePair.protocol.sendData(data, activePair.remoteAddr);
661
- }
662
- else {
663
- // log("Cannot send data, ice not connected");
664
- return;
665
- }
666
- }
667
843
  getDefaultCandidate() {
668
844
  const candidates = this.localCandidates.sort((a, b) => a.priority - b.priority);
669
845
  const [candidate] = candidates;
670
846
  return candidate;
671
847
  }
672
- requestReceived(message, addr, protocol, rawData) {
673
- if (message.messageMethod !== const_1.methods.BINDING) {
674
- this.respondError(message, addr, protocol, [400, "Bad Request"]);
675
- return;
676
- }
677
- // # authenticate request
678
- try {
679
- (0, message_1.parseMessage)(rawData, Buffer.from(this.localPassword, "utf8"));
680
- if (!this.remoteUsername) {
681
- const rxUsername = `${this.localUserName}:${this.remoteUsername}`;
682
- if (message.getAttributeValue("USERNAME") != rxUsername) {
683
- throw new Error("Wrong username");
684
- }
685
- }
686
- }
687
- catch (error) {
688
- this.respondError(message, addr, protocol, [400, "Bad Request"]);
689
- return;
690
- }
691
- const { iceControlling } = this;
692
- // 7.2.1.1. Detecting and Repairing Role Conflicts
693
- if (iceControlling && message.attributesKeys.includes("ICE-CONTROLLING")) {
694
- if (this._tieBreaker >= message.getAttributeValue("ICE-CONTROLLING")) {
695
- this.respondError(message, addr, protocol, [487, "Role Conflict"]);
696
- return;
697
- }
698
- else {
699
- this.switchRole(false);
700
- }
701
- }
702
- else if (!iceControlling &&
703
- message.attributesKeys.includes("ICE-CONTROLLED")) {
704
- if (this._tieBreaker < message.getAttributeValue("ICE-CONTROLLED")) {
705
- this.respondError(message, addr, protocol, [487, "Role Conflict"]);
706
- }
707
- else {
708
- this.switchRole(true);
709
- return;
710
- }
711
- }
712
- if (this.options.filterStunResponse &&
713
- !this.options.filterStunResponse(message, addr, protocol)) {
714
- return;
715
- }
716
- // # send binding response
717
- const response = new message_1.Message(const_1.methods.BINDING, const_1.classes.RESPONSE, message.transactionId);
718
- response
719
- .setAttribute("XOR-MAPPED-ADDRESS", addr)
720
- .addMessageIntegrity(Buffer.from(this.localPassword, "utf8"))
721
- .addFingerprint();
722
- protocol.sendStun(response, addr).catch((e) => {
723
- log("sendStun error", e);
724
- });
725
- // todo fix
726
- // if (this.checkList.length === 0) {
727
- // this.earlyChecks.push([message, addr, protocol]);
728
- // } else {
729
- this.checkIncoming(message, addr, protocol);
730
- // }
731
- }
732
- dataReceived(data, component) {
733
- try {
734
- this.onData.execute(data, component);
735
- }
736
- catch (error) {
737
- log("dataReceived", error);
738
- }
739
- }
740
848
  // for test only
741
849
  set remoteCandidates(value) {
742
850
  if (this.remoteCandidatesEnd)
@@ -744,12 +852,12 @@ class Connection {
744
852
  this._remoteCandidates = [];
745
853
  for (const remoteCandidate of value) {
746
854
  try {
747
- validateRemoteCandidate(remoteCandidate);
855
+ (0, iceBase_1.validateRemoteCandidate)(remoteCandidate);
748
856
  }
749
857
  catch (error) {
750
858
  continue;
751
859
  }
752
- this.remoteCandidates.push(remoteCandidate);
860
+ this._remoteCandidates.push(remoteCandidate);
753
861
  }
754
862
  this.remoteCandidatesEnd = true;
755
863
  }
@@ -757,36 +865,32 @@ class Connection {
757
865
  return this._remoteCandidates;
758
866
  }
759
867
  sortCheckList() {
760
- sortCandidatePairs(this.checkList, this.iceControlling);
868
+ (0, iceBase_1.sortCandidatePairs)(this.checkList, this.iceControlling);
761
869
  }
762
870
  findPair(protocol, remoteCandidate) {
763
871
  const pair = this.checkList.find((pair) => (0, isEqual_1.default)(pair.protocol, protocol) &&
764
872
  (0, isEqual_1.default)(pair.remoteCandidate, remoteCandidate));
765
873
  return pair;
766
874
  }
767
- setPairState(pair, state) {
768
- log("setPairState", pair.toJSON(), CandidatePairState[state]);
769
- pair.updateState(state);
770
- }
771
875
  switchRole(iceControlling) {
772
876
  log("switch role", iceControlling);
773
877
  this.iceControlling = iceControlling;
774
878
  this.sortCheckList();
775
879
  }
776
- resetNominatedPair() {
777
- log("resetNominatedPair");
778
- this.nominated = undefined;
779
- this.nominating = false;
780
- }
781
880
  checkComplete(pair) {
782
881
  pair.handle = undefined;
783
- if (pair.state === CandidatePairState.SUCCEEDED) {
882
+ if (pair.state === iceBase_1.CandidatePairState.SUCCEEDED) {
784
883
  // Updating the Nominated Flag
785
884
  // https://www.rfc-editor.org/rfc/rfc8445#section-7.3.1.5,
786
885
  // Once the nominated flag is set for a component of a data stream, it
787
886
  // concludes the ICE processing for that component. See Section 8.
788
887
  // So disallow overwriting of the pair nominated for that component
789
- if (pair.nominated && this.nominated == undefined) {
888
+ if (pair.nominated &&
889
+ // remoteのgenerationをチェックする.localのgenerationは更新が間に合わないかもしれないのでチェックしない
890
+ (pair.remoteCandidate.generation != undefined
891
+ ? pair.remoteCandidate.generation === this.generation
892
+ : true) &&
893
+ this.nominated == undefined) {
790
894
  log("nominated", pair.toJSON());
791
895
  this.nominated = pair;
792
896
  this.nominating = false;
@@ -796,8 +900,8 @@ class Connection {
796
900
  // nominated pairs for that media stream.
797
901
  for (const p of this.checkList) {
798
902
  if (p.component === pair.component &&
799
- [CandidatePairState.WAITING, CandidatePairState.FROZEN].includes(p.state)) {
800
- this.setPairState(p, CandidatePairState.FAILED);
903
+ [iceBase_1.CandidatePairState.WAITING, iceBase_1.CandidatePairState.FROZEN].includes(p.state)) {
904
+ p.updateState(iceBase_1.CandidatePairState.FAILED);
801
905
  }
802
906
  }
803
907
  }
@@ -807,27 +911,28 @@ class Connection {
807
911
  if (this.nominated) {
808
912
  if (!this.checkListDone) {
809
913
  log("ICE completed");
810
- this.checkListState.put(new Promise((r) => r(ICE_COMPLETED)));
914
+ this.checkListState.put(new Promise((r) => r(iceBase_1.ICE_COMPLETED)));
811
915
  this.checkListDone = true;
812
916
  }
813
917
  return;
814
918
  }
919
+ log("not completed", pair.toJSON());
815
920
  // 7.1.3.2.3. Updating Pair States
816
921
  for (const p of this.checkList) {
817
922
  if (p.localCandidate.foundation === pair.localCandidate.foundation &&
818
- p.state === CandidatePairState.FROZEN) {
819
- this.setPairState(p, CandidatePairState.WAITING);
923
+ p.state === iceBase_1.CandidatePairState.FROZEN) {
924
+ p.updateState(iceBase_1.CandidatePairState.WAITING);
820
925
  }
821
926
  }
822
927
  }
823
928
  {
824
- const list = [CandidatePairState.SUCCEEDED, CandidatePairState.FAILED];
929
+ const list = [iceBase_1.CandidatePairState.SUCCEEDED, iceBase_1.CandidatePairState.FAILED];
825
930
  if (this.checkList.find(({ state }) => !list.includes(state))) {
826
931
  return;
827
932
  }
828
933
  }
829
934
  if (!this.iceControlling) {
830
- const target = CandidatePairState.SUCCEEDED;
935
+ const target = iceBase_1.CandidatePairState.SUCCEEDED;
831
936
  if (this.checkList.find(({ state }) => state === target)) {
832
937
  return;
833
938
  }
@@ -835,17 +940,22 @@ class Connection {
835
940
  if (!this.checkListDone) {
836
941
  log("ICE failed");
837
942
  this.checkListState.put(new Promise((r) => {
838
- r(ICE_FAILED);
943
+ r(iceBase_1.ICE_FAILED);
839
944
  }));
840
945
  }
841
946
  }
947
+ addPair(pair) {
948
+ this.checkList.push(pair);
949
+ this.sortCheckList();
950
+ }
842
951
  // 7.2. STUN Server Procedures
843
952
  // 7.2.1.3、7.2.1.4、および7.2.1.5
844
953
  checkIncoming(message, addr, protocol) {
845
- // log("checkIncoming", message.toJSON(), addr);
846
954
  // """
847
955
  // Handle a successful incoming check.
848
956
  // """
957
+ const txUsername = message.getAttributeValue("USERNAME");
958
+ const { remoteUsername: localUsername } = decodeTxUsername(txUsername);
849
959
  // find remote candidate
850
960
  let remoteCandidate;
851
961
  const [host, port] = addr;
@@ -857,20 +967,27 @@ class Connection {
857
967
  }
858
968
  if (!remoteCandidate) {
859
969
  // 7.2.1.3. Learning Peer Reflexive Candidates
860
- remoteCandidate = new candidate_1.Candidate((0, helper_1.randomString)(10), 1, "udp", message.getAttributeValue("PRIORITY"), host, port, "prflx");
861
- this.remoteCandidates.push(remoteCandidate);
970
+ remoteCandidate = new candidate_1.Candidate((0, helper_1.randomString)(10), 1, "udp", message.getAttributeValue("PRIORITY"), host, port, "prflx", undefined, undefined, undefined, undefined, undefined);
971
+ this._remoteCandidates.push(remoteCandidate);
862
972
  }
863
973
  // find pair
864
974
  let pair = this.findPair(protocol, remoteCandidate);
865
975
  if (!pair) {
866
- pair = new CandidatePair(protocol, remoteCandidate);
867
- this.setPairState(pair, CandidatePairState.WAITING);
868
- this.checkList.push(pair);
869
- this.sortCheckList();
976
+ pair = new iceBase_1.CandidatePair(protocol, remoteCandidate, this.iceControlling);
977
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
978
+ this.addPair(pair);
870
979
  }
980
+ pair.localCandidate.ufrag = localUsername;
981
+ log("Triggered Checks", message.toJSON(), pair.toJSON(), {
982
+ localUsername: this.localUsername,
983
+ remoteUsername: this.remoteUsername,
984
+ localPassword: this.localPassword,
985
+ remotePassword: this.remotePassword,
986
+ generation: this.generation,
987
+ });
871
988
  // 7.2.1.4. Triggered Checks
872
- if ([CandidatePairState.WAITING, CandidatePairState.FAILED].includes(pair.state)) {
873
- pair.handle = (0, helper_1.future)(this.checkStart(pair));
989
+ if ([iceBase_1.CandidatePairState.WAITING, iceBase_1.CandidatePairState.FAILED].includes(pair.state)) {
990
+ pair.handle = this.checkStart(pair);
874
991
  }
875
992
  else {
876
993
  pair;
@@ -879,7 +996,7 @@ class Connection {
879
996
  if (message.attributesKeys.includes("USE-CANDIDATE") &&
880
997
  !this.iceControlling) {
881
998
  pair.remoteNominated = true;
882
- if (pair.state === CandidatePairState.SUCCEEDED) {
999
+ if (pair.state === iceBase_1.CandidatePairState.SUCCEEDED) {
883
1000
  pair.nominated = true;
884
1001
  this.checkComplete(pair);
885
1002
  }
@@ -888,13 +1005,13 @@ class Connection {
888
1005
  tryPair(protocol, remoteCandidate) {
889
1006
  if (protocol.localCandidate?.canPairWith(remoteCandidate) &&
890
1007
  !this.findPair(protocol, remoteCandidate)) {
891
- const pair = new CandidatePair(protocol, remoteCandidate);
1008
+ const pair = new iceBase_1.CandidatePair(protocol, remoteCandidate, this.iceControlling);
892
1009
  if (this.options.filterCandidatePair &&
893
1010
  !this.options.filterCandidatePair(pair)) {
894
1011
  return;
895
1012
  }
896
- this.checkList.push(pair);
897
- this.setPairState(pair, CandidatePairState.WAITING);
1013
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
1014
+ this.addPair(pair);
898
1015
  }
899
1016
  }
900
1017
  pairLocalProtocol(protocol) {
@@ -902,20 +1019,20 @@ class Connection {
902
1019
  this.tryPair(protocol, remoteCandidate);
903
1020
  }
904
1021
  }
905
- buildRequest(pair, nominate) {
906
- const txUsername = `${this.remoteUsername}:${this.localUserName}`;
1022
+ buildRequest({ nominate, remoteUsername, localUsername, iceControlling, }) {
1023
+ const txUsername = encodeTxUsername({ remoteUsername, localUsername });
907
1024
  const request = new message_1.Message(const_1.methods.BINDING, const_1.classes.REQUEST);
908
1025
  request
909
1026
  .setAttribute("USERNAME", txUsername)
910
- .setAttribute("PRIORITY", (0, candidate_1.candidatePriority)(pair.component, "prflx"));
911
- if (this.iceControlling) {
912
- request.setAttribute("ICE-CONTROLLING", this._tieBreaker);
1027
+ .setAttribute("PRIORITY", (0, candidate_1.candidatePriority)("prflx"));
1028
+ if (iceControlling) {
1029
+ request.setAttribute("ICE-CONTROLLING", this.tieBreaker);
913
1030
  if (nominate) {
914
1031
  request.setAttribute("USE-CANDIDATE", null);
915
1032
  }
916
1033
  }
917
1034
  else {
918
- request.setAttribute("ICE-CONTROLLED", this._tieBreaker);
1035
+ request.setAttribute("ICE-CONTROLLED", this.tieBreaker);
919
1036
  }
920
1037
  return request;
921
1038
  }
@@ -931,128 +1048,11 @@ class Connection {
931
1048
  }
932
1049
  }
933
1050
  exports.Connection = Connection;
934
- class CandidatePair {
935
- get state() {
936
- return this._state;
937
- }
938
- toJSON() {
939
- return {
940
- protocol: this.protocol.type,
941
- remoteAddr: this.remoteAddr,
942
- };
943
- }
944
- constructor(protocol, remoteCandidate) {
945
- Object.defineProperty(this, "protocol", {
946
- enumerable: true,
947
- configurable: true,
948
- writable: true,
949
- value: protocol
950
- });
951
- Object.defineProperty(this, "remoteCandidate", {
952
- enumerable: true,
953
- configurable: true,
954
- writable: true,
955
- value: remoteCandidate
956
- });
957
- Object.defineProperty(this, "handle", {
958
- enumerable: true,
959
- configurable: true,
960
- writable: true,
961
- value: void 0
962
- });
963
- Object.defineProperty(this, "nominated", {
964
- enumerable: true,
965
- configurable: true,
966
- writable: true,
967
- value: false
968
- });
969
- Object.defineProperty(this, "remoteNominated", {
970
- enumerable: true,
971
- configurable: true,
972
- writable: true,
973
- value: false
974
- });
975
- // 5.7.4. Computing States
976
- Object.defineProperty(this, "_state", {
977
- enumerable: true,
978
- configurable: true,
979
- writable: true,
980
- value: CandidatePairState.FROZEN
981
- });
982
- }
983
- updateState(state) {
984
- this._state = state;
985
- }
986
- get localCandidate() {
987
- if (!this.protocol.localCandidate)
988
- throw new Error("localCandidate not exist");
989
- return this.protocol.localCandidate;
990
- }
991
- get remoteAddr() {
992
- return [this.remoteCandidate.host, this.remoteCandidate.port];
993
- }
994
- get component() {
995
- return this.localCandidate.component;
996
- }
997
- }
998
- exports.CandidatePair = CandidatePair;
999
- const ICE_COMPLETED = 1;
1000
- const ICE_FAILED = 2;
1001
- const CONSENT_INTERVAL = 5;
1002
- const CONSENT_FAILURES = 6;
1003
- var CandidatePairState;
1004
- (function (CandidatePairState) {
1005
- CandidatePairState[CandidatePairState["FROZEN"] = 0] = "FROZEN";
1006
- CandidatePairState[CandidatePairState["WAITING"] = 1] = "WAITING";
1007
- CandidatePairState[CandidatePairState["IN_PROGRESS"] = 2] = "IN_PROGRESS";
1008
- CandidatePairState[CandidatePairState["SUCCEEDED"] = 3] = "SUCCEEDED";
1009
- CandidatePairState[CandidatePairState["FAILED"] = 4] = "FAILED";
1010
- })(CandidatePairState || (exports.CandidatePairState = CandidatePairState = {}));
1011
- const defaultOptions = {
1012
- useIpv4: true,
1013
- useIpv6: true,
1051
+ const encodeTxUsername = ({ remoteUsername, localUsername, }) => {
1052
+ return `${remoteUsername}:${localUsername}`;
1053
+ };
1054
+ const decodeTxUsername = (txUsername) => {
1055
+ const [remoteUsername, localUsername] = txUsername.split(":");
1056
+ return { remoteUsername, localUsername };
1014
1057
  };
1015
- function validateRemoteCandidate(candidate) {
1016
- // """
1017
- // Check the remote candidate is supported.
1018
- // """
1019
- if (!["host", "relay", "srflx"].includes(candidate.type))
1020
- throw new Error(`Unexpected candidate type "${candidate.type}"`);
1021
- // ipaddress.ip_address(candidate.host)
1022
- return candidate;
1023
- }
1024
- function sortCandidatePairs(pairs, iceControlling) {
1025
- pairs.sort((a, b) => candidatePairPriority(a.localCandidate, a.remoteCandidate, iceControlling) -
1026
- candidatePairPriority(b.localCandidate, b.remoteCandidate, iceControlling));
1027
- }
1028
- // 5.7.2. Computing Pair Priority and Ordering Pairs
1029
- function candidatePairPriority(local, remote, iceControlling) {
1030
- const G = (iceControlling && local.priority) || remote.priority;
1031
- const D = (iceControlling && remote.priority) || local.priority;
1032
- return (1 << 32) * Math.min(G, D) + 2 * Math.max(G, D) + (G > D ? 1 : 0);
1033
- }
1034
- async function serverReflexiveCandidate(protocol, stunServer) {
1035
- // """
1036
- // Query STUN server to obtain a server-reflexive candidate.
1037
- // """
1038
- // # perform STUN query
1039
- const request = new message_1.Message(const_1.methods.BINDING, const_1.classes.REQUEST);
1040
- try {
1041
- const [response] = await protocol.request(request, stunServer);
1042
- const localCandidate = protocol.localCandidate;
1043
- if (!localCandidate)
1044
- throw new Error("not exist");
1045
- return new candidate_1.Candidate((0, candidate_1.candidateFoundation)("srflx", "udp", localCandidate.host), localCandidate.component, localCandidate.transport, (0, candidate_1.candidatePriority)(localCandidate.component, "srflx"), response.getAttributeValue("XOR-MAPPED-ADDRESS")[0], response.getAttributeValue("XOR-MAPPED-ADDRESS")[1], "srflx", localCandidate.host, localCandidate.port);
1046
- }
1047
- catch (error) {
1048
- // todo fix
1049
- log("error serverReflexiveCandidate", error);
1050
- }
1051
- }
1052
- function validateAddress(addr) {
1053
- if (addr && Number.isNaN(addr[1])) {
1054
- return [addr[0], 443];
1055
- }
1056
- return addr;
1057
- }
1058
1058
  //# sourceMappingURL=ice.js.map