@bytecodealliance/preview2-shim 0.14.2 → 0.15.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.
- package/lib/browser/sockets.js +0 -14
- package/lib/io/calls.js +72 -135
- package/lib/io/worker-http.js +21 -18
- package/lib/io/worker-io.js +186 -44
- package/lib/io/worker-socket-tcp.js +250 -96
- package/lib/io/worker-socket-udp.js +524 -167
- package/lib/io/worker-sockets.js +371 -0
- package/lib/io/worker-thread.js +677 -489
- package/lib/nodejs/cli.js +3 -3
- package/lib/nodejs/clocks.js +9 -6
- package/lib/nodejs/filesystem.js +87 -25
- package/lib/nodejs/http.js +106 -96
- package/lib/nodejs/index.js +0 -2
- package/lib/nodejs/sockets.js +563 -17
- package/lib/synckit/index.js +4 -3
- package/package.json +2 -2
- package/lib/common/assert.js +0 -7
- package/lib/nodejs/sockets/socket-common.js +0 -129
- package/lib/nodejs/sockets/socketopts-bindings.js +0 -94
- package/lib/nodejs/sockets/tcp-socket-impl.js +0 -885
- package/lib/nodejs/sockets/udp-socket-impl.js +0 -768
- package/lib/nodejs/sockets/wasi-sockets.js +0 -341
- package/lib/synckit/index.d.ts +0 -71
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { lookup } from "node:dns/promises";
|
|
3
|
+
import { Socket } from "node:dgram";
|
|
4
|
+
import {
|
|
5
|
+
ALL,
|
|
6
|
+
BADFAMILY,
|
|
7
|
+
CANCELLED,
|
|
8
|
+
CONNREFUSED,
|
|
9
|
+
NODATA,
|
|
10
|
+
NOMEM,
|
|
11
|
+
NONAME,
|
|
12
|
+
NOTFOUND,
|
|
13
|
+
REFUSED,
|
|
14
|
+
SERVFAIL,
|
|
15
|
+
TIMEOUT,
|
|
16
|
+
V4MAPPED,
|
|
17
|
+
} from "node:dns";
|
|
18
|
+
import {
|
|
19
|
+
EACCES,
|
|
20
|
+
EADDRINUSE,
|
|
21
|
+
EADDRNOTAVAIL,
|
|
22
|
+
EALREADY,
|
|
23
|
+
EBADF,
|
|
24
|
+
ECONNABORTED,
|
|
25
|
+
ECONNREFUSED,
|
|
26
|
+
ECONNRESET,
|
|
27
|
+
EINVAL,
|
|
28
|
+
ENOBUFS,
|
|
29
|
+
ENOMEM,
|
|
30
|
+
ENOTCONN,
|
|
31
|
+
ENOTSUP,
|
|
32
|
+
EPERM,
|
|
33
|
+
EWOULDBLOCK,
|
|
34
|
+
} from "node:constants";
|
|
35
|
+
|
|
36
|
+
let stateCnt = 0;
|
|
37
|
+
export const SOCKET_STATE_INIT = ++stateCnt;
|
|
38
|
+
export const SOCKET_STATE_BIND = ++stateCnt;
|
|
39
|
+
export const SOCKET_STATE_BOUND = ++stateCnt;
|
|
40
|
+
export const SOCKET_STATE_LISTEN = ++stateCnt;
|
|
41
|
+
export const SOCKET_STATE_LISTENER = ++stateCnt;
|
|
42
|
+
export const SOCKET_STATE_CONNECT = ++stateCnt;
|
|
43
|
+
export const SOCKET_STATE_CONNECTION = ++stateCnt;
|
|
44
|
+
export const SOCKET_STATE_CLOSED = ++stateCnt;
|
|
45
|
+
|
|
46
|
+
const dnsLookupOptions = {
|
|
47
|
+
verbatim: true,
|
|
48
|
+
all: true,
|
|
49
|
+
hints: V4MAPPED | ALL,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export function noLookup(ip, _opts, cb) {
|
|
53
|
+
cb(null, ip);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function socketResolveAddress(name) {
|
|
57
|
+
const isIpNum = isIP(
|
|
58
|
+
name[0] === "[" && name[name.length - 1] === "]" ? name.slice(1, -1) : name
|
|
59
|
+
);
|
|
60
|
+
if (isIpNum > 0) {
|
|
61
|
+
return Promise.resolve([
|
|
62
|
+
{
|
|
63
|
+
tag: "ipv" + isIpNum,
|
|
64
|
+
val: (isIpNum === 4 ? ipv4ToTuple : ipv6ToTuple)(name),
|
|
65
|
+
},
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
// verify it is a valid domain name using the URL parser
|
|
69
|
+
let parsedUrl = null;
|
|
70
|
+
try {
|
|
71
|
+
parsedUrl = new URL(`https://${name}`);
|
|
72
|
+
if (
|
|
73
|
+
parsedUrl.port.length ||
|
|
74
|
+
parsedUrl.username.length ||
|
|
75
|
+
parsedUrl.password.length ||
|
|
76
|
+
parsedUrl.pathname !== "/" ||
|
|
77
|
+
parsedUrl.search.length ||
|
|
78
|
+
parsedUrl.hash.length
|
|
79
|
+
)
|
|
80
|
+
parsedUrl = null;
|
|
81
|
+
} catch {
|
|
82
|
+
// empty
|
|
83
|
+
}
|
|
84
|
+
if (!parsedUrl) throw "invalid-argument";
|
|
85
|
+
|
|
86
|
+
return lookup(name, dnsLookupOptions).then(
|
|
87
|
+
(addresses) => {
|
|
88
|
+
return addresses.map(({ address, family }) => {
|
|
89
|
+
[
|
|
90
|
+
{
|
|
91
|
+
tag: "ipv" + family,
|
|
92
|
+
val: (family === 4 ? ipv4ToTuple : ipv6ToTuple)(address),
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
(err) => {
|
|
98
|
+
switch (err.code) {
|
|
99
|
+
// TODO: verify these more carefully
|
|
100
|
+
case NODATA:
|
|
101
|
+
case BADFAMILY:
|
|
102
|
+
case NONAME:
|
|
103
|
+
case NOTFOUND:
|
|
104
|
+
throw "name-unresolvable";
|
|
105
|
+
case TIMEOUT:
|
|
106
|
+
case REFUSED:
|
|
107
|
+
case CONNREFUSED:
|
|
108
|
+
case SERVFAIL:
|
|
109
|
+
case NOMEM:
|
|
110
|
+
case CANCELLED:
|
|
111
|
+
throw "temporary-resolver-failure";
|
|
112
|
+
default:
|
|
113
|
+
throw "permanent-resolver-failure";
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function convertSocketError(err) {
|
|
120
|
+
switch (err?.code) {
|
|
121
|
+
case "EBADF":
|
|
122
|
+
case "ENOTCONN":
|
|
123
|
+
case "ERR_SOCKET_DGRAM_NOT_CONNECTED":
|
|
124
|
+
return "invalid-state";
|
|
125
|
+
case "EACCES":
|
|
126
|
+
case "EPERM":
|
|
127
|
+
return "access-denied";
|
|
128
|
+
case "ENOTSUP":
|
|
129
|
+
return "not-supported";
|
|
130
|
+
case "EINVAL":
|
|
131
|
+
return "invalid-argument";
|
|
132
|
+
case "ENOMEM":
|
|
133
|
+
case "ENOBUFS":
|
|
134
|
+
return "out-of-memory";
|
|
135
|
+
case "EALREADY":
|
|
136
|
+
return "concurrency-conflict";
|
|
137
|
+
case "EWOULDBLOCK":
|
|
138
|
+
return "would-block";
|
|
139
|
+
// TODO: return "new-socket-limit";
|
|
140
|
+
case "EADDRNOTAVAIL":
|
|
141
|
+
return "address-not-bindable";
|
|
142
|
+
case "EADDRINUSE":
|
|
143
|
+
return "address-in-use";
|
|
144
|
+
// TODO: return "remote-unreachable";
|
|
145
|
+
case "ECONNREFUSED":
|
|
146
|
+
return "connection-refused";
|
|
147
|
+
case "ECONNRESET":
|
|
148
|
+
return "connection-reset";
|
|
149
|
+
case "ECONNABORTED":
|
|
150
|
+
return "connection-aborted";
|
|
151
|
+
default:
|
|
152
|
+
return "unknown";
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function convertSocketErrorCode(code) {
|
|
157
|
+
switch (code) {
|
|
158
|
+
case 4053: // windows
|
|
159
|
+
case 4083:
|
|
160
|
+
case ENOTCONN:
|
|
161
|
+
case EBADF:
|
|
162
|
+
return "invalid-state";
|
|
163
|
+
case EACCES:
|
|
164
|
+
case EPERM:
|
|
165
|
+
return "access-denied";
|
|
166
|
+
case ENOTSUP:
|
|
167
|
+
return "not-supported";
|
|
168
|
+
case EINVAL:
|
|
169
|
+
return "invalid-argument";
|
|
170
|
+
case ENOMEM:
|
|
171
|
+
case ENOBUFS:
|
|
172
|
+
return "out-of-memory";
|
|
173
|
+
case EALREADY:
|
|
174
|
+
return "concurrency-conflict";
|
|
175
|
+
case EWOULDBLOCK:
|
|
176
|
+
return "would-block";
|
|
177
|
+
// TODO: return "new-socket-limit";
|
|
178
|
+
case 4090: // windows
|
|
179
|
+
case EADDRNOTAVAIL:
|
|
180
|
+
return "address-not-bindable";
|
|
181
|
+
case 4091: // windows
|
|
182
|
+
case EADDRINUSE:
|
|
183
|
+
return "address-in-use";
|
|
184
|
+
// TODO: return "remote-unreachable";
|
|
185
|
+
case ECONNREFUSED:
|
|
186
|
+
return "connection-refused";
|
|
187
|
+
case ECONNRESET:
|
|
188
|
+
return "connection-reset";
|
|
189
|
+
case ECONNABORTED:
|
|
190
|
+
return "connection-aborted";
|
|
191
|
+
// TODO: return "datagram-too-large";
|
|
192
|
+
// TODO: return "name-unresolvable";
|
|
193
|
+
// TODO: return "temporary-resolver-failure";
|
|
194
|
+
default:
|
|
195
|
+
// process._rawDebug('unknown error code', code);
|
|
196
|
+
return "unknown";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @typedef {import("../../../types/interfaces/wasi-sockets-network.js").IpSocketAddress} IpSocketAddress
|
|
202
|
+
* @typedef {import("../../../types/interfaces/wasi-sockets-tcp.js").IpAddressFamily} IpAddressFamily
|
|
203
|
+
* @typedef {import("../../../types/interfaces/wasi-sockets-tcp").TcpSocket} TcpSocket
|
|
204
|
+
* @typedef {import("../../../types/interfaces/wasi-sockets-udp").UdpSocket} UdpSocket
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
export function tupleToIPv6(arr) {
|
|
208
|
+
if (arr.length !== 8) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
return arr.map((segment) => segment.toString(16)).join(":");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function tupleToIpv4(arr) {
|
|
215
|
+
if (arr.length !== 4) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
return arr.map((segment) => segment.toString(10)).join(".");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param {IpSocketAddress} ipSocketAddress
|
|
223
|
+
* @returns {boolean}
|
|
224
|
+
*/
|
|
225
|
+
export function isMulticastIpAddress(ipSocketAddress) {
|
|
226
|
+
return (
|
|
227
|
+
(ipSocketAddress.tag === "ipv4" &&
|
|
228
|
+
ipSocketAddress.val.address[0] === 0xe0) ||
|
|
229
|
+
(ipSocketAddress.tag === "ipv6" &&
|
|
230
|
+
ipSocketAddress.val.address[0] === 0xff00)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* @param {IpSocketAddress} ipSocketAddress
|
|
236
|
+
* @returns {boolean}
|
|
237
|
+
*/
|
|
238
|
+
export function isIPv4MappedAddress(ipSocketAddress) {
|
|
239
|
+
return (
|
|
240
|
+
ipSocketAddress.tag === "ipv6" && ipSocketAddress.val.address[5] === 0xffff
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @param {IpSocketAddress} ipSocketAddress
|
|
246
|
+
* @returns {boolean}
|
|
247
|
+
*/
|
|
248
|
+
export function isUnicastIpAddress(ipSocketAddress) {
|
|
249
|
+
return (
|
|
250
|
+
!isMulticastIpAddress(ipSocketAddress) &&
|
|
251
|
+
!isBroadcastIpAddress(ipSocketAddress)
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {IpSocketAddress} isWildcardAddress
|
|
257
|
+
* @returns {boolean}
|
|
258
|
+
*/
|
|
259
|
+
export function isWildcardAddress(ipSocketAddress) {
|
|
260
|
+
const { address } = ipSocketAddress.val;
|
|
261
|
+
if (ipSocketAddress.tag === "ipv4")
|
|
262
|
+
return (
|
|
263
|
+
address[0] === 0 &&
|
|
264
|
+
address[1] === 0 &&
|
|
265
|
+
address[2] === 0 &&
|
|
266
|
+
address[3] === 0
|
|
267
|
+
);
|
|
268
|
+
else
|
|
269
|
+
return (
|
|
270
|
+
address[0] === 0 &&
|
|
271
|
+
address[1] === 0 &&
|
|
272
|
+
address[2] === 0 &&
|
|
273
|
+
address[3] === 0 &&
|
|
274
|
+
address[4] === 0 &&
|
|
275
|
+
address[5] === 0 &&
|
|
276
|
+
address[6] === 0 &&
|
|
277
|
+
address[7] === 0
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @param {IpSocketAddress} isWildcardAddress
|
|
283
|
+
* @returns {boolean}
|
|
284
|
+
*/
|
|
285
|
+
export function isBroadcastIpAddress(ipSocketAddress) {
|
|
286
|
+
const { address } = ipSocketAddress.val;
|
|
287
|
+
return (
|
|
288
|
+
ipSocketAddress.tag === "ipv4" &&
|
|
289
|
+
address[0] === 0xff &&
|
|
290
|
+
address[1] === 0xff &&
|
|
291
|
+
address[2] === 0xff &&
|
|
292
|
+
address[3] === 0xff
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
*
|
|
298
|
+
* @param {IpSocketAddress} addr
|
|
299
|
+
* @param {boolean} includePort
|
|
300
|
+
* @returns {string}
|
|
301
|
+
*/
|
|
302
|
+
export function serializeIpAddress(addr) {
|
|
303
|
+
if (addr.tag === "ipv4") return tupleToIpv4(addr.val.address);
|
|
304
|
+
return tupleToIPv6(addr.val.address);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function ipv6ToTuple(ipv6) {
|
|
308
|
+
const [lhs, rhs = ""] = ipv6.includes("::") ? ipv6.split("::") : [ipv6];
|
|
309
|
+
const lhsParts = lhs === "" ? [] : lhs.split(":");
|
|
310
|
+
const rhsParts = rhs === "" ? [] : rhs.split(":");
|
|
311
|
+
return [
|
|
312
|
+
...lhsParts,
|
|
313
|
+
...Array(8 - lhsParts.length - rhsParts.length).fill(0),
|
|
314
|
+
...rhsParts,
|
|
315
|
+
].map((segment) => parseInt(segment, 16));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function ipv4ToTuple(ipv4) {
|
|
319
|
+
return ipv4.split(".").map((segment) => parseInt(segment, 10));
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
*
|
|
324
|
+
* @param {string} addr
|
|
325
|
+
* @param {IpAddressFamily} family
|
|
326
|
+
* @returns {IpSocketAddress}
|
|
327
|
+
*/
|
|
328
|
+
export function ipSocketAddress(family, addr, port) {
|
|
329
|
+
if (family === "ipv4")
|
|
330
|
+
return {
|
|
331
|
+
tag: "ipv4",
|
|
332
|
+
val: {
|
|
333
|
+
port,
|
|
334
|
+
address: ipv4ToTuple(addr)
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
return {
|
|
338
|
+
tag: "ipv6",
|
|
339
|
+
val: {
|
|
340
|
+
port,
|
|
341
|
+
flowInfo: 0,
|
|
342
|
+
address: ipv6ToTuple(addr),
|
|
343
|
+
scopeId: 0
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
let _recvBufferSize, _sendBufferSize;
|
|
349
|
+
async function getDefaultBufferSizes () {
|
|
350
|
+
var s = new Socket({ type: 'udp4' });
|
|
351
|
+
s.bind(0);
|
|
352
|
+
await new Promise((resolve, reject) => {
|
|
353
|
+
s.once('error', reject);
|
|
354
|
+
s.once('listening', resolve);
|
|
355
|
+
});
|
|
356
|
+
_recvBufferSize = BigInt(s.getRecvBufferSize());
|
|
357
|
+
_sendBufferSize = BigInt(s.getSendBufferSize());
|
|
358
|
+
s.close();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export async function getDefaultSendBufferSize () {
|
|
362
|
+
if (!_sendBufferSize)
|
|
363
|
+
await getDefaultBufferSizes();
|
|
364
|
+
return _sendBufferSize;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export async function getDefaultReceiveBufferSize () {
|
|
368
|
+
if (!_recvBufferSize)
|
|
369
|
+
await getDefaultBufferSizes();
|
|
370
|
+
return _recvBufferSize;
|
|
371
|
+
}
|