Adding more execution parameters for experimental results (evaluation).
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / util / PrintUtils.java
index ae6b5786c47503f5b40842f84a90d11fa01f50bc..3d3a3beee61143adcbe351674fcb88bf1c0c079e 100644 (file)
@@ -2,11 +2,19 @@ package edu.uci.iotproject.util;
 
 import edu.uci.iotproject.DnsMap;
 import edu.uci.iotproject.analysis.PcapPacketPair;
+import org.apache.commons.math3.stat.clustering.Cluster;
 
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.pcap4j.core.PcapPacket;
+
 /**
  * Utility methods for generating (output) strings.
  *
@@ -15,8 +23,125 @@ import java.util.stream.Collectors;
  */
 public class PrintUtils {
 
+    /**
+     * This is the path for writing the list of list of packet pairs {@code List<List<PcapPacket>>} into a file.
+     * The packet pairs are the pairs in one cluster, so the list represents a cluster that has been derived through
+     * the DBSCAN algorithm.
+     *
+     * E.g., this file could contain a list like the following:
+     *
+     * [[1109, 613],[1111, 613],[1115, 613],...]
+     *
+     * This list has lists of PcapPacket pairs as its members. We do not maintain the pairs in the form of
+     * {@code Cluster<PcapPacketPair>} objects because there might be a situation where we could combine multiple
+     * PcapPacketPair objects into a longer signature, i.e., a string of PcapPacket objects and not just a pair.
+     */
+    private static final String SERIALIZABLE_FILE_PATH = "./signature.sig";
+
     private PrintUtils() { /* private constructor to prevent instantiation */ }
 
+    /**
+     * Write the list of list of packet pairs {@code List<List<PcapPacket>>} into a file.
+     *
+     * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of
+     * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects.
+     * We do not maintain the pairs in the form of {@code Cluster<PcapPacketPair>} objects because there might be
+     * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of
+     * PcapPacket objects and not just a pair.
+     *
+     * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the
+     *                 default file name {@code SERIALIZABLE_FILE_PATH}.
+     * @param clusterPackets The {@link Cluster} objects in the form of list of {@code PcapPacket} objects.
+     */
+    public static void serializeClustersIntoFile(String fileName, List<List<PcapPacket>> clusterPackets) {
+        if (fileName == null)
+            fileName = SERIALIZABLE_FILE_PATH;
+        try (ObjectOutputStream oos =
+                new ObjectOutputStream(new FileOutputStream(fileName))) {
+            oos.writeObject(clusterPackets);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Write the signature {@code List<List<List<PcapPacket>>>} into a file.
+     *
+     * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of
+     * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects.
+     * We do not maintain the pairs in the form of {@code Cluster<PcapPacketPair>} objects because there might be
+     * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of
+     * PcapPacket objects and not just a pair.
+     *
+     * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the
+     *                 default file name {@code SERIALIZABLE_FILE_PATH}.
+     * @param signature The {@link Cluster} objects in the form of list of {@code PcapPacket} objects.
+     */
+    public static void serializeSignatureIntoFile(String fileName, List<List<List<PcapPacket>>> signature) {
+        if (fileName == null)
+            fileName = SERIALIZABLE_FILE_PATH;
+        try (ObjectOutputStream oos =
+                     new ObjectOutputStream(new FileOutputStream(fileName))) {
+            oos.writeObject(signature);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Read the list of list of packet pairs {@code List<List<PcapPacket>>} from a file.
+     *
+     * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of
+     * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects.
+     * We do not maintain the pairs in the form of {@code Cluster<PcapPacketPair>} objects because there might be
+     * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of
+     * PcapPacket objects and not just a pair.
+     *
+     * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the
+     *                 default file name {@code SERIALIZABLE_FILE_PATH}.
+     * @return The list of list of {@link Cluster} objects ({@code List<List<PcapPacket>>}) that is read from file.
+     */
+    public static List<List<PcapPacket>> deserializeClustersFromFile(String fileName) {
+        if (fileName == null)
+            fileName = SERIALIZABLE_FILE_PATH;
+        List<List<PcapPacket>> ppListOfList = null;
+        try (ObjectInputStream ois =
+                     new ObjectInputStream(new FileInputStream(fileName))) {
+            ppListOfList = (List<List<PcapPacket>>) ois.readObject();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        return ppListOfList;
+    }
+
+    /**
+     * Read the list of list of packet pairs {@code List<List<List<PcapPacket>>>} from a file.
+     *
+     * After the DBSCAN algorithm derives the clusters from pairs, we save the signature in the form of list of
+     * packet pairs. We harvest the pairs and transform them back into a list of PcapPacket objects.
+     * We do not maintain the pairs in the form of {@code Cluster<PcapPacketPair>} objects because there might be
+     * a situation where we could combine multiple PcapPacketPair objects into a longer signature, i.e., a string of
+     * PcapPacket objects and not just a pair.
+     *
+     * @param fileName The path of the file in {@link String}. We could leave this one {@code null} if we wanted the
+     *                 default file name {@code SERIALIZABLE_FILE_PATH}.
+     * @return The list of list of list of {@link Cluster} objects ({@code List<List<List<PcapPacket>>>})
+     *         that is read from file.
+     */
+    public static List<List<List<PcapPacket>>> deserializeSignatureFromFile(String fileName) {
+        if (fileName == null)
+            fileName = SERIALIZABLE_FILE_PATH;
+        List<List<List<PcapPacket>>> ppListOfListOfList = null;
+        try (ObjectInputStream ois =
+                     new ObjectInputStream(new FileInputStream(fileName))) {
+            ppListOfListOfList = (List<List<List<PcapPacket>>>) ois.readObject();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        return ppListOfListOfList;
+    }
 
     /**
      * Converts a {@code PcapPacketPair} into a CSV string containing the packet lengths of the two packets in the pair.
@@ -61,15 +186,15 @@ public class PrintUtils {
         Optional<Set<String>> secondHostnames = secondSrc.map(src -> ipHostnameMappings.getHostnamesForIp(src));
         final String delimiter = " ";
         if (firstHostnames != null) {
-            // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
+            // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter).
             firstSrc = firstHostnames.stream().collect(Collectors.joining(delimiter));
         }
-        // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter)
+        // If one IP maps to multiple hostnames, we concatenate the hostnames (separated by a delimiter).
         Optional<String> hostnames = secondHostnames.map(hostnameSet -> hostnameSet.stream().collect(Collectors.joining(delimiter)));
         // Fall back to IP if we couldn't second pair is present, but we couldn't map to (a) hostname(s).
         secondSrc = hostnames.isPresent() ? hostnames : secondSrc;
 
-        // Check if the first source is C (client) or S (server)
+        // Check if the first source is C (client) or S (server).
         String firstSrcCorS = packetPair.isFirstClient() ? "C" : "S";
         String secondSrcCorS = packetPair.isSecondClient() ? "C" : "S";
 
@@ -81,4 +206,16 @@ public class PrintUtils {
                 secondSrcCorS);
     }
 
+    /**
+     * Generate a string that summarizes/describes {@code cluster}.
+     * @param cluster The {@link Cluster} to summarize/describe.
+     * @return A string that summarizes/describes {@code cluster}.
+     */
+    public static String toSummaryString(Cluster<PcapPacketPair> cluster) {
+        StringBuilder sb = new StringBuilder();
+        for (PcapPacketPair ppp : cluster.getPoints()) {
+            sb.append(toCsv(ppp, ppp.getDnsMap()) + System.lineSeparator());
+        }
+        return sb.toString();
+    }
 }