tcpip 0.2.1 → 0.2.2-alpha.1
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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;var N=(s,e)=>(e=Symbol[s])?e:Symbol.for("Symbol."+s),z=s=>{throw TypeError(s)};var l=(s,e,t)=>{if(e!=null){typeof e!="object"&&typeof e!="function"&&z("Object expected");var r,n;t&&(r=e[N("asyncDispose")]),r===void 0&&(r=e[N("dispose")],t&&(n=r)),typeof r!="function"&&z("Object not disposable"),n&&(r=function(){try{n.call(this)}catch(o){return Promise.reject(o)}}),s.push([t,r,e])}else t&&s.push([t]);return e},m=(s,e,t)=>{var r=typeof SuppressedError=="function"?SuppressedError:function(a,i,c,p){return p=Error(c),p.name="SuppressedError",p.error=a,p.suppressed=i,p},n=a=>e=t?new r(a,e,"An error was suppressed during disposal"):(t=!0,a),o=a=>{for(;a=s.pop();)try{var i=a[1]&&a[1].call(a[2]);if(a[0])return Promise.resolve(i).then(o,c=>(n(c),o()))}catch(c){n(c)}if(t)throw e};return o()};var d=Symbol.for("Symbol.dispose"),u=Symbol.for("Symbol.asyncDispose");var _browser_wasi_shim = require('@bjorn3/browser_wasi_shim');var h=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,t){this.#e.set(e,t)}setInner(e,t){this.#t.set(e,t)}getOuter(e){let t=this.#e.get(e);if(!t)throw new Error(`outer hooks not set for ${e}`);return t}getInner(e){let t=this.#t.get(e);if(!t)throw new Error(`inner hooks not set for ${e}`);return t}},A=class extends Number{constructor(e,t){super(e),this.free=t}[d](){this.free(this.valueOf())}},E=class extends Map{#e=new Map;wait(e){return new Promise(t=>{let r=_nullishCoalesce(this.#e.get(e), () => (new Set));r.add(t),this.#e.set(e,r)})}set(e,t){super.set(e,t);let r=this.#e.get(e);if(r)for(let n of r)n(t),r.delete(n);return this}};function k(s,e){let t=s.getReader();return G(t,e)}async function*G(s,e){try{for(;;){let{done:t,value:r}=await s.read();if(t)return r;yield r}}finally{_optionalChain([e, 'optionalAccess', _2 => _2.preventCancel])||await s.cancel(),s.releaseLock()}}var I=class extends ReadableStream{#e;constructor({lock:e,...t},r){super(t,r),this.#e=e}getReader(){let e=super.getReader();return this.locked&&_optionalChain([this, 'access', _3 => _3.#e, 'optionalCall', _4 => _4()]),e}pipeThrough(e,t){let r=super.pipeThrough(e,t);return this.locked&&_optionalChain([this, 'access', _5 => _5.#e, 'optionalCall', _6 => _6()]),r}pipeTo(e,t){let r=super.pipeTo(e,t);return this.locked&&_optionalChain([this, 'access', _7 => _7.#e, 'optionalCall', _8 => _8()]),r}tee(){let[e,t]=super.tee();return this.locked&&_optionalChain([this, 'access', _9 => _9.#e, 'optionalCall', _10 => _10()]),[e,t]}};async function b(){return await new Promise(s=>queueMicrotask(s))}var f=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new A(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let t=e.length,r=this.smartMalloc(t);return new Uint8Array(this.exports.memory.buffer,r.valueOf(),t).set(e),r}copyFromMemory(e,t){let r=this.exports.memory.buffer.slice(e,e+t);return new Uint8Array(r)}};function R(s){return new Uint8Array(s.split(".").map(e=>parseInt(e,10)))}function v(s){let[e,t]=s.split("/");if(!e||!t)throw new Error("invalid cidr");let r=parseInt(t,10),n=Q(r);return{ipAddress:R(e),netmask:n}}function Q(s){let e=new Uint8Array(4);for(let t=0;t<s;t++){let r=Math.floor(t/8),n=7-t%8,o=e[r];if(o===void 0)throw new Error("invalid mask size");e[r]=o|1<<n}return e}var U= (_class =class extends f{constructor(...args) { super(...args); _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }__init() {this.interfaces=new Map}__init2() {this.imports={register_loopback_interface:e=>{let t=new g;this.interfaces.set(e,t)}}}async create(e){var c=[];try{let{ipAddress:t,netmask:r}=v(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_loopback_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("loopback interface failed to register");return i}catch(p){var y=p,P=!0}finally{m(c,y,P)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_loopback_interface(t),this.interfaces.delete(t);return}}}, _class),g= exports.LoopbackInterface =class{};function D(s){let e=s.split(":");if(e.length!==6)throw new Error("invalid mac address");return new Uint8Array(e.map(t=>{let r=parseInt(t,16);if(Number.isNaN(r))throw new Error("invalid mac address");return r}))}var S=new h,L= (_class2 =class extends f{constructor(...args2) { super(...args2); _class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this); }__init3() {this.interfaces=new Map}__init4() {this.imports={register_tap_interface:e=>{let t=new x;S.setOuter(t,{sendFrame:r=>{let n=this.copyToMemory(r);this.exports.send_tap_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_frame:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await b();let o=this.interfaces.get(e);if(!o){console.error("received frame on unknown tap interface");return}S.getInner(o).receiveFrame(new Uint8Array(n))}}}async create(e){var y=[];try{let t=D(e.mac);let{ipAddress:r,netmask:n}=v(e.ip);let o=l(y,this.copyToMemory(t));let a=l(y,this.copyToMemory(r));let i=l(y,this.copyToMemory(n));let c=this.exports.create_tap_interface(o,a,i);let p=this.interfaces.get(c);if(!p)throw new Error("tap interface failed to register");return p}catch(P){var j=P,q=!0}finally{m(y,j,q)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tap_interface(t),this.interfaces.delete(t);return}}}, _class2),x= exports.TapInterface =class{#e;#t=!1;constructor(){S.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _11 => _11.#e, 'optionalAccess', _12 => _12.enqueue, 'call', _13 => _13(e)])}}}),this.readable=new I({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{S.getOuter(this).sendFrame(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var V={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var F=new h,w=new h,W=1460,Le=W*4,Oe=W*4,Z=W,O= (_class3 =class extends f{constructor(...args3) { super(...args3); _class3.prototype.__init5.call(this); }#e=new Map;#t=new E;#r=new Map;__init5() {this.imports={accept_tcp_connection:async(e,t)=>{let r=this.#e.get(e);if(!r){console.error("new tcp connection to unknown listener");return}await b();let n=new _;w.setOuter(n,{send:async o=>{let a=Number(this.copyToMemory(o)),i=this.exports.send_tcp_chunk(t,a,o.length);for(;i<o.length;){await new Promise(p=>{this.#r.set(t,p)});let c=o.length-i;i+=this.exports.send_tcp_chunk(t,a+i,c)}},updateReceiveBuffer:o=>{this.exports.update_tcp_receive_buffer(t,o)},close:async()=>{let o=this.exports.close_tcp_connection(t);if(o!==V.ERR_OK)throw new Error(`failed to close tcp connection: ${o}`)}}),this.#t.set(t,n),F.getInner(r).accept(n)},connected_tcp_connection:async e=>{await b();let t=new _;w.setOuter(t,{send:async r=>{let n=Number(this.copyToMemory(r)),o=this.exports.send_tcp_chunk(e,n,r.length);for(;o<r.length;){await new Promise(i=>{this.#r.set(e,i)});let a=r.length-o;o+=this.exports.send_tcp_chunk(e,n+o,a)}},updateReceiveBuffer:r=>{this.exports.update_tcp_receive_buffer(e,r)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,t)},closed_tcp_connection:async e=>{let t=this.#t.get(e);if(!t){console.error("received close on unknown tcp connection");return}await w.getInner(t).close()},receive_tcp_chunk:async(e,t,r)=>{let n=this.copyFromMemory(t,r),o=this.#t.get(e);if(!o){console.error("received chunk on unknown tcp connection");return}await b(),w.getInner(o).receive(new Uint8Array(n))},sent_tcp_chunk:(e,t)=>{let r=this.#r.get(e);this.#r.delete(e),_optionalChain([r, 'optionalCall', _15 => _15(t)])}}}async listen(e){var o=[];try{let t=l(o,e.host?this.copyToMemory(R(e.host)):null);let r=this.exports.create_tcp_listener(t,e.port);let n=new H;F.setOuter(n,{});this.#e.set(r,n);return n}catch(a){var i=a,c=!0}finally{m(o,i,c)}}async connect(e){var o=[];try{let t=l(o,this.copyToMemory(R(e.host)));let r=this.exports.create_tcp_connection(t,e.port);let n=await this.#t.wait(r);if(!n)throw new Error("tcp failed to connect");return n}catch(a){var i=a,c=!0}finally{m(o,i,c)}}}, _class3),H= exports.TcpListener =class{#e=[];#t;constructor(){F.setInner(this,{accept:async e=>{this.#e.push(e),_optionalChain([this, 'access', _16 => _16.#t, 'optionalCall', _17 => _17()])}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},_= exports.TcpConnection =class{#e=[];#t;#r;constructor(){w.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:Z,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await w.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!_optionalChain([this, 'access', _18 => _18.#t, 'optionalAccess', _19 => _19.desiredSize]))return;let e=0;for(;this.#e.length>0;){let t=this.#e[0].length;if(e+t>this.#t.desiredSize)break;let r=this.#e.shift();this.#t.enqueue(r),e+=r.length}e>0&&w.getOuter(this).updateReceiveBuffer(e)}async close(){await w.getOuter(this).close(),_optionalChain([this, 'access', _20 => _20.#t, 'optionalAccess', _21 => _21.error, 'call', _22 => _22(new Error("tcp connection closed"))]),_optionalChain([this, 'access', _23 => _23.#r, 'optionalAccess', _24 => _24.error, 'call', _25 => _25(new Error("tcp connection closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}};var C=new h,M= (_class4 =class extends f{constructor(...args4) { super(...args4); _class4.prototype.__init6.call(this);_class4.prototype.__init7.call(this); }__init6() {this.interfaces=new Map}__init7() {this.imports={register_tun_interface:e=>{let t=new T;C.setOuter(t,{sendPacket:r=>{let n=this.copyToMemory(r);this.exports.send_tun_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_packet:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await b();let o=this.interfaces.get(e);if(!o){console.error("received packet on unknown tun interface");return}C.getInner(o).receivePacket(new Uint8Array(n))}}}async create(e){var c=[];try{let{ipAddress:t,netmask:r}=v(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_tun_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("tun interface failed to register");return i}catch(p){var y=p,P=!0}finally{m(c,y,P)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tun_interface(t),this.interfaces.delete(t);return}}}, _class4),T= exports.TunInterface =class{#e;#t=!1;constructor(){C.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _26 => _26.#e, 'optionalAccess', _27 => _27.enqueue, 'call', _28 => _28(e)])}}}),this.readable=new I({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{C.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var X=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function $(s,e){return X?Y(s,e):fetch(s)}async function Y(s,e){let t=await Promise.resolve().then(() => _interopRequireWildcard(require("fs"))),{Readable:r}=await Promise.resolve().then(() => _interopRequireWildcard(require("stream"))),n=t.createReadStream(s),o=r.toWeb(n);return new Response(o,{headers:{"Content-Type":e}})}async function re(s){let e=new B(s);return await e.ready,e}var B=class{#e;#t;#r=new U;#n=new M;#o=new L;#s=new O;get interfaces(){return this.#i()}constructor(e={}){this.#e={...e,initializeLoopback:_nullishCoalesce(e.initializeLoopback, () => (!0))},this.ready=this.#a(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#a(){let e=new (0, _browser_wasi_shim.WASI)([],[],[new (0, _browser_wasi_shim.OpenFile)(new (0, _browser_wasi_shim.File)([])),_browser_wasi_shim.ConsoleStdout.lineBuffered(a=>console.log(`[WASI stdout] ${a}`)),_browser_wasi_shim.ConsoleStdout.lineBuffered(a=>console.warn(`[WASI stderr] ${a}`))]),t=$(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:r}=await WebAssembly.instantiateStreaming(t,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#r.imports,...this.#n.imports,...this.#o.imports,...this.#s.imports}}),n=r;this.#r.register(n.exports),this.#n.register(n.exports),this.#o.register(n.exports),this.#s.register(n.exports);let o=e.start(n);if(o!==0)throw new Error(`wasi start failed with code ${o}`);this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#i(){yield*this.#r.interfaces.values(),yield*this.#n.interfaces.values(),yield*this.#o.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#r.create(e)}async createTunInterface(e){return await this.ready,this.#n.create(e)}async createTapInterface(e){return await this.ready,this.#o.create(e)}async removeInterface(e){if(await this.ready,e instanceof g)return this.#r.remove(e);if(e instanceof T)return this.#n.remove(e);if(e instanceof x)return this.#o.remove(e);throw new Error("unknown interface type")}async listenTcp(e){return await this.ready,this.#s.listen(e)}async connectTcp(e){return await this.ready,this.#s.connect(e)}};exports.LoopbackInterface = g; exports.NetworkStack = B; exports.TapInterface = x; exports.TcpConnection = _; exports.TcpListener = H; exports.TunInterface = T; exports.createStack = re;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;var W=(s,e)=>(e=Symbol[s])?e:Symbol.for("Symbol."+s),N=s=>{throw TypeError(s)};var l=(s,e,t)=>{if(e!=null){typeof e!="object"&&typeof e!="function"&&N("Object expected");var r,n;t&&(r=e[W("asyncDispose")]),r===void 0&&(r=e[W("dispose")],t&&(n=r)),typeof r!="function"&&N("Object not disposable"),n&&(r=function(){try{n.call(this)}catch(o){return Promise.reject(o)}}),s.push([t,r,e])}else t&&s.push([t]);return e},f=(s,e,t)=>{var r=typeof SuppressedError=="function"?SuppressedError:function(a,i,c,p){return p=Error(c),p.name="SuppressedError",p.error=a,p.suppressed=i,p},n=a=>e=t?new r(a,e,"An error was suppressed during disposal"):(t=!0,a),o=a=>{for(;a=s.pop();)try{var i=a[1]&&a[1].call(a[2]);if(a[0])return Promise.resolve(i).then(o,c=>(n(c),o()))}catch(c){n(c)}if(t)throw e};return o()};var d="dispose"in Symbol?Symbol.dispose:Symbol.for("Symbol.dispose");var _browser_wasi_shim = require('@bjorn3/browser_wasi_shim');var h=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,t){this.#e.set(e,t)}setInner(e,t){this.#t.set(e,t)}getOuter(e){let t=this.#e.get(e);if(!t)throw new Error(`outer hooks not set for ${e}`);return t}getInner(e){let t=this.#t.get(e);if(!t)throw new Error(`inner hooks not set for ${e}`);return t}},_=class extends Number{constructor(e,t){super(e),this.free=t}[d](){this.free(this.valueOf())}},A=class extends Map{#e=new Map;wait(e){return new Promise(t=>{let r=_nullishCoalesce(this.#e.get(e), () => (new Set));r.add(t),this.#e.set(e,r)})}set(e,t){super.set(e,t);let r=this.#e.get(e);if(r)for(let n of r)n(t),r.delete(n);return this}};function I(s,e){let t=s.getReader();return q(t,e)}async function*q(s,e){try{for(;;){let{done:t,value:r}=await s.read();if(t)return r;yield r}}finally{_optionalChain([e, 'optionalAccess', _2 => _2.preventCancel])||await s.cancel(),s.releaseLock()}}var w=class extends ReadableStream{#e;constructor({lock:e,...t},r){super(t,r),this.#e=e}getReader(){let e=super.getReader();return this.locked&&_optionalChain([this, 'access', _3 => _3.#e, 'optionalCall', _4 => _4()]),e}pipeThrough(e,t){let r=super.pipeThrough(e,t);return this.locked&&_optionalChain([this, 'access', _5 => _5.#e, 'optionalCall', _6 => _6()]),r}pipeTo(e,t){let r=super.pipeTo(e,t);return this.locked&&_optionalChain([this, 'access', _7 => _7.#e, 'optionalCall', _8 => _8()]),r}tee(){let[e,t]=super.tee();return this.locked&&_optionalChain([this, 'access', _9 => _9.#e, 'optionalCall', _10 => _10()]),[e,t]}};async function y(){return await new Promise(s=>queueMicrotask(s))}var u=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new _(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let t=e.length,r=this.smartMalloc(t);return new Uint8Array(this.exports.memory.buffer,r.valueOf(),t).set(e),r}copyFromMemory(e,t){let r=this.exports.memory.buffer.slice(e,e+t);return new Uint8Array(r)}};function E(s){return new Uint8Array(s.split(".").map(e=>parseInt(e,10)))}function k(s){let[e,t]=s.split("/");if(!e||!t)throw new Error("invalid cidr");let r=parseInt(t,10),n=G(r);return{ipAddress:E(e),netmask:n}}function G(s){let e=new Uint8Array(4);for(let t=0;t<s;t++){let r=Math.floor(t/8),n=7-t%8,o=e[r];if(o===void 0)throw new Error("invalid mask size");e[r]=o|1<<n}return e}var R= (_class =class extends u{constructor(...args) { super(...args); _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }__init() {this.interfaces=new Map}__init2() {this.imports={register_loopback_interface:e=>{let t=new v;this.interfaces.set(e,t)}}}async create(e){var c=[];try{let{ipAddress:t,netmask:r}=k(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_loopback_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("loopback interface failed to register");return i}catch(p){var m=p,T=!0}finally{f(c,m,T)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_loopback_interface(t),this.interfaces.delete(t);return}}}, _class),v= exports.LoopbackInterface =class{};function z(s){let e=s.split(":");if(e.length!==6)throw new Error("invalid mac address");return new Uint8Array(e.map(t=>{let r=parseInt(t,16);if(Number.isNaN(r))throw new Error("invalid mac address");return r}))}var U=new h,S= (_class2 =class extends u{constructor(...args2) { super(...args2); _class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this); }__init3() {this.interfaces=new Map}__init4() {this.imports={register_tap_interface:e=>{let t=new g;U.setOuter(t,{sendFrame:r=>{let n=this.copyToMemory(r);this.exports.send_tap_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_frame:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await y();let o=this.interfaces.get(e);if(!o){console.error("received frame on unknown tap interface");return}U.getInner(o).receiveFrame(new Uint8Array(n))}}}async create(e){var m=[];try{let t=z(e.mac);let{ipAddress:r,netmask:n}=k(e.ip);let o=l(m,this.copyToMemory(t));let a=l(m,this.copyToMemory(r));let i=l(m,this.copyToMemory(n));let c=this.exports.create_tap_interface(o,a,i);let p=this.interfaces.get(c);if(!p)throw new Error("tap interface failed to register");return p}catch(T){var D=T,j=!0}finally{f(m,D,j)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tap_interface(t),this.interfaces.delete(t);return}}}, _class2),g= exports.TapInterface =class{#e;#t=!1;constructor(){U.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _11 => _11.#e, 'optionalAccess', _12 => _12.enqueue, 'call', _13 => _13(e)])}}}),this.readable=new w({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{U.getOuter(this).sendFrame(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var V={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var B=new h,b=new h,F=1460,Se=F*4,Le=F*4,Q=F,L= (_class3 =class extends u{constructor(...args3) { super(...args3); _class3.prototype.__init5.call(this); }#e=new Map;#t=new A;#r=new Map;__init5() {this.imports={accept_tcp_connection:async(e,t)=>{let r=this.#e.get(e);if(!r){console.error("new tcp connection to unknown listener");return}await y();let n=new P;b.setOuter(n,{send:async o=>{let a=Number(this.copyToMemory(o)),i=this.exports.send_tcp_chunk(t,a,o.length);for(;i<o.length;){await new Promise(p=>{this.#r.set(t,p)});let c=o.length-i;i+=this.exports.send_tcp_chunk(t,a+i,c)}},updateReceiveBuffer:o=>{this.exports.update_tcp_receive_buffer(t,o)},close:async()=>{let o=this.exports.close_tcp_connection(t);if(o!==V.ERR_OK)throw new Error(`failed to close tcp connection: ${o}`)}}),this.#t.set(t,n),B.getInner(r).accept(n)},connected_tcp_connection:async e=>{await y();let t=new P;b.setOuter(t,{send:async r=>{let n=Number(this.copyToMemory(r)),o=this.exports.send_tcp_chunk(e,n,r.length);for(;o<r.length;){await new Promise(i=>{this.#r.set(e,i)});let a=r.length-o;o+=this.exports.send_tcp_chunk(e,n+o,a)}},updateReceiveBuffer:r=>{this.exports.update_tcp_receive_buffer(e,r)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,t)},closed_tcp_connection:async e=>{let t=this.#t.get(e);if(!t){console.error("received close on unknown tcp connection");return}await b.getInner(t).close()},receive_tcp_chunk:async(e,t,r)=>{let n=this.copyFromMemory(t,r),o=this.#t.get(e);if(!o){console.error("received chunk on unknown tcp connection");return}await y(),b.getInner(o).receive(new Uint8Array(n))},sent_tcp_chunk:(e,t)=>{let r=this.#r.get(e);this.#r.delete(e),_optionalChain([r, 'optionalCall', _15 => _15(t)])}}}async listen(e){var o=[];try{let t=l(o,e.host?this.copyToMemory(E(e.host)):null);let r=this.exports.create_tcp_listener(t,e.port);let n=new O;B.setOuter(n,{});this.#e.set(r,n);return n}catch(a){var i=a,c=!0}finally{f(o,i,c)}}async connect(e){var o=[];try{let t=l(o,this.copyToMemory(E(e.host)));let r=this.exports.create_tcp_connection(t,e.port);let n=await this.#t.wait(r);if(!n)throw new Error("tcp failed to connect");return n}catch(a){var i=a,c=!0}finally{f(o,i,c)}}}, _class3),O= exports.TcpListener =class{#e=[];#t;constructor(){B.setInner(this,{accept:async e=>{this.#e.push(e),_optionalChain([this, 'access', _16 => _16.#t, 'optionalCall', _17 => _17()])}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},P= exports.TcpConnection =class{#e=[];#t;#r;constructor(){b.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:Q,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await b.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!_optionalChain([this, 'access', _18 => _18.#t, 'optionalAccess', _19 => _19.desiredSize]))return;let e=0;for(;this.#e.length>0;){let t=this.#e[0].length;if(e+t>this.#t.desiredSize)break;let r=this.#e.shift();this.#t.enqueue(r),e+=r.length}e>0&&b.getOuter(this).updateReceiveBuffer(e)}async close(){await b.getOuter(this).close(),_optionalChain([this, 'access', _20 => _20.#t, 'optionalAccess', _21 => _21.error, 'call', _22 => _22(new Error("tcp connection closed"))]),_optionalChain([this, 'access', _23 => _23.#r, 'optionalAccess', _24 => _24.error, 'call', _25 => _25(new Error("tcp connection closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}};var H=new h,C= (_class4 =class extends u{constructor(...args4) { super(...args4); _class4.prototype.__init6.call(this);_class4.prototype.__init7.call(this); }__init6() {this.interfaces=new Map}__init7() {this.imports={register_tun_interface:e=>{let t=new x;H.setOuter(t,{sendPacket:r=>{let n=this.copyToMemory(r);this.exports.send_tun_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_packet:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await y();let o=this.interfaces.get(e);if(!o){console.error("received packet on unknown tun interface");return}H.getInner(o).receivePacket(new Uint8Array(n))}}}async create(e){var c=[];try{let{ipAddress:t,netmask:r}=k(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_tun_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("tun interface failed to register");return i}catch(p){var m=p,T=!0}finally{f(c,m,T)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tun_interface(t),this.interfaces.delete(t);return}}}, _class4),x= exports.TunInterface =class{#e;#t=!1;constructor(){H.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _26 => _26.#e, 'optionalAccess', _27 => _27.enqueue, 'call', _28 => _28(e)])}}}),this.readable=new w({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{H.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var Z=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function $(s,e){return Z?X(s,e):fetch(s)}async function X(s,e){let t=await Promise.resolve().then(() => _interopRequireWildcard(require("fs"))),{Readable:r}=await Promise.resolve().then(() => _interopRequireWildcard(require("stream"))),n=t.createReadStream(s),o=r.toWeb(n);return new Response(o,{headers:{"Content-Type":e}})}async function te(s){let e=new M(s);return await e.ready,e}var M=class{#e;#t;#r=new R;#n=new C;#o=new S;#s=new L;get interfaces(){return this.#i()}constructor(e={}){this.#e={...e,initializeLoopback:_nullishCoalesce(e.initializeLoopback, () => (!0))},this.ready=this.#a(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#a(){let e=new (0, _browser_wasi_shim.WASI)([],[],[new (0, _browser_wasi_shim.OpenFile)(new (0, _browser_wasi_shim.File)([])),_browser_wasi_shim.ConsoleStdout.lineBuffered(a=>console.log(`[WASI stdout] ${a}`)),_browser_wasi_shim.ConsoleStdout.lineBuffered(a=>console.warn(`[WASI stderr] ${a}`))]),t=$(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:r}=await WebAssembly.instantiateStreaming(t,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#r.imports,...this.#n.imports,...this.#o.imports,...this.#s.imports}}),n=r;this.#r.register(n.exports),this.#n.register(n.exports),this.#o.register(n.exports),this.#s.register(n.exports);let o=e.start(n);if(o!==0)throw new Error(`wasi start failed with code ${o}`);this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#i(){yield*this.#r.interfaces.values(),yield*this.#n.interfaces.values(),yield*this.#o.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#r.create(e)}async createTunInterface(e){return await this.ready,this.#n.create(e)}async createTapInterface(e){return await this.ready,this.#o.create(e)}async removeInterface(e){if(await this.ready,e instanceof v)return this.#r.remove(e);if(e instanceof x)return this.#n.remove(e);if(e instanceof g)return this.#o.remove(e);throw new Error("unknown interface type")}async listenTcp(e){return await this.ready,this.#s.listen(e)}async connectTcp(e){return await this.ready,this.#s.connect(e)}};exports.LoopbackInterface = v; exports.NetworkStack = M; exports.TapInterface = g; exports.TcpConnection = P; exports.TcpListener = O; exports.TunInterface = x; exports.createStack = te;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","../polyfills/disposable.ts","../src/stack.ts","../src/util.ts"],"names":["DisposeSymbol","AsyncDisposeSymbol","Hooks","#outerHooks","#innerHooks","key","hooks"],"mappings":"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","file":"/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","sourcesContent":[null,"/**\n * Scoped polyfill for `Symbol.dispose` and `Symbol.asyncDispose` without\n * polluting the global scope. Required for the `using` keyword which we\n * use internally.\n * \n * We export these symbols as 'Symbol.dispose' and 'Symbol.asyncDispose'\n * which tells ESBuild to inject them into the output bundle.\n * \n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` and `Symbol.for(\"Symbol.asyncDispose\")` if the\n * built-in `Symbol.dispose` and `Symbol.asyncDispose` are not available.\n */\n\nconst DisposeSymbol = Symbol.for('Symbol.dispose');\nconst AsyncDisposeSymbol = Symbol.for('Symbol.asyncDispose');\n\nexport {\n DisposeSymbol as 'Symbol.dispose',\n AsyncDisposeSymbol as 'Symbol.asyncDispose'\n};\n","import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport {\n LoopbackBindings,\n LoopbackInterface,\n type LoopbackInterfaceOptions,\n} from './bindings/loopback-interface.js';\nimport {\n TapBindings,\n TapInterface,\n type TapInterfaceOptions,\n} from './bindings/tap-interface.js';\nimport {\n TcpBindings,\n type TcpConnectionOptions,\n type TcpListenerOptions,\n} from './bindings/tcp.js';\nimport {\n TunBindings,\n TunInterface,\n type TunInterfaceOptions,\n} from './bindings/tun-interface.js';\nimport { fetchFile } from './fetch-file.js';\nimport type { NetworkInterface, WasmInstance } from './types.js';\n\nexport async function createStack(options?: NetworkStackOptions) {\n const stack = new NetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n initializeLoopback?: boolean;\n};\n\nexport class NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n\n #loopbackBindings = new LoopbackBindings();\n #tunBindings = new TunBindings();\n #tapBindings = new TapBindings();\n #tcpBindings = new TcpBindings();\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#tcpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n\n const result = wasi.start(wasmInstance);\n\n if (result !== 0) {\n throw new Error(`wasi start failed with code ${result}`);\n }\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async removeInterface(\n netInterface: LoopbackInterface | TunInterface | TapInterface\n ) {\n await this.ready;\n\n if (netInterface instanceof LoopbackInterface) {\n return this.#loopbackBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TunInterface) {\n return this.#tunBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TapInterface) {\n return this.#tapBindings.remove(netInterface);\n }\n\n throw new Error('unknown interface type');\n }\n\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n}\n","/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","../polyfills/disposable.ts","../src/stack.ts","../src/util.ts"],"names":["DisposeSymbol","Hooks","#outerHooks","#innerHooks","key","hooks"],"mappings":"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","file":"/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","sourcesContent":[null,"/**\n * Scoped polyfill for `Symbol.dispose` without polluting the global scope.\n * Required for the `using` keyword which we use internally.\n * \n * We export this symbol as 'Symbol.dispose' which tells ESBuild to inject\n * it into the output bundle.\n * \n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` if the built-in `Symbol.dispose` is not available.\n */\n\nconst DisposeSymbol = 'dispose' in (Symbol as object) ? Symbol.dispose : Symbol.for('Symbol.dispose');\n\nexport {\n DisposeSymbol as 'Symbol.dispose'\n};\n","import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport {\n LoopbackBindings,\n LoopbackInterface,\n type LoopbackInterfaceOptions,\n} from './bindings/loopback-interface.js';\nimport {\n TapBindings,\n TapInterface,\n type TapInterfaceOptions,\n} from './bindings/tap-interface.js';\nimport {\n TcpBindings,\n type TcpConnectionOptions,\n type TcpListenerOptions,\n} from './bindings/tcp.js';\nimport {\n TunBindings,\n TunInterface,\n type TunInterfaceOptions,\n} from './bindings/tun-interface.js';\nimport { fetchFile } from './fetch-file.js';\nimport type { NetworkInterface, WasmInstance } from './types.js';\n\nexport async function createStack(options?: NetworkStackOptions) {\n const stack = new NetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n initializeLoopback?: boolean;\n};\n\nexport class NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n\n #loopbackBindings = new LoopbackBindings();\n #tunBindings = new TunBindings();\n #tapBindings = new TapBindings();\n #tcpBindings = new TcpBindings();\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#tcpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n\n const result = wasi.start(wasmInstance);\n\n if (result !== 0) {\n throw new Error(`wasi start failed with code ${result}`);\n }\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async removeInterface(\n netInterface: LoopbackInterface | TunInterface | TapInterface\n ) {\n await this.ready;\n\n if (netInterface instanceof LoopbackInterface) {\n return this.#loopbackBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TunInterface) {\n return this.#tunBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TapInterface) {\n return this.#tapBindings.remove(netInterface);\n }\n\n throw new Error('unknown interface type');\n }\n\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n}\n","/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var N=(s,e)=>(e=Symbol[s])?e:Symbol.for("Symbol."+s),z=s=>{throw TypeError(s)};var l=(s,e,t)=>{if(e!=null){typeof e!="object"&&typeof e!="function"&&z("Object expected");var r,n;t&&(r=e[N("asyncDispose")]),r===void 0&&(r=e[N("dispose")],t&&(n=r)),typeof r!="function"&&z("Object not disposable"),n&&(r=function(){try{n.call(this)}catch(o){return Promise.reject(o)}}),s.push([t,r,e])}else t&&s.push([t]);return e},m=(s,e,t)=>{var r=typeof SuppressedError=="function"?SuppressedError:function(a,i,c,p){return p=Error(c),p.name="SuppressedError",p.error=a,p.suppressed=i,p},n=a=>e=t?new r(a,e,"An error was suppressed during disposal"):(t=!0,a),o=a=>{for(;a=s.pop();)try{var i=a[1]&&a[1].call(a[2]);if(a[0])return Promise.resolve(i).then(o,c=>(n(c),o()))}catch(c){n(c)}if(t)throw e};return o()};var d=Symbol.for("Symbol.dispose"),u=Symbol.for("Symbol.asyncDispose");import{ConsoleStdout as K,File as J,OpenFile as ee,WASI as te}from"@bjorn3/browser_wasi_shim";var h=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,t){this.#e.set(e,t)}setInner(e,t){this.#t.set(e,t)}getOuter(e){let t=this.#e.get(e);if(!t)throw new Error(`outer hooks not set for ${e}`);return t}getInner(e){let t=this.#t.get(e);if(!t)throw new Error(`inner hooks not set for ${e}`);return t}},A=class extends Number{free;constructor(e,t){super(e),this.free=t}[d](){this.free(this.valueOf())}},E=class extends Map{#e=new Map;wait(e){return new Promise(t=>{let r=this.#e.get(e)??new Set;r.add(t),this.#e.set(e,r)})}set(e,t){super.set(e,t);let r=this.#e.get(e);if(r)for(let n of r)n(t),r.delete(n);return this}};function k(s,e){let t=s.getReader();return G(t,e)}async function*G(s,e){try{for(;;){let{done:t,value:r}=await s.read();if(t)return r;yield r}}finally{e?.preventCancel||await s.cancel(),s.releaseLock()}}var I=class extends ReadableStream{#e;constructor({lock:e,...t},r){super(t,r),this.#e=e}getReader(){let e=super.getReader();return this.locked&&this.#e?.(),e}pipeThrough(e,t){let r=super.pipeThrough(e,t);return this.locked&&this.#e?.(),r}pipeTo(e,t){let r=super.pipeTo(e,t);return this.locked&&this.#e?.(),r}tee(){let[e,t]=super.tee();return this.locked&&this.#e?.(),[e,t]}};async function b(){return await new Promise(s=>queueMicrotask(s))}var f=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new A(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let t=e.length,r=this.smartMalloc(t);return new Uint8Array(this.exports.memory.buffer,r.valueOf(),t).set(e),r}copyFromMemory(e,t){let r=this.exports.memory.buffer.slice(e,e+t);return new Uint8Array(r)}};function R(s){return new Uint8Array(s.split(".").map(e=>parseInt(e,10)))}function v(s){let[e,t]=s.split("/");if(!e||!t)throw new Error("invalid cidr");let r=parseInt(t,10),n=Q(r);return{ipAddress:R(e),netmask:n}}function Q(s){let e=new Uint8Array(4);for(let t=0;t<s;t++){let r=Math.floor(t/8),n=7-t%8,o=e[r];if(o===void 0)throw new Error("invalid mask size");e[r]=o|1<<n}return e}var U=class extends f{interfaces=new Map;imports={register_loopback_interface:e=>{let t=new g;this.interfaces.set(e,t)}};async create(e){var c=[];try{let{ipAddress:t,netmask:r}=v(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_loopback_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("loopback interface failed to register");return i}catch(p){var y=p,P=!0}finally{m(c,y,P)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_loopback_interface(t),this.interfaces.delete(t);return}}},g=class{};function D(s){let e=s.split(":");if(e.length!==6)throw new Error("invalid mac address");return new Uint8Array(e.map(t=>{let r=parseInt(t,16);if(Number.isNaN(r))throw new Error("invalid mac address");return r}))}var S=new h,L=class extends f{interfaces=new Map;imports={register_tap_interface:e=>{let t=new x;S.setOuter(t,{sendFrame:r=>{let n=this.copyToMemory(r);this.exports.send_tap_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_frame:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await b();let o=this.interfaces.get(e);if(!o){console.error("received frame on unknown tap interface");return}S.getInner(o).receiveFrame(new Uint8Array(n))}};async create(e){var y=[];try{let t=D(e.mac);let{ipAddress:r,netmask:n}=v(e.ip);let o=l(y,this.copyToMemory(t));let a=l(y,this.copyToMemory(r));let i=l(y,this.copyToMemory(n));let c=this.exports.create_tap_interface(o,a,i);let p=this.interfaces.get(c);if(!p)throw new Error("tap interface failed to register");return p}catch(P){var j=P,q=!0}finally{m(y,j,q)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tap_interface(t),this.interfaces.delete(t);return}}},x=class{#e;#t=!1;readable;writable;constructor(){S.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e?.enqueue(e)}}}),this.readable=new I({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{S.getOuter(this).sendFrame(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var V={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var F=new h,w=new h,W=1460,Le=W*4,Oe=W*4,Z=W,O=class extends f{#e=new Map;#t=new E;#r=new Map;imports={accept_tcp_connection:async(e,t)=>{let r=this.#e.get(e);if(!r){console.error("new tcp connection to unknown listener");return}await b();let n=new _;w.setOuter(n,{send:async o=>{let a=Number(this.copyToMemory(o)),i=this.exports.send_tcp_chunk(t,a,o.length);for(;i<o.length;){await new Promise(p=>{this.#r.set(t,p)});let c=o.length-i;i+=this.exports.send_tcp_chunk(t,a+i,c)}},updateReceiveBuffer:o=>{this.exports.update_tcp_receive_buffer(t,o)},close:async()=>{let o=this.exports.close_tcp_connection(t);if(o!==V.ERR_OK)throw new Error(`failed to close tcp connection: ${o}`)}}),this.#t.set(t,n),F.getInner(r).accept(n)},connected_tcp_connection:async e=>{await b();let t=new _;w.setOuter(t,{send:async r=>{let n=Number(this.copyToMemory(r)),o=this.exports.send_tcp_chunk(e,n,r.length);for(;o<r.length;){await new Promise(i=>{this.#r.set(e,i)});let a=r.length-o;o+=this.exports.send_tcp_chunk(e,n+o,a)}},updateReceiveBuffer:r=>{this.exports.update_tcp_receive_buffer(e,r)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,t)},closed_tcp_connection:async e=>{let t=this.#t.get(e);if(!t){console.error("received close on unknown tcp connection");return}await w.getInner(t).close()},receive_tcp_chunk:async(e,t,r)=>{let n=this.copyFromMemory(t,r),o=this.#t.get(e);if(!o){console.error("received chunk on unknown tcp connection");return}await b(),w.getInner(o).receive(new Uint8Array(n))},sent_tcp_chunk:(e,t)=>{let r=this.#r.get(e);this.#r.delete(e),r?.(t)}};async listen(e){var o=[];try{let t=l(o,e.host?this.copyToMemory(R(e.host)):null);let r=this.exports.create_tcp_listener(t,e.port);let n=new H;F.setOuter(n,{});this.#e.set(r,n);return n}catch(a){var i=a,c=!0}finally{m(o,i,c)}}async connect(e){var o=[];try{let t=l(o,this.copyToMemory(R(e.host)));let r=this.exports.create_tcp_connection(t,e.port);let n=await this.#t.wait(r);if(!n)throw new Error("tcp failed to connect");return n}catch(a){var i=a,c=!0}finally{m(o,i,c)}}},H=class{#e=[];#t;constructor(){F.setInner(this,{accept:async e=>{this.#e.push(e),this.#t?.()}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},_=class{#e=[];#t;#r;readable;writable;constructor(){w.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:Z,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await w.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!this.#t?.desiredSize)return;let e=0;for(;this.#e.length>0;){let t=this.#e[0].length;if(e+t>this.#t.desiredSize)break;let r=this.#e.shift();this.#t.enqueue(r),e+=r.length}e>0&&w.getOuter(this).updateReceiveBuffer(e)}async close(){await w.getOuter(this).close(),this.#t?.error(new Error("tcp connection closed")),this.#r?.error(new Error("tcp connection closed"))}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}};var C=new h,M=class extends f{interfaces=new Map;imports={register_tun_interface:e=>{let t=new T;C.setOuter(t,{sendPacket:r=>{let n=this.copyToMemory(r);this.exports.send_tun_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_packet:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await b();let o=this.interfaces.get(e);if(!o){console.error("received packet on unknown tun interface");return}C.getInner(o).receivePacket(new Uint8Array(n))}};async create(e){var c=[];try{let{ipAddress:t,netmask:r}=v(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_tun_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("tun interface failed to register");return i}catch(p){var y=p,P=!0}finally{m(c,y,P)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tun_interface(t),this.interfaces.delete(t);return}}},T=class{#e;#t=!1;readable;writable;constructor(){C.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e?.enqueue(e)}}}),this.readable=new I({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{C.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return k(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var X=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function $(s,e){return X?Y(s,e):fetch(s)}async function Y(s,e){let t=await import("node:fs"),{Readable:r}=await import("node:stream"),n=t.createReadStream(s),o=r.toWeb(n);return new Response(o,{headers:{"Content-Type":e}})}async function re(s){let e=new B(s);return await e.ready,e}var B=class{#e;#t;#r=new U;#n=new M;#o=new L;#s=new O;ready;get interfaces(){return this.#i()}constructor(e={}){this.#e={...e,initializeLoopback:e.initializeLoopback??!0},this.ready=this.#a(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#a(){let e=new te([],[],[new ee(new J([])),K.lineBuffered(a=>console.log(`[WASI stdout] ${a}`)),K.lineBuffered(a=>console.warn(`[WASI stderr] ${a}`))]),t=$(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:r}=await WebAssembly.instantiateStreaming(t,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#r.imports,...this.#n.imports,...this.#o.imports,...this.#s.imports}}),n=r;this.#r.register(n.exports),this.#n.register(n.exports),this.#o.register(n.exports),this.#s.register(n.exports);let o=e.start(n);if(o!==0)throw new Error(`wasi start failed with code ${o}`);this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#i(){yield*this.#r.interfaces.values(),yield*this.#n.interfaces.values(),yield*this.#o.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#r.create(e)}async createTunInterface(e){return await this.ready,this.#n.create(e)}async createTapInterface(e){return await this.ready,this.#o.create(e)}async removeInterface(e){if(await this.ready,e instanceof g)return this.#r.remove(e);if(e instanceof T)return this.#n.remove(e);if(e instanceof x)return this.#o.remove(e);throw new Error("unknown interface type")}async listenTcp(e){return await this.ready,this.#s.listen(e)}async connectTcp(e){return await this.ready,this.#s.connect(e)}};export{g as LoopbackInterface,B as NetworkStack,x as TapInterface,_ as TcpConnection,H as TcpListener,T as TunInterface,re as createStack};
|
|
1
|
+
var W=(s,e)=>(e=Symbol[s])?e:Symbol.for("Symbol."+s),N=s=>{throw TypeError(s)};var l=(s,e,t)=>{if(e!=null){typeof e!="object"&&typeof e!="function"&&N("Object expected");var r,n;t&&(r=e[W("asyncDispose")]),r===void 0&&(r=e[W("dispose")],t&&(n=r)),typeof r!="function"&&N("Object not disposable"),n&&(r=function(){try{n.call(this)}catch(o){return Promise.reject(o)}}),s.push([t,r,e])}else t&&s.push([t]);return e},f=(s,e,t)=>{var r=typeof SuppressedError=="function"?SuppressedError:function(a,i,c,p){return p=Error(c),p.name="SuppressedError",p.error=a,p.suppressed=i,p},n=a=>e=t?new r(a,e,"An error was suppressed during disposal"):(t=!0,a),o=a=>{for(;a=s.pop();)try{var i=a[1]&&a[1].call(a[2]);if(a[0])return Promise.resolve(i).then(o,c=>(n(c),o()))}catch(c){n(c)}if(t)throw e};return o()};var d="dispose"in Symbol?Symbol.dispose:Symbol.for("Symbol.dispose");import{ConsoleStdout as K,File as Y,OpenFile as J,WASI as ee}from"@bjorn3/browser_wasi_shim";var h=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,t){this.#e.set(e,t)}setInner(e,t){this.#t.set(e,t)}getOuter(e){let t=this.#e.get(e);if(!t)throw new Error(`outer hooks not set for ${e}`);return t}getInner(e){let t=this.#t.get(e);if(!t)throw new Error(`inner hooks not set for ${e}`);return t}},_=class extends Number{free;constructor(e,t){super(e),this.free=t}[d](){this.free(this.valueOf())}},A=class extends Map{#e=new Map;wait(e){return new Promise(t=>{let r=this.#e.get(e)??new Set;r.add(t),this.#e.set(e,r)})}set(e,t){super.set(e,t);let r=this.#e.get(e);if(r)for(let n of r)n(t),r.delete(n);return this}};function I(s,e){let t=s.getReader();return q(t,e)}async function*q(s,e){try{for(;;){let{done:t,value:r}=await s.read();if(t)return r;yield r}}finally{e?.preventCancel||await s.cancel(),s.releaseLock()}}var w=class extends ReadableStream{#e;constructor({lock:e,...t},r){super(t,r),this.#e=e}getReader(){let e=super.getReader();return this.locked&&this.#e?.(),e}pipeThrough(e,t){let r=super.pipeThrough(e,t);return this.locked&&this.#e?.(),r}pipeTo(e,t){let r=super.pipeTo(e,t);return this.locked&&this.#e?.(),r}tee(){let[e,t]=super.tee();return this.locked&&this.#e?.(),[e,t]}};async function y(){return await new Promise(s=>queueMicrotask(s))}var u=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new _(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let t=e.length,r=this.smartMalloc(t);return new Uint8Array(this.exports.memory.buffer,r.valueOf(),t).set(e),r}copyFromMemory(e,t){let r=this.exports.memory.buffer.slice(e,e+t);return new Uint8Array(r)}};function E(s){return new Uint8Array(s.split(".").map(e=>parseInt(e,10)))}function k(s){let[e,t]=s.split("/");if(!e||!t)throw new Error("invalid cidr");let r=parseInt(t,10),n=G(r);return{ipAddress:E(e),netmask:n}}function G(s){let e=new Uint8Array(4);for(let t=0;t<s;t++){let r=Math.floor(t/8),n=7-t%8,o=e[r];if(o===void 0)throw new Error("invalid mask size");e[r]=o|1<<n}return e}var R=class extends u{interfaces=new Map;imports={register_loopback_interface:e=>{let t=new v;this.interfaces.set(e,t)}};async create(e){var c=[];try{let{ipAddress:t,netmask:r}=k(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_loopback_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("loopback interface failed to register");return i}catch(p){var m=p,T=!0}finally{f(c,m,T)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_loopback_interface(t),this.interfaces.delete(t);return}}},v=class{};function z(s){let e=s.split(":");if(e.length!==6)throw new Error("invalid mac address");return new Uint8Array(e.map(t=>{let r=parseInt(t,16);if(Number.isNaN(r))throw new Error("invalid mac address");return r}))}var U=new h,S=class extends u{interfaces=new Map;imports={register_tap_interface:e=>{let t=new g;U.setOuter(t,{sendFrame:r=>{let n=this.copyToMemory(r);this.exports.send_tap_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_frame:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await y();let o=this.interfaces.get(e);if(!o){console.error("received frame on unknown tap interface");return}U.getInner(o).receiveFrame(new Uint8Array(n))}};async create(e){var m=[];try{let t=z(e.mac);let{ipAddress:r,netmask:n}=k(e.ip);let o=l(m,this.copyToMemory(t));let a=l(m,this.copyToMemory(r));let i=l(m,this.copyToMemory(n));let c=this.exports.create_tap_interface(o,a,i);let p=this.interfaces.get(c);if(!p)throw new Error("tap interface failed to register");return p}catch(T){var D=T,j=!0}finally{f(m,D,j)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tap_interface(t),this.interfaces.delete(t);return}}},g=class{#e;#t=!1;readable;writable;constructor(){U.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e?.enqueue(e)}}}),this.readable=new w({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{U.getOuter(this).sendFrame(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var V={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var B=new h,b=new h,F=1460,Se=F*4,Le=F*4,Q=F,L=class extends u{#e=new Map;#t=new A;#r=new Map;imports={accept_tcp_connection:async(e,t)=>{let r=this.#e.get(e);if(!r){console.error("new tcp connection to unknown listener");return}await y();let n=new P;b.setOuter(n,{send:async o=>{let a=Number(this.copyToMemory(o)),i=this.exports.send_tcp_chunk(t,a,o.length);for(;i<o.length;){await new Promise(p=>{this.#r.set(t,p)});let c=o.length-i;i+=this.exports.send_tcp_chunk(t,a+i,c)}},updateReceiveBuffer:o=>{this.exports.update_tcp_receive_buffer(t,o)},close:async()=>{let o=this.exports.close_tcp_connection(t);if(o!==V.ERR_OK)throw new Error(`failed to close tcp connection: ${o}`)}}),this.#t.set(t,n),B.getInner(r).accept(n)},connected_tcp_connection:async e=>{await y();let t=new P;b.setOuter(t,{send:async r=>{let n=Number(this.copyToMemory(r)),o=this.exports.send_tcp_chunk(e,n,r.length);for(;o<r.length;){await new Promise(i=>{this.#r.set(e,i)});let a=r.length-o;o+=this.exports.send_tcp_chunk(e,n+o,a)}},updateReceiveBuffer:r=>{this.exports.update_tcp_receive_buffer(e,r)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,t)},closed_tcp_connection:async e=>{let t=this.#t.get(e);if(!t){console.error("received close on unknown tcp connection");return}await b.getInner(t).close()},receive_tcp_chunk:async(e,t,r)=>{let n=this.copyFromMemory(t,r),o=this.#t.get(e);if(!o){console.error("received chunk on unknown tcp connection");return}await y(),b.getInner(o).receive(new Uint8Array(n))},sent_tcp_chunk:(e,t)=>{let r=this.#r.get(e);this.#r.delete(e),r?.(t)}};async listen(e){var o=[];try{let t=l(o,e.host?this.copyToMemory(E(e.host)):null);let r=this.exports.create_tcp_listener(t,e.port);let n=new O;B.setOuter(n,{});this.#e.set(r,n);return n}catch(a){var i=a,c=!0}finally{f(o,i,c)}}async connect(e){var o=[];try{let t=l(o,this.copyToMemory(E(e.host)));let r=this.exports.create_tcp_connection(t,e.port);let n=await this.#t.wait(r);if(!n)throw new Error("tcp failed to connect");return n}catch(a){var i=a,c=!0}finally{f(o,i,c)}}},O=class{#e=[];#t;constructor(){B.setInner(this,{accept:async e=>{this.#e.push(e),this.#t?.()}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},P=class{#e=[];#t;#r;readable;writable;constructor(){b.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:Q,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await b.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!this.#t?.desiredSize)return;let e=0;for(;this.#e.length>0;){let t=this.#e[0].length;if(e+t>this.#t.desiredSize)break;let r=this.#e.shift();this.#t.enqueue(r),e+=r.length}e>0&&b.getOuter(this).updateReceiveBuffer(e)}async close(){await b.getOuter(this).close(),this.#t?.error(new Error("tcp connection closed")),this.#r?.error(new Error("tcp connection closed"))}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}};var H=new h,C=class extends u{interfaces=new Map;imports={register_tun_interface:e=>{let t=new x;H.setOuter(t,{sendPacket:r=>{let n=this.copyToMemory(r);this.exports.send_tun_interface(e,n,r.length)}}),this.interfaces.set(e,t)},receive_packet:async(e,t,r)=>{let n=this.copyFromMemory(t,r);await y();let o=this.interfaces.get(e);if(!o){console.error("received packet on unknown tun interface");return}H.getInner(o).receivePacket(new Uint8Array(n))}};async create(e){var c=[];try{let{ipAddress:t,netmask:r}=k(e.ip);let n=l(c,this.copyToMemory(t));let o=l(c,this.copyToMemory(r));let a=this.exports.create_tun_interface(n,o);let i=this.interfaces.get(a);if(!i)throw new Error("tun interface failed to register");return i}catch(p){var m=p,T=!0}finally{f(c,m,T)}}async remove(e){for(let[t,r]of this.interfaces.entries())if(r===e){this.exports.remove_tun_interface(t),this.interfaces.delete(t);return}}},x=class{#e;#t=!1;readable;writable;constructor(){H.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e?.enqueue(e)}}}),this.readable=new w({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{H.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return I(this.readable)}[Symbol.asyncIterator](){return this.listen()}};var Z=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function $(s,e){return Z?X(s,e):fetch(s)}async function X(s,e){let t=await import("node:fs"),{Readable:r}=await import("node:stream"),n=t.createReadStream(s),o=r.toWeb(n);return new Response(o,{headers:{"Content-Type":e}})}async function te(s){let e=new M(s);return await e.ready,e}var M=class{#e;#t;#r=new R;#n=new C;#o=new S;#s=new L;ready;get interfaces(){return this.#i()}constructor(e={}){this.#e={...e,initializeLoopback:e.initializeLoopback??!0},this.ready=this.#a(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#a(){let e=new ee([],[],[new J(new Y([])),K.lineBuffered(a=>console.log(`[WASI stdout] ${a}`)),K.lineBuffered(a=>console.warn(`[WASI stderr] ${a}`))]),t=$(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:r}=await WebAssembly.instantiateStreaming(t,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#r.imports,...this.#n.imports,...this.#o.imports,...this.#s.imports}}),n=r;this.#r.register(n.exports),this.#n.register(n.exports),this.#o.register(n.exports),this.#s.register(n.exports);let o=e.start(n);if(o!==0)throw new Error(`wasi start failed with code ${o}`);this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#i(){yield*this.#r.interfaces.values(),yield*this.#n.interfaces.values(),yield*this.#o.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#r.create(e)}async createTunInterface(e){return await this.ready,this.#n.create(e)}async createTapInterface(e){return await this.ready,this.#o.create(e)}async removeInterface(e){if(await this.ready,e instanceof v)return this.#r.remove(e);if(e instanceof x)return this.#n.remove(e);if(e instanceof g)return this.#o.remove(e);throw new Error("unknown interface type")}async listenTcp(e){return await this.ready,this.#s.listen(e)}async connectTcp(e){return await this.ready,this.#s.connect(e)}};export{v as LoopbackInterface,M as NetworkStack,g as TapInterface,P as TcpConnection,O as TcpListener,x as TunInterface,te as createStack};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../polyfills/disposable.ts","../src/stack.ts","../src/util.ts","../src/bindings/base.ts","../src/protocols/ipv4.ts","../src/bindings/loopback-interface.ts","../src/protocols/ethernet.ts","../src/bindings/tap-interface.ts","../src/lwip/errors.ts","../src/bindings/tcp.ts","../src/bindings/tun-interface.ts","../src/fetch-file.ts"],"sourcesContent":["/**\n * Scoped polyfill for `Symbol.dispose` and `Symbol.asyncDispose` without\n * polluting the global scope. Required for the `using` keyword which we\n * use internally.\n * \n * We export these symbols as 'Symbol.dispose' and 'Symbol.asyncDispose'\n * which tells ESBuild to inject them into the output bundle.\n * \n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` and `Symbol.for(\"Symbol.asyncDispose\")` if the\n * built-in `Symbol.dispose` and `Symbol.asyncDispose` are not available.\n */\n\nconst DisposeSymbol = Symbol.for('Symbol.dispose');\nconst AsyncDisposeSymbol = Symbol.for('Symbol.asyncDispose');\n\nexport {\n DisposeSymbol as 'Symbol.dispose',\n AsyncDisposeSymbol as 'Symbol.asyncDispose'\n};\n","import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport {\n LoopbackBindings,\n LoopbackInterface,\n type LoopbackInterfaceOptions,\n} from './bindings/loopback-interface.js';\nimport {\n TapBindings,\n TapInterface,\n type TapInterfaceOptions,\n} from './bindings/tap-interface.js';\nimport {\n TcpBindings,\n type TcpConnectionOptions,\n type TcpListenerOptions,\n} from './bindings/tcp.js';\nimport {\n TunBindings,\n TunInterface,\n type TunInterfaceOptions,\n} from './bindings/tun-interface.js';\nimport { fetchFile } from './fetch-file.js';\nimport type { NetworkInterface, WasmInstance } from './types.js';\n\nexport async function createStack(options?: NetworkStackOptions) {\n const stack = new NetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n initializeLoopback?: boolean;\n};\n\nexport class NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n\n #loopbackBindings = new LoopbackBindings();\n #tunBindings = new TunBindings();\n #tapBindings = new TapBindings();\n #tcpBindings = new TcpBindings();\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#tcpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n\n const result = wasi.start(wasmInstance);\n\n if (result !== 0) {\n throw new Error(`wasi start failed with code ${result}`);\n }\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async removeInterface(\n netInterface: LoopbackInterface | TunInterface | TapInterface\n ) {\n await this.ready;\n\n if (netInterface instanceof LoopbackInterface) {\n return this.#loopbackBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TunInterface) {\n return this.#tunBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TapInterface) {\n return this.#tapBindings.remove(netInterface);\n }\n\n throw new Error('unknown interface type');\n }\n\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n}\n","/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n","import type { SysExports, WasiExports } from '../types.js';\nimport { UniquePointer } from '../util.js';\n\nexport abstract class Bindings<Imports, Exports> {\n #exports?: Exports & WasiExports & SysExports;\n\n abstract imports: Imports;\n get exports(): Exports & WasiExports & SysExports {\n if (!this.#exports) {\n throw new Error('exports were not registered');\n }\n return this.#exports;\n }\n\n register(exports: Exports & WasiExports & SysExports) {\n this.#exports = exports;\n }\n\n smartMalloc(size: number) {\n return new UniquePointer(this.exports.malloc(size), this.exports.free);\n }\n\n copyToMemory(data: Uint8Array) {\n const length = data.length;\n const pointer = this.smartMalloc(length);\n\n const memoryView = new Uint8Array(\n this.exports.memory.buffer,\n pointer.valueOf(),\n length\n );\n\n memoryView.set(data);\n\n return pointer;\n }\n\n copyFromMemory(ptr: number, length: number): Uint8Array {\n const buffer = this.exports.memory.buffer.slice(ptr, ptr + length);\n return new Uint8Array(buffer);\n }\n}\n","import {\n createIcmpMessage,\n parseIcmpMessage,\n type IcmpMessage,\n} from './icmp.js';\nimport { calculateChecksum } from './util.js';\n\nexport type IPv4Address = `${number}.${number}.${number}.${number}`;\nexport type IPv4Cidr = `${IPv4Address}/${number}`;\n\nexport type IPv4PacketBase = {\n version: number;\n dscp: number;\n ecn: number;\n identification: number;\n flags: number;\n fragmentOffset: number;\n ttl: number;\n protocol: string;\n sourceIP: IPv4Address;\n destinationIP: IPv4Address;\n};\n\nexport type IcmpIPv4Packet = IPv4PacketBase & {\n protocol: 'icmp';\n payload: IcmpMessage;\n};\n\nexport type TcpIPv4Packet = IPv4PacketBase & {\n protocol: 'tcp';\n payload: Uint8Array;\n};\n\nexport type UdpIPv4Packet = IPv4PacketBase & {\n protocol: 'udp';\n payload: Uint8Array;\n};\n\nexport type IPv4Packet = IcmpIPv4Packet | TcpIPv4Packet | UdpIPv4Packet;\n\nexport const IPV4_HEADER_LENGTH = 20;\n\n/**\n * Parses an IPv4 packet into an object.\n */\nexport function parseIPv4Packet(data: Uint8Array): IPv4Packet {\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n const headerChecksum = dataView.getUint16(10);\n const header = data.subarray(0, IPV4_HEADER_LENGTH);\n\n if (calculateChecksum(header, 10) !== headerChecksum) {\n throw new Error('invalid ipv4 checksum');\n }\n\n const totalLength = dataView.getUint16(2);\n\n if (totalLength !== data.length) {\n throw new Error('invalid ipv4 total length');\n }\n\n const versionAndHeaderLength = dataView.getUint8(0);\n const version = versionAndHeaderLength >> 4;\n const headerLength = (versionAndHeaderLength & 0xf) * 4;\n const dscp = dataView.getUint8(1) >> 2;\n const ecn = dataView.getUint8(1) & 0x3;\n const identification = dataView.getUint16(4);\n const flags = dataView.getUint8(6) >> 5;\n const fragmentOffset =\n ((dataView.getUint8(6) & 0x1f) << 8) | dataView.getUint8(7);\n const ttl = dataView.getUint8(8);\n const protocol = parseIPv4Protocol(dataView.getUint8(9));\n const sourceIP = parseIPv4Address(data.subarray(12, 16));\n const destinationIP = parseIPv4Address(data.subarray(16, 20));\n const payload = data.subarray(headerLength);\n\n switch (protocol) {\n case 'icmp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload: parseIcmpMessage(payload),\n };\n case 'tcp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload,\n };\n case 'udp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload,\n };\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\n/**\n * Serializes an IPv4 packet from an `IPv4Packet` object.\n */\nexport function createIPv4Packet(packet: IPv4Packet): Uint8Array {\n let payload: Uint8Array;\n\n switch (packet.protocol) {\n case 'icmp':\n payload = createIcmpMessage(packet.payload);\n break;\n case 'tcp':\n payload = packet.payload;\n break;\n case 'udp':\n payload = packet.payload;\n break;\n default:\n throw new Error('unknown ipv4 protocol');\n }\n\n const data = new Uint8Array(IPV4_HEADER_LENGTH + payload.length);\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n const totalLength = IPV4_HEADER_LENGTH + payload.length;\n\n dataView.setUint8(0, (packet.version << 4) | (IPV4_HEADER_LENGTH / 4));\n dataView.setUint8(1, (packet.dscp << 2) | packet.ecn);\n dataView.setUint16(2, totalLength);\n dataView.setUint16(4, packet.identification);\n dataView.setUint8(6, (packet.flags << 5) | (packet.fragmentOffset >> 8));\n dataView.setUint8(7, packet.fragmentOffset & 0xff);\n dataView.setUint8(8, packet.ttl);\n dataView.setUint8(9, serializeIPv4Protocol(packet.protocol));\n\n data.set(serializeIPv4Address(packet.sourceIP), 12);\n data.set(serializeIPv4Address(packet.destinationIP), 16);\n\n // Checksum applies to just the header\n const header = data.subarray(0, IPV4_HEADER_LENGTH);\n const checksum = calculateChecksum(header, 10);\n dataView.setUint16(10, checksum);\n\n data.set(payload, 20);\n\n return data;\n}\n\n/**\n * Parses an IPv4 address Uint8Array into a string.\n */\nexport function parseIPv4Address(data: Uint8Array) {\n return data.join('.') as IPv4Address;\n}\n\n/**\n * Serialize an IPv4 address string into a Uint8Array.\n */\nexport function serializeIPv4Address(ip: string) {\n return new Uint8Array(ip.split('.').map((byte) => parseInt(byte, 10)));\n}\n\nexport function parseIPv4Protocol(protocol: number) {\n switch (protocol) {\n case 1:\n return 'icmp';\n case 6:\n return 'tcp';\n case 17:\n return 'udp';\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\nexport function serializeIPv4Protocol(protocol: string) {\n switch (protocol) {\n case 'icmp':\n return 1;\n case 'tcp':\n return 6;\n case 'udp':\n return 17;\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\n/**\n * Serialize a CIDR notation string into an object with a\n * Uint8Array IP address and netmask.\n */\nexport function serializeIPv4Cidr(cidr: IPv4Cidr) {\n const [ipString, maskSizeString] = cidr.split('/');\n\n if (!ipString || !maskSizeString) {\n throw new Error('invalid cidr');\n }\n\n const maskSize = parseInt(maskSizeString, 10);\n const netmask = generateNetmask(maskSize);\n\n return {\n ipAddress: serializeIPv4Address(ipString),\n netmask,\n };\n}\n\n/**\n * Generates a netmask from a mask size.\n */\nexport function generateNetmask(maskSize: number) {\n const mask = new Uint8Array(4);\n\n for (let i = 0; i < maskSize; i++) {\n const byteIndex = Math.floor(i / 8);\n const bitIndex = 7 - (i % 8);\n const maskByte = mask[byteIndex];\n if (maskByte === undefined) {\n throw new Error('invalid mask size');\n }\n mask[byteIndex] = maskByte | (1 << bitIndex);\n }\n\n return mask;\n}\n","import { Bindings } from './base.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\n\ntype LoopbackInterfaceHandle = Pointer;\n\nexport type LoopbackImports = {\n register_loopback_interface(handle: LoopbackInterfaceHandle): void;\n};\n\nexport type LoopbackExports = {\n create_loopback_interface(\n ipAddress: Pointer,\n netmask: Pointer\n ): LoopbackInterfaceHandle;\n remove_loopback_interface(handle: LoopbackInterfaceHandle): void;\n};\n\nexport class LoopbackBindings extends Bindings<\n LoopbackImports,\n LoopbackExports\n> {\n interfaces = new Map<LoopbackInterfaceHandle, LoopbackInterface>();\n\n imports = {\n register_loopback_interface: (handle: LoopbackInterfaceHandle) => {\n const loopbackInterface = new LoopbackInterface();\n this.interfaces.set(handle, loopbackInterface);\n },\n };\n\n async create(options: LoopbackInterfaceOptions) {\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_loopback_interface(\n ipAddressPtr,\n netmaskPtr\n );\n\n const loopbackInterface = this.interfaces.get(handle);\n\n if (!loopbackInterface) {\n throw new Error('loopback interface failed to register');\n }\n\n return loopbackInterface;\n }\n\n async remove(loopbackInterface: LoopbackInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === loopbackInterface) {\n this.exports.remove_loopback_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type LoopbackInterfaceOptions = {\n ip: IPv4Cidr;\n};\nexport class LoopbackInterface {}\n","import { createArpMessage, parseArpMessage, type ArpMessage } from './arp.js';\nimport { createIPv4Packet, parseIPv4Packet, type IPv4Packet } from './ipv4.js';\n\nexport type MacAddress =\n `${string}:${string}:${string}:${string}:${string}:${string}`;\n\nexport type EthernetFrameBase = {\n destinationMac: MacAddress;\n sourceMac: MacAddress;\n};\n\nexport type IPv4EthernetFrame = EthernetFrameBase & {\n type: 'ipv4';\n payload: IPv4Packet;\n};\n\nexport type ARPEthernetFrame = EthernetFrameBase & {\n type: 'arp';\n payload: ArpMessage;\n};\n\n// TODO: IPv6EthernetFrame\nexport type EthernetFrame = IPv4EthernetFrame | ARPEthernetFrame;\n\n/**\n * Parses an Ethernet frame into an object.\n */\nexport function parseEthernetFrame(frame: Uint8Array): EthernetFrame {\n const destinationMacBytes = frame.subarray(0, 6);\n const sourceMacBytes = frame.subarray(6, 12);\n const typeBytes = frame.subarray(12, 14);\n const payload = frame.subarray(14);\n\n const destinationMac = parseMacAddress(destinationMacBytes);\n const sourceMac = parseMacAddress(sourceMacBytes);\n const type = parseEthernetType(typeBytes);\n\n switch (type) {\n case 'ipv4':\n return {\n destinationMac,\n sourceMac,\n type,\n payload: parseIPv4Packet(payload),\n };\n case 'arp':\n return {\n destinationMac,\n sourceMac,\n type,\n payload: parseArpMessage(payload),\n };\n default:\n throw new Error('unknown ethernet type');\n }\n}\n\n/**\n * Serializes an Ethernet frame from a Frame object.\n */\nexport function createEthernetFrame(frame: EthernetFrame): Uint8Array {\n let payload: Uint8Array;\n\n switch (frame.type) {\n case 'ipv4':\n payload = createIPv4Packet(frame.payload);\n break;\n break;\n case 'arp':\n payload = createArpMessage(frame.payload);\n break;\n default:\n throw new Error('unknown ethernet type');\n }\n\n const data = new Uint8Array(14 + payload.length);\n\n data.set(serializeMacAddress(frame.destinationMac), 0);\n data.set(serializeMacAddress(frame.sourceMac), 6);\n data.set(createEthernetType(frame.type), 12);\n data.set(payload, 14);\n\n return data;\n}\n\n/**\n * Parses a MAC address Uint8Array into a string.\n */\nexport function parseMacAddress(mac: Uint8Array) {\n if (mac.length !== 6) {\n throw new Error('invalid mac address');\n }\n\n return Array.from(mac)\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join(':') as MacAddress;\n}\n\n/**\n * Serializes a MAC address string into a Uint8Array.\n */\nexport function serializeMacAddress(mac: string) {\n const segments = mac.split(':');\n\n if (segments.length !== 6) {\n throw new Error('invalid mac address');\n }\n\n return new Uint8Array(\n segments.map((byte) => {\n const parsed = parseInt(byte, 16);\n if (Number.isNaN(parsed)) {\n throw new Error('invalid mac address');\n }\n return parsed;\n })\n );\n}\n\n/**\n * Parses an Ethernet type into a string.\n */\nexport function parseEthernetType(etherType: Uint8Array) {\n const dataView = new DataView(\n etherType.buffer,\n etherType.byteOffset,\n etherType.byteLength\n );\n\n const type = dataView.getUint16(0);\n\n switch (type) {\n case 0x0800:\n return 'ipv4';\n case 0x86dd:\n return 'ipv6';\n case 0x0806:\n return 'arp';\n default:\n throw new Error('unknown ethernet type');\n }\n}\n\n/**\n * Serializes an Ethernet type from a string.\n */\nexport function createEthernetType(type: 'ipv4' | 'ipv6' | 'arp') {\n const data = new Uint8Array(2);\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n switch (type) {\n case 'ipv4':\n dataView.setUint16(0, 0x0800);\n break;\n case 'ipv6':\n dataView.setUint16(0, 0x86dd);\n break;\n case 'arp':\n dataView.setUint16(0, 0x0806);\n break;\n default:\n throw new Error('unknown ethernet type');\n }\n\n return data;\n}\n","import { Bindings } from './base.js';\nimport { serializeMacAddress, type MacAddress } from '../protocols/ethernet.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport {\n ExtendedReadableStream,\n fromReadable,\n Hooks,\n nextMicrotask,\n} from '../util.js';\n\ntype TapInterfaceHandle = Pointer;\n\ntype TapInterfaceOuterHooks = {\n sendFrame(frame: Uint8Array): void;\n};\n\ntype TapInterfaceInnerHooks = {\n receiveFrame(frame: Uint8Array): void;\n};\n\nconst tapInterfaceHooks = new Hooks<\n TapInterface,\n TapInterfaceOuterHooks,\n TapInterfaceInnerHooks\n>();\n\nexport type TapImports = {\n register_tap_interface(handle: TapInterfaceHandle): void;\n receive_frame(\n handle: TapInterfaceHandle,\n framePtr: number,\n length: number\n ): Promise<void>;\n};\n\nexport type TapExports = {\n create_tap_interface(\n macAddress: Pointer,\n ipAddress: Pointer,\n netmask: Pointer\n ): TapInterfaceHandle;\n remove_tap_interface(handle: TapInterfaceHandle): void;\n send_tap_interface(\n handle: TapInterfaceHandle,\n frame: Pointer,\n length: number\n ): void;\n};\n\nexport class TapBindings extends Bindings<TapImports, TapExports> {\n interfaces = new Map<TapInterfaceHandle, TapInterface>();\n\n imports = {\n register_tap_interface: (handle: TapInterfaceHandle) => {\n const tapInterface = new TapInterface();\n\n tapInterfaceHooks.setOuter(tapInterface, {\n sendFrame: (frame) => {\n const framePtr = this.copyToMemory(frame);\n this.exports.send_tap_interface(handle, framePtr, frame.length);\n },\n });\n\n this.interfaces.set(handle, tapInterface);\n },\n receive_frame: async (\n handle: TapInterfaceHandle,\n framePtr: number,\n length: number\n ) => {\n const frame = this.copyFromMemory(framePtr, length);\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n // This also gives the consumer a chance to start listening before we enqueue the first frame\n await nextMicrotask();\n\n const tapInterface = this.interfaces.get(handle);\n\n if (!tapInterface) {\n console.error('received frame on unknown tap interface');\n return;\n }\n\n tapInterfaceHooks\n .getInner(tapInterface)\n .receiveFrame(new Uint8Array(frame));\n },\n };\n\n async create(options: TapInterfaceOptions) {\n const macAddress = serializeMacAddress(options.mac);\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using macAddressPtr = this.copyToMemory(macAddress);\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_tap_interface(\n macAddressPtr,\n ipAddressPtr,\n netmaskPtr\n );\n\n const tapInterface = this.interfaces.get(handle);\n\n if (!tapInterface) {\n throw new Error('tap interface failed to register');\n }\n\n return tapInterface;\n }\n\n async remove(tapInterface: TapInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === tapInterface) {\n this.exports.remove_tap_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type TapInterfaceOptions = {\n mac: MacAddress;\n ip: IPv4Cidr;\n};\n\nexport class TapInterface {\n #readableController?: ReadableStreamController<Uint8Array>;\n #isListening = false;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tapInterfaceHooks.setInner(this, {\n receiveFrame: async (frame: Uint8Array) => {\n // Do not buffer frames until the consumer signals intent\n // to listen - otherwise memory will grow indefinitely\n if (!this.#isListening) {\n return;\n }\n\n if (!this.#readableController) {\n throw new Error('readable stream not initialized');\n }\n\n this.#readableController?.enqueue(frame);\n },\n });\n\n this.readable = new ExtendedReadableStream<Uint8Array>({\n start: (controller) => {\n this.#readableController = controller;\n },\n lock: () => {\n // We interpret anything that locks the stream (getReader, pipeThrough, pipeTo, tee)\n // as intent to start listening\n this.#isListening = true;\n },\n });\n\n this.writable = new WritableStream({\n write: (packet) => {\n tapInterfaceHooks.getOuter(this).sendFrame(packet);\n },\n });\n }\n\n listen() {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {\n return this.listen();\n }\n}\n","// Intentionally not using enum to avoid need for a transpiler\nexport const LwipError = {\n ERR_OK: 0,\n ERR_MEM: -1,\n ERR_BUF: -2,\n ERR_TIMEOUT: -3,\n ERR_RTE: -4,\n ERR_INPROGRESS: -5,\n ERR_VAL: -6,\n ERR_WOULDBLOCK: -7,\n ERR_USE: -8,\n ERR_ALREADY: -9,\n ERR_ISCONN: -10,\n ERR_CONN: -11,\n ERR_IF: -12,\n ERR_ABRT: -13,\n ERR_RST: -14,\n ERR_CLSD: -15,\n ERR_ARG: -16,\n} as const;\n\nexport type LwipError = (typeof LwipError)[keyof typeof LwipError];\n","import { Bindings } from './base.js';\nimport { LwipError } from '../lwip/errors.js';\nimport { serializeIPv4Address, type IPv4Address } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport { EventMap, fromReadable, Hooks, nextMicrotask } from '../util.js';\n\ntype TcpListenerHandle = Pointer;\ntype TcpConnectionHandle = Pointer;\n\ntype TcpListenerOuterHooks = {};\n\ntype TcpListenerInnerHooks = {\n accept(connection: TcpConnection): void;\n};\n\ntype TcpConnectionOuterHooks = {\n send(data: Uint8Array): Promise<void>;\n updateReceiveBuffer(length: number): void;\n close(): Promise<void>;\n};\n\ntype TcpConnectionInnerHooks = {\n receive(data: Uint8Array): Promise<void>;\n close(): Promise<void>;\n};\n\nconst tcpListenerHooks = new Hooks<\n TcpListener,\n TcpListenerOuterHooks,\n TcpListenerInnerHooks\n>();\n\nconst tcpConnectionHooks = new Hooks<\n TcpConnection,\n TcpConnectionOuterHooks,\n TcpConnectionInnerHooks\n>();\n\nexport const MAX_SEGMENT_SIZE = 1460; // This must match TCP_MSS in lwipopts.h\nexport const MAX_WINDOW_SIZE = MAX_SEGMENT_SIZE * 4; // This must match TCP_WND in lwipopts.h\nexport const SEND_BUFFER_SIZE = MAX_SEGMENT_SIZE * 4; // This must match TCP_SND_BUF in lwipopts.h\nexport const READABLE_HIGH_WATER_MARK = MAX_SEGMENT_SIZE;\n\nexport type TcpImports = {\n accept_tcp_connection(\n listenerHandle: TcpListenerHandle,\n connectionHandle: TcpConnectionHandle\n ): Promise<void>;\n connected_tcp_connection(handle: TcpConnectionHandle): Promise<void>;\n closed_tcp_connection(handle: TcpConnectionHandle): Promise<void>;\n receive_tcp_chunk(\n handle: TcpConnectionHandle,\n chunkPtr: number,\n length: number\n ): Promise<void>;\n sent_tcp_chunk(handle: TcpConnectionHandle, length: number): void;\n};\n\nexport type TcpExports = {\n create_tcp_listener(host: Pointer | null, port: number): TcpListenerHandle;\n create_tcp_connection(host: Pointer, port: number): TcpConnectionHandle;\n close_tcp_connection(handle: TcpConnectionHandle): number;\n send_tcp_chunk(\n handle: TcpConnectionHandle,\n chunk: number,\n length: number\n ): number;\n update_tcp_receive_buffer(handle: TcpConnectionHandle, length: number): void;\n};\n\nexport class TcpBindings extends Bindings<TcpImports, TcpExports> {\n #tcpListeners = new Map<TcpListenerHandle, TcpListener>();\n #tcpConnections = new EventMap<TcpConnectionHandle, TcpConnection>();\n #tcpAcks = new Map<TcpConnectionHandle, (length: number) => void>();\n\n imports = {\n accept_tcp_connection: async (\n listenerHandle: TcpListenerHandle,\n connectionHandle: TcpConnectionHandle\n ) => {\n const listener = this.#tcpListeners.get(listenerHandle);\n\n if (!listener) {\n console.error('new tcp connection to unknown listener');\n return;\n }\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n const connection = new TcpConnection();\n\n tcpConnectionHooks.setOuter(connection, {\n send: async (data) => {\n const dataPtr = Number(this.copyToMemory(data));\n\n let bytesQueued = this.exports.send_tcp_chunk(\n connectionHandle,\n dataPtr,\n data.length\n );\n\n // If the entire data was not queued, send the remaining\n // chunks as space becomes available\n while (bytesQueued < data.length) {\n await new Promise<number>((resolve) => {\n this.#tcpAcks.set(connectionHandle, resolve);\n });\n const bytesRemaining = data.length - bytesQueued;\n\n bytesQueued += this.exports.send_tcp_chunk(\n connectionHandle,\n dataPtr + bytesQueued,\n bytesRemaining\n );\n }\n },\n updateReceiveBuffer: (length: number) => {\n this.exports.update_tcp_receive_buffer(connectionHandle, length);\n },\n close: async () => {\n const result = this.exports.close_tcp_connection(connectionHandle);\n\n if (result !== LwipError.ERR_OK) {\n throw new Error(`failed to close tcp connection: ${result}`);\n }\n },\n });\n\n this.#tcpConnections.set(connectionHandle, connection);\n\n tcpListenerHooks.getInner(listener).accept(connection);\n },\n connected_tcp_connection: async (handle: TcpConnectionHandle) => {\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n const connection = new TcpConnection();\n\n tcpConnectionHooks.setOuter(connection, {\n send: async (data) => {\n const dataPtr = Number(this.copyToMemory(data));\n\n let bytesQueued = this.exports.send_tcp_chunk(\n handle,\n dataPtr,\n data.length\n );\n\n // If the entire data was not queued, send the remaining\n // chunks as space becomes available\n while (bytesQueued < data.length) {\n await new Promise<number>((resolve) => {\n this.#tcpAcks.set(handle, resolve);\n });\n const bytesRemaining = data.length - bytesQueued;\n\n bytesQueued += this.exports.send_tcp_chunk(\n handle,\n dataPtr + bytesQueued,\n bytesRemaining\n );\n }\n },\n updateReceiveBuffer: (length: number) => {\n this.exports.update_tcp_receive_buffer(handle, length);\n },\n close: async () => {\n this.exports.close_tcp_connection(handle);\n },\n });\n\n this.#tcpConnections.set(handle, connection);\n },\n closed_tcp_connection: async (handle: TcpConnectionHandle) => {\n const connection = this.#tcpConnections.get(handle);\n\n if (!connection) {\n console.error('received close on unknown tcp connection');\n return;\n }\n\n await tcpConnectionHooks.getInner(connection).close();\n },\n receive_tcp_chunk: async (\n handle: TcpConnectionHandle,\n chunkPtr: number,\n length: number\n ) => {\n const chunk = this.copyFromMemory(chunkPtr, length);\n const connection = this.#tcpConnections.get(handle);\n\n if (!connection) {\n console.error('received chunk on unknown tcp connection');\n return;\n }\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n tcpConnectionHooks.getInner(connection).receive(new Uint8Array(chunk));\n },\n sent_tcp_chunk: (handle: TcpConnectionHandle, length: number) => {\n const notifyAck = this.#tcpAcks.get(handle);\n this.#tcpAcks.delete(handle);\n notifyAck?.(length);\n },\n };\n\n async listen(options: TcpListenerOptions) {\n using hostPtr = options.host\n ? this.copyToMemory(serializeIPv4Address(options.host))\n : null;\n\n const handle = this.exports.create_tcp_listener(hostPtr, options.port);\n\n const tcpListener = new TcpListener();\n\n tcpListenerHooks.setOuter(tcpListener, {});\n\n this.#tcpListeners.set(handle, tcpListener);\n\n return tcpListener;\n }\n\n async connect(options: TcpConnectionOptions) {\n using hostPtr = this.copyToMemory(serializeIPv4Address(options.host));\n\n const handle = this.exports.create_tcp_connection(hostPtr, options.port);\n\n const tcpConnection = await this.#tcpConnections.wait(handle);\n\n if (!tcpConnection) {\n throw new Error('tcp failed to connect');\n }\n\n return tcpConnection;\n }\n}\n\nexport type TcpListenerOptions = {\n host?: IPv4Address;\n port: number;\n};\n\nexport class TcpListener implements AsyncIterable<TcpConnection> {\n #connections: TcpConnection[] = [];\n #notifyConnection?: () => void;\n\n constructor() {\n tcpListenerHooks.setInner(this, {\n accept: async (connection: TcpConnection) => {\n this.#connections.push(connection);\n this.#notifyConnection?.();\n },\n });\n }\n\n async *[Symbol.asyncIterator](): AsyncIterableIterator<TcpConnection> {\n while (true) {\n await new Promise<void>((resolve) => {\n this.#notifyConnection = resolve;\n });\n\n yield* this.#connections;\n this.#connections = [];\n }\n }\n}\n\nexport type TcpConnectionOptions = {\n host: IPv4Address;\n port: number;\n};\n\nexport class TcpConnection implements AsyncIterable<Uint8Array> {\n #receiveBuffer: Uint8Array[] = [];\n #readableController?: ReadableStreamDefaultController<Uint8Array>;\n #writableController?: WritableStreamDefaultController;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tcpConnectionHooks.setInner(this, {\n receive: async (data: Uint8Array) => {\n // We maintain our own receive buffer prior to enqueueing to the readable\n // stream so that we can send window updates as data is consumed\n this.#receiveBuffer.push(data);\n this.#enqueueBuffer();\n },\n close: async () => {\n this.close();\n },\n });\n\n this.readable = new ReadableStream(\n {\n start: (controller) => {\n this.#readableController = controller;\n },\n pull: () => {\n this.#enqueueBuffer();\n },\n },\n {\n highWaterMark: READABLE_HIGH_WATER_MARK,\n size: (chunk) => chunk.byteLength,\n }\n );\n\n this.writable = new WritableStream(\n {\n start: (controller) => {\n this.#writableController = controller;\n },\n write: async (chunk) => {\n await tcpConnectionHooks.getOuter(this).send(chunk);\n },\n },\n {\n // Send buffer is managed by the TCP stack\n highWaterMark: 0,\n }\n );\n }\n\n #enqueueBuffer() {\n if (!this.#readableController?.desiredSize) {\n return;\n }\n\n let bytesEnqueued = 0;\n\n // Enqueue chunks until the desired size is reached\n while (this.#receiveBuffer.length > 0) {\n const chunkLength = this.#receiveBuffer[0]!.length;\n\n if (bytesEnqueued + chunkLength > this.#readableController.desiredSize) {\n break;\n }\n\n const chunk = this.#receiveBuffer.shift()!;\n this.#readableController.enqueue(chunk);\n bytesEnqueued += chunk.length;\n }\n\n // Notify the TCP stack that we've read the data\n if (bytesEnqueued > 0) {\n tcpConnectionHooks.getOuter(this).updateReceiveBuffer(bytesEnqueued);\n }\n }\n\n async close() {\n await tcpConnectionHooks.getOuter(this).close();\n this.#readableController?.error(new Error('tcp connection closed'));\n this.#writableController?.error(new Error('tcp connection closed'));\n }\n\n [Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n}\n","import { Bindings } from './base.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport {\n ExtendedReadableStream,\n fromReadable,\n Hooks,\n nextMicrotask,\n} from '../util.js';\n\ntype TunInterfaceHandle = Pointer;\n\ntype TunInterfaceOuterHooks = {\n sendPacket(packet: Uint8Array): void;\n};\n\ntype TunInterfaceInnerHooks = {\n receivePacket(packet: Uint8Array): void;\n};\n\nconst tunInterfaceHooks = new Hooks<\n TunInterface,\n TunInterfaceOuterHooks,\n TunInterfaceInnerHooks\n>();\n\nexport type TunImports = {\n register_tun_interface(handle: TunInterfaceHandle): void;\n receive_packet(\n handle: TunInterfaceHandle,\n packetPtr: number,\n length: number\n ): Promise<void>;\n};\n\nexport type TunExports = {\n create_tun_interface(\n ipAddress: Pointer,\n netmask: Pointer\n ): TunInterfaceHandle;\n remove_tun_interface(handle: TunInterfaceHandle): void;\n send_tun_interface(\n handle: TunInterfaceHandle,\n packet: Pointer,\n length: number\n ): void;\n};\n\nexport class TunBindings extends Bindings<TunImports, TunExports> {\n interfaces = new Map<TunInterfaceHandle, TunInterface>();\n\n imports = {\n register_tun_interface: (handle: TunInterfaceHandle) => {\n const tunInterface = new TunInterface();\n\n tunInterfaceHooks.setOuter(tunInterface, {\n sendPacket: (packet) => {\n const packetPtr = this.copyToMemory(packet);\n this.exports.send_tun_interface(handle, packetPtr, packet.length);\n },\n });\n\n this.interfaces.set(handle, tunInterface);\n },\n receive_packet: async (\n handle: TunInterfaceHandle,\n packetPtr: number,\n length: number\n ) => {\n const packet = this.copyFromMemory(packetPtr, length);\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n // This also gives the consumer a chance to start listening before we enqueue the first packet\n await nextMicrotask();\n\n const tunInterface = this.interfaces.get(handle);\n\n if (!tunInterface) {\n console.error('received packet on unknown tun interface');\n return;\n }\n\n tunInterfaceHooks\n .getInner(tunInterface)\n .receivePacket(new Uint8Array(packet));\n },\n };\n\n async create(options: TunInterfaceOptions) {\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_tun_interface(ipAddressPtr, netmaskPtr);\n\n const tunInterface = this.interfaces.get(handle);\n\n if (!tunInterface) {\n throw new Error('tun interface failed to register');\n }\n\n return tunInterface;\n }\n\n async remove(tunInterface: TunInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === tunInterface) {\n this.exports.remove_tun_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type TunInterfaceOptions = {\n ip: IPv4Cidr;\n};\n\nexport class TunInterface {\n #readableController?: ReadableStreamController<Uint8Array>;\n #isListening = false;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tunInterfaceHooks.setInner(this, {\n receivePacket: async (packet: Uint8Array) => {\n // Do not buffer packets until the consumer signals intent\n // to listen - otherwise memory will grow indefinitely\n if (!this.#isListening) {\n return;\n }\n\n if (!this.#readableController) {\n throw new Error('readable stream not initialized');\n }\n\n this.#readableController?.enqueue(packet);\n },\n });\n\n this.readable = new ExtendedReadableStream<Uint8Array>({\n start: (controller) => {\n this.#readableController = controller;\n },\n lock: () => {\n // We interpret anything that locks the stream (getReader, pipeThrough, pipeTo, tee)\n // as intent to start listening\n this.#isListening = true;\n },\n });\n\n this.writable = new WritableStream({\n write: (packet) => {\n tunInterfaceHooks.getOuter(this).sendPacket(packet);\n },\n });\n }\n\n listen() {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {\n return this.listen();\n }\n}\n","const IN_NODE =\n typeof process === 'object' &&\n typeof process.versions === 'object' &&\n typeof process.versions.node === 'string';\n\n/**\n * Fetches a file from the network or filesystem\n * depending on the environment.\n */\nexport async function fetchFile(input: string | URL, type: string) {\n if (IN_NODE) {\n return fetchFileNode(input, type);\n }\n return fetch(input);\n}\n\nasync function fetchFileNode(input: string | URL, type: string) {\n const fs = await import('node:fs');\n const { Readable } = await import('node:stream');\n const nodeStream = fs.createReadStream(input);\n const stream = Readable.toWeb(nodeStream) as ReadableStream<Uint8Array>;\n return new Response(stream, { headers: { 'Content-Type': type } });\n}\n"],"mappings":"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","names":["DisposeSymbol","AsyncDisposeSymbol","ConsoleStdout","File","OpenFile","WASI","Hooks","#outerHooks","#innerHooks","key","hooks","UniquePointer","address","free","DisposeSymbol","EventMap","#listeners","resolve","listeners","value","listener","fromReadable","readable","options","reader","fromReader","done","ExtendedReadableStream","#notifyLock","lock","underlyingSource","strategy","transform","stream","dest","promise","a","b","nextMicrotask","Bindings","#exports","exports","size","UniquePointer","data","length","pointer","ptr","buffer","serializeIPv4Address","ip","byte","serializeIPv4Cidr","cidr","ipString","maskSizeString","maskSize","netmask","generateNetmask","serializeIPv4Address","mask","i","byteIndex","bitIndex","maskByte","LoopbackBindings","Bindings","handle","loopbackInterface","LoopbackInterface","options","_stack","ipAddress","netmask","serializeIPv4Cidr","ipAddressPtr","__using","netmaskPtr","_","_error","_hasError","__callDispose","loopback","serializeMacAddress","mac","segments","byte","parsed","tapInterfaceHooks","Hooks","TapBindings","Bindings","handle","tapInterface","TapInterface","frame","framePtr","length","nextMicrotask","options","_stack","macAddress","serializeMacAddress","ipAddress","netmask","serializeIPv4Cidr","macAddressPtr","__using","ipAddressPtr","netmaskPtr","_","_error","_hasError","__callDispose","loopback","#readableController","#isListening","ExtendedReadableStream","controller","packet","fromReadable","LwipError","tcpListenerHooks","Hooks","tcpConnectionHooks","MAX_SEGMENT_SIZE","MAX_WINDOW_SIZE","SEND_BUFFER_SIZE","READABLE_HIGH_WATER_MARK","TcpBindings","Bindings","#tcpListeners","#tcpConnections","EventMap","#tcpAcks","listenerHandle","connectionHandle","listener","nextMicrotask","connection","TcpConnection","data","dataPtr","bytesQueued","resolve","bytesRemaining","length","result","LwipError","handle","chunkPtr","chunk","notifyAck","options","_stack","hostPtr","__using","serializeIPv4Address","tcpListener","TcpListener","_","_error","_hasError","__callDispose","tcpConnection","#connections","#notifyConnection","#receiveBuffer","#readableController","#writableController","#enqueueBuffer","controller","bytesEnqueued","chunkLength","fromReadable","tunInterfaceHooks","Hooks","TunBindings","Bindings","handle","tunInterface","TunInterface","packet","packetPtr","length","nextMicrotask","options","_stack","ipAddress","netmask","serializeIPv4Cidr","ipAddressPtr","__using","netmaskPtr","_","_error","_hasError","__callDispose","loopback","#readableController","#isListening","ExtendedReadableStream","controller","fromReadable","IN_NODE","fetchFile","input","type","fetchFileNode","fs","Readable","nodeStream","stream","createStack","options","stack","NetworkStack","#options","#loopIntervalId","#loopbackBindings","LoopbackBindings","#tunBindings","TunBindings","#tapBindings","TapBindings","#tcpBindings","TcpBindings","#listInterfaces","#init","wasi","WASI","OpenFile","File","ConsoleStdout","msg","source","fetchFile","instance","wasmInstance","result","netInterface","LoopbackInterface","TunInterface","TapInterface"]}
|
|
1
|
+
{"version":3,"sources":["../polyfills/disposable.ts","../src/stack.ts","../src/util.ts","../src/bindings/base.ts","../src/protocols/ipv4.ts","../src/bindings/loopback-interface.ts","../src/protocols/ethernet.ts","../src/bindings/tap-interface.ts","../src/lwip/errors.ts","../src/bindings/tcp.ts","../src/bindings/tun-interface.ts","../src/fetch-file.ts"],"sourcesContent":["/**\n * Scoped polyfill for `Symbol.dispose` without polluting the global scope.\n * Required for the `using` keyword which we use internally.\n * \n * We export this symbol as 'Symbol.dispose' which tells ESBuild to inject\n * it into the output bundle.\n * \n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` if the built-in `Symbol.dispose` is not available.\n */\n\nconst DisposeSymbol = 'dispose' in (Symbol as object) ? Symbol.dispose : Symbol.for('Symbol.dispose');\n\nexport {\n DisposeSymbol as 'Symbol.dispose'\n};\n","import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport {\n LoopbackBindings,\n LoopbackInterface,\n type LoopbackInterfaceOptions,\n} from './bindings/loopback-interface.js';\nimport {\n TapBindings,\n TapInterface,\n type TapInterfaceOptions,\n} from './bindings/tap-interface.js';\nimport {\n TcpBindings,\n type TcpConnectionOptions,\n type TcpListenerOptions,\n} from './bindings/tcp.js';\nimport {\n TunBindings,\n TunInterface,\n type TunInterfaceOptions,\n} from './bindings/tun-interface.js';\nimport { fetchFile } from './fetch-file.js';\nimport type { NetworkInterface, WasmInstance } from './types.js';\n\nexport async function createStack(options?: NetworkStackOptions) {\n const stack = new NetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n initializeLoopback?: boolean;\n};\n\nexport class NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n\n #loopbackBindings = new LoopbackBindings();\n #tunBindings = new TunBindings();\n #tapBindings = new TapBindings();\n #tcpBindings = new TcpBindings();\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#tcpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n\n const result = wasi.start(wasmInstance);\n\n if (result !== 0) {\n throw new Error(`wasi start failed with code ${result}`);\n }\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async removeInterface(\n netInterface: LoopbackInterface | TunInterface | TapInterface\n ) {\n await this.ready;\n\n if (netInterface instanceof LoopbackInterface) {\n return this.#loopbackBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TunInterface) {\n return this.#tunBindings.remove(netInterface);\n }\n\n if (netInterface instanceof TapInterface) {\n return this.#tapBindings.remove(netInterface);\n }\n\n throw new Error('unknown interface type');\n }\n\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n}\n","/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n","import type { SysExports, WasiExports } from '../types.js';\nimport { UniquePointer } from '../util.js';\n\nexport abstract class Bindings<Imports, Exports> {\n #exports?: Exports & WasiExports & SysExports;\n\n abstract imports: Imports;\n get exports(): Exports & WasiExports & SysExports {\n if (!this.#exports) {\n throw new Error('exports were not registered');\n }\n return this.#exports;\n }\n\n register(exports: Exports & WasiExports & SysExports) {\n this.#exports = exports;\n }\n\n smartMalloc(size: number) {\n return new UniquePointer(this.exports.malloc(size), this.exports.free);\n }\n\n copyToMemory(data: Uint8Array) {\n const length = data.length;\n const pointer = this.smartMalloc(length);\n\n const memoryView = new Uint8Array(\n this.exports.memory.buffer,\n pointer.valueOf(),\n length\n );\n\n memoryView.set(data);\n\n return pointer;\n }\n\n copyFromMemory(ptr: number, length: number): Uint8Array {\n const buffer = this.exports.memory.buffer.slice(ptr, ptr + length);\n return new Uint8Array(buffer);\n }\n}\n","import {\n createIcmpMessage,\n parseIcmpMessage,\n type IcmpMessage,\n} from './icmp.js';\nimport { calculateChecksum } from './util.js';\n\nexport type IPv4Address = `${number}.${number}.${number}.${number}`;\nexport type IPv4Cidr = `${IPv4Address}/${number}`;\n\nexport type IPv4PacketBase = {\n version: number;\n dscp: number;\n ecn: number;\n identification: number;\n flags: number;\n fragmentOffset: number;\n ttl: number;\n protocol: string;\n sourceIP: IPv4Address;\n destinationIP: IPv4Address;\n};\n\nexport type IcmpIPv4Packet = IPv4PacketBase & {\n protocol: 'icmp';\n payload: IcmpMessage;\n};\n\nexport type TcpIPv4Packet = IPv4PacketBase & {\n protocol: 'tcp';\n payload: Uint8Array;\n};\n\nexport type UdpIPv4Packet = IPv4PacketBase & {\n protocol: 'udp';\n payload: Uint8Array;\n};\n\nexport type IPv4Packet = IcmpIPv4Packet | TcpIPv4Packet | UdpIPv4Packet;\n\nexport const IPV4_HEADER_LENGTH = 20;\n\n/**\n * Parses an IPv4 packet into an object.\n */\nexport function parseIPv4Packet(data: Uint8Array): IPv4Packet {\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n const headerChecksum = dataView.getUint16(10);\n const header = data.subarray(0, IPV4_HEADER_LENGTH);\n\n if (calculateChecksum(header, 10) !== headerChecksum) {\n throw new Error('invalid ipv4 checksum');\n }\n\n const totalLength = dataView.getUint16(2);\n\n if (totalLength !== data.length) {\n throw new Error('invalid ipv4 total length');\n }\n\n const versionAndHeaderLength = dataView.getUint8(0);\n const version = versionAndHeaderLength >> 4;\n const headerLength = (versionAndHeaderLength & 0xf) * 4;\n const dscp = dataView.getUint8(1) >> 2;\n const ecn = dataView.getUint8(1) & 0x3;\n const identification = dataView.getUint16(4);\n const flags = dataView.getUint8(6) >> 5;\n const fragmentOffset =\n ((dataView.getUint8(6) & 0x1f) << 8) | dataView.getUint8(7);\n const ttl = dataView.getUint8(8);\n const protocol = parseIPv4Protocol(dataView.getUint8(9));\n const sourceIP = parseIPv4Address(data.subarray(12, 16));\n const destinationIP = parseIPv4Address(data.subarray(16, 20));\n const payload = data.subarray(headerLength);\n\n switch (protocol) {\n case 'icmp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload: parseIcmpMessage(payload),\n };\n case 'tcp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload,\n };\n case 'udp':\n return {\n version,\n dscp,\n ecn,\n identification,\n flags,\n fragmentOffset,\n ttl,\n protocol,\n sourceIP,\n destinationIP,\n payload,\n };\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\n/**\n * Serializes an IPv4 packet from an `IPv4Packet` object.\n */\nexport function createIPv4Packet(packet: IPv4Packet): Uint8Array {\n let payload: Uint8Array;\n\n switch (packet.protocol) {\n case 'icmp':\n payload = createIcmpMessage(packet.payload);\n break;\n case 'tcp':\n payload = packet.payload;\n break;\n case 'udp':\n payload = packet.payload;\n break;\n default:\n throw new Error('unknown ipv4 protocol');\n }\n\n const data = new Uint8Array(IPV4_HEADER_LENGTH + payload.length);\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n const totalLength = IPV4_HEADER_LENGTH + payload.length;\n\n dataView.setUint8(0, (packet.version << 4) | (IPV4_HEADER_LENGTH / 4));\n dataView.setUint8(1, (packet.dscp << 2) | packet.ecn);\n dataView.setUint16(2, totalLength);\n dataView.setUint16(4, packet.identification);\n dataView.setUint8(6, (packet.flags << 5) | (packet.fragmentOffset >> 8));\n dataView.setUint8(7, packet.fragmentOffset & 0xff);\n dataView.setUint8(8, packet.ttl);\n dataView.setUint8(9, serializeIPv4Protocol(packet.protocol));\n\n data.set(serializeIPv4Address(packet.sourceIP), 12);\n data.set(serializeIPv4Address(packet.destinationIP), 16);\n\n // Checksum applies to just the header\n const header = data.subarray(0, IPV4_HEADER_LENGTH);\n const checksum = calculateChecksum(header, 10);\n dataView.setUint16(10, checksum);\n\n data.set(payload, 20);\n\n return data;\n}\n\n/**\n * Parses an IPv4 address Uint8Array into a string.\n */\nexport function parseIPv4Address(data: Uint8Array) {\n return data.join('.') as IPv4Address;\n}\n\n/**\n * Serialize an IPv4 address string into a Uint8Array.\n */\nexport function serializeIPv4Address(ip: string) {\n return new Uint8Array(ip.split('.').map((byte) => parseInt(byte, 10)));\n}\n\nexport function parseIPv4Protocol(protocol: number) {\n switch (protocol) {\n case 1:\n return 'icmp';\n case 6:\n return 'tcp';\n case 17:\n return 'udp';\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\nexport function serializeIPv4Protocol(protocol: string) {\n switch (protocol) {\n case 'icmp':\n return 1;\n case 'tcp':\n return 6;\n case 'udp':\n return 17;\n default:\n throw new Error('unknown ipv4 protocol');\n }\n}\n\n/**\n * Serialize a CIDR notation string into an object with a\n * Uint8Array IP address and netmask.\n */\nexport function serializeIPv4Cidr(cidr: IPv4Cidr) {\n const [ipString, maskSizeString] = cidr.split('/');\n\n if (!ipString || !maskSizeString) {\n throw new Error('invalid cidr');\n }\n\n const maskSize = parseInt(maskSizeString, 10);\n const netmask = generateNetmask(maskSize);\n\n return {\n ipAddress: serializeIPv4Address(ipString),\n netmask,\n };\n}\n\n/**\n * Generates a netmask from a mask size.\n */\nexport function generateNetmask(maskSize: number) {\n const mask = new Uint8Array(4);\n\n for (let i = 0; i < maskSize; i++) {\n const byteIndex = Math.floor(i / 8);\n const bitIndex = 7 - (i % 8);\n const maskByte = mask[byteIndex];\n if (maskByte === undefined) {\n throw new Error('invalid mask size');\n }\n mask[byteIndex] = maskByte | (1 << bitIndex);\n }\n\n return mask;\n}\n","import { Bindings } from './base.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\n\ntype LoopbackInterfaceHandle = Pointer;\n\nexport type LoopbackImports = {\n register_loopback_interface(handle: LoopbackInterfaceHandle): void;\n};\n\nexport type LoopbackExports = {\n create_loopback_interface(\n ipAddress: Pointer,\n netmask: Pointer\n ): LoopbackInterfaceHandle;\n remove_loopback_interface(handle: LoopbackInterfaceHandle): void;\n};\n\nexport class LoopbackBindings extends Bindings<\n LoopbackImports,\n LoopbackExports\n> {\n interfaces = new Map<LoopbackInterfaceHandle, LoopbackInterface>();\n\n imports = {\n register_loopback_interface: (handle: LoopbackInterfaceHandle) => {\n const loopbackInterface = new LoopbackInterface();\n this.interfaces.set(handle, loopbackInterface);\n },\n };\n\n async create(options: LoopbackInterfaceOptions) {\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_loopback_interface(\n ipAddressPtr,\n netmaskPtr\n );\n\n const loopbackInterface = this.interfaces.get(handle);\n\n if (!loopbackInterface) {\n throw new Error('loopback interface failed to register');\n }\n\n return loopbackInterface;\n }\n\n async remove(loopbackInterface: LoopbackInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === loopbackInterface) {\n this.exports.remove_loopback_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type LoopbackInterfaceOptions = {\n ip: IPv4Cidr;\n};\nexport class LoopbackInterface {}\n","import { createArpMessage, parseArpMessage, type ArpMessage } from './arp.js';\nimport { createIPv4Packet, parseIPv4Packet, type IPv4Packet } from './ipv4.js';\n\nexport type MacAddress =\n `${string}:${string}:${string}:${string}:${string}:${string}`;\n\nexport type EthernetFrameBase = {\n destinationMac: MacAddress;\n sourceMac: MacAddress;\n};\n\nexport type IPv4EthernetFrame = EthernetFrameBase & {\n type: 'ipv4';\n payload: IPv4Packet;\n};\n\nexport type ARPEthernetFrame = EthernetFrameBase & {\n type: 'arp';\n payload: ArpMessage;\n};\n\n// TODO: IPv6EthernetFrame\nexport type EthernetFrame = IPv4EthernetFrame | ARPEthernetFrame;\n\n/**\n * Parses an Ethernet frame into an object.\n */\nexport function parseEthernetFrame(frame: Uint8Array): EthernetFrame {\n const destinationMacBytes = frame.subarray(0, 6);\n const sourceMacBytes = frame.subarray(6, 12);\n const typeBytes = frame.subarray(12, 14);\n const payload = frame.subarray(14);\n\n const destinationMac = parseMacAddress(destinationMacBytes);\n const sourceMac = parseMacAddress(sourceMacBytes);\n const type = parseEthernetType(typeBytes);\n\n switch (type) {\n case 'ipv4':\n return {\n destinationMac,\n sourceMac,\n type,\n payload: parseIPv4Packet(payload),\n };\n case 'arp':\n return {\n destinationMac,\n sourceMac,\n type,\n payload: parseArpMessage(payload),\n };\n default:\n throw new Error('unknown ethernet type');\n }\n}\n\n/**\n * Serializes an Ethernet frame from a Frame object.\n */\nexport function createEthernetFrame(frame: EthernetFrame): Uint8Array {\n let payload: Uint8Array;\n\n switch (frame.type) {\n case 'ipv4':\n payload = createIPv4Packet(frame.payload);\n break;\n break;\n case 'arp':\n payload = createArpMessage(frame.payload);\n break;\n default:\n throw new Error('unknown ethernet type');\n }\n\n const data = new Uint8Array(14 + payload.length);\n\n data.set(serializeMacAddress(frame.destinationMac), 0);\n data.set(serializeMacAddress(frame.sourceMac), 6);\n data.set(createEthernetType(frame.type), 12);\n data.set(payload, 14);\n\n return data;\n}\n\n/**\n * Parses a MAC address Uint8Array into a string.\n */\nexport function parseMacAddress(mac: Uint8Array) {\n if (mac.length !== 6) {\n throw new Error('invalid mac address');\n }\n\n return Array.from(mac)\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join(':') as MacAddress;\n}\n\n/**\n * Serializes a MAC address string into a Uint8Array.\n */\nexport function serializeMacAddress(mac: string) {\n const segments = mac.split(':');\n\n if (segments.length !== 6) {\n throw new Error('invalid mac address');\n }\n\n return new Uint8Array(\n segments.map((byte) => {\n const parsed = parseInt(byte, 16);\n if (Number.isNaN(parsed)) {\n throw new Error('invalid mac address');\n }\n return parsed;\n })\n );\n}\n\n/**\n * Parses an Ethernet type into a string.\n */\nexport function parseEthernetType(etherType: Uint8Array) {\n const dataView = new DataView(\n etherType.buffer,\n etherType.byteOffset,\n etherType.byteLength\n );\n\n const type = dataView.getUint16(0);\n\n switch (type) {\n case 0x0800:\n return 'ipv4';\n case 0x86dd:\n return 'ipv6';\n case 0x0806:\n return 'arp';\n default:\n throw new Error('unknown ethernet type');\n }\n}\n\n/**\n * Serializes an Ethernet type from a string.\n */\nexport function createEthernetType(type: 'ipv4' | 'ipv6' | 'arp') {\n const data = new Uint8Array(2);\n const dataView = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\n switch (type) {\n case 'ipv4':\n dataView.setUint16(0, 0x0800);\n break;\n case 'ipv6':\n dataView.setUint16(0, 0x86dd);\n break;\n case 'arp':\n dataView.setUint16(0, 0x0806);\n break;\n default:\n throw new Error('unknown ethernet type');\n }\n\n return data;\n}\n","import { Bindings } from './base.js';\nimport { serializeMacAddress, type MacAddress } from '../protocols/ethernet.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport {\n ExtendedReadableStream,\n fromReadable,\n Hooks,\n nextMicrotask,\n} from '../util.js';\n\ntype TapInterfaceHandle = Pointer;\n\ntype TapInterfaceOuterHooks = {\n sendFrame(frame: Uint8Array): void;\n};\n\ntype TapInterfaceInnerHooks = {\n receiveFrame(frame: Uint8Array): void;\n};\n\nconst tapInterfaceHooks = new Hooks<\n TapInterface,\n TapInterfaceOuterHooks,\n TapInterfaceInnerHooks\n>();\n\nexport type TapImports = {\n register_tap_interface(handle: TapInterfaceHandle): void;\n receive_frame(\n handle: TapInterfaceHandle,\n framePtr: number,\n length: number\n ): Promise<void>;\n};\n\nexport type TapExports = {\n create_tap_interface(\n macAddress: Pointer,\n ipAddress: Pointer,\n netmask: Pointer\n ): TapInterfaceHandle;\n remove_tap_interface(handle: TapInterfaceHandle): void;\n send_tap_interface(\n handle: TapInterfaceHandle,\n frame: Pointer,\n length: number\n ): void;\n};\n\nexport class TapBindings extends Bindings<TapImports, TapExports> {\n interfaces = new Map<TapInterfaceHandle, TapInterface>();\n\n imports = {\n register_tap_interface: (handle: TapInterfaceHandle) => {\n const tapInterface = new TapInterface();\n\n tapInterfaceHooks.setOuter(tapInterface, {\n sendFrame: (frame) => {\n const framePtr = this.copyToMemory(frame);\n this.exports.send_tap_interface(handle, framePtr, frame.length);\n },\n });\n\n this.interfaces.set(handle, tapInterface);\n },\n receive_frame: async (\n handle: TapInterfaceHandle,\n framePtr: number,\n length: number\n ) => {\n const frame = this.copyFromMemory(framePtr, length);\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n // This also gives the consumer a chance to start listening before we enqueue the first frame\n await nextMicrotask();\n\n const tapInterface = this.interfaces.get(handle);\n\n if (!tapInterface) {\n console.error('received frame on unknown tap interface');\n return;\n }\n\n tapInterfaceHooks\n .getInner(tapInterface)\n .receiveFrame(new Uint8Array(frame));\n },\n };\n\n async create(options: TapInterfaceOptions) {\n const macAddress = serializeMacAddress(options.mac);\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using macAddressPtr = this.copyToMemory(macAddress);\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_tap_interface(\n macAddressPtr,\n ipAddressPtr,\n netmaskPtr\n );\n\n const tapInterface = this.interfaces.get(handle);\n\n if (!tapInterface) {\n throw new Error('tap interface failed to register');\n }\n\n return tapInterface;\n }\n\n async remove(tapInterface: TapInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === tapInterface) {\n this.exports.remove_tap_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type TapInterfaceOptions = {\n mac: MacAddress;\n ip: IPv4Cidr;\n};\n\nexport class TapInterface {\n #readableController?: ReadableStreamController<Uint8Array>;\n #isListening = false;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tapInterfaceHooks.setInner(this, {\n receiveFrame: async (frame: Uint8Array) => {\n // Do not buffer frames until the consumer signals intent\n // to listen - otherwise memory will grow indefinitely\n if (!this.#isListening) {\n return;\n }\n\n if (!this.#readableController) {\n throw new Error('readable stream not initialized');\n }\n\n this.#readableController?.enqueue(frame);\n },\n });\n\n this.readable = new ExtendedReadableStream<Uint8Array>({\n start: (controller) => {\n this.#readableController = controller;\n },\n lock: () => {\n // We interpret anything that locks the stream (getReader, pipeThrough, pipeTo, tee)\n // as intent to start listening\n this.#isListening = true;\n },\n });\n\n this.writable = new WritableStream({\n write: (packet) => {\n tapInterfaceHooks.getOuter(this).sendFrame(packet);\n },\n });\n }\n\n listen() {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {\n return this.listen();\n }\n}\n","// Intentionally not using enum to avoid need for a transpiler\nexport const LwipError = {\n ERR_OK: 0,\n ERR_MEM: -1,\n ERR_BUF: -2,\n ERR_TIMEOUT: -3,\n ERR_RTE: -4,\n ERR_INPROGRESS: -5,\n ERR_VAL: -6,\n ERR_WOULDBLOCK: -7,\n ERR_USE: -8,\n ERR_ALREADY: -9,\n ERR_ISCONN: -10,\n ERR_CONN: -11,\n ERR_IF: -12,\n ERR_ABRT: -13,\n ERR_RST: -14,\n ERR_CLSD: -15,\n ERR_ARG: -16,\n} as const;\n\nexport type LwipError = (typeof LwipError)[keyof typeof LwipError];\n","import { Bindings } from './base.js';\nimport { LwipError } from '../lwip/errors.js';\nimport { serializeIPv4Address, type IPv4Address } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport { EventMap, fromReadable, Hooks, nextMicrotask } from '../util.js';\n\ntype TcpListenerHandle = Pointer;\ntype TcpConnectionHandle = Pointer;\n\ntype TcpListenerOuterHooks = {};\n\ntype TcpListenerInnerHooks = {\n accept(connection: TcpConnection): void;\n};\n\ntype TcpConnectionOuterHooks = {\n send(data: Uint8Array): Promise<void>;\n updateReceiveBuffer(length: number): void;\n close(): Promise<void>;\n};\n\ntype TcpConnectionInnerHooks = {\n receive(data: Uint8Array): Promise<void>;\n close(): Promise<void>;\n};\n\nconst tcpListenerHooks = new Hooks<\n TcpListener,\n TcpListenerOuterHooks,\n TcpListenerInnerHooks\n>();\n\nconst tcpConnectionHooks = new Hooks<\n TcpConnection,\n TcpConnectionOuterHooks,\n TcpConnectionInnerHooks\n>();\n\nexport const MAX_SEGMENT_SIZE = 1460; // This must match TCP_MSS in lwipopts.h\nexport const MAX_WINDOW_SIZE = MAX_SEGMENT_SIZE * 4; // This must match TCP_WND in lwipopts.h\nexport const SEND_BUFFER_SIZE = MAX_SEGMENT_SIZE * 4; // This must match TCP_SND_BUF in lwipopts.h\nexport const READABLE_HIGH_WATER_MARK = MAX_SEGMENT_SIZE;\n\nexport type TcpImports = {\n accept_tcp_connection(\n listenerHandle: TcpListenerHandle,\n connectionHandle: TcpConnectionHandle\n ): Promise<void>;\n connected_tcp_connection(handle: TcpConnectionHandle): Promise<void>;\n closed_tcp_connection(handle: TcpConnectionHandle): Promise<void>;\n receive_tcp_chunk(\n handle: TcpConnectionHandle,\n chunkPtr: number,\n length: number\n ): Promise<void>;\n sent_tcp_chunk(handle: TcpConnectionHandle, length: number): void;\n};\n\nexport type TcpExports = {\n create_tcp_listener(host: Pointer | null, port: number): TcpListenerHandle;\n create_tcp_connection(host: Pointer, port: number): TcpConnectionHandle;\n close_tcp_connection(handle: TcpConnectionHandle): number;\n send_tcp_chunk(\n handle: TcpConnectionHandle,\n chunk: number,\n length: number\n ): number;\n update_tcp_receive_buffer(handle: TcpConnectionHandle, length: number): void;\n};\n\nexport class TcpBindings extends Bindings<TcpImports, TcpExports> {\n #tcpListeners = new Map<TcpListenerHandle, TcpListener>();\n #tcpConnections = new EventMap<TcpConnectionHandle, TcpConnection>();\n #tcpAcks = new Map<TcpConnectionHandle, (length: number) => void>();\n\n imports = {\n accept_tcp_connection: async (\n listenerHandle: TcpListenerHandle,\n connectionHandle: TcpConnectionHandle\n ) => {\n const listener = this.#tcpListeners.get(listenerHandle);\n\n if (!listener) {\n console.error('new tcp connection to unknown listener');\n return;\n }\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n const connection = new TcpConnection();\n\n tcpConnectionHooks.setOuter(connection, {\n send: async (data) => {\n const dataPtr = Number(this.copyToMemory(data));\n\n let bytesQueued = this.exports.send_tcp_chunk(\n connectionHandle,\n dataPtr,\n data.length\n );\n\n // If the entire data was not queued, send the remaining\n // chunks as space becomes available\n while (bytesQueued < data.length) {\n await new Promise<number>((resolve) => {\n this.#tcpAcks.set(connectionHandle, resolve);\n });\n const bytesRemaining = data.length - bytesQueued;\n\n bytesQueued += this.exports.send_tcp_chunk(\n connectionHandle,\n dataPtr + bytesQueued,\n bytesRemaining\n );\n }\n },\n updateReceiveBuffer: (length: number) => {\n this.exports.update_tcp_receive_buffer(connectionHandle, length);\n },\n close: async () => {\n const result = this.exports.close_tcp_connection(connectionHandle);\n\n if (result !== LwipError.ERR_OK) {\n throw new Error(`failed to close tcp connection: ${result}`);\n }\n },\n });\n\n this.#tcpConnections.set(connectionHandle, connection);\n\n tcpListenerHooks.getInner(listener).accept(connection);\n },\n connected_tcp_connection: async (handle: TcpConnectionHandle) => {\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n const connection = new TcpConnection();\n\n tcpConnectionHooks.setOuter(connection, {\n send: async (data) => {\n const dataPtr = Number(this.copyToMemory(data));\n\n let bytesQueued = this.exports.send_tcp_chunk(\n handle,\n dataPtr,\n data.length\n );\n\n // If the entire data was not queued, send the remaining\n // chunks as space becomes available\n while (bytesQueued < data.length) {\n await new Promise<number>((resolve) => {\n this.#tcpAcks.set(handle, resolve);\n });\n const bytesRemaining = data.length - bytesQueued;\n\n bytesQueued += this.exports.send_tcp_chunk(\n handle,\n dataPtr + bytesQueued,\n bytesRemaining\n );\n }\n },\n updateReceiveBuffer: (length: number) => {\n this.exports.update_tcp_receive_buffer(handle, length);\n },\n close: async () => {\n this.exports.close_tcp_connection(handle);\n },\n });\n\n this.#tcpConnections.set(handle, connection);\n },\n closed_tcp_connection: async (handle: TcpConnectionHandle) => {\n const connection = this.#tcpConnections.get(handle);\n\n if (!connection) {\n console.error('received close on unknown tcp connection');\n return;\n }\n\n await tcpConnectionHooks.getInner(connection).close();\n },\n receive_tcp_chunk: async (\n handle: TcpConnectionHandle,\n chunkPtr: number,\n length: number\n ) => {\n const chunk = this.copyFromMemory(chunkPtr, length);\n const connection = this.#tcpConnections.get(handle);\n\n if (!connection) {\n console.error('received chunk on unknown tcp connection');\n return;\n }\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n await nextMicrotask();\n\n tcpConnectionHooks.getInner(connection).receive(new Uint8Array(chunk));\n },\n sent_tcp_chunk: (handle: TcpConnectionHandle, length: number) => {\n const notifyAck = this.#tcpAcks.get(handle);\n this.#tcpAcks.delete(handle);\n notifyAck?.(length);\n },\n };\n\n async listen(options: TcpListenerOptions) {\n using hostPtr = options.host\n ? this.copyToMemory(serializeIPv4Address(options.host))\n : null;\n\n const handle = this.exports.create_tcp_listener(hostPtr, options.port);\n\n const tcpListener = new TcpListener();\n\n tcpListenerHooks.setOuter(tcpListener, {});\n\n this.#tcpListeners.set(handle, tcpListener);\n\n return tcpListener;\n }\n\n async connect(options: TcpConnectionOptions) {\n using hostPtr = this.copyToMemory(serializeIPv4Address(options.host));\n\n const handle = this.exports.create_tcp_connection(hostPtr, options.port);\n\n const tcpConnection = await this.#tcpConnections.wait(handle);\n\n if (!tcpConnection) {\n throw new Error('tcp failed to connect');\n }\n\n return tcpConnection;\n }\n}\n\nexport type TcpListenerOptions = {\n host?: IPv4Address;\n port: number;\n};\n\nexport class TcpListener implements AsyncIterable<TcpConnection> {\n #connections: TcpConnection[] = [];\n #notifyConnection?: () => void;\n\n constructor() {\n tcpListenerHooks.setInner(this, {\n accept: async (connection: TcpConnection) => {\n this.#connections.push(connection);\n this.#notifyConnection?.();\n },\n });\n }\n\n async *[Symbol.asyncIterator](): AsyncIterableIterator<TcpConnection> {\n while (true) {\n await new Promise<void>((resolve) => {\n this.#notifyConnection = resolve;\n });\n\n yield* this.#connections;\n this.#connections = [];\n }\n }\n}\n\nexport type TcpConnectionOptions = {\n host: IPv4Address;\n port: number;\n};\n\nexport class TcpConnection implements AsyncIterable<Uint8Array> {\n #receiveBuffer: Uint8Array[] = [];\n #readableController?: ReadableStreamDefaultController<Uint8Array>;\n #writableController?: WritableStreamDefaultController;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tcpConnectionHooks.setInner(this, {\n receive: async (data: Uint8Array) => {\n // We maintain our own receive buffer prior to enqueueing to the readable\n // stream so that we can send window updates as data is consumed\n this.#receiveBuffer.push(data);\n this.#enqueueBuffer();\n },\n close: async () => {\n this.close();\n },\n });\n\n this.readable = new ReadableStream(\n {\n start: (controller) => {\n this.#readableController = controller;\n },\n pull: () => {\n this.#enqueueBuffer();\n },\n },\n {\n highWaterMark: READABLE_HIGH_WATER_MARK,\n size: (chunk) => chunk.byteLength,\n }\n );\n\n this.writable = new WritableStream(\n {\n start: (controller) => {\n this.#writableController = controller;\n },\n write: async (chunk) => {\n await tcpConnectionHooks.getOuter(this).send(chunk);\n },\n },\n {\n // Send buffer is managed by the TCP stack\n highWaterMark: 0,\n }\n );\n }\n\n #enqueueBuffer() {\n if (!this.#readableController?.desiredSize) {\n return;\n }\n\n let bytesEnqueued = 0;\n\n // Enqueue chunks until the desired size is reached\n while (this.#receiveBuffer.length > 0) {\n const chunkLength = this.#receiveBuffer[0]!.length;\n\n if (bytesEnqueued + chunkLength > this.#readableController.desiredSize) {\n break;\n }\n\n const chunk = this.#receiveBuffer.shift()!;\n this.#readableController.enqueue(chunk);\n bytesEnqueued += chunk.length;\n }\n\n // Notify the TCP stack that we've read the data\n if (bytesEnqueued > 0) {\n tcpConnectionHooks.getOuter(this).updateReceiveBuffer(bytesEnqueued);\n }\n }\n\n async close() {\n await tcpConnectionHooks.getOuter(this).close();\n this.#readableController?.error(new Error('tcp connection closed'));\n this.#writableController?.error(new Error('tcp connection closed'));\n }\n\n [Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n}\n","import { Bindings } from './base.js';\nimport { serializeIPv4Cidr, type IPv4Cidr } from '../protocols/ipv4.js';\nimport type { Pointer } from '../types.js';\nimport {\n ExtendedReadableStream,\n fromReadable,\n Hooks,\n nextMicrotask,\n} from '../util.js';\n\ntype TunInterfaceHandle = Pointer;\n\ntype TunInterfaceOuterHooks = {\n sendPacket(packet: Uint8Array): void;\n};\n\ntype TunInterfaceInnerHooks = {\n receivePacket(packet: Uint8Array): void;\n};\n\nconst tunInterfaceHooks = new Hooks<\n TunInterface,\n TunInterfaceOuterHooks,\n TunInterfaceInnerHooks\n>();\n\nexport type TunImports = {\n register_tun_interface(handle: TunInterfaceHandle): void;\n receive_packet(\n handle: TunInterfaceHandle,\n packetPtr: number,\n length: number\n ): Promise<void>;\n};\n\nexport type TunExports = {\n create_tun_interface(\n ipAddress: Pointer,\n netmask: Pointer\n ): TunInterfaceHandle;\n remove_tun_interface(handle: TunInterfaceHandle): void;\n send_tun_interface(\n handle: TunInterfaceHandle,\n packet: Pointer,\n length: number\n ): void;\n};\n\nexport class TunBindings extends Bindings<TunImports, TunExports> {\n interfaces = new Map<TunInterfaceHandle, TunInterface>();\n\n imports = {\n register_tun_interface: (handle: TunInterfaceHandle) => {\n const tunInterface = new TunInterface();\n\n tunInterfaceHooks.setOuter(tunInterface, {\n sendPacket: (packet) => {\n const packetPtr = this.copyToMemory(packet);\n this.exports.send_tun_interface(handle, packetPtr, packet.length);\n },\n });\n\n this.interfaces.set(handle, tunInterface);\n },\n receive_packet: async (\n handle: TunInterfaceHandle,\n packetPtr: number,\n length: number\n ) => {\n const packet = this.copyFromMemory(packetPtr, length);\n\n // Wait for synchronous lwIP operations to complete to prevent reentrancy issues\n // This also gives the consumer a chance to start listening before we enqueue the first packet\n await nextMicrotask();\n\n const tunInterface = this.interfaces.get(handle);\n\n if (!tunInterface) {\n console.error('received packet on unknown tun interface');\n return;\n }\n\n tunInterfaceHooks\n .getInner(tunInterface)\n .receivePacket(new Uint8Array(packet));\n },\n };\n\n async create(options: TunInterfaceOptions) {\n const { ipAddress, netmask } = serializeIPv4Cidr(options.ip);\n\n using ipAddressPtr = this.copyToMemory(ipAddress);\n using netmaskPtr = this.copyToMemory(netmask);\n\n const handle = this.exports.create_tun_interface(ipAddressPtr, netmaskPtr);\n\n const tunInterface = this.interfaces.get(handle);\n\n if (!tunInterface) {\n throw new Error('tun interface failed to register');\n }\n\n return tunInterface;\n }\n\n async remove(tunInterface: TunInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === tunInterface) {\n this.exports.remove_tun_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type TunInterfaceOptions = {\n ip: IPv4Cidr;\n};\n\nexport class TunInterface {\n #readableController?: ReadableStreamController<Uint8Array>;\n #isListening = false;\n\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n\n constructor() {\n tunInterfaceHooks.setInner(this, {\n receivePacket: async (packet: Uint8Array) => {\n // Do not buffer packets until the consumer signals intent\n // to listen - otherwise memory will grow indefinitely\n if (!this.#isListening) {\n return;\n }\n\n if (!this.#readableController) {\n throw new Error('readable stream not initialized');\n }\n\n this.#readableController?.enqueue(packet);\n },\n });\n\n this.readable = new ExtendedReadableStream<Uint8Array>({\n start: (controller) => {\n this.#readableController = controller;\n },\n lock: () => {\n // We interpret anything that locks the stream (getReader, pipeThrough, pipeTo, tee)\n // as intent to start listening\n this.#isListening = true;\n },\n });\n\n this.writable = new WritableStream({\n write: (packet) => {\n tunInterfaceHooks.getOuter(this).sendPacket(packet);\n },\n });\n }\n\n listen() {\n if (this.readable.locked) {\n throw new Error('readable stream already locked');\n }\n return fromReadable(this.readable);\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {\n return this.listen();\n }\n}\n","const IN_NODE =\n typeof process === 'object' &&\n typeof process.versions === 'object' &&\n typeof process.versions.node === 'string';\n\n/**\n * Fetches a file from the network or filesystem\n * depending on the environment.\n */\nexport async function fetchFile(input: string | URL, type: string) {\n if (IN_NODE) {\n return fetchFileNode(input, type);\n }\n return fetch(input);\n}\n\nasync function fetchFileNode(input: string | URL, type: string) {\n const fs = await import('node:fs');\n const { Readable } = await import('node:stream');\n const nodeStream = fs.createReadStream(input);\n const stream = Readable.toWeb(nodeStream) as ReadableStream<Uint8Array>;\n return new Response(stream, { headers: { 'Content-Type': type } });\n}\n"],"mappings":"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","names":["DisposeSymbol","ConsoleStdout","File","OpenFile","WASI","Hooks","#outerHooks","#innerHooks","key","hooks","UniquePointer","address","free","DisposeSymbol","EventMap","#listeners","resolve","listeners","value","listener","fromReadable","readable","options","reader","fromReader","done","ExtendedReadableStream","#notifyLock","lock","underlyingSource","strategy","transform","stream","dest","promise","a","b","nextMicrotask","Bindings","#exports","exports","size","UniquePointer","data","length","pointer","ptr","buffer","serializeIPv4Address","ip","byte","serializeIPv4Cidr","cidr","ipString","maskSizeString","maskSize","netmask","generateNetmask","serializeIPv4Address","mask","i","byteIndex","bitIndex","maskByte","LoopbackBindings","Bindings","handle","loopbackInterface","LoopbackInterface","options","_stack","ipAddress","netmask","serializeIPv4Cidr","ipAddressPtr","__using","netmaskPtr","_","_error","_hasError","__callDispose","loopback","serializeMacAddress","mac","segments","byte","parsed","tapInterfaceHooks","Hooks","TapBindings","Bindings","handle","tapInterface","TapInterface","frame","framePtr","length","nextMicrotask","options","_stack","macAddress","serializeMacAddress","ipAddress","netmask","serializeIPv4Cidr","macAddressPtr","__using","ipAddressPtr","netmaskPtr","_","_error","_hasError","__callDispose","loopback","#readableController","#isListening","ExtendedReadableStream","controller","packet","fromReadable","LwipError","tcpListenerHooks","Hooks","tcpConnectionHooks","MAX_SEGMENT_SIZE","MAX_WINDOW_SIZE","SEND_BUFFER_SIZE","READABLE_HIGH_WATER_MARK","TcpBindings","Bindings","#tcpListeners","#tcpConnections","EventMap","#tcpAcks","listenerHandle","connectionHandle","listener","nextMicrotask","connection","TcpConnection","data","dataPtr","bytesQueued","resolve","bytesRemaining","length","result","LwipError","handle","chunkPtr","chunk","notifyAck","options","_stack","hostPtr","__using","serializeIPv4Address","tcpListener","TcpListener","_","_error","_hasError","__callDispose","tcpConnection","#connections","#notifyConnection","#receiveBuffer","#readableController","#writableController","#enqueueBuffer","controller","bytesEnqueued","chunkLength","fromReadable","tunInterfaceHooks","Hooks","TunBindings","Bindings","handle","tunInterface","TunInterface","packet","packetPtr","length","nextMicrotask","options","_stack","ipAddress","netmask","serializeIPv4Cidr","ipAddressPtr","__using","netmaskPtr","_","_error","_hasError","__callDispose","loopback","#readableController","#isListening","ExtendedReadableStream","controller","fromReadable","IN_NODE","fetchFile","input","type","fetchFileNode","fs","Readable","nodeStream","stream","createStack","options","stack","NetworkStack","#options","#loopIntervalId","#loopbackBindings","LoopbackBindings","#tunBindings","TunBindings","#tapBindings","TapBindings","#tcpBindings","TcpBindings","#listInterfaces","#init","wasi","WASI","OpenFile","File","ConsoleStdout","msg","source","fetchFile","instance","wasmInstance","result","netInterface","LoopbackInterface","TunInterface","TapInterface"]}
|