Renaming root project name.
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / io / PcapHandleReader.java
1 package edu.uci.iotproject.io;
2
3 import edu.uci.iotproject.analysis.PcapPacketFilter;
4 import org.pcap4j.core.*;
5
6 import java.io.EOFException;
7 import java.util.concurrent.TimeoutException;
8
9 /**
10  * Reads packets from a {@link PcapHandle} (online or offline) and delivers those packets that pass the test exercised
11  * by the provided {@link PcapPacketFilter} onto the provided {@link PacketListener}s.
12  *
13  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
14  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
15  */
16 public class PcapHandleReader {
17
18     private final PcapPacketFilter mPacketFilter;
19     private final PcapHandle mHandle;
20     private final PacketListener[] mPacketListeners;
21     private volatile boolean mTerminated = false;
22
23     /**
24      * Create a {@code PcapHandleReader}.
25      * @param handle An <em>open</em> {@link PcapHandle} that packets will be read from.
26      * @param packetFilter A {@link PcapPacketFilter} that dictates which of the packets read from {@code handle} should
27      *                     be delivered to {@code packetListeners}. Note that while a value of {@code null} is not
28      *                     permitted here, the caller can instead simply provide an implementation that always returns
29      *                     {@code true} if they want to include all packets read from {@code handle}.
30      * @param packetListeners One or more {@link PacketListener}s to which those packets read from {@code handle} that
31      *                        pass through {@code packetFilter} are delivered.
32      */
33     public PcapHandleReader(PcapHandle handle, PcapPacketFilter packetFilter, PacketListener... packetListeners) {
34         mHandle = handle;
35         mPacketFilter = packetFilter;
36         mPacketListeners = packetListeners;
37     }
38
39
40     /**
41      * Start reading (and filtering) packets from the provided {@link PcapHandle}.
42      * @throws PcapNativeException if an error occurs in the pcap native library.
43      * @throws NotOpenException if the provided {@code PcapHandle} is not open.
44      */
45     public void readFromHandle() throws PcapNativeException, NotOpenException {
46         int outOfOrderPackets = 0;
47         try {
48             PcapPacket prevPacket = null;
49             PcapPacket packet = null;
50
51             while (!mTerminated) {
52                 try {
53                     packet = mHandle.getNextPacketEx();
54                 } catch (TimeoutException te) {
55                     System.err.println("timeout occurred while reading from network interface");
56                     // No need to check termination flag here. Can defer it to the loop condition as it is the next
57                     // instruction anyway.
58                     continue;
59                 }
60
61                 if (packet == null) {
62                     System.err.println("null-packet read from handle");
63                     continue;
64                 }
65
66                 if (prevPacket != null && packet.getTimestamp().isBefore(prevPacket.getTimestamp())) {
67                     outOfOrderPackets++;
68                     /*
69                     // Fail early if assumption doesn't hold.
70                     mHandle.close();
71                     throw new AssertionError("Packets not in ascending temporal order");
72                     */
73                 }
74                 if (mPacketFilter.shouldIncludePacket(packet)) {
75                     // Packet accepted for inclusion; deliver it to observing client code.
76                     for (PacketListener consumer : mPacketListeners) {
77                         consumer.gotPacket(packet);
78                     }
79                 }
80                 prevPacket = packet;
81             }
82         } catch (EOFException eof) {
83             // Reached end of file. All good.
84             System.out.println(String.format("%s: finished reading pcap file", getClass().getSimpleName()));
85         }
86         if (outOfOrderPackets > 0) {
87             System.err.println(
88                     String.format("[[[ %s: %d packets appeared out of order (with regards to their timestamps) ]]]",
89                             getClass().getSimpleName(), outOfOrderPackets));
90         }
91         mHandle.close();
92     }
93
94     /**
95      * Stop reading from the wrapped {@link PcapHandle}. Note that this call only <em>initiates</em> the shutdown by
96      * setting a termination flag. Shutdown will be deferred until the time at which this flag can be checked by
97      * {@link #readFromHandle()}. For example, if {@link #readFromHandle()} is currently in the middle of a blocking
98      * call to {@link PcapHandle#getNextPacketEx()}, shutdown will not occur until the next packet is returned from the
99      * wrapped {@link PcapHandle} or its read timeout expires. Use {@link #hasTerminated()} to check if the shutdown
100      * has completed.
101      */
102     public void stopReading() {
103         mTerminated = true;
104     }
105
106     /**
107      * Checks if this {@link PcapHandleReader} has gracefully terminated, i.e., that the wrapped {@link PcapHandle} has
108      * been closed.
109      *
110      * @return {@code true} if this {@link PcapHandleReader} has terminated, {@code false} otherwise.
111      */
112     public boolean hasTerminated() {
113         return mTerminated && !mHandle.isOpen();
114     }
115
116 }