@bytecodealliance/preview2-shim 0.17.2 → 0.17.4

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.
@@ -1,27 +1,27 @@
1
- import { createSocket } from "node:dgram";
1
+ import { createSocket } from 'node:dgram';
2
2
  import {
3
- createFuture,
4
- futureDispose,
5
- futureTakeValue,
6
- pollStateReady,
7
- verifyPollsDroppedForDrop,
8
- } from "./worker-thread.js";
3
+ createFuture,
4
+ futureDispose,
5
+ futureTakeValue,
6
+ pollStateReady,
7
+ verifyPollsDroppedForDrop,
8
+ } from './worker-thread.js';
9
9
  import {
10
- convertSocketError,
11
- convertSocketErrorCode,
12
- getDefaultReceiveBufferSize,
13
- getDefaultSendBufferSize,
14
- ipSocketAddress,
15
- isIPv4MappedAddress,
16
- isWildcardAddress,
17
- noLookup,
18
- serializeIpAddress,
19
- SOCKET_STATE_BIND,
20
- SOCKET_STATE_BOUND,
21
- SOCKET_STATE_CLOSED,
22
- SOCKET_STATE_CONNECTION,
23
- SOCKET_STATE_INIT,
24
- } from "./worker-sockets.js";
10
+ convertSocketError,
11
+ convertSocketErrorCode,
12
+ getDefaultReceiveBufferSize,
13
+ getDefaultSendBufferSize,
14
+ ipSocketAddress,
15
+ isIPv4MappedAddress,
16
+ isWildcardAddress,
17
+ noLookup,
18
+ serializeIpAddress,
19
+ SOCKET_STATE_BIND,
20
+ SOCKET_STATE_BOUND,
21
+ SOCKET_STATE_CLOSED,
22
+ SOCKET_STATE_CONNECTION,
23
+ SOCKET_STATE_INIT,
24
+ } from './worker-sockets.js';
25
25
 
26
26
  // Experimental support for batched UDP sends. Set this to true to enable.
27
27
  // This is not enabled by default because we need to figure out how to know
@@ -61,7 +61,7 @@ const UDP_BATCH_SENDS = false;
61
61
  */
62
62
 
63
63
  let udpSocketCnt = 0,
64
- datagramStreamCnt = 0;
64
+ datagramStreamCnt = 0;
65
65
 
66
66
  /**
67
67
  * @type {Map<number, UdpSocketRecord>}
@@ -78,27 +78,32 @@ export const datagramStreams = new Map();
78
78
  * @returns {number}
79
79
  */
80
80
  export function createUdpSocket({ family, unicastHopLimit }) {
81
- const udpSocket = createSocket({
82
- type: family === "ipv6" ? "udp6" : "udp4",
83
- reuseAddr: false,
84
- ipv6Only: family === "ipv6",
85
- lookup: noLookup,
86
- });
87
- udpSockets.set(++udpSocketCnt, {
88
- state: SOCKET_STATE_INIT,
89
- remoteAddress: null,
90
- remotePort: null,
91
- sendBufferSize: null,
92
- receiveBufferSize: null,
93
- unicastHopLimit,
94
- udpSocket,
95
- future: null,
96
- serializedLocalAddress: null,
97
- pollState: { ready: true, listener: null, polls: [], parentStream: null },
98
- incomingDatagramStream: null,
99
- outgoingDatagramStream: null,
100
- });
101
- return udpSocketCnt;
81
+ const udpSocket = createSocket({
82
+ type: family === 'ipv6' ? 'udp6' : 'udp4',
83
+ reuseAddr: false,
84
+ ipv6Only: family === 'ipv6',
85
+ lookup: noLookup,
86
+ });
87
+ udpSockets.set(++udpSocketCnt, {
88
+ state: SOCKET_STATE_INIT,
89
+ remoteAddress: null,
90
+ remotePort: null,
91
+ sendBufferSize: null,
92
+ receiveBufferSize: null,
93
+ unicastHopLimit,
94
+ udpSocket,
95
+ future: null,
96
+ serializedLocalAddress: null,
97
+ pollState: {
98
+ ready: true,
99
+ listener: null,
100
+ polls: [],
101
+ parentStream: null,
102
+ },
103
+ incomingDatagramStream: null,
104
+ outgoingDatagramStream: null,
105
+ });
106
+ return udpSocketCnt;
102
107
  }
103
108
 
104
109
  /**
@@ -106,43 +111,45 @@ export function createUdpSocket({ family, unicastHopLimit }) {
106
111
  * @returns {DatagramStreamRecord}
107
112
  */
