1 package edu.uci.iotproject;
3 import org.pcap4j.core.PcapPacket;
4 import org.pcap4j.packet.IpV4Packet;
5 import org.pcap4j.packet.TcpPacket;
7 import java.util.ArrayList;
8 import java.util.Collections;
10 import java.util.Objects;
13 * Models a (TCP) conversation/connection/session/flow (packet's belonging to the same session between a client and a
15 * Holds a list of {@link PcapPacket}s identified as pertaining to the flow. Note that this list is <em>not</em>
16 * considered when determining equality of two {@code Conversation} instances in order to allow for a
17 * {@code Conversation} to function as a key in data structures such as {@link java.util.Map} and {@link java.util.Set}.
18 * See {@link #equals(Object)} for the definition of equality.
20 public class Conversation {
22 private final String mClientIp;
23 private final int mClientPort;
24 private final String mServerIp;
25 private final int mServerPort;
26 private final List<PcapPacket> mPackets;
29 * Constructs a new {@code Conversation}.
30 * @param clientIp The IP of the host that is considered the client (i.e. the host that initiates the conversation)
31 * in the conversation.
32 * @param clientPort The port number used by the client for the conversation.
33 * @param serverIp The IP of the host that is considered the server (i.e. is the responder) in the conversation.
34 * @param serverPort The port number used by the server for the conversation.
36 public Conversation(String clientIp, int clientPort, String serverIp, int serverPort) {
37 this.mClientIp = clientIp;
38 this.mClientPort = clientPort;
39 this.mServerIp = serverIp;
40 this.mServerPort = serverPort;
41 this.mPackets = new ArrayList<>();
45 * Add a packet to the list of packets associated with this conversation.
46 * @param packet The packet that is to be added to (associated with) this conversation.
48 public void addPacket(PcapPacket packet) {
49 // Apply precondition to preserve class invariant: all packets in mPackets must match the 4 tuple that
50 // defines the conversation.
51 // ==== Precondition: verify that packet does indeed pertain to conversation. ====
52 IpV4Packet ipPacket = Objects.requireNonNull(packet.get(IpV4Packet.class));
53 // For now we only support TCP flows.
54 TcpPacket tcpPacket = Objects.requireNonNull(packet.get(TcpPacket.class));
55 String ipSrc = ipPacket.getHeader().getSrcAddr().getHostAddress();
56 String ipDst = ipPacket.getHeader().getDstAddr().getHostAddress();
57 int srcPort = tcpPacket.getHeader().getSrcPort().valueAsInt();
58 int dstPort = tcpPacket.getHeader().getDstPort().valueAsInt();
59 String clientIp, serverIp;
60 int clientPort, serverPort;
61 if (ipSrc.equals(mClientIp)) {
72 if (!(clientIp.equals(mClientIp) && clientPort == mClientPort &&
73 serverIp.equals(mServerIp) && serverPort == mServerPort)) {
74 throw new IllegalArgumentException(
75 String.format("Attempt to add packet that does not pertain to %s",
76 Conversation.class.getSimpleName()));
78 // ================================================================================
83 * Get a list of packets pertaining to this {@code Conversation}.
84 * The returned list is a read-only list.
85 * @return the list of packets pertaining to this {@code Conversation}.
87 public List<PcapPacket> getPackets() {
88 // Return read-only view to prevent external code from manipulating internal state (preserve invariant).
89 return Collections.unmodifiableList(mPackets);
92 // =========================================================================================================
93 // We simply reuse equals and hashCode methods of String.class to be able to use this class as a key
97 * <em>Note:</em> currently, equality is determined based on pairwise equality of the elements of the four tuple
98 * ({@link #mClientIp}, {@link #mClientPort}, {@link #mServerIp}, {@link #mServerPort}) for {@code this} and
100 * @param obj The object to test for equality with {@code this}.
101 * @return {@code true} if {@code obj} is considered equal to {@code this} based on the definition of equality given above.
104 public boolean equals(Object obj) {
105 return obj instanceof Conversation && this.toString().equals(obj.toString());
109 public int hashCode() {
110 return toString().hashCode();
112 // =========================================================================================================
115 public String toString() {
116 return String.format("%s:%d %s:%d", mClientIp, mClientPort, mServerIp, mServerPort);