@ai-ecoverse/slicc-kernel 1.2.0 → 1.3.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.
@@ -56,6 +56,15 @@ var SIGNAL_BY_NAME = {
56
56
  };
57
57
 
58
58
  // src/fs/types.ts
59
+ function normalizePath(path) {
60
+ const parts = [];
61
+ for (const part of path.split("/")) {
62
+ if (part === "" || part === ".") continue;
63
+ if (part === "..") parts.pop();
64
+ else parts.push(part);
65
+ }
66
+ return `/${parts.join("/")}`;
67
+ }
59
68
  function inodeOf(path) {
60
69
  let h1 = 3735928559;
61
70
  let h2 = 1103547991;
@@ -104,8 +113,8 @@ function toErrno(Fs, err) {
104
113
  return err;
105
114
  }
106
115
  const code = err?.code;
107
- const errno = typeof code === "string" ? ERRNO_BY_CODE[code] ?? EIO : EIO;
108
- return new Fs.ErrnoError(errno);
116
+ const errno2 = typeof code === "string" ? ERRNO_BY_CODE[code] ?? EIO : EIO;
117
+ return new Fs.ErrnoError(errno2);
109
118
  }
110
119
  function liveNodePath(node) {
111
120
  const parts = [];
@@ -495,8 +504,8 @@ function outermostDirs(dirs) {
495
504
  }
496
505
  function describeMountError(err) {
497
506
  if (err instanceof Error) return err.message;
498
- const errno = err?.errno;
499
- return typeof errno === "number" ? `errno ${errno}` : String(err);
507
+ const errno2 = err?.errno;
508
+ return typeof errno2 === "number" ? `errno ${errno2}` : String(err);
500
509
  }
501
510
  function mountLiveVfsDirs(Fs, bridge, dirs, warn) {
502
511
  if (typeof Fs.filesystems !== "object" || !Fs.filesystems) {
@@ -620,8 +629,8 @@ function decodeSabResult(status2, payload) {
620
629
  case SAB_STATUS_ERRNO: {
621
630
  try {
622
631
  const parsed = JSON.parse(decoder.decode(payload));
623
- const errno = typeof parsed.errno === "string" && /^E[A-Z]+$/.test(parsed.errno) ? parsed.errno : "EIO";
624
- return { ok: false, errno, message: String(parsed.message ?? errno) };
632
+ const errno2 = typeof parsed.errno === "string" && /^E[A-Z]+$/.test(parsed.errno) ? parsed.errno : "EIO";
633
+ return { ok: false, errno: errno2, message: String(parsed.message ?? errno2) };
625
634
  } catch {
626
635
  return { ok: false, errno: "EIO", message: "sync-sab: malformed errno payload" };
627
636
  }
@@ -797,6 +806,7 @@ var WASI_ERRNO = {
797
806
  EAFNOSUPPORT: 5,
798
807
  EAGAIN: 6,
799
808
  ECONNREFUSED: 14,
809
+ EEXIST: 20,
800
810
  EINPROGRESS: 26,
801
811
  EISCONN: 30,
802
812
  ENETUNREACH: 40,
@@ -834,6 +844,7 @@ var POLLHUP = 16;
834
844
  var POLLRDNORM = 64;
835
845
  var POLLWRNORM = 256;
836
846
  var O_NONBLOCK = 2048;
847
+ var SOCKET_MODE = 49663;
837
848
  var PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
838
849
  function isPtyPath(path) {
839
850
  return PTY_PATH.test(path);
@@ -881,6 +892,8 @@ function nonblocking(stream) {
881
892
  }
882
893
  var KernelStreams = class {
883
894
  refs = /* @__PURE__ */ new Map();
895
+ socketRoot;
896
+ sockets = 0;
884
897
  Fs;
885
898
  sys;
886
899
  options;
@@ -896,6 +909,27 @@ var KernelStreams = class {
896
909
  if (terminal ?? this.sys.isatty?.(kfd) ?? false) stream.tty = this.ttyOps(kfd);
897
910
  else delete stream.tty;
898
911
  }
912
+ attachSocket(stream, kfd) {
913
+ this.attach(stream, kfd, false);
914
+ stream.sliccKernelSocket = true;
915
+ }
916
+ socketStream(flags) {
917
+ const fs = this.Fs;
918
+ if (!fs.mount || !fs.createNode || !fs.createStream) {
919
+ const stream = this.Fs.open("/dev/null", 2);
920
+ stream.flags = flags;
921
+ return stream;
922
+ }
923
+ const createNode = fs.createNode;
924
+ this.socketRoot ??= fs.mount({ mount: () => createNode(null, "/", 16895, 0) }, {}, null);
925
+ const ino = ++this.sockets;
926
+ const node = fs.createNode(this.socketRoot, `socket:${ino}`, SOCKET_MODE, 0);
927
+ const now = /* @__PURE__ */ new Date();
928
+ const stat = { dev: 0, ino, mode: SOCKET_MODE, nlink: 1, uid: 0, gid: 0, rdev: 0, size: 0 };
929
+ const times = { atime: now, mtime: now, ctime: now, blksize: 4096, blocks: 0 };
930
+ node.node_ops = { getattr: () => ({ ...stat, ...times }) };
931
+ return fs.createStream({ node, flags, seekable: false, position: 0, stream_ops: {} });
932
+ }
899
933
  nameTerminal(stream) {
900
934
  const kfd = stream.sliccKernelFd;
901
935
  if (!stream.tty || kfd === void 0) return;
@@ -1660,6 +1694,9 @@ function describeForFork(Fs, sys, streams, livePath) {
1660
1694
  }
1661
1695
  function kernelEntry(stream, kernel) {
1662
1696
  const cloexec = closesOnExec(stream) ? { cloexec: true } : {};
1697
+ if (stream.sliccKernelSocket) {
1698
+ return { fd: stream.fd, kernel, kind: "socket", flags: stream.flags, ...cloexec };
1699
+ }
1663
1700
  const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : "stream";
1664
1701
  return { fd: stream.fd, kernel, kind, ...cloexec };
1665
1702
  }
@@ -1701,7 +1738,8 @@ function inheritedSlot(fd, stream) {
1701
1738
  const access = ACCESS[stream.flags & O_ACCMODE];
1702
1739
  return { fd, device, ...access ? { access } : {} };
1703
1740
  }
1704
- return { fd, kernel: stream.sliccKernelFd };
1741
+ const flags = stream.sliccKernelSocket ? { flags: stream.flags } : {};
1742
+ return { fd, kernel: stream.sliccKernelFd, ...flags };
1705
1743
  }
1706
1744
  function place(Fs, stream, fd) {
1707
1745
  if (stream.fd === fd) return stream;
@@ -1709,7 +1747,8 @@ function place(Fs, stream, fd) {
1709
1747
  Fs.closeStream(stream.fd);
1710
1748
  return moved;
1711
1749
  }
1712
- function placeholder(Fs, entry) {
1750
+ function placeholder(Fs, streams, entry) {
1751
+ if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR);
1713
1752
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
1714
1753
  if (entry.kind === "stream") return Fs.open("/dev/null", O_RDWR);
1715
1754
  Fs.mkdirTree(PLACEHOLDER_DIR);
@@ -1730,8 +1769,9 @@ function asFifo(stream, streams, identity) {
1730
1769
  };
1731
1770
  }
1732
1771
  function placeKernelStream(Fs, streams, entry) {
1733
- const stream = place(Fs, placeholder(Fs, entry), entry.fd);
1772
+ const stream = place(Fs, placeholder(Fs, streams, entry), entry.fd);
1734
1773
  if (entry.kind === "file") streams.attachFile(stream, entry.kernel);
1774
+ else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
1735
1775
  else streams.attach(stream, entry.kernel, entry.kind === "tty");
1736
1776
  if (entry.kind === "tty") streams.nameTerminal(stream);
1737
1777
  if (entry.kind === "stream") {
@@ -1759,6 +1799,40 @@ function restoreForkedStreams(Fs, streams, table) {
1759
1799
  }
1760
1800
  }
1761
1801
 
1802
+ // src/process/process-http.ts
1803
+ var HttpError = class extends Error {
1804
+ code;
1805
+ constructor(code, message) {
1806
+ super(message);
1807
+ this.code = code;
1808
+ }
1809
+ };
1810
+ function createHttpKernel(transport) {
1811
+ const call = (req) => {
1812
+ const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
1813
+ if (!r.ok) throw new HttpError(r.errno, r.message);
1814
+ return r;
1815
+ };
1816
+ return {
1817
+ request(req) {
1818
+ const r = call({
1819
+ op: "net-request",
1820
+ url: req.url,
1821
+ method: (req.method ?? "GET").toUpperCase(),
1822
+ headers: req.headers ?? [],
1823
+ ...req.body ? { body: req.body } : {}
1824
+ });
1825
+ return r.json;
1826
+ },
1827
+ read(handle, max) {
1828
+ return call({ op: "net-read", handle, max }).bytes;
1829
+ },
1830
+ close(handle) {
1831
+ call({ op: "net-close", handle });
1832
+ }
1833
+ };
1834
+ }
1835
+
1762
1836
  // src/process/process-signals.ts
1763
1837
  var SignalGate = class {
1764
1838
  reported = { caught: 0, ignored: 0 };
@@ -1821,6 +1895,160 @@ var SignalGate = class {
1821
1895
  }
1822
1896
  };
1823
1897
 
1898
+ // src/process/process-sockets.ts
1899
+ var O_RDWR2 = 2;
1900
+ var KILLED_BY_SIGPIPE2 = 128 + 13;
1901
+ function errno(e) {
1902
+ if (e instanceof SyscallError) return -wasiErrno(e.code);
1903
+ const code = e?.errno;
1904
+ if (typeof code === "number") return -code;
1905
+ throw e;
1906
+ }
1907
+ var O_WRONLY = 1;
1908
+ var O_CREAT3 = 64;
1909
+ var O_EXCL3 = 128;
1910
+ function resolved(Fs, addr) {
1911
+ if (addr.family !== "unix" || !addr.path || addr.path.startsWith("\0")) return addr;
1912
+ const path = addr.path.startsWith("/") ? addr.path : `${Fs.cwd()}/${addr.path}`;
1913
+ return { family: "unix", path: normalizePath(path) };
1914
+ }
1915
+ function socketNode(Fs, addr) {
1916
+ if (addr.family !== "unix" || !addr.path || addr.path.startsWith("\0")) return void 0;
1917
+ const fs = Fs;
1918
+ let stream;
1919
+ try {
1920
+ stream = Fs.open(addr.path, O_WRONLY | O_CREAT3 | O_EXCL3, 493);
1921
+ } catch (e) {
1922
+ if (e?.errno === wasiErrno("EEXIST")) {
1923
+ throw new SyscallError("EADDRINUSE");
1924
+ }
1925
+ throw e;
1926
+ }
1927
+ if (Fs.close) Fs.close(stream);
1928
+ else Fs.closeStream(stream.fd);
1929
+ return { remove: () => fs.unlink?.(addr.path) };
1930
+ }
1931
+ function createSocketKernel(deps) {
1932
+ const { transport, Fs, sys, streams } = deps;
1933
+ const call = (req) => {
1934
+ const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
1935
+ if (!r.ok) throw new SyscallError(r.errno);
1936
+ return r;
1937
+ };
1938
+ const json = (req) => {
1939
+ const r = call(req);
1940
+ return r.ok && r.kind === "json" ? r.json : void 0;
1941
+ };
1942
+ const done = (req) => {
1943
+ call(req);
1944
+ return 0;
1945
+ };
1946
+ const guard = (op) => {
1947
+ for (; ; ) {
1948
+ try {
1949
+ return op();
1950
+ } catch (e) {
1951
+ const restart = e instanceof SyscallError && e.code === "EINTR" && deps.restartable?.();
1952
+ if (!restart) return errno(e);
1953
+ }
1954
+ }
1955
+ };
1956
+ const socketAt = (fd) => {
1957
+ const stream = Fs.getStream(fd);
1958
+ if (!stream) throw new SyscallError("EBADF");
1959
+ if (!stream.sliccKernelSocket || stream.sliccKernelFd === void 0) {
1960
+ throw new SyscallError("ENOTSOCK");
1961
+ }
1962
+ return stream;
1963
+ };
1964
+ const kfd = (fd) => socketAt(fd).sliccKernelFd;
1965
+ const install = (k, nonblock, cloexec = false) => {
1966
+ let stream;
1967
+ try {
1968
+ stream = streams.socketStream(O_RDWR2 | (nonblock ? O_NONBLOCK : 0));
1969
+ } catch (e) {
1970
+ sys.close(k);
1971
+ throw e;
1972
+ }
1973
+ streams.attachSocket(stream, k);
1974
+ setCloseOnExec(stream, cloexec);
1975
+ return stream.fd;
1976
+ };
1977
+ return {
1978
+ socket: (domain, nonblock, cloexec) => guard(() => install(json({ op: "sock-open", domain }), nonblock, cloexec)),
1979
+ socketpair: (domain, nonblock, cloexec) => guard(() => {
1980
+ const [a, b] = json({ op: "sock-pair", domain });
1981
+ let first;
1982
+ try {
1983
+ first = install(a, nonblock, cloexec);
1984
+ } catch (e) {
1985
+ sys.close(b);
1986
+ throw e;
1987
+ }
1988
+ try {
1989
+ return [first, install(b, nonblock, cloexec)];
1990
+ } catch (e) {
1991
+ const stream = Fs.getStream(first);
1992
+ if (stream) stream.stream_ops.close?.(stream);
1993
+ Fs.closeStream(first);
1994
+ throw e;
1995
+ }
1996
+ }),
1997
+ bind: (fd, given) => guard(() => {
1998
+ const addr = resolved(Fs, given);
1999
+ const node = socketNode(Fs, addr);
2000
+ try {
2001
+ return done({ op: "sock-bind", fd: kfd(fd), addr });
2002
+ } catch (e) {
2003
+ node?.remove();
2004
+ throw e;
2005
+ }
2006
+ }),
2007
+ listen: (fd, backlog) => guard(() => done({ op: "sock-listen", fd: kfd(fd), backlog })),
2008
+ accept: (fd, nonblock, cloexec) => guard(() => {
2009
+ const listener = socketAt(fd);
2010
+ const req = {
2011
+ op: "sock-accept",
2012
+ fd: listener.sliccKernelFd,
2013
+ nonblock: (listener.flags & O_NONBLOCK) !== 0
2014
+ };
2015
+ const got = json(req);
2016
+ return { fd: install(got.fd, nonblock, cloexec), peer: got.peer };
2017
+ }),
2018
+ connect: (fd, addr) => guard(() => {
2019
+ const stream = socketAt(fd);
2020
+ const nonblock = (stream.flags & O_NONBLOCK) !== 0;
2021
+ return done({
2022
+ op: "sock-connect",
2023
+ fd: stream.sliccKernelFd,
2024
+ addr: resolved(Fs, addr),
2025
+ nonblock
2026
+ });
2027
+ }),
2028
+ shutdown: (fd, how) => guard(() => done({ op: "sock-shutdown", fd: kfd(fd), how })),
2029
+ name: (fd, peer) => guard(() => json({ op: "sock-name", fd: kfd(fd), peer })),
2030
+ getopt: (fd, level, name) => guard(() => ({ value: json({ op: "sock-getopt", fd: kfd(fd), level, name }) })),
2031
+ setopt: (fd, level, name, value) => guard(() => done({ op: "sock-setopt", fd: kfd(fd), level, name, value })),
2032
+ send: (fd, bytes, flags) => guard(() => {
2033
+ const stream = socketAt(fd);
2034
+ const nonblock = flags.dontwait === true || (stream.flags & O_NONBLOCK) !== 0;
2035
+ try {
2036
+ return sys.write(stream.sliccKernelFd, bytes, { nonblock });
2037
+ } catch (e) {
2038
+ const broken = e instanceof SyscallError && e.code === "EPIPE";
2039
+ if (broken && !flags.nosignal && !deps.sigpipe?.())
2040
+ throw new ProcessExit(KILLED_BY_SIGPIPE2);
2041
+ throw e;
2042
+ }
2043
+ }),
2044
+ recv: (fd, max, flags) => guard(() => {
2045
+ const stream = socketAt(fd);
2046
+ const nonblock = flags.dontwait === true || (stream.flags & O_NONBLOCK) !== 0;
2047
+ return sys.read(stream.sliccKernelFd, max, { nonblock, peek: flags.peek === true });
2048
+ })
2049
+ };
2050
+ }
2051
+
1824
2052
  // src/process/realm-user.ts
1825
2053
  var REALM_UID = 1e3;
1826
2054
  var REALM_GID = 1e3;
@@ -1950,10 +2178,10 @@ function wireKernelFd(Fs, streams, entry) {
1950
2178
  });
1951
2179
  }
1952
2180
  var O_RDONLY = 0;
1953
- var O_WRONLY = 1;
1954
- var O_RDWR2 = 2;
2181
+ var O_WRONLY2 = 1;
2182
+ var O_RDWR3 = 2;
1955
2183
  function openDevice(Fs, fd, meta) {
1956
- const flags = meta.access === "read" ? O_RDONLY : meta.access === "write" ? O_WRONLY : O_RDWR2;
2184
+ const flags = meta.access === "read" ? O_RDONLY : meta.access === "write" ? O_WRONLY2 : O_RDWR3;
1957
2185
  let stream;
1958
2186
  try {
1959
2187
  stream = Fs.open(`/dev/${meta.device}`, flags);
@@ -2147,6 +2375,15 @@ async function runWasmProcess(init, port, deps = {}) {
2147
2375
  inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
2148
2376
  stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath)
2149
2377
  });
2378
+ running.sliccKernel.http = createHttpKernel(transport);
2379
+ running.sliccKernel.net = createSocketKernel({
2380
+ transport,
2381
+ Fs: running.FS,
2382
+ sys,
2383
+ streams,
2384
+ sigpipe,
2385
+ restartable
2386
+ });
2150
2387
  try {
2151
2388
  return runMain(running, init);
2152
2389
  } finally {