werift 0.20.1 → 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 (90) hide show
  1. package/lib/common/src/event.js +0 -3
  2. package/lib/common/src/event.js.map +1 -1
  3. package/lib/dtls/src/flight/server/flight2.js +5 -3
  4. package/lib/dtls/src/flight/server/flight2.js.map +1 -1
  5. package/lib/dtls/src/index.d.ts +1 -1
  6. package/lib/dtls/src/index.js.map +1 -1
  7. package/lib/dtls/src/record/receive.js +1 -1
  8. package/lib/dtls/src/record/receive.js.map +1 -1
  9. package/lib/ice/src/candidate.d.ts +2 -1
  10. package/lib/ice/src/candidate.js +17 -4
  11. package/lib/ice/src/candidate.js.map +1 -1
  12. package/lib/ice/src/helper.d.ts +6 -6
  13. package/lib/ice/src/helper.js +18 -15
  14. package/lib/ice/src/helper.js.map +1 -1
  15. package/lib/ice/src/ice.d.ts +28 -75
  16. package/lib/ice/src/ice.js +388 -418
  17. package/lib/ice/src/ice.js.map +1 -1
  18. package/lib/ice/src/iceBase.d.ts +109 -0
  19. package/lib/ice/src/iceBase.js +166 -0
  20. package/lib/ice/src/iceBase.js.map +1 -0
  21. package/lib/ice/src/index.d.ts +1 -0
  22. package/lib/ice/src/index.js +1 -0
  23. package/lib/ice/src/index.js.map +1 -1
  24. package/lib/ice/src/stun/message.d.ts +6 -0
  25. package/lib/ice/src/stun/message.js +4 -0
  26. package/lib/ice/src/stun/message.js.map +1 -1
  27. package/lib/ice/src/stun/protocol.d.ts +5 -6
  28. package/lib/ice/src/stun/protocol.js +18 -18
  29. package/lib/ice/src/stun/protocol.js.map +1 -1
  30. package/lib/ice/src/stun/transaction.js +6 -1
  31. package/lib/ice/src/stun/transaction.js.map +1 -1
  32. package/lib/ice/src/turn/protocol.d.ts +6 -5
  33. package/lib/ice/src/turn/protocol.js +54 -36
  34. package/lib/ice/src/turn/protocol.js.map +1 -1
  35. package/lib/ice/src/types/model.d.ts +4 -0
  36. package/lib/ice/src/types/model.js.map +1 -1
  37. package/lib/rtp/src/extra/container/webm/container.d.ts +3 -1
  38. package/lib/rtp/src/extra/container/webm/container.js +8 -2
  39. package/lib/rtp/src/extra/container/webm/container.js.map +1 -1
  40. package/lib/rtp/src/extra/container/webm/ebml/id.d.ts +6 -0
  41. package/lib/rtp/src/extra/container/webm/ebml/id.js +6 -0
  42. package/lib/rtp/src/extra/container/webm/ebml/id.js.map +1 -1
  43. package/lib/rtp/src/extra/processor/webm.d.ts +11 -16
  44. package/lib/rtp/src/extra/processor/webm.js.map +1 -1
  45. package/lib/rtp/src/extra/processor/webmCallback.d.ts +1 -10
  46. package/lib/rtp/src/extra/processor/webmCallback.js.map +1 -1
  47. package/lib/rtp/src/rtp/headerExtension.d.ts +45 -3
  48. package/lib/rtp/src/rtp/headerExtension.js +15 -0
  49. package/lib/rtp/src/rtp/headerExtension.js.map +1 -1
  50. package/lib/sctp/src/index.d.ts +1 -1
  51. package/lib/sctp/src/index.js.map +1 -1
  52. package/lib/webrtc/src/const.d.ts +2 -2
  53. package/lib/webrtc/src/const.js.map +1 -1
  54. package/lib/webrtc/src/media/extension/rtpExtension.d.ts +1 -0
  55. package/lib/webrtc/src/media/extension/rtpExtension.js +6 -0
  56. package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
  57. package/lib/webrtc/src/media/router.d.ts +0 -3
  58. package/lib/webrtc/src/media/router.js.map +1 -1
  59. package/lib/webrtc/src/media/rtpReceiver.d.ts +1 -2
  60. package/lib/webrtc/src/media/rtpReceiver.js +2 -2
  61. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  62. package/lib/webrtc/src/media/track.d.ts +2 -2
  63. package/lib/webrtc/src/media/track.js.map +1 -1
  64. package/lib/webrtc/src/nonstandard/recorder/index.d.ts +1 -0
  65. package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
  66. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +1 -0
  67. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  68. package/lib/webrtc/src/peerConnection.d.ts +12 -6
  69. package/lib/webrtc/src/peerConnection.js +94 -82
  70. package/lib/webrtc/src/peerConnection.js.map +1 -1
  71. package/lib/webrtc/src/sdp.js +15 -3
  72. package/lib/webrtc/src/sdp.js.map +1 -1
  73. package/lib/webrtc/src/transport/dtls.d.ts +5 -5
  74. package/lib/webrtc/src/transport/dtls.js +7 -18
  75. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  76. package/lib/webrtc/src/transport/ice.d.ts +20 -9
  77. package/lib/webrtc/src/transport/ice.js +97 -32
  78. package/lib/webrtc/src/transport/ice.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/const.ts +2 -2
  81. package/src/media/extension/rtpExtension.ts +6 -0
  82. package/src/media/router.ts +2 -3
  83. package/src/media/rtpReceiver.ts +4 -3
  84. package/src/media/track.ts +7 -2
  85. package/src/nonstandard/recorder/index.ts +1 -0
  86. package/src/nonstandard/recorder/writer/webm.ts +47 -43
  87. package/src/peerConnection.ts +118 -88
  88. package/src/sdp.ts +16 -3
  89. package/src/transport/dtls.ts +11 -9
  90. package/src/transport/ice.ts +73 -26
