@ai-ecoverse/slicc-kernel 1.110.8 → 1.112.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.
- package/README.md +11 -3
- package/dist/kernel-worker.js +790 -532
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +21 -11
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +706 -448
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +21 -11
- package/dist/process-worker.js.map +2 -2
- package/dist/types/kernel/fd-table.d.ts +1 -1
- package/dist/types/kernel/net/datagram-wire.d.ts +1 -0
- package/dist/types/kernel/net/hosts-file.d.ts +5 -0
- package/dist/types/kernel/net/resolver.d.ts +4 -0
- package/dist/types/kernel/socket-syscalls.d.ts +1 -0
- package/dist/types/kernel/socket.d.ts +6 -0
- package/dist/types/kernel/unix-dgram.d.ts +47 -0
- package/package.json +1 -1
package/dist/kernel-worker.js
CHANGED
|
@@ -4674,6 +4674,7 @@ var LOCAL_ONLY = new Routes();
|
|
|
4674
4674
|
var LoopbackNet = class {
|
|
4675
4675
|
bound = /* @__PURE__ */ new Map();
|
|
4676
4676
|
dgrams = /* @__PURE__ */ new Map();
|
|
4677
|
+
unixDgrams = /* @__PURE__ */ new Map();
|
|
4677
4678
|
activators = /* @__PURE__ */ new Map();
|
|
4678
4679
|
internal = /* @__PURE__ */ new Set();
|
|
4679
4680
|
reserved = /* @__PURE__ */ new Set();
|
|
@@ -4699,6 +4700,18 @@ var LoopbackNet = class {
|
|
|
4699
4700
|
this.dgrams.set(port, socket);
|
|
4700
4701
|
return { ...addr, port };
|
|
4701
4702
|
}
|
|
4703
|
+
bindUnixDgram(socket, key) {
|
|
4704
|
+
if (this.bound.has(key) || this.unixDgrams.has(key)) throw new KernelError("EADDRINUSE");
|
|
4705
|
+
this.unixDgrams.set(key, socket);
|
|
4706
|
+
}
|
|
4707
|
+
releaseUnixDgram(key, socket) {
|
|
4708
|
+
if (this.unixDgrams.get(key) === socket) this.unixDgrams.delete(key);
|
|
4709
|
+
}
|
|
4710
|
+
unixDgramAt(key) {
|
|
4711
|
+
const socket = this.unixDgrams.get(key);
|
|
4712
|
+
if (socket) return socket;
|
|
4713
|
+
throw new KernelError(this.bound.has(key) ? "EPROTOTYPE" : "ECONNREFUSED");
|
|
4714
|
+
}
|
|
4702
4715
|
releaseDgram(addr, socket) {
|
|
4703
4716
|
if (this.dgrams.get(addr.port) === socket) this.dgrams.delete(addr.port);
|
|
4704
4717
|
}
|
|
@@ -4752,7 +4765,9 @@ var LoopbackNet = class {
|
|
|
4752
4765
|
} else this.bindable(addr, kernel);
|
|
4753
4766
|
const named = addr.family === "inet" && addr.port === 0 ? { ...addr, port: this.ephemeral() } : addr;
|
|
4754
4767
|
const key = keyOf(named, name2);
|
|
4755
|
-
if (this.bound.has(key) && !name2
|
|
4768
|
+
if (this.bound.has(key) && !name2 || this.unixDgrams.has(key)) {
|
|
4769
|
+
throw new KernelError("EADDRINUSE");
|
|
4770
|
+
}
|
|
4756
4771
|
this.bound.set(key, socket);
|
|
4757
4772
|
socket.named = name2;
|
|
4758
4773
|
return named;
|
|
@@ -4766,6 +4781,7 @@ var LoopbackNet = class {
|
|
|
4766
4781
|
throw new KernelError("ENETUNREACH");
|
|
4767
4782
|
}
|
|
4768
4783
|
const key = keyOf(addr, name2);
|
|
4784
|
+
if (this.unixDgrams.has(key)) throw new KernelError("EPROTOTYPE");
|
|
4769
4785
|
if (!this.bound.has(key)) this.activators.get(key)?.();
|
|
4770
4786
|
const socket = this.bound.get(key);
|
|
4771
4787
|
if (!socket?.listening) throw new KernelError("ECONNREFUSED");
|
|
@@ -6176,7 +6192,7 @@ function satisfies(version, range2) {
|
|
|
6176
6192
|
}
|
|
6177
6193
|
|
|
6178
6194
|
// src/version.ts
|
|
6179
|
-
var KERNEL_VERSION = true ? "1.
|
|
6195
|
+
var KERNEL_VERSION = true ? "1.112.0" : "0.0.0-dev";
|
|
6180
6196
|
var OS_RELEASE = "6.0.0-slicc";
|
|
6181
6197
|
function procVersion() {
|
|
6182
6198
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11764,470 +11780,84 @@ var ProcessClocks = class {
|
|
|
11764
11780
|
}
|
|
11765
11781
|
};
|
|
11766
11782
|
|
|
11767
|
-
// src/
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
waiting = /* @__PURE__ */ new Map();
|
|
11785
|
-
nextId = 0;
|
|
11786
|
-
constructor(port, traits, routes) {
|
|
11787
|
-
this.port = port;
|
|
11788
|
-
this.traits = traits;
|
|
11789
|
-
this.routes = routes;
|
|
11790
|
-
}
|
|
11791
|
-
receive(reply) {
|
|
11792
|
-
const waiter = this.waiting.get(reply.uid);
|
|
11793
|
-
if (!waiter) return;
|
|
11794
|
-
this.waiting.delete(reply.uid);
|
|
11795
|
-
if (reply.uplink === "error") {
|
|
11796
|
-
waiter.reject(Object.assign(new Error(reply.message), { code: reply.code }));
|
|
11797
|
-
} else waiter.resolve(reply);
|
|
11798
|
-
}
|
|
11799
|
-
ask(call, signal, transfer) {
|
|
11800
|
-
const waiter = Promise.withResolvers();
|
|
11801
|
-
this.waiting.set(call.uid, waiter);
|
|
11802
|
-
const abort = () => {
|
|
11803
|
-
this.waiting.delete(call.uid);
|
|
11804
|
-
this.port.postMessage({ uplink: "cancel", uid: call.uid });
|
|
11805
|
-
waiter.reject(signal?.reason);
|
|
11806
|
-
};
|
|
11807
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
11808
|
-
const settled = () => signal?.removeEventListener("abort", abort);
|
|
11809
|
-
waiter.promise.then(settled, settled);
|
|
11810
|
-
this.port.postMessage(call, transfer);
|
|
11811
|
-
return waiter.promise;
|
|
11783
|
+
// src/fs/pages.ts
|
|
11784
|
+
var PAGE = 64 * 1024;
|
|
11785
|
+
var READAHEAD = 1024 * 1024;
|
|
11786
|
+
var CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
11787
|
+
var WRITEBACK = 8 * 1024 * 1024;
|
|
11788
|
+
var RUN = 1024 * 1024;
|
|
11789
|
+
var Pages = class {
|
|
11790
|
+
length;
|
|
11791
|
+
stored;
|
|
11792
|
+
shrink;
|
|
11793
|
+
pages = /* @__PURE__ */ new Map();
|
|
11794
|
+
dirty = /* @__PURE__ */ new Set();
|
|
11795
|
+
free = [];
|
|
11796
|
+
pinned = false;
|
|
11797
|
+
constructor(size) {
|
|
11798
|
+
this.length = size;
|
|
11799
|
+
this.stored = size;
|
|
11812
11800
|
}
|
|
11813
|
-
|
|
11814
|
-
|
|
11815
|
-
{ uplink: "resolve", uid: ++this.nextId, name: name2, family },
|
|
11816
|
-
signal
|
|
11817
|
-
);
|
|
11818
|
-
return answerOf(reply);
|
|
11801
|
+
get dirtyBytes() {
|
|
11802
|
+
return this.dirty.size * PAGE;
|
|
11819
11803
|
}
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
const { host, port } = req;
|
|
11823
|
-
const opened2 = await this.ask(
|
|
11824
|
-
{ uplink: "dial", uid: ++this.nextId, host, port },
|
|
11825
|
-
req.signal
|
|
11826
|
-
);
|
|
11827
|
-
const { cid, localAddr, remoteAddr } = opened2;
|
|
11828
|
-
return {
|
|
11829
|
-
localAddr,
|
|
11830
|
-
remoteAddr,
|
|
11831
|
-
read: async () => {
|
|
11832
|
-
const got = await this.ask({
|
|
11833
|
-
uplink: "read",
|
|
11834
|
-
uid: ++this.nextId,
|
|
11835
|
-
cid
|
|
11836
|
-
});
|
|
11837
|
-
return got.bytes;
|
|
11838
|
-
},
|
|
11839
|
-
write: async (bytes) => {
|
|
11840
|
-
const copy = bytes.slice();
|
|
11841
|
-
const call = { uplink: "write", uid: ++this.nextId, cid, bytes: copy };
|
|
11842
|
-
const done4 = await this.ask(call, void 0, [
|
|
11843
|
-
copy.buffer
|
|
11844
|
-
]);
|
|
11845
|
-
return done4.n;
|
|
11846
|
-
},
|
|
11847
|
-
closeWrite: () => this.port.postMessage({ uplink: "close-write", cid }),
|
|
11848
|
-
close: () => this.port.postMessage({ uplink: "close", cid })
|
|
11849
|
-
};
|
|
11804
|
+
get changed() {
|
|
11805
|
+
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
11850
11806
|
}
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
const
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
return
|
|
11864
|
-
localAddr,
|
|
11865
|
-
send: async (bytes, host, port) => {
|
|
11866
|
-
const copy = bytes.slice();
|
|
11867
|
-
const call = {
|
|
11868
|
-
uplink: "udp-send",
|
|
11869
|
-
uid: ++this.nextId,
|
|
11870
|
-
cid,
|
|
11871
|
-
bytes: copy,
|
|
11872
|
-
host,
|
|
11873
|
-
port
|
|
11874
|
-
};
|
|
11875
|
-
await this.ask(call, void 0, [copy.buffer]);
|
|
11876
|
-
},
|
|
11877
|
-
messages: {
|
|
11878
|
-
[Symbol.asyncIterator]: async function* () {
|
|
11879
|
-
for (; ; ) {
|
|
11880
|
-
const got = await recv();
|
|
11881
|
-
if (!got.message) return;
|
|
11882
|
-
yield got.message;
|
|
11883
|
-
}
|
|
11884
|
-
}
|
|
11885
|
-
},
|
|
11886
|
-
close: () => this.port.postMessage({ uplink: "udp-close", cid })
|
|
11887
|
-
};
|
|
11807
|
+
missing(at, length2) {
|
|
11808
|
+
this.evict();
|
|
11809
|
+
const end = Math.min(this.stored, at + length2, this.length);
|
|
11810
|
+
const runs = [];
|
|
11811
|
+
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
11812
|
+
if (this.pages.has(page)) continue;
|
|
11813
|
+
const last2 = runs[runs.length - 1];
|
|
11814
|
+
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
11815
|
+
else runs.push([page * PAGE, PAGE]);
|
|
11816
|
+
}
|
|
11817
|
+
const last = runs[runs.length - 1];
|
|
11818
|
+
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
11819
|
+
return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
|
|
11888
11820
|
}
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
var SO_BROADCAST = 6;
|
|
11902
|
-
var SO_SNDBUF2 = 7;
|
|
11903
|
-
var SO_RCVBUF2 = 8;
|
|
11904
|
-
var SO_DOMAIN2 = 39;
|
|
11905
|
-
var SOCK_DGRAM = 2;
|
|
11906
|
-
var AF_INET2 = 2;
|
|
11907
|
-
var IP_MULTICAST_FIRST = 32;
|
|
11908
|
-
var IP_MULTICAST_LAST = 36;
|
|
11909
|
-
var SEND_ERRORS = ["ENETUNREACH", "EHOSTUNREACH", "EACCES", "EMSGSIZE"];
|
|
11910
|
-
var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
|
|
11911
|
-
function sendError(e) {
|
|
11912
|
-
if (e instanceof KernelError) return e;
|
|
11913
|
-
const code = e?.code;
|
|
11914
|
-
return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
|
|
11915
|
-
}
|
|
11916
|
-
function sameAddr(a, b) {
|
|
11917
|
-
return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
|
|
11918
|
-
}
|
|
11919
|
-
function familyOf(host) {
|
|
11920
|
-
return host.includes(":") ? 6 : 4;
|
|
11921
|
-
}
|
|
11922
|
-
var KernelDgram = class {
|
|
11923
|
-
local;
|
|
11924
|
-
peer;
|
|
11925
|
-
net;
|
|
11926
|
-
queue = [];
|
|
11927
|
-
queued = 0;
|
|
11928
|
-
pending;
|
|
11929
|
-
closed = false;
|
|
11930
|
-
sending = 0;
|
|
11931
|
-
changes = new Changes();
|
|
11932
|
-
options = /* @__PURE__ */ new Map();
|
|
11933
|
-
uplinks = /* @__PURE__ */ new Map();
|
|
11934
|
-
stop = new AbortController();
|
|
11935
|
-
constructor(net) {
|
|
11936
|
-
this.net = net;
|
|
11821
|
+
partial(at, length2) {
|
|
11822
|
+
if (length2 === 0) return [];
|
|
11823
|
+
this.evict();
|
|
11824
|
+
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
|
|
11825
|
+
const runs = [];
|
|
11826
|
+
for (const page of edges) {
|
|
11827
|
+
const start2 = page * PAGE;
|
|
11828
|
+
const covered = at <= start2 && at + length2 >= start2 + PAGE;
|
|
11829
|
+
if (covered || this.pages.has(page) || start2 >= this.stored) continue;
|
|
11830
|
+
runs.push([start2, Math.min(PAGE, this.stored - start2)]);
|
|
11831
|
+
}
|
|
11832
|
+
return runs;
|
|
11937
11833
|
}
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11834
|
+
fill(start2, bytes) {
|
|
11835
|
+
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
11836
|
+
const page = (start2 + at) / PAGE;
|
|
11837
|
+
if (this.pages.has(page)) continue;
|
|
11838
|
+
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
11839
|
+
const fresh2 = this.take(part.length);
|
|
11840
|
+
fresh2.set(part);
|
|
11841
|
+
this.pages.set(page, fresh2);
|
|
11842
|
+
}
|
|
11941
11843
|
}
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11844
|
+
read(at, length2) {
|
|
11845
|
+
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
|
|
11846
|
+
this.readInto(at, out);
|
|
11847
|
+
return out;
|
|
11945
11848
|
}
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
}
|
|
11959
|
-
route(host) {
|
|
11960
|
-
const where = this.net.destination(host);
|
|
11961
|
-
if (where === "loopback" || where === "uplink") return where;
|
|
11962
|
-
throw new KernelError("ENETUNREACH");
|
|
11963
|
-
}
|
|
11964
|
-
takeError() {
|
|
11965
|
-
const pending = this.pending;
|
|
11966
|
-
this.pending = void 0;
|
|
11967
|
-
return pending;
|
|
11968
|
-
}
|
|
11969
|
-
async send(bytes, to) {
|
|
11970
|
-
if (this.closed) throw new KernelError("EBADF");
|
|
11971
|
-
const pending = this.takeError();
|
|
11972
|
-
if (pending) throw new KernelError(pending);
|
|
11973
|
-
const target = to ?? this.peer;
|
|
11974
|
-
if (!target) throw new KernelError("EDESTADDRREQ");
|
|
11975
|
-
if (target.family !== "inet") throw new KernelError("EAFNOSUPPORT");
|
|
11976
|
-
const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
|
|
11977
|
-
if (bytes.length > max) throw new KernelError("EMSGSIZE");
|
|
11978
|
-
const where = this.route(target.host);
|
|
11979
|
-
const local = this.bound();
|
|
11980
|
-
if (where === "uplink") return this.sendUp(bytes, target);
|
|
11981
|
-
const from = {
|
|
11982
|
-
family: "inet",
|
|
11983
|
-
host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
|
|
11984
|
-
port: local.port
|
|
11985
|
-
};
|
|
11986
|
-
const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
|
|
11987
|
-
if (!delivered && this.peer && sameAddr(this.peer, target)) {
|
|
11988
|
-
this.pending = "ECONNREFUSED";
|
|
11989
|
-
this.changes.wake();
|
|
11990
|
-
}
|
|
11991
|
-
return bytes.length;
|
|
11992
|
-
}
|
|
11993
|
-
async sendUp(bytes, to) {
|
|
11994
|
-
const uplink = this.net.uplinkFor(to.host)?.uplink;
|
|
11995
|
-
if (!uplink || !carriesUdp(uplink)) throw new KernelError("ENETUNREACH");
|
|
11996
|
-
this.sending += bytes.length;
|
|
11997
|
-
try {
|
|
11998
|
-
const socket = await this.uplinkSocket(uplink, familyOf(to.host));
|
|
11999
|
-
await socket.send(bytes.slice(), to.host, to.port);
|
|
12000
|
-
} catch (e) {
|
|
12001
|
-
throw sendError(e);
|
|
12002
|
-
} finally {
|
|
12003
|
-
this.sending -= bytes.length;
|
|
12004
|
-
this.changes.wake();
|
|
12005
|
-
}
|
|
12006
|
-
return bytes.length;
|
|
12007
|
-
}
|
|
12008
|
-
uplinkSocket(uplink, family) {
|
|
12009
|
-
const known = this.uplinks.get(family);
|
|
12010
|
-
if (known !== void 0) return known;
|
|
12011
|
-
const opening2 = Promise.resolve().then(() => {
|
|
12012
|
-
if (!uplink.udp) throw new KernelError("ENETUNREACH");
|
|
12013
|
-
return uplink.udp({ family, signal: this.stop.signal });
|
|
12014
|
-
});
|
|
12015
|
-
this.uplinks.set(family, opening2);
|
|
12016
|
-
opening2.then(
|
|
12017
|
-
(socket) => {
|
|
12018
|
-
if (this.closed) {
|
|
12019
|
-
socket.close();
|
|
12020
|
-
return;
|
|
12021
|
-
}
|
|
12022
|
-
void this.pump(socket, family);
|
|
12023
|
-
},
|
|
12024
|
-
() => this.uplinks.delete(family)
|
|
12025
|
-
);
|
|
12026
|
-
return opening2;
|
|
12027
|
-
}
|
|
12028
|
-
async pump(socket, family) {
|
|
12029
|
-
const iterate = async () => {
|
|
12030
|
-
for await (const message3 of socket.messages) {
|
|
12031
|
-
if (this.closed) return;
|
|
12032
|
-
const from = { family: "inet", host: message3.host, port: message3.port };
|
|
12033
|
-
if ("bytes" in message3) this.deliver({ bytes: message3.bytes, from });
|
|
12034
|
-
else this.unreachable(message3.error, from);
|
|
12035
|
-
}
|
|
12036
|
-
};
|
|
12037
|
-
await iterate().catch(() => void 0);
|
|
12038
|
-
if (!this.closed) this.uplinks.delete(family);
|
|
12039
|
-
socket.close();
|
|
12040
|
-
}
|
|
12041
|
-
unreachable(error, from) {
|
|
12042
|
-
if (!this.peer || !sameAddr(this.peer, from)) return;
|
|
12043
|
-
this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
|
|
12044
|
-
this.changes.wake();
|
|
12045
|
-
}
|
|
12046
|
-
deliver(datagram2) {
|
|
12047
|
-
if (this.closed) return false;
|
|
12048
|
-
if (this.peer && !sameAddr(this.peer, datagram2.from)) return true;
|
|
12049
|
-
const full = this.queue.length >= DGRAM_QUEUE_COUNT || this.queued + datagram2.bytes.length > DGRAM_QUEUE_BYTES;
|
|
12050
|
-
if (full) return true;
|
|
12051
|
-
this.queue.push(datagram2);
|
|
12052
|
-
this.queued += datagram2.bytes.length;
|
|
12053
|
-
this.changes.wake();
|
|
12054
|
-
return true;
|
|
12055
|
-
}
|
|
12056
|
-
async receive(max, peek, signal) {
|
|
12057
|
-
for (; ; ) {
|
|
12058
|
-
const pending = this.takeError();
|
|
12059
|
-
if (pending) throw new KernelError(pending);
|
|
12060
|
-
if (this.closed) throw new KernelError("EBADF");
|
|
12061
|
-
const next3 = this.queue[0];
|
|
12062
|
-
if (next3) {
|
|
12063
|
-
if (!peek) {
|
|
12064
|
-
this.queue.shift();
|
|
12065
|
-
this.queued -= next3.bytes.length;
|
|
12066
|
-
this.changes.wake();
|
|
12067
|
-
}
|
|
12068
|
-
const size = Math.max(0, max);
|
|
12069
|
-
return {
|
|
12070
|
-
bytes: next3.bytes.slice(0, size),
|
|
12071
|
-
from: next3.from,
|
|
12072
|
-
truncated: next3.bytes.length > size
|
|
12073
|
-
};
|
|
12074
|
-
}
|
|
12075
|
-
await this.changes.wait(signal);
|
|
12076
|
-
}
|
|
12077
|
-
}
|
|
12078
|
-
async read(max, signal) {
|
|
12079
|
-
return (await this.receive(max, false, signal)).bytes;
|
|
12080
|
-
}
|
|
12081
|
-
async peek(max, signal) {
|
|
12082
|
-
return (await this.receive(max, true, signal)).bytes;
|
|
12083
|
-
}
|
|
12084
|
-
write(bytes) {
|
|
12085
|
-
return this.send(bytes);
|
|
12086
|
-
}
|
|
12087
|
-
poll() {
|
|
12088
|
-
return {
|
|
12089
|
-
readable: this.queue.length > 0 || this.pending !== void 0 || this.closed,
|
|
12090
|
-
writable: this.sending < DGRAM_SEND_ROOM,
|
|
12091
|
-
hangup: this.closed,
|
|
12092
|
-
...this.pending !== void 0 ? { error: true } : {}
|
|
12093
|
-
};
|
|
12094
|
-
}
|
|
12095
|
-
changed(signal) {
|
|
12096
|
-
return this.changes.wait(signal);
|
|
12097
|
-
}
|
|
12098
|
-
shutdown(how) {
|
|
12099
|
-
if (!this.peer) throw new KernelError("ENOTCONN");
|
|
12100
|
-
if (how < 0 || how > 2) throw new KernelError("EINVAL");
|
|
12101
|
-
}
|
|
12102
|
-
getOption(level, name2) {
|
|
12103
|
-
if (level === SOL_SOCKET2) {
|
|
12104
|
-
switch (name2) {
|
|
12105
|
-
case SO_TYPE2:
|
|
12106
|
-
return SOCK_DGRAM;
|
|
12107
|
-
case SO_ERROR2: {
|
|
12108
|
-
const pending = this.takeError();
|
|
12109
|
-
return pending ? wasiErrno(pending) : 0;
|
|
12110
|
-
}
|
|
12111
|
-
case SO_DOMAIN2:
|
|
12112
|
-
return AF_INET2;
|
|
12113
|
-
case SO_BROADCAST:
|
|
12114
|
-
return 0;
|
|
12115
|
-
case SO_SNDBUF2:
|
|
12116
|
-
return this.options.get(`${level}:${name2}`) ?? DGRAM_SEND_ROOM;
|
|
12117
|
-
case SO_RCVBUF2:
|
|
12118
|
-
return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
|
|
12119
|
-
}
|
|
12120
|
-
}
|
|
12121
|
-
if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
|
|
12122
|
-
throw new KernelError("ENOPROTOOPT");
|
|
12123
|
-
}
|
|
12124
|
-
return this.options.get(`${level}:${name2}`) ?? 0;
|
|
12125
|
-
}
|
|
12126
|
-
setOption(level, name2, value2) {
|
|
12127
|
-
if (level === SOL_SOCKET2 && name2 === SO_BROADCAST && value2 !== 0) {
|
|
12128
|
-
throw new KernelError("EOPNOTSUPP");
|
|
12129
|
-
}
|
|
12130
|
-
if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
|
|
12131
|
-
throw new KernelError("ENOPROTOOPT");
|
|
12132
|
-
}
|
|
12133
|
-
this.options.set(`${level}:${name2}`, value2);
|
|
12134
|
-
}
|
|
12135
|
-
close() {
|
|
12136
|
-
if (this.closed) return;
|
|
12137
|
-
this.closed = true;
|
|
12138
|
-
this.stop.abort();
|
|
12139
|
-
for (const opening2 of this.uplinks.values()) {
|
|
12140
|
-
opening2.then(
|
|
12141
|
-
(socket) => socket.close(),
|
|
12142
|
-
() => void 0
|
|
12143
|
-
);
|
|
12144
|
-
}
|
|
12145
|
-
this.uplinks.clear();
|
|
12146
|
-
if (this.local) this.net.releaseDgram(this.local, this);
|
|
12147
|
-
this.queue.length = 0;
|
|
12148
|
-
this.queued = 0;
|
|
12149
|
-
this.changes.wake();
|
|
12150
|
-
}
|
|
12151
|
-
};
|
|
12152
|
-
|
|
12153
|
-
// src/fs/pages.ts
|
|
12154
|
-
var PAGE = 64 * 1024;
|
|
12155
|
-
var READAHEAD = 1024 * 1024;
|
|
12156
|
-
var CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
12157
|
-
var WRITEBACK = 8 * 1024 * 1024;
|
|
12158
|
-
var RUN = 1024 * 1024;
|
|
12159
|
-
var Pages = class {
|
|
12160
|
-
length;
|
|
12161
|
-
stored;
|
|
12162
|
-
shrink;
|
|
12163
|
-
pages = /* @__PURE__ */ new Map();
|
|
12164
|
-
dirty = /* @__PURE__ */ new Set();
|
|
12165
|
-
free = [];
|
|
12166
|
-
pinned = false;
|
|
12167
|
-
constructor(size) {
|
|
12168
|
-
this.length = size;
|
|
12169
|
-
this.stored = size;
|
|
12170
|
-
}
|
|
12171
|
-
get dirtyBytes() {
|
|
12172
|
-
return this.dirty.size * PAGE;
|
|
12173
|
-
}
|
|
12174
|
-
get changed() {
|
|
12175
|
-
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
12176
|
-
}
|
|
12177
|
-
missing(at, length2) {
|
|
12178
|
-
this.evict();
|
|
12179
|
-
const end = Math.min(this.stored, at + length2, this.length);
|
|
12180
|
-
const runs = [];
|
|
12181
|
-
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
12182
|
-
if (this.pages.has(page)) continue;
|
|
12183
|
-
const last2 = runs[runs.length - 1];
|
|
12184
|
-
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
12185
|
-
else runs.push([page * PAGE, PAGE]);
|
|
12186
|
-
}
|
|
12187
|
-
const last = runs[runs.length - 1];
|
|
12188
|
-
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
12189
|
-
return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
|
|
12190
|
-
}
|
|
12191
|
-
partial(at, length2) {
|
|
12192
|
-
if (length2 === 0) return [];
|
|
12193
|
-
this.evict();
|
|
12194
|
-
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
|
|
12195
|
-
const runs = [];
|
|
12196
|
-
for (const page of edges) {
|
|
12197
|
-
const start2 = page * PAGE;
|
|
12198
|
-
const covered = at <= start2 && at + length2 >= start2 + PAGE;
|
|
12199
|
-
if (covered || this.pages.has(page) || start2 >= this.stored) continue;
|
|
12200
|
-
runs.push([start2, Math.min(PAGE, this.stored - start2)]);
|
|
12201
|
-
}
|
|
12202
|
-
return runs;
|
|
12203
|
-
}
|
|
12204
|
-
fill(start2, bytes) {
|
|
12205
|
-
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
12206
|
-
const page = (start2 + at) / PAGE;
|
|
12207
|
-
if (this.pages.has(page)) continue;
|
|
12208
|
-
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
12209
|
-
const fresh2 = this.take(part.length);
|
|
12210
|
-
fresh2.set(part);
|
|
12211
|
-
this.pages.set(page, fresh2);
|
|
12212
|
-
}
|
|
12213
|
-
}
|
|
12214
|
-
read(at, length2) {
|
|
12215
|
-
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
|
|
12216
|
-
this.readInto(at, out);
|
|
12217
|
-
return out;
|
|
12218
|
-
}
|
|
12219
|
-
readInto(at, out) {
|
|
12220
|
-
const end = Math.min(this.length, at + out.length);
|
|
12221
|
-
for (let pos = at; pos < end; ) {
|
|
12222
|
-
const page = Math.floor(pos / PAGE);
|
|
12223
|
-
const from = pos - page * PAGE;
|
|
12224
|
-
const n = Math.min(PAGE - from, end - pos);
|
|
12225
|
-
const bytes = this.pages.get(page);
|
|
12226
|
-
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
12227
|
-
else out.fill(0, pos - at, pos - at + n);
|
|
12228
|
-
pos += n;
|
|
12229
|
-
}
|
|
12230
|
-
return Math.max(0, end - at);
|
|
11849
|
+
readInto(at, out) {
|
|
11850
|
+
const end = Math.min(this.length, at + out.length);
|
|
11851
|
+
for (let pos = at; pos < end; ) {
|
|
11852
|
+
const page = Math.floor(pos / PAGE);
|
|
11853
|
+
const from = pos - page * PAGE;
|
|
11854
|
+
const n = Math.min(PAGE - from, end - pos);
|
|
11855
|
+
const bytes = this.pages.get(page);
|
|
11856
|
+
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
11857
|
+
else out.fill(0, pos - at, pos - at + n);
|
|
11858
|
+
pos += n;
|
|
11859
|
+
}
|
|
11860
|
+
return Math.max(0, end - at);
|
|
12231
11861
|
}
|
|
12232
11862
|
write(at, bytes) {
|
|
12233
11863
|
for (let done4 = 0; done4 < bytes.length; ) {
|
|
@@ -14929,6 +14559,130 @@ var HttpHandles = class {
|
|
|
14929
14559
|
}
|
|
14930
14560
|
};
|
|
14931
14561
|
|
|
14562
|
+
// src/kernel/net/uplink.ts
|
|
14563
|
+
function carriesUdp(uplink) {
|
|
14564
|
+
return uplink.traits.udp === true && typeof uplink.udp === "function";
|
|
14565
|
+
}
|
|
14566
|
+
function answerOf(result) {
|
|
14567
|
+
const answer = Array.isArray(result) ? { addresses: result } : result;
|
|
14568
|
+
const addresses = Array.isArray(answer?.addresses) ? answer.addresses.filter((a) => typeof a === "string") : [];
|
|
14569
|
+
return {
|
|
14570
|
+
addresses,
|
|
14571
|
+
...typeof answer?.ttl === "number" && answer.ttl >= 0 ? { ttl: answer.ttl } : {}
|
|
14572
|
+
};
|
|
14573
|
+
}
|
|
14574
|
+
var NEVER = new Routes(true);
|
|
14575
|
+
var RemoteUplink = class {
|
|
14576
|
+
traits;
|
|
14577
|
+
routes;
|
|
14578
|
+
port;
|
|
14579
|
+
waiting = /* @__PURE__ */ new Map();
|
|
14580
|
+
nextId = 0;
|
|
14581
|
+
constructor(port, traits, routes) {
|
|
14582
|
+
this.port = port;
|
|
14583
|
+
this.traits = traits;
|
|
14584
|
+
this.routes = routes;
|
|
14585
|
+
}
|
|
14586
|
+
receive(reply) {
|
|
14587
|
+
const waiter = this.waiting.get(reply.uid);
|
|
14588
|
+
if (!waiter) return;
|
|
14589
|
+
this.waiting.delete(reply.uid);
|
|
14590
|
+
if (reply.uplink === "error") {
|
|
14591
|
+
waiter.reject(Object.assign(new Error(reply.message), { code: reply.code }));
|
|
14592
|
+
} else waiter.resolve(reply);
|
|
14593
|
+
}
|
|
14594
|
+
ask(call, signal, transfer) {
|
|
14595
|
+
const waiter = Promise.withResolvers();
|
|
14596
|
+
this.waiting.set(call.uid, waiter);
|
|
14597
|
+
const abort = () => {
|
|
14598
|
+
this.waiting.delete(call.uid);
|
|
14599
|
+
this.port.postMessage({ uplink: "cancel", uid: call.uid });
|
|
14600
|
+
waiter.reject(signal?.reason);
|
|
14601
|
+
};
|
|
14602
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
14603
|
+
const settled = () => signal?.removeEventListener("abort", abort);
|
|
14604
|
+
waiter.promise.then(settled, settled);
|
|
14605
|
+
this.port.postMessage(call, transfer);
|
|
14606
|
+
return waiter.promise;
|
|
14607
|
+
}
|
|
14608
|
+
async resolve(name2, family, signal) {
|
|
14609
|
+
const reply = await this.ask(
|
|
14610
|
+
{ uplink: "resolve", uid: ++this.nextId, name: name2, family },
|
|
14611
|
+
signal
|
|
14612
|
+
);
|
|
14613
|
+
return answerOf(reply);
|
|
14614
|
+
}
|
|
14615
|
+
async dial(req) {
|
|
14616
|
+
req.signal.throwIfAborted();
|
|
14617
|
+
const { host, port } = req;
|
|
14618
|
+
const opened2 = await this.ask(
|
|
14619
|
+
{ uplink: "dial", uid: ++this.nextId, host, port },
|
|
14620
|
+
req.signal
|
|
14621
|
+
);
|
|
14622
|
+
const { cid, localAddr, remoteAddr } = opened2;
|
|
14623
|
+
return {
|
|
14624
|
+
localAddr,
|
|
14625
|
+
remoteAddr,
|
|
14626
|
+
read: async () => {
|
|
14627
|
+
const got = await this.ask({
|
|
14628
|
+
uplink: "read",
|
|
14629
|
+
uid: ++this.nextId,
|
|
14630
|
+
cid
|
|
14631
|
+
});
|
|
14632
|
+
return got.bytes;
|
|
14633
|
+
},
|
|
14634
|
+
write: async (bytes) => {
|
|
14635
|
+
const copy = bytes.slice();
|
|
14636
|
+
const call = { uplink: "write", uid: ++this.nextId, cid, bytes: copy };
|
|
14637
|
+
const done4 = await this.ask(call, void 0, [
|
|
14638
|
+
copy.buffer
|
|
14639
|
+
]);
|
|
14640
|
+
return done4.n;
|
|
14641
|
+
},
|
|
14642
|
+
closeWrite: () => this.port.postMessage({ uplink: "close-write", cid }),
|
|
14643
|
+
close: () => this.port.postMessage({ uplink: "close", cid })
|
|
14644
|
+
};
|
|
14645
|
+
}
|
|
14646
|
+
async udp(req) {
|
|
14647
|
+
req.signal.throwIfAborted();
|
|
14648
|
+
const opened2 = await this.ask(
|
|
14649
|
+
{ uplink: "udp-open", uid: ++this.nextId, family: req.family },
|
|
14650
|
+
req.signal
|
|
14651
|
+
);
|
|
14652
|
+
const { cid, localAddr } = opened2;
|
|
14653
|
+
const recv = () => this.ask({
|
|
14654
|
+
uplink: "udp-recv",
|
|
14655
|
+
uid: ++this.nextId,
|
|
14656
|
+
cid
|
|
14657
|
+
});
|
|
14658
|
+
return {
|
|
14659
|
+
localAddr,
|
|
14660
|
+
send: async (bytes, host, port) => {
|
|
14661
|
+
const copy = bytes.slice();
|
|
14662
|
+
const call = {
|
|
14663
|
+
uplink: "udp-send",
|
|
14664
|
+
uid: ++this.nextId,
|
|
14665
|
+
cid,
|
|
14666
|
+
bytes: copy,
|
|
14667
|
+
host,
|
|
14668
|
+
port
|
|
14669
|
+
};
|
|
14670
|
+
await this.ask(call, void 0, [copy.buffer]);
|
|
14671
|
+
},
|
|
14672
|
+
messages: {
|
|
14673
|
+
[Symbol.asyncIterator]: async function* () {
|
|
14674
|
+
for (; ; ) {
|
|
14675
|
+
const got = await recv();
|
|
14676
|
+
if (!got.message) return;
|
|
14677
|
+
yield got.message;
|
|
14678
|
+
}
|
|
14679
|
+
}
|
|
14680
|
+
},
|
|
14681
|
+
close: () => this.port.postMessage({ uplink: "udp-close", cid })
|
|
14682
|
+
};
|
|
14683
|
+
}
|
|
14684
|
+
};
|
|
14685
|
+
|
|
14932
14686
|
// src/kernel/net/resolver.ts
|
|
14933
14687
|
var RESOLVE_TTL_MAX = 60;
|
|
14934
14688
|
var RESOLVE_TIMEOUT_MS = 1e4;
|
|
@@ -14952,6 +14706,7 @@ var Resolver = class {
|
|
|
14952
14706
|
own;
|
|
14953
14707
|
cache = /* @__PURE__ */ new Map();
|
|
14954
14708
|
pending = /* @__PURE__ */ new Map();
|
|
14709
|
+
hosts;
|
|
14955
14710
|
constructor(options) {
|
|
14956
14711
|
this.uplink = options.uplink;
|
|
14957
14712
|
this.routes = options.routes;
|
|
@@ -14959,6 +14714,14 @@ var Resolver = class {
|
|
|
14959
14714
|
this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
|
|
14960
14715
|
this.log = options.log ?? ((message3) => console.warn(message3));
|
|
14961
14716
|
this.own = ownNames(options.hostname ?? DEFAULT_HOSTNAME);
|
|
14717
|
+
this.hosts = options.hosts;
|
|
14718
|
+
}
|
|
14719
|
+
async fromFile(key, family) {
|
|
14720
|
+
const listed = (await this.hosts?.().catch(() => void 0))?.get(key);
|
|
14721
|
+
if (!listed) return void 0;
|
|
14722
|
+
const v4 = listed.filter((a) => ipv4Bytes(a) !== void 0);
|
|
14723
|
+
const v6 = listed.filter((a) => ipv4Bytes(a) === void 0);
|
|
14724
|
+
return family === 4 ? v4 : family === 6 ? v6 : [...v4, ...v6];
|
|
14962
14725
|
}
|
|
14963
14726
|
async resolve(name2, family, blocking) {
|
|
14964
14727
|
const key = name2.toLowerCase().replace(/\.$/, "");
|
|
@@ -14967,6 +14730,8 @@ var Resolver = class {
|
|
|
14967
14730
|
const v4 = family !== 6 && local ? [local] : [];
|
|
14968
14731
|
return family === 4 ? v4 : [...v4, key];
|
|
14969
14732
|
}
|
|
14733
|
+
const listed = this.hosts ? await this.fromFile(key, family) : void 0;
|
|
14734
|
+
if (listed?.length) return listed;
|
|
14970
14735
|
if (local) {
|
|
14971
14736
|
const six = loopbackName(key, this.own) ? ["::1"] : [];
|
|
14972
14737
|
return family === 6 ? six : family === 4 ? [local] : [local, ...six];
|
|
@@ -15848,78 +15613,340 @@ async function semSyscall(req, proc) {
|
|
|
15848
15613
|
)
|
|
15849
15614
|
);
|
|
15850
15615
|
}
|
|
15851
|
-
case "sem-close":
|
|
15852
|
-
handles.close(req.handle);
|
|
15853
|
-
return ok2();
|
|
15854
|
-
case "sem-unlink": {
|
|
15855
|
-
const name2 = semName(req.name);
|
|
15856
|
-
table.unlink(name2, unlinks(name2));
|
|
15857
|
-
return ok2();
|
|
15616
|
+
case "sem-close":
|
|
15617
|
+
handles.close(req.handle);
|
|
15618
|
+
return ok2();
|
|
15619
|
+
case "sem-unlink": {
|
|
15620
|
+
const name2 = semName(req.name);
|
|
15621
|
+
table.unlink(name2, unlinks(name2));
|
|
15622
|
+
return ok2();
|
|
15623
|
+
}
|
|
15624
|
+
case "sem-post":
|
|
15625
|
+
handles.get(req.handle).post();
|
|
15626
|
+
return ok2();
|
|
15627
|
+
case "sem-getvalue":
|
|
15628
|
+
return ok2(handles.get(req.handle).value);
|
|
15629
|
+
case "sem-wait": {
|
|
15630
|
+
const sem = handles.get(req.handle);
|
|
15631
|
+
if (sem.take()) return ok2();
|
|
15632
|
+
if (req.how === "try") throw new KernelError("EAGAIN");
|
|
15633
|
+
if (req.how === "timed" && req.timeoutMs === 0) throw new KernelError("ETIMEDOUT");
|
|
15634
|
+
const got = await sem.wait(proc.blocking(), req.how === "block" ? -1 : req.timeoutMs);
|
|
15635
|
+
if (!got) throw new KernelError("ETIMEDOUT");
|
|
15636
|
+
return ok2();
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15639
|
+
}
|
|
15640
|
+
|
|
15641
|
+
// src/kernel/socket-nodes.ts
|
|
15642
|
+
function filePath(addr) {
|
|
15643
|
+
if (addr.family !== "unix" || addr.path === "" || addr.path.startsWith("\0")) return void 0;
|
|
15644
|
+
return normalizePath(addr.path);
|
|
15645
|
+
}
|
|
15646
|
+
function nameOf(st) {
|
|
15647
|
+
return { key: `${st.dev ?? 0}:${st.ino}`, typed: st.isSocket === true };
|
|
15648
|
+
}
|
|
15649
|
+
function codeOf3(err) {
|
|
15650
|
+
return err?.code;
|
|
15651
|
+
}
|
|
15652
|
+
function socketNames(deps) {
|
|
15653
|
+
const { fs } = deps;
|
|
15654
|
+
return {
|
|
15655
|
+
async make(path) {
|
|
15656
|
+
const g = deps.guard();
|
|
15657
|
+
if (g) await inParent(g, "bind", path);
|
|
15658
|
+
const owner = deps.owner();
|
|
15659
|
+
try {
|
|
15660
|
+
await deps.create(path, owner);
|
|
15661
|
+
} catch (err) {
|
|
15662
|
+
if (codeOf3(err) === "EEXIST") throw new KernelError("EADDRINUSE");
|
|
15663
|
+
throw err;
|
|
15664
|
+
}
|
|
15665
|
+
const remove = () => fs.rm(path, { file: true }).catch(() => void 0);
|
|
15666
|
+
try {
|
|
15667
|
+
if (!deps.owners && owner.mode !== void 0) await fs.chmod(path, owner.mode);
|
|
15668
|
+
return { ...nameOf(await fs.lstat(path)), remove };
|
|
15669
|
+
} catch (err) {
|
|
15670
|
+
await remove();
|
|
15671
|
+
throw err;
|
|
15672
|
+
}
|
|
15673
|
+
},
|
|
15674
|
+
async find(path) {
|
|
15675
|
+
const g = deps.guard();
|
|
15676
|
+
if (g) await need(g, "connect", path, W_OK, { directory: false });
|
|
15677
|
+
return nameOf(await fs.stat(path));
|
|
15678
|
+
}
|
|
15679
|
+
};
|
|
15680
|
+
}
|
|
15681
|
+
|
|
15682
|
+
// src/kernel/dgram.ts
|
|
15683
|
+
var DGRAM_QUEUE_BYTES = 256 * 1024;
|
|
15684
|
+
var DGRAM_QUEUE_COUNT = 512;
|
|
15685
|
+
var DGRAM_SEND_ROOM = 256 * 1024;
|
|
15686
|
+
var MAX_DATAGRAM_V4 = 65507;
|
|
15687
|
+
var MAX_DATAGRAM_V6 = 65527;
|
|
15688
|
+
var SOL_SOCKET2 = 1;
|
|
15689
|
+
var IPPROTO_IP = 0;
|
|
15690
|
+
var SO_TYPE2 = 3;
|
|
15691
|
+
var SO_ERROR2 = 4;
|
|
15692
|
+
var SO_BROADCAST = 6;
|
|
15693
|
+
var SO_SNDBUF2 = 7;
|
|
15694
|
+
var SO_RCVBUF2 = 8;
|
|
15695
|
+
var SO_DOMAIN2 = 39;
|
|
15696
|
+
var SOCK_DGRAM = 2;
|
|
15697
|
+
var AF_INET2 = 2;
|
|
15698
|
+
var IP_MULTICAST_FIRST = 32;
|
|
15699
|
+
var IP_MULTICAST_LAST = 36;
|
|
15700
|
+
var SEND_ERRORS = ["ENETUNREACH", "EHOSTUNREACH", "EACCES", "EMSGSIZE"];
|
|
15701
|
+
var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
|
|
15702
|
+
function sendError(e) {
|
|
15703
|
+
if (e instanceof KernelError) return e;
|
|
15704
|
+
const code = e?.code;
|
|
15705
|
+
return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
|
|
15706
|
+
}
|
|
15707
|
+
function sameAddr(a, b) {
|
|
15708
|
+
return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
|
|
15709
|
+
}
|
|
15710
|
+
function familyOf(host) {
|
|
15711
|
+
return host.includes(":") ? 6 : 4;
|
|
15712
|
+
}
|
|
15713
|
+
var KernelDgram = class {
|
|
15714
|
+
local;
|
|
15715
|
+
peer;
|
|
15716
|
+
net;
|
|
15717
|
+
queue = [];
|
|
15718
|
+
queued = 0;
|
|
15719
|
+
pending;
|
|
15720
|
+
closed = false;
|
|
15721
|
+
sending = 0;
|
|
15722
|
+
changes = new Changes();
|
|
15723
|
+
options = /* @__PURE__ */ new Map();
|
|
15724
|
+
uplinks = /* @__PURE__ */ new Map();
|
|
15725
|
+
stop = new AbortController();
|
|
15726
|
+
constructor(net) {
|
|
15727
|
+
this.net = net;
|
|
15728
|
+
}
|
|
15729
|
+
bind(addr) {
|
|
15730
|
+
if (this.local) throw new KernelError("EINVAL");
|
|
15731
|
+
this.local = this.net.bindDgram(this, addr);
|
|
15732
|
+
}
|
|
15733
|
+
bound() {
|
|
15734
|
+
this.local ??= this.net.bindDgram(this, { family: "inet", host: "0.0.0.0", port: 0 });
|
|
15735
|
+
return this.local;
|
|
15736
|
+
}
|
|
15737
|
+
connectTo(addr) {
|
|
15738
|
+
if (addr.family !== "inet") throw new KernelError("EAFNOSUPPORT");
|
|
15739
|
+
this.route(addr.host);
|
|
15740
|
+
this.bound();
|
|
15741
|
+
this.peer = { family: "inet", host: canonicalHost(addr.host), port: addr.port };
|
|
15742
|
+
this.pending = void 0;
|
|
15743
|
+
this.drain((d) => sameAddr(d.from, addr));
|
|
15744
|
+
}
|
|
15745
|
+
drain(keep2) {
|
|
15746
|
+
const kept = this.queue.filter(keep2);
|
|
15747
|
+
this.queue.splice(0, this.queue.length, ...kept);
|
|
15748
|
+
this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
|
|
15749
|
+
}
|
|
15750
|
+
route(host) {
|
|
15751
|
+
const where = this.net.destination(host);
|
|
15752
|
+
if (where === "loopback" || where === "uplink") return where;
|
|
15753
|
+
throw new KernelError("ENETUNREACH");
|
|
15754
|
+
}
|
|
15755
|
+
takeError() {
|
|
15756
|
+
const pending = this.pending;
|
|
15757
|
+
this.pending = void 0;
|
|
15758
|
+
return pending;
|
|
15759
|
+
}
|
|
15760
|
+
async send(bytes, to) {
|
|
15761
|
+
if (this.closed) throw new KernelError("EBADF");
|
|
15762
|
+
const pending = this.takeError();
|
|
15763
|
+
if (pending) throw new KernelError(pending);
|
|
15764
|
+
const target = to ?? this.peer;
|
|
15765
|
+
if (!target) throw new KernelError("EDESTADDRREQ");
|
|
15766
|
+
if (target.family !== "inet") throw new KernelError("EAFNOSUPPORT");
|
|
15767
|
+
const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
|
|
15768
|
+
if (bytes.length > max) throw new KernelError("EMSGSIZE");
|
|
15769
|
+
const where = this.route(target.host);
|
|
15770
|
+
const local = this.bound();
|
|
15771
|
+
if (where === "uplink") return this.sendUp(bytes, target);
|
|
15772
|
+
const from = {
|
|
15773
|
+
family: "inet",
|
|
15774
|
+
host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
|
|
15775
|
+
port: local.port
|
|
15776
|
+
};
|
|
15777
|
+
const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
|
|
15778
|
+
if (!delivered && this.peer && sameAddr(this.peer, target)) {
|
|
15779
|
+
this.pending = "ECONNREFUSED";
|
|
15780
|
+
this.changes.wake();
|
|
15781
|
+
}
|
|
15782
|
+
return bytes.length;
|
|
15783
|
+
}
|
|
15784
|
+
async sendUp(bytes, to) {
|
|
15785
|
+
const uplink = this.net.uplinkFor(to.host)?.uplink;
|
|
15786
|
+
if (!uplink || !carriesUdp(uplink)) throw new KernelError("ENETUNREACH");
|
|
15787
|
+
this.sending += bytes.length;
|
|
15788
|
+
try {
|
|
15789
|
+
const socket = await this.uplinkSocket(uplink, familyOf(to.host));
|
|
15790
|
+
await socket.send(bytes.slice(), to.host, to.port);
|
|
15791
|
+
} catch (e) {
|
|
15792
|
+
throw sendError(e);
|
|
15793
|
+
} finally {
|
|
15794
|
+
this.sending -= bytes.length;
|
|
15795
|
+
this.changes.wake();
|
|
15796
|
+
}
|
|
15797
|
+
return bytes.length;
|
|
15798
|
+
}
|
|
15799
|
+
uplinkSocket(uplink, family) {
|
|
15800
|
+
const known = this.uplinks.get(family);
|
|
15801
|
+
if (known !== void 0) return known;
|
|
15802
|
+
const opening2 = Promise.resolve().then(() => {
|
|
15803
|
+
if (!uplink.udp) throw new KernelError("ENETUNREACH");
|
|
15804
|
+
return uplink.udp({ family, signal: this.stop.signal });
|
|
15805
|
+
});
|
|
15806
|
+
this.uplinks.set(family, opening2);
|
|
15807
|
+
opening2.then(
|
|
15808
|
+
(socket) => {
|
|
15809
|
+
if (this.closed) {
|
|
15810
|
+
socket.close();
|
|
15811
|
+
return;
|
|
15812
|
+
}
|
|
15813
|
+
void this.pump(socket, family);
|
|
15814
|
+
},
|
|
15815
|
+
() => this.uplinks.delete(family)
|
|
15816
|
+
);
|
|
15817
|
+
return opening2;
|
|
15818
|
+
}
|
|
15819
|
+
async pump(socket, family) {
|
|
15820
|
+
const iterate = async () => {
|
|
15821
|
+
for await (const message3 of socket.messages) {
|
|
15822
|
+
if (this.closed) return;
|
|
15823
|
+
const from = { family: "inet", host: message3.host, port: message3.port };
|
|
15824
|
+
if ("bytes" in message3) this.deliver({ bytes: message3.bytes, from });
|
|
15825
|
+
else this.unreachable(message3.error, from);
|
|
15826
|
+
}
|
|
15827
|
+
};
|
|
15828
|
+
await iterate().catch(() => void 0);
|
|
15829
|
+
if (!this.closed) this.uplinks.delete(family);
|
|
15830
|
+
socket.close();
|
|
15831
|
+
}
|
|
15832
|
+
unreachable(error, from) {
|
|
15833
|
+
if (!this.peer || !sameAddr(this.peer, from)) return;
|
|
15834
|
+
this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
|
|
15835
|
+
this.changes.wake();
|
|
15836
|
+
}
|
|
15837
|
+
deliver(datagram2) {
|
|
15838
|
+
if (this.closed) return false;
|
|
15839
|
+
if (this.peer && !sameAddr(this.peer, datagram2.from)) return true;
|
|
15840
|
+
const full = this.queue.length >= DGRAM_QUEUE_COUNT || this.queued + datagram2.bytes.length > DGRAM_QUEUE_BYTES;
|
|
15841
|
+
if (full) return true;
|
|
15842
|
+
this.queue.push(datagram2);
|
|
15843
|
+
this.queued += datagram2.bytes.length;
|
|
15844
|
+
this.changes.wake();
|
|
15845
|
+
return true;
|
|
15846
|
+
}
|
|
15847
|
+
async receive(max, peek, signal) {
|
|
15848
|
+
for (; ; ) {
|
|
15849
|
+
const pending = this.takeError();
|
|
15850
|
+
if (pending) throw new KernelError(pending);
|
|
15851
|
+
if (this.closed) throw new KernelError("EBADF");
|
|
15852
|
+
const next3 = this.queue[0];
|
|
15853
|
+
if (next3) {
|
|
15854
|
+
if (!peek) {
|
|
15855
|
+
this.queue.shift();
|
|
15856
|
+
this.queued -= next3.bytes.length;
|
|
15857
|
+
this.changes.wake();
|
|
15858
|
+
}
|
|
15859
|
+
const size = Math.max(0, max);
|
|
15860
|
+
return {
|
|
15861
|
+
bytes: next3.bytes.slice(0, size),
|
|
15862
|
+
from: next3.from,
|
|
15863
|
+
truncated: next3.bytes.length > size
|
|
15864
|
+
};
|
|
15865
|
+
}
|
|
15866
|
+
await this.changes.wait(signal);
|
|
15867
|
+
}
|
|
15868
|
+
}
|
|
15869
|
+
async read(max, signal) {
|
|
15870
|
+
return (await this.receive(max, false, signal)).bytes;
|
|
15871
|
+
}
|
|
15872
|
+
async peek(max, signal) {
|
|
15873
|
+
return (await this.receive(max, true, signal)).bytes;
|
|
15874
|
+
}
|
|
15875
|
+
write(bytes) {
|
|
15876
|
+
return this.send(bytes);
|
|
15877
|
+
}
|
|
15878
|
+
poll() {
|
|
15879
|
+
return {
|
|
15880
|
+
readable: this.queue.length > 0 || this.pending !== void 0 || this.closed,
|
|
15881
|
+
writable: this.sending < DGRAM_SEND_ROOM,
|
|
15882
|
+
hangup: this.closed,
|
|
15883
|
+
...this.pending !== void 0 ? { error: true } : {}
|
|
15884
|
+
};
|
|
15885
|
+
}
|
|
15886
|
+
changed(signal) {
|
|
15887
|
+
return this.changes.wait(signal);
|
|
15888
|
+
}
|
|
15889
|
+
shutdown(how) {
|
|
15890
|
+
if (!this.peer) throw new KernelError("ENOTCONN");
|
|
15891
|
+
if (how < 0 || how > 2) throw new KernelError("EINVAL");
|
|
15892
|
+
}
|
|
15893
|
+
getOption(level, name2) {
|
|
15894
|
+
if (level === SOL_SOCKET2) {
|
|
15895
|
+
switch (name2) {
|
|
15896
|
+
case SO_TYPE2:
|
|
15897
|
+
return SOCK_DGRAM;
|
|
15898
|
+
case SO_ERROR2: {
|
|
15899
|
+
const pending = this.takeError();
|
|
15900
|
+
return pending ? wasiErrno(pending) : 0;
|
|
15901
|
+
}
|
|
15902
|
+
case SO_DOMAIN2:
|
|
15903
|
+
return AF_INET2;
|
|
15904
|
+
case SO_BROADCAST:
|
|
15905
|
+
return 0;
|
|
15906
|
+
case SO_SNDBUF2:
|
|
15907
|
+
return this.options.get(`${level}:${name2}`) ?? DGRAM_SEND_ROOM;
|
|
15908
|
+
case SO_RCVBUF2:
|
|
15909
|
+
return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
|
|
15910
|
+
}
|
|
15858
15911
|
}
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
return ok2();
|
|
15862
|
-
case "sem-getvalue":
|
|
15863
|
-
return ok2(handles.get(req.handle).value);
|
|
15864
|
-
case "sem-wait": {
|
|
15865
|
-
const sem = handles.get(req.handle);
|
|
15866
|
-
if (sem.take()) return ok2();
|
|
15867
|
-
if (req.how === "try") throw new KernelError("EAGAIN");
|
|
15868
|
-
if (req.how === "timed" && req.timeoutMs === 0) throw new KernelError("ETIMEDOUT");
|
|
15869
|
-
const got = await sem.wait(proc.blocking(), req.how === "block" ? -1 : req.timeoutMs);
|
|
15870
|
-
if (!got) throw new KernelError("ETIMEDOUT");
|
|
15871
|
-
return ok2();
|
|
15912
|
+
if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
|
|
15913
|
+
throw new KernelError("ENOPROTOOPT");
|
|
15872
15914
|
}
|
|
15915
|
+
return this.options.get(`${level}:${name2}`) ?? 0;
|
|
15873
15916
|
}
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
function filePath(addr) {
|
|
15878
|
-
if (addr.family !== "unix" || addr.path === "" || addr.path.startsWith("\0")) return void 0;
|
|
15879
|
-
return normalizePath(addr.path);
|
|
15880
|
-
}
|
|
15881
|
-
function nameOf(st) {
|
|
15882
|
-
return { key: `${st.dev ?? 0}:${st.ino}`, typed: st.isSocket === true };
|
|
15883
|
-
}
|
|
15884
|
-
function codeOf3(err) {
|
|
15885
|
-
return err?.code;
|
|
15886
|
-
}
|
|
15887
|
-
function socketNames(deps) {
|
|
15888
|
-
const { fs } = deps;
|
|
15889
|
-
return {
|
|
15890
|
-
async make(path) {
|
|
15891
|
-
const g = deps.guard();
|
|
15892
|
-
if (g) await inParent(g, "bind", path);
|
|
15893
|
-
const owner = deps.owner();
|
|
15894
|
-
try {
|
|
15895
|
-
await deps.create(path, owner);
|
|
15896
|
-
} catch (err) {
|
|
15897
|
-
if (codeOf3(err) === "EEXIST") throw new KernelError("EADDRINUSE");
|
|
15898
|
-
throw err;
|
|
15899
|
-
}
|
|
15900
|
-
const remove = () => fs.rm(path, { file: true }).catch(() => void 0);
|
|
15901
|
-
try {
|
|
15902
|
-
if (!deps.owners && owner.mode !== void 0) await fs.chmod(path, owner.mode);
|
|
15903
|
-
return { ...nameOf(await fs.lstat(path)), remove };
|
|
15904
|
-
} catch (err) {
|
|
15905
|
-
await remove();
|
|
15906
|
-
throw err;
|
|
15907
|
-
}
|
|
15908
|
-
},
|
|
15909
|
-
async find(path) {
|
|
15910
|
-
const g = deps.guard();
|
|
15911
|
-
if (g) await need(g, "connect", path, W_OK, { directory: false });
|
|
15912
|
-
return nameOf(await fs.stat(path));
|
|
15917
|
+
setOption(level, name2, value2) {
|
|
15918
|
+
if (level === SOL_SOCKET2 && name2 === SO_BROADCAST && value2 !== 0) {
|
|
15919
|
+
throw new KernelError("EOPNOTSUPP");
|
|
15913
15920
|
}
|
|
15914
|
-
|
|
15915
|
-
|
|
15921
|
+
if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
|
|
15922
|
+
throw new KernelError("ENOPROTOOPT");
|
|
15923
|
+
}
|
|
15924
|
+
this.options.set(`${level}:${name2}`, value2);
|
|
15925
|
+
}
|
|
15926
|
+
close() {
|
|
15927
|
+
if (this.closed) return;
|
|
15928
|
+
this.closed = true;
|
|
15929
|
+
this.stop.abort();
|
|
15930
|
+
for (const opening2 of this.uplinks.values()) {
|
|
15931
|
+
opening2.then(
|
|
15932
|
+
(socket) => socket.close(),
|
|
15933
|
+
() => void 0
|
|
15934
|
+
);
|
|
15935
|
+
}
|
|
15936
|
+
this.uplinks.clear();
|
|
15937
|
+
if (this.local) this.net.releaseDgram(this.local, this);
|
|
15938
|
+
this.queue.length = 0;
|
|
15939
|
+
this.queued = 0;
|
|
15940
|
+
this.changes.wake();
|
|
15941
|
+
}
|
|
15942
|
+
};
|
|
15916
15943
|
|
|
15917
15944
|
// src/kernel/net/datagram-wire.ts
|
|
15918
15945
|
function encodeReceived(got) {
|
|
15919
15946
|
const host = new TextEncoder().encode(got.host);
|
|
15920
15947
|
const out = new Uint8Array(4 + host.length + got.bytes.length);
|
|
15921
15948
|
const view2 = new DataView(out.buffer);
|
|
15922
|
-
view2.setUint8(0, got.truncated ? 1 : 0);
|
|
15949
|
+
view2.setUint8(0, (got.truncated ? 1 : 0) | (got.unix ? 2 : 0));
|
|
15923
15950
|
view2.setUint16(1, got.port);
|
|
15924
15951
|
view2.setUint8(3, host.length);
|
|
15925
15952
|
out.set(host, 4);
|
|
@@ -15927,6 +15954,152 @@ function encodeReceived(got) {
|
|
|
15927
15954
|
return out;
|
|
15928
15955
|
}
|
|
15929
15956
|
|
|
15957
|
+
// src/kernel/unix-dgram.ts
|
|
15958
|
+
var SOL_SOCKET3 = 1;
|
|
15959
|
+
var SO_TYPE3 = 3;
|
|
15960
|
+
var SO_ERROR3 = 4;
|
|
15961
|
+
var SO_SNDBUF3 = 7;
|
|
15962
|
+
var SO_RCVBUF3 = 8;
|
|
15963
|
+
var SO_DOMAIN3 = 39;
|
|
15964
|
+
var SOCK_DGRAM2 = 2;
|
|
15965
|
+
var AF_UNIX2 = 1;
|
|
15966
|
+
var UNNAMED = { family: "unix", path: "" };
|
|
15967
|
+
var UnixDgram = class _UnixDgram {
|
|
15968
|
+
local;
|
|
15969
|
+
peer;
|
|
15970
|
+
key;
|
|
15971
|
+
peerCred;
|
|
15972
|
+
target;
|
|
15973
|
+
net;
|
|
15974
|
+
queue = [];
|
|
15975
|
+
queued = 0;
|
|
15976
|
+
closed = false;
|
|
15977
|
+
changes = new Changes();
|
|
15978
|
+
options = /* @__PURE__ */ new Map();
|
|
15979
|
+
constructor(net) {
|
|
15980
|
+
this.net = net;
|
|
15981
|
+
}
|
|
15982
|
+
static pair(net, cred) {
|
|
15983
|
+
const a = new _UnixDgram(net);
|
|
15984
|
+
const b = new _UnixDgram(net);
|
|
15985
|
+
a.target = b;
|
|
15986
|
+
b.target = a;
|
|
15987
|
+
a.peer = b.peer = UNNAMED;
|
|
15988
|
+
a.peerCred = b.peerCred = cred;
|
|
15989
|
+
return [a, b];
|
|
15990
|
+
}
|
|
15991
|
+
bind(addr, key) {
|
|
15992
|
+
if (addr.family !== "unix") throw new KernelError("EINVAL");
|
|
15993
|
+
if (this.local) throw new KernelError("EINVAL");
|
|
15994
|
+
if (addr.path === "") throw new KernelError("EINVAL");
|
|
15995
|
+
this.net.bindUnixDgram(this, key);
|
|
15996
|
+
this.local = { family: "unix", path: addr.path };
|
|
15997
|
+
this.key = key;
|
|
15998
|
+
}
|
|
15999
|
+
connectTo(addr, target) {
|
|
16000
|
+
this.target = target;
|
|
16001
|
+
this.peer = addr;
|
|
16002
|
+
const kept = this.queue.filter((d) => d.sender === target);
|
|
16003
|
+
this.queue.splice(0, this.queue.length, ...kept);
|
|
16004
|
+
this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
|
|
16005
|
+
}
|
|
16006
|
+
destination() {
|
|
16007
|
+
if (!this.target) throw new KernelError("EDESTADDRREQ");
|
|
16008
|
+
return this.target;
|
|
16009
|
+
}
|
|
16010
|
+
room(bytes) {
|
|
16011
|
+
return this.closed || this.queue.length < DGRAM_QUEUE_COUNT && this.queued + bytes <= DGRAM_QUEUE_BYTES;
|
|
16012
|
+
}
|
|
16013
|
+
async send(bytes, to, nonblock, signal) {
|
|
16014
|
+
if (this.closed) throw new KernelError("EBADF");
|
|
16015
|
+
if (bytes.length > DGRAM_QUEUE_BYTES) throw new KernelError("EMSGSIZE");
|
|
16016
|
+
if (to.target && to.target !== this) throw new KernelError("EPERM");
|
|
16017
|
+
while (!to.room(bytes.length)) {
|
|
16018
|
+
if (nonblock) throw new KernelError("EAGAIN");
|
|
16019
|
+
await to.changed(signal);
|
|
16020
|
+
}
|
|
16021
|
+
if (to.closed) throw new KernelError("ECONNREFUSED");
|
|
16022
|
+
to.queue.push({ bytes: bytes.slice(), from: this.local ?? UNNAMED, sender: this });
|
|
16023
|
+
to.queued += bytes.length;
|
|
16024
|
+
to.changes.wake();
|
|
16025
|
+
return bytes.length;
|
|
16026
|
+
}
|
|
16027
|
+
async receive(max, peek, signal) {
|
|
16028
|
+
for (; ; ) {
|
|
16029
|
+
if (this.closed) throw new KernelError("EBADF");
|
|
16030
|
+
const next3 = this.queue[0];
|
|
16031
|
+
if (next3) {
|
|
16032
|
+
if (!peek) {
|
|
16033
|
+
this.queue.shift();
|
|
16034
|
+
this.queued -= next3.bytes.length;
|
|
16035
|
+
this.changes.wake();
|
|
16036
|
+
}
|
|
16037
|
+
const size = Math.max(0, max);
|
|
16038
|
+
return {
|
|
16039
|
+
bytes: next3.bytes.slice(0, size),
|
|
16040
|
+
from: next3.from,
|
|
16041
|
+
truncated: next3.bytes.length > size
|
|
16042
|
+
};
|
|
16043
|
+
}
|
|
16044
|
+
await this.changes.wait(signal);
|
|
16045
|
+
}
|
|
16046
|
+
}
|
|
16047
|
+
async read(max, signal) {
|
|
16048
|
+
return (await this.receive(max, false, signal)).bytes;
|
|
16049
|
+
}
|
|
16050
|
+
async peek(max, signal) {
|
|
16051
|
+
return (await this.receive(max, true, signal)).bytes;
|
|
16052
|
+
}
|
|
16053
|
+
write(bytes, signal) {
|
|
16054
|
+
return this.send(bytes, this.destination(), false, signal);
|
|
16055
|
+
}
|
|
16056
|
+
poll() {
|
|
16057
|
+
const target = this.target;
|
|
16058
|
+
return {
|
|
16059
|
+
readable: this.queue.length > 0 || this.closed,
|
|
16060
|
+
writable: !target || target.room(1),
|
|
16061
|
+
hangup: this.closed
|
|
16062
|
+
};
|
|
16063
|
+
}
|
|
16064
|
+
changed(signal) {
|
|
16065
|
+
return this.changes.wait(signal);
|
|
16066
|
+
}
|
|
16067
|
+
shutdown(how) {
|
|
16068
|
+
if (!this.peer) throw new KernelError("ENOTCONN");
|
|
16069
|
+
if (how < 0 || how > 2) throw new KernelError("EINVAL");
|
|
16070
|
+
}
|
|
16071
|
+
getOption(level, name2) {
|
|
16072
|
+
if (level === SOL_SOCKET3) {
|
|
16073
|
+
switch (name2) {
|
|
16074
|
+
case SO_TYPE3:
|
|
16075
|
+
return SOCK_DGRAM2;
|
|
16076
|
+
case SO_ERROR3:
|
|
16077
|
+
return 0;
|
|
16078
|
+
case SO_DOMAIN3:
|
|
16079
|
+
return AF_UNIX2;
|
|
16080
|
+
case SO_SNDBUF3:
|
|
16081
|
+
case SO_RCVBUF3:
|
|
16082
|
+
return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
|
|
16083
|
+
}
|
|
16084
|
+
}
|
|
16085
|
+
return this.options.get(`${level}:${name2}`) ?? 0;
|
|
16086
|
+
}
|
|
16087
|
+
setOption(level, name2, value2) {
|
|
16088
|
+
this.options.set(`${level}:${name2}`, value2);
|
|
16089
|
+
}
|
|
16090
|
+
close() {
|
|
16091
|
+
if (this.closed) return;
|
|
16092
|
+
this.closed = true;
|
|
16093
|
+
if (this.key !== void 0) this.net.releaseUnixDgram(this.key, this);
|
|
16094
|
+
this.queue.length = 0;
|
|
16095
|
+
this.queued = 0;
|
|
16096
|
+
this.changes.wake();
|
|
16097
|
+
}
|
|
16098
|
+
};
|
|
16099
|
+
function isDatagram(file) {
|
|
16100
|
+
return file instanceof KernelDgram || file instanceof UnixDgram;
|
|
16101
|
+
}
|
|
16102
|
+
|
|
15930
16103
|
// src/kernel/socket-syscalls.ts
|
|
15931
16104
|
var SOCKET_OPS = [
|
|
15932
16105
|
"sock-open",
|
|
@@ -15945,32 +16118,37 @@ var SOCKET_OPS = [
|
|
|
15945
16118
|
];
|
|
15946
16119
|
function socketAt(fds, fd) {
|
|
15947
16120
|
const file = anySocketAt(fds, fd);
|
|
15948
|
-
if (file instanceof
|
|
16121
|
+
if (!(file instanceof KernelSocket)) throw new KernelError("EOPNOTSUPP");
|
|
15949
16122
|
return file;
|
|
15950
16123
|
}
|
|
15951
16124
|
function anySocketAt(fds, fd) {
|
|
15952
16125
|
const file = fds.get(fd).file;
|
|
15953
|
-
if (!(file instanceof KernelSocket) && !(file instanceof KernelDgram)) {
|
|
16126
|
+
if (!(file instanceof KernelSocket) && !(file instanceof KernelDgram) && !(file instanceof UnixDgram)) {
|
|
15954
16127
|
throw new KernelError("ENOTSOCK");
|
|
15955
16128
|
}
|
|
15956
16129
|
return file;
|
|
15957
16130
|
}
|
|
15958
16131
|
function dgramAt(fds, fd) {
|
|
15959
16132
|
const file = anySocketAt(fds, fd);
|
|
15960
|
-
if (
|
|
16133
|
+
if (file instanceof KernelSocket) throw new KernelError("EOPNOTSUPP");
|
|
15961
16134
|
return file;
|
|
15962
16135
|
}
|
|
16136
|
+
async function unixTarget(proc, addr) {
|
|
16137
|
+
if (addr.family !== "unix") throw new KernelError("EAFNOSUPPORT");
|
|
16138
|
+
const path = filePath(addr);
|
|
16139
|
+
const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
|
|
16140
|
+
return proc.net.unixDgramAt(keyOf(path !== void 0 ? { family: "unix", path } : addr, name2));
|
|
16141
|
+
}
|
|
15963
16142
|
var ok3 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
15964
16143
|
async function socketSyscall(req, proc) {
|
|
15965
16144
|
const { fds, net } = proc;
|
|
15966
16145
|
switch (req.op) {
|
|
15967
16146
|
case "sock-open": {
|
|
15968
|
-
|
|
15969
|
-
const file = req.type === "dgram" ? new KernelDgram(net) : net.socket(req.domain);
|
|
16147
|
+
const file = req.type !== "dgram" ? net.socket(req.domain) : req.domain === "unix" ? new UnixDgram(net) : new KernelDgram(net);
|
|
15970
16148
|
return ok3(fds.install(new OpenFile(file), 3));
|
|
15971
16149
|
}
|
|
15972
16150
|
case "sock-pair": {
|
|
15973
|
-
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
16151
|
+
const [a, b] = req.type === "dgram" && req.domain === "unix" ? UnixDgram.pair(net, proc.cred?.()) : KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
15974
16152
|
const first = fds.install(new OpenFile(a), 3);
|
|
15975
16153
|
try {
|
|
15976
16154
|
return ok3([first, fds.install(new OpenFile(b), 3)]);
|
|
@@ -15996,7 +16174,7 @@ async function socketSyscall(req, proc) {
|
|
|
15996
16174
|
const socket = anySocketAt(fds, req.fd);
|
|
15997
16175
|
const addr = req.peer ? socket.peer : socket.local;
|
|
15998
16176
|
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
15999
|
-
return ok3(addr ?? unnamed(socket instanceof
|
|
16177
|
+
return ok3(addr ?? unnamed(socket instanceof KernelSocket ? socket.domain : domainOf(socket)));
|
|
16000
16178
|
}
|
|
16001
16179
|
case "sock-getopt":
|
|
16002
16180
|
return ok3(anySocketAt(fds, req.fd).getOption(req.level, req.name));
|
|
@@ -16018,6 +16196,10 @@ async function connect(req, proc) {
|
|
|
16018
16196
|
target.connectTo(req.addr);
|
|
16019
16197
|
return ok3();
|
|
16020
16198
|
}
|
|
16199
|
+
if (target instanceof UnixDgram) {
|
|
16200
|
+
target.connectTo(req.addr, await unixTarget(proc, req.addr));
|
|
16201
|
+
return ok3();
|
|
16202
|
+
}
|
|
16021
16203
|
const path = filePath(req.addr);
|
|
16022
16204
|
const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
|
|
16023
16205
|
const stamp = proc.net.facadeAt(req.addr) && await proc.stamp?.();
|
|
@@ -16029,8 +16211,23 @@ async function connect(req, proc) {
|
|
|
16029
16211
|
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
16030
16212
|
return ok3();
|
|
16031
16213
|
}
|
|
16214
|
+
async function bindUnixDgram(proc, socket, addr) {
|
|
16215
|
+
const path = filePath(addr);
|
|
16216
|
+
if (path === void 0 || !proc.names) {
|
|
16217
|
+
socket.bind(addr, keyOf(addr));
|
|
16218
|
+
return;
|
|
16219
|
+
}
|
|
16220
|
+
const name2 = await proc.names.make(path);
|
|
16221
|
+
try {
|
|
16222
|
+
socket.bind({ family: "unix", path }, keyOf({ family: "unix", path }, name2));
|
|
16223
|
+
} catch (err) {
|
|
16224
|
+
await name2.remove();
|
|
16225
|
+
throw err;
|
|
16226
|
+
}
|
|
16227
|
+
}
|
|
16032
16228
|
async function bind(proc, fd, addr) {
|
|
16033
16229
|
const socket = anySocketAt(proc.fds, fd);
|
|
16230
|
+
if (socket instanceof UnixDgram) return bindUnixDgram(proc, socket, addr);
|
|
16034
16231
|
const path = filePath(addr);
|
|
16035
16232
|
if (!(socket instanceof KernelSocket) || path === void 0 || !proc.names) {
|
|
16036
16233
|
socket.bind(addr);
|
|
@@ -16047,6 +16244,7 @@ async function bind(proc, fd, addr) {
|
|
|
16047
16244
|
}
|
|
16048
16245
|
async function datagram(req, proc) {
|
|
16049
16246
|
const dgram = dgramAt(proc.fds, req.fd);
|
|
16247
|
+
if (dgram instanceof UnixDgram) return unixDatagram(req, dgram, proc);
|
|
16050
16248
|
if (req.op === "sock-sendto") {
|
|
16051
16249
|
if (req.nonblock && !pollFile(dgram).writable) throw new KernelError("EAGAIN");
|
|
16052
16250
|
return ok3(await dgram.send(req.body, req.addr));
|
|
@@ -16057,6 +16255,24 @@ async function datagram(req, proc) {
|
|
|
16057
16255
|
const { bytes, from, truncated } = got;
|
|
16058
16256
|
return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated, ...from }) };
|
|
16059
16257
|
}
|
|
16258
|
+
async function unixDatagram(req, dgram, proc) {
|
|
16259
|
+
if (req.op === "sock-sendto") {
|
|
16260
|
+
const to = req.addr ? await unixTarget(proc, req.addr) : dgram.destination();
|
|
16261
|
+
return ok3(await dgram.send(req.body, to, req.nonblock, proc.blocking()));
|
|
16262
|
+
}
|
|
16263
|
+
const ready2 = pollFile(dgram).readable;
|
|
16264
|
+
if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
|
|
16265
|
+
const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
|
|
16266
|
+
const { bytes, from, truncated } = got;
|
|
16267
|
+
return {
|
|
16268
|
+
ok: true,
|
|
16269
|
+
kind: "bytes",
|
|
16270
|
+
bytes: encodeReceived({ bytes, truncated, host: from.path, port: 0, unix: true })
|
|
16271
|
+
};
|
|
16272
|
+
}
|
|
16273
|
+
function domainOf(socket) {
|
|
16274
|
+
return socket instanceof UnixDgram ? "unix" : "inet";
|
|
16275
|
+
}
|
|
16060
16276
|
function interruptible2(dialing, signal) {
|
|
16061
16277
|
return new Promise((resolve2, reject) => {
|
|
16062
16278
|
const abort = () => reject(new KernelError("EINTR"));
|
|
@@ -17874,8 +18090,8 @@ var WasmProcess = class {
|
|
|
17874
18090
|
const terminal = (file.tty ?? file.pty?.slave)?.name;
|
|
17875
18091
|
return {
|
|
17876
18092
|
tty: file.tty !== void 0,
|
|
17877
|
-
kind: file instanceof KernelSocket || file
|
|
17878
|
-
...file
|
|
18093
|
+
kind: file instanceof KernelSocket || isDatagram(file) ? "socket" : kernelFdKind(file),
|
|
18094
|
+
...isDatagram(file) ? { dgram: true } : {},
|
|
17879
18095
|
...file.heldMeta ? { meta: file.heldMeta } : {},
|
|
17880
18096
|
...flags2 !== void 0 ? { flags: flags2 } : {},
|
|
17881
18097
|
...this.fds.closesOnExec(fd) ? { cloexec: true } : {},
|
|
@@ -18311,7 +18527,7 @@ function inheritedFds(fds) {
|
|
|
18311
18527
|
return fds.numbers().filter((fd) => fd > 2 && !fds.get(fd).file.held).map((fd) => {
|
|
18312
18528
|
const open = fds.get(fd);
|
|
18313
18529
|
const flags2 = fds.statusFlags(fd);
|
|
18314
|
-
const kind = open.file instanceof KernelSocket || open.file
|
|
18530
|
+
const kind = open.file instanceof KernelSocket || isDatagram(open.file) ? "socket" : kernelFdKind(open.file);
|
|
18315
18531
|
const meta = open.file.heldMeta;
|
|
18316
18532
|
return {
|
|
18317
18533
|
fd,
|
|
@@ -18917,6 +19133,43 @@ var JobTable = class {
|
|
|
18917
19133
|
}
|
|
18918
19134
|
};
|
|
18919
19135
|
|
|
19136
|
+
// src/kernel/net/hosts-file.ts
|
|
19137
|
+
var HOSTS_PATH = "/etc/hosts";
|
|
19138
|
+
function parseHosts(text) {
|
|
19139
|
+
const table = /* @__PURE__ */ new Map();
|
|
19140
|
+
for (const raw of text.split("\n")) {
|
|
19141
|
+
const [address, ...names] = raw.replace(/#.*/, "").trim().split(/\s+/);
|
|
19142
|
+
if (!address || names.length === 0) continue;
|
|
19143
|
+
if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
|
|
19144
|
+
for (const name2 of names) {
|
|
19145
|
+
const key = name2.toLowerCase().replace(/\.$/, "");
|
|
19146
|
+
const known = table.get(key) ?? [];
|
|
19147
|
+
if (!known.includes(address)) known.push(address);
|
|
19148
|
+
table.set(key, known);
|
|
19149
|
+
}
|
|
19150
|
+
}
|
|
19151
|
+
return table;
|
|
19152
|
+
}
|
|
19153
|
+
function hostsReader(fs, path = HOSTS_PATH) {
|
|
19154
|
+
let stamp = "";
|
|
19155
|
+
let table;
|
|
19156
|
+
return async () => {
|
|
19157
|
+
const st = await fs.stat(path).catch(() => void 0);
|
|
19158
|
+
if (!st?.isFile) {
|
|
19159
|
+
stamp = "";
|
|
19160
|
+
table = void 0;
|
|
19161
|
+
return void 0;
|
|
19162
|
+
}
|
|
19163
|
+
const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
|
|
19164
|
+
if (now === stamp && table) return table;
|
|
19165
|
+
const text = await fs.readFile(path).catch(() => void 0);
|
|
19166
|
+
if (text === void 0) return void 0;
|
|
19167
|
+
stamp = now;
|
|
19168
|
+
table = parseHosts(text);
|
|
19169
|
+
return table;
|
|
19170
|
+
};
|
|
19171
|
+
}
|
|
19172
|
+
|
|
18920
19173
|
// src/kernel/net/redirect-hops.ts
|
|
18921
19174
|
var HELD_MS = 3e4;
|
|
18922
19175
|
var HELD_MAX = 64;
|
|
@@ -22289,7 +22542,12 @@ var Launcher = class {
|
|
|
22289
22542
|
this.uplink = options.uplink;
|
|
22290
22543
|
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
22291
22544
|
if (options.uplink?.routes) this.routes.set(options.uplink.routes);
|
|
22292
|
-
this.resolver = new Resolver({
|
|
22545
|
+
this.resolver = new Resolver({
|
|
22546
|
+
uplink: options.uplink,
|
|
22547
|
+
routes: this.routes,
|
|
22548
|
+
hostname,
|
|
22549
|
+
hosts: hostsReader(this.base)
|
|
22550
|
+
});
|
|
22293
22551
|
if (options.uplink) this.net.useUplink({ uplink: options.uplink, routes: this.routes });
|
|
22294
22552
|
enableNetwork(this.net, {
|
|
22295
22553
|
transport: this.transport,
|