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 = 3_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         if (mTriggerIndex >= mTriggerTimes.size()) {
59             // Don't include packet if we've exhausted the list of trigger times.
60             return false;
61         }
62
63         // TODO hmm, is this correct?
64         Instant trigger = mTriggerTimes.get(mTriggerIndex);
65         if (trigger.isBefore(packet.getTimestamp()) &&
66                 packet.getTimestamp().isBefore(trigger.plusMillis(INCLUSION_WINDOW_MILLIS))) {
67             // Packet lies within INCLUSION_WINDOW_MILLIS after currently considered trigger, include it.
68             return true;
69         } else {
70             if (!trigger.isBefore(packet.getTimestamp())) {
71                 // Packet is before currently considered trigger, so it shouldn't be included
72                 return false;
73             } else {
74                 // Packet is >= INCLUSION_WINDOW_MILLIS after currently considered trigger.
75                 // Proceed to next trigger to see if it lies in range of that.
76                 // Note that there's an assumption here that no two trigger intervals don't overlap!
77                 mTriggerIndex++;
78                 return shouldIncludePacket(packet);
79             }
80         }
81     }
82
83 }