@@ -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
12
  const promises_1 = __importDefault(require("timers/promises"));
19
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 common_1.Event()
150
- });
151
- Object.defineProperty(this, "stateChanged", {
152
- enumerable: true,
153
- configurable: true,
154
- writable: true,
155
- value: new common_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,17 +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) ?? [
415
+ const { stunServer, turnServer } = this.options;
416
+ this.stunServer = (0, iceBase_1.validateAddress)(stunServer) ?? [
372
417
  "stun.l.google.com",
373
418
  19302,
374
419
  ];
375
- this.turnServer = validateAddress(turnServer);
376
- this.useIpv4 = useIpv4;
377
- this.useIpv6 = useIpv6;
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;
378
477
  }
379
478
  setRemoteParams({ iceLite, usernameFragment, password, }) {
380
479
  log("setRemoteParams", { iceLite, usernameFragment, password });
@@ -383,11 +482,11 @@ class Connection {
383
482
  this.remotePassword = password;
384
483
  }
385
484
  // 4.1.1 Gathering Candidates
386
- async gatherCandidates(cb) {
485
+ async gatherCandidates() {
387
486
  if (!this.localCandidatesStart) {
388
487
  this.localCandidatesStart = true;
389
488
  this.promiseGatherCandidates = new common_1.Event();
390
- let address = (0, utils_1.getHostAddresses)(this.useIpv4, this.useIpv6);
489
+ let address = (0, utils_1.getHostAddresses)(this.options.useIpv4, this.options.useIpv6);
391
490
  const { interfaceAddresses } = this.options;
392
491
  if (interfaceAddresses) {
393
492
  const filteredAddresses = address.filter((check) => Object.values(interfaceAddresses).includes(check));
@@ -398,18 +497,86 @@ class Connection {
398
497
  if (this.options.additionalHostAddresses) {
399
498
  address = Array.from(new Set([...this.options.additionalHostAddresses, ...address]));
400
499
  }
401
- const candidates = await this.getCandidates(address, 5, cb);
500
+ const candidates = await this.getCandidates(address, 5);
402
501
  this.localCandidates = [...this.localCandidates, ...candidates];
403
- this._localCandidatesEnd = true;
502
+ this.localCandidatesEnd = true;
404
503
  this.promiseGatherCandidates.execute();
405
504
  }
406
505
  this.setState("completed");
407
506
  }
408
- 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) {
409
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
+ });
410
576
  await Promise.allSettled(addresses.map(async (address) => {
411
577
  // # create transport
412
- const protocol = new protocol_1.StunProtocol(this);
578
+ const protocol = new protocol_1.StunProtocol();
579
+ this.ensureProtocol(protocol);
413
580
  try {
414
581
  await protocol.connectionMade((0, net_1.isIPv4)(address), this.options.portRange, this.options.interfaceAddresses);
415
582
  }
@@ -417,16 +584,14 @@ class Connection {
417
584
  log("protocol STUN", error);
418
585
  return;
419
586
  }
420
- protocol.localAddress = address;
587
+ protocol.localIp = address;
421
588
  this.protocols.push(protocol);
422
589
  // # add host candidate
423
590
  const candidateAddress = [address, protocol.getExtraInfo()[1]];
424
- 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");
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);
425
592
  this.pairLocalProtocol(protocol);
426
593
  candidates.push(protocol.localCandidate);
427
- if (cb) {
428
- cb(protocol.localCandidate);
429
- }
594
+ this.onIceCandidate.execute(protocol.localCandidate);
430
595
  }));
431
596
  let candidatePromises = [];
432
597
  // # query STUN server for server-reflexive candidates (IPv4 only)
@@ -436,9 +601,12 @@ class Connection {
436
601
  const timer = setTimeout(f, timeout * 1000);
437
602
  if (protocol.localCandidate?.host &&
438
603
  (0, net_1.isIPv4)(protocol.localCandidate?.host)) {
439
- const candidate = await serverReflexiveCandidate(protocol, stunServer).catch((error) => log("error", error));
440
- if (candidate && cb)
441
- 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
+ }
442
610
  clearTimeout(timer);
443
611
  r(candidate);
444
612
  }
@@ -458,7 +626,6 @@ class Connection {
458
626
  address: turnServer,
459
627
  username: turnUsername,
460
628
  password: turnPassword,
461
- ice: this,
462
629
  }, {
463
630
  portRange: this.options.portRange,
464
631
  interfaceAddresses: this.options.interfaceAddresses,
@@ -469,7 +636,6 @@ class Connection {
469
636
  address: turnServer,
470
637
  username: turnUsername,
471
638
  password: turnPassword,
472
- ice: this,
473
639
  }, {
474
640
  portRange: this.options.portRange,
475
641
  interfaceAddresses: this.options.interfaceAddresses,
@@ -480,14 +646,13 @@ class Connection {
480
646
  throw e;
481
647
  }
482
648
  });
649
+ this.ensureProtocol(protocol);
483
650
  this.protocols.push(protocol);
484
651
  const candidateAddress = protocol.turn.relayedAddress;
485
652
  const relatedAddress = protocol.turn.mappedAddress;
486
653
  log("turn candidateAddress", candidateAddress);
487
- 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]);
488
- if (cb) {
489
- cb(protocol.localCandidate);
490
- }
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);
491
656
  return protocol.localCandidate;