108
113
  function createIncomingDatagramStream(socket) {
109
- const id = ++datagramStreamCnt;
110
- const pollState = {
111
- ready: false,
112
- listener: null,
113
- polls: [],
114
- parentStream: null,
115
- };
116
- const datagramStream = {
117
- id,
118
- active: true,
119
- error: null,
120
- socket,
121
- queue: [],
122
- cleanup,
123
- pollState,
124
- };
125
- const { udpSocket } = socket;
126
- datagramStreams.set(id, datagramStream);
127
- function cleanup() {
128
- udpSocket.off("message", onMessage);
129
- udpSocket.off("error", onError);
130
- }
131
- function onMessage(data, rinfo) {
132
- const family = rinfo.family.toLowerCase();
133
- datagramStream.queue.push({
134
- data,
135
- remoteAddress: ipSocketAddress(family, rinfo.address, rinfo.port),
136
- });
137
- if (!pollState.ready) pollStateReady(pollState);
138
- }
139
- function onError(err) {
140
- datagramStream.error = err;
141
- pollStateReady(datagramStream.pollState);
142
- }
143
- udpSocket.on("message", onMessage);
144
- udpSocket.once("error", onError);
145
- return datagramStream;
114
+ const id = ++datagramStreamCnt;
115
+ const pollState = {
116
+ ready: false,
117
+ listener: null,
118
+ polls: [],
119
+ parentStream: null,
120
+ };
121
+ const datagramStream = {
122
+ id,
123
+ active: true,
124
+ error: null,
125
+ socket,
126
+ queue: [],
127
+ cleanup,
128
+ pollState,
129
+ };
130
+ const { udpSocket } = socket;
131
+ datagramStreams.set(id, datagramStream);
132
+ function cleanup() {
133
+ udpSocket.off('message', onMessage);
134
+ udpSocket.off('error', onError);
135
+ }
136
+ function onMessage(data, rinfo) {
137
+ const family = rinfo.family.toLowerCase();
138
+ datagramStream.queue.push({
139
+ data,
140
+ remoteAddress: ipSocketAddress(family, rinfo.address, rinfo.port),
141
+ });
142
+ if (!pollState.ready) {
143
+ pollStateReady(pollState);
144
+ }
145
+ }
146
+ function onError(err) {
147
+ datagramStream.error = err;
148
+ pollStateReady(datagramStream.pollState);
149
+ }
150
+ udpSocket.on('message', onMessage);
151
+ udpSocket.once('error', onError);
152
+ return datagramStream;
146
153
  }
147
154
 
148
155
  /**
@@ -150,78 +157,92 @@ function createIncomingDatagramStream(socket) {
150
157
  * @returns {DatagramStreamRecord}
151
158
  */
152
159
  function createOutgoingDatagramStream(socket) {
153
- const id = ++datagramStreamCnt;
154
- const datagramStream = {
155
- id,
156
- active: true,
157
- error: null,
158
- socket,
159
- cleanup,
160
- pollState: { ready: true, listener: null, polls: [], parentStream: null },
161
- };
162
- const { udpSocket } = socket;
163
- datagramStreams.set(id, datagramStream);
164
- udpSocket.on("error", onError);
165
- function onError(err) {
166
- datagramStream.error = err;
167
- pollStateReady(datagramStream.pollState);
168
- }
169
- function cleanup() {
170
- udpSocket.off("error", onError);
171
- }
172
- return datagramStream;
160
+ const id = ++datagramStreamCnt;
161
+ const datagramStream = {
162
+ id,
163
+ active: true,
164
+ error: null,
165
+ socket,
166
+ cleanup,
167
+ pollState: {
168
+ ready: true,
169
+ listener: null,
170
+ polls: [],
171
+ parentStream: null,
172
+ },
173
+ };
174
+ const { udpSocket } = socket;
175
+ datagramStreams.set(id, datagramStream);
176
+ udpSocket.on('error', onError);
177
+ function onError(err) {
178
+ datagramStream.error = err;
179
+ pollStateReady(datagramStream.pollState);
180
+ }
181
+ function cleanup() {
182
+ udpSocket.off('error', onError);
183
+ }
184
+ return datagramStream;
173
185
  }
174
186
 
