feat(core): modems run — the pair in the project, and a modem of another project hands its frames on (K0–K2)
Measured first: tools/java-oracle's ModemRun joins two networks by a pair of Java modems over TCP on localhost. The modem has no card and adds no delay of its own — a frame takes the cables on both sides, nothing more. The core pairs the two enabled modems on a port (Swift's inProject, with its conditions and cycle suppression) on Java's timing: no 20 ms. The modem example of FILIUS now pings through instead of failing the core. A modem of another project (relay) gives its frames to whoever runs the engine and puts on its cable what comes back, with this engine's frame and packet numbers; a frame dies after MAXIMUM_RELAY_HOPS trips. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
// Runs a story on modem-lan's network in Java FILIUS (ScenarioNetwork): two
|
||||
// networks joined by a pair of modems, a server and a client on localhost
|
||||
// (ModemFirmware over a real TCP socket). Records every frame each card saw
|
||||
// and when each call started and ended.
|
||||
//
|
||||
// ModemRun <scenario.json> <story> <milliseconds> <out.json>
|
||||
//
|
||||
// 10.0.0.1 and 10.0.0.3 sit on a switch with the server modem; 10.0.0.2 is
|
||||
// cabled straight to the client modem. The stories:
|
||||
// ping the modems connected, 10.0.0.1 pings 10.0.0.2 twice
|
||||
// unconnected the modems not connected, 10.0.0.1 pings 10.0.0.2: ARP
|
||||
// goes into the modem and no further
|
||||
|
||||
import filius.software.vermittlungsschicht.IcmpPaket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ModemRun {
|
||||
static final String HOST = "00000000-0000-0000-0000-000000000401";
|
||||
|
||||
static ScenarioNetwork network;
|
||||
static final List<Object[]> events = new ArrayList<>();
|
||||
|
||||
interface Call {
|
||||
String run() throws Exception;
|
||||
}
|
||||
|
||||
static synchronized void event(String what) {
|
||||
events.add(new Object[] { System.currentTimeMillis() - network.start, what });
|
||||
}
|
||||
|
||||
static void call(String label, Call call) {
|
||||
event(label + " called");
|
||||
try {
|
||||
event(label + " returned " + call.run());
|
||||
} catch (Exception e) {
|
||||
event(label + " failed " + e.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
static String icmp(IcmpPaket packet) {
|
||||
return packet == null ? "null" : "ICMP " + packet.getIcmpType() + "/" + packet.getIcmpCode() + " from " + packet.getSender();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
network = ScenarioNetwork.read(args[0]);
|
||||
String story = args[1];
|
||||
long end = Long.parseLong(args[2]);
|
||||
// Connected in the design, as one does with the settings panel's button before starting.
|
||||
if (!story.equals("unconnected")) network.connectModems();
|
||||
network.start();
|
||||
Thread.sleep(500);
|
||||
switch (story) {
|
||||
case "ping":
|
||||
call("sendProbe 10.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("10.0.0.2", 64, 1, 1)));
|
||||
call("sendProbe 10.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("10.0.0.2", 64, 1, 2)));
|
||||
break;
|
||||
case "unconnected":
|
||||
call("sendProbe 10.0.0.2", () -> icmp(network.system(HOST).holeICMP().sendProbe("10.0.0.2", 64, 1, 1)));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown story " + story);
|
||||
}
|
||||
long rest = network.start + end - System.currentTimeMillis();
|
||||
if (rest > 0) Thread.sleep(rest);
|
||||
|
||||
ScenarioNetwork.Json out = new ScenarioNetwork.Json();
|
||||
out.open('{');
|
||||
network.writeFrames(out);
|
||||
synchronized (ModemRun.class) {
|
||||
out.key("events").open('[');
|
||||
for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).close(']');
|
||||
out.close(']');
|
||||
}
|
||||
out.close('}');
|
||||
network.stop();
|
||||
ScenarioNetwork.write(args[3], out);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import filius.hardware.knoten.Gateway;
|
||||
import filius.hardware.knoten.InternetKnoten;
|
||||
import filius.hardware.knoten.Knoten;
|
||||
import filius.hardware.knoten.LokalerKnoten;
|
||||
import filius.hardware.knoten.Modem;
|
||||
import filius.hardware.knoten.Notebook;
|
||||
import filius.hardware.knoten.Rechner;
|
||||
import filius.hardware.knoten.Switch;
|
||||
@@ -30,6 +31,7 @@ import filius.software.netzzugangsschicht.EthernetFrame;
|
||||
import filius.software.system.Betriebssystem;
|
||||
import filius.software.system.GatewayFirmware;
|
||||
import filius.software.system.InternetKnotenBetriebssystem;
|
||||
import filius.software.system.ModemFirmware;
|
||||
import filius.software.system.SwitchFirmware;
|
||||
import filius.software.system.VermittlungsrechnerBetriebssystem;
|
||||
import filius.software.transportschicht.Segment;
|
||||
@@ -58,6 +60,8 @@ public class ScenarioNetwork {
|
||||
/** Each card's MAC address, under its node's id (the first card) or `id#index` (the others). */
|
||||
final Map<String, String> macByNode = new LinkedHashMap<>();
|
||||
final List<String> servers = new ArrayList<>();
|
||||
/** The modems of the scenario, servers and clients. */
|
||||
final List<String> modems = new ArrayList<>();
|
||||
/** Loaded from a .fls file (fromFile): started as the action mode starts it, in the file's order. */
|
||||
boolean fromFile;
|
||||
/** fromFile: each card's MAC address and its node's name with the card's index, `name/index`. */
|
||||
@@ -136,6 +140,10 @@ public class ScenarioNetwork {
|
||||
// Its first card is the WAN port, its second the LAN port.
|
||||
knoten = new Gateway();
|
||||
break;
|
||||
case "remoteLink":
|
||||
// Java's modem: one port, no card; it joins its partner over TCP (modems below).
|
||||
knoten = new Modem();
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("node kind " + kind + " is not built by this tool");
|
||||
}
|
||||
@@ -235,6 +243,17 @@ public class ScenarioNetwork {
|
||||
for (Object each : list(scenario.getOrDefault("rip", new ArrayList<>()))) {
|
||||
((VermittlungsrechnerBetriebssystem) system(nodes.get((String) each))).setRipEnabled(true);
|
||||
}
|
||||
// Modems: Java pairs a server and a client over TCP on the port (the client
|
||||
// connects to ipAdresse); connectModems() makes the connection, as the
|
||||
// button of the settings panel does.
|
||||
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("modems", new HashMap<>())).entrySet()) {
|
||||
Map<String, Object> config = map(entry.getValue());
|
||||
ModemFirmware firmware = (ModemFirmware) nodes.get(entry.getKey()).getSystemSoftware();
|
||||
firmware.setMode("server".equals(config.get("mode")) ? ModemFirmware.SERVER : ModemFirmware.CLIENT);
|
||||
firmware.setPort(((Number) config.get("port")).intValue());
|
||||
firmware.setIpAdresse("localhost");
|
||||
modems.add(entry.getKey());
|
||||
}
|
||||
// Firewalls: the core's defaults (inactive, drop, ICMP through, SYN only, UDP filtered) and its rules.
|
||||
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("firewalls", new HashMap<>())).entrySet()) {
|
||||
Map<String, Object> config = map(entry.getValue());
|
||||
@@ -285,6 +304,20 @@ public class ScenarioNetwork {
|
||||
}
|
||||
}
|
||||
|
||||
/** Every server modem listens, then every client connects (JModemKonfiguration's button). */
|
||||
void connectModems() throws InterruptedException {
|
||||
for (String id : modems) {
|
||||
ModemFirmware firmware = (ModemFirmware) nodes.get(id).getSystemSoftware();
|
||||
if (firmware.getMode() == ModemFirmware.SERVER) firmware.starteServer();
|
||||
}
|
||||
Thread.sleep(300);
|
||||
for (String id : modems) {
|
||||
ModemFirmware firmware = (ModemFirmware) nodes.get(id).getSystemSoftware();
|
||||
if (firmware.getMode() == ModemFirmware.CLIENT) firmware.starteClient();
|
||||
}
|
||||
Thread.sleep(300);
|
||||
}
|
||||
|
||||
InternetKnotenBetriebssystem system(String nodeId) {
|
||||
return (InternetKnotenBetriebssystem) nodes.get(nodeId).getSystemSoftware();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user