123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065 |
- package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeSupport;
- import java.io.File;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.text.SimpleDateFormat;
- import java.util.Calendar;
- import java.util.Comparator;
- import java.util.Date;
- import java.util.LinkedHashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Locale;
- import java.util.Random;
- import java.util.concurrent.ThreadLocalRandom;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.Controller;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.control.NetworkController;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.devices.SWaTDevice;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.distributionHandler.SWaTDatasetDistributionHandler;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.Pair;
- import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.SWaTUtilities;
- /**
- * The functions of the SWaT network traffic simulation.
- * @author Fabian Kaiser
- */
- public class SWaTSimulationManagerNetwork {
-
- /**
- * Network controller for the simulation.
- */
- private NetworkController networkController;
-
- /**
- * The duration of the simulation in seconds.
- */
- private int durationInSeconds;
-
- /**
- * The path of the directory where the output files are saved.
- */
- private String outputDirectoryPath;
-
- /**
- * The start time of the simulation.
- */
- private Calendar outputFileNameTime;
-
- /**
- * The start time of the simulation.
- */
- private Calendar startTime;
-
- /**
- * A list of pairs with all response times as keys and the corresponding CSV strings as values.
- */
- private LinkedList<Pair<Double, String>> allTimes = new LinkedList<Pair<Double, String>>();
-
- /**
- * The transaction IDs that are currently in use and the date they can be reused.
- */
- private LinkedHashMap<Integer, LinkedList<Pair<Date, Date>>> transactionIDsCurrentlyInUseUntil = new LinkedHashMap<Integer, LinkedList<Pair<Date, Date>>>();
-
- /**
- * The distribution handlers for dataset A1 or A6 with the connection names as keys.
- */
- private LinkedHashMap<String, SWaTDatasetDistributionHandler> distributionHandlers = new LinkedHashMap<String, SWaTDatasetDistributionHandler>();
-
- /**
- * Pass-by-reference value to stop the simulation.
- */
- private boolean[] passByReferenceValue_KeepSimulationRunning;
-
- /**
- * Variable needed as Observable.
- */
- private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
-
- /**
- * The results of the simulation from {@link SWaTSimulationManagerPhysical#getSimulationResults()}.
- */
- private LinkedHashMap<Integer, String[]> physicalSimulationResults;
-
- /**
- * A counter for the number of processed connections.
- */
- private int connectionCounter = 0;
-
- /**
- * Counts the number of output files.
- */
- private int outputFileCounter = 0;
-
- /**
- * The number of rows per output file.
- */
- private int rowsPerOutputFile = 500000;
-
- /**
- * The number of the current row of the output file.
- */
- private int outputFileRowCounter = 0;
-
- /**
- * Whether the optimized output is activated.<br>
- * The optimization writes the output files already during the simulation instead of waiting
- * until the simulation is finished.<br>
- * The optimization should be activated if more than 10000 seconds are simulated to prevent
- * Out of Memory exceptions.
- */
- private boolean optimizeOutput = false;
-
- /**
- * The constructor.
- * @param controller The controller of the scenario.
- */
- public SWaTSimulationManagerNetwork(Controller controller) {
- this.networkController = controller.getNetworkController();
- }
- /**
- * Starts the simulation.
- * @param duration The duration of the simulation in seconds.
- * @param startTime The start time of the simulation.
- * @param outputDirectoryPath The path of the directory for the output files.
- * @param propertyChangeListener The PropertyChangeListener to observe this class.
- * @param physicalSimulationResults The results of the simulation from {@link SWaTSimulationManagerPhysical#getSimulationResults()}
- * @param passByReferenceValue_KeepSimulationRunning The PropertyChangeListener to observe this class.
- * @param timeOffset The time offset between the occurrence of a sensor reading in the physical data and the time it is used in network packets.
- */
- public void startSimulation(String duration, Calendar startTime, String outputDirectoryPath, boolean[] passByReferenceValue_KeepSimulationRunning,
- PropertyChangeListener propertyChangeListener, LinkedHashMap<Integer, String[]> physicalSimulationResults, int timeOffset) {
- // Reset variables
- distributionHandlers = new LinkedHashMap<String, SWaTDatasetDistributionHandler>();
- setDatasetDistributionHandlers();
- durationInSeconds = Integer.parseInt(duration);
- this.outputDirectoryPath = outputDirectoryPath;
- this.passByReferenceValue_KeepSimulationRunning = passByReferenceValue_KeepSimulationRunning;
- this.propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
- outputFileNameTime = (Calendar) startTime.clone();
- this.startTime = (Calendar) startTime.clone();
- this.startTime.set(Calendar.SECOND, startTime.get(Calendar.SECOND)+timeOffset);
- allTimes = new LinkedList<Pair<Double, String>>();
- transactionIDsCurrentlyInUseUntil = new LinkedHashMap<Integer, LinkedList<Pair<Date, Date>>>();
- this.physicalSimulationResults = physicalSimulationResults;
- connectionCounter = 0;
- if(durationInSeconds > 10000) optimizeOutput = true;
-
- LinkedList<Thread> threadList = new LinkedList<Thread>();
- List<SmartDevice> deviceList = SWaTUtilities.getSortedDeviceList(networkController);
- for(SmartDevice device:deviceList) {
- connectionCounter = 0;
- if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
- if(device.getClass().getSimpleName().equals("SWaTDevice") && device.getName().startsWith("Switch") == false) {
- Thread deviceThread = new Thread(() -> {
- simulateDevice((SWaTDevice)device);
- });
- deviceThread.start();
- threadList.add(deviceThread);
- }
- }
-
- // Wait for threads to finish
- for(Thread thread:threadList)
- try {
- thread.join();
- } catch (InterruptedException e) {
- System.out.println("One of the threads of the network simulation was interrupted.");
- }
- if(passByReferenceValue_KeepSimulationRunning[0] == true) {
- if(optimizeOutput == false)
- saveCSVOutput();
- else
- saveCSVOutputRest();
- }
- }
- /**
- * Simulates the request packets of a device and the corresponding response packets.
- * @param device The device to be simulated.
- */
- private void simulateDevice(SWaTDevice device){
- LinkedList<Thread> threadList = new LinkedList<Thread>();
-
- String deviceName = device.getName();
- propertyChangeSupport.firePropertyChange("statusPercentageNetworkSimulation", 0, deviceName);
- List<String> elementConnections = SWaTUtilities.getElementConnections(device, networkController);
- for(String connection:elementConnections) {
- Thread connectionThread = new Thread(() -> {
- connectionCounter++;
- String sendingDistribution = device.getDeviceData().get(connection+"_"+"sendingCurrent");
- String destinationDeviceName = SWaTUtilities.getDestinationDeviceName(connection);
-
-
- // Construct distribution handler names for dataset A1 and A6 distributions
- String distributionHandlerNameRequest = sendingDistribution+"_Request_"+(deviceName+"-"+destinationDeviceName);
- String distributionHandlerNameResponse = sendingDistribution+"_Response_"+(destinationDeviceName+"-"+deviceName);
- distributionHandlerNameRequest = distributionHandlerNameRequest.replaceAll(" ", "");
- distributionHandlerNameResponse = distributionHandlerNameResponse.replaceAll(" ", "");
-
- // Device that send only read tag service requests
- LinkedList<String> readTagServiceDevices = new LinkedList<String>();
- readTagServiceDevices.add("PLC 1");
- readTagServiceDevices.add("PLC 2");
- readTagServiceDevices.add("PLC 3");
- readTagServiceDevices.add("PLC 4");
- readTagServiceDevices.add("PLC 5");
- readTagServiceDevices.add("PLC 6");
-
- // CSV columns
- String dateRequest;
- String dateResponse;
- String timeRequest;
- String timeResponse;
- String orig = "192.168.1.48";
- String type = "log";
- String ifname = "eth1";
- String ifdir = "outbound";
- String src = device.getDeviceData().get(connection+"_"+"sourceIPAddress");
- String dst;
- String proto = "tcp";
- String appi_nameRequest;
- String appi_nameResponse;
- String proxy_src_ip;
- String Modbus_Function_Code;
- String Modbus_Function_DescriptionRequest;
- String Modbus_Function_DescriptionResponse;
- String Modbus_Transaction_ID;
- String SCADA_Tag = "";
- String Modbus_ValueRequest = "Number of Elements: 1";
- String Modbus_ValueResponse = "";
- String service; // destination port
- String s_port = device.getDeviceData().get(connection+"_"+"outboundPort"); // source port
- String Tag = "0";
-
- // Simulate request times
- List<String> destinationInformation = SWaTUtilities.getConnectionInformation(destinationDeviceName, deviceName, networkController);
- LinkedList<Double> requestTimesList = new LinkedList<Double>();
- LinkedList<Double> responseTimesList = new LinkedList<Double>();
- switch(sendingDistribution) {
- case "Constant Value":
- double constantValueSending = Double.parseDouble(device.getDeviceData().get(connection+"_sendingConstantValue"));
- requestTimesList = simulateConstantValueTimes(null, constantValueSending);
- break;
- case "Normal Distribution":
- double meanSending = Double.parseDouble(device.getDeviceData().get(connection+"_sendingNormalDistributionMean"));
- double standardDeviationSending = Double.parseDouble(device.getDeviceData().get(connection+"_sendingNormalDistributionSD"));
- requestTimesList = simulateNormalDistributionTimes(null, meanSending, standardDeviationSending);
- break;
- default: // "Dataset A1 Distribution" || "Dataset A6 Distribution"
- if(distributionHandlers.containsKey(distributionHandlerNameRequest) == false)
- break;
- double requestStandardDeviation = Double.parseDouble(device.getDeviceData().get(connection+"_"+sendingDistribution.replaceAll(" ", "")+"SendingSD"));
- requestTimesList = simulateTimesForRequestConnection(distributionHandlerNameRequest, requestStandardDeviation);
- }
-
- // Simulate response times
- String responseDistribution = destinationInformation.get(2);
- switch(responseDistribution) {
- case "Constant Value":
- double constantValueResponse = Double.parseDouble(device.getDeviceData().get(connection+"_responseConstantValue"));
- responseTimesList = simulateConstantValueTimes(requestTimesList, constantValueResponse);
- break;
- case "Normal Distribution":
- double meanResponse = Double.parseDouble(device.getDeviceData().get(connection+"_responseNormalDistributionMean"));
- double standardDeviationResponse = Double.parseDouble(device.getDeviceData().get(connection+"_responseNormalDistributionSD"));
- responseTimesList = simulateNormalDistributionTimes(requestTimesList, meanResponse, standardDeviationResponse);
- break;
- default: // "Dataset A1 Distribution" || "Dataset A6 Distribution"
- if(distributionHandlers.containsKey(distributionHandlerNameResponse) == false)
- break;
- double responseStandardDeviation = Double.parseDouble(device.getDeviceData().get(connection+"_"+destinationInformation.get(2).replaceAll(" ", "")+"ResponseSD"));
- responseTimesList = simulateTimesForResponseConnection(requestTimesList, distributionHandlerNameResponse, responseStandardDeviation);
- }
-
- int responseTimes = responseTimesList.size();
- int responseTimesPercent = responseTimes/100;
- if(responseTimesPercent == 0) {
- responseTimesPercent = 1;
- connectionCounter = 0;
- }
- for(int i = 0; i < responseTimes; i++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
-
- if(i % responseTimesPercent == 0) propertyChangeSupport.firePropertyChange("statusPercentageNetworkSimulation", 0, deviceName+", Connection "+connectionCounter+" "+(int)(i/responseTimesPercent)+"%");
- // Process dates and times
- double requestTime = requestTimesList.get(i);
- int timeInFullSeconds = (int) requestTime;
- Calendar startTimeClone = (Calendar) startTime.clone();
- startTimeClone.set(Calendar.SECOND, startTimeClone.get(Calendar.SECOND)+timeInFullSeconds);
- Date date = startTimeClone.getTime();
- dateRequest = new SimpleDateFormat("ddMMMyyyy",Locale.ROOT).format(date);
- timeRequest = new SimpleDateFormat("H:mm:ss").format(date);
-
- double responseTime = responseTimesList.get(i);
- timeInFullSeconds = (int) (requestTime + responseTime);
- Calendar endTime = (Calendar) startTime.clone();
- endTime.set(Calendar.SECOND, endTime.get(Calendar.SECOND)+timeInFullSeconds);
- date = endTime.getTime();
- dateResponse = new SimpleDateFormat("ddMMMyyyy",Locale.ROOT).format(date);
- timeResponse = new SimpleDateFormat("H:mm:ss").format(date);
-
- int currentSimulationTimeInSeconds = (int) (startTimeClone.getTimeInMillis()-startTime.getTimeInMillis())/1000;
-
- // IP addresses
- proxy_src_ip = src;
- dst = destinationInformation.get(0);
-
- // SCADA
- String connectionEnding = connection.substring(connection.length()-5);
- if(connectionEnding.startsWith("PLC"))
- SCADA_Tag = getSCADATagDatasetA1ForDestinationPLC(Integer.parseInt(connectionEnding.substring(connectionEnding.length()-1)));
-
- // Modbus information
- if(readTagServiceDevices.contains(deviceName)) {
- appi_nameRequest = "CIP_read_tag_service";
- appi_nameResponse = appi_nameRequest;
- Modbus_Function_Code = "76";
- Modbus_Function_DescriptionRequest= "Read Tag Service";
- Modbus_Function_DescriptionResponse = "Read Tag Service - Response";
- }
- else {
- switch(deviceName) {
- case "Historian":
- String[] appi_nameHistorian =
- {"Common Industrial Protocol - get attribute all",
- "Common Industrial Protocol - get attribute single",
- "Common Industrial Protocol - multiple service packet"};
- appi_nameRequest = appi_nameHistorian[new Random().nextInt(appi_nameHistorian.length)];
- Modbus_Function_Code = "";
- Modbus_Function_DescriptionRequest = "";
- Modbus_Function_DescriptionResponse = "";
- appi_nameResponse = "Common Industrial Protocol - success";
- break;
- case "Engineering Workstation":
- appi_nameRequest = "CIP_func79";
- appi_nameResponse = appi_nameRequest;
- Modbus_Function_Code = "79";
- Modbus_Function_DescriptionRequest= "Unknown Function Code";
- Modbus_Function_DescriptionResponse = "Unknown Function Code - Response";
- break;
- default: // SCADA
- appi_nameRequest = "CIP_func75";
- appi_nameResponse = appi_nameRequest;
- Modbus_Function_Code = "75";
- Modbus_Function_DescriptionRequest= "Unknown Function Code";
- Modbus_Function_DescriptionResponse = "Unknown Function Code - Response";
- }
- Modbus_ValueRequest = "";
- Modbus_ValueResponse = "";
- SCADA_Tag = "";
- }
- switch(SCADA_Tag) {
- case "":
- Modbus_ValueResponse = "";
- break;
- case "HMI_LIT101":
- String sensorReadingLIT101 = SWaTUtilities.convertDoubleStringToSWaTNetworkHexString(physicalSimulationResults.get(currentSimulationTimeInSeconds)[0]);
- int[] randomValuesLIT101 = new int[] {32, 34, 36, 44, 96, 98, 100};
- Modbus_ValueResponse = sensorReadingLIT101 + "; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x00 0x00 0x96 0x44; 0x00 0x00 0x48 0x44; 0x00 0x00 0xfa 0x43; 0x00 0x00 0x7a 0x43; ";
- Modbus_ValueResponse += randomValuesLIT101[ThreadLocalRandom.current().nextInt(0, randomValuesLIT101.length)];
- Modbus_ValueResponse += "; " + sensorReadingLIT101;
- break;
- case "HMI_AIT202":
- String sensorReadingAIT202 = SWaTUtilities.convertDoubleStringToSWaTNetworkHexString(physicalSimulationResults.get(currentSimulationTimeInSeconds)[1]);
- Modbus_ValueResponse = sensorReadingAIT202 + "; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x00 0x00 0x20 0x41; 0x9a 0x99 0xe1 0x40; 0x66 0x66 0xde 0x40; 0x00 0x00 0x40 0x40; 34; ";
- Modbus_ValueResponse += sensorReadingAIT202;
- break;
- case "HMI_FIT201":
- String sensorReadingFIT201 = SWaTUtilities.convertDoubleStringToSWaTNetworkHexString(physicalSimulationResults.get(currentSimulationTimeInSeconds)[2]);
- int[] randomValuesFIT201 = new int[] {0, 2, 12};
- Modbus_ValueResponse = sensorReadingFIT201 + "; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x00 0x00 0x60 0x40; 0x00 0x00 0x00 0x40; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x05 0xab 0x59 0x43; ";
- Modbus_ValueResponse += randomValuesFIT201[ThreadLocalRandom.current().nextInt(0, randomValuesFIT201.length)];
- Modbus_ValueResponse += "; " + sensorReadingFIT201 +"; 4";
- break;
- case "HMI_LIT301":
- String sensorReadingLIT301 = SWaTUtilities.convertDoubleStringToSWaTNetworkHexString(physicalSimulationResults.get(currentSimulationTimeInSeconds)[3]);
- int[] randomValuesLIT301 = new int[] {32, 34, 36, 44, 98, 100};
- Modbus_ValueResponse = sensorReadingLIT301 + "; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x00 0x00 0x96 0x44; 0x00 0x00 0x7a 0x44; 0x00 0x00 0x2f 0x44; 0x00 0x00 0x7a 0x43; ";
- Modbus_ValueResponse += randomValuesLIT301[ThreadLocalRandom.current().nextInt(0, randomValuesLIT301.length)];
- Modbus_ValueResponse += "; " + sensorReadingLIT301;
- break;
- case "HMI_LIT401":
- String sensorReadingLIT401 = SWaTUtilities.convertDoubleStringToSWaTNetworkHexString(physicalSimulationResults.get(currentSimulationTimeInSeconds)[4]);
- int[] randomValuesLIT401 = new int[] {32, 34, 36, 44, 98, 99, 100};
- Modbus_ValueResponse = sensorReadingLIT401 + "; 0x00 0x00 0x00 0x00; 0x00 0x00 0x00 0x00; 0x00 0x80 0x89 0x44; 0x00 0x00 0x7a 0x44; 0x00 0x00 0x2f 0x44; 0x00 0x00 0x7a 0x43; ";
- Modbus_ValueResponse += randomValuesLIT401[ThreadLocalRandom.current().nextInt(0, randomValuesLIT401.length)];
- Modbus_ValueResponse += "; " + sensorReadingLIT401;
- break;
- }
-
- // Modbus transaction ID
- Calendar endTimeClone = (Calendar) endTime.clone();
- endTimeClone.set(Calendar.SECOND, endTimeClone.get(Calendar.SECOND)+1);
- Modbus_Transaction_ID = String.valueOf(getValidTransactionID(startTimeClone.getTime(), endTimeClone.getTime()));
-
- // Ports
- service = destinationInformation.get(1);
-
- // Tag
- Tag = physicalSimulationResults.get(currentSimulationTimeInSeconds)[5];
-
- // Parts of the output
- String outputSubString1 = orig+","+type+","+ifname+","+ifdir+","+src+","+dst+","+proto+",";
- String outputSubString2 = ","+ proxy_src_ip+","+Modbus_Function_Code+",";
- String outputSubString3 = ","+Modbus_Transaction_ID+","+SCADA_Tag+",";
- String outputSubString4 = ","+service+","+s_port+","+Tag;
-
- // Complete output
- String outputRequest = dateRequest+","+timeRequest+","+outputSubString1+appi_nameRequest+outputSubString2+Modbus_Function_DescriptionRequest+outputSubString3+Modbus_ValueRequest+outputSubString4;
- String outputResponse = dateResponse+","+timeResponse+","+outputSubString1+appi_nameResponse+outputSubString2+Modbus_Function_DescriptionResponse+outputSubString3+Modbus_ValueResponse+outputSubString4;
-
- // Special cases
- if(sendingDistribution.equals("Dataset A1 Distribution")) {
- if(connection.equals("Historian via Switch 2 to Engineering Workstation") || connection.equals("Engineering Workstation via Switch 2 to Historian")){
- int timeDistance = 0;
- String appi_name1 = "";
- String appi_name2 = "Unknown Traffic";
- if(connection.equals("Historian via Switch 2 to Engineering Workstation")) {
- // Combination of two packets with 50 seconds time between them and no responses
- timeDistance = 50;
- appi_name1 = "DCE-RPC Protocol";
- }
- else { // Engineering Workstation via Switch 2 to Historian
- // Combination of two packets with 42 or 22 seconds time between them with probability 2/5 and 3/5 and no responses
- int[] probabilities = {42, 42, 22, 22, 22};
- timeDistance = probabilities[new Random().nextInt(probabilities.length)];
- appi_name1 = "OSIsoft PI";
- }
-
- Calendar specialTime = (Calendar) startTimeClone.clone();
- specialTime.set(Calendar.SECOND, specialTime.get(Calendar.SECOND)+timeDistance);
- Date specialDate = specialTime.getTime();
- String dateSpecialOutput2 = new SimpleDateFormat("ddMMMyyyy").format(specialDate);
- String timeSpecialOutput2 = new SimpleDateFormat("H:mm:ss").format(specialDate);
-
- String output1 = dateRequest+","+timeRequest+","+outputSubString1+","+appi_name1+","+ proxy_src_ip+",,,,,,"+outputSubString4;
- String output2 = dateSpecialOutput2+","+timeSpecialOutput2+","+outputSubString1+","+appi_name2+","+ proxy_src_ip+",,,,,,"+outputSubString4;
-
- appendToAllTimesSynchronized(new Pair<Double, String>(requestTime, output1));
- appendToAllTimesSynchronized(new Pair<Double, String>(requestTime+timeDistance, output2));
- break;
- }
- else if(connection.equals("Engineering Workstation via Switch 2 to SCADA")) {
- // Packet without response
- String output1 = dateRequest+","+timeRequest+","+outputSubString1+",VNC,"+ proxy_src_ip+",,,,,,"+outputSubString4;
- appendToAllTimesSynchronized(new Pair<Double, String>(requestTime, output1));
- break;
- }
- else if(connection.startsWith("SCADA via Switch 2 and Switch 1 to PLC")) {
- // Very unpredictable packets that only occur at the very beginning and the very end of dataset A1
- break;
- }
- }
-
- // Add to list
- appendToAllTimesSynchronized(new Pair<Double, String>(requestTime, outputRequest));
- appendToAllTimesSynchronized(new Pair<Double, String>(requestTime+responseTime, outputResponse));
-
- }
- });
- connectionThread.start();
- threadList.add(connectionThread);
- }
- // Wait for threads to finish
- for(Thread thread:threadList)
- try {
- thread.join();
- } catch (InterruptedException e) {
- System.out.println("One of the threads of the network simulation was interrupted.");
- }
- }
-
- /**
- * Simulates the times of requests for a connection.
- * @param connectionHandlerName The name of the connection handler.
- * @param requestStandardDeviation The standard deviation of requests for this connection.
- * @return The times of requests for a connection.
- */
- private LinkedList<Double> simulateTimesForRequestConnection(String connectionHandlerName, double requestStandardDeviation){
- LinkedList<Double> times = new LinkedList<Double>();
- SWaTDatasetDistributionHandler distributionHandler = distributionHandlers.get(connectionHandlerName);
- distributionHandler.setBandwidth(requestStandardDeviation);
- double simulatedTime = 0.0;
- while(true) {
- double nextValue = distributionHandler.sampleNextValueExactly();
-
- if(simulatedTime+nextValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- // Add new request times to the variables
- simulatedTime += nextValue;
- times.add(simulatedTime);
- }
- }
- return times;
- }
-
- /**
- * Simulates the times of responses to requests.
- * @param requestTimes The list of request times.
- * @param connectionHandlerName The name of the connection handler.
- * @param responseStandardDeviation The standard deviation of responses for this connection.
- * @return
- */
- private LinkedList<Double> simulateTimesForResponseConnection(LinkedList<Double> requestTimes, String connectionHandlerName, double responseStandardDeviation){
- LinkedList<Double> times = new LinkedList<Double>();
-
- SWaTDatasetDistributionHandler distributionHandler = distributionHandlers.get(connectionHandlerName);
- distributionHandler.setBandwidth(responseStandardDeviation);
- for(Double requestTime:requestTimes) {
- double nextValue = distributionHandler.sampleNextValueExactly();
- if(requestTime+nextValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- times.add(nextValue);
- }
- }
- return times;
- }
-
-
- /**
- * Simulates the times for constant value distributions.
- * @param requestTimes The list of request times or null if the request times are to be sampled.
- * @param constantValue The constant value of the distribution.
- * @return The times for constant value distributions.
- */
- private LinkedList<Double> simulateConstantValueTimes(LinkedList<Double> requestTimes, double constantValue){
- LinkedList<Double> times = new LinkedList<Double>();
- if(requestTimes != null) { // Responses
- for(Double requestTime:requestTimes) {
- if(requestTime+constantValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- times.add(constantValue);
- }
- }
- }
- else { // Requests
- double simulatedTime = 0.0;
- while(true) {
- if(simulatedTime+constantValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- // Add new request times to the variables
- simulatedTime += constantValue;
- times.add(simulatedTime);
- }
- }
- }
- return times;
- }
-
- /**
- * Simulates the times for normal distributions.
- * @param requestTimes The list of request times or null if the request times are to be sampled.
- * @param mean The mean value of the distribution.
- * @param standardDeviation The standard deviation value of the distribution.
- * @return The times for constant value distributions.
- */
- private LinkedList<Double> simulateNormalDistributionTimes(LinkedList<Double> requestTimes, double mean, double standardDeviation){
- LinkedList<Double> times = new LinkedList<Double>();
- Random rng = new Random();
- if(requestTimes != null) { // Responses
- for(Double requestTime:requestTimes) {
- double nextValue;
- while(true) {
- nextValue = rng.nextGaussian()*standardDeviation+mean;
- if(nextValue >= 0.0)
- break;
- }
- if(requestTime+nextValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- times.add(nextValue);
- }
- }
- return times;
- }
- else { // Requests
- double simulatedTime = 0.0;
- while(true) {
- double nextValue;
- while(true) {
- nextValue = rng.nextGaussian()*standardDeviation+mean;
- if(nextValue >= 0.0)
- break;
- }
-
- if(simulatedTime+nextValue > durationInSeconds)
- break; // Stop simulation if it would exceed the duration
- else {
- // Add new request times to the variables
- simulatedTime += nextValue;
- times.add(simulatedTime);
- }
- }
- }
- return times;
- }
-
- /**
- * Sorts the times list according to the time
- */
- private void sortTimesList() {
- allTimes.sort(new Comparator<Pair<Double,String>>(){
- public int compare(Pair<Double, String> pair1, Pair<Double, String> pair2) {
- Double key1 = pair1.getLeft();
- Double key2 = pair2.getLeft();
- if(key1 > key2) return 1;
- else if(key1 < key2) return -1;
- return 0;
- }
- });
- }
-
- /**
- * Saves the CSV output.
- */
- private void saveCSVOutput() {
- String filePathName = outputDirectoryPath+"/IoTDGF_SWaT Simulation";
- String fileNameAddition = "_"+new SimpleDateFormat("yyyy-MM-dd HH.mm.ss").format(outputFileNameTime.getTime())+"_Network";
- // Write file
- FileWriter outputWriter;
- try {
- sortTimesList();
- double rowsPerFile = 500000;
- double rowsPerFileCurrent = rowsPerFile;
- double numberOfTimes = allTimes.size();
- int numberOfFiles = (int) Math.ceil(numberOfTimes/rowsPerFile);
- int rowsInLastFile = (int) (numberOfTimes-rowsPerFile*(numberOfFiles-1));
- int num = 0;
- int numberOfTimesTenth = (int) numberOfTimes/100;
- if(numberOfTimesTenth == 0) numberOfTimesTenth = 1;
- for(int j = 0; j < numberOfFiles; j++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
- if(j == numberOfFiles-1) // Last File
- rowsPerFileCurrent = rowsInLastFile;
- StringBuilder outputStringBuilder = new StringBuilder(300*((int) rowsPerFileCurrent));
- outputStringBuilder.append("num,date,time,orig,type,i/f_name,i/f_dir,src,dst,proto,appi_name,"+
- "proxy_src_ip,Modbus_Function_Code,Modbus_Function_Description"+
- ",Modbus_Transaction_ID,SCADA_Tag,Modbus_Value,service,s_port,Tag\n");
- for(int i = 0; i < rowsPerFileCurrent; i++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) break;
- num++;
- String CSVRow = allTimes.pop().getRight();//allTimes.get((int)(j*rowsPerFile+i)).getRight();
- outputStringBuilder.append(num+","+CSVRow);
- if(i < rowsPerFileCurrent-1)
- outputStringBuilder.append("\n");
- if(num % numberOfTimesTenth == 0) {
- propertyChangeSupport.firePropertyChange("statusPercentageNetworkOutput", 0, (int)(num/numberOfTimesTenth));
- }
- }
- if(passByReferenceValue_KeepSimulationRunning[0] == true) {
- String outputFileName = filePathName+fileNameAddition;
- if(numberOfFiles > 1)
- outputFileName += "_"+String.valueOf(j+1)+" of "+numberOfFiles;
-
- // Try file name combinations until one does not yet exist
- File outputFile;
- int fileNameAdditionExtra = 0;
- while(true) {
- String fileNameCandidate = outputFileName;
- if(fileNameAdditionExtra > 0) fileNameCandidate += "_"+fileNameAdditionExtra;
- outputFile = new File(fileNameCandidate+".csv");
-
- if(outputFile.exists())
- fileNameAdditionExtra++;
- else
- break;
- }
- if(fileNameAdditionExtra > 0) outputFileName += "_"+fileNameAdditionExtra;
- outputFileName += ".csv";
-
- outputWriter = new FileWriter(outputFileName);
- outputWriter.write(outputStringBuilder.toString());
- outputWriter.close();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- System.out.println("Could not write network simulation output to file");
- }
-
- }
-
- /**
- * Returns the SCADA Tag for a given destination PLC in the style of dataset A1.
- * @param PLCNumber 1-6
- * @return The SCADA Tag for a given destination PLC in the style of dataset A1.
- */
- private String getSCADATagDatasetA1ForDestinationPLC(int PLCNumber){
- String SCADATag = "";
- switch(PLCNumber) {
- case 1:
- SCADATag = "HMI_LIT101";
- break;
- case 2:
- String[] tags = {"HMI_FIT201", "HMI_AIT202"};
- int randomNumber = ThreadLocalRandom.current().nextInt(0, 2);
- SCADATag = tags[randomNumber];
- break;
- case 3:
- SCADATag = "HMI_LIT301";
- break;
- case 4:
- SCADATag = "HMI_LIT401";
- break;
- case 5:
- SCADATag = "HMI_AIT501";
- break;
- case 6:
- SCADATag = "HMI_FIT601";
- break;
- }
- return SCADATag;
- }
-
- /**
- * Generates a valid transaction ID that is currently not in use.</br>
- * Synchronized to enable parallelization.
- * @param startDate The start date of the read tag service.
- * @param endDate The end date of the read tag service.
- * @return The transaction ID.
- */
- private synchronized int getValidTransactionID(Date startDate, Date endDate) {
- int randomID = 0;
- Pair<Date, Date> currentDatePair = new Pair<Date, Date>(startDate, endDate);
- while(true) {
- randomID = ThreadLocalRandom.current().nextInt(0, 65536);
- if(transactionIDsCurrentlyInUseUntil.containsKey(randomID)) {
- boolean iDIsGood = false;
- LinkedList<Pair<Date, Date>> transactionIDDates = transactionIDsCurrentlyInUseUntil.get(randomID);
- int numberOfDates = transactionIDDates.size();
- Date pairBeforeEndDate;
- Date pairAfterStartDate;
- if(numberOfDates == 1) { // Add before or after the only other pair
- Pair<Date, Date> firstDatePair = transactionIDDates.getFirst();
- if(firstDatePair.getLeft().after(endDate))
- transactionIDDates.add(0, currentDatePair);
- else
- transactionIDDates.add(currentDatePair);
- iDIsGood = true;
- }
- else
- for(int i = 1; i <= numberOfDates; i++) {
- if(i == 1 && transactionIDDates.get(0).getLeft().after(endDate)) { // Add before all existing pairs
- transactionIDDates.add(0, currentDatePair);
- iDIsGood = true;
- break;
- }
- else if(i == numberOfDates) { // Add after all existing pairs
- transactionIDDates.add(currentDatePair);
- iDIsGood = true;
- break;
- }
- else { // Add between pairs
- pairBeforeEndDate = transactionIDDates.get(i-1).getRight();
- pairAfterStartDate = transactionIDDates.get(i).getLeft();
- if(pairBeforeEndDate.before(startDate) && pairAfterStartDate.after(endDate)) {
- // Add new time window
- transactionIDDates.add(i, currentDatePair);
- iDIsGood = true;
- break;
- }
- }
- }
- if(iDIsGood) {
- transactionIDsCurrentlyInUseUntil.put(randomID, transactionIDDates);
- break;
- }
- }
- else {
- // ID was never in use until now
- LinkedList<Pair<Date, Date>> transactionIDDates = new LinkedList<Pair<Date, Date>>();
- transactionIDDates.add(currentDatePair);
- transactionIDsCurrentlyInUseUntil.put(randomID, transactionIDDates);
- break;
- }
- }
- return randomID;
- }
-
- /**
- * Sets the distribution handlers.
- */
- private void setDatasetDistributionHandlers() {
- // Some lines are commented out because they are for very rare special cases
- distributionHandlers.put("DatasetA1Distribution_Request_EngineeringWorkstation-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_EngineeringWorkstation-Historian_corrected.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_EngineeringWorkstation-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_EngineeringWorkstation-PLC5.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_EngineeringWorkstation-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_EngineeringWorkstation-SCADA_corrected.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_Historian-EngineeringWorkstation", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_Historian-EngineeringWorkstation_corrected.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_Historian-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_Historian-PLC1_corrected.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_Historian-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_Historian-PLC2.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_Historian-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_Historian-PLC3.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_PLC1-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_PLC1-PLC2.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_PLC2-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_PLC2-PLC3.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_PLC3-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_PLC3-PLC4.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_PLC6-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_PLC6-PLC1.txt"));
- distributionHandlers.put("DatasetA1Distribution_Request_PLC6-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_PLC6-PLC2.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC1.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC2.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC3.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC4.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC5.txt"));
- // distributionHandlers.put("DatasetA1Distribution_Request_SCADA-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Request_SCADA-PLC6.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_EngineeringWorkstation-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_EngineeringWorkstation-Historian.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_Historian-EngineeringWorkstation", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_Historian-EngineeringWorkstation.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC1-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC1-PLC6.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC1-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC1-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC2-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC2-PLC1.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC2-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC2-PLC6.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC2-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC2-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC3-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC3-Historian.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC3-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC3-PLC2.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC3-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC3-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC4-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC4-PLC3.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC4-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC4-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC5-EngineeringWorkstation", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC5-EngineeringWorkstation.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC5-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC5-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_PLC6-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_PLC6-SCADA.txt"));
- distributionHandlers.put("DatasetA1Distribution_Response_SCADA-EngineeringWorkstation", SWaTUtilities.readDatasetDistributionData("DatasetA1Distribution_Response_SCADA-EngineeringWorkstation.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_Historian-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_Historian-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC1-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC1-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC1-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC1-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC1-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC1-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC1-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC1-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC1-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC1-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC2-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC2-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC2-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC2-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC2-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC2-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC3-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC3-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC3-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC3-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC3-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC3-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC4-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC4-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC4-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC4-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC5-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC5-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC6-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC6-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_PLC6-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_PLC6-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Request_SCADA-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Request_SCADA-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC1-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC1-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC1-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC1-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC1-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC1-SCADA.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC2-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC2-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC2-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC2-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC2-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC2-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC2-PLC6", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC2-PLC6.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC2-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC2-SCADA.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC3-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC3-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC3-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC3-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC3-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC3-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC3-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC3-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC3-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC3-SCADA.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-PLC5", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-PLC5.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC4-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC4-SCADA.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC5-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC5-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC5-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC5-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC5-PLC2", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC5-PLC2.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC5-PLC4", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC5-PLC4.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC5-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC5-SCADA.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC6-Historian", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC6-Historian.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC6-PLC1", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC6-PLC1.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC6-PLC3", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC6-PLC3.txt"));
- distributionHandlers.put("DatasetA6Distribution_Response_PLC6-SCADA", SWaTUtilities.readDatasetDistributionData("DatasetA6Distribution_Response_PLC6-SCADA.txt"));
- }
-
- /**
- * Append elements to allTimes in a thread-safe way.
- * @param pairToAdd The pair of times to add to allTimes.
- */
- private synchronized void appendToAllTimesSynchronized(Pair<Double, String> pairToAdd) {
- allTimes.add(pairToAdd);
- if(optimizeOutput)
- if(allTimes.size() == rowsPerOutputFile*5) // The multiplicator can be changed for further optimization wrt. the available RAM
- saveCSVOutputOneFile();
- }
-
- /**
- * Saves one file worth of CSV output.
- */
- private void saveCSVOutputOneFile() {
- String filePathName = outputDirectoryPath+"/IoTDGF_SWaT Simulation";
- String fileNameAddition = "_"+new SimpleDateFormat("yyyy-MM-dd HH.mm.ss").format(outputFileNameTime.getTime())+"_Network";
- // Write file
- FileWriter outputWriter;
- try {
- outputFileCounter++;
- sortTimesList();
- Calendar currentTime = (Calendar) startTime.clone();
- double currentRunTimeDouble = allTimes.getLast().getLeft();
- int currentRunTime = (int) currentRunTimeDouble;
- currentTime.set(Calendar.SECOND, currentTime.get(Calendar.SECOND)+currentRunTime-60);
- removeOldTransactionIDs(currentTime.getTime());
-
- int rowsPerFileCurrent = rowsPerOutputFile;
- int numberOfTimesTenth = rowsPerOutputFile/100;
- int num = 0;
- if(numberOfTimesTenth == 0) numberOfTimesTenth = 1;
- if(passByReferenceValue_KeepSimulationRunning[0] == false) return;
- StringBuilder outputStringBuilder = new StringBuilder(300*rowsPerOutputFile);
- outputStringBuilder.append("num,date,time,orig,type,i/f_name,i/f_dir,src,dst,proto,appi_name,"+
- "proxy_src_ip,Modbus_Function_Code,Modbus_Function_Description"+
- ",Modbus_Transaction_ID,SCADA_Tag,Modbus_Value,service,s_port,Tag\n");
- for(int i = 0; i < rowsPerFileCurrent; i++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) return;
- num++;
- outputFileRowCounter++;
- String CSVRow = allTimes.pop().getRight();
- outputStringBuilder.append(outputFileRowCounter+","+CSVRow);
- if(i < rowsPerFileCurrent-1)
- outputStringBuilder.append("\n");
- if(num % numberOfTimesTenth == 0) {
- propertyChangeSupport.firePropertyChange("statusPercentageNetworkOutput", 0, (int)(num/numberOfTimesTenth));
- }
- }
- if(passByReferenceValue_KeepSimulationRunning[0] == true) {
- String outputFileName = filePathName+fileNameAddition;
- outputFileName += "_"+outputFileCounter;
-
- // Try file name combinations until one does not yet exist
- File outputFile;
- int fileNameAdditionExtra = 0;
- while(true) {
- String fileNameCandidate = outputFileName;
- if(fileNameAdditionExtra > 0) fileNameCandidate += "_"+fileNameAdditionExtra;
- outputFile = new File(fileNameCandidate+".csv");
-
- if(outputFile.exists())
- fileNameAdditionExtra++;
- else
- break;
- }
- if(fileNameAdditionExtra > 0) outputFileName += "_"+fileNameAdditionExtra;
- outputFileName += ".csv";
-
- outputWriter = new FileWriter(outputFileName);
- outputWriter.write(outputStringBuilder.toString());
- outputWriter.close();
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- System.out.println("Could not write network simulation output to file");
- }
-
- }
-
- /**
- * Saves the rest of the CSV output.
- */
- private void saveCSVOutputRest() {
- String filePathName = outputDirectoryPath+"/IoTDGF_SWaT Simulation";
- String fileNameAddition = "_"+new SimpleDateFormat("yyyy-MM-dd HH.mm.ss").format(outputFileNameTime.getTime())+"_Network";
- // Write file
- FileWriter outputWriter;
- try {
- sortTimesList();
- double rowsPerFileCurrent = rowsPerOutputFile;
- double numberOfTimes = allTimes.size();
- int numberOfFiles = (int) Math.ceil(numberOfTimes/rowsPerOutputFile);
- int rowsInLastFile = (int) (numberOfTimes-rowsPerOutputFile*(numberOfFiles-1));
- int num = 0;
- int numberOfTimesTenth = (int) numberOfTimes/100;
- if(numberOfTimesTenth == 0) numberOfTimesTenth = 1;
- for(int j = 0; j < numberOfFiles; j++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) return;
- outputFileCounter++;
- if(j == numberOfFiles-1) // Last File
- rowsPerFileCurrent = rowsInLastFile;
- StringBuilder outputStringBuilder = new StringBuilder(300*rowsPerOutputFile);
- outputStringBuilder.append("num,date,time,orig,type,i/f_name,i/f_dir,src,dst,proto,appi_name,"+
- "proxy_src_ip,Modbus_Function_Code,Modbus_Function_Description"+
- ",Modbus_Transaction_ID,SCADA_Tag,Modbus_Value,service,s_port,Tag\n");
- for(int i = 0; i < rowsPerFileCurrent; i++) {
- if(passByReferenceValue_KeepSimulationRunning[0] == false) return;
- num++;
- outputFileRowCounter++;
- String CSVRow = allTimes.pop().getRight();//allTimes.get((int)(j*rowsPerFile+i)).getRight();
- outputStringBuilder.append(outputFileRowCounter+","+CSVRow);
- if(i < rowsPerFileCurrent-1)
- outputStringBuilder.append("\n");
- if(num % numberOfTimesTenth == 0) {
- propertyChangeSupport.firePropertyChange("statusPercentageNetworkOutput", 0, (int)(num/numberOfTimesTenth));
- }
- }
- if(passByReferenceValue_KeepSimulationRunning[0] == true) {
- String outputFileName = filePathName+fileNameAddition;
- outputFileName += "_"+outputFileCounter;
-
- // Try file name combinations until one does not yet exist
- File outputFile;
- int fileNameAdditionExtra = 0;
- while(true) {
- String fileNameCandidate = outputFileName;
- if(fileNameAdditionExtra > 0) fileNameCandidate += "_"+fileNameAdditionExtra;
- outputFile = new File(fileNameCandidate+".csv");
-
- if(outputFile.exists())
- fileNameAdditionExtra++;
- else
- break;
- }
- if(fileNameAdditionExtra > 0) outputFileName += "_"+fileNameAdditionExtra;
- outputFileName += ".csv";
-
- outputWriter = new FileWriter(outputFileName);
- outputWriter.write(outputStringBuilder.toString());
- outputWriter.close();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- System.out.println("Could not write network simulation output to file");
- }
-
- }
-
- /**
- * Removes the transaction IDs with a end time in the before the date variable.
- * @param currentDateTime The data variable.
- */
- private void removeOldTransactionIDs(Date currentDateTime) {
- for(int i = 0; i < 65536; i++) {
- if(transactionIDsCurrentlyInUseUntil.containsKey(i)) {
- LinkedList<Pair<Date, Date>> datePairList = transactionIDsCurrentlyInUseUntil.get(i);
- while(true) {
- if(datePairList.size() == 0) break;
- Pair<Date, Date> datePair = datePairList.getFirst();
- if(datePair.getRight().before(currentDateTime))
- datePairList.removeFirst();
- else
- break;
- }
- }
- }
- }
- }
|