1 package edu.uci.iotproject.io;
3 import edu.uci.iotproject.analysis.PcapPacketFilter;
4 import org.pcap4j.core.*;
6 import java.io.EOFException;
7 import java.util.concurrent.TimeoutException;
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.
13 * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
14 * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
16 public class PcapHandleReader {
18 private final PcapPacketFilter mPacketFilter;
19 private final PcapHandle mHandle;
20 private final PacketListener[] mPacketListeners;
21 private volatile boolean mTerminated = false;
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.
33 public PcapHandleReader(PcapHandle handle, PcapPacketFilter packetFilter, PacketListener... packetListeners) {
35 mPacketFilter = packetFilter;
36 mPacketListeners = packetListeners;
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.
45 public void readFromHandle() throws PcapNativeException, NotOpenException {
46 int outOfOrderPackets = 0;
48 PcapPacket prevPacket = null;
49 PcapPacket packet = null;
51 while (!mTerminated) {
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.
62 System.err.println("null-packet read from handle");
66 if (prevPacket != null && packet.getTimestamp().isBefore(prevPacket.getTimestamp())) {
69 // Fail early if assumption doesn't hold.
71 throw new AssertionError("Packets not in ascending temporal order");
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);
82 } catch (EOFException eof) {
83 // Reached end of file. All good.
84 System.out.println(String.format("%s: finished reading pcap file", getClass().getSimpleName()));
86 if (outOfOrderPackets > 0) {
88 String.format("[[[ %s: %d packets appeared out of order (with regards to their timestamps) ]]]",
89 getClass().getSimpleName(), outOfOrderPackets));
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
102 public void stopReading() {
107 * Checks if this {@link PcapHandleReader} has gracefully terminated, i.e., that the wrapped {@link PcapHandle} has
110 * @return {@code true} if this {@link PcapHandleReader} has terminated, {@code false} otherwise.
112 public boolean hasTerminated() {
113 return mTerminated && !mHandle.isOpen();