492
657
  })().catch((error) => {
493
658
  log("query TURN server", error);
@@ -512,23 +677,32 @@ class Connection {
512
677
  // This coroutine returns if a candidate pair was successfully nominated
513
678
  // and raises an exception otherwise.
514
679
  // """
515
- log("start connect ice", this.localCandidates);
516
- if (!this._localCandidatesEnd) {
517
- if (!this.localCandidatesStart)
680
+ log("start connect ice");
681
+ if (!this.localCandidatesEnd) {
682
+ if (!this.localCandidatesStart) {
518
683
  throw new Error("Local candidates gathering was not performed");
519
- if (this.promiseGatherCandidates)
684
+ }
685
+ if (this.promiseGatherCandidates) {
520
686
  // wait for GatherCandidates finish
521
687
  await this.promiseGatherCandidates.asPromise();
688
+ }
522
689
  }
523
- if (!this.remoteUsername || !this.remotePassword)
690
+ if (!this.remoteUsername || !this.remotePassword) {
524
691
  throw new Error("Remote username or password is missing");
692
+ }
525
693
  // # 5.7.1. Forming Candidate Pairs
526
- this.remoteCandidates.forEach(this.pairRemoteCandidate);
694
+ for (const c of this.remoteCandidates) {
695
+ this.pairRemoteCandidate(c);
696
+ }
527
697
  this.sortCheckList();
528
698
  this.unfreezeInitial();
699
+ log("earlyChecks", this.localPassword, this.earlyChecks.length);
529
700
  // # handle early checks
530
- this.earlyChecks.forEach((earlyCheck) => this.checkIncoming(...earlyCheck));
701
+ for (const earlyCheck of this.earlyChecks) {
702
+ this.checkIncoming(...earlyCheck);
703
+ }
531
704
  this.earlyChecks = [];
705
+ this.earlyChecksDone = true;
532
706
  // # perform checks
533
707
  // 5.8. Scheduling Checks
534
708
  for (;;) {
@@ -539,17 +713,19 @@ class Connection {
539
713
  await promises_1.default.setTimeout(20);
540
714
  }
541
715
  // # wait for completion
542
- let res = ICE_FAILED;
543
- 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) {
544
718
  res = await this.checkListState.get();
545
719
  }
546
720
  // # cancel remaining checks
547
- this.checkList.forEach((check) => check.handle?.cancel());
548
- if (res !== ICE_COMPLETED) {
721
+ for (const check of this.checkList) {
722
+ check.handle?.resolve?.();
723
+ }
724
+ if (res !== iceBase_1.ICE_COMPLETED) {
549
725
  throw new Error("ICE negotiation failed");
550
726
  }
551
727
  // # start consent freshness tests
552
- this.queryConsentHandle = (0, helper_1.future)(this.queryConsent());
728
+ this.queryConsent();
553
729
  this.setState("connected");
554
730
  }
555
731
  unfreezeInitial() {
@@ -557,16 +733,16 @@ class Connection {
557
733
  const [firstPair] = this.checkList;
558
734
  if (!firstPair)
559
735
  return;
560
- if (firstPair.state === CandidatePairState.FROZEN) {
561
- this.setPairState(firstPair, CandidatePairState.WAITING);
736
+ if (firstPair.state === iceBase_1.CandidatePairState.FROZEN) {
737
+ firstPair.updateState(iceBase_1.CandidatePairState.WAITING);
562
738
  }
563
739
  // # unfreeze pairs with same component but different foundations
564
740
  const seenFoundations = new Set(firstPair.localCandidate.foundation);
565
741
  for (const pair of this.checkList) {
566
742
  if (pair.component === firstPair.component &&
567
743
  !seenFoundations.has(pair.localCandidate.foundation) &&
568
- pair.state === CandidatePairState.FROZEN) {
569
- this.setPairState(pair, CandidatePairState.WAITING);
744
+ pair.state === iceBase_1.CandidatePairState.FROZEN) {
745
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
570
746
  seenFoundations.add(pair.localCandidate.foundation);
571
747
  }
572
748
  }
@@ -583,17 +759,17 @@ class Connection {
583
759
  return false;
584
760
  return true;
585
761
  })
586
- .find((pair) => pair.state === CandidatePairState.WAITING);
762
+ .find((pair) => pair.state === iceBase_1.CandidatePairState.WAITING);
587
763
  if (pair) {
588
- pair.handle = (0, helper_1.future)(this.checkStart(pair));
764
+ pair.handle = this.checkStart(pair);
589
765
  return true;
590
766
  }
591
767
  }
592
768
  {
593
769
  // # find the highest-priority pair that is in the frozen state
594
- const pair = this.checkList.find((pair) => pair.state === CandidatePairState.FROZEN);
770
+ const pair = this.checkList.find((pair) => pair.state === iceBase_1.CandidatePairState.FROZEN);
595
771
  if (pair) {
596
- pair.handle = (0, helper_1.future)(this.checkStart(pair));
772
+ pair.handle = this.checkStart(pair);
597
773
  return true;
598
774
  }
599
775
  }
@@ -609,19 +785,11 @@ class Connection {
609
785
  // """
610
786
  this.setState("closed");
611
787
  // # stop consent freshness tests
612
- if (this.queryConsentHandle && !this.queryConsentHandle.done()) {
613
- this.queryConsentHandle.cancel();
614
- try {
615
- await this.queryConsentHandle.promise;
616
- }
617
- catch (error) {
618
- // pass
619
- }
620
- }
788
+ this.queryConsentHandle?.resolve?.();
621
789
  // # stop check list
622
790
  if (this.checkList && !this.checkListDone) {
623
791
  this.checkListState.put(new Promise((r) => {
624
- r(ICE_FAILED);
792
+ r(iceBase_1.ICE_FAILED);
625
793
  }));
626
794
  }
627
795
  this.nominated = undefined;
@@ -632,7 +800,8 @@ class Connection {
632
800
  }
633
801
  this.protocols = [];
634
802
  this.localCandidates = [];
635
- await this.lookup?.close();
803
+ this.lookup?.close?.();
804
+ this.lookup = undefined;
636
805
  }
637
806
  setState(state) {
638
807
  this.state = state;
@@ -650,8 +819,6 @@ class Connection {
650
819
  }
651
820
  if (remoteCandidate.host.includes(".local")) {
652
821
  try {
653
- if (this.state === "closed")
654
- return;
655
822
  if (!this.lookup) {
656
823
  this.lookup = new lookup_1.MdnsLookup();
657
824
  }
@@ -663,105 +830,21 @@ class Connection {
663
830
  }
664
831
  }
665
832
  try {
666
- validateRemoteCandidate(remoteCandidate);
833
+ (0, iceBase_1.validateRemoteCandidate)(remoteCandidate);
667
834
  }
668
835
  catch (error) {
669
836
  return;
670
837
  }
671
838
  log("addRemoteCandidate", remoteCandidate);
672
- this.remoteCandidates.push(remoteCandidate);
839
+ this._remoteCandidates.push(remoteCandidate);
673
840
  this.pairRemoteCandidate(remoteCandidate);
674
841
  this.sortCheckList();
675
842
  }
676
- async sendTo(data) {
677
- // """
678
- // Send a datagram on the specified component.
679
- // If the connection is not established, a `ConnectionError` is raised.
680
- // :param data: The data to be sent.
681
- // :param component: The component on which to send the data.
682
- // """
683
- const activePair = this.nominated;
684
- if (activePair) {
685
- await activePair.protocol.sendData(data, activePair.remoteAddr);
686
- }
687
- else {
688
- // log("Cannot send data, ice not connected");
689
- return;
690
- }
691
- }
692
843
  getDefaultCandidate() {
693
844
  const candidates = this.localCandidates.sort((a, b) => a.priority - b.priority);
694
845
  const [candidate] = candidates;
695
846
  return candidate;
696
847
  }
697
- requestReceived(message, addr, protocol, rawData) {
698
- if (message.messageMethod !== const_1.methods.BINDING) {
699
- this.respondError(message, addr, protocol, [400, "Bad Request"]);
700
- return;
701
- }
702
- // # authenticate request
703
- try {
704
- (0, message_1.parseMessage)(rawData, Buffer.from(this.localPassword, "utf8"));
705
- if (!this.remoteUsername) {
706
- const rxUsername = `${this.localUserName}:${this.remoteUsername}`;
707
- if (message.getAttributeValue("USERNAME") != rxUsername) {
708
- throw new Error("Wrong username");
709
- }
710
- }
711
- }
712
- catch (error) {
713
- this.respondError(message, addr, protocol, [400, "Bad Request"]);
714
- return;
715
- }
716
- const { iceControlling } = this;
717
- // 7.2.1.1. Detecting and Repairing Role Conflicts
718
- if (iceControlling && message.attributesKeys.includes("ICE-CONTROLLING")) {
719
- if (this._tieBreaker >= message.getAttributeValue("ICE-CONTROLLING")) {
720
- this.respondError(message, addr, protocol, [487, "Role Conflict"]);
721
- return;
722
- }
723
- else {
724
- this.switchRole(false);
725
- }
726
- }
727
- else if (!iceControlling &&
728
- message.attributesKeys.includes("ICE-CONTROLLED")) {
729
- if (this._tieBreaker < message.getAttributeValue("ICE-CONTROLLED")) {
730
- this.respondError(message, addr, protocol, [487, "Role Conflict"]);
731
- }
732
- else {
733
- this.switchRole(true);
734
- return;
735
- }
736
- }
737
- if (this.options.filterStunResponse &&
738
- !this.options.filterStunResponse(message, addr, protocol)) {
739
- return;
740
- }
741
- // # send binding response
742
- const response = new message_1.Message(const_1.methods.BINDING, const_1.classes.RESPONSE, message.transactionId);
743
- response
744
- .setAttribute("XOR-MAPPED-ADDRESS", addr)
745
- .addMessageIntegrity(Buffer.from(this.localPassword, "utf8"))
746
- .addFingerprint();
747
- protocol.sendStun(response, addr).catch((e) => {
748
- log("sendStun error", e);
749
- });
750
- // todo fix
751
- // if (this.checkList.length === 0) {
752
- // this.earlyChecks.push([message, addr, protocol]);
753
- // } else {
754
- this.checkIncoming(message, addr, protocol);
755
- // }
756
- }
757
- dataReceived(data, component) {
758
- try {
759
- this.onData.execute(data, component);
760
- }
761
- catch (error) {
762
- log("dataReceived", error);
763
- }
764
- }
765
848
  // for test only
766
849
  set remoteCandidates(value) {
767
850
  if (this.remoteCandidatesEnd)
@@ -769,12 +852,12 @@ class Connection {
769
852
  this._remoteCandidates = [];
770
853
  for (const remoteCandidate of value) {
771
854
  try {
772
- validateRemoteCandidate(remoteCandidate);
855
+ (0, iceBase_1.validateRemoteCandidate)(remoteCandidate);
773
856
  }
774
857
  catch (error) {
775
858
  continue;
776
859
  }
777
- this.remoteCandidates.push(remoteCandidate);
860
+ this._remoteCandidates.push(remoteCandidate);
778
861
  }
779
862
  this.remoteCandidatesEnd = true;
780
863
  }
@@ -782,36 +865,32 @@ class Connection {
782
865
  return this._remoteCandidates;
783
866
  }
784
867
  sortCheckList() {
785
- sortCandidatePairs(this.checkList, this.iceControlling);
868
+ (0, iceBase_1.sortCandidatePairs)(this.checkList, this.iceControlling);
786
869
  }
787
870
  findPair(protocol, remoteCandidate) {
788
871
  const pair = this.checkList.find((pair) => (0, isEqual_1.default)(pair.protocol, protocol) &&
789
872
  (0, isEqual_1.default)(pair.remoteCandidate, remoteCandidate));
790
873
  return pair;
791
874
  }
792
- setPairState(pair, state) {
793
- log("setPairState", pair.toJSON(), CandidatePairState[state]);
794
- pair.updateState(state);
795
- }
796
875
  switchRole(iceControlling) {
797
876
  log("switch role", iceControlling);
798
877
  this.iceControlling = iceControlling;
799
878
  this.sortCheckList();
800
879
  }
801
- resetNominatedPair() {
802
- log("resetNominatedPair");
803
- this.nominated = undefined;
804
- this.nominating = false;
805
- }
806
880
  checkComplete(pair) {
807
881
  pair.handle = undefined;
808
- if (pair.state === CandidatePairState.SUCCEEDED) {
882
+ if (pair.state === iceBase_1.CandidatePairState.SUCCEEDED) {
809
883
  // Updating the Nominated Flag
810
884
  // https://www.rfc-editor.org/rfc/rfc8445#section-7.3.1.5,
811
885
  // Once the nominated flag is set for a component of a data stream, it
812
886
  // concludes the ICE processing for that component. See Section 8.
813
887
  // So disallow overwriting of the pair nominated for that component
814
- 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) {
815
894
  log("nominated", pair.toJSON());
816
895
  this.nominated = pair;
817
896
  this.nominating = false;
@@ -821,8 +900,8 @@ class Connection {
821
900
  // nominated pairs for that media stream.
822
901
  for (const p of this.checkList) {
823
902
  if (p.component === pair.component &&
824
- [CandidatePairState.WAITING, CandidatePairState.FROZEN].includes(p.state)) {
825
- this.setPairState(p, CandidatePairState.FAILED);
903
+ [iceBase_1.CandidatePairState.WAITING, iceBase_1.CandidatePairState.FROZEN].includes(p.state)) {
904
+ p.updateState(iceBase_1.CandidatePairState.FAILED);
826
905
  }
827
906
  }
828
907
  }
@@ -832,27 +911,28 @@ class Connection {
832
911
  if (this.nominated) {
833
912
  if (!this.checkListDone) {
834
913
  log("ICE completed");
835
- this.checkListState.put(new Promise((r) => r(ICE_COMPLETED)));
914
+ this.checkListState.put(new Promise((r) => r(iceBase_1.ICE_COMPLETED)));
836
915
  this.checkListDone = true;
837
916
  }
838
917
  return;
839
918
  }
919
+ log("not completed", pair.toJSON());
840
920
  // 7.1.3.2.3. Updating Pair States
841
921
  for (const p of this.checkList) {
842
922
  if (p.localCandidate.foundation === pair.localCandidate.foundation &&
843
- p.state === CandidatePairState.FROZEN) {
844
- this.setPairState(p, CandidatePairState.WAITING);
923
+ p.state === iceBase_1.CandidatePairState.FROZEN) {
924
+ p.updateState(iceBase_1.CandidatePairState.WAITING);
845
925
  }
846
926
  }
847
927
  }
848
928
  {
849
- const list = [CandidatePairState.SUCCEEDED, CandidatePairState.FAILED];
929
+ const list = [iceBase_1.CandidatePairState.SUCCEEDED, iceBase_1.CandidatePairState.FAILED];
850
930
  if (this.checkList.find(({ state }) => !list.includes(state))) {
851
931
  return;
852
932
  }
853
933
  }
854
934
  if (!this.iceControlling) {
855
- const target = CandidatePairState.SUCCEEDED;
935
+ const target = iceBase_1.CandidatePairState.SUCCEEDED;
856
936
  if (this.checkList.find(({ state }) => state === target)) {
857
937
  return;
858
938
  }
@@ -860,17 +940,22 @@ class Connection {
860
940
  if (!this.checkListDone) {
861
941
  log("ICE failed");
862
942
  this.checkListState.put(new Promise((r) => {
863
- r(ICE_FAILED);
943
+ r(iceBase_1.ICE_FAILED);
864
944
  }));
865
945
  }
866
946
  }
947
+ addPair(pair) {
948
+ this.checkList.push(pair);
949
+ this.sortCheckList();
950
+ }
867
951
  // 7.2. STUN Server Procedures
868
952
  // 7.2.1.3、7.2.1.4、および7.2.1.5
869
953
  checkIncoming(message, addr, protocol) {
870
- // log("checkIncoming", message.toJSON(), addr);
871
954
  // """
872
955
  // Handle a successful incoming check.
873
956
  // """
957
+ const txUsername = message.getAttributeValue("USERNAME");
958
+ const { remoteUsername: localUsername } = decodeTxUsername(txUsername);
874
959
  // find remote candidate
875
960
  let remoteCandidate;
876
961
  const [host, port] = addr;
@@ -882,20 +967,27 @@ class Connection {
882
967
  }
883
968
  if (!remoteCandidate) {
884
969
  // 7.2.1.3. Learning Peer Reflexive Candidates
885
- remoteCandidate = new candidate_1.Candidate((0, helper_1.randomString)(10), 1, "udp", message.getAttributeValue("PRIORITY"), host, port, "prflx");
886
- 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);
887
972
  }
888
973
  // find pair
889
974
  let pair = this.findPair(protocol, remoteCandidate);
890
975
  if (!pair) {
891
- pair = new CandidatePair(protocol, remoteCandidate);
892
- this.setPairState(pair, CandidatePairState.WAITING);
893
- this.checkList.push(pair);
894
- this.sortCheckList();
976
+ pair = new iceBase_1.CandidatePair(protocol, remoteCandidate, this.iceControlling);
977
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
978
+ this.addPair(pair);
895
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
+ });
896
988
  // 7.2.1.4. Triggered Checks
897
- if ([CandidatePairState.WAITING, CandidatePairState.FAILED].includes(pair.state)) {
898
- 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);
899
991
  }
900
992
  else {
901
993
  pair;
@@ -904,7 +996,7 @@ class Connection {
904
996
  if (message.attributesKeys.includes("USE-CANDIDATE") &&
905
997
  !this.iceControlling) {
906
998
  pair.remoteNominated = true;
907
- if (pair.state === CandidatePairState.SUCCEEDED) {
999
+ if (pair.state === iceBase_1.CandidatePairState.SUCCEEDED) {
908
1000
  pair.nominated = true;
909
1001
  this.checkComplete(pair);
910
1002
  }
@@ -913,13 +1005,13 @@ class Connection {
913
1005
  tryPair(protocol, remoteCandidate) {
914
1006
  if (protocol.localCandidate?.canPairWith(remoteCandidate) &&
915
1007
  !this.findPair(protocol, remoteCandidate)) {
916
- const pair = new CandidatePair(protocol, remoteCandidate);
1008
+ const pair = new iceBase_1.CandidatePair(protocol, remoteCandidate, this.iceControlling);
917
1009
  if (this.options.filterCandidatePair &&
918
1010
  !this.options.filterCandidatePair(pair)) {
919
1011
  return;
920
1012
  }
921
- this.checkList.push(pair);
922
- this.setPairState(pair, CandidatePairState.WAITING);
1013
+ pair.updateState(iceBase_1.CandidatePairState.WAITING);
1014
+ this.addPair(pair);
923
1015
  }
924
1016
  }
925
1017
  pairLocalProtocol(protocol) {
@@ -927,20 +1019,20 @@ class Connection {
927
1019
  this.tryPair(protocol, remoteCandidate);
928
1020
  }
929
1021
  }
930
- buildRequest(pair, nominate) {
931
- const txUsername = `${this.remoteUsername}:${this.localUserName}`;
1022
+ buildRequest({ nominate, remoteUsername, localUsername, iceControlling, }) {
1023
+ const txUsername = encodeTxUsername({ remoteUsername, localUsername });
932
1024
  const request = new message_1.Message(const_1.methods.BINDING, const_1.classes.REQUEST);
933
1025
  request
934
1026
  .setAttribute("USERNAME", txUsername)
935
1027
  .setAttribute("PRIORITY", (0, candidate_1.candidatePriority)("prflx"));
936
- if (this.iceControlling) {
937
- request.setAttribute("ICE-CONTROLLING", this._tieBreaker);
1028
+ if (iceControlling) {
1029
+ request.setAttribute("ICE-CONTROLLING", this.tieBreaker);
938
1030
  if (nominate) {
939
1031
  request.setAttribute("USE-CANDIDATE", null);
940
1032
  }
941
1033
  }
942
1034
  else {
943
- request.setAttribute("ICE-CONTROLLED", this._tieBreaker);
1035
+ request.setAttribute("ICE-CONTROLLED", this.tieBreaker);
944
1036
  }
945
1037
  return request;
946
1038
  }
@@ -956,133 +1048,11 @@ class Connection {
956
1048
  }
957
1049
  }
958
1050
  exports.Connection = Connection;
959
- class CandidatePair {
960
- get state() {
961
- return this._state;
962
- }
963
- toJSON() {
964
- return {
965
- protocol: this.protocol.type,
966
- remoteAddr: this.remoteAddr,
967
- };
968
- }
969
- constructor(protocol, remoteCandidate) {
970
- Object.defineProperty(this, "protocol", {
971
- enumerable: true,
972
- configurable: true,
973
- writable: true,
974
- value: protocol
975
- });
976
- Object.defineProperty(this, "remoteCandidate", {
977
- enumerable: true,
978
- configurable: true,
979
- writable: true,
980
- value: remoteCandidate
981
- });
982
- Object.defineProperty(this, "handle", {
983
- enumerable: true,
984
- configurable: true,
985
- writable: true,
986
- value: void 0
987
- });
988
- Object.defineProperty(this, "nominated", {
989
- enumerable: true,
990
- configurable: true,
991
- writable: true,
992
- value: false
993
- });
994
- Object.defineProperty(this, "remoteNominated", {
995
- enumerable: true,
996
- configurable: true,
997
- writable: true,
998
- value: false
999
- });
1000
- // 5.7.4. Computing States
1001
- Object.defineProperty(this, "_state", {
1002
- enumerable: true,
1003
- configurable: true,
1004
- writable: true,
1005
- value: CandidatePairState.FROZEN
1006
- });
1007
- }
1008
- updateState(state) {
1009
- this._state = state;
1010
- }
1011
- get localCandidate() {
1012
- if (!this.protocol.localCandidate) {
1013
- throw new Error("localCandidate not exist");
1014
- }
1015
- return this.protocol.localCandidate;
1016
- }
1017
- get remoteAddr() {
1018
- return [this.remoteCandidate.host, this.remoteCandidate.port];
1019
- }
1020
- get component() {
1021
- return this.localCandidate.component;
1022
- }
1023
- }
1024
- exports.CandidatePair = CandidatePair;
1025
- const ICE_COMPLETED = 1;
1026
- const ICE_FAILED = 2;
1027
- const CONSENT_INTERVAL = 5;
1028
- const CONSENT_FAILURES = 6;
1029
- var CandidatePairState;
1030
- (function (CandidatePairState) {
1031
- CandidatePairState[CandidatePairState["FROZEN"] = 0] = "FROZEN";
1032
- CandidatePairState[CandidatePairState["WAITING"] = 1] = "WAITING";
1033
- CandidatePairState[CandidatePairState["IN_PROGRESS"] = 2] = "IN_PROGRESS";
1034
- CandidatePairState[CandidatePairState["SUCCEEDED"] = 3] = "SUCCEEDED";
1035
- CandidatePairState[CandidatePairState["FAILED"] = 4] = "FAILED";
1036
- })(CandidatePairState || (exports.CandidatePairState = CandidatePairState = {}));
1037
- const defaultOptions = {
1038
- useIpv4: true,
1039
- 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 };
1040
1057
  };
1041
- function validateRemoteCandidate(candidate) {
1042
- // """
1043
- // Check the remote candidate is supported.
1044
- // """
1045
- if (!["host", "relay", "srflx"].includes(candidate.type))
1046
- throw new Error(`Unexpected candidate type "${candidate.type}"`);
1047
- // ipaddress.ip_address(candidate.host)
1048
- return candidate;
1049
- }
1050
- function sortCandidatePairs(pairs, iceControlling) {
1051
- return pairs
1052
- .sort((a, b) => candidatePairPriority(a.localCandidate, a.remoteCandidate, iceControlling) -
1053
- candidatePairPriority(b.localCandidate, b.remoteCandidate, iceControlling))
1054
- .reverse();
1055
- }
1056
- // 5.7.2. Computing Pair Priority and Ordering Pairs
1057
- function candidatePairPriority(local, remote, iceControlling) {
1058
- const G = (iceControlling && local.priority) || remote.priority;
1059
- const D = (iceControlling && remote.priority) || local.priority;
1060
- return (1 << 32) * Math.min(G, D) + 2 * Math.max(G, D) + (G > D ? 1 : 0);
1061
- }
1062
- async function serverReflexiveCandidate(protocol, stunServer) {
1063
- // """
1064
- // Query STUN server to obtain a server-reflexive candidate.
1065
- // """
1066
- // # perform STUN query
1067
- const request = new message_1.Message(const_1.methods.BINDING, const_1.classes.REQUEST);
1068
- try {
1069
- const [response] = await protocol.request(request, stunServer);
1070
- const localCandidate = protocol.localCandidate;
1071
- if (!localCandidate) {
1072
- throw new Error("not exist");
1073
- }
1074
- const candidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("srflx", "udp", localCandidate.host), localCandidate.component, localCandidate.transport, (0, candidate_1.candidatePriority)("srflx"), response.getAttributeValue("XOR-MAPPED-ADDRESS")[0], response.getAttributeValue("XOR-MAPPED-ADDRESS")[1], "srflx", localCandidate.host, localCandidate.port);
1075
- return candidate;
1076
- }
1077
- catch (error) {
1078
- // todo fix
1079
- log("error serverReflexiveCandidate", error);
1080
- }
1081
- }
1082
- function validateAddress(addr) {
1083
- if (addr && Number.isNaN(addr[1])) {
1084
- return [addr[0], 443];
1085
- }
1086
- return addr;
1087
- }
1088
1058
  //# sourceMappingURL=ice.js.map