@bytecodealliance/preview2-shim 0.17.2 → 0.17.3
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/cli.js +91 -94
- package/lib/browser/clocks.js +30 -29
- package/lib/browser/filesystem.js +298 -251
- package/lib/browser/http.js +129 -128
- package/lib/browser/index.js +8 -16
- package/lib/browser/io.js +143 -135
- package/lib/browser/random.js +44 -42
- package/lib/browser/sockets.js +68 -166
- package/lib/common/instantiation.js +127 -0
- package/lib/io/calls.js +7 -5
- package/lib/io/worker-http.js +175 -157
- package/lib/io/worker-io.js +402 -386
- package/lib/io/worker-socket-tcp.js +271 -219
- package/lib/io/worker-socket-udp.js +494 -429
- package/lib/io/worker-sockets.js +276 -262
- package/lib/io/worker-thread.js +943 -864
- package/lib/nodejs/cli.js +64 -63
- package/lib/nodejs/clocks.js +51 -45
- package/lib/nodejs/filesystem.js +788 -654
- package/lib/nodejs/http.js +693 -617
- package/lib/nodejs/index.js +8 -16
- package/lib/nodejs/random.js +32 -28
- package/lib/nodejs/sockets.js +538 -474
- package/lib/synckit/index.js +94 -85
- package/package.json +9 -5
- package/types/index.d.ts +0 -1
- package/types/instantiation.d.ts +112 -0
|
@@ -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,27 +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
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
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
|
-
|
|
416
|
-
|
|
451
|
+
const { unicastHopLimit } = udpSockets.get(id);
|
|
452
|
+
return unicastHopLimit;
|
|
417
453
|
}
|
|
418
454
|
|
|
419
455
|
export function socketUdpDispose(id) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
513
|
-
|
|
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
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
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
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
}
|