@bytecodealliance/preview3-shim 0.1.2 → 0.2.1
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.
- package/dist/nodejs/cli.d.ts +51 -0
- package/dist/nodejs/cli.js +106 -0
- package/dist/nodejs/clocks.d.ts +55 -0
- package/dist/nodejs/clocks.js +83 -0
- package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
- package/dist/nodejs/filesystem/descriptor.js +1010 -0
- package/dist/nodejs/filesystem/error.d.ts +61 -0
- package/dist/nodejs/filesystem/error.js +86 -0
- package/dist/nodejs/filesystem/utils.d.ts +8 -0
- package/dist/nodejs/filesystem/utils.js +25 -0
- package/dist/nodejs/filesystem.js +2 -0
- package/dist/nodejs/finalization.d.ts +2 -0
- package/{lib → dist}/nodejs/finalization.js +15 -21
- package/dist/nodejs/future.d.ts +98 -0
- package/dist/nodejs/future.js +176 -0
- package/dist/nodejs/http/client.d.ts +22 -0
- package/dist/nodejs/http/client.js +138 -0
- package/dist/nodejs/http/error.d.ts +18 -0
- package/dist/nodejs/http/error.js +62 -0
- package/dist/nodejs/http/fields.d.ts +144 -0
- package/dist/nodejs/http/fields.js +332 -0
- package/dist/nodejs/http/request.d.ts +256 -0
- package/dist/nodejs/http/request.js +606 -0
- package/dist/nodejs/http/response.d.ts +82 -0
- package/dist/nodejs/http/response.js +202 -0
- package/dist/nodejs/http/server.d.ts +13 -0
- package/dist/nodejs/http/server.js +127 -0
- package/dist/nodejs/http.d.ts +19 -0
- package/{lib → dist}/nodejs/http.js +13 -18
- package/dist/nodejs/index.js +8 -0
- package/dist/nodejs/random.d.ts +5 -0
- package/{lib → dist}/nodejs/random.js +2 -8
- package/dist/nodejs/sockets/address.d.ts +78 -0
- package/dist/nodejs/sockets/address.js +120 -0
- package/dist/nodejs/sockets/error.d.ts +83 -0
- package/dist/nodejs/sockets/error.js +120 -0
- package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
- package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
- package/dist/nodejs/sockets/tcp.d.ts +333 -0
- package/dist/nodejs/sockets/tcp.js +723 -0
- package/dist/nodejs/sockets/udp.d.ts +224 -0
- package/dist/nodejs/sockets/udp.js +475 -0
- package/dist/nodejs/sockets.d.ts +11 -0
- package/{lib → dist}/nodejs/sockets.js +2 -5
- package/dist/nodejs/stream.d.ts +161 -0
- package/dist/nodejs/stream.js +388 -0
- package/dist/nodejs/workers/cli-worker.d.ts +1 -0
- package/dist/nodejs/workers/cli-worker.js +41 -0
- package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
- package/dist/nodejs/workers/filesystem-worker.js +109 -0
- package/dist/nodejs/workers/http-worker.d.ts +1 -0
- package/dist/nodejs/workers/http-worker.js +355 -0
- package/dist/nodejs/workers/resource-worker.d.ts +13 -0
- package/dist/nodejs/workers/resource-worker.js +152 -0
- package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
- package/dist/nodejs/workers/tcp-worker.js +318 -0
- package/dist/nodejs/workers/udp-worker.d.ts +1 -0
- package/dist/nodejs/workers/udp-worker.js +156 -0
- package/package.json +20 -12
- package/types/interfaces/wasi-cli-environment.d.ts +3 -3
- package/types/interfaces/wasi-cli-exit.d.ts +12 -1
- package/types/interfaces/wasi-cli-run.d.ts +1 -1
- package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
- package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
- package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
- package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
- package/types/interfaces/wasi-cli-types.d.ts +5 -5
- package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
- package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
- package/types/interfaces/wasi-clocks-types.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
- package/types/interfaces/wasi-http-client.d.ts +1 -1
- package/types/interfaces/wasi-http-handler.d.ts +1 -1
- package/types/interfaces/wasi-http-types.d.ts +34 -34
- package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
- package/types/interfaces/wasi-random-insecure.d.ts +5 -5
- package/types/interfaces/wasi-random-random.d.ts +5 -5
- package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
- package/types/interfaces/wasi-sockets-types.d.ts +121 -121
- package/types/wasi-cli-command.d.ts +23 -23
- package/types/wasi-http-service.d.ts +14 -14
- package/lib/nodejs/cli.js +0 -127
- package/lib/nodejs/clocks.js +0 -98
- package/lib/nodejs/filesystem/descriptor.js +0 -1093
- package/lib/nodejs/filesystem/error.js +0 -92
- package/lib/nodejs/filesystem/utils.js +0 -19
- package/lib/nodejs/future.js +0 -190
- package/lib/nodejs/http/client.js +0 -161
- package/lib/nodejs/http/error.js +0 -71
- package/lib/nodejs/http/fields.js +0 -373
- package/lib/nodejs/http/request.js +0 -691
- package/lib/nodejs/http/response.js +0 -227
- package/lib/nodejs/http/server.js +0 -157
- package/lib/nodejs/sockets/address.js +0 -146
- package/lib/nodejs/sockets/error.js +0 -123
- package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
- package/lib/nodejs/sockets/tcp.js +0 -801
- package/lib/nodejs/sockets/udp.js +0 -516
- package/lib/nodejs/stream.js +0 -437
- package/lib/nodejs/workers/cli-worker.js +0 -49
- package/lib/nodejs/workers/filesystem-worker.js +0 -119
- package/lib/nodejs/workers/http-worker.js +0 -417
- package/lib/nodejs/workers/resource-worker.js +0 -195
- package/lib/nodejs/workers/tcp-worker.js +0 -370
- package/lib/nodejs/workers/udp-worker.js +0 -194
- /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
- /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
|
@@ -1,370 +0,0 @@
|
|
|
1
|
-
import { Socket, Server } from "node:net";
|
|
2
|
-
import { Readable } from "stream";
|
|
3
|
-
import { pipeline } from "stream/promises";
|
|
4
|
-
import { once } from "node:events";
|
|
5
|
-
|
|
6
|
-
import { Router } from "../workers/resource-worker.js";
|
|
7
|
-
import { serializeIpAddress, makeIpAddress, ipAddressConflict } from "../sockets/address.js";
|
|
8
|
-
import { SocketError } from "../sockets/error.js";
|
|
9
|
-
|
|
10
|
-
import process from "node:process";
|
|
11
|
-
const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
|
|
12
|
-
|
|
13
|
-
// Socket instances stored by ID
|
|
14
|
-
const sockets = new Map();
|
|
15
|
-
// Unique IDs for sockets
|
|
16
|
-
let NEXT_SOCKET_ID = 0n;
|
|
17
|
-
|
|
18
|
-
// Handle worker messages
|
|
19
|
-
Router()
|
|
20
|
-
.beforeAll((msg) => {
|
|
21
|
-
if (msg.op !== "tcp-create" && !sockets.has(msg.socketId)) {
|
|
22
|
-
throw new Error("Invalid socket ID");
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
.op("tcp-create", handleTcpCreate)
|
|
26
|
-
.op("tcp-bind", handleTcpBind)
|
|
27
|
-
.op("tcp-connect", handleTcpConnect)
|
|
28
|
-
.op("tcp-listen", handleTcpListen)
|
|
29
|
-
.op("tcp-send", handleTcpSend)
|
|
30
|
-
.op("tcp-receive", handleTcpReceive)
|
|
31
|
-
.op("tcp-get-local-address", handleGetLocalAddress)
|
|
32
|
-
.op("tcp-get-remote-address", handleGetRemoteAddress)
|
|
33
|
-
.op("tcp-set-listen-backlog-size", handleTcpSetBacklogSize)
|
|
34
|
-
.op("tcp-set-keep-alive", handleTcpSetKeepAlive)
|
|
35
|
-
.op("tcp-recv-buffer-size", handleRecvBufferSize)
|
|
36
|
-
.op("tcp-send-buffer-size", handleSendBufferSize)
|
|
37
|
-
.op("tcp-dispose", handleTcpDispose);
|
|
38
|
-
|
|
39
|
-
// Create a new TCP socket
|
|
40
|
-
function handleTcpCreate({ family }) {
|
|
41
|
-
const socketId = NEXT_SOCKET_ID++;
|
|
42
|
-
const handle = new TCP(TCPConstants.SOCKET);
|
|
43
|
-
|
|
44
|
-
sockets.set(socketId, {
|
|
45
|
-
handle,
|
|
46
|
-
family,
|
|
47
|
-
tcp: null,
|
|
48
|
-
server: null,
|
|
49
|
-
backlog: 128,
|
|
50
|
-
localAddress: null,
|
|
51
|
-
disposed: false,
|
|
52
|
-
activeStreams: 0,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
return { socketId };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Bind a socket to local address
|
|
59
|
-
async function handleTcpBind({ socketId, localAddress }) {
|
|
60
|
-
const socket = sockets.get(socketId);
|
|
61
|
-
const address = serializeIpAddress(localAddress);
|
|
62
|
-
const port = localAddress.val.port;
|
|
63
|
-
|
|
64
|
-
const { handle, family } = socket;
|
|
65
|
-
|
|
66
|
-
const hasConflict = [...sockets].some(
|
|
67
|
-
([id, { localAddress: boundAddress }]) =>
|
|
68
|
-
id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress),
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (hasConflict) {
|
|
72
|
-
const err = new Error("EADDRINUSE");
|
|
73
|
-
err.code = "EADDRINUSE";
|
|
74
|
-
throw err;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
await new Promise((resolve, reject) => {
|
|
78
|
-
let code;
|
|
79
|
-
if (family === "ipv6") {
|
|
80
|
-
code = handle.bind6(address, port, TCPConstants.UV_TCP_IPV6ONLY);
|
|
81
|
-
} else {
|
|
82
|
-
code = handle.bind(address, port);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (code !== 0) {
|
|
86
|
-
reject(SocketError.from(-code));
|
|
87
|
-
} else {
|
|
88
|
-
resolve();
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const out = {};
|
|
93
|
-
const code = handle.getsockname(out);
|
|
94
|
-
if (code !== 0) {
|
|
95
|
-
throw SocketError.from(-code);
|
|
96
|
-
}
|
|
97
|
-
socket.localAddress = makeIpAddress(out.family.toLowerCase(), out.address, out.port);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Connect a socket to remote address
|
|
101
|
-
async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
102
|
-
const socket = sockets.get(socketId);
|
|
103
|
-
const host = serializeIpAddress(remoteAddress);
|
|
104
|
-
const port = remoteAddress.val.port;
|
|
105
|
-
|
|
106
|
-
const tcp = (socket.tcp = new Socket({
|
|
107
|
-
handle: socket.handle,
|
|
108
|
-
pauseOnCreate: true,
|
|
109
|
-
allowHalfOpen: true,
|
|
110
|
-
}));
|
|
111
|
-
|
|
112
|
-
const onConnect = once(tcp, "connect");
|
|
113
|
-
const onError = once(tcp, "error").then(([err]) => {
|
|
114
|
-
throw err;
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// TODO(tandr): Add lookup
|
|
118
|
-
tcp.connect({ port, host });
|
|
119
|
-
|
|
120
|
-
await Promise.race([onConnect, onError]);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async function handleTcpListen({ socketId, stream }) {
|
|
124
|
-
const writer = stream.getWriter();
|
|
125
|
-
const socket = sockets.get(socketId);
|
|
126
|
-
const { handle, backlog, family } = socket;
|
|
127
|
-
|
|
128
|
-
const server = new Server({
|
|
129
|
-
pauseOnConnect: true,
|
|
130
|
-
allowHalfOpen: true,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
const onListening = once(server, "listening");
|
|
134
|
-
const onError = once(server, "error").then(([err]) => {
|
|
135
|
-
throw err;
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
server.listen(handle, backlog);
|
|
139
|
-
|
|
140
|
-
await Promise.race([onListening, onError]);
|
|
141
|
-
|
|
142
|
-
const addr = server.address();
|
|
143
|
-
if (addr && typeof addr === "object") {
|
|
144
|
-
socket.localAddress = makeIpAddress(family, addr.address, addr.port);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
server.on("connection", (conn) => {
|
|
148
|
-
conn.allowHalfOpen = true;
|
|
149
|
-
const id = NEXT_SOCKET_ID++;
|
|
150
|
-
sockets.set(id, {
|
|
151
|
-
handle: conn._handle,
|
|
152
|
-
family,
|
|
153
|
-
backlog,
|
|
154
|
-
tcp: conn,
|
|
155
|
-
server: null,
|
|
156
|
-
localAddress: makeIpAddress(family, conn.localAddress, conn.localPort),
|
|
157
|
-
disposed: false,
|
|
158
|
-
activeStreams: 0,
|
|
159
|
-
});
|
|
160
|
-
writer.write({ family, socketId: id });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
socket.server = server;
|
|
164
|
-
server.on("error", (err) => stream.abort(err));
|
|
165
|
-
server.on("close", () => writer.close());
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
async function handleTcpSend({ socketId, stream }) {
|
|
169
|
-
const socket = sockets.get(socketId);
|
|
170
|
-
socket.activeStreams++;
|
|
171
|
-
|
|
172
|
-
const { tcp } = socket;
|
|
173
|
-
const readable = Readable.fromWeb(stream);
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
await pipeline(readable, tcp);
|
|
177
|
-
} finally {
|
|
178
|
-
socket.activeStreams--;
|
|
179
|
-
cleanupDisposedSocket(socketId, socket);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
async function handleTcpReceive({ socketId, stream }) {
|
|
184
|
-
const socket = sockets.get(socketId);
|
|
185
|
-
const writer = stream.getWriter();
|
|
186
|
-
socket.activeStreams++;
|
|
187
|
-
|
|
188
|
-
const { tcp } = socket;
|
|
189
|
-
|
|
190
|
-
try {
|
|
191
|
-
await new Promise((resolve, reject) => {
|
|
192
|
-
let settled = false;
|
|
193
|
-
let pending = Promise.resolve();
|
|
194
|
-
|
|
195
|
-
const cleanup = () => {
|
|
196
|
-
tcp.off("data", onData);
|
|
197
|
-
tcp.off("end", onEnd);
|
|
198
|
-
tcp.off("error", onError);
|
|
199
|
-
};
|
|
200
|
-
const settle = (err) => {
|
|
201
|
-
if (settled) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
settled = true;
|
|
205
|
-
cleanup();
|
|
206
|
-
if (err) {
|
|
207
|
-
reject(err);
|
|
208
|
-
} else {
|
|
209
|
-
resolve();
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
const onData = (chunk) => {
|
|
213
|
-
tcp.pause();
|
|
214
|
-
pending = pending.then(async () => {
|
|
215
|
-
try {
|
|
216
|
-
await writer.write(chunk);
|
|
217
|
-
} catch {
|
|
218
|
-
settle();
|
|
219
|
-
return;
|
|
220
|
-
} finally {
|
|
221
|
-
// Always undo the pause, even if the guest dropped or cancelled the
|
|
222
|
-
// receive stream. Otherwise the send path can remain backpressured
|
|
223
|
-
// forever.
|
|
224
|
-
tcp.resume();
|
|
225
|
-
}
|
|
226
|
-
}, settle);
|
|
227
|
-
};
|
|
228
|
-
const onEnd = () => {
|
|
229
|
-
pending = pending.then(async () => {
|
|
230
|
-
try {
|
|
231
|
-
await writer.close();
|
|
232
|
-
} catch {
|
|
233
|
-
// The guest can drop the receive stream before remote EOF.
|
|
234
|
-
}
|
|
235
|
-
settle();
|
|
236
|
-
}, settle);
|
|
237
|
-
};
|
|
238
|
-
const onError = (err) => {
|
|
239
|
-
pending = pending.finally(() => settle(err));
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
writer.closed.then(
|
|
243
|
-
() => settle(),
|
|
244
|
-
() => settle(),
|
|
245
|
-
);
|
|
246
|
-
tcp.on("data", onData);
|
|
247
|
-
tcp.once("end", onEnd);
|
|
248
|
-
tcp.once("error", onError);
|
|
249
|
-
tcp.resume();
|
|
250
|
-
});
|
|
251
|
-
} finally {
|
|
252
|
-
writer.releaseLock();
|
|
253
|
-
socket.activeStreams--;
|
|
254
|
-
cleanupDisposedSocket(socketId, socket);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function cleanupDisposedSocket(socketId, socket) {
|
|
259
|
-
if (!socket.disposed || socket.activeStreams > 0) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (socket.server) {
|
|
264
|
-
socket.server.close();
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (socket.tcp) {
|
|
268
|
-
socket.tcp.destroy();
|
|
269
|
-
}
|
|
270
|
-
if (socket.handle) {
|
|
271
|
-
socket.handle.close();
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
sockets.delete(socketId);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async function handleGetLocalAddress({ socketId }) {
|
|
278
|
-
const socket = sockets.get(socketId);
|
|
279
|
-
const out = {};
|
|
280
|
-
|
|
281
|
-
const code = socket.handle.getsockname(out);
|
|
282
|
-
if (code !== 0) {
|
|
283
|
-
throw new SocketError.from(-code);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async function handleGetRemoteAddress({ socketId }) {
|
|
290
|
-
const socket = sockets.get(socketId);
|
|
291
|
-
const out = {};
|
|
292
|
-
|
|
293
|
-
const code = socket.handle.getpeername(out);
|
|
294
|
-
if (code !== 0) {
|
|
295
|
-
throw new SocketError.from(-code);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function handleTcpSetBacklogSize({ socketId, value }) {
|
|
302
|
-
const socket = sockets.get(socketId);
|
|
303
|
-
socket.backlog = Number(value);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
async function handleTcpSetKeepAlive({ socketId, keepAliveEnabled, keepAliveIdleTime }) {
|
|
307
|
-
const socket = sockets.get(socketId);
|
|
308
|
-
const time = Number(keepAliveIdleTime / 1_000_000_000n);
|
|
309
|
-
|
|
310
|
-
const code = socket.handle.setKeepAlive(keepAliveEnabled, time);
|
|
311
|
-
if (code !== 0) {
|
|
312
|
-
throw mapErrorCode(-code);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async function handleRecvBufferSize({ socketId }) {
|
|
317
|
-
const socket = sockets.get(socketId);
|
|
318
|
-
|
|
319
|
-
if (socket.tcp) {
|
|
320
|
-
return BigInt(socket.tcp.getRecvBufferSize());
|
|
321
|
-
} else {
|
|
322
|
-
return await getDefaultReceiveBufferSize();
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
async function handleSendBufferSize({ socketId }) {
|
|
327
|
-
const socket = sockets.get(socketId);
|
|
328
|
-
if (socket.tcp) {
|
|
329
|
-
return BigInt(socket.tcp.getSendBufferSize());
|
|
330
|
-
} else {
|
|
331
|
-
return await getDefaultSendBufferSize();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function handleTcpDispose({ socketId }) {
|
|
336
|
-
const socket = sockets.get(socketId);
|
|
337
|
-
if (!socket) {
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
socket.disposed = true;
|
|
342
|
-
cleanupDisposedSocket(socketId, socket);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
let _recvBufferSize, _sendBufferSize;
|
|
346
|
-
async function getDefaultBufferSizes() {
|
|
347
|
-
var s = new Socket();
|
|
348
|
-
s.bind(0);
|
|
349
|
-
await new Promise((resolve, reject) => {
|
|
350
|
-
s.once("error", reject);
|
|
351
|
-
s.once("listening", resolve);
|
|
352
|
-
});
|
|
353
|
-
_recvBufferSize = BigInt(s.getRecvBufferSize());
|
|
354
|
-
_sendBufferSize = BigInt(s.getSendBufferSize());
|
|
355
|
-
s.close();
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
export async function getDefaultSendBufferSize() {
|
|
359
|
-
if (!_sendBufferSize) {
|
|
360
|
-
await getDefaultBufferSizes();
|
|
361
|
-
}
|
|
362
|
-
return _sendBufferSize;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export async function getDefaultReceiveBufferSize() {
|
|
366
|
-
if (!_recvBufferSize) {
|
|
367
|
-
await getDefaultBufferSizes();
|
|
368
|
-
}
|
|
369
|
-
return _recvBufferSize;
|
|
370
|
-
}
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { once } from "node:events";
|
|
2
|
-
|
|
3
|
-
import { Router } from "../workers/resource-worker.js";
|
|
4
|
-
import {
|
|
5
|
-
serializeIpAddress,
|
|
6
|
-
makeIpAddress,
|
|
7
|
-
ipAddressConflict,
|
|
8
|
-
isLoopbackIpAddress,
|
|
9
|
-
} from "../sockets/address.js";
|
|
10
|
-
|
|
11
|
-
import dgram from "node:dgram";
|
|
12
|
-
|
|
13
|
-
const sockets = new Map();
|
|
14
|
-
// Unique IDs for sockets
|
|
15
|
-
let NEXT_SOCKET_ID = 0n;
|
|
16
|
-
|
|
17
|
-
export function noLookup(ip, _opts, cb) {
|
|
18
|
-
cb(null, ip);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
Router()
|
|
22
|
-
.beforeAll((msg) => {
|
|
23
|
-
if (msg.op !== "udp-create" && !sockets.has(msg.socketId)) {
|
|
24
|
-
throw new Error("Invalid socket ID");
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
.op("udp-create", handleCreate)
|
|
28
|
-
.op("udp-bind", handleBind)
|
|
29
|
-
.op("udp-connect", handleConnect)
|
|
30
|
-
.op("udp-disconnect", handleDisconnect)
|
|
31
|
-
.op("udp-send", handleSend)
|
|
32
|
-
.op("udp-receive", handleReceive)
|
|
33
|
-
.op("udp-get-local-address", handleGetLocal)
|
|
34
|
-
.op("udp-set-unicast-hop-limit", handleSetHop)
|
|
35
|
-
.op("udp-recv-buffer-size", handleRecvBuffer)
|
|
36
|
-
.op("udp-send-buffer-size", handleSendBuffer)
|
|
37
|
-
.op("udp-dispose", handleDispose);
|
|
38
|
-
|
|
39
|
-
function handleCreate({ family }) {
|
|
40
|
-
const socketId = NEXT_SOCKET_ID++;
|
|
41
|
-
const socket = {
|
|
42
|
-
family,
|
|
43
|
-
connected: null,
|
|
44
|
-
localAddress: null,
|
|
45
|
-
receiveQueue: [],
|
|
46
|
-
};
|
|
47
|
-
socket.udp = createSocket(socket);
|
|
48
|
-
sockets.set(socketId, socket);
|
|
49
|
-
|
|
50
|
-
return { socketId };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function createSocket(socket) {
|
|
54
|
-
const type = socket.family === "ipv6" ? "udp6" : "udp4";
|
|
55
|
-
const ipv6Only = socket.family === "ipv6";
|
|
56
|
-
const udp = dgram.createSocket({
|
|
57
|
-
type,
|
|
58
|
-
ipv6Only,
|
|
59
|
-
reuseAddr: false,
|
|
60
|
-
lookup: noLookup,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
udp.on("message", (msg, rinfo) => socket.receiveQueue.push({ msg, rinfo }));
|
|
64
|
-
udp.on("error", () => {});
|
|
65
|
-
return udp;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function handleBind({ socketId, localAddress }) {
|
|
69
|
-
const socket = sockets.get(socketId);
|
|
70
|
-
const hasConflict = [...sockets].some(
|
|
71
|
-
([id, { localAddress: boundAddress }]) =>
|
|
72
|
-
id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress),
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
if (hasConflict) {
|
|
76
|
-
const err = new Error("EADDRINUSE");
|
|
77
|
-
err.code = "EADDRINUSE";
|
|
78
|
-
throw err;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const addr = serializeIpAddress(localAddress);
|
|
82
|
-
const port = localAddress.val.port;
|
|
83
|
-
|
|
84
|
-
const onListening = once(socket.udp, "listening");
|
|
85
|
-
const onError = once(socket.udp, "error").then(([err]) => {
|
|
86
|
-
throw err;
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
socket.udp.bind(port, addr);
|
|
90
|
-
|
|
91
|
-
await Promise.race([onListening, onError]);
|
|
92
|
-
const boundAddr = socket.udp.address();
|
|
93
|
-
socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async function handleConnect({ socketId, remoteAddress }) {
|
|
97
|
-
const socket = sockets.get(socketId);
|
|
98
|
-
const preserveLocalAddress =
|
|
99
|
-
socket.connected &&
|
|
100
|
-
socket.localAddress &&
|
|
101
|
-
isLoopbackIpAddress(socket.connected) &&
|
|
102
|
-
isLoopbackIpAddress(remoteAddress);
|
|
103
|
-
|
|
104
|
-
if (socket.connected) {
|
|
105
|
-
const localAddress = preserveLocalAddress ? socket.localAddress : null;
|
|
106
|
-
await new Promise((resolve) => socket.udp.close(resolve));
|
|
107
|
-
socket.udp = createSocket(socket);
|
|
108
|
-
if (localAddress) {
|
|
109
|
-
await handleBind({ socketId, localAddress });
|
|
110
|
-
} else {
|
|
111
|
-
socket.localAddress = null;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const addr = serializeIpAddress(remoteAddress);
|
|
116
|
-
const port = remoteAddress.val.port;
|
|
117
|
-
|
|
118
|
-
await new Promise((resolve, reject) => {
|
|
119
|
-
socket.udp.connect(port, addr, (err) => (err ? reject(err) : resolve()));
|
|
120
|
-
});
|
|
121
|
-
const boundAddr = socket.udp.address();
|
|
122
|
-
socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
|
|
123
|
-
socket.connected = remoteAddress;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function handleDisconnect({ socketId }) {
|
|
127
|
-
const socket = sockets.get(socketId);
|
|
128
|
-
socket.udp.disconnect();
|
|
129
|
-
socket.connected = null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
async function handleSend({ socketId, data, remoteAddress }) {
|
|
133
|
-
const socket = sockets.get(socketId);
|
|
134
|
-
const isConnected = socket.connected != null;
|
|
135
|
-
|
|
136
|
-
await new Promise((resolve, reject) => {
|
|
137
|
-
if (isConnected) {
|
|
138
|
-
socket.udp.send(data, (err) => (err ? reject(err) : resolve()));
|
|
139
|
-
} else {
|
|
140
|
-
const addr = serializeIpAddress(remoteAddress);
|
|
141
|
-
const port = remoteAddress.val.port;
|
|
142
|
-
|
|
143
|
-
socket.udp.send(data, port, addr, (err) => (err ? reject(err) : resolve()));
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const boundAddr = socket.udp.address();
|
|
148
|
-
socket.localAddress = makeIpAddress(socket.family, boundAddr.address, boundAddr.port);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function handleReceive({ socketId }) {
|
|
152
|
-
const socket = sockets.get(socketId);
|
|
153
|
-
if (socket.receiveQueue.length === 0) {
|
|
154
|
-
await Promise.race([
|
|
155
|
-
once(socket.udp, "message"),
|
|
156
|
-
once(socket.udp, "error").then(([err]) => {
|
|
157
|
-
throw err;
|
|
158
|
-
}),
|
|
159
|
-
]);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const { msg, rinfo } = socket.receiveQueue.shift();
|
|
163
|
-
return {
|
|
164
|
-
data: msg,
|
|
165
|
-
remoteAddress: makeIpAddress(socket.family, rinfo.address, rinfo.port),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function handleGetLocal({ socketId }) {
|
|
170
|
-
const socket = sockets.get(socketId);
|
|
171
|
-
const addr = socket.udp.address();
|
|
172
|
-
return makeIpAddress(socket.family, addr.address, addr.port);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function handleSetHop({ socketId, value }) {
|
|
176
|
-
const socket = sockets.get(socketId);
|
|
177
|
-
socket.udp.setTTL(value);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function handleRecvBuffer({ socketId }) {
|
|
181
|
-
const socket = sockets.get(socketId);
|
|
182
|
-
return BigInt(socket.udp.getRecvBufferSize());
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function handleSendBuffer({ socketId }) {
|
|
186
|
-
const socket = sockets.get(socketId);
|
|
187
|
-
return BigInt(socket.udp.getSendBufferSize());
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function handleDispose({ socketId }) {
|
|
191
|
-
const socket = sockets.get(socketId);
|
|
192
|
-
socket.udp.close();
|
|
193
|
-
sockets.delete(socketId);
|
|
194
|
-
}
|
|
File without changes
|
|
File without changes
|