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