Merge branch 'master' of https://github.uci.edu/rtrimana/smart_home_traffic
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / analysis / TriggerTrafficExtractor.java
1 package edu.uci.iotproject.analysis;
2
3 import edu.uci.iotproject.io.PcapHandleReader;
4 import org.pcap4j.core.*;
5
6 import java.time.Instant;
7 import java.util.Collections;
8 import java.util.List;
9 import java.util.concurrent.TimeoutException;
10
11 /**
12  * TODO add class documentation.
13  *
14  * @author Janus Varmarken
15  */
16 public class TriggerTrafficExtractor implements PcapPacketFilter {
17
18     private final String mPcapFilePath;
19     private final List<Instant> mTriggerTimes;
20     private final String mDeviceIp;
21
22     private int mTriggerIndex = 0;
23
24
25     private static final int INCLUSION_WINDOW_MILLIS = 20_000;
26
27     public TriggerTrafficExtractor(String pcapFilePath, List<Instant> triggerTimes, String deviceIp) throws PcapNativeException, NotOpenException {
28         mPcapFilePath = pcapFilePath;
29         // Ensure that trigger times are sorted in ascending as we rely on this fact in the logic that works out if a
30         // packet is related to a trigger.
31         Collections.sort(triggerTimes, (i1, i2) -> {
32             if (i1.isBefore(i2)) return -1;
33             else if (i2.isBefore(i1)) return 1;
34             else return 0;
35         });
36         mTriggerTimes = Collections.unmodifiableList(triggerTimes);
37         mDeviceIp = deviceIp;
38     }
39
40
41     public void performExtraction(PacketListener... extractedPacketsConsumers) throws PcapNativeException, NotOpenException, TimeoutException {
42         PcapHandle handle;
43         try {
44             handle = Pcaps.openOffline(mPcapFilePath, PcapHandle.TimestampPrecision.NANO);
45         } catch (PcapNativeException pne) {
46             handle = Pcaps.openOffline(mPcapFilePath);
47         }
48         // Use the native support for BPF to immediately filter irrelevant traffic.
49         handle.setFilter("ip host " + mDeviceIp, BpfProgram.BpfCompileMode.OPTIMIZE);
50         PcapHandleReader pcapReader = new PcapHandleReader(handle, this, extractedPacketsConsumers);
51         pcapReader.readFromHandle();
52         // Reset trigger index (in case client code chooses to rerun the extraction)
53         mTriggerIndex = 0;
54     }
55
56     @Override
57     public boolean shouldIncludePacket(PcapPacket packet) {
58         // New version. Simpler, but slower: the later a packet arrives, the more elements of mTriggerTimes will need to
59         // be traversed.
60         return mTriggerTimes.stream().anyMatch(
61                 trigger -> trigger.isBefore(packet.getTimestamp()) &&
62                         packet.getTimestamp().isBefore(trigger.plusMillis(INCLUSION_WINDOW_MILLIS))
63         );
64
65         /*
66         // Old version. Faster, but more complex - is it correct?
67         if (mTriggerIndex >= mTriggerTimes.size()) {
68             // Don't include packet if we've exhausted the list of trigger times.
69             return false;
70         }
71
72         // TODO hmm, is this correct?
73         Instant trigger = mTriggerTimes.get(mTriggerIndex);
74         if (trigger.isBefore(packet.getTimestamp()) &&
75                 packet.getTimestamp().isBefore(trigger.plusMillis(INCLUSION_WINDOW_MILLIS))) {
76             // Packet lies within INCLUSION_WINDOW_MILLIS after currently considered trigger, include it.
77             return true;
78         } else {
79             if (!trigger.isBefore(packet.getTimestamp())) {
80                 // Packet is before currently considered trigger, so it shouldn't be included
81                 return false;
82             } else {
83                 // Packet is >= INCLUSION_WINDOW_MILLIS after currently considered trigger.
84                 // Proceed to next trigger to see if it lies in range of that.
85                 // Note that there's an assumption here that no two trigger intervals don't overlap!
86                 mTriggerIndex++;
87                 return shouldIncludePacket(packet);
88             }
89         }
90         */
91     }
92
93 }