Skip to content

Commit

Permalink
feat: add impl for node sockets (wip) (#214)
Browse files Browse the repository at this point in the history
* feat: add initial impl for node sockets

* chore: update sockets tests

* feat: add TcpSocketImpl

* chore: temp disable eslint in lib/sockets/**

* chore: refactor instanceNetwork + dropNetwork

* chore: tcp socket impl wip

* chore: createTcpSocket/startBind/finishBind

* fix: dupe-class-members

* chore: add throws entry to jsdoc

* chore: improve startBind() logic

* chore: improve startConnect() + test

* chore: improve tcp-socket impl

* refactor: start-* finish-* methods to match specs

* chore: use assertion statement in tcp-socket-impl

* refactor: tcp-socket-impl

* chore: use err.code to catch sockets errors

* chore: migrate tcp-socket-impl to use tcp_wrap

* chore: mock listen and connect calls

* fix: bind connectReq.oncomplete to class method

* chore: reorder test suites

* chore: add e2e test for tcp-socket-impl

* chore: hook up internal events

* chore: update impl to match latest wit specs

* fix: support bind6 and connect6

* chore: move assert to own file

* chore: use assert

* chore: use ipv6 in tests

* chore: add streams to tcp-socket-impl (wip)

* fix: add error code -49 address-not-bindable

* feat: add udp-socket-impl method signatures

* fix: handle error -99

* chore: document udp errors

* chore: wip

* feat(udp): wip impl

* chore: clean imports

* chore: use new folder structure

* chore(udp): use Symbols for local state

* chore: sync impl with lastest specs

* chore: remove useless logs

* chore(udp): fix according to conformance tests

* fix(tcp): removed deprecated methods

* chore: try to reuse an existing udp socket (wip)

* fix: make conformance preview2_udp_states pass

* feat: add ip-name-lookup (wip)

* chore: socket resolve addresses (#1)

* chore: add missing import from node:dns/promises

* chore: resolve ipv6 :: and ::1

* fix(udp): make preview2_udp_sockopts apss

* chore: delete unused code

* chore: add comments

* chore: more conformance tests passing!

* chore: use enums for socket conn state

* chore: make preview2_tcp_states pass

* fix: make preview2_tcp_connect pass (wip)

* fix: refactor isUnicastIpAddress

* fix: make preview2_tcp_bind pass

* fix: make preview2_tcp_connect pass

* chore: refactor code

* chore: preview2_tcp_sample_application wip

* fix: preview2_tcp_bind and preview2_udp_bind

* chore: stashing wip fixes

* fix: improve tests and add more comments for hop limits

* chore: rename errorState property

* fix: make unit tests pass

* chore: fix linting

---------

Co-authored-by: Guy Bedford <[email protected]>
  • Loading branch information
manekinekko and guybedford authored Nov 28, 2023
1 parent 3810b69 commit 64475eb
Show file tree
Hide file tree
Showing 14 changed files with 2,473 additions and 227 deletions.
7 changes: 7 additions & 0 deletions packages/preview2-shim/lib/common/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function assert(condition, tag, _val) {
if (condition) {
// TODO: throw meaningful errors
// NOTE: wasmtime conformance tests are expecting a string here (a tag)
throw tag;
}
}
5 changes: 5 additions & 0 deletions packages/preview2-shim/lib/io/calls.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ export const HTTP_CREATE_REQUEST = ++call_id << 24;
export const CLOCKS_NOW = ++call_id << 24;
export const CLOCKS_DURATION_SUBSCRIBE = ++call_id << 24;
export const CLOCKS_INSTANT_SUBSCRIBE = ++call_id << 24;

// Sockets
export const SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST = ++call_id << 24;
export const SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST = ++call_id << 24;
export const SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST = ++call_id << 24;
1 change: 1 addition & 0 deletions packages/preview2-shim/lib/io/stream-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export const STDIN = ++cnt;
export const STDOUT = ++cnt;
export const STDERR = ++cnt;
export const FILE = ++cnt;
export const SOCKET = ++cnt;
export const INCOMING_BODY = ++cnt;
export const OUTGOING_BODY = ++cnt;
44 changes: 37 additions & 7 deletions packages/preview2-shim/lib/io/worker-thread.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { runAsWorker } from "../synckit/index.js";
import { FILE, STDOUT, STDERR, STDIN } from "./stream-types.js";
import { resolve } from "node:dns/promises";
import { createReadStream, createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { hrtime } from "node:process";
import { Readable } from "node:stream";
import { runAsWorker } from "../synckit/index.js";
import {
CALL_MASK,
CALL_SHIFT,
CALL_TYPE_MASK,
CLOCKS_DURATION_SUBSCRIBE,
CLOCKS_INSTANT_SUBSCRIBE,
CLOCKS_NOW,
FUTURE_DISPOSE_AND_GET_VALUE,
FUTURE_DISPOSE,
FUTURE_DISPOSE_AND_GET_VALUE,
HTTP_CREATE_REQUEST,
INPUT_STREAM_BLOCKING_READ,
INPUT_STREAM_BLOCKING_SKIP,
Expand All @@ -30,12 +30,16 @@ import {
OUTPUT_STREAM_FLUSH,
OUTPUT_STREAM_SPLICE,
OUTPUT_STREAM_SUBSCRIBE,
OUTPUT_STREAM_WRITE_ZEROES,
OUTPUT_STREAM_WRITE,
POLL_POLL_LIST,
OUTPUT_STREAM_WRITE_ZEROES,
POLL_POLLABLE_BLOCK,
POLL_POLLABLE_READY,
POLL_POLL_LIST,
SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST,
SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST,
SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST,
} from "./calls.js";
import { FILE, SOCKET, STDERR, STDIN, STDOUT } from "./stream-types.js";

let streamCnt = 0,
pollCnt = 0;
Expand Down Expand Up @@ -120,6 +124,30 @@ function handle(call, id, payload) {
return createFuture(createHttpRequest(method, url, headers, body));
}

// Sockets
case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST:
return createFuture(resolve(payload.hostname));
case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST:
return void unfinishedFutures.delete(id);
case SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST: {
const future = unfinishedFutures.get(id);
if (!future) {
// future not ready yet
if (unfinishedPolls.get(id)) {
throw 'would-block';
}
throw new Error("future already got and dropped");
}
unfinishedFutures.delete(id);
return future;
}
case OUTPUT_STREAM_CREATE | SOCKET: {
// TODO: implement
}
case INPUT_STREAM_CREATE | SOCKET: {
// TODO: implement
}

// Stdio
case OUTPUT_STREAM_DISPOSE | STDOUT:
case OUTPUT_STREAM_DISPOSE | STDERR:
Expand Down Expand Up @@ -434,14 +462,16 @@ function handle(call, id, payload) {
}

// poll promises must always resolve and never error
// once the future is resolved, it is removed from unfinishedPolls
function createPoll(promise) {
const pollId = ++pollCnt;
unfinishedPolls.set(
pollId,
promise.then(
() => void unfinishedPolls.delete(pollId),
() => {
(err) => {
process._rawDebug("Unexpected poll error");
process._rawDebug(err);
process.exit(1);
}
)
Expand Down
3 changes: 3 additions & 0 deletions packages/preview2-shim/lib/nodejs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ export {
sockets,
cli
}

export { WasiSockets } from "./sockets/wasi-sockets.js";

211 changes: 11 additions & 200 deletions packages/preview2-shim/lib/nodejs/sockets.js
Original file line number Diff line number Diff line change
@@ -1,200 +1,11 @@
export const instanceNetwork = {
instanceNetwork () {
console.log(`[sockets] instance network`);
}
};

export const ipNameLookup = {
dropResolveAddressStream () {

},
subscribe () {

},
resolveAddresses () {

},
resolveNextAddress () {

},
nonBlocking () {

},
setNonBlocking () {

},
};

export const network = {
dropNetwork () {

}
};

export const tcpCreateSocket = {
createTcpSocket () {

}
};

export const tcp = {
subscribe () {

},
dropTcpSocket() {

},
bind() {

},
connect() {

},
listen() {

},
accept() {

},
localAddress() {

},
remoteAddress() {

},
addressFamily() {

},
ipv6Only() {

},
setIpv6Only() {

},
setListenBacklogSize() {

},
keepAlive() {

},
setKeepAlive() {

},
noDelay() {

},
setNoDelay() {

},
unicastHopLimit() {

},
setUnicastHopLimit() {

},
receiveBufferSize() {

},
setReceiveBufferSize() {

},
sendBufferSize() {

},
setSendBufferSize() {

},
nonBlocking() {

},
setNonBlocking() {

},
shutdown() {

}
};

export const udp = {
subscribe () {

},

dropUdpSocket () {

},

bind () {

},

connect () {

},

receive () {

},

send () {

},

localAddress () {

},

remoteAddress () {

},

addressFamily () {

},

ipv6Only () {

},

setIpv6Only () {

},

unicastHopLimit () {

},

setUnicastHopLimit () {

},

receiveBufferSize () {

},

setReceiveBufferSize () {

},

sendBufferSize () {

},

setSendBufferSize () {

},

nonBlocking () {

},

setNonBlocking () {

}
};

export const udpCreateSocket = {
createTcpSocket () {

}
};
import { WasiSockets } from "./sockets/wasi-sockets.js";

export const {
ipNameLookup,
instanceNetwork,
network,
tcpCreateSocket,
udpCreateSocket,
tcp,
udp,
} = new WasiSockets();
Loading

0 comments on commit 64475eb

Please sign in to comment.