Skip to content

Commit a5799a9

Browse files
authored
feat: track TCP connection state (#217)
Depends on #206 This PR makes the TCP module store a state for each TCP connection and compute the sequence and ACK numbers for each segment, according to [RFC 9293](https://datatracker.ietf.org/doc/html/rfc9293#name-other-states).
1 parent 8147e3d commit a5799a9

File tree

6 files changed

+780
-169
lines changed

6 files changed

+780
-169
lines changed

src/packets/tcp.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { Ports } from "./ip";
99

1010
export const TCP_FLAGS_KEY = "tcp_flags";
1111

12+
// 2 bytes number
13+
export type Port = number;
14+
1215
export class Flags {
1316
// Urgent Pointer field significant
1417
public urg = false;
@@ -92,10 +95,10 @@ export class TcpSegment implements IpPayload {
9295
//
9396
// 2 bytes
9497
// The source port number.
95-
sourcePort: number;
98+
sourcePort: Port;
9699
// 2 bytes
97100
// The destination port number.
98-
destinationPort: number;
101+
destinationPort: Port;
99102
// 4 bytes
100103
// The sequence number of the first data octet in this segment (except
101104
// when SYN is present). If SYN is present the sequence number is the
@@ -147,10 +150,10 @@ export class TcpSegment implements IpPayload {
147150
constructor(
148151
srcPort: number,
149152
dstPort: number,
150-
seqNum: number,
151-
ackNum: number,
152-
flags: Flags,
153-
data: Uint8Array,
153+
seqNum = 0,
154+
ackNum = 0,
155+
flags: Flags = new Flags(),
156+
data: Uint8Array = new Uint8Array(0),
154157
) {
155158
checkUint(srcPort, 16);
156159
checkUint(dstPort, 16);
@@ -165,6 +168,16 @@ export class TcpSegment implements IpPayload {
165168
this.data = data;
166169
}
167170

171+
withFlags(flags: Flags): TcpSegment {
172+
this.flags = flags;
173+
return this;
174+
}
175+
176+
withData(data: Uint8Array): TcpSegment {
177+
this.data = data;
178+
return this;
179+
}
180+
168181
computeChecksum(): number {
169182
const segmentBytes = this.toBytes({ withChecksum: false });
170183

src/programs/http_client.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ProgramInfo } from "../graphics/renderables/device_info";
33
import { DeviceId } from "../types/graphs/datagraph";
44
import { ViewGraph } from "../types/graphs/viewgraph";
55
import { Layer } from "../types/layer";
6+
import { AsyncQueue } from "../types/network-modules/asyncQueue";
67
import { TcpSocket } from "../types/network-modules/tcpModule";
78
import { ViewHost } from "../types/view-devices";
89
import { ProgramBase } from "./program_base";
@@ -66,7 +67,7 @@ export class HttpClient extends ProgramBase {
6667

6768
// Read response
6869
const buffer = new Uint8Array(1024);
69-
const readLength = await socket.read(buffer);
70+
const readLength = await socket.readAll(buffer);
7071
if (readLength < 0) {
7172
console.error("HttpClient failed to read from socket");
7273
return;
@@ -85,6 +86,8 @@ export class HttpServer extends ProgramBase {
8586

8687
private port: number;
8788

89+
private stopChannel = new AsyncQueue<"stop">();
90+
8891
protected _parseInputs(inputs: string[]): void {
8992
if (inputs.length !== 0) {
9093
console.error(
@@ -105,8 +108,7 @@ export class HttpServer extends ProgramBase {
105108
}
106109

107110
protected _stop() {
108-
// Nothing to do
109-
// TODO: stop serving requests
111+
this.stopChannel.push("stop");
110112
}
111113

112114
private async serveHttpRequests() {
@@ -124,11 +126,17 @@ export class HttpServer extends ProgramBase {
124126
return;
125127
}
126128

129+
const stopPromise = this.stopChannel.pop();
130+
127131
while (true) {
128-
const socket = await listener.next();
132+
const socket = await Promise.race([stopPromise, listener.next()]);
133+
if (socket === "stop") {
134+
break;
135+
}
129136

130137
this.serveClient(socket);
131138
}
139+
listener.close();
132140
}
133141

134142
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -139,7 +147,7 @@ export class HttpServer extends ProgramBase {
139147

140148
async serveClient(socket: TcpSocket) {
141149
const buffer = new Uint8Array(1024).fill(0);
142-
const readLength = await socket.read(buffer);
150+
const readLength = await socket.readAll(buffer);
143151

144152
// eslint-disable-next-line @typescript-eslint/no-unused-vars
145153
const readContents = buffer.slice(0, readLength);

0 commit comments

Comments
 (0)