@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/dist/node.js CHANGED
@@ -1858,6 +1858,7 @@ var LOCAL_ONLY = new Routes();
1858
1858
  var LoopbackNet = class {
1859
1859
  bound = /* @__PURE__ */ new Map();
1860
1860
  dgrams = /* @__PURE__ */ new Map();
1861
+ unixDgrams = /* @__PURE__ */ new Map();
1861
1862
  activators = /* @__PURE__ */ new Map();
1862
1863
  internal = /* @__PURE__ */ new Set();
1863
1864
  reserved = /* @__PURE__ */ new Set();
@@ -1883,6 +1884,18 @@ var LoopbackNet = class {
1883
1884
  this.dgrams.set(port, socket);
1884
1885
  return { ...addr, port };
1885
1886
  }
1887
+ bindUnixDgram(socket, key) {
1888
+ if (this.bound.has(key) || this.unixDgrams.has(key)) throw new KernelError("EADDRINUSE");
1889
+ this.unixDgrams.set(key, socket);
1890
+ }
1891
+ releaseUnixDgram(key, socket) {
1892
+ if (this.unixDgrams.get(key) === socket) this.unixDgrams.delete(key);
1893
+ }
1894
+ unixDgramAt(key) {
1895
+ const socket = this.unixDgrams.get(key);
1896
+ if (socket) return socket;
1897
+ throw new KernelError(this.bound.has(key) ? "EPROTOTYPE" : "ECONNREFUSED");
1898
+ }
1886
1899
  releaseDgram(addr, socket) {
1887
1900
  if (this.dgrams.get(addr.port) === socket) this.dgrams.delete(addr.port);
1888
1901
  }
@@ -1936,7 +1949,9 @@ var LoopbackNet = class {
1936
1949
  } else this.bindable(addr, kernel);
1937
1950
  const named = addr.family === "inet" && addr.port === 0 ? { ...addr, port: this.ephemeral() } : addr;
1938
1951
  const key = keyOf(named, name2);
1939
- if (this.bound.has(key) && !name2) throw new KernelError("EADDRINUSE");
1952
+ if (this.bound.has(key) && !name2 || this.unixDgrams.has(key)) {
1953
+ throw new KernelError("EADDRINUSE");
1954
+ }
1940
1955
  this.bound.set(key, socket);
1941
1956
  socket.named = name2;
1942
1957
  return named;
@@ -1950,6 +1965,7 @@ var LoopbackNet = class {
1950
1965
  throw new KernelError("ENETUNREACH");
1951
1966
  }
1952
1967
  const key = keyOf(addr, name2);
1968
+ if (this.unixDgrams.has(key)) throw new KernelError("EPROTOTYPE");
1953
1969
  if (!this.bound.has(key)) this.activators.get(key)?.();
1954
1970
  const socket = this.bound.get(key);
1955
1971
  if (!socket?.listening) throw new KernelError("ECONNREFUSED");
@@ -6494,7 +6510,7 @@ function satisfies(version, range2) {
6494
6510
  }
6495
6511
 
6496
6512
  // src/version.ts
6497
- var KERNEL_VERSION = true ? "1.110.8" : "0.0.0-dev";
6513
+ var KERNEL_VERSION = true ? "1.112.0" : "0.0.0-dev";
6498
6514
  var OS_RELEASE = "6.0.0-slicc";
6499
6515
  function procVersion() {
6500
6516
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -11860,391 +11876,115 @@ var ProcessClocks = class {
11860
11876
  }
11861
11877
  };
11862
11878
 
11863
- // src/kernel/net/uplink.ts
11864
- function carriesUdp(uplink) {
11865
- return uplink.traits.udp === true && typeof uplink.udp === "function";
11866
- }
11867
- function answerOf(result) {
11868
- const answer = Array.isArray(result) ? { addresses: result } : result;
11869
- const addresses = Array.isArray(answer?.addresses) ? answer.addresses.filter((a) => typeof a === "string") : [];
11870
- return {
11871
- addresses,
11872
- ...typeof answer?.ttl === "number" && answer.ttl >= 0 ? { ttl: answer.ttl } : {}
11873
- };
11874
- }
11875
- var NEVER = new Routes(true);
11876
-
11877
- // src/kernel/dgram.ts
11878
- var DGRAM_QUEUE_BYTES = 256 * 1024;
11879
- var DGRAM_QUEUE_COUNT = 512;
11880
- var DGRAM_SEND_ROOM = 256 * 1024;
11881
- var MAX_DATAGRAM_V4 = 65507;
11882
- var MAX_DATAGRAM_V6 = 65527;
11883
- var SOL_SOCKET2 = 1;
11884
- var IPPROTO_IP = 0;
11885
- var SO_TYPE2 = 3;
11886
- var SO_ERROR2 = 4;
11887
- var SO_BROADCAST = 6;
11888
- var SO_SNDBUF2 = 7;
11889
- var SO_RCVBUF2 = 8;
11890
- var SO_DOMAIN2 = 39;
11891
- var SOCK_DGRAM = 2;
11892
- var AF_INET2 = 2;
11893
- var IP_MULTICAST_FIRST = 32;
11894
- var IP_MULTICAST_LAST = 36;
11895
- var SEND_ERRORS = ["ENETUNREACH", "EHOSTUNREACH", "EACCES", "EMSGSIZE"];
11896
- var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
11897
- function sendError(e) {
11898
- if (e instanceof KernelError) return e;
11899
- const code = e?.code;
11900
- return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
11901
- }
11902
- function sameAddr(a, b) {
11903
- return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
11904
- }
11905
- function familyOf(host) {
11906
- return host.includes(":") ? 6 : 4;
11907
- }
11908
- var KernelDgram = class {
11909
- local;
11910
- peer;
11911
- net;
11912
- queue = [];
11913
- queued = 0;
11914
- pending;
11915
- closed = false;
11916
- sending = 0;
11917
- changes = new Changes();
11918
- options = /* @__PURE__ */ new Map();
11919
- uplinks = /* @__PURE__ */ new Map();
11920
- stop = new AbortController();
11921
- constructor(net) {
11922
- this.net = net;
11879
+ // src/fs/pages.ts
11880
+ var PAGE = 64 * 1024;
11881
+ var READAHEAD = 1024 * 1024;
11882
+ var CLEAN_LIMIT = 4 * 1024 * 1024;
11883
+ var WRITEBACK = 8 * 1024 * 1024;
11884
+ var RUN = 1024 * 1024;
11885
+ var Pages = class {
11886
+ length;
11887
+ stored;
11888
+ shrink;
11889
+ pages = /* @__PURE__ */ new Map();
11890
+ dirty = /* @__PURE__ */ new Set();
11891
+ free = [];
11892
+ pinned = false;
11893
+ constructor(size) {
11894
+ this.length = size;
11895
+ this.stored = size;
11923
11896
  }
11924
- bind(addr) {
11925
- if (this.local) throw new KernelError("EINVAL");
11926
- this.local = this.net.bindDgram(this, addr);
11897
+ get dirtyBytes() {
11898
+ return this.dirty.size * PAGE;
11927
11899
  }
11928
- bound() {
11929
- this.local ??= this.net.bindDgram(this, { family: "inet", host: "0.0.0.0", port: 0 });
11930
- return this.local;
11900
+ get changed() {
11901
+ return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
11931
11902
  }
11932
- connectTo(addr) {
11933
- if (addr.family !== "inet") throw new KernelError("EAFNOSUPPORT");
11934
- this.route(addr.host);
11935
- this.bound();
11936
- this.peer = { family: "inet", host: canonicalHost(addr.host), port: addr.port };
11937
- this.pending = void 0;
11938
- this.drain((d) => sameAddr(d.from, addr));
11903
+ missing(at, length2) {
11904
+ this.evict();
11905
+ const end = Math.min(this.stored, at + length2, this.length);
11906
+ const runs = [];
11907
+ for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
11908
+ if (this.pages.has(page)) continue;
11909
+ const last2 = runs[runs.length - 1];
11910
+ if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
11911
+ else runs.push([page * PAGE, PAGE]);
11912
+ }
11913
+ const last = runs[runs.length - 1];
11914
+ if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
11915
+ return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
11939
11916
  }
11940
- drain(keep2) {
11941
- const kept = this.queue.filter(keep2);
11942
- this.queue.splice(0, this.queue.length, ...kept);
11943
- this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
11917
+ partial(at, length2) {
11918
+ if (length2 === 0) return [];
11919
+ this.evict();
11920
+ const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
11921
+ const runs = [];
11922
+ for (const page of edges) {
11923
+ const start2 = page * PAGE;
11924
+ const covered = at <= start2 && at + length2 >= start2 + PAGE;
11925
+ if (covered || this.pages.has(page) || start2 >= this.stored) continue;
11926
+ runs.push([start2, Math.min(PAGE, this.stored - start2)]);
11927
+ }
11928
+ return runs;
11944
11929
  }
11945
- route(host) {
11946
- const where = this.net.destination(host);
11947
- if (where === "loopback" || where === "uplink") return where;
11948
- throw new KernelError("ENETUNREACH");
11930
+ fill(start2, bytes) {
11931
+ for (let at = 0; at < bytes.length; at += PAGE) {
11932
+ const page = (start2 + at) / PAGE;
11933
+ if (this.pages.has(page)) continue;
11934
+ const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
11935
+ const fresh2 = this.take(part.length);
11936
+ fresh2.set(part);
11937
+ this.pages.set(page, fresh2);
11938
+ }
11949
11939
  }
11950
- takeError() {
11951
- const pending = this.pending;
11952
- this.pending = void 0;
11953
- return pending;
11940
+ read(at, length2) {
11941
+ const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
11942
+ this.readInto(at, out);
11943
+ return out;
11954
11944
  }
11955
- async send(bytes, to) {
11956
- if (this.closed) throw new KernelError("EBADF");
11957
- const pending = this.takeError();
11958
- if (pending) throw new KernelError(pending);
11959
- const target = to ?? this.peer;
11960
- if (!target) throw new KernelError("EDESTADDRREQ");
11961
- if (target.family !== "inet") throw new KernelError("EAFNOSUPPORT");
11962
- const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
11963
- if (bytes.length > max) throw new KernelError("EMSGSIZE");
11964
- const where = this.route(target.host);
11965
- const local = this.bound();
11966
- if (where === "uplink") return this.sendUp(bytes, target);
11967
- const from = {
11968
- family: "inet",
11969
- host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
11970
- port: local.port
11971
- };
11972
- const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
11973
- if (!delivered && this.peer && sameAddr(this.peer, target)) {
11974
- this.pending = "ECONNREFUSED";
11975
- this.changes.wake();
11945
+ readInto(at, out) {
11946
+ const end = Math.min(this.length, at + out.length);
11947
+ for (let pos = at; pos < end; ) {
11948
+ const page = Math.floor(pos / PAGE);
11949
+ const from = pos - page * PAGE;
11950
+ const n = Math.min(PAGE - from, end - pos);
11951
+ const bytes = this.pages.get(page);
11952
+ if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
11953
+ else out.fill(0, pos - at, pos - at + n);
11954
+ pos += n;
11976
11955
  }
11977
- return bytes.length;
11956
+ return Math.max(0, end - at);
11978
11957
  }
11979
- async sendUp(bytes, to) {
11980
- const uplink = this.net.uplinkFor(to.host)?.uplink;
11981
- if (!uplink || !carriesUdp(uplink)) throw new KernelError("ENETUNREACH");
11982
- this.sending += bytes.length;
11983
- try {
11984
- const socket = await this.uplinkSocket(uplink, familyOf(to.host));
11985
- await socket.send(bytes.slice(), to.host, to.port);
11986
- } catch (e) {
11987
- throw sendError(e);
11988
- } finally {
11989
- this.sending -= bytes.length;
11990
- this.changes.wake();
11958
+ write(at, bytes) {
11959
+ for (let done4 = 0; done4 < bytes.length; ) {
11960
+ const pos = at + done4;
11961
+ const page = Math.floor(pos / PAGE);
11962
+ const from = pos - page * PAGE;
11963
+ const n = Math.min(PAGE - from, bytes.length - done4);
11964
+ let target = this.pages.get(page);
11965
+ if (!target) {
11966
+ target = this.take(0);
11967
+ this.pages.set(page, target);
11968
+ }
11969
+ target.set(bytes.subarray(done4, done4 + n), from);
11970
+ this.dirty.add(page);
11971
+ done4 += n;
11991
11972
  }
11992
- return bytes.length;
11993
- }
11994
- uplinkSocket(uplink, family) {
11995
- const known = this.uplinks.get(family);
11996
- if (known !== void 0) return known;
11997
- const opening2 = Promise.resolve().then(() => {
11998
- if (!uplink.udp) throw new KernelError("ENETUNREACH");
11999
- return uplink.udp({ family, signal: this.stop.signal });
12000
- });
12001
- this.uplinks.set(family, opening2);
12002
- opening2.then(
12003
- (socket) => {
12004
- if (this.closed) {
12005
- socket.close();
12006
- return;
12007
- }
12008
- void this.pump(socket, family);
12009
- },
12010
- () => this.uplinks.delete(family)
12011
- );
12012
- return opening2;
11973
+ this.length = Math.max(this.length, at + bytes.length);
12013
11974
  }
12014
- async pump(socket, family) {
12015
- const iterate = async () => {
12016
- for await (const message3 of socket.messages) {
12017
- if (this.closed) return;
12018
- const from = { family: "inet", host: message3.host, port: message3.port };
12019
- if ("bytes" in message3) this.deliver({ bytes: message3.bytes, from });
12020
- else this.unreachable(message3.error, from);
11975
+ truncate(size) {
11976
+ if (size < this.stored) {
11977
+ this.stored = size;
11978
+ this.shrink = Math.min(this.shrink ?? size, size);
11979
+ }
11980
+ if (size < this.length) {
11981
+ const edge = Math.floor(size / PAGE);
11982
+ for (const page of [...this.pages.keys()]) {
11983
+ if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
12021
11984
  }
12022
- };
12023
- await iterate().catch(() => void 0);
12024
- if (!this.closed) this.uplinks.delete(family);
12025
- socket.close();
12026
- }
12027
- unreachable(error, from) {
12028
- if (!this.peer || !sameAddr(this.peer, from)) return;
12029
- this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
12030
- this.changes.wake();
12031
- }
12032
- deliver(datagram2) {
12033
- if (this.closed) return false;
12034
- if (this.peer && !sameAddr(this.peer, datagram2.from)) return true;
12035
- const full = this.queue.length >= DGRAM_QUEUE_COUNT || this.queued + datagram2.bytes.length > DGRAM_QUEUE_BYTES;
12036
- if (full) return true;
12037
- this.queue.push(datagram2);
12038
- this.queued += datagram2.bytes.length;
12039
- this.changes.wake();
12040
- return true;
12041
- }
12042
- async receive(max, peek, signal) {
12043
- for (; ; ) {
12044
- const pending = this.takeError();
12045
- if (pending) throw new KernelError(pending);
12046
- if (this.closed) throw new KernelError("EBADF");
12047
- const next3 = this.queue[0];
12048
- if (next3) {
12049
- if (!peek) {
12050
- this.queue.shift();
12051
- this.queued -= next3.bytes.length;
12052
- this.changes.wake();
12053
- }
12054
- const size = Math.max(0, max);
12055
- return {
12056
- bytes: next3.bytes.slice(0, size),
12057
- from: next3.from,
12058
- truncated: next3.bytes.length > size
12059
- };
12060
- }
12061
- await this.changes.wait(signal);
12062
- }
12063
- }
12064
- async read(max, signal) {
12065
- return (await this.receive(max, false, signal)).bytes;
12066
- }
12067
- async peek(max, signal) {
12068
- return (await this.receive(max, true, signal)).bytes;
12069
- }
12070
- write(bytes) {
12071
- return this.send(bytes);
12072
- }
12073
- poll() {
12074
- return {
12075
- readable: this.queue.length > 0 || this.pending !== void 0 || this.closed,
12076
- writable: this.sending < DGRAM_SEND_ROOM,
12077
- hangup: this.closed,
12078
- ...this.pending !== void 0 ? { error: true } : {}
12079
- };
12080
- }
12081
- changed(signal) {
12082
- return this.changes.wait(signal);
12083
- }
12084
- shutdown(how) {
12085
- if (!this.peer) throw new KernelError("ENOTCONN");
12086
- if (how < 0 || how > 2) throw new KernelError("EINVAL");
12087
- }
12088
- getOption(level, name2) {
12089
- if (level === SOL_SOCKET2) {
12090
- switch (name2) {
12091
- case SO_TYPE2:
12092
- return SOCK_DGRAM;
12093
- case SO_ERROR2: {
12094
- const pending = this.takeError();
12095
- return pending ? wasiErrno(pending) : 0;
12096
- }
12097
- case SO_DOMAIN2:
12098
- return AF_INET2;
12099
- case SO_BROADCAST:
12100
- return 0;
12101
- case SO_SNDBUF2:
12102
- return this.options.get(`${level}:${name2}`) ?? DGRAM_SEND_ROOM;
12103
- case SO_RCVBUF2:
12104
- return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
12105
- }
12106
- }
12107
- if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
12108
- throw new KernelError("ENOPROTOOPT");
12109
- }
12110
- return this.options.get(`${level}:${name2}`) ?? 0;
12111
- }
12112
- setOption(level, name2, value2) {
12113
- if (level === SOL_SOCKET2 && name2 === SO_BROADCAST && value2 !== 0) {
12114
- throw new KernelError("EOPNOTSUPP");
12115
- }
12116
- if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
12117
- throw new KernelError("ENOPROTOOPT");
12118
- }
12119
- this.options.set(`${level}:${name2}`, value2);
12120
- }
12121
- close() {
12122
- if (this.closed) return;
12123
- this.closed = true;
12124
- this.stop.abort();
12125
- for (const opening2 of this.uplinks.values()) {
12126
- opening2.then(
12127
- (socket) => socket.close(),
12128
- () => void 0
12129
- );
12130
- }
12131
- this.uplinks.clear();
12132
- if (this.local) this.net.releaseDgram(this.local, this);
12133
- this.queue.length = 0;
12134
- this.queued = 0;
12135
- this.changes.wake();
12136
- }
12137
- };
12138
-
12139
- // src/fs/pages.ts
12140
- var PAGE = 64 * 1024;
12141
- var READAHEAD = 1024 * 1024;
12142
- var CLEAN_LIMIT = 4 * 1024 * 1024;
12143
- var WRITEBACK = 8 * 1024 * 1024;
12144
- var RUN = 1024 * 1024;
12145
- var Pages = class {
12146
- length;
12147
- stored;
12148
- shrink;
12149
- pages = /* @__PURE__ */ new Map();
12150
- dirty = /* @__PURE__ */ new Set();
12151
- free = [];
12152
- pinned = false;
12153
- constructor(size) {
12154
- this.length = size;
12155
- this.stored = size;
12156
- }
12157
- get dirtyBytes() {
12158
- return this.dirty.size * PAGE;
12159
- }
12160
- get changed() {
12161
- return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
12162
- }
12163
- missing(at, length2) {
12164
- this.evict();
12165
- const end = Math.min(this.stored, at + length2, this.length);
12166
- const runs = [];
12167
- for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
12168
- if (this.pages.has(page)) continue;
12169
- const last2 = runs[runs.length - 1];
12170
- if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
12171
- else runs.push([page * PAGE, PAGE]);
12172
- }
12173
- const last = runs[runs.length - 1];
12174
- if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
12175
- return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
12176
- }
12177
- partial(at, length2) {
12178
- if (length2 === 0) return [];
12179
- this.evict();
12180
- const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
12181
- const runs = [];
12182
- for (const page of edges) {
12183
- const start2 = page * PAGE;
12184
- const covered = at <= start2 && at + length2 >= start2 + PAGE;
12185
- if (covered || this.pages.has(page) || start2 >= this.stored) continue;
12186
- runs.push([start2, Math.min(PAGE, this.stored - start2)]);
12187
- }
12188
- return runs;
12189
- }
12190
- fill(start2, bytes) {
12191
- for (let at = 0; at < bytes.length; at += PAGE) {
12192
- const page = (start2 + at) / PAGE;
12193
- if (this.pages.has(page)) continue;
12194
- const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
12195
- const fresh2 = this.take(part.length);
12196
- fresh2.set(part);
12197
- this.pages.set(page, fresh2);
12198
- }
12199
- }
12200
- read(at, length2) {
12201
- const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
12202
- this.readInto(at, out);
12203
- return out;
12204
- }
12205
- readInto(at, out) {
12206
- const end = Math.min(this.length, at + out.length);
12207
- for (let pos = at; pos < end; ) {
12208
- const page = Math.floor(pos / PAGE);
12209
- const from = pos - page * PAGE;
12210
- const n = Math.min(PAGE - from, end - pos);
12211
- const bytes = this.pages.get(page);
12212
- if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
12213
- else out.fill(0, pos - at, pos - at + n);
12214
- pos += n;
12215
- }
12216
- return Math.max(0, end - at);
12217
- }
12218
- write(at, bytes) {
12219
- for (let done4 = 0; done4 < bytes.length; ) {
12220
- const pos = at + done4;
12221
- const page = Math.floor(pos / PAGE);
12222
- const from = pos - page * PAGE;
12223
- const n = Math.min(PAGE - from, bytes.length - done4);
12224
- let target = this.pages.get(page);
12225
- if (!target) {
12226
- target = this.take(0);
12227
- this.pages.set(page, target);
12228
- }
12229
- target.set(bytes.subarray(done4, done4 + n), from);
12230
- this.dirty.add(page);
12231
- done4 += n;
12232
- }
12233
- this.length = Math.max(this.length, at + bytes.length);
12234
- }
12235
- truncate(size) {
12236
- if (size < this.stored) {
12237
- this.stored = size;
12238
- this.shrink = Math.min(this.shrink ?? size, size);
12239
- }
12240
- if (size < this.length) {
12241
- const edge = Math.floor(size / PAGE);
12242
- for (const page of [...this.pages.keys()]) {
12243
- if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
12244
- }
12245
- this.pages.get(edge)?.fill(0, size - edge * PAGE);
12246
- }
12247
- this.length = size;
11985
+ this.pages.get(edge)?.fill(0, size - edge * PAGE);
11986
+ }
11987
+ this.length = size;
12248
11988
  }
12249
11989
  plan() {
12250
11990
  const runs = [];
@@ -14867,6 +14607,20 @@ var HttpHandles = class {
14867
14607
  }
14868
14608
  };
14869
14609
 
14610
+ // src/kernel/net/uplink.ts
14611
+ function carriesUdp(uplink) {
14612
+ return uplink.traits.udp === true && typeof uplink.udp === "function";
14613
+ }
14614
+ function answerOf(result) {
14615
+ const answer = Array.isArray(result) ? { addresses: result } : result;
14616
+ const addresses = Array.isArray(answer?.addresses) ? answer.addresses.filter((a) => typeof a === "string") : [];
14617
+ return {
14618
+ addresses,
14619
+ ...typeof answer?.ttl === "number" && answer.ttl >= 0 ? { ttl: answer.ttl } : {}
14620
+ };
14621
+ }
14622
+ var NEVER = new Routes(true);
14623
+
14870
14624
  // src/kernel/net/resolver.ts
14871
14625
  var RESOLVE_TTL_MAX = 60;
14872
14626
  var RESOLVE_TIMEOUT_MS = 1e4;
@@ -14890,6 +14644,7 @@ var Resolver = class {
14890
14644
  own;
14891
14645
  cache = /* @__PURE__ */ new Map();
14892
14646
  pending = /* @__PURE__ */ new Map();
14647
+ hosts;
14893
14648
  constructor(options) {
14894
14649
  this.uplink = options.uplink;
14895
14650
  this.routes = options.routes;
@@ -14897,6 +14652,14 @@ var Resolver = class {
14897
14652
  this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
14898
14653
  this.log = options.log ?? ((message3) => console.warn(message3));
14899
14654
  this.own = ownNames(options.hostname ?? DEFAULT_HOSTNAME);
14655
+ this.hosts = options.hosts;
14656
+ }
14657
+ async fromFile(key, family) {
14658
+ const listed = (await this.hosts?.().catch(() => void 0))?.get(key);
14659
+ if (!listed) return void 0;
14660
+ const v4 = listed.filter((a) => ipv4Bytes(a) !== void 0);
14661
+ const v6 = listed.filter((a) => ipv4Bytes(a) === void 0);
14662
+ return family === 4 ? v4 : family === 6 ? v6 : [...v4, ...v6];
14900
14663
  }
14901
14664
  async resolve(name2, family, blocking) {
14902
14665
  const key = name2.toLowerCase().replace(/\.$/, "");
@@ -14905,6 +14668,8 @@ var Resolver = class {
14905
14668
  const v4 = family !== 6 && local ? [local] : [];
14906
14669
  return family === 4 ? v4 : [...v4, key];
14907
14670
  }
14671
+ const listed = this.hosts ? await this.fromFile(key, family) : void 0;
14672
+ if (listed?.length) return listed;
14908
14673
  if (local) {
14909
14674
  const six = loopbackName(key, this.own) ? ["::1"] : [];
14910
14675
  return family === 6 ? six : family === 4 ? [local] : [local, ...six];
@@ -15786,78 +15551,340 @@ async function semSyscall(req, proc) {
15786
15551
  )
15787
15552
  );
15788
15553
  }
15789
- case "sem-close":
15790
- handles.close(req.handle);
15791
- return ok2();
15792
- case "sem-unlink": {
15793
- const name2 = semName(req.name);
15794
- table.unlink(name2, unlinks(name2));
15795
- return ok2();
15554
+ case "sem-close":
15555
+ handles.close(req.handle);
15556
+ return ok2();
15557
+ case "sem-unlink": {
15558
+ const name2 = semName(req.name);
15559
+ table.unlink(name2, unlinks(name2));
15560
+ return ok2();
15561
+ }
15562
+ case "sem-post":
15563
+ handles.get(req.handle).post();
15564
+ return ok2();
15565
+ case "sem-getvalue":
15566
+ return ok2(handles.get(req.handle).value);
15567
+ case "sem-wait": {
15568
+ const sem = handles.get(req.handle);
15569
+ if (sem.take()) return ok2();
15570
+ if (req.how === "try") throw new KernelError("EAGAIN");
15571
+ if (req.how === "timed" && req.timeoutMs === 0) throw new KernelError("ETIMEDOUT");
15572
+ const got = await sem.wait(proc.blocking(), req.how === "block" ? -1 : req.timeoutMs);
15573
+ if (!got) throw new KernelError("ETIMEDOUT");
15574
+ return ok2();
15575
+ }
15576
+ }
15577
+ }
15578
+
15579
+ // src/kernel/socket-nodes.ts
15580
+ function filePath(addr) {
15581
+ if (addr.family !== "unix" || addr.path === "" || addr.path.startsWith("\0")) return void 0;
15582
+ return normalizePath(addr.path);
15583
+ }
15584
+ function nameOf(st) {
15585
+ return { key: `${st.dev ?? 0}:${st.ino}`, typed: st.isSocket === true };
15586
+ }
15587
+ function codeOf3(err) {
15588
+ return err?.code;
15589
+ }
15590
+ function socketNames(deps) {
15591
+ const { fs } = deps;
15592
+ return {
15593
+ async make(path) {
15594
+ const g = deps.guard();
15595
+ if (g) await inParent(g, "bind", path);
15596
+ const owner = deps.owner();
15597
+ try {
15598
+ await deps.create(path, owner);
15599
+ } catch (err) {
15600
+ if (codeOf3(err) === "EEXIST") throw new KernelError("EADDRINUSE");
15601
+ throw err;
15602
+ }
15603
+ const remove = () => fs.rm(path, { file: true }).catch(() => void 0);
15604
+ try {
15605
+ if (!deps.owners && owner.mode !== void 0) await fs.chmod(path, owner.mode);
15606
+ return { ...nameOf(await fs.lstat(path)), remove };
15607
+ } catch (err) {
15608
+ await remove();
15609
+ throw err;
15610
+ }
15611
+ },
15612
+ async find(path) {
15613
+ const g = deps.guard();
15614
+ if (g) await need(g, "connect", path, W_OK, { directory: false });
15615
+ return nameOf(await fs.stat(path));
15616
+ }
15617
+ };
15618
+ }
15619
+
15620
+ // src/kernel/dgram.ts
15621
+ var DGRAM_QUEUE_BYTES = 256 * 1024;
15622
+ var DGRAM_QUEUE_COUNT = 512;
15623
+ var DGRAM_SEND_ROOM = 256 * 1024;
15624
+ var MAX_DATAGRAM_V4 = 65507;
15625
+ var MAX_DATAGRAM_V6 = 65527;
15626
+ var SOL_SOCKET2 = 1;
15627
+ var IPPROTO_IP = 0;
15628
+ var SO_TYPE2 = 3;
15629
+ var SO_ERROR2 = 4;
15630
+ var SO_BROADCAST = 6;
15631
+ var SO_SNDBUF2 = 7;
15632
+ var SO_RCVBUF2 = 8;
15633
+ var SO_DOMAIN2 = 39;
15634
+ var SOCK_DGRAM = 2;
15635
+ var AF_INET2 = 2;
15636
+ var IP_MULTICAST_FIRST = 32;
15637
+ var IP_MULTICAST_LAST = 36;
15638
+ var SEND_ERRORS = ["ENETUNREACH", "EHOSTUNREACH", "EACCES", "EMSGSIZE"];
15639
+ var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
15640
+ function sendError(e) {
15641
+ if (e instanceof KernelError) return e;
15642
+ const code = e?.code;
15643
+ return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
15644
+ }
15645
+ function sameAddr(a, b) {
15646
+ return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
15647
+ }
15648
+ function familyOf(host) {
15649
+ return host.includes(":") ? 6 : 4;
15650
+ }
15651
+ var KernelDgram = class {
15652
+ local;
15653
+ peer;
15654
+ net;
15655
+ queue = [];
15656
+ queued = 0;
15657
+ pending;
15658
+ closed = false;
15659
+ sending = 0;
15660
+ changes = new Changes();
15661
+ options = /* @__PURE__ */ new Map();
15662
+ uplinks = /* @__PURE__ */ new Map();
15663
+ stop = new AbortController();
15664
+ constructor(net) {
15665
+ this.net = net;
15666
+ }
15667
+ bind(addr) {
15668
+ if (this.local) throw new KernelError("EINVAL");
15669
+ this.local = this.net.bindDgram(this, addr);
15670
+ }
15671
+ bound() {
15672
+ this.local ??= this.net.bindDgram(this, { family: "inet", host: "0.0.0.0", port: 0 });
15673
+ return this.local;
15674
+ }
15675
+ connectTo(addr) {
15676
+ if (addr.family !== "inet") throw new KernelError("EAFNOSUPPORT");
15677
+ this.route(addr.host);
15678
+ this.bound();
15679
+ this.peer = { family: "inet", host: canonicalHost(addr.host), port: addr.port };
15680
+ this.pending = void 0;
15681
+ this.drain((d) => sameAddr(d.from, addr));
15682
+ }
15683
+ drain(keep2) {
15684
+ const kept = this.queue.filter(keep2);
15685
+ this.queue.splice(0, this.queue.length, ...kept);
15686
+ this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
15687
+ }
15688
+ route(host) {
15689
+ const where = this.net.destination(host);
15690
+ if (where === "loopback" || where === "uplink") return where;
15691
+ throw new KernelError("ENETUNREACH");
15692
+ }
15693
+ takeError() {
15694
+ const pending = this.pending;
15695
+ this.pending = void 0;
15696
+ return pending;
15697
+ }
15698
+ async send(bytes, to) {
15699
+ if (this.closed) throw new KernelError("EBADF");
15700
+ const pending = this.takeError();
15701
+ if (pending) throw new KernelError(pending);
15702
+ const target = to ?? this.peer;
15703
+ if (!target) throw new KernelError("EDESTADDRREQ");
15704
+ if (target.family !== "inet") throw new KernelError("EAFNOSUPPORT");
15705
+ const max = familyOf(target.host) === 6 ? MAX_DATAGRAM_V6 : MAX_DATAGRAM_V4;
15706
+ if (bytes.length > max) throw new KernelError("EMSGSIZE");
15707
+ const where = this.route(target.host);
15708
+ const local = this.bound();
15709
+ if (where === "uplink") return this.sendUp(bytes, target);
15710
+ const from = {
15711
+ family: "inet",
15712
+ host: local.host === "0.0.0.0" ? "127.0.0.1" : local.host,
15713
+ port: local.port
15714
+ };
15715
+ const delivered = this.net.deliverDgram(target.port, { bytes: bytes.slice(), from });
15716
+ if (!delivered && this.peer && sameAddr(this.peer, target)) {
15717
+ this.pending = "ECONNREFUSED";
15718
+ this.changes.wake();
15719
+ }
15720
+ return bytes.length;
15721
+ }
15722
+ async sendUp(bytes, to) {
15723
+ const uplink = this.net.uplinkFor(to.host)?.uplink;
15724
+ if (!uplink || !carriesUdp(uplink)) throw new KernelError("ENETUNREACH");
15725
+ this.sending += bytes.length;
15726
+ try {
15727
+ const socket = await this.uplinkSocket(uplink, familyOf(to.host));
15728
+ await socket.send(bytes.slice(), to.host, to.port);
15729
+ } catch (e) {
15730
+ throw sendError(e);
15731
+ } finally {
15732
+ this.sending -= bytes.length;
15733
+ this.changes.wake();
15734
+ }
15735
+ return bytes.length;
15736
+ }
15737
+ uplinkSocket(uplink, family) {
15738
+ const known = this.uplinks.get(family);
15739
+ if (known !== void 0) return known;
15740
+ const opening2 = Promise.resolve().then(() => {
15741
+ if (!uplink.udp) throw new KernelError("ENETUNREACH");
15742
+ return uplink.udp({ family, signal: this.stop.signal });
15743
+ });
15744
+ this.uplinks.set(family, opening2);
15745
+ opening2.then(
15746
+ (socket) => {
15747
+ if (this.closed) {
15748
+ socket.close();
15749
+ return;
15750
+ }
15751
+ void this.pump(socket, family);
15752
+ },
15753
+ () => this.uplinks.delete(family)
15754
+ );
15755
+ return opening2;
15756
+ }
15757
+ async pump(socket, family) {
15758
+ const iterate = async () => {
15759
+ for await (const message3 of socket.messages) {
15760
+ if (this.closed) return;
15761
+ const from = { family: "inet", host: message3.host, port: message3.port };
15762
+ if ("bytes" in message3) this.deliver({ bytes: message3.bytes, from });
15763
+ else this.unreachable(message3.error, from);
15764
+ }
15765
+ };
15766
+ await iterate().catch(() => void 0);
15767
+ if (!this.closed) this.uplinks.delete(family);
15768
+ socket.close();
15769
+ }
15770
+ unreachable(error, from) {
15771
+ if (!this.peer || !sameAddr(this.peer, from)) return;
15772
+ this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
15773
+ this.changes.wake();
15774
+ }
15775
+ deliver(datagram2) {
15776
+ if (this.closed) return false;
15777
+ if (this.peer && !sameAddr(this.peer, datagram2.from)) return true;
15778
+ const full = this.queue.length >= DGRAM_QUEUE_COUNT || this.queued + datagram2.bytes.length > DGRAM_QUEUE_BYTES;
15779
+ if (full) return true;
15780
+ this.queue.push(datagram2);
15781
+ this.queued += datagram2.bytes.length;
15782
+ this.changes.wake();
15783
+ return true;
15784
+ }
15785
+ async receive(max, peek, signal) {
15786
+ for (; ; ) {
15787
+ const pending = this.takeError();
15788
+ if (pending) throw new KernelError(pending);
15789
+ if (this.closed) throw new KernelError("EBADF");
15790
+ const next3 = this.queue[0];
15791
+ if (next3) {
15792
+ if (!peek) {
15793
+ this.queue.shift();
15794
+ this.queued -= next3.bytes.length;
15795
+ this.changes.wake();
15796
+ }
15797
+ const size = Math.max(0, max);
15798
+ return {
15799
+ bytes: next3.bytes.slice(0, size),
15800
+ from: next3.from,
15801
+ truncated: next3.bytes.length > size
15802
+ };
15803
+ }
15804
+ await this.changes.wait(signal);
15805
+ }
15806
+ }
15807
+ async read(max, signal) {
15808
+ return (await this.receive(max, false, signal)).bytes;
15809
+ }
15810
+ async peek(max, signal) {
15811
+ return (await this.receive(max, true, signal)).bytes;
15812
+ }
15813
+ write(bytes) {
15814
+ return this.send(bytes);
15815
+ }
15816
+ poll() {
15817
+ return {
15818
+ readable: this.queue.length > 0 || this.pending !== void 0 || this.closed,
15819
+ writable: this.sending < DGRAM_SEND_ROOM,
15820
+ hangup: this.closed,
15821
+ ...this.pending !== void 0 ? { error: true } : {}
15822
+ };
15823
+ }
15824
+ changed(signal) {
15825
+ return this.changes.wait(signal);
15826
+ }
15827
+ shutdown(how) {
15828
+ if (!this.peer) throw new KernelError("ENOTCONN");
15829
+ if (how < 0 || how > 2) throw new KernelError("EINVAL");
15830
+ }
15831
+ getOption(level, name2) {
15832
+ if (level === SOL_SOCKET2) {
15833
+ switch (name2) {
15834
+ case SO_TYPE2:
15835
+ return SOCK_DGRAM;
15836
+ case SO_ERROR2: {
15837
+ const pending = this.takeError();
15838
+ return pending ? wasiErrno(pending) : 0;
15839
+ }
15840
+ case SO_DOMAIN2:
15841
+ return AF_INET2;
15842
+ case SO_BROADCAST:
15843
+ return 0;
15844
+ case SO_SNDBUF2:
15845
+ return this.options.get(`${level}:${name2}`) ?? DGRAM_SEND_ROOM;
15846
+ case SO_RCVBUF2:
15847
+ return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
15848
+ }
15796
15849
  }
15797
- case "sem-post":
15798
- handles.get(req.handle).post();
15799
- return ok2();
15800
- case "sem-getvalue":
15801
- return ok2(handles.get(req.handle).value);
15802
- case "sem-wait": {
15803
- const sem = handles.get(req.handle);
15804
- if (sem.take()) return ok2();
15805
- if (req.how === "try") throw new KernelError("EAGAIN");
15806
- if (req.how === "timed" && req.timeoutMs === 0) throw new KernelError("ETIMEDOUT");
15807
- const got = await sem.wait(proc.blocking(), req.how === "block" ? -1 : req.timeoutMs);
15808
- if (!got) throw new KernelError("ETIMEDOUT");
15809
- return ok2();
15850
+ if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
15851
+ throw new KernelError("ENOPROTOOPT");
15810
15852
  }
15853
+ return this.options.get(`${level}:${name2}`) ?? 0;
15811
15854
  }
15812
- }
15813
-
15814
- // src/kernel/socket-nodes.ts
15815
- function filePath(addr) {
15816
- if (addr.family !== "unix" || addr.path === "" || addr.path.startsWith("\0")) return void 0;
15817
- return normalizePath(addr.path);
15818
- }
15819
- function nameOf(st) {
15820
- return { key: `${st.dev ?? 0}:${st.ino}`, typed: st.isSocket === true };
15821
- }
15822
- function codeOf3(err) {
15823
- return err?.code;
15824
- }
15825
- function socketNames(deps) {
15826
- const { fs } = deps;
15827
- return {
15828
- async make(path) {
15829
- const g = deps.guard();
15830
- if (g) await inParent(g, "bind", path);
15831
- const owner = deps.owner();
15832
- try {
15833
- await deps.create(path, owner);
15834
- } catch (err) {
15835
- if (codeOf3(err) === "EEXIST") throw new KernelError("EADDRINUSE");
15836
- throw err;
15837
- }
15838
- const remove = () => fs.rm(path, { file: true }).catch(() => void 0);
15839
- try {
15840
- if (!deps.owners && owner.mode !== void 0) await fs.chmod(path, owner.mode);
15841
- return { ...nameOf(await fs.lstat(path)), remove };
15842
- } catch (err) {
15843
- await remove();
15844
- throw err;
15845
- }
15846
- },
15847
- async find(path) {
15848
- const g = deps.guard();
15849
- if (g) await need(g, "connect", path, W_OK, { directory: false });
15850
- return nameOf(await fs.stat(path));
15855
+ setOption(level, name2, value2) {
15856
+ if (level === SOL_SOCKET2 && name2 === SO_BROADCAST && value2 !== 0) {
15857
+ throw new KernelError("EOPNOTSUPP");
15851
15858
  }
15852
- };
15853
- }
15859
+ if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
15860
+ throw new KernelError("ENOPROTOOPT");
15861
+ }
15862
+ this.options.set(`${level}:${name2}`, value2);
15863
+ }
15864
+ close() {
15865
+ if (this.closed) return;
15866
+ this.closed = true;
15867
+ this.stop.abort();
15868
+ for (const opening2 of this.uplinks.values()) {
15869
+ opening2.then(
15870
+ (socket) => socket.close(),
15871
+ () => void 0
15872
+ );
15873
+ }
15874
+ this.uplinks.clear();
15875
+ if (this.local) this.net.releaseDgram(this.local, this);
15876
+ this.queue.length = 0;
15877
+ this.queued = 0;
15878
+ this.changes.wake();
15879
+ }
15880
+ };
15854
15881
 
15855
15882
  // src/kernel/net/datagram-wire.ts
15856
15883
  function encodeReceived(got) {
15857
15884
  const host = new TextEncoder().encode(got.host);
15858
15885
  const out = new Uint8Array(4 + host.length + got.bytes.length);
15859
15886
  const view2 = new DataView(out.buffer);
15860
- view2.setUint8(0, got.truncated ? 1 : 0);
15887
+ view2.setUint8(0, (got.truncated ? 1 : 0) | (got.unix ? 2 : 0));
15861
15888
  view2.setUint16(1, got.port);
15862
15889
  view2.setUint8(3, host.length);
15863
15890
  out.set(host, 4);
@@ -15865,6 +15892,152 @@ function encodeReceived(got) {
15865
15892
  return out;
15866
15893
  }
15867
15894
 
15895
+ // src/kernel/unix-dgram.ts
15896
+ var SOL_SOCKET3 = 1;
15897
+ var SO_TYPE3 = 3;
15898
+ var SO_ERROR3 = 4;
15899
+ var SO_SNDBUF3 = 7;
15900
+ var SO_RCVBUF3 = 8;
15901
+ var SO_DOMAIN3 = 39;
15902
+ var SOCK_DGRAM2 = 2;
15903
+ var AF_UNIX2 = 1;
15904
+ var UNNAMED = { family: "unix", path: "" };
15905
+ var UnixDgram = class _UnixDgram {
15906
+ local;
15907
+ peer;
15908
+ key;
15909
+ peerCred;
15910
+ target;
15911
+ net;
15912
+ queue = [];
15913
+ queued = 0;
15914
+ closed = false;
15915
+ changes = new Changes();
15916
+ options = /* @__PURE__ */ new Map();
15917
+ constructor(net) {
15918
+ this.net = net;
15919
+ }
15920
+ static pair(net, cred) {
15921
+ const a = new _UnixDgram(net);
15922
+ const b = new _UnixDgram(net);
15923
+ a.target = b;
15924
+ b.target = a;
15925
+ a.peer = b.peer = UNNAMED;
15926
+ a.peerCred = b.peerCred = cred;
15927
+ return [a, b];
15928
+ }
15929
+ bind(addr, key) {
15930
+ if (addr.family !== "unix") throw new KernelError("EINVAL");
15931
+ if (this.local) throw new KernelError("EINVAL");
15932
+ if (addr.path === "") throw new KernelError("EINVAL");
15933
+ this.net.bindUnixDgram(this, key);
15934
+ this.local = { family: "unix", path: addr.path };
15935
+ this.key = key;
15936
+ }
15937
+ connectTo(addr, target) {
15938
+ this.target = target;
15939
+ this.peer = addr;
15940
+ const kept = this.queue.filter((d) => d.sender === target);
15941
+ this.queue.splice(0, this.queue.length, ...kept);
15942
+ this.queued = kept.reduce((sum, d) => sum + d.bytes.length, 0);
15943
+ }
15944
+ destination() {
15945
+ if (!this.target) throw new KernelError("EDESTADDRREQ");
15946
+ return this.target;
15947
+ }
15948
+ room(bytes) {
15949
+ return this.closed || this.queue.length < DGRAM_QUEUE_COUNT && this.queued + bytes <= DGRAM_QUEUE_BYTES;
15950
+ }
15951
+ async send(bytes, to, nonblock, signal) {
15952
+ if (this.closed) throw new KernelError("EBADF");
15953
+ if (bytes.length > DGRAM_QUEUE_BYTES) throw new KernelError("EMSGSIZE");
15954
+ if (to.target && to.target !== this) throw new KernelError("EPERM");
15955
+ while (!to.room(bytes.length)) {
15956
+ if (nonblock) throw new KernelError("EAGAIN");
15957
+ await to.changed(signal);
15958
+ }
15959
+ if (to.closed) throw new KernelError("ECONNREFUSED");
15960
+ to.queue.push({ bytes: bytes.slice(), from: this.local ?? UNNAMED, sender: this });
15961
+ to.queued += bytes.length;
15962
+ to.changes.wake();
15963
+ return bytes.length;
15964
+ }
15965
+ async receive(max, peek, signal) {
15966
+ for (; ; ) {
15967
+ if (this.closed) throw new KernelError("EBADF");
15968
+ const next3 = this.queue[0];
15969
+ if (next3) {
15970
+ if (!peek) {
15971
+ this.queue.shift();
15972
+ this.queued -= next3.bytes.length;
15973
+ this.changes.wake();
15974
+ }
15975
+ const size = Math.max(0, max);
15976
+ return {
15977
+ bytes: next3.bytes.slice(0, size),
15978
+ from: next3.from,
15979
+ truncated: next3.bytes.length > size
15980
+ };
15981
+ }
15982
+ await this.changes.wait(signal);
15983
+ }
15984
+ }
15985
+ async read(max, signal) {
15986
+ return (await this.receive(max, false, signal)).bytes;
15987
+ }
15988
+ async peek(max, signal) {
15989
+ return (await this.receive(max, true, signal)).bytes;
15990
+ }
15991
+ write(bytes, signal) {
15992
+ return this.send(bytes, this.destination(), false, signal);
15993
+ }
15994
+ poll() {
15995
+ const target = this.target;
15996
+ return {
15997
+ readable: this.queue.length > 0 || this.closed,
15998
+ writable: !target || target.room(1),
15999
+ hangup: this.closed
16000
+ };
16001
+ }
16002
+ changed(signal) {
16003
+ return this.changes.wait(signal);
16004
+ }
16005
+ shutdown(how) {
16006
+ if (!this.peer) throw new KernelError("ENOTCONN");
16007
+ if (how < 0 || how > 2) throw new KernelError("EINVAL");
16008
+ }
16009
+ getOption(level, name2) {
16010
+ if (level === SOL_SOCKET3) {
16011
+ switch (name2) {
16012
+ case SO_TYPE3:
16013
+ return SOCK_DGRAM2;
16014
+ case SO_ERROR3:
16015
+ return 0;
16016
+ case SO_DOMAIN3:
16017
+ return AF_UNIX2;
16018
+ case SO_SNDBUF3:
16019
+ case SO_RCVBUF3:
16020
+ return this.options.get(`${level}:${name2}`) ?? DGRAM_QUEUE_BYTES;
16021
+ }
16022
+ }
16023
+ return this.options.get(`${level}:${name2}`) ?? 0;
16024
+ }
16025
+ setOption(level, name2, value2) {
16026
+ this.options.set(`${level}:${name2}`, value2);
16027
+ }
16028
+ close() {
16029
+ if (this.closed) return;
16030
+ this.closed = true;
16031
+ if (this.key !== void 0) this.net.releaseUnixDgram(this.key, this);
16032
+ this.queue.length = 0;
16033
+ this.queued = 0;
16034
+ this.changes.wake();
16035
+ }
16036
+ };
16037
+ function isDatagram(file) {
16038
+ return file instanceof KernelDgram || file instanceof UnixDgram;
16039
+ }
16040
+
15868
16041
  // src/kernel/socket-syscalls.ts
15869
16042
  var SOCKET_OPS = [
15870
16043
  "sock-open",
@@ -15883,32 +16056,37 @@ var SOCKET_OPS = [
15883
16056
  ];
15884
16057
  function socketAt(fds, fd) {
15885
16058
  const file = anySocketAt(fds, fd);
15886
- if (file instanceof KernelDgram) throw new KernelError("EOPNOTSUPP");
16059
+ if (!(file instanceof KernelSocket)) throw new KernelError("EOPNOTSUPP");
15887
16060
  return file;
15888
16061
  }
15889
16062
  function anySocketAt(fds, fd) {
15890
16063
  const file = fds.get(fd).file;
15891
- if (!(file instanceof KernelSocket) && !(file instanceof KernelDgram)) {
16064
+ if (!(file instanceof KernelSocket) && !(file instanceof KernelDgram) && !(file instanceof UnixDgram)) {
15892
16065
  throw new KernelError("ENOTSOCK");
15893
16066
  }
15894
16067
  return file;
15895
16068
  }
15896
16069
  function dgramAt(fds, fd) {
15897
16070
  const file = anySocketAt(fds, fd);
15898
- if (!(file instanceof KernelDgram)) throw new KernelError("EOPNOTSUPP");
16071
+ if (file instanceof KernelSocket) throw new KernelError("EOPNOTSUPP");
15899
16072
  return file;
15900
16073
  }
16074
+ async function unixTarget(proc, addr) {
16075
+ if (addr.family !== "unix") throw new KernelError("EAFNOSUPPORT");
16076
+ const path = filePath(addr);
16077
+ const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
16078
+ return proc.net.unixDgramAt(keyOf(path !== void 0 ? { family: "unix", path } : addr, name2));
16079
+ }
15901
16080
  var ok3 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
15902
16081
  async function socketSyscall(req, proc) {
15903
16082
  const { fds, net } = proc;
15904
16083
  switch (req.op) {
15905
16084
  case "sock-open": {
15906
- if (req.type === "dgram" && req.domain !== "inet") throw new KernelError("EPROTONOSUPPORT");
15907
- const file = req.type === "dgram" ? new KernelDgram(net) : net.socket(req.domain);
16085
+ const file = req.type !== "dgram" ? net.socket(req.domain) : req.domain === "unix" ? new UnixDgram(net) : new KernelDgram(net);
15908
16086
  return ok3(fds.install(new OpenFile(file), 3));
15909
16087
  }
15910
16088
  case "sock-pair": {
15911
- const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
16089
+ const [a, b] = req.type === "dgram" && req.domain === "unix" ? UnixDgram.pair(net, proc.cred?.()) : KernelSocket.pair(net, req.domain, proc.cred?.());
15912
16090
  const first = fds.install(new OpenFile(a), 3);
15913
16091
  try {
15914
16092
  return ok3([first, fds.install(new OpenFile(b), 3)]);
@@ -15934,7 +16112,7 @@ async function socketSyscall(req, proc) {
15934
16112
  const socket = anySocketAt(fds, req.fd);
15935
16113
  const addr = req.peer ? socket.peer : socket.local;
15936
16114
  if (req.peer && !addr) throw new KernelError("ENOTCONN");
15937
- return ok3(addr ?? unnamed(socket instanceof KernelDgram ? "inet" : socket.domain));
16115
+ return ok3(addr ?? unnamed(socket instanceof KernelSocket ? socket.domain : domainOf(socket)));
15938
16116
  }
15939
16117
  case "sock-getopt":
15940
16118
  return ok3(anySocketAt(fds, req.fd).getOption(req.level, req.name));
@@ -15956,6 +16134,10 @@ async function connect(req, proc) {
15956
16134
  target.connectTo(req.addr);
15957
16135
  return ok3();
15958
16136
  }
16137
+ if (target instanceof UnixDgram) {
16138
+ target.connectTo(req.addr, await unixTarget(proc, req.addr));
16139
+ return ok3();
16140
+ }
15959
16141
  const path = filePath(req.addr);
15960
16142
  const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
15961
16143
  const stamp = proc.net.facadeAt(req.addr) && await proc.stamp?.();
@@ -15967,8 +16149,23 @@ async function connect(req, proc) {
15967
16149
  if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
15968
16150
  return ok3();
15969
16151
  }
16152
+ async function bindUnixDgram(proc, socket, addr) {
16153
+ const path = filePath(addr);
16154
+ if (path === void 0 || !proc.names) {
16155
+ socket.bind(addr, keyOf(addr));
16156
+ return;
16157
+ }
16158
+ const name2 = await proc.names.make(path);
16159
+ try {
16160
+ socket.bind({ family: "unix", path }, keyOf({ family: "unix", path }, name2));
16161
+ } catch (err) {
16162
+ await name2.remove();
16163
+ throw err;
16164
+ }
16165
+ }
15970
16166
  async function bind(proc, fd, addr) {
15971
16167
  const socket = anySocketAt(proc.fds, fd);
16168
+ if (socket instanceof UnixDgram) return bindUnixDgram(proc, socket, addr);
15972
16169
  const path = filePath(addr);
15973
16170
  if (!(socket instanceof KernelSocket) || path === void 0 || !proc.names) {
15974
16171
  socket.bind(addr);
@@ -15985,6 +16182,7 @@ async function bind(proc, fd, addr) {
15985
16182
  }
15986
16183
  async function datagram(req, proc) {
15987
16184
  const dgram = dgramAt(proc.fds, req.fd);
16185
+ if (dgram instanceof UnixDgram) return unixDatagram(req, dgram, proc);
15988
16186
  if (req.op === "sock-sendto") {
15989
16187
  if (req.nonblock && !pollFile(dgram).writable) throw new KernelError("EAGAIN");
15990
16188
  return ok3(await dgram.send(req.body, req.addr));
@@ -15995,6 +16193,24 @@ async function datagram(req, proc) {
15995
16193
  const { bytes, from, truncated } = got;
15996
16194
  return { ok: true, kind: "bytes", bytes: encodeReceived({ bytes, truncated, ...from }) };
15997
16195
  }
16196
+ async function unixDatagram(req, dgram, proc) {
16197
+ if (req.op === "sock-sendto") {
16198
+ const to = req.addr ? await unixTarget(proc, req.addr) : dgram.destination();
16199
+ return ok3(await dgram.send(req.body, to, req.nonblock, proc.blocking()));
16200
+ }
16201
+ const ready2 = pollFile(dgram).readable;
16202
+ if (req.nonblock && !ready2) throw new KernelError("EAGAIN");
16203
+ const got = await dgram.receive(req.max, req.peek, ready2 ? void 0 : proc.blocking());
16204
+ const { bytes, from, truncated } = got;
16205
+ return {
16206
+ ok: true,
16207
+ kind: "bytes",
16208
+ bytes: encodeReceived({ bytes, truncated, host: from.path, port: 0, unix: true })
16209
+ };
16210
+ }
16211
+ function domainOf(socket) {
16212
+ return socket instanceof UnixDgram ? "unix" : "inet";
16213
+ }
15998
16214
  function interruptible2(dialing, signal) {
15999
16215
  return new Promise((resolve2, reject) => {
16000
16216
  const abort = () => reject(new KernelError("EINTR"));
@@ -17812,8 +18028,8 @@ var WasmProcess = class {
17812
18028
  const terminal = (file.tty ?? file.pty?.slave)?.name;
17813
18029
  return {
17814
18030
  tty: file.tty !== void 0,
17815
- kind: file instanceof KernelSocket || file instanceof KernelDgram ? "socket" : kernelFdKind(file),
17816
- ...file instanceof KernelDgram ? { dgram: true } : {},
18031
+ kind: file instanceof KernelSocket || isDatagram(file) ? "socket" : kernelFdKind(file),
18032
+ ...isDatagram(file) ? { dgram: true } : {},
17817
18033
  ...file.heldMeta ? { meta: file.heldMeta } : {},
17818
18034
  ...flags2 !== void 0 ? { flags: flags2 } : {},
17819
18035
  ...this.fds.closesOnExec(fd) ? { cloexec: true } : {},
@@ -18249,7 +18465,7 @@ function inheritedFds(fds) {
18249
18465
  return fds.numbers().filter((fd) => fd > 2 && !fds.get(fd).file.held).map((fd) => {
18250
18466
  const open = fds.get(fd);
18251
18467
  const flags2 = fds.statusFlags(fd);
18252
- const kind = open.file instanceof KernelSocket || open.file instanceof KernelDgram ? "socket" : kernelFdKind(open.file);
18468
+ const kind = open.file instanceof KernelSocket || isDatagram(open.file) ? "socket" : kernelFdKind(open.file);
18253
18469
  const meta = open.file.heldMeta;
18254
18470
  return {
18255
18471
  fd,
@@ -18855,6 +19071,43 @@ var JobTable = class {
18855
19071
  }
18856
19072
  };
18857
19073
 
19074
+ // src/kernel/net/hosts-file.ts
19075
+ var HOSTS_PATH = "/etc/hosts";
19076
+ function parseHosts(text) {
19077
+ const table = /* @__PURE__ */ new Map();
19078
+ for (const raw of text.split("\n")) {
19079
+ const [address, ...names] = raw.replace(/#.*/, "").trim().split(/\s+/);
19080
+ if (!address || names.length === 0) continue;
19081
+ if (ipv4Bytes(address) === void 0 && ipv6Groups(address) === void 0) continue;
19082
+ for (const name2 of names) {
19083
+ const key = name2.toLowerCase().replace(/\.$/, "");
19084
+ const known = table.get(key) ?? [];
19085
+ if (!known.includes(address)) known.push(address);
19086
+ table.set(key, known);
19087
+ }
19088
+ }
19089
+ return table;
19090
+ }
19091
+ function hostsReader(fs, path = HOSTS_PATH) {
19092
+ let stamp = "";
19093
+ let table;
19094
+ return async () => {
19095
+ const st = await fs.stat(path).catch(() => void 0);
19096
+ if (!st?.isFile) {
19097
+ stamp = "";
19098
+ table = void 0;
19099
+ return void 0;
19100
+ }
19101
+ const now = `${st.ino}:${st.size}:${st.mtime.getTime()}`;
19102
+ if (now === stamp && table) return table;
19103
+ const text = await fs.readFile(path).catch(() => void 0);
19104
+ if (text === void 0) return void 0;
19105
+ stamp = now;
19106
+ table = parseHosts(text);
19107
+ return table;
19108
+ };
19109
+ }
19110
+
18858
19111
  // src/kernel/net/redirect-hops.ts
18859
19112
  var HELD_MS = 3e4;
18860
19113
  var HELD_MAX = 64;
@@ -22295,7 +22548,12 @@ var Launcher = class {
22295
22548
  this.uplink = options.uplink;
22296
22549
  this.routes = new Routes(options.uplink?.traits.ipv6 === true);
22297
22550
  if (options.uplink?.routes) this.routes.set(options.uplink.routes);
22298
- this.resolver = new Resolver({ uplink: options.uplink, routes: this.routes, hostname });
22551
+ this.resolver = new Resolver({
22552
+ uplink: options.uplink,
22553
+ routes: this.routes,
22554
+ hostname,
22555
+ hosts: hostsReader(this.base)
22556
+ });
22299
22557
  if (options.uplink) this.net.useUplink({ uplink: options.uplink, routes: this.routes });
22300
22558
  enableNetwork(this.net, {
22301
22559
  transport: this.transport,