ViewersRun takes the rows of Java's viewers from the firmware: a switch's table, a home router's NAT table, each after its reset, and the frames "Pakete verwerfen" drops while it is held. The core writes a frame as Java does and resets the NAT's dynamic entries; the room sends both tables as views, drops while any client holds the button, and sends the dropped frames, begun anew with each start, with the clock their times of day are written from; the editor opens a table with a tap on a switch or home router and holds "Pakete verwerfen" in its toolbar, which now wraps on a phone. This completes F4.6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
170 lines
7.4 KiB
Java
170 lines
7.4 KiB
Java
// What FILIUS' viewers of a running simulation show, in Java FILIUS: a
|
|
// switch's source address table (SwitchFirmware.holeSAT, shown by
|
|
// SatViewer), a home router's NAT table (GatewayFirmware.holeNAT, shown by
|
|
// NatViewer), each also after its "reset" (loescheSAT, loescheNAT), and the
|
|
// frames "Pakete verwerfen" drops while it is held (Verbindung.setDrop,
|
|
// Lauscher.getDroppedDataUnits, shown by SimulationControl). The viewers only
|
|
// show these rows, so they are taken from the firmware directly. Times are
|
|
// written with the run's start (the rows hold wall-clock times).
|
|
//
|
|
// ViewersRun <scenario.json> <story> <out.json>
|
|
//
|
|
// switch switch-lan (retention 5 s): .10 pings .20 and .30; the table;
|
|
// reset; .10 pings .20 again; the table; aged after the retention;
|
|
// "Pakete verwerfen" held while .10 pings .30; the dropped frames
|
|
// nat nat-home (port forwarding TCP 8080 to 192.168.0.10:80):
|
|
// 192.168.0.10 pings 42.0.0.20 and sends a datagram to its port 7;
|
|
// the table; reset; the table
|
|
|
|
import filius.hardware.Verbindung;
|
|
import filius.hardware.knoten.Switch;
|
|
import filius.rahmenprogramm.nachrichten.Lauscher;
|
|
import filius.software.system.GatewayFirmware;
|
|
import filius.software.system.InternetKnotenBetriebssystem;
|
|
import filius.software.system.SwitchFirmware;
|
|
import filius.software.transportschicht.UDPSocket;
|
|
import filius.software.vermittlungsschicht.IcmpPaket;
|
|
|
|
import java.io.FileOutputStream;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Method;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Vector;
|
|
|
|
public class ViewersRun {
|
|
static final String SWITCH = "00000000-0000-0000-0000-000000000104";
|
|
static final String PC10 = "00000000-0000-0000-0000-000000000101";
|
|
static final String GATEWAY = "00000000-0000-0000-0000-000000000502";
|
|
static final String LAN_PC = "00000000-0000-0000-0000-000000000501";
|
|
static final String SERVER = "00000000-0000-0000-0000-000000000504";
|
|
|
|
static ScenarioNetwork network;
|
|
static final List<Object> steps = new ArrayList<>();
|
|
|
|
static InternetKnotenBetriebssystem os(String id) {
|
|
return (InternetKnotenBetriebssystem) network.nodes.get(id).getSystemSoftware();
|
|
}
|
|
|
|
static String ping(String from, String target, int sequence) {
|
|
IcmpPaket answer = os(from).holeICMP().sendProbe(target, 64, 1, sequence);
|
|
return answer == null ? "null" : "ICMP " + answer.getIcmpType() + "/" + answer.getIcmpCode();
|
|
}
|
|
|
|
static List<List<String>> rows(Vector<Vector<String>> table) {
|
|
List<List<String>> rows = new ArrayList<>();
|
|
for (Vector<String> row : table) rows.add(new ArrayList<>(row));
|
|
return rows;
|
|
}
|
|
|
|
/** Each learned address's last update, in milliseconds since the start. */
|
|
@SuppressWarnings("unchecked")
|
|
static Map<String, Long> satTimes(SwitchFirmware firmware) throws Exception {
|
|
Field field = SwitchFirmware.class.getDeclaredField("sat");
|
|
field.setAccessible(true);
|
|
Map<String, Object> sat = (Map<String, Object>) field.get(firmware);
|
|
Map<String, Long> times = new LinkedHashMap<>();
|
|
for (Map.Entry<String, Object> entry : sat.entrySet()) {
|
|
Method update = entry.getValue().getClass().getMethod("holeLetztesUpdate");
|
|
update.setAccessible(true);
|
|
times.put(entry.getKey().toUpperCase(), ((java.util.Date) update.invoke(entry.getValue())).getTime() - network.start);
|
|
}
|
|
return times;
|
|
}
|
|
|
|
static void step(String name, Map<String, Object> shown) {
|
|
Map<String, Object> result = new LinkedHashMap<>();
|
|
result.put("step", name);
|
|
result.put("at", System.currentTimeMillis() - network.start);
|
|
result.putAll(shown);
|
|
steps.add(result);
|
|
}
|
|
|
|
static Map<String, Object> sat() throws Exception {
|
|
SwitchFirmware firmware = (SwitchFirmware) network.nodes.get(SWITCH).getSystemSoftware();
|
|
firmware.checkSAT();
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
shown.put("rows", rows(firmware.holeSAT()));
|
|
shown.put("updated", satTimes(firmware));
|
|
shown.put("ports", ((Switch) network.nodes.get(SWITCH)).getAnschluesse().size());
|
|
return shown;
|
|
}
|
|
|
|
static Map<String, Object> nat() {
|
|
Map<String, Object> shown = new LinkedHashMap<>();
|
|
shown.put("rows", rows(((GatewayFirmware) network.nodes.get(GATEWAY).getSystemSoftware()).holeNAT()));
|
|
return shown;
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
try {
|
|
run(args);
|
|
} catch (Throwable error) {
|
|
error.printStackTrace();
|
|
System.exit(1);
|
|
}
|
|
System.exit(0);
|
|
}
|
|
|
|
static void run(String[] args) throws Exception {
|
|
network = ScenarioNetwork.read(args[0]);
|
|
String story = args[1];
|
|
network.start();
|
|
Thread.sleep(500);
|
|
Map<String, Object> output = new LinkedHashMap<>();
|
|
output.put("startEpoch", network.start);
|
|
if (story.equals("switch")) {
|
|
Map<String, Object> answers = new LinkedHashMap<>();
|
|
answers.put("ping .20", ping(PC10, "192.168.0.20", 1));
|
|
answers.put("ping .30", ping(PC10, "192.168.0.30", 2));
|
|
Map<String, Object> shown = sat();
|
|
shown.put("answers", answers);
|
|
step("after pings", shown);
|
|
((SwitchFirmware) network.nodes.get(SWITCH).getSystemSoftware()).loescheSAT();
|
|
step("reset", sat());
|
|
Map<String, Object> again = sat();
|
|
again.put("answers", Map.of("ping .20", ping(PC10, "192.168.0.20", 3)));
|
|
again.putAll(sat());
|
|
step("ping .20 again", again);
|
|
Thread.sleep(6000);
|
|
step("after the retention", sat());
|
|
|
|
Lauscher.getLauscher().resetDroppedDataUnits();
|
|
Verbindung.setDrop(true);
|
|
String dropped = ping(PC10, "192.168.0.30", 4);
|
|
Verbindung.setDrop(false);
|
|
Map<String, Object> drop = new LinkedHashMap<>();
|
|
drop.put("answer", dropped);
|
|
drop.put("dropped", Lauscher.getLauscher().getDroppedDataUnits());
|
|
step("dropped while held", drop);
|
|
Map<String, Object> after = new LinkedHashMap<>();
|
|
after.put("answer", ping(PC10, "192.168.0.30", 5));
|
|
after.put("dropped", Lauscher.getLauscher().getDroppedDataUnits());
|
|
step("released", after);
|
|
} else {
|
|
step("start", nat());
|
|
Map<String, Object> answers = new LinkedHashMap<>();
|
|
answers.put("ping 42.0.0.20", ping(LAN_PC, "42.0.0.20", 1));
|
|
UDPSocket socket = new UDPSocket(os(LAN_PC), "42.0.0.20", 7);
|
|
socket.verbinden();
|
|
socket.senden("one");
|
|
answers.put("udp port", socket.holeLokalenPort());
|
|
Thread.sleep(1500);
|
|
Map<String, Object> shown = nat();
|
|
shown.put("answers", answers);
|
|
step("after ping and datagram", shown);
|
|
((GatewayFirmware) network.nodes.get(GATEWAY).getSystemSoftware()).loescheNAT();
|
|
step("reset", nat());
|
|
}
|
|
output.put("steps", steps);
|
|
try (FileOutputStream out = new FileOutputStream(args[2])) {
|
|
out.write((FlsOracle.Json.write(output, "") + "\n").getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
network.stop();
|
|
System.out.println("viewer steps: " + steps.size());
|
|
}
|
|
}
|