@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.
@@ -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) throw new KernelError("EADDRINUSE");
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.110.8" : "0.0.0-dev";
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/kernel/net/uplink.ts
11768
- function carriesUdp(uplink) {
11769
- return uplink.traits.udp === true && typeof uplink.udp === "function";
11770
- }
11771
- function answerOf(result) {
11772
- const answer = Array.isArray(result) ? { addresses: result } : result;
11773
- const addresses = Array.isArray(answer?.addresses) ? answer.addresses.filter((a) => typeof a === "string") : [];
11774
- return {
11775
- addresses,
11776
- ...typeof answer?.ttl === "number" && answer.ttl >= 0 ? { ttl: answer.ttl } : {}
11777
- };
11778
- }
11779
- var NEVER = new Routes(true);
11780
- var RemoteUplink = class {
11781
- traits;
11782
- routes;
11783
- port;
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
- async resolve(name2, family, signal) {
11814
- const reply = await this.ask(
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
- async dial(req) {
11821
- req.signal.throwIfAborted();
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
- async udp(req) {
11852
- req.signal.throwIfAborted();
11853
- const opened2 = await this.ask(
11854
- { uplink: "udp-open", uid: ++this.nextId, family: req.family },
11855
- req.signal
11856
- );
11857
- const { cid, localAddr } = opened2;
11858
- const recv = () => this.ask({
11859
- uplink: "udp-recv",
11860
- uid: ++this.nextId,
11861
- cid
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
- // src/kernel/dgram.ts
11892
- var DGRAM_QUEUE_BYTES = 256 * 1024;
11893
- var DGRAM_QUEUE_COUNT = 512;
11894
- var DGRAM_SEND_ROOM = 256 * 1024;
11895
- var MAX_DATAGRAM_V4 = 65507;
11896
- var MAX_DATAGRAM_V6 = 65527;
11897
- var SOL_SOCKET2 = 1;
11898
- var IPPROTO_IP = 0;
11899
- var SO_TYPE2 = 3;
11900
- var SO_ERROR2 = 4;
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
- bind(addr) {
11939
- if (this.local) throw new KernelError("EINVAL");
11940
- this.local = this.net.bindDgram(this, addr);
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
- bound() {
11943
- this.local ??= this.net.bindDgram(this, { family: "inet", host: "0.0.0.0", port: 0 });
11944
- return this.local;
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
- connectTo(addr) {
11947
- if (addr.family !== "inet") throw new KernelError("EAFNOSUPPORT");
11948
- this.route(addr.host);
11949
- this.bound();
11950
- this.peer = { family: "inet", host: canonicalHost(addr.host), port: addr.port };
11951
- this.pending = void 0;
11952
- this.drain((d) => sameAddr(d.from, addr));
11953
- }
11954
- drain(keep2) {
11955
- const kept = this.queue.filter(keep2);
11956
- this.queue.splice(0, this.queue.length, ...kept);
11957
- this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
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
- case "sem-post":
15860
- handles.get(req.handle).post();
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
- // src/kernel/socket-nodes.ts
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 KernelDgram) throw new KernelError("EOPNOTSUPP");
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 (!(file instanceof KernelDgram)) throw new KernelError("EOPNOTSUPP");
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
- if (req.type === "dgram" && req.domain !== "inet") throw new KernelError("EPROTONOSUPPORT");
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 KernelDgram ? "inet" : socket.domain));
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 instanceof KernelDgram ? "socket" : kernelFdKind(file),
17878
- ...file instanceof KernelDgram ? { dgram: true } : {},
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 instanceof KernelDgram ? "socket" : kernelFdKind(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({ uplink: options.uplink, routes: this.routes, hostname });
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,