tmf: Initial commit of Pcap Parser
[deliverable/tracecompass.git] / org.eclipse.linuxtools.pcap.core / src / org / eclipse / linuxtools / pcap / core / protocol / pcap / PcapPacket.java
1 /*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Vincent Perot - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.pcap.core.protocol.pcap;
14
15 import java.nio.ByteBuffer;
16 import java.nio.ByteOrder;
17 import java.util.Map;
18
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.eclipse.linuxtools.pcap.core.packet.BadPacketException;
22 import org.eclipse.linuxtools.pcap.core.packet.Packet;
23 import org.eclipse.linuxtools.pcap.core.protocol.Protocol;
24 import org.eclipse.linuxtools.pcap.core.protocol.ethernet2.EthernetIIPacket;
25 import org.eclipse.linuxtools.pcap.core.protocol.unknown.UnknownPacket;
26 import org.eclipse.linuxtools.pcap.core.trace.PcapFile;
27 import org.eclipse.linuxtools.pcap.core.trace.PcapFileValues;
28 import org.eclipse.linuxtools.pcap.core.util.ConversionHelper;
29 import org.eclipse.linuxtools.pcap.core.util.LinkTypeHelper;
30 import org.eclipse.linuxtools.pcap.core.util.PcapTimestampScale;
31
32 import com.google.common.collect.ImmutableMap;
33
34 /**
35 * Class that represents a Pcap packet. This is the highest level of
36 * encapsulation.
37 *
38 * @author Vincent Perot
39 */
40 public class PcapPacket extends Packet {
41
42 private static final int TIMESTAMP_MICROSECOND_MAX = 1000000;
43 private static final int TIMESTAMP_NANOSECOND_MAX = 1000000000;
44
45 private final @Nullable Packet fChildPacket;
46 private final @Nullable ByteBuffer fPayload;
47
48 private final long fTimestamp; // In microseconds
49 private final long fIncludedLength;
50 private final long fOriginalLength;
51 private final long fPacketIndex;
52
53 private @Nullable PcapEndpoint fSourceEndpoint;
54 private @Nullable PcapEndpoint fDestinationEndpoint;
55
56 private @Nullable ImmutableMap<String, String> fFields;
57
58 /**
59 * Constructor of the Pcap Packet class.
60 *
61 * @param file
62 * The file that contains this packet.
63 * @param parent
64 * The parent packet of this packet (the encapsulating packet).
65 * @param header
66 * The header of the packet.
67 * @param payload
68 * The payload of this packet.
69 * @param index
70 * The index of the packet in the file.
71 * @throws BadPacketException
72 * Thrown when the Packet is erroneous.
73 */
74 public PcapPacket(PcapFile file, @Nullable Packet parent, ByteBuffer header, @Nullable ByteBuffer payload, long index) throws BadPacketException {
75 super(file, parent, Protocol.PCAP);
76
77 if (header.array().length < PcapFileValues.PACKET_HEADER_SIZE) {
78 fChildPacket = null;
79 throw new BadPacketException("The Pcap packet header is too small."); //$NON-NLS-1$
80 }
81
82 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
83 // methods.
84 fSourceEndpoint = null;
85 fDestinationEndpoint = null;
86
87 fFields = null;
88
89 fPacketIndex = index;
90
91 // PcapPacket header in File endian
92 header.order(getPcapFile().getByteOrder());
93 header.position(0);
94 long timestampMostSignificant = ConversionHelper.unsignedIntToLong(header.getInt());
95 long timestampLeastSignificant = ConversionHelper.unsignedIntToLong(header.getInt());
96
97 switch (getTimestampScale()) {
98 case MICROSECOND:
99 if (timestampLeastSignificant > TIMESTAMP_MICROSECOND_MAX) {
100 fChildPacket = null;
101 throw new BadPacketException("The timestamp is erroneous."); //$NON-NLS-1$
102 }
103 fTimestamp = TIMESTAMP_MICROSECOND_MAX * timestampMostSignificant + timestampLeastSignificant;
104 break;
105 case NANOSECOND:
106 if (timestampLeastSignificant > TIMESTAMP_NANOSECOND_MAX) {
107 fChildPacket = null;
108 throw new BadPacketException("The timestamp is erroneous."); //$NON-NLS-1$
109 }
110 fTimestamp = TIMESTAMP_NANOSECOND_MAX * timestampMostSignificant + timestampLeastSignificant;
111 break;
112 default:
113 throw new IllegalArgumentException("The timestamp precision is not valid!"); //$NON-NLS-1$
114 }
115
116 fIncludedLength = ConversionHelper.unsignedIntToLong(header.getInt());
117 fOriginalLength = ConversionHelper.unsignedIntToLong(header.getInt());
118
119 // Set up payload
120 final ByteBuffer pcapPacket = payload;
121 if (pcapPacket == null) {
122 fChildPacket = null;
123 fPayload = null;
124 return;
125 }
126
127 pcapPacket.order(ByteOrder.BIG_ENDIAN);
128 pcapPacket.position(0);
129 fPayload = pcapPacket;
130
131 // Find Child Packet
132 fChildPacket = findChildPacket();
133
134 }
135
136 @Override
137 public @Nullable Packet getChildPacket() {
138 return fChildPacket;
139 }
140
141 @Override
142 public @Nullable ByteBuffer getPayload() {
143 return fPayload;
144 }
145
146 /**
147 * Getter method that returns the timestamp of this packet, in microseconds/nanoseconds
148 * relative to epoch.
149 *
150 * @return The timestamp of the packet.
151 */
152 public long getTimestamp() {
153 return fTimestamp;
154 }
155
156 /**
157 * Getter method that returns the length in bytes of the packet that was
158 * included in the {@link PcapFile}.
159 *
160 * @return The included length of the packet.
161 */
162 public long getIncludedLength() {
163 return fIncludedLength;
164 }
165
166 /**
167 * Getter method that returns the original length in bytes of the packet.
168 *
169 * @return The included length of the packet.
170 */
171 public long getOriginalLength() {
172 return fOriginalLength;
173 }
174
175 /**
176 * Method that indicates if this packet was truncated at capture time.
177 *
178 * @return Whether the packet is truncated or not.
179 */
180 public boolean isTruncated() {
181 return fIncludedLength != fOriginalLength;
182 }
183
184 /**
185 * Getter method that returns the index of the packet.
186 *
187 * @return The index of the packet.
188 */
189 public long getIndex() {
190 return fPacketIndex;
191 }
192
193 @Override
194 public String toString() {
195 // TODO Decide if first capture is 0 or 1. Right now, it is 0.
196 String string = getProtocol().getName() + " " + fPacketIndex + //$NON-NLS-1$
197 ": " + fOriginalLength + " bytes on wire, " + //$NON-NLS-1$ //$NON-NLS-2$
198 fIncludedLength + " bytes captured.\nArrival time: " + //$NON-NLS-1$
199 ConversionHelper.toGMTTime(fTimestamp, getTimestampScale()) + "\n"; //$NON-NLS-1$
200
201 final Packet child = fChildPacket;
202 if (child != null) {
203 return string + child.toString();
204 }
205 return string;
206 }
207
208 /**
209 * {@inheritDoc}
210 *
211 * See http://www.tcpdump.org/linktypes.html
212 */
213 @Override
214 protected @Nullable Packet findChildPacket() throws BadPacketException {
215 @Nullable
216 ByteBuffer payload = fPayload;
217 if (payload == null) {
218 return null;
219 }
220
221 switch ((int) getPcapFile().getDataLinkType()) {
222 case LinkTypeHelper.LINKTYPE_ETHERNET:
223 return new EthernetIIPacket(getPcapFile(), this, payload);
224 default: // TODO add more protocols
225 return new UnknownPacket(getPcapFile(), this, payload);
226 }
227 }
228
229 @Override
230 public boolean validate() {
231 // Not yet implemented. ATM, we consider that all packets are valid.
232 // This is the case for all packets.
233 // TODO Implement it.
234 return true;
235 }
236
237 @Override
238 public PcapEndpoint getSourceEndpoint() {
239 @Nullable PcapEndpoint endpoint = fSourceEndpoint;
240 if (endpoint == null) {
241 endpoint = new PcapEndpoint(this, true);
242 }
243 fSourceEndpoint = endpoint;
244 return fSourceEndpoint;
245 }
246
247 @Override
248 public PcapEndpoint getDestinationEndpoint() {
249 @Nullable
250 PcapEndpoint endpoint = fDestinationEndpoint;
251
252 if (endpoint == null) {
253 endpoint = new PcapEndpoint(this, false);
254 }
255 fDestinationEndpoint = endpoint;
256 return fDestinationEndpoint;
257 }
258
259 // TODO handle plural form correctly
260 // TODO microsec
261 @Override
262 public Map<String, String> getFields() {
263 ImmutableMap<String, String> map = fFields;
264 if (map == null) {
265 @SuppressWarnings("null")
266 @NonNull ImmutableMap<String, String> newMap = ImmutableMap.<String, String> builder()
267 .put("Frame", String.valueOf(fPacketIndex)) //$NON-NLS-1$
268 .put("Frame Length", String.valueOf(fOriginalLength) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
269 .put("Capture Length", String.valueOf(fIncludedLength) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
270 .put("Capture Time", ConversionHelper.toGMTTime(fTimestamp, getTimestampScale())) //$NON-NLS-1$
271 .build();
272 fFields = newMap;
273 return newMap;
274 }
275 return map;
276 }
277
278 @Override
279 public String getLocalSummaryString() {
280 return "Frame " + fPacketIndex + ": " + fOriginalLength + " bytes on wire, " + fIncludedLength + " bytes captured"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
281 }
282
283 @Override
284 protected String getSignificationString() {
285 return "New Frame: " + fOriginalLength + " bytes on wire"; //$NON-NLS-1$ //$NON-NLS-2$
286 }
287
288 @Override
289 public int hashCode() {
290 final int prime = 31;
291 int result = 1;
292
293 Packet child = fChildPacket;
294 if (child == null) {
295 result = prime * result;
296 } else {
297 result = prime * result + child.hashCode();
298 }
299
300 result = prime * result + (int) (fIncludedLength ^ (fIncludedLength >>> 32));
301 result = prime * result + (int) (fOriginalLength ^ (fOriginalLength >>> 32));
302 result = prime * result + (int) (fPacketIndex ^ (fPacketIndex >>> 32));
303
304 ByteBuffer payload = fPayload;
305 if (payload == null) {
306 result = prime * result;
307 } else {
308 result = prime * result + payload.hashCode();
309 }
310
311 result = prime * result + (int) (fTimestamp ^ (fTimestamp >>> 32));
312 return result;
313 }
314
315 @Override
316 public boolean equals(@Nullable Object obj) {
317 if (this == obj) {
318 return true;
319 }
320 if (obj == null) {
321 return false;
322 }
323 if (getClass() != obj.getClass()) {
324 return false;
325 }
326 PcapPacket other = (PcapPacket) obj;
327 final Packet child = fChildPacket;
328 if (child != null) {
329 if (!child.equals(other.fChildPacket)) {
330 return false;
331 }
332 } else {
333 if (other.fChildPacket != null) {
334 return false;
335 }
336 }
337
338 if (fIncludedLength != other.fIncludedLength) {
339 return false;
340 }
341 if (fOriginalLength != other.fOriginalLength) {
342 return false;
343 }
344 if (fPacketIndex != other.fPacketIndex) {
345 return false;
346 }
347 final ByteBuffer payload = fPayload;
348 if (payload != null) {
349 if (!payload.equals(other.fPayload)) {
350 return false;
351 }
352 } else {
353 if (other.fPayload != null) {
354 return false;
355 }
356 }
357
358 if (fTimestamp != other.fTimestamp) {
359 return false;
360 }
361 return true;
362 }
363
364 /**
365 * Getter method that returns the Timestamp precision of the packet.
366 *
367 * @return the Timestamp precision.
368 */
369 public PcapTimestampScale getTimestampScale() {
370 return getPcapFile().getTimestampPrecision();
371 }
372 }
This page took 0.038307 seconds and 5 git commands to generate.