175
187
  export function socketUdpBindStart(id, localAddress, family) {
176
- const socket = udpSockets.get(id);
177
-
178
- if (family !== localAddress.tag || isIPv4MappedAddress(localAddress))
179
- throw "invalid-argument";
180
-
181
- const serializedLocalAddress = serializeIpAddress(localAddress);
182
-
183
- if (socket.state !== SOCKET_STATE_INIT) throw "invalid-state";
184
- socket.state = SOCKET_STATE_BIND;
185
- const { udpSocket } = socket;
186
- socket.future = createFuture(
187
- new Promise((resolve, reject) => {
188
- function bindOk() {
189
- resolve();
190
- udpSocket.off("error", bindErr);
191
- }
192
- function bindErr(err) {
193
- reject(convertSocketError(err));
194
- udpSocket.off("listening", bindOk);
195
- }
196
- udpSocket.once("listening", bindOk);
197
- udpSocket.once("error", bindErr);
198
- udpSocket.bind(localAddress.val.port, serializedLocalAddress);
199
- }),
200
- socket.pollState
201
- );
188
+ const socket = udpSockets.get(id);
189
+
190
+ if (family !== localAddress.tag || isIPv4MappedAddress(localAddress)) {
191
+ throw 'invalid-argument';
192
+ }
193
+
194
+ const serializedLocalAddress = serializeIpAddress(localAddress);
195
+
196
+ if (socket.state !== SOCKET_STATE_INIT) {
197
+ throw 'invalid-state';
198
+ }
199
+ socket.state = SOCKET_STATE_BIND;
200
+ const { udpSocket } = socket;
201
+ socket.future = createFuture(
202
+ new Promise((resolve, reject) => {
203
+ function bindOk() {
204
+ resolve();
205
+ udpSocket.off('error', bindErr);
206
+ }
207
+ function bindErr(err) {
208
+ reject(convertSocketError(err));
209
+ udpSocket.off('listening', bindOk);
210
+ }
211
+ udpSocket.once('listening', bindOk);
212
+ udpSocket.once('error', bindErr);
213
+ udpSocket.bind(localAddress.val.port, serializedLocalAddress);
214
+ }),
215
+ socket.pollState
216
+ );
202
217
  }
203
218
 
204
219
  export function socketUdpBindFinish(id) {
205
- const socket = udpSockets.get(id);
206
- if (socket.state !== SOCKET_STATE_BIND) throw "not-in-progress";
207
- if (!socket.pollState.ready) throw "would-block";
208
- const { tag, val } = futureTakeValue(socket.future).val;
209
- futureDispose(socket.future, false);
210
- socket.future = null;
211
- if (tag === "err") {
212
- socket.state = SOCKET_STATE_CLOSED;
213
- throw val;
214
- } else {
215
- // once bound, we can now set the options
216
- // since Node.js doesn't support setting them until bound
217
- socket.udpSocket.setTTL(socket.unicastHopLimit);
218
- if (socket.sendBufferSize)
219
- socket.udpSocket.setRecvBufferSize(socket.sendBufferSize);
220
- if (socket.receieveBufferSize)
221
- socket.udpSocket.setSendBufferSize(socket.receiveBufferSize);
222
- socket.state = SOCKET_STATE_BOUND;
223
- return val;
224
- }
220
+ const socket = udpSockets.get(id);
221
+ if (socket.state !== SOCKET_STATE_BIND) {
222
+ throw 'not-in-progress';
223
+ }
224
+ if (!socket.pollState.ready) {
225
+ throw 'would-block';
226
+ }
227
+ const { tag, val } = futureTakeValue(socket.future).val;
228
+ futureDispose(socket.future, false);
229
+ socket.future = null;
230
+ if (tag === 'err') {
231
+ socket.state = SOCKET_STATE_CLOSED;
232
+ throw val;
233
+ } else {
234
+ // once bound, we can now set the options
235
+ // since Node.js doesn't support setting them until bound
236
+ socket.udpSocket.setTTL(socket.unicastHopLimit);
237
+ if (socket.sendBufferSize) {
238
+ socket.udpSocket.setRecvBufferSize(socket.sendBufferSize);
239
+ }
240
+ if (socket.receieveBufferSize) {
241
+ socket.udpSocket.setSendBufferSize(socket.receiveBufferSize);
242
+ }
243
+ socket.state = SOCKET_STATE_BOUND;
244
+ return val;
245
+ }
225
246
  }
226
247
 
227
248
  /**
@@ -229,14 +250,14 @@ export function socketUdpBindFinish(id) {
229
250
  * @returns {IpSocketAddress}
230
251
  */
231
252
  export function socketUdpGetLocalAddress(id) {
232
- const { udpSocket } = udpSockets.get(id);
233
- let address, family, port;
234
- try {
235
- ({ address, family, port } = udpSocket.address());
236
- } catch (err) {
237
- throw convertSocketError(err);
238
- }
239
- return ipSocketAddress(family.toLowerCase(), address, port);
253
+ const { udpSocket } = udpSockets.get(id);
254
+ let address, family, port;
255
+ try {
256
+ ({ address, family, port } = udpSocket.address());
257
+ } catch (err) {
258
+ throw convertSocketError(err);
259
+ }
260
+ return ipSocketAddress(family.toLowerCase(), address, port);
240
261
  }
241
262
 
242
263
  /**
@@ -244,333 +265,377 @@ export function socketUdpGetLocalAddress(id) {
244
265
  * @returns {IpSocketAddress}
245
266
  */
246
267
  export function socketUdpGetRemoteAddress(id) {
247
- const { udpSocket } = udpSockets.get(id);
248
- let address, family, port;
249
- try {
250
- ({ address, family, port } = udpSocket.remoteAddress());
251
- } catch (err) {
252
- throw convertSocketError(err);
253
- }
254
- return ipSocketAddress(family.toLowerCase(), address, port);
268
+ const { udpSocket } = udpSockets.get(id);
269
+ let address, family, port;
270
+ try {
271
+ ({ address, family, port } = udpSocket.remoteAddress());
272
+ } catch (err) {
273
+ throw convertSocketError(err);
274
+ }
275
+ return ipSocketAddress(family.toLowerCase(), address, port);
255
276
  }
