@bytecodealliance/preview2-shim 0.20.2 → 0.21.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.
@@ -1,5 +1,5 @@
1
1
  import { PollState } from "./worker-thread.js";
2
- import { Socket as TcpSocket } from "node:net";
2
+ import { Server, Socket as TcpSocket } from "node:net";
3
3
  import { IpSocketAddress } from "../../types/interfaces/wasi-sockets-network.js";
4
4
  interface PendingAccept {
5
5
  tcpSocket: TcpSocket | null;
@@ -10,8 +10,11 @@ interface TcpSocketRecord {
10
10
  state: number;
11
11
  future: number | null;
12
12
  tcpSocket: TcpSocket | null;
13
+ server: Server | null;
14
+ localAddress: IpSocketAddress | null;
13
15
  listenBacklogSize: number;
14
- handle: TCP;
16
+ keepAlive: boolean;
17
+ keepAliveIdleTime: number;
15
18
  pendingAccepts: PendingAccept[];
16
19
  pollState: PollState | null;
17
20
  }
@@ -1,20 +1,20 @@
1
1
  import { createFuture, createReadableStream, createReadableStreamPollState, createWritableStream, futureDispose, futureTakeValue, pollStateReady, verifyPollsDroppedForDrop, } from "./worker-thread.js";
2
2
  import process from "node:process";
3
- // TODO: tcp_wrap is no longer exposed in newer versions of Node.js
4
- const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
5
- import { convertSocketError, convertSocketErrorCode, ipSocketAddress, isIPv4MappedAddress, isMulticastIpAddress, isUnicastIpAddress, isWildcardAddress, noLookup, serializeIpAddress, SOCKET_STATE_BIND, SOCKET_STATE_BOUND, SOCKET_STATE_CLOSED, SOCKET_STATE_CONNECT, SOCKET_STATE_CONNECTION, SOCKET_STATE_INIT, SOCKET_STATE_LISTEN, SOCKET_STATE_LISTENER, } from "./worker-sockets.js";
3
+ import { convertSocketError, ipSocketAddress, isIPv4MappedAddress, isMulticastIpAddress, isUnicastIpAddress, isWildcardAddress, noLookup, serializeIpAddress, SOCKET_STATE_BIND, SOCKET_STATE_BOUND, SOCKET_STATE_CLOSED, SOCKET_STATE_CONNECT, SOCKET_STATE_CONNECTION, SOCKET_STATE_INIT, SOCKET_STATE_LISTEN, SOCKET_STATE_LISTENER, } from "./worker-sockets.js";
6
4
  import { Server, Socket as TcpSocket } from "node:net";
7
5
  const win = process.platform === "win32";
8
6
  export const tcpSockets = new Map();
9
7
  let tcpSocketCnt = 0;
10
8
  export function createTcpSocket() {
11
- const handle = new TCP(TCPConstants.SOCKET);
12
9
  tcpSockets.set(++tcpSocketCnt, {
13
10
  state: SOCKET_STATE_INIT,
14
11
  future: null,
15
12
  tcpSocket: null,
13
+ server: null,
14
+ localAddress: null,
16
15
  listenBacklogSize: 128,
17
- handle,
16
+ keepAlive: false,
17
+ keepAliveIdleTime: 0,
18
18
  pendingAccepts: [],
19
19
  pollState: {
20
20
  ready: true,
@@ -44,7 +44,7 @@ export function socketTcpFinish(id, fromState, toState) {
44
44
  socket.state = toState;
45
45
  // for the listener, we must immediately transition back to unresolved
46
46
  if (toState === SOCKET_STATE_LISTENER) {
47
- socket.pollState.ready = false;
47
+ socket.pollState.ready = socket.pendingAccepts.length > 0;
48
48
  }
49
49
  return val;
50
50
  }
@@ -60,26 +60,77 @@ export function socketTcpBindStart(id, localAddress, family) {
60
60
  throw "invalid-argument";
61
61
  }
62
62
  socket.state = SOCKET_STATE_BIND;
63
- const { handle } = socket;
64
- socket.future = createFuture((async () => {
63
+ socket.future = createFuture(new Promise((resolve, reject) => {
65
64
  const address = serializeIpAddress(localAddress);
66
65
  const port = localAddress.val.port;
67
- const code = localAddress.tag === "ipv6"
68
- ? handle.bind6(address, port, TCPConstants.UV_TCP_IPV6ONLY)
69
- : handle.bind(address, port);
70
- if (code !== 0) {
71
- throw convertSocketErrorCode(-code);
66
+ // node:net has no public standalone TCP bind API. Keep a server open
67
+ // to reserve the endpoint, then reuse it for listen or close it for connect.
68
+ const server = (socket.server = createTcpServer(socket));
69
+ function handleErr(err) {
70
+ server.off("listening", handleListen);
71
+ reject(convertSocketError(err));
72
72
  }
73
- // This is a Node.js / libuv quirk to force the bind error to be thrown
74
- // (specifically address-in-use).
75
- {
76
- const out = {};
77
- const code = handle.getsockname(out);
78
- if (code !== 0) {
79
- throw convertSocketErrorCode(-code);
73
+ function handleListen() {
74
+ server.off("error", handleErr);
75
+ const boundAddress = server.address();
76
+ if (!boundAddress || typeof boundAddress === "string") {
77
+ reject("invalid-state");
78
+ return;
80
79
  }
80
+ socket.localAddress = ipSocketAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
81
+ resolve();
81
82
  }
82
- })(), socket.pollState);
83
+ server.once("listening", handleListen);
84
+ server.once("error", handleErr);
85
+ server.listen({
86
+ host: address ?? undefined,
87
+ port,
88
+ backlog: socket.listenBacklogSize,
89
+ ipv6Only: family === "ipv6",
90
+ });
91
+ }), socket.pollState);
92
+ }
93
+ function createTcpServer(socket) {
94
+ const server = new Server({
95
+ pauseOnConnect: true,
96
+ allowHalfOpen: true,
97
+ });
98
+ server.on("connection", (tcpSocket) => {
99
+ // The reservation is already listening at the OS level, so reject any
100
+ // connections that arrive before the WASI socket enters its listen state.
101
+ if (socket.state !== SOCKET_STATE_LISTEN && socket.state !== SOCKET_STATE_LISTENER) {
102
+ tcpSocket.destroy();
103
+ return;
104
+ }
105
+ pollStateReady(socket.pollState);
106
+ const pollState = createReadableStreamPollState(tcpSocket);
107
+ socket.pendingAccepts.push({
108
+ tcpSocket,
109
+ err: null,
110
+ pollState,
111
+ });
112
+ });
113
+ server.on("error", (err) => {
114
+ if (socket.state === SOCKET_STATE_LISTEN || socket.state === SOCKET_STATE_LISTENER) {
115
+ pollStateReady(socket.pollState);
116
+ socket.pendingAccepts.push({
117
+ tcpSocket: null,
118
+ err,
119
+ pollState: null,
120
+ });
121
+ }
122
+ });
123
+ return server;
124
+ }
125
+ function closeTcpServer(socket) {
126
+ const server = socket.server;
127
+ socket.server = null;
128
+ if (!server) {
129
+ return Promise.resolve();
130
+ }
131
+ return new Promise((resolve, reject) => {
132
+ server.close((err) => (err ? reject(err) : resolve()));
133
+ });
83
134
  }
84
135
  export function socketTcpConnectStart(id, remoteAddress, family) {
85
136
  const socket = tcpSockets.get(id);
@@ -95,71 +146,44 @@ export function socketTcpConnectStart(id, remoteAddress, family) {
95
146
  throw "invalid-argument";
96
147
  }
97
148
  socket.state = SOCKET_STATE_CONNECT;
98
- socket.future = createFuture(new Promise((resolve, reject) => {
149
+ socket.future = createFuture((async () => {
150
+ const localAddress = socket.localAddress;
151
+ await closeTcpServer(socket);
99
152
  const tcpSocket = (socket.tcpSocket = new TcpSocket({
100
- // @ts-expect-error Not present in type definition
101
- handle: socket.handle,
102
- pauseOnCreate: true,
103
153
  allowHalfOpen: true,
104
154
  }));
105
- function handleErr(err) {
106
- tcpSocket.off("connect", handleConnect);
107
- reject(convertSocketError(err));
108
- }
109
- function handleConnect() {
110
- tcpSocket.off("error", handleErr);
111
- resolve([createReadableStream(tcpSocket), createWritableStream(tcpSocket)]);
112
- }
113
- tcpSocket.once("connect", handleConnect);
114
- tcpSocket.once("error", handleErr);
115
- tcpSocket.connect({
116
- port: remoteAddress.val.port,
117
- host: serializeIpAddress(remoteAddress) ?? undefined,
118
- lookup: noLookup,
155
+ tcpSocket.setKeepAlive(socket.keepAlive, socket.keepAliveIdleTime);
156
+ await new Promise((resolve, reject) => {
157
+ function handleErr(err) {
158
+ tcpSocket.off("connect", handleConnect);
159
+ reject(convertSocketError(err));
160
+ }
161
+ function handleConnect() {
162
+ tcpSocket.off("error", handleErr);
163
+ resolve();
164
+ }
165
+ tcpSocket.once("connect", handleConnect);
166
+ tcpSocket.once("error", handleErr);
167
+ tcpSocket.connect({
168
+ port: remoteAddress.val.port,
169
+ host: serializeIpAddress(remoteAddress) ?? undefined,
170
+ lookup: noLookup,
171
+ localAddress: localAddress
172
+ ? (serializeIpAddress(localAddress) ?? undefined)
173
+ : undefined,
174
+ localPort: localAddress?.val.port,
175
+ });
119
176
  });
120
- }), socket.pollState);
177
+ return [createReadableStream(tcpSocket), createWritableStream(tcpSocket)];
178
+ })(), socket.pollState);
121
179
  }
122
180
  export function socketTcpListenStart(id) {
123
181
  const socket = tcpSockets.get(id);
124
182
  if (socket.state !== SOCKET_STATE_BOUND) {
125
183
  throw "invalid-state";
126
184
  }
127
- const { handle } = socket;
128
185
  socket.state = SOCKET_STATE_LISTEN;
129
- socket.future = createFuture(new Promise((resolve, reject) => {
130
- const server = new Server({
131
- pauseOnConnect: true,
132
- allowHalfOpen: true,
133
- });
134
- function handleErr(err) {
135
- server.off("listening", handleListen);
136
- reject(convertSocketError(err));
137
- }
138
- function handleListen() {
139
- server.off("error", handleErr);
140
- server.on("connection", (tcpSocket) => {
141
- pollStateReady(socket.pollState);
142
- const pollState = createReadableStreamPollState(tcpSocket);
143
- socket.pendingAccepts.push({
144
- tcpSocket,
145
- err: null,
146
- pollState,
147
- });
148
- });
149
- server.on("error", (err) => {
150
- pollStateReady(socket.pollState);
151
- socket.pendingAccepts.push({
152
- tcpSocket: null,
153
- err,
154
- pollState: null,
155
- });
156
- });
157
- resolve();
158
- }
159
- server.once("listening", handleListen);
160
- server.once("error", handleErr);
161
- server.listen(handle, socket.listenBacklogSize);
162
- }), socket.pollState);
186
+ socket.future = createFuture(Promise.resolve(), socket.pollState);
163
187
  }
164
188
  export function socketTcpAccept(id) {
165
189
  const socket = tcpSockets.get(id);
@@ -181,9 +205,11 @@ export function socketTcpAccept(id) {
181
205
  state: SOCKET_STATE_CONNECTION,
182
206
  future: null,
183
207
  tcpSocket: accept.tcpSocket,
208
+ server: null,
209
+ localAddress: null,
184
210
  listenBacklogSize: 128,
185
- // @ts-expect-error
186
- handle: accept.tcpSocket?._handle,
211
+ keepAlive: false,
212
+ keepAliveIdleTime: 0,
187
213
  pendingAccepts: [],
188
214
  pollState: accept.pollState,
189
215
  });
@@ -207,22 +233,22 @@ export function socketTcpSetListenBacklogSize(id, backlogSize) {
207
233
  socket.listenBacklogSize = Number(backlogSize);
208
234
  }
209
235
  export function socketTcpGetLocalAddress(id) {
210
- const { handle } = tcpSockets.get(id);
211
- const out = {};
212
- const code = handle.getsockname(out);
213
- if (code !== 0) {
214
- throw convertSocketErrorCode(-code);
236
+ const socket = tcpSockets.get(id);
237
+ const address = socket.tcpSocket?.address();
238
+ if (address && typeof address !== "string" && "family" in address) {
239
+ return ipSocketAddress(address.family.toLowerCase(), address.address, address.port);
240
+ }
241
+ if (socket.localAddress) {
242
+ return socket.localAddress;
215
243
  }
216
- return ipSocketAddress(out.family.toLowerCase(), out.address, out.port);
244
+ throw "invalid-state";
217
245
  }
218
246
  export function socketTcpGetRemoteAddress(id) {
219
- const { handle } = tcpSockets.get(id);
220
- const out = {};
221
- const code = handle.getpeername(out);
222
- if (code !== 0) {
223
- throw convertSocketErrorCode(-code);
247
+ const { tcpSocket } = tcpSockets.get(id);
248
+ if (!tcpSocket?.remoteFamily || !tcpSocket.remoteAddress || !tcpSocket.remotePort) {
249
+ throw "invalid-state";
224
250
  }
225
- return ipSocketAddress(out.family.toLowerCase(), out.address, out.port);
251
+ return ipSocketAddress(tcpSocket.remoteFamily.toLowerCase(), tcpSocket.remoteAddress, tcpSocket.remotePort);
226
252
  }
227
253
  export function socketTcpShutdown(id, _shutdownType) {
228
254
  const socket = tcpSockets.get(id);
@@ -237,15 +263,15 @@ export function socketTcpShutdown(id, _shutdownType) {
237
263
  }
238
264
  }
239
265
  export function socketTcpSetKeepAlive(id, { keepAlive, keepAliveIdleTime }) {
240
- const { handle } = tcpSockets.get(id);
241
- const code = handle.setKeepAlive(keepAlive, Number(keepAliveIdleTime / 1000000000n));
242
- if (code !== 0) {
243
- throw convertSocketErrorCode(-code);
244
- }
266
+ const socket = tcpSockets.get(id);
267
+ socket.keepAlive = keepAlive;
268
+ socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
269
+ socket.tcpSocket?.setKeepAlive(socket.keepAlive, socket.keepAliveIdleTime);
245
270
  }
246
271
  export function socketTcpDispose(id) {
247
272
  const socket = tcpSockets.get(id);
248
273
  verifyPollsDroppedForDrop(socket.pollState, "tcp socket");
249
- socket.handle.close();
274
+ socket.server?.close();
275
+ socket.tcpSocket?.destroy();
250
276
  tcpSockets.delete(id);
251
277
  }
@@ -719,18 +719,19 @@ async function getDefaultReceiveBufferSize() {
719
719
  }
720
720
  //#endregion
721
721
  //#region dist/io/worker-socket-tcp.js
722
- const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
723
722
  const win = process.platform === "win32";
724
723
  const tcpSockets = /* @__PURE__ */ new Map();
725
724
  let tcpSocketCnt = 0;
726
725
  function createTcpSocket() {
727
- const handle = new TCP(TCPConstants.SOCKET);
728
726
  tcpSockets.set(++tcpSocketCnt, {
729
727
  state: SOCKET_STATE_INIT,
730
728
  future: null,
731
729
  tcpSocket: null,
730
+ server: null,
731
+ localAddress: null,
732
732
  listenBacklogSize: 128,
733
- handle,
733
+ keepAlive: false,
734
+ keepAliveIdleTime: 0,
734
735
  pendingAccepts: [],
735
736
  pollState: {
736
737
  ready: true,
@@ -753,7 +754,7 @@ function socketTcpFinish(id, fromState, toState) {
753
754
  throw val;
754
755
  } else {
755
756
  socket.state = toState;
756
- if (toState === SOCKET_STATE_LISTENER) socket.pollState.ready = false;
757
+ if (toState === SOCKET_STATE_LISTENER) socket.pollState.ready = socket.pendingAccepts.length > 0;
757
758
  return val;
758
759
  }
759
760
  }
@@ -762,85 +763,109 @@ function socketTcpBindStart(id, localAddress, family) {
762
763
  if (socket.state !== SOCKET_STATE_INIT) throw "invalid-state";
763
764
  if (family !== localAddress.tag || !isUnicastIpAddress(localAddress) || isIPv4MappedAddress(localAddress)) throw "invalid-argument";
764
765
  socket.state = SOCKET_STATE_BIND;
765
- const { handle } = socket;
766
- socket.future = createFuture((async () => {
766
+ socket.future = createFuture(new Promise((resolve, reject) => {
767
767
  const address = serializeIpAddress(localAddress);
768
768
  const port = localAddress.val.port;
769
- const code = localAddress.tag === "ipv6" ? handle.bind6(address, port, TCPConstants.UV_TCP_IPV6ONLY) : handle.bind(address, port);
770
- if (code !== 0) throw convertSocketErrorCode(-code);
771
- {
772
- const code = handle.getsockname({});
773
- if (code !== 0) throw convertSocketErrorCode(-code);
769
+ const server = socket.server = createTcpServer(socket);
770
+ function handleErr(err) {
771
+ server.off("listening", handleListen);
772
+ reject(convertSocketError(err));
774
773
  }
775
- })(), socket.pollState);
774
+ function handleListen() {
775
+ server.off("error", handleErr);
776
+ const boundAddress = server.address();
777
+ if (!boundAddress || typeof boundAddress === "string") {
778
+ reject("invalid-state");
779
+ return;
780
+ }
781
+ socket.localAddress = ipSocketAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
782
+ resolve();
783
+ }
784
+ server.once("listening", handleListen);
785
+ server.once("error", handleErr);
786
+ server.listen({
787
+ host: address ?? void 0,
788
+ port,
789
+ backlog: socket.listenBacklogSize,
790
+ ipv6Only: family === "ipv6"
791
+ });
792
+ }), socket.pollState);
793
+ }
794
+ function createTcpServer(socket) {
795
+ const server = new Server({
796
+ pauseOnConnect: true,
797
+ allowHalfOpen: true
798
+ });
799
+ server.on("connection", (tcpSocket) => {
800
+ if (socket.state !== SOCKET_STATE_LISTEN && socket.state !== SOCKET_STATE_LISTENER) {
801
+ tcpSocket.destroy();
802
+ return;
803
+ }
804
+ pollStateReady(socket.pollState);
805
+ const pollState = createReadableStreamPollState(tcpSocket);
806
+ socket.pendingAccepts.push({
807
+ tcpSocket,
808
+ err: null,
809
+ pollState
810
+ });
811
+ });
812
+ server.on("error", (err) => {
813
+ if (socket.state === SOCKET_STATE_LISTEN || socket.state === SOCKET_STATE_LISTENER) {
814
+ pollStateReady(socket.pollState);
815
+ socket.pendingAccepts.push({
816
+ tcpSocket: null,
817
+ err,
818
+ pollState: null
819
+ });
820
+ }
821
+ });
822
+ return server;
823
+ }
824
+ function closeTcpServer(socket) {
825
+ const server = socket.server;
826
+ socket.server = null;
827
+ if (!server) return Promise.resolve();
828
+ return new Promise((resolve, reject) => {
829
+ server.close((err) => err ? reject(err) : resolve());
830
+ });
776
831
  }
777
832
  function socketTcpConnectStart(id, remoteAddress, family) {
778
833
  const socket = tcpSockets.get(id);
779
834
  if (socket.state !== SOCKET_STATE_INIT && socket.state !== SOCKET_STATE_BOUND) throw "invalid-state";
780
835
  if (isWildcardAddress(remoteAddress) || family !== remoteAddress.tag || !isUnicastIpAddress(remoteAddress) || isMulticastIpAddress(remoteAddress) || remoteAddress.val.port === 0 || isIPv4MappedAddress(remoteAddress)) throw "invalid-argument";
781
836
  socket.state = SOCKET_STATE_CONNECT;
782
- socket.future = createFuture(new Promise((resolve, reject) => {
783
- const tcpSocket = socket.tcpSocket = new Socket({
784
- handle: socket.handle,
785
- pauseOnCreate: true,
786
- allowHalfOpen: true
787
- });
788
- function handleErr(err) {
789
- tcpSocket.off("connect", handleConnect);
790
- reject(convertSocketError(err));
791
- }
792
- function handleConnect() {
793
- tcpSocket.off("error", handleErr);
794
- resolve([createReadableStream(tcpSocket), createWritableStream(tcpSocket)]);
795
- }
796
- tcpSocket.once("connect", handleConnect);
797
- tcpSocket.once("error", handleErr);
798
- tcpSocket.connect({
799
- port: remoteAddress.val.port,
800
- host: serializeIpAddress(remoteAddress) ?? void 0,
801
- lookup: noLookup
837
+ socket.future = createFuture((async () => {
838
+ const localAddress = socket.localAddress;
839
+ await closeTcpServer(socket);
840
+ const tcpSocket = socket.tcpSocket = new Socket({ allowHalfOpen: true });
841
+ tcpSocket.setKeepAlive(socket.keepAlive, socket.keepAliveIdleTime);
842
+ await new Promise((resolve, reject) => {
843
+ function handleErr(err) {
844
+ tcpSocket.off("connect", handleConnect);
845
+ reject(convertSocketError(err));
846
+ }
847
+ function handleConnect() {
848
+ tcpSocket.off("error", handleErr);
849
+ resolve();
850
+ }
851
+ tcpSocket.once("connect", handleConnect);
852
+ tcpSocket.once("error", handleErr);
853
+ tcpSocket.connect({
854
+ port: remoteAddress.val.port,
855
+ host: serializeIpAddress(remoteAddress) ?? void 0,
856
+ lookup: noLookup,
857
+ localAddress: localAddress ? serializeIpAddress(localAddress) ?? void 0 : void 0,
858
+ localPort: localAddress?.val.port
859
+ });
802
860
  });
803
- }), socket.pollState);
861
+ return [createReadableStream(tcpSocket), createWritableStream(tcpSocket)];
862
+ })(), socket.pollState);
804
863
  }
805
864
  function socketTcpListenStart(id) {
806
865
  const socket = tcpSockets.get(id);
807
866
  if (socket.state !== SOCKET_STATE_BOUND) throw "invalid-state";
808
- const { handle } = socket;
809
867
  socket.state = SOCKET_STATE_LISTEN;
810
- socket.future = createFuture(new Promise((resolve, reject) => {
811
- const server = new Server({
812
- pauseOnConnect: true,
813
- allowHalfOpen: true
814
- });
815
- function handleErr(err) {
816
- server.off("listening", handleListen);
817
- reject(convertSocketError(err));
818
- }
819
- function handleListen() {
820
- server.off("error", handleErr);
821
- server.on("connection", (tcpSocket) => {
822
- pollStateReady(socket.pollState);
823
- const pollState = createReadableStreamPollState(tcpSocket);
824
- socket.pendingAccepts.push({
825
- tcpSocket,
826
- err: null,
827
- pollState
828
- });
829
- });
830
- server.on("error", (err) => {
831
- pollStateReady(socket.pollState);
832
- socket.pendingAccepts.push({
833
- tcpSocket: null,
834
- err,
835
- pollState: null
836
- });
837
- });
838
- resolve();
839
- }
840
- server.once("listening", handleListen);
841
- server.once("error", handleErr);
842
- server.listen(handle, socket.listenBacklogSize);
843
- }), socket.pollState);
868
+ socket.future = createFuture(Promise.resolve(), socket.pollState);
844
869
  }
845
870
  function socketTcpAccept(id) {
846
871
  const socket = tcpSockets.get(id);
@@ -856,8 +881,11 @@ function socketTcpAccept(id) {
856
881
  state: SOCKET_STATE_CONNECTION,
857
882
  future: null,
858
883
  tcpSocket: accept.tcpSocket,
884
+ server: null,
885
+ localAddress: null,
859
886
  listenBacklogSize: 128,
860
- handle: accept.tcpSocket?._handle,
887
+ keepAlive: false,
888
+ keepAliveIdleTime: 0,
861
889
  pendingAccepts: [],
862
890
  pollState: accept.pollState
863
891
  });
@@ -874,18 +902,16 @@ function socketTcpSetListenBacklogSize(id, backlogSize) {
874
902
  socket.listenBacklogSize = Number(backlogSize);
875
903
  }
876
904
  function socketTcpGetLocalAddress(id) {
877
- const { handle } = tcpSockets.get(id);
878
- const out = {};
879
- const code = handle.getsockname(out);
880
- if (code !== 0) throw convertSocketErrorCode(-code);
881
- return ipSocketAddress(out.family.toLowerCase(), out.address, out.port);
905
+ const socket = tcpSockets.get(id);
906
+ const address = socket.tcpSocket?.address();
907
+ if (address && typeof address !== "string" && "family" in address) return ipSocketAddress(address.family.toLowerCase(), address.address, address.port);
908
+ if (socket.localAddress) return socket.localAddress;
909
+ throw "invalid-state";
882
910
  }
883
911
  function socketTcpGetRemoteAddress(id) {
884
- const { handle } = tcpSockets.get(id);
885
- const out = {};
886
- const code = handle.getpeername(out);
887
- if (code !== 0) throw convertSocketErrorCode(-code);
888
- return ipSocketAddress(out.family.toLowerCase(), out.address, out.port);
912
+ const { tcpSocket } = tcpSockets.get(id);
913
+ if (!tcpSocket?.remoteFamily || !tcpSocket.remoteAddress || !tcpSocket.remotePort) throw "invalid-state";
914
+ return ipSocketAddress(tcpSocket.remoteFamily.toLowerCase(), tcpSocket.remoteAddress, tcpSocket.remotePort);
889
915
  }
890
916
  function socketTcpShutdown(id, _shutdownType) {
891
917
  const socket = tcpSockets.get(id);
@@ -894,14 +920,16 @@ function socketTcpShutdown(id, _shutdownType) {
894
920
  else socket.tcpSocket?.destroy();
895
921
  }
896
922
  function socketTcpSetKeepAlive(id, { keepAlive, keepAliveIdleTime }) {
897
- const { handle } = tcpSockets.get(id);
898
- const code = handle.setKeepAlive(keepAlive, Number(keepAliveIdleTime / 1000000000n));
899
- if (code !== 0) throw convertSocketErrorCode(-code);
923
+ const socket = tcpSockets.get(id);
924
+ socket.keepAlive = keepAlive;
925
+ socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
926
+ socket.tcpSocket?.setKeepAlive(socket.keepAlive, socket.keepAliveIdleTime);
900
927
  }
901
928
  function socketTcpDispose(id) {
902
929
  const socket = tcpSockets.get(id);
903
930
  verifyPollsDroppedForDrop(socket.pollState, "tcp socket");
904
- socket.handle.close();
931
+ socket.server?.close();
932
+ socket.tcpSocket?.destroy();
905
933
  tcpSockets.delete(id);
906
934
  }
907
935
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytecodealliance/preview2-shim",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "description": "WASI Preview2 shim for JS environments",
5
5
  "homepage": "https://github.com/bytecodealliance/jco#readme",
6
6
  "bugs": {