test(core): WLAN measured with Java FILIUS — a wireless cable is a cable, an SSID connects nothing

WlanRun pings on the new network wlan-lan: over wireless cables, over a
plain cable, and to and from a notebook on the switch's SSID without a
cable. The engine matches Java without a change: it runs the links only.
Swift's wirelessAssociations, which join a host to its SSID's switch at
run time, are not taken. ScenarioNetwork sets wireless cables, wireless
cards and SSIDs; a corpus test pings over the wireless cables of
multicast_server.fls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 08:04:18 +00:00
co-authored by Claude Opus 5.5
parent 7a77bc1b43
commit 65ccd9ddd7
14 changed files with 677 additions and 7 deletions
+15 -1
View File
@@ -1,5 +1,6 @@
// A core scenario's network (packages/core/test/scenarios/*.scenario.json:
// nodes, links, devices, dhcpServers, dhcpClients) built in Java FILIUS the
// nodes, links (wireless or not), devices, switches' and hosts' SSIDs,
// dhcpServers, dhcpClients, …) built in Java FILIUS the
// way the core reads it: a port's MAC is its `mac`, else the core's
// stableGeneratedMacAddress. Started as the action mode starts it (every
// system software's starten()); afterwards every frame each network card saw
@@ -22,8 +23,10 @@ import filius.rahmenprogramm.nachrichten.Lauscher;
import filius.software.dhcp.DHCPServer;
import filius.software.dns.DNSServer;
import filius.software.netzzugangsschicht.EthernetFrame;
import filius.software.system.Betriebssystem;
import filius.software.system.GatewayFirmware;
import filius.software.system.InternetKnotenBetriebssystem;
import filius.software.system.SwitchFirmware;
import filius.software.system.VermittlungsrechnerBetriebssystem;
import filius.software.transportschicht.Segment;
import filius.software.transportschicht.TcpSegment;
@@ -139,6 +142,17 @@ public class ScenarioNetwork {
Map<String, Object> link = map(each);
Kabel cable = new Kabel();
cable.setAnschluesse(new Port[] { ports.get(link.get("sourcePort")), ports.get(link.get("targetPort")) });
cable.setWireless(Boolean.TRUE.equals(link.get("wireless")));
}
// A switch's SSID, a host's wireless card and the SSID it joins: what the
// editor reads to lay a wireless cable; the simulation does not ask.
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("switches", new HashMap<>())).entrySet()) {
((SwitchFirmware) nodes.get(entry.getKey()).getSystemSoftware()).setSSID((String) map(entry.getValue()).get("ssid"));
}
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("wireless", new HashMap<>())).entrySet()) {
Betriebssystem os = (Betriebssystem) system(nodes.get(entry.getKey()));
os.nicWireless(true);
os.setSsid((String) map(entry.getValue()).get("ssid"));
}
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("dhcpServers", new HashMap<>())).entrySet()) {
Map<String, Object> config = map(entry.getValue());
+85
View File
@@ -0,0 +1,85 @@
// Runs wlan-lan's network in Java FILIUS (ScenarioNetwork) and records what a
// wireless connection does at run time: every frame each card saw and when
// each call started and ended.
//
// WlanRun <scenario.json> <story> <milliseconds> <out.json>
//
// Notebooks 192.168.1.11 and .12 with wireless cards on the switch's SSID
// "schule", each joined by a wireless cable; PC 192.168.1.13 on a plain
// cable; notebook 192.168.1.14 with a wireless card on "schule" but no cable
// (as after the switch's SSID changed: Java's editor removes the cable and
// does not lay it again). The stories:
// pingWired .11 pings .13
// pingWireless .11 pings .12
// pingWithoutCable .11 pings .14
// pingFromWithoutCable .14 pings .11
import filius.software.vermittlungsschicht.IcmpPaket;
import java.util.ArrayList;
import java.util.List;
public class WlanRun {
static final String NOTEBOOK = "00000000-0000-0000-0000-000000000601";
static final String UNCABLED = "00000000-0000-0000-0000-000000000605";
static ScenarioNetwork network;
static final List<Object[]> events = new ArrayList<>();
static synchronized void event(String what) {
events.add(new Object[] { System.currentTimeMillis() - network.start, what });
}
static String icmp(IcmpPaket packet) {
return packet == null ? "null" : "ICMP " + packet.getIcmpType() + "/" + packet.getIcmpCode() + " from " + packet.getSender();
}
static void ping(String from, String target) {
String label = "sendProbe " + target;
event(label + " called");
try {
event(label + " returned " + icmp(network.system(from).holeICMP().sendProbe(target, 64, 1, 1)));
} catch (Exception e) {
event(label + " failed " + e.getClass().getSimpleName());
}
}
public static void main(String[] args) throws Exception {
network = ScenarioNetwork.read(args[0]);
String story = args[1];
long end = Long.parseLong(args[2]);
network.start();
Thread.sleep(500);
switch (story) {
case "pingWired":
ping(NOTEBOOK, "192.168.1.13");
break;
case "pingWireless":
ping(NOTEBOOK, "192.168.1.12");
break;
case "pingWithoutCable":
ping(NOTEBOOK, "192.168.1.14");
break;
case "pingFromWithoutCable":
ping(UNCABLED, "192.168.1.11");
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 (WlanRun.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);
}
}