@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.
@@ -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
+ }