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