Skip to content

Commit 4760db1

Browse files
committed
refactor: Improve Chunk and SCTPTimerManager classes with enhanced error handling and parsing methods; add DTO conversion methods
1 parent cefd167 commit 4760db1

File tree

2 files changed

+90
-32
lines changed

2 files changed

+90
-32
lines changed

packages/sctp/src/chunk.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ export class Chunk {
4646
}
4747

4848
get bytes() {
49-
if (!this.body) throw new Error();
49+
if (!this.body) {
50+
throw new Error("Chunk body is undefined");
51+
}
5052

5153
const header = Buffer.alloc(4);
5254
header.writeUInt8(this.type, 0);
@@ -60,6 +62,17 @@ export class Chunk {
6062
]);
6163
return data;
6264
}
65+
66+
static parse(data: Buffer) {
67+
if (data.length < 4) {
68+
throw new Error("Chunk header length is less than 4 bytes");
69+
}
70+
const type = data.readUInt8(0);
71+
const flags = data.readUInt8(1);
72+
const length = data.readUInt16BE(2);
73+
const body = data.subarray(4, length);
74+
return { type, flags, length, body };
75+
}
6376
}
6477

6578
export class BaseInitChunk extends Chunk {
@@ -484,7 +497,7 @@ function padL(l: number) {
484497
function encodeParams(params: [number, Buffer][]) {
485498
let body = Buffer.from("");
486499
let padding = Buffer.from("");
487-
params.forEach(([type, value]) => {
500+
for (const [type, value] of params) {
488501
const length = value.length + 4;
489502
const paramHeader = Buffer.alloc(4);
490503
paramHeader.writeUInt16BE(type, 0);
@@ -493,7 +506,7 @@ function encodeParams(params: [number, Buffer][]) {
493506
padding = Buffer.concat(
494507
[...Array(padL(length))].map(() => Buffer.from("\x00")),
495508
);
496-
});
509+
}
497510
return body;
498511
}
499512

@@ -509,6 +522,20 @@ export function decodeParams(body: Buffer): [number, Buffer][] {
509522
return params;
510523
}
511524

525+
export const parseChunk = (data: Buffer) => {
526+
const { type, flags, length, body } = Chunk.parse(data);
527+
528+
const ChunkClass = CHUNK_BY_TYPE[type.toString()];
529+
if (!ChunkClass) {
530+
throw new Error("unknown");
531+
}
532+
533+
return {
534+
chunk: new ChunkClass(flags, body),
535+
length,
536+
};
537+
};
538+
512539
export function parsePacket(data: Buffer): [number, number, number, Chunk[]] {
513540
if (data.length < 12)
514541
throw new Error("SCTP packet length is less than 12 bytes");
@@ -532,17 +559,9 @@ export function parsePacket(data: Buffer): [number, number, number, Chunk[]] {
532559
const chunks: Chunk[] = [];
533560
let pos = 12;
534561
while (pos + 4 <= data.length) {
535-
const chunkType = data.readUInt8(pos);
536-
const chunkFlags = data.readUInt8(pos + 1);
537-
const chunkLength = data.readUInt16BE(pos + 2);
538-
const chunkBody = data.slice(pos + 4, pos + chunkLength);
539-
const ChunkClass = CHUNK_BY_TYPE[chunkType.toString()];
540-
if (ChunkClass) {
541-
chunks.push(new ChunkClass(chunkFlags, chunkBody));
542-
} else {
543-
throw new Error("unknown");
544-
}
545-
pos += chunkLength + padL(chunkLength);
562+
const { length, chunk } = parseChunk(data.subarray(pos));
563+
chunks.push(chunk);
564+
pos += length + padL(length);
546565
}
547566
return [sourcePort, destinationPort, verificationTag, chunks];
548567
}

packages/sctp/src/timer.ts

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Chunk } from "./chunk";
1+
import { type Chunk, parseChunk } from "./chunk";
22
import {
33
SCTP_MAX_ASSOCIATION_RETRANS,
44
SCTP_MAX_INIT_RETRANS,
@@ -19,16 +19,14 @@ export enum SCTPTimerType {
1919
RECONFIG = "reconfig", // re-configuration
2020
}
2121

22+
interface Deps {
23+
sendChunk: (chunk: Chunk) => Promise<void>;
24+
}
25+
2226
/**
2327
* SCTP タイマーの管理を行うクラス
2428
*/
2529
export class SCTPTimerManager {
26-
// タイマーハンドラ
27-
private t1Handle?: NodeJS.Timeout;
28-
private t2Handle?: NodeJS.Timeout;
29-
private t3Handle?: NodeJS.Timeout;
30-
private reconfigHandle?: NodeJS.Timeout;
31-
3230
// タイマー関連の状態管理
3331
private t1Chunk?: Chunk;
3432
private t1Failures = 0;
@@ -38,17 +36,20 @@ export class SCTPTimerManager {
3836
rto: number = SCTP_RTO_INITIAL;
3937
private srtt?: number;
4038
private rttvar?: number;
41-
onT1Expired = new Event<[number]>();
42-
onT2Expired = new Event<[number]>();
43-
onT3Expired = new Event<[]>();
44-
onReconfigExpired = new Event<[number]>();
45-
private sendChunk: (chunk: Chunk) => Promise<void>;
46-
47-
constructor({
48-
sendChunk,
49-
}: {
50-
sendChunk: (chunk: Chunk) => Promise<void>;
51-
}) {
39+
40+
// タイマーハンドラ
41+
private t1Handle?: NodeJS.Timeout;
42+
private t2Handle?: NodeJS.Timeout;
43+
private t3Handle?: NodeJS.Timeout;
44+
private reconfigHandle?: NodeJS.Timeout;
45+
46+
readonly onT1Expired = new Event<[number]>();
47+
readonly onT2Expired = new Event<[number]>();
48+
readonly onT3Expired = new Event<[]>();
49+
readonly onReconfigExpired = new Event<[number]>();
50+
private readonly sendChunk: (chunk: Chunk) => Promise<void>;
51+
52+
constructor({ sendChunk }: Deps) {
5253
this.sendChunk = sendChunk;
5354
}
5455

@@ -303,4 +304,42 @@ export class SCTPTimerManager {
303304
Math.min(this.srtt + 4 * this.rttvar, SCTP_RTO_MAX),
304305
);
305306
}
307+
308+
toDto(): SCTPTimerDto {
309+
return {
310+
t1Chunk: this.t1Chunk?.bytes,
311+
t1Failures: this.t1Failures,
312+
t2Chunk: this.t2Chunk?.bytes,
313+
t2Failures: this.t2Failures,
314+
reconfigFailures: this.reconfigFailures,
315+
rto: this.rto,
316+
srtt: this.srtt,
317+
rttvar: this.rttvar,
318+
};
319+
}
320+
321+
static fromDto(dto: SCTPTimerDto, deps: Deps): SCTPTimerManager {
322+
const timerManager = new SCTPTimerManager(deps);
323+
timerManager.t1Chunk = dto.t1Chunk && parseChunk(dto.t1Chunk).chunk;
324+
timerManager.t1Failures = dto.t1Failures;
325+
timerManager.t2Chunk = dto.t2Chunk && parseChunk(dto.t2Chunk).chunk;
326+
timerManager.t2Failures = dto.t2Failures;
327+
timerManager.reconfigFailures = dto.reconfigFailures;
328+
timerManager.rto = dto.rto;
329+
timerManager.srtt = dto.srtt;
330+
timerManager.rttvar = dto.rttvar;
331+
332+
return timerManager;
333+
}
334+
}
335+
336+
interface SCTPTimerDto {
337+
t1Chunk: Buffer | undefined;
338+
t1Failures: number;
339+
t2Chunk: Buffer | undefined;
340+
t2Failures: number;
341+
reconfigFailures: number;
342+
rto: number;
343+
srtt: number | undefined;
344+
rttvar: number | undefined;
306345
}

0 commit comments

Comments
 (0)