feat(core): event queue, Ethernet, switch, ARP, IPv4, ICMP, routing and firewall
First slice of the TypeScript port of the filius-ipad runtime engine, with 29 tests ported from the Swift suite. Parts not ported yet throw NotPortedError instead of guessing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
// Ported from filius-ipad (GPLv2/GPLv3):
|
||||
// State/TopologyNetworkRuntimeEngine.swift (parseIPv4, sameSubnet)
|
||||
// State/TopologyEditorState.swift (TopologyRuntimeManualRoute.parseIPv4)
|
||||
//
|
||||
// Two parsers exist on purpose, as in the Swift source: the runtime reads an
|
||||
// octet the way Swift's `UInt8(String)` does, the route editor the way Java
|
||||
// FILIUS validates its table cells (see routeTable.ts).
|
||||
|
||||
/**
|
||||
* Swift `UInt8(segment)`: an optional sign, then decimal digits, value 0…255.
|
||||
* Leading zeros are allowed ("007" is 7), whitespace is not.
|
||||
*/
|
||||
function parseSwiftOctet(segment: string): number | undefined {
|
||||
if (!/^[+-]?[0-9]+$/.test(segment)) return undefined;
|
||||
const value = Number(segment);
|
||||
if (!Number.isInteger(value) || value < 0 || value > 255) return undefined;
|
||||
return Object.is(value, -0) ? 0 : value;
|
||||
}
|
||||
|
||||
/** Dotted quad to an unsigned 32-bit number, or undefined. */
|
||||
export function parseIPv4(value: string): number | undefined {
|
||||
const segments = value.split('.');
|
||||
if (segments.length !== 4) return undefined;
|
||||
let address = 0;
|
||||
for (const segment of segments) {
|
||||
const octet = parseSwiftOctet(segment);
|
||||
if (octet === undefined) return undefined;
|
||||
address = ((address << 8) | octet) >>> 0;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
export function formatIPv4(address: number): string {
|
||||
return [24, 16, 8, 0].map((shift) => String((address >>> shift) & 0xff)).join('.');
|
||||
}
|
||||
|
||||
export function sameSubnet(lhs: string, rhs: string, mask: string): boolean {
|
||||
const left = parseIPv4(lhs);
|
||||
const right = parseIPv4(rhs);
|
||||
const netmask = parseIPv4(mask);
|
||||
if (left === undefined || right === undefined || netmask === undefined) return false;
|
||||
return ((left & netmask) >>> 0) === ((right & netmask) >>> 0);
|
||||
}
|
||||
|
||||
/** `address & mask` as an unsigned number. */
|
||||
export function maskAddress(address: number, mask: number): number {
|
||||
return (address & mask) >>> 0;
|
||||
}
|
||||
Reference in New Issue
Block a user