@ai-ecoverse/slicc-kernel 1.90.0 → 1.91.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.
@@ -2305,34 +2305,40 @@ function readyEvents(subs, ready) {
2305
2305
  hangup: ready.hangup?.includes(s.fd) === true
2306
2306
  }));
2307
2307
  }
2308
+ function selectOnce(deps, read2, write2, timeoutMs) {
2309
+ try {
2310
+ const ready = deps.kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
2311
+ return { ready, interrupted: false };
2312
+ } catch (e) {
2313
+ if (!deps.interruptWakes || e.code !== "EINTR") throw e;
2314
+ return { ready: { read: [], write: [] }, interrupted: true };
2315
+ }
2316
+ }
2317
+ function waitEvents(deps, subs, { events, read: read2, write: write2 }, entered) {
2318
+ const earliest = subs.reduce((min, s) => Math.min(min, s.deadline), Infinity);
2319
+ const timeout = () => {
2320
+ if (events.length > 0 || entered) return 0;
2321
+ return earliest === Infinity ? -1 : Math.max(0, Math.ceil(earliest - performance.now()));
2322
+ };
2323
+ for (; ; ) {
2324
+ const { ready, interrupted } = selectOnce(deps, read2, write2, timeout());
2325
+ events.push(...readyEvents(subs, ready));
2326
+ if (interrupted) return true;
2327
+ if (events.length > 0 || entered || earliest === Infinity) return false;
2328
+ if (performance.now() >= earliest) return false;
2329
+ }
2330
+ }
2308
2331
  function pollOneoff(deps, inPtr, outPtr, nsubs, neventsPtr) {
2309
2332
  if (nsubs === 0) return E.INVAL;
2310
- const { mem, kernel } = deps;
2333
+ const { mem } = deps;
2311
2334
  const subs = readSubscriptions(mem, inPtr, nsubs, deps.now);
2312
- const { events, read: read2, write: write2 } = classify(deps.fds, subs);
2313
- let interrupted = false;
2314
- const earliest = subs.reduce((min, s) => Math.min(min, s.deadline), Infinity);
2315
- const expired = () => performance.now() >= earliest;
2316
- if (read2.length > 0 || write2.length > 0 || events.length === 0) {
2317
- do {
2318
- let timeoutMs = -1;
2319
- if (events.length > 0) timeoutMs = 0;
2320
- else if (earliest !== Infinity)
2321
- timeoutMs = Math.max(0, Math.ceil(earliest - performance.now()));
2322
- let ready;
2323
- try {
2324
- ready = kernel.call({ op: "fd-select", read: read2, write: write2, timeoutMs });
2325
- } catch (e) {
2326
- if (!deps.interruptWakes || e.code !== "EINTR") throw e;
2327
- interrupted = true;
2328
- ready = { read: [], write: [] };
2329
- }
2330
- events.push(
2331
- ...readyEvents(subs, ready)
2332
- );
2333
- } while (events.length === 0 && !interrupted && earliest !== Infinity && !expired());
2334
- }
2335
+ const found = classify(deps.fds, subs);
2336
+ const { events, read: read2, write: write2 } = found;
2337
+ const entered = deps.entered === true && deps.interruptWakes !== true;
2338
+ const waits = read2.length > 0 || write2.length > 0 || events.length === 0;
2339
+ const interrupted = waits && waitEvents(deps, subs, found, entered);
2335
2340
  const after = performance.now();
2341
+ if (entered && events.length === 0 && !subs.some((s) => s.deadline <= after)) return E.INTR;
2336
2342
  for (const s of subs) {
2337
2343
  if (s.type === EVENTTYPE.CLOCK && (interrupted || s.deadline <= after)) {
2338
2344
  events.push({ userdata: s.userdata, error: E.SUCCESS, type: s.type });
@@ -2538,6 +2544,7 @@ var init_wasi_host = __esm({
2538
2544
  cache;
2539
2545
  startCwd;
2540
2546
  interruptWakes = false;
2547
+ entered = false;
2541
2548
  onRaise;
2542
2549
  muted;
2543
2550
  signals;
@@ -2761,7 +2768,8 @@ var init_wasi_host = __esm({
2761
2768
  fds: this.fds,
2762
2769
  kernel: this.o.kernel,
2763
2770
  now: (id) => this.now(id),
2764
- interruptWakes: this.interruptWakes
2771
+ interruptWakes: this.interruptWakes,
2772
+ entered: this.entered
2765
2773
  },
2766
2774
  inPtr,
2767
2775
  outPtr,
@@ -2778,7 +2786,7 @@ var init_wasi_host = __esm({
2778
2786
  this.mem.view().setUint32(nevents, 0, true);
2779
2787
  if (mask.deliverUnblocked()) return E.INTR;
2780
2788
  if (n > 0) return this.poll(inPtr, outPtr, n, nevents);
2781
- return this.suspend();
2789
+ return this.entered ? E.INTR : this.suspend();
2782
2790
  } finally {
2783
2791
  mask.deliverUnblocked();
2784
2792
  mask.restore(old);
@@ -3876,7 +3884,7 @@ var KERNEL_VERSION, OS_RELEASE;
3876
3884
  var init_version = __esm({
3877
3885
  "src/version.ts"() {
3878
3886
  "use strict";
3879
- KERNEL_VERSION = true ? "1.90.0" : "0.0.0-dev";
3887
+ KERNEL_VERSION = true ? "1.91.0" : "0.0.0-dev";
3880
3888
  OS_RELEASE = "6.0.0-slicc";
3881
3889
  }
3882
3890
  });
@@ -4812,6 +4820,52 @@ var init_js_exit = __esm({
4812
4820
  }
4813
4821
  });
4814
4822
 
4823
+ // src/kernel/net/loopback-names.ts
4824
+ function isKernelLoopbackHost(hostname) {
4825
+ const host = hostname.replace(/^\[(.*)\]$/, "$1").replace(/\.$/, "").toLowerCase();
4826
+ return host === "localhost" || host.endsWith(".localhost") || host === "0.0.0.0" || LOOPBACK_V4.test(host) || LOOPBACK_V6.has(host) || MAPPED_V4.test(host);
4827
+ }
4828
+ function reserved(name2) {
4829
+ const lower = name2.toLowerCase();
4830
+ return lower === "localhost" || lower.endsWith(".localhost") || lower === HOST_LOOPBACK || lower === "wasmer.sh" || /^\d+(\.\d+){3}$/.test(lower);
4831
+ }
4832
+ function isHostname(name2) {
4833
+ if (typeof name2 !== "string" || name2.length > 253 || reserved(name2)) return false;
4834
+ return name2.split(".").every((l) => LABEL.test(l));
4835
+ }
4836
+ function hostnameOf(env) {
4837
+ return isHostname(env.HOSTNAME) ? env.HOSTNAME : DEFAULT_HOSTNAME;
4838
+ }
4839
+ function ownNames(hostname) {
4840
+ return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
4841
+ }
4842
+ function hostsFile(hostname = DEFAULT_HOSTNAME) {
4843
+ return [
4844
+ "127.0.0.1 localhost localhost.localdomain",
4845
+ "::1 localhost ip6-localhost",
4846
+ `${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
4847
+ `${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
4848
+ ""
4849
+ ].join("\n");
4850
+ }
4851
+ var HOST_LOOPBACK, HOST_LOOPBACK_ADDRESS, PAGE_LOOPBACK, PAGE_LOOPBACK_URL, LOOPBACK_V4, LOOPBACK_V6, MAPPED_V4, DEFAULT_HOSTNAME, HOSTNAME_ADDRESS, LIBC_HOSTNAMES, LABEL;
4852
+ var init_loopback_names = __esm({
4853
+ "src/kernel/net/loopback-names.ts"() {
4854
+ "use strict";
4855
+ HOST_LOOPBACK = "host.slicc.internal";
4856
+ HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
4857
+ PAGE_LOOPBACK = "kernel.localhost";
4858
+ PAGE_LOOPBACK_URL = `http://{port}.${PAGE_LOOPBACK}`;
4859
+ LOOPBACK_V4 = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
4860
+ LOOPBACK_V6 = /* @__PURE__ */ new Set(["::1", "::", "0:0:0:0:0:0:0:1"]);
4861
+ MAPPED_V4 = /^::ffff:7f[0-9a-f]{2}:[0-9a-f]{1,4}$/;
4862
+ DEFAULT_HOSTNAME = "slicc";
4863
+ HOSTNAME_ADDRESS = "127.0.1.1";
4864
+ LIBC_HOSTNAMES = ["emscripten", "wasmer.sh"];
4865
+ LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
4866
+ }
4867
+ });
4868
+
4815
4869
  // src/process/js/js-fetch.ts
4816
4870
  function withoutFragment(url) {
4817
4871
  url.hash = "";
@@ -4826,11 +4880,20 @@ function plain(status2, text) {
4826
4880
  headers: { "content-type": "text/plain; charset=utf-8" }
4827
4881
  });
4828
4882
  }
4883
+ function local2(url) {
4884
+ return isKernelLoopbackHost(new URL(url).hostname);
4885
+ }
4829
4886
  function rewrite(hop, status2, location) {
4830
4887
  const next2 = new URL(location, hop.url);
4831
4888
  if (next2.protocol !== "http:" && next2.protocol !== "https:") {
4832
4889
  throw failed(new JsCallError("EPROTONOSUPPORT", next2.protocol));
4833
4890
  }
4891
+ if (local2(next2.href) && !local2(hop.url)) {
4892
+ const from = new URL(hop.url).origin;
4893
+ throw failed(
4894
+ new JsCallError("EACCES", `a redirect from ${from} into the kernel's loopback: ${next2.href}`)
4895
+ );
4896
+ }
4834
4897
  const toGet = (status2 === 301 || status2 === 302) && hop.method === "POST" || status2 === 303 && hop.method !== "GET" && hop.method !== "HEAD";
4835
4898
  const crossOrigin = next2.origin !== new URL(hop.url).origin;
4836
4899
  const headers = hop.headers.filter(
@@ -4999,13 +5062,15 @@ async function bodyOf(request, cap, signal) {
4999
5062
  return out;
5000
5063
  }
5001
5064
  function fetchOp(kernel) {
5002
- let traits;
5003
- const traitsOf = () => {
5004
- traits ??= kernel.json({ op: "net-traits" });
5005
- traits.catch(() => {
5006
- traits = void 0;
5065
+ const traits = /* @__PURE__ */ new Map();
5066
+ const traitsOf = (url) => {
5067
+ const own = local2(url);
5068
+ const known = traits.get(own) ?? kernel.json({ op: "net-traits", url });
5069
+ traits.set(own, known);
5070
+ known.catch(() => {
5071
+ traits.delete(own);
5007
5072
  });
5008
- return traits;
5073
+ return known;
5009
5074
  };
5010
5075
  const close = (handle) => kernel.raw({ op: "net-close", handle });
5011
5076
  const send = async (hop, signal) => {
@@ -5092,6 +5157,13 @@ function fetchOp(kernel) {
5092
5157
  });
5093
5158
  return withMeta(response, head.url, redirected);
5094
5159
  };
5160
+ const traitsAt = (at) => traitsOf(at).catch((err) => {
5161
+ throw failed(err);
5162
+ });
5163
+ const redirect = async (hop, status2, location, known) => {
5164
+ const next2 = rewrite(hop, status2, location);
5165
+ return [next2, local2(next2.url) === local2(hop.url) ? known : await traitsAt(next2.url)];
5166
+ };
5095
5167
  return async (input, init) => {
5096
5168
  const request = new Request(input, init);
5097
5169
  const { signal } = request;
@@ -5101,9 +5173,7 @@ function fetchOp(kernel) {
5101
5173
  if (protocol !== "http:" && protocol !== "https:") {
5102
5174
  throw failed(new JsCallError("EPROTONOSUPPORT", protocol));
5103
5175
  }
5104
- const known = await traitsOf().catch((err) => {
5105
- throw failed(err);
5106
- });
5176
+ let known = await traitsAt(request.url);
5107
5177
  if (!known.manualRedirects && request.redirect !== "follow") {
5108
5178
  throw failed(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
5109
5179
  }
@@ -5129,7 +5199,7 @@ function fetchOp(kernel) {
5129
5199
  await close(head.handle);
5130
5200
  if (request.redirect === "error") throw failed(new JsCallError("EREDIRECT", hop.url));
5131
5201
  if (hops >= MAX_REDIRECTS) throw failed(new JsCallError("ELOOP", hop.url));
5132
- hop = rewrite(hop, head.status, location);
5202
+ [hop, known] = await redirect(hop, head.status, location, known);
5133
5203
  }
5134
5204
  };
5135
5205
  }
@@ -5137,6 +5207,7 @@ var CHUNK2, MAX_REDIRECTS, NULL_BODY, REDIRECTS, BODY_HEADERS, DECODED, CREDENTI
5137
5207
  var init_js_fetch = __esm({
5138
5208
  "src/process/js/js-fetch.ts"() {
5139
5209
  "use strict";
5210
+ init_loopback_names();
5140
5211
  init_js_kernel();
5141
5212
  CHUNK2 = 64 * 1024;
5142
5213
  MAX_REDIRECTS = 20;
@@ -5176,7 +5247,7 @@ function port(n) {
5176
5247
  function netOps(kernel, io) {
5177
5248
  const name2 = async (fd, peer) => addressOf(await kernel.json({ op: "sock-name", fd, peer }));
5178
5249
  const connection = async (fd) => {
5179
- const [local2, remote] = [await name2(fd, false), await name2(fd, true)];
5250
+ const [local3, remote] = [await name2(fd, false), await name2(fd, true)];
5180
5251
  const stop = new AbortController();
5181
5252
  let closed;
5182
5253
  const close = () => {
@@ -5201,7 +5272,7 @@ function netOps(kernel, io) {
5201
5272
  close: async () => void await shut(SHUT_WR),
5202
5273
  abort: () => close()
5203
5274
  });
5204
- return { fd, local: local2, remote, readable: readable3, writable: writable2, close };
5275
+ return { fd, local: local3, remote, readable: readable3, writable: writable2, close };
5205
5276
  };
5206
5277
  const resolve = async (host, signal) => {
5207
5278
  if (IPV4.test(host)) return host;
@@ -5301,45 +5372,6 @@ var init_js_net = __esm({
5301
5372
  }
5302
5373
  });
5303
5374
 
5304
- // src/kernel/net/loopback-names.ts
5305
- function reserved(name2) {
5306
- const lower = name2.toLowerCase();
5307
- return lower === "localhost" || lower.endsWith(".localhost") || lower === HOST_LOOPBACK || lower === "wasmer.sh" || /^\d+(\.\d+){3}$/.test(lower);
5308
- }
5309
- function isHostname(name2) {
5310
- if (typeof name2 !== "string" || name2.length > 253 || reserved(name2)) return false;
5311
- return name2.split(".").every((l) => LABEL.test(l));
5312
- }
5313
- function hostnameOf(env) {
5314
- return isHostname(env.HOSTNAME) ? env.HOSTNAME : DEFAULT_HOSTNAME;
5315
- }
5316
- function ownNames(hostname) {
5317
- return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
5318
- }
5319
- function hostsFile(hostname = DEFAULT_HOSTNAME) {
5320
- return [
5321
- "127.0.0.1 localhost localhost.localdomain",
5322
- "::1 localhost ip6-localhost",
5323
- `${HOSTNAME_ADDRESS} ${ownNames(hostname).join(" ")}`,
5324
- `${HOST_LOOPBACK_ADDRESS.join(".")} ${HOST_LOOPBACK}`,
5325
- ""
5326
- ].join("\n");
5327
- }
5328
- var HOST_LOOPBACK, HOST_LOOPBACK_ADDRESS, PAGE_LOOPBACK, PAGE_LOOPBACK_URL, DEFAULT_HOSTNAME, HOSTNAME_ADDRESS, LIBC_HOSTNAMES, LABEL;
5329
- var init_loopback_names = __esm({
5330
- "src/kernel/net/loopback-names.ts"() {
5331
- "use strict";
5332
- HOST_LOOPBACK = "host.slicc.internal";
5333
- HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
5334
- PAGE_LOOPBACK = "kernel.localhost";
5335
- PAGE_LOOPBACK_URL = `http://{port}.${PAGE_LOOPBACK}`;
5336
- DEFAULT_HOSTNAME = "slicc";
5337
- HOSTNAME_ADDRESS = "127.0.1.1";
5338
- LIBC_HOSTNAMES = ["emscripten", "wasmer.sh"];
5339
- LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i;
5340
- }
5341
- });
5342
-
5343
5375
  // src/process/wasi-errno.ts
5344
5376
  function wasiErrno(code2) {
5345
5377
  return WASI_ERRNO[code2] ?? E.IO;
@@ -10292,12 +10324,12 @@ function anySelect(Fs, transport, read2, write2, timeoutMs) {
10292
10324
  const kernelRead = read2.filter((fd) => !own(fd));
10293
10325
  const kernelWrite = write2.filter((fd) => !own(fd));
10294
10326
  for (; ; ) {
10295
- const local2 = ownReady(Fs, read2.filter(own), write2.filter(own));
10296
- const pending = local2.read.length > 0 || local2.write.length > 0;
10327
+ const local3 = ownReady(Fs, read2.filter(own), write2.filter(own));
10328
+ const pending = local3.read.length > 0 || local3.write.length > 0;
10297
10329
  const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
10298
10330
  const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
10299
10331
  if (typeof got === "number") return got;
10300
- const ready = { read: [...local2.read, ...got.read], write: [...local2.write, ...got.write] };
10332
+ const ready = { read: [...local3.read, ...got.read], write: [...local3.write, ...got.write] };
10301
10333
  if (ready.read.length > 0 || ready.write.length > 0 || Date.now() >= deadline) {
10302
10334
  return ready;
10303
10335
  }
@@ -13393,10 +13425,8 @@ var init_wasix_host = __esm({
13393
13425
  const v = mem.view();
13394
13426
  const timed = timeoutPtr !== 0 && v.getUint8(timeoutPtr) === 1;
13395
13427
  const ms = timed ? Number(v.getBigUint64(timeoutPtr + 8, true)) / 1e6 : Number.POSITIVE_INFINITY;
13396
- v.setUint8(
13397
- wokenPtr,
13398
- futexWait(i32(), ptr >> 2, expected | 0, ms, host.interrupted) ? 1 : 0
13399
- );
13428
+ const woken = host.entered || futexWait(i32(), ptr >> 2, expected | 0, ms, host.interrupted);
13429
+ v.setUint8(wokenPtr, woken ? 1 : 0);
13400
13430
  },
13401
13431
  futex_wake: (ptr, wokenPtr) => {
13402
13432
  Atomics.notify(i32(), ptr >> 2, 1);
@@ -13564,9 +13594,10 @@ function delivering(ns, table, host, driver, before) {
13564
13594
  }
13565
13595
  const fn = value2;
13566
13596
  out[name2] = (...args) => {
13597
+ host.entered = false;
13567
13598
  if (driver.idle) {
13568
13599
  before?.();
13569
- host.interrupted?.();
13600
+ host.entered = host.interrupted?.() === true;
13570
13601
  }
13571
13602
  return fn(...args);
13572
13603
  };