+
+ /**
+ * Sort the signatures in the {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects.
+ * The purpose of this is to sort the order of signatures in the signature list. For detection purposes, we need
+ * to know if one signature occurs earlier/later in time with respect to the other signatures for more confidence
+ * in detecting the occurrence of an event.
+ * @param signatures A {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects that needs sorting.
+ * We assume that innermost {@code List} of {@code PcapPacket} objects have been sorted ascending
+ * by timestamps. By the time we use this method, we should have sorted it when calling the
+ * {@code clusterToListOfPcapPackets} method.
+ * @return A sorted {@code List} of {@code List} of {@code List} of {@code PcapPacket} objects.
+ */
+ public static List<List<List<PcapPacket>>> sortSignatures(List<List<List<PcapPacket>>> signatures) {
+ // TODO: This is the simplest solution!!! Might not cover all corner cases.
+ // TODO: Sort the list of lists based on the first packet's timestamps!
+ //Collections.sort(signatures, (p1, p2) -> {
+ // return p1.get(0).get(0).getTimestamp().compareTo(p2.get(0).get(0).getTimestamp());
+ //});
+ // TODO: The following is a more complete solution that covers corner cases.
+ // Sort the list of lists based on one-to-one comparison between timestamps of signatures on both lists.
+ // This also takes into account the fact that the number of signatures in the two lists could be different.
+ // Additionally, this code forces the comparison between two signatures only if they occur in the
+ // INCLUSION_WINDOW_MILLIS window; otherwise, it tries to find the right pair of signatures in the time window.
+ Collections.sort(signatures, (p1, p2) -> {
+ int compare = 0;
+ int comparePrev = 0;
+ int count1 = 0;
+ int count2 = 0;
+ // Need to make sure that both are not out of bound!
+ while(count1 + 1 < p1.size() && count2 + 1 < p2.size()) {
+ long timestamp1 = p1.get(count1).get(0).getTimestamp().toEpochMilli();
+ long timestamp2 = p2.get(count2).get(0).getTimestamp().toEpochMilli();
+ // The two timestamps have to be within a 15-second window!
+ if(Math.abs(timestamp1 - timestamp2) < TriggerTrafficExtractor.INCLUSION_WINDOW_MILLIS) {
+ // If these two are within INCLUSION_WINDOW_MILLIS window then compare!
+ compare = p1.get(count1).get(0).getTimestamp().compareTo(p2.get(count2).get(0).getTimestamp());
+ if (comparePrev != 0) { // First time since it is 0
+ if (Integer.signum(compare) != Integer.signum(comparePrev)) {
+ // Throw an exception if the order of the two signatures is not consistent,
+ // E.g., 111, 222, 333 in one occassion and 222, 333, 111 in the other.
+ throw new Error("For some reason, the order of signatures are not always consistent!" +
+ "Returning the original data structure of signatures...");
+ }
+ }
+ comparePrev = compare;
+ count1++;
+ count2++;
+ } else {
+ // If not within INCLUSION_WINDOW_MILLIS window then find the correct pair
+ // by incrementing one of them.
+ if(timestamp1 < timestamp2)
+ count1++;
+ else
+ count2++;
+ }
+ }
+ return compare;
+ });
+ return signatures;
+ }