256
277
 
257
278
  export function socketUdpStream(id, remoteAddress) {
258
- const socket = udpSockets.get(id);
259
- const { udpSocket } = socket;
260
-
261
- if (
262
- socket.state !== SOCKET_STATE_BOUND &&
263
- socket.state !== SOCKET_STATE_CONNECTION
264
- )
265
- throw "invalid-state";
266
-
267
- if (socket.state === SOCKET_STATE_INIT && !remoteAddress)
268
- throw "invalid-state";
269
-
270
- if (
271
- remoteAddress &&
272
- (remoteAddress.val.port === 0 ||
273
- isWildcardAddress(remoteAddress) ||
274
- (remoteAddress.tag === "ipv6" && isIPv4MappedAddress(remoteAddress)))
275
- )
276
- throw "invalid-argument";
277
-
278
- if (socket.state === SOCKET_STATE_CONNECTION) {
279
- socketDatagramStreamClear(socket.incomingDatagramStream);
280
- socketDatagramStreamClear(socket.outgoingDatagramStream);
281
- try {
282
- udpSocket.disconnect();
283
- } catch (e) {
284
- throw convertSocketErrorCode(e);
285
- }
286
- }
287
-
288
- if (remoteAddress) {
289
- const serializedRemoteAddress = serializeIpAddress(remoteAddress);
290
- socket.remoteAddress = serializedRemoteAddress;
291
- socket.remotePort = remoteAddress.val.port;
292
- return new Promise((resolve, reject) => {
293
- function connectOk() {
294
- if (socket.state === SOCKET_STATE_INIT) {
295
- socket.udpSocket.setTTL(socket.unicastHopLimit);
296
- socket.udpSocket.setRecvBufferSize(socket.sendBufferSize);
297
- socket.udpSocket.setSendBufferSize(socket.receiveBufferSize);
279
+ const socket = udpSockets.get(id);
280
+ const { udpSocket } = socket;
281
+
282
+ if (
283
+ socket.state !== SOCKET_STATE_BOUND &&
284
+ socket.state !== SOCKET_STATE_CONNECTION
285
+ ) {
286
+ throw 'invalid-state';
287
+ }
288
+
289
+ if (socket.state === SOCKET_STATE_INIT && !remoteAddress) {
290
+ throw 'invalid-state';
291
+ }
292
+
293
+ if (
294
+ remoteAddress &&
295
+ (remoteAddress.val.port === 0 ||
296
+ isWildcardAddress(remoteAddress) ||
297
+ (remoteAddress.tag === 'ipv6' &&
298
+ isIPv4MappedAddress(remoteAddress)))
299
+ ) {
300
+ throw 'invalid-argument';
301
+ }
302
+
303
+ if (socket.state === SOCKET_STATE_CONNECTION) {
304
+ socketDatagramStreamClear(socket.incomingDatagramStream);
305
+ socketDatagramStreamClear(socket.outgoingDatagramStream);
306
+ try {
307
+ udpSocket.disconnect();
308
+ } catch (e) {
309
+ throw convertSocketErrorCode(e);
298
310
  }
299
- udpSocket.off("error", connectErr);
300
- socket.state = SOCKET_STATE_CONNECTION;
301
- resolve([
302
- (socket.incomingDatagramStream = createIncomingDatagramStream(socket))
303
- .id,
304
- (socket.outgoingDatagramStream = createOutgoingDatagramStream(socket))
305
- .id,
306
- ]);
307
- }
308
- function connectErr(err) {
309
- udpSocket.off("connect", connectOk);
310
- reject(convertSocketError(err));
311
- }
312
- udpSocket.once("connect", connectOk);
313
- udpSocket.once("error", connectErr);
314
- udpSocket.connect(remoteAddress.val.port, serializedRemoteAddress);
315
- });
316
- } else {
317
- socket.state = SOCKET_STATE_BOUND;
318
- socket.remoteAddress = null;
319
- socket.remotePort = null;
320
- return [
321
- (socket.incomingDatagramStream = createIncomingDatagramStream(socket)).id,
322
- (socket.outgoingDatagramStream = createOutgoingDatagramStream(socket)).id,
323
- ];
324
- }
311
+ }
312
+
313
+ if (remoteAddress) {
314
+ const serializedRemoteAddress = serializeIpAddress(remoteAddress);
315
+ socket.remoteAddress = serializedRemoteAddress;
316
+ socket.remotePort = remoteAddress.val.port;
317
+ return new Promise((resolve, reject) => {
318
+ function connectOk() {
319
+ if (socket.state === SOCKET_STATE_INIT) {
320
+ socket.udpSocket.setTTL(socket.unicastHopLimit);
321
+ socket.udpSocket.setRecvBufferSize(socket.sendBufferSize);
322
+ socket.udpSocket.setSendBufferSize(
323
+ socket.receiveBufferSize
324
+ );
325
+ }
326
+ udpSocket.off('error', connectErr);
327
+ socket.state = SOCKET_STATE_CONNECTION;
328
+ resolve([
329
+ (socket.incomingDatagramStream =
330
+ createIncomingDatagramStream(socket)).id,
331
+ (socket.outgoingDatagramStream =
332
+ createOutgoingDatagramStream(socket)).id,
333
+ ]);
334
+ }
335
+ function connectErr(err) {
336
+ udpSocket.off('connect', connectOk);
337
+ reject(convertSocketError(err));
338
+ }
339
+ udpSocket.once('connect', connectOk);
340
+ udpSocket.once('error', connectErr);
341
+ udpSocket.connect(remoteAddress.val.port, serializedRemoteAddress);
342
+ });
343
+ } else {
344
+ socket.state = SOCKET_STATE_BOUND;
345
+ socket.remoteAddress = null;
346
+ socket.remotePort = null;
347
+ return [
348
+ (socket.incomingDatagramStream =
349
+ createIncomingDatagramStream(socket)).id,
350
+ (socket.outgoingDatagramStream =
351
+ createOutgoingDatagramStream(socket)).id,
352
+ ];
353
+ }
325
354
  }
326
355
 
327
356
  export function socketUdpSetReceiveBufferSize(id, bufferSize) {
328
- const socket = udpSockets.get(id);
329
- bufferSize = Number(bufferSize);
330
- if (
331
- socket.state !== SOCKET_STATE_INIT &&
332
- socket.state !== SOCKET_STATE_BIND
333
- ) {
334
- try {
335
- socket.udpSocket.setRecvBufferSize(bufferSize);
336
- } catch (err) {
337
- throw convertSocketError(err);
357
+ const socket = udpSockets.get(id);
358
+ bufferSize = Number(bufferSize);
359
+ if (
360
+ socket.state !== SOCKET_STATE_INIT &&
361
+ socket.state !== SOCKET_STATE_BIND
362
+ ) {
363
+ try {
364
+ socket.udpSocket.setRecvBufferSize(bufferSize);
365
+ } catch (err) {
366
+ throw convertSocketError(err);
367
+ }
338
368
  }
339
- }
340
- socket.receiveBufferSize = bufferSize;
369
+ socket.receiveBufferSize = bufferSize;
341
370
  }
342
371
 
343
372
  export function socketUdpSetSendBufferSize(id, bufferSize) {
344
- const socket = udpSockets.get(id);
345
- bufferSize = Number(bufferSize);
346
- if (
347
- socket.state !== SOCKET_STATE_INIT &&
348
- socket.state !== SOCKET_STATE_BIND
349
- ) {
350
- try {
351
- socket.udpSocket.setSendBufferSize(bufferSize);
352
- } catch (err) {
353
- throw convertSocketError(err);
373
+ const socket = udpSockets.get(id);
374
+ bufferSize = Number(bufferSize);
375
+ if (
376
+ socket.state !== SOCKET_STATE_INIT &&
377
+ socket.state !== SOCKET_STATE_BIND
378
+ ) {
379
+ try {
380
+ socket.udpSocket.setSendBufferSize(bufferSize);
381
+ } catch (err) {
382
+ throw convertSocketError(err);
383
+ }
354
384
  }
355
- }
356
- socket.sendBufferSize = bufferSize;
385
+ socket.sendBufferSize = bufferSize;
357
386
  }
358
387
 
359
388
  export function socketUdpSetUnicastHopLimit(id, hopLimit) {
360
- const socket = udpSockets.get(id);
361
- if (
362
- socket.state !== SOCKET_STATE_INIT &&
363
- socket.state !== SOCKET_STATE_BIND
364
- ) {
365
- try {
366
- socket.udpSocket.setTTL(hopLimit);
367
- } catch (err) {
368
- throw convertSocketError(err);
389
+ const socket = udpSockets.get(id);
390
+ if (
391
+ socket.state !== SOCKET_STATE_INIT &&
392
+ socket.state !== SOCKET_STATE_BIND
393
+ ) {
394
+ try {
395
+ socket.udpSocket.setTTL(hopLimit);
396
+ } catch (err) {
397
+ throw convertSocketError(err);
398
+ }
369
399
  }
370
- }
371
- socket.unicastHopLimit = hopLimit;
400
+ socket.unicastHopLimit = hopLimit;
372
401
  }
373
402
 
374
403
  export async function socketUdpGetReceiveBufferSize(id) {
375
- const socket = udpSockets.get(id);
376
- if (socket.receiveBufferSize) return BigInt(socket.receiveBufferSize);
377
- if (
378
- socket.state !== SOCKET_STATE_INIT &&
379
- socket.state !== SOCKET_STATE_BIND
380
- ) {
381
- try {
382
- return BigInt(
383
- (socket.receiveBufferSize = socket.udpSocket.getRecvBufferSize())
384
- );
385
- } catch (err) {
386
- throw convertSocketError(err);
404
+ const socket = udpSockets.get(id);
405
+ if (socket.receiveBufferSize) {
406
+ return BigInt(socket.receiveBufferSize);
407
+ }
408
+ if (
409
+ socket.state !== SOCKET_STATE_INIT &&
410
+ socket.state !== SOCKET_STATE_BIND
411
+ ) {
412
+ try {
413
+ return BigInt(
414
+ (socket.receiveBufferSize =
415
+ socket.udpSocket.getRecvBufferSize())
416
+ );
417
+ } catch (err) {
418
+ throw convertSocketError(err);
419
+ }
420
+ } else {
421
+ return BigInt(
422
+ (socket.receiveBufferSize = await getDefaultReceiveBufferSize())
423
+ );
387
424
  }
388
- } else {
389
- return BigInt(
390
- (socket.receiveBufferSize = await getDefaultReceiveBufferSize())
391
- );
392
- }
393
425
  }
394
426
 
395
427
  export async function socketUdpGetSendBufferSize(id) {
396
- const socket = udpSockets.get(id);
397
- if (socket.sendBufferSize) return BigInt(socket.sendBufferSize);
398
- if (
399
- socket.state !== SOCKET_STATE_INIT &&
400
- socket.state !== SOCKET_STATE_BIND
401
- ) {
402
- try {
403
- return BigInt(
404
- (socket.sendBufferSize = socket.udpSocket.getSendBufferSize())
405
- );
406
- } catch (err) {
407
- throw convertSocketError(err);
428
+ const socket = udpSockets.get(id);
429
+ if (socket.sendBufferSize) {
430
+ return BigInt(socket.sendBufferSize);
431
+ }
432
+ if (
433
+ socket.state !== SOCKET_STATE_INIT &&
434
+ socket.state !== SOCKET_STATE_BIND
435
+ ) {
436
+ try {
437
+ return BigInt(
438
+ (socket.sendBufferSize = socket.udpSocket.getSendBufferSize())
439
+ );
440
+ } catch (err) {
441
+ throw convertSocketError(err);
442
+ }
443
+ } else {
444
+ return BigInt(
445
+ (socket.sendBufferSize = await getDefaultSendBufferSize())
446
+ );
408
447
  }
409
- } else {
410
- return BigInt((socket.sendBufferSize = await getDefaultSendBufferSize()));
411
- }
412
448
  }
413
449
 
414
450
  export function socketUdpGetUnicastHopLimit(id) {
415
- const { unicastHopLimit } = udpSockets.get(id);
416
- return unicastHopLimit;
451
+ const { unicastHopLimit } = udpSockets.get(id);
452
+ return unicastHopLimit;
417
453
  }
418
454
 
419
455
  export function socketUdpDispose(id) {
420
- const { udpSocket } = udpSockets.get(id);
421
- return new Promise((resolve) => {
422
- udpSocket.close(() => {
423
- udpSockets.delete(id);
424
- resolve(0);
456
+ const { udpSocket } = udpSockets.get(id);
457
+ return new Promise((resolve) => {
458
+ udpSocket.close(() => {
459
+ udpSockets.delete(id);
460
+ resolve(0);
461
+ });
425
462
  });
426
- });
427
463
  }
428
464
 
429
465
  export function socketIncomingDatagramStreamReceive(id, maxResults) {
430
- const datagramStream = datagramStreams.get(id);
431
- if (!datagramStream.active)
432
- throw new Error(
433
- "wasi-io trap: attempt to receive on inactive incoming datagram stream"
434
- );
435
- if (maxResults === 0n || datagramStream.queue.length === 0) return [];
436
- if (datagramStream.error) throw convertSocketError(datagramStream.error);
437
- return datagramStream.queue.splice(0, Number(maxResults));
466
+ const datagramStream = datagramStreams.get(id);
467
+ if (!datagramStream.active) {
468
+ throw new Error(
469
+ 'wasi-io trap: attempt to receive on inactive incoming datagram stream'
470
+ );
471
+ }
472
+ if (maxResults === 0n || datagramStream.queue.length === 0) {
473
+ return [];
474
+ }
475
+ if (datagramStream.error) {
476
+ throw convertSocketError(datagramStream.error);
477
+ }
478
+ return datagramStream.queue.splice(0, Number(maxResults));
438
479
  }
439
480
 
440
481
  export async function socketOutgoingDatagramStreamSend(id, datagrams) {
441
- const { active, socket } = datagramStreams.get(id);
442
- if (!active)
443
- throw new Error(
444
- "wasi-io trap: writing to inactive outgoing datagram stream"
445
- );
482
+ const { active, socket } = datagramStreams.get(id);
483
+ if (!active) {
484
+ throw new Error(
485
+ 'wasi-io trap: writing to inactive outgoing datagram stream'
486
+ );
487
+ }
446
488
 
447
- const { udpSocket } = socket;
448
- let sendQueue = [],
449
- sendQueueAddress,
450
- sendQueuePort;
451
- let datagramsSent = 0;
452
- for (const { data, remoteAddress } of datagrams) {
453
- const address = remoteAddress
454
- ? serializeIpAddress(remoteAddress)
455
- : socket.remoteAddress;
456
- const port = remoteAddress?.val.port ?? socket.remotePort;
457
- let sendLastBatch = !UDP_BATCH_SENDS;
458
- if (sendQueue.length > 0) {
459
- if (sendQueueAddress === address && sendQueuePort === port) {
460
- sendQueue.push(data);
461
- } else {
462
- sendLastBatch = true;
463
- }
464
- } else {
465
- sendQueueAddress = address;
466
- sendQueuePort = port;
467
- sendQueue.push(data);
468
- }
469
- if (sendLastBatch) {
470
- const err = await doSendBatch();
471
- if (err) return BigInt(datagramsSent);
472
- if (UDP_BATCH_SENDS) {
473
- sendQueue = [data];
474
- sendQueuePort = port;
475
- sendQueueAddress = address;
476
- } else {
477
- sendQueue = [];
478
- sendQueuePort = port;
479
- sendQueueAddress = address;
480
- }
481
- }
482
- }
483
- if (sendQueue.length) {
484
- const err = await doSendBatch();
485
- if (err) return BigInt(datagramsSent);
486
- }
487
-
488
- if (datagramsSent !== datagrams.length)
489
- throw new Error("wasi-io trap: expected to have sent all the datagrams");
490
- return BigInt(datagramsSent);
491
-
492
- function doSendBatch() {
493
- return new Promise((resolve, reject) => {
494
- if (socket.remoteAddress) {
495
- if (sendQueueAddress !== socket.remoteAddress || sendQueuePort !== socket.remotePort)
496
- return void reject("invalid-argument");
497
- udpSocket.send(sendQueue, handler);
498
- } else {
499
- if (!sendQueueAddress)
500
- return void reject("invalid-argument");
501
- udpSocket.send(sendQueue, sendQueuePort, sendQueueAddress, handler);
502
- }
503
- function handler(err, _sentBytes) {
489
+ const { udpSocket } = socket;
490
+ let sendQueue = [],
491
+ sendQueueAddress,
492
+ sendQueuePort;
493
+ let datagramsSent = 0;
494
+ for (const { data, remoteAddress } of datagrams) {
495
+ const address = remoteAddress
496
+ ? serializeIpAddress(remoteAddress)
497
+ : socket.remoteAddress;
498
+ const port = remoteAddress?.val.port ?? socket.remotePort;
499
+ let sendLastBatch = !UDP_BATCH_SENDS;
500
+ if (sendQueue.length > 0) {
501
+ if (sendQueueAddress === address && sendQueuePort === port) {
502
+ sendQueue.push(data);
503
+ } else {
504
+ sendLastBatch = true;
505
+ }
506
+ } else {
507
+ sendQueueAddress = address;
508
+ sendQueuePort = port;
509
+ sendQueue.push(data);
510
+ }
511
+ if (sendLastBatch) {
512
+ const err = await doSendBatch();
513
+ if (err) {
514
+ return BigInt(datagramsSent);
515
+ }
516
+ if (UDP_BATCH_SENDS) {
517
+ sendQueue = [data];
518
+ sendQueuePort = port;
519
+ sendQueueAddress = address;
520
+ } else {
521
+ sendQueue = [];
522
+ sendQueuePort = port;
523
+ sendQueueAddress = address;
524
+ }
525
+ }
526
+ }
527
+ if (sendQueue.length) {
528
+ const err = await doSendBatch();
504
529
  if (err) {
505
- // TODO: update datagramsSent properly on error for multiple sends
506
- // to enable send batching. Perhaps a Node.js PR could
507
- // still set the second sendBytes arg?
508
- if (datagramsSent > 0) resolve(datagramsSent);
509
- else reject(convertSocketError(err));
510
- return;
530
+ return BigInt(datagramsSent);
511
531
  }
512
- datagramsSent += sendQueue.length;
513
- resolve(false);
514
- }
515
- });
516
- }
532
+ }
533
+
534
+ if (datagramsSent !== datagrams.length) {
535
+ throw new Error(
536
+ 'wasi-io trap: expected to have sent all the datagrams'
537
+ );
538
+ }
539
+ return BigInt(datagramsSent);
540
+
541
+ function doSendBatch() {
542
+ return new Promise((resolve, reject) => {
543
+ if (socket.remoteAddress) {
544
+ if (
545
+ sendQueueAddress !== socket.remoteAddress ||
546
+ sendQueuePort !== socket.remotePort
547
+ ) {
548
+ return void reject('invalid-argument');
549
+ }
550
+ udpSocket.send(sendQueue, handler);
551
+ } else {
552
+ if (!sendQueueAddress) {
553
+ return void reject('invalid-argument');
554
+ }
555
+ udpSocket.send(
556
+ sendQueue,
557
+ sendQueuePort,
558
+ sendQueueAddress,
559
+ handler
560
+ );
561
+ }
562
+ function handler(err, _sentBytes) {
563
+ if (err) {
564
+ // TODO: update datagramsSent properly on error for multiple sends
565
+ // to enable send batching. Perhaps a Node.js PR could
566
+ // still set the second sendBytes arg?
567
+ if (datagramsSent > 0) {
568
+ resolve(datagramsSent);
569
+ } else {
570
+ reject(convertSocketError(err));
571
+ }
572
+ return;
573
+ }
574
+ datagramsSent += sendQueue.length;
575
+ resolve(false);
576
+ }
577
+ });
578
+ }
517
579
  }
518
580
 
519
581
  function checkSend(socket) {
520
- try {
521
- return Math.floor(
522
- (socket.udpSocket.getSendBufferSize() -
523
- socket.udpSocket.getSendQueueSize()) /
524
- 1500
525
- );
526
- } catch (err) {
527
- throw convertSocketError(err);
528
- }
582
+ try {
583
+ return Math.floor(
584
+ (socket.udpSocket.getSendBufferSize() -
585
+ socket.udpSocket.getSendQueueSize()) /
586
+ 1500
587
+ );
588
+ } catch (err) {
589
+ throw convertSocketError(err);
590
+ }
529
591
  }
530
592
 
531
593
  function pollSend(socket) {
532
- socket.pollState.ready = false;
533
- // The only way we have of dealing with getting a backpressure
534
- // ready signal in Node.js is to just poll on the queue reducing.
535
- // Ideally this should implement backoff on the poll interval,
536
- // but that work should be done alongside careful benchmarking
537
- // in due course.
538
- setTimeout(() => {
539
- const remaining = checkSend(socket);
540
- if (remaining > 0) {
541
- pollStateReady(socket.pollState);
542
- } else {
543
- pollSend(socket);
544
- }
545
- });
594
+ socket.pollState.ready = false;
595
+ // The only way we have of dealing with getting a backpressure
596
+ // ready signal in Node.js is to just poll on the queue reducing.
597
+ // Ideally this should implement backoff on the poll interval,
598
+ // but that work should be done alongside careful benchmarking
599
+ // in due course.
600
+ setTimeout(() => {
601
+ const remaining = checkSend(socket);
602
+ if (remaining > 0) {
603
+ pollStateReady(socket.pollState);
604
+ } else {
605
+ pollSend(socket);
606
+ }
607
+ });
546
608
  }
547
609
 
548
610
  export function socketOutgoingDatagramStreamCheckSend(id) {
549
- const { active, socket } = datagramStreams.get(id);
550
- if (!active)
551
- throw new Error(
552
- "wasi-io trap: check send on inactive outgoing datagram stream"
553
- );
554
- const remaining = checkSend(socket);
555
- if (remaining <= 0) pollSend(socket);
556
- return BigInt(remaining);
611
+ const { active, socket } = datagramStreams.get(id);
612
+ if (!active) {
613
+ throw new Error(
614
+ 'wasi-io trap: check send on inactive outgoing datagram stream'
615
+ );
616
+ }
617
+ const remaining = checkSend(socket);
618
+ if (remaining <= 0) {
619
+ pollSend(socket);
620
+ }
621
+ return BigInt(remaining);
557
622
  }
558
623
 
559
624
  function socketDatagramStreamClear(datagramStream) {
560
- datagramStream.active = false;
561
- if (datagramStream.cleanup) {
562
- datagramStream.cleanup();
563
- datagramStream.cleanup = null;
564
- }
625
+ datagramStream.active = false;
626
+ if (datagramStream.cleanup) {
627
+ datagramStream.cleanup();
628
+ datagramStream.cleanup = null;
629
+ }
565
630
  }
566
631
 
567
632
  export function socketDatagramStreamDispose(id) {
568
- const datagramStream = datagramStreams.get(id);
569
- datagramStream.active = false;
570
- if (datagramStream.cleanup) {
571
- datagramStream.cleanup();
572
- datagramStream.cleanup = null;
573
- }
574
- verifyPollsDroppedForDrop(datagramStream.pollState, "datagram stream");
575
- datagramStreams.delete(id);
633
+ const datagramStream = datagramStreams.get(id);
634
+ datagramStream.active = false;
635
+ if (datagramStream.cleanup) {
636
+ datagramStream.cleanup();
637
+ datagramStream.cleanup = null;
638
+ }
639
+ verifyPollsDroppedForDrop(datagramStream.pollState, 'datagram stream');
640
+ datagramStreams.delete(id);
576
641
  }