f8c323782485527c2bd0dc26858618ab6baca6dd
[pingpong.git] / Code / Projects / PacketLevelSignatureExtractor / src / main / java / edu / uci / iotproject / trafficreassembly / layer2 / Layer2Flow.java
1 package edu.uci.iotproject.trafficreassembly.layer2;
2
3 import org.pcap4j.core.PcapPacket;
4 import org.pcap4j.packet.EthernetPacket;
5 import org.pcap4j.util.MacAddress;
6
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.List;
10
11 /**
12  * Models a layer 2 flow: groups packets exchanged between two specific endpoints (MAC addresses).
13  *
14  * @author Janus Varmarken {@literal <jvarmark@uci.edu>}
15  * @author Rahmadi Trimananda {@literal <rtrimana@uci.edu>}
16  */
17 public class Layer2Flow {
18
19     /**
20      * The first endpoint of this layer 2 flow.
21      */
22     private final MacAddress mEndpoint1;
23
24     /**
25      * The second endpoint of this layer 2 flow.
26      */
27     private final MacAddress mEndpoint2;
28
29     /**
30      * Clients observing for changes to this layer 2 flow.
31      */
32     private final List<Layer2FlowObserver> mFlowObservers = new ArrayList<>();
33
34     public Layer2Flow(MacAddress endpoint1, MacAddress endpoint2) {
35         mEndpoint1 = endpoint1;
36         mEndpoint2 = endpoint2;
37     }
38
39     /**
40      * Get the first endpoint of this flow.
41      * @return the first endpoint of this flow.
42      */
43     public MacAddress getEndpoint1() {
44         return mEndpoint1;
45     }
46
47     /**
48      * Get the second endpoint of this flow.
49      * @return the second endpoint of this flow.
50      */
51     public MacAddress getEndpoint2() {
52         return mEndpoint2;
53     }
54
55     /**
56      * Register as an observer of this flow.
57      * @param observer The client that is to be notified whenever this flow changes (has new packets added).
58      */
59     public void addFlowObserver(Layer2FlowObserver observer) {
60         mFlowObservers.add(observer);
61     }
62
63     /**
64      * Deregister as an observer of this flow.
65      * @param observer The client that no longer wishes to be notified whenever this flow changes.
66      */
67     public void removeFlowObserver(Layer2FlowObserver observer) {
68         mFlowObservers.remove(observer);
69     }
70
71     /**
72      * The packets in the flow.
73      */
74     private final List<PcapPacket> mPackets = new ArrayList<>();
75
76     /**
77      * Add a packet to this flow.
78      * @param packet The packet that is to be added to the flow.
79      */
80     public void addPacket(PcapPacket packet) {
81         verifyAddresses(packet);
82         mPackets.add(packet);
83         // Notify flow observers of the new packet
84         mFlowObservers.forEach(o -> o.onNewPacket(this, packet));
85     }
86
87     /**
88      * Get the packets pertaining to this flow.
89      * @return The packets pertaining to this flow.
90      */
91     public List<PcapPacket> getPackets() {
92         return Collections.unmodifiableList(mPackets);
93     }
94
95     /**
96      * Verify that a packet pertains to this flow.
97      * @param packet The packet that is to be verified.
98      */
99     private void verifyAddresses(PcapPacket packet) {
100         EthernetPacket ethPkt = packet.get(EthernetPacket.class);
101         MacAddress srcAddr = ethPkt.getHeader().getSrcAddr();
102         MacAddress dstAddr = ethPkt.getHeader().getDstAddr();
103         if ((mEndpoint1.equals(srcAddr) && mEndpoint2.equals(dstAddr)) ||
104                 (mEndpoint1.equals(dstAddr) && mEndpoint2.equals(srcAddr))) {
105             // All is good.
106             return;
107         }
108         throw new IllegalArgumentException("Mismatch in MACs: packet does not pertain to this flow");
109     }
110
111     @Override
112     public String toString() {
113         return getClass().getSimpleName() + String.format(" with mEndpoint1=%s and mEndpoint2=%s", mEndpoint1, mEndpoint2);
114     }
115 }