First work on layer 2 sequence matching. Basic functionality seems to work. Cleanup...
[pingpong.git] / Code / Projects / SmartPlugDetector / src / main / java / edu / uci / iotproject / StateMachine.java
1 package edu.uci.iotproject;
2
3 import org.jgrapht.Graphs;
4 import org.jgrapht.graph.DefaultEdge;
5 import org.jgrapht.graph.SimpleDirectedGraph;
6 import org.pcap4j.core.PcapPacket;
7
8 import java.util.List;
9 import java.util.Optional;
10
11 /**
12  * TODO add class documentation.
13  *
14  * @author Janus Varmarken
15  */
16 public class StateMachine {
17
18
19     private final SimpleDirectedGraph<Vertex, DefaultEdge> mGraph = new SimpleDirectedGraph<>(DefaultEdge.class);
20
21
22     public StateMachine(List<List<PcapPacket>> subCluster) {
23
24         for (List<PcapPacket> seqVariation : subCluster) {
25
26             Vertex currVtx;
27             Vertex prevVtx = null;
28
29             for (int i = 0; i < seqVariation.size(); i++) {
30                 // Create new vertex corresponding to this packet of the sequence
31                 PcapPacket currPkt = seqVariation.get(i);
32                 currVtx = new Vertex(currPkt.getOriginalLength(), i);
33
34
35
36
37
38                 mGraph.addVertex(currVtx);
39
40
41
42                 if (prevVtx != null) {
43                     // Link vertex representing previous packet of sequence to this vertex.
44                     mGraph.addEdge(prevVtx, currVtx);
45
46                 }
47
48                 // Current vertex becomes previous vertex for next iteration.
49                 prevVtx = currVtx;
50             }
51         }
52
53     }
54
55
56     private Vertex mCurrentState;
57
58 //    @Override
59 //    public void gotPacket(PcapPacket packet) {
60 //        // Generate a vertex corresponding to the received packet.
61 //        // We expect a packet at the layer that follows the current state's layer.
62 //        Vertex pktVtx = new Vertex(packet.getOriginalLength(), mCurrentState.mLayer + 1);
63 //        // Check if such a vertex is present as a successor of the current state
64 //        Optional<Vertex> match = Graphs.successorListOf(mGraph, mCurrentState).stream().
65 //                filter(v -> v.equals(pktVtx)).findFirst();
66 //        // If yes, we move to that new state (new vertex).
67 //        match.ifPresent(v -> mCurrentState = v);
68 //        // TODO buffer the packets that got us here
69 //        // TODO check if we've reached the final layer...
70 //
71 //    }
72
73
74     /**
75      * Attempts to use {@code packet} to advance this state machine.
76      * @param packet
77      * @return {@code true} if this state machine could progress by consuming {@code packet}, {@code false} otherwise.
78      */
79     public boolean attemptAdvance(PcapPacket packet) {
80         // Generate a vertex corresponding to the received packet.
81         // We expect a packet at the layer that follows the current state's layer.
82         Vertex pktVtx = new Vertex(packet.getOriginalLength(), mCurrentState.mLayer + 1);
83         // Check if such a vertex is present as a successor of the current state
84         Optional<Vertex> match = Graphs.successorListOf(mGraph, mCurrentState).stream().
85                 filter(v -> v.equals(pktVtx)).findFirst();
86         if (match.isPresent()) {
87             // If yes, we move to that new state (new vertex).
88             mCurrentState = match.get();
89             // TODO buffer the packet to keep track of what packets got us here (keep track of the match)
90             // TODO check if we've reached the final layer...
91
92             return true;
93         }
94         return false;
95     }
96
97     private static class Vertex {
98
99         // TODO how to include direction of packets here...
100
101         private final int mPktLength;
102         private final int mLayer;
103
104
105         private Vertex(int pktLength, int layer) {
106             mPktLength = pktLength;
107             mLayer = layer;
108         }
109
110
111         @Override
112         public boolean equals(Object obj) {
113             if (!(obj instanceof Vertex)) return false;
114             Vertex that = (Vertex) obj;
115             return that.mPktLength == this.mPktLength && that.mLayer == this.mLayer;
116         }
117
118         @Override
119         public int hashCode() {
120 //            return Integer.hashCode(mPktLength);
121             // Hack: use string's hashCode implementation.
122             return (Integer.toString(mPktLength) + " " + Integer.toString(mLayer)).hashCode();
123         }
124
125     }
126 }