Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
shinyoshiaki committed Feb 16, 2024
1 parent f63f2c6 commit b62b0d2
Showing 1 changed file with 54 additions and 33 deletions.
87 changes: 54 additions & 33 deletions packages/ice/src/turn/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { setTimeout } from "timers/promises";
import { InterfaceAddresses } from "../../../common/src/network";
import { Candidate } from "../candidate";
import { TransactionFailed } from "../exceptions";
import { Future, future } from "../helper";
import { Future, future, randomTransactionId } from "../helper";
import { Connection } from "../ice";
import { classes, methods } from "../stun/const";
import { Message, parseMessage } from "../stun/message";
Expand All @@ -18,6 +18,7 @@ import { Address, Protocol } from "../types/model";

const log = debug("werift-ice:packages/ice/src/turn/protocol.ts");

const DEFAULT_ALLOCATION_LIFETIME = 600;
const TCP_TRANSPORT = 0x06000000;
const UDP_TRANSPORT = 0x11000000;

Expand Down Expand Up @@ -155,39 +156,19 @@ class TurnClient implements Protocol {
}

async connect() {
const withoutCred = new Message(methods.ALLOCATE, classes.REQUEST);
withoutCred
const request = new Message(methods.ALLOCATE, classes.REQUEST);
request
.setAttribute("LIFETIME", this.lifetime)
.setAttribute("REQUESTED-TRANSPORT", UDP_TRANSPORT);

const err: TransactionFailed = await this.request(
withoutCred,
this.server,
).catch((e) => e);

// resolve dns address
this.server = err.addr;

if (err.response.getAttributeValue("NONCE")) {
this.nonce = err.response.getAttributeValue("NONCE");
}
if (err.response.getAttributeValue("REALM")) {
this.realm = err.response.getAttributeValue("REALM");
}
this.integrityKey = makeIntegrityKey(
this.username,
this.realm!,
this.password,
);

const request = new Message(methods.ALLOCATE, classes.REQUEST);
request.setAttribute("REQUESTED-TRANSPORT", UDP_TRANSPORT);

const [response] = await this.request(request, this.server);
const [response] = await this.requestWithRetry(request, this.server);
this.relayedAddress = response.getAttributeValue("XOR-RELAYED-ADDRESS");
this.mappedAddress = response.getAttributeValue("XOR-MAPPED-ADDRESS");
const exp = response.getAttributeValue("LIFETIME");

this.refreshHandle = future(this.refresh());
this.refreshHandle = future(this.refresh(exp));

return this.relayedAddress;
}

async createPermission(peerAddress: Address) {
Expand All @@ -204,7 +185,7 @@ class TurnClient implements Protocol {
return response;
}

refresh = () =>
refresh = (exp: number) =>
new PCancelable(async (_, f, onCancel) => {
let run = true;
onCancel(() => {
Expand All @@ -214,12 +195,12 @@ class TurnClient implements Protocol {

while (run) {
// refresh before expire
await setTimeout((5 / 6) * this.lifetime * 1000);
await setTimeout((5 / 6) * exp * 1000);

const request = new Message(methods.REFRESH, classes.REQUEST);
request.setAttribute("LIFETIME", this.lifetime);
request.setAttribute("LIFETIME", exp);

await this.request(request, this.server);
await this.requestWithRetry(request, this.server);
}
});

Expand Down Expand Up @@ -248,6 +229,46 @@ class TurnClient implements Protocol {
}
}

async requestWithRetry(
request: Message,
addr: Address,
): Promise<[Message, Address]> {
let message: Message, address: Address;
try {
[message, address] = await this.request(request, addr);
} catch (error) {
if (error instanceof TransactionFailed == false) {
throw error;
}

// resolve dns address
this.server = error.addr;

const errorCode = error.response.getAttributeValue("ERROR-CODE");
const nonce = error.response.getAttributeValue("NONCE");
const realm = error.response.getAttributeValue("REALM");
if (
nonce &&
((errorCode === 401 && realm) || (errorCode === 438 && this.realm))
) {
this.nonce = nonce;
if (errorCode === 401) {
this.realm = realm;
}
this.integrityKey = makeIntegrityKey(
this.username,
this.realm!,
this.password,
);
request.transactionId = randomTransactionId();
[message, address] = await this.request(request, addr);
} else {
throw error;
}
}
return [message!, address!];
}

async sendData(data: Buffer, addr: Address) {
const channel = await this.getChannel(addr);

Expand Down Expand Up @@ -309,7 +330,7 @@ export async function createTurnEndpoint(
},
) {
if (lifetime == undefined) {
lifetime = 600;
lifetime = DEFAULT_ALLOCATION_LIFETIME;
}

const transport = await UdpTransport.init(
Expand Down

0 comments on commit b62b0d2

Please sign in to comment.