6e6109dac493a9563471926ff136175932819fcd
[deliverable/tracecompass.git] / pcap / org.eclipse.tracecompass.pcap.core / src / org / eclipse / tracecompass / internal / pcap / core / protocol / tcp / TCPPacket.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.tracecompass.internal.pcap.core.protocol.tcp;
14
15 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
16
17 import java.nio.ByteBuffer;
18 import java.nio.ByteOrder;
19 import java.util.Arrays;
20 import java.util.Map;
21
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.eclipse.tracecompass.common.core.NonNullUtils;
24 import org.eclipse.tracecompass.internal.pcap.core.packet.BadPacketException;
25 import org.eclipse.tracecompass.internal.pcap.core.packet.Packet;
26 import org.eclipse.tracecompass.internal.pcap.core.protocol.PcapProtocol;
27 import org.eclipse.tracecompass.internal.pcap.core.protocol.unknown.UnknownPacket;
28 import org.eclipse.tracecompass.internal.pcap.core.trace.PcapFile;
29 import org.eclipse.tracecompass.internal.pcap.core.util.ConversionHelper;
30
31 import com.google.common.collect.ImmutableMap;
32 import com.google.common.collect.ImmutableMap.Builder;
33
34 /**
35 * Class that represents a TCP packet.
36 *
37 * @author Vincent Perot
38 */
39 public class TCPPacket extends Packet {
40
41 private final @Nullable Packet fChildPacket;
42 private final @Nullable ByteBuffer fPayload;
43
44 private final int fSourcePort;
45 private final int fDestinationPort;
46 private final long fSequenceNumber;
47 private final long fAcknowledgmentNumber;
48 private final int fDataOffset; // in 4 bytes block
49 private final byte fReservedField;
50 private final boolean fNSFlag;
51 private final boolean fCWRFlag;
52 private final boolean fECEFlag;
53 private final boolean fURGFlag;
54 private final boolean fACKFlag;
55 private final boolean fPSHFlag;
56 private final boolean fRSTFlag;
57 private final boolean fSYNFlag;
58 private final boolean fFINFlag;
59 private final int fWindowSize;
60 private final int fChecksum;
61 private final int fUrgentPointer;
62 private final @Nullable byte[] fOptions; // TODO Interpret options.
63
64 private @Nullable TCPEndpoint fSourceEndpoint;
65 private @Nullable TCPEndpoint fDestinationEndpoint;
66
67 private @Nullable Map<String, String> fFields;
68
69 /**
70 * Constructor of the TCP Packet class.
71 *
72 * @param file
73 * The file that contains this packet.
74 * @param parent
75 * The parent packet of this packet (the encapsulating packet).
76 * @param packet
77 * The entire packet (header and payload).
78 * @throws BadPacketException
79 * Thrown when the packet is erroneous.
80 */
81 public TCPPacket(PcapFile file, @Nullable Packet parent, ByteBuffer packet) throws BadPacketException {
82 super(file, parent, PcapProtocol.TCP);
83
84 // The endpoints are lazy loaded. They are defined in the get*Endpoint()
85 // methods.
86 fSourceEndpoint = null;
87 fDestinationEndpoint = null;
88
89 fFields = null;
90
91 packet.order(ByteOrder.BIG_ENDIAN);
92 packet.position(0);
93
94 fSourcePort = ConversionHelper.unsignedShortToInt(packet.getShort());
95 fDestinationPort = ConversionHelper.unsignedShortToInt(packet.getShort());
96 fSequenceNumber = ConversionHelper.unsignedIntToLong(packet.getInt());
97 fAcknowledgmentNumber = ConversionHelper.unsignedIntToLong(packet.getInt());
98
99 byte storage = packet.get();
100 fDataOffset = ((storage & 0b11110000) >>> 4) & 0x000000FF;
101 fReservedField = (byte) ((storage & 0b00001110) >>> 1);
102 fNSFlag = isBitSet(storage, 0);
103
104 storage = packet.get();
105 fCWRFlag = isBitSet(storage, 7);
106 fECEFlag = isBitSet(storage, 6);
107 fURGFlag = isBitSet(storage, 5);
108 fACKFlag = isBitSet(storage, 4);
109 fPSHFlag = isBitSet(storage, 3);
110 fRSTFlag = isBitSet(storage, 2);
111 fSYNFlag = isBitSet(storage, 1);
112 fFINFlag = isBitSet(storage, 0);
113
114 fWindowSize = ConversionHelper.unsignedShortToInt(packet.getShort());
115 fChecksum = ConversionHelper.unsignedShortToInt(packet.getShort());
116 fUrgentPointer = ConversionHelper.unsignedShortToInt(packet.getShort());
117
118 // Get options if any
119 if (fDataOffset > TCPValues.DEFAULT_HEADER_LENGTH) {
120 fOptions = new byte[(fDataOffset - TCPValues.DEFAULT_HEADER_LENGTH) * TCPValues.BLOCK_SIZE];
121 packet.get(fOptions);
122 } else {
123 fOptions = null;
124 }
125
126 // Get payload if any.
127 if (packet.array().length - packet.position() > 0) {
128 byte[] array = new byte[packet.array().length - packet.position()];
129 packet.get(array);
130 ByteBuffer payload = ByteBuffer.wrap(array);
131 payload.order(ByteOrder.BIG_ENDIAN);
132 payload.position(0);
133 fPayload = payload;
134 } else {
135 fPayload = null;
136 }
137
138 // find child packet
139 fChildPacket = findChildPacket();
140
141 }
142
143 @Override
144 public @Nullable Packet getChildPacket() {
145 return fChildPacket;
146 }
147
148 @Override
149 public @Nullable ByteBuffer getPayload() {
150 return fPayload;
151 }
152
153 /**
154 * {@inheritDoc}
155 *
156 * See http://www.iana.org/assignments/service-names-port-numbers/service-
157 * names-port-numbers.xhtml or
158 * http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
159 */
160 @Override
161 protected @Nullable Packet findChildPacket() throws BadPacketException {
162 // TODO implement further protocols and update this
163 ByteBuffer payload = fPayload;
164 if (payload == null) {
165 return null;
166 }
167
168 return new UnknownPacket(getPcapFile(), this, payload);
169 }
170
171 @Override
172 public String toString() {
173 final ByteBuffer payload = fPayload;
174 int length = 0;
175 if (payload != null) {
176 length = payload.array().length;
177 }
178
179 String flagString = ""; // TODO Finish it. Im just too lazy. //$NON-NLS-1$
180 String string = getProtocol().getName() + ", Source Port: " + fSourcePort + ", Destination Port: " + fDestinationPort + //$NON-NLS-1$ //$NON-NLS-2$
181 "\nSequence Number: " + fSequenceNumber + ", Acknowledgment Number: " + fAcknowledgmentNumber + //$NON-NLS-1$ //$NON-NLS-2$
182 "\nHeader length: " + fDataOffset * TCPValues.BLOCK_SIZE + " bytes, Data length: " + length + //$NON-NLS-1$ //$NON-NLS-2$
183 "\n" + flagString + "Window size value: " + fWindowSize + ", Urgent Pointer: " + String.format("%s%04x", "0x", fUrgentPointer) + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
184 "\nChecksum: " + String.format("%s%04x", "0x", fChecksum) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
185 final Packet child = fChildPacket;
186 if (child != null) {
187 return string + child.toString();
188 }
189 return string;
190 }
191
192 /**
193 * Getter method that returns the TCP Source Port.
194 *
195 * @return The source Port.
196 */
197 public int getSourcePort() {
198 return fSourcePort;
199 }
200
201 /**
202 * Getter method that returns the TCP Destination Port.
203 *
204 * @return The destination Port.
205 */
206 public int getDestinationPort() {
207 return fDestinationPort;
208 }
209
210 /**
211 * Getter method that returns the Sequence Number. The sequence number has a
212 * dual role:
213 * <ul>
214 * <li>If the SYN flag is set (1), then this is the initial sequence number.
215 * The sequence number of the actual first data byte and the acknowledged
216 * number in the corresponding ACK are then this sequence number plus 1.</li>
217 * <li>If the SYN flag is clear (0), then this is the accumulated sequence
218 * number of the first data byte of this segment for the current session.</li>
219 * </ul>
220 *
221 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
222 *
223 * @return The Sequence Number.
224 */
225 public long getSequenceNumber() {
226 return fSequenceNumber;
227 }
228
229 /**
230 * Getter method that returns the Acknowledgment Number.
231 *
232 * If the ACK flag is set then the value of this field is the next sequence
233 * number that the receiver is expecting. This acknowledges receipt of all
234 * prior bytes (if any). The first ACK sent by each end acknowledges the
235 * other end's initial sequence number itself, but no data.
236 *
237 * Source: http://en.wikipedia.org/wiki/Transmission_Control_Protocol
238 *
239 * @return The Acknowledgment Number.
240 */
241 public long getAcknowledgmentNumber() {
242 return fAcknowledgmentNumber;
243 }
244
245 /**
246 * Getter method that returns the size of the TCP header in 4 bytes data
247 * block. The minimum size is 5 words and the maximum is 15 words.
248 *
249 * @return The Data Offset.
250 */
251 public int getDataOffset() {
252 return fDataOffset;
253 }
254
255 /**
256 * Getter method that returns the Reserved field. This field is for future
257 * use and should always be zero. In this library, it is used as a mean to
258 * verify the validity of a TCP packet.
259 *
260 * @return The Reserved Field.
261 */
262 public byte getReservedField() {
263 return fReservedField;
264 }
265
266 /**
267 * Getter method that returns the state of the NS flag.
268 *
269 * @return The state of the NS flag.
270 */
271 public boolean isNSFlagSet() {
272 return fNSFlag;
273 }
274
275 /**
276 * Getter method that returns the state of the CWR flag.
277 *
278 * @return The state of the CWR flag.
279 */
280 public boolean isCongestionWindowReducedFlagSet() {
281 return fCWRFlag;
282 }
283
284 /**
285 * Getter method that returns the state of the ECE flag.
286 *
287 * @return The state of the ECE flag.
288 */
289 public boolean isECNEchoFlagSet() {
290 return fECEFlag;
291 }
292
293 /**
294 * Getter method that returns the state of the URG flag.
295 *
296 * @return The state of the URG flag.
297 */
298 public boolean isUrgentFlagSet() {
299 return fURGFlag;
300 }
301
302 /**
303 * Getter method that returns the state of the ACK flag.
304 *
305 * @return The state of the ACK flag.
306 */
307 public boolean isAcknowledgeFlagSet() {
308 return fACKFlag;
309 }
310
311 /**
312 * Getter method that returns the state of the PSH flag.
313 *
314 * @return The state of the PSH flag.
315 */
316 public boolean isPushFlagSet() {
317 return fPSHFlag;
318 }
319
320 /**
321 * Getter method that returns the state of the RST flag.
322 *
323 * @return The state of the RST flag.
324 */
325 public boolean isResetFlagSet() {
326 return fRSTFlag;
327 }
328
329 /**
330 * Getter method that returns the state of the SYN flag.
331 *
332 * @return The state of the SYN flag.
333 */
334 public boolean isSynchronizationFlagSet() {
335 return fSYNFlag;
336 }
337
338 /**
339 * Getter method that returns the state of the FIN flag.
340 *
341 * @return The state of the FIN flag.
342 */
343 public boolean isFinalFlagSet() {
344 return fFINFlag;
345 }
346
347 /**
348 * Getter method that returns the size of the windows, in windows size unit
349 * (by default, bytes), that the sender of this packet is willing to
350 * receive.
351 *
352 * @return The Window Size.
353 */
354 public int getWindowSize() {
355 return fWindowSize;
356 }
357
358 /**
359 * Getter method that returns the checksum of this packet. This checksum may
360 * be wrong if the packet is erroneous.
361 *
362 * @return The data and header checksum.
363 */
364 public int getChecksum() {
365 return fChecksum;
366 }
367
368 /**
369 * Getter method that returns the Urgent Pointer. If the URG flag is set,
370 * this field is an offset from the sequence number indicating the last
371 * urgent data byte.
372 *
373 * @return The Urgent Pointer.
374 */
375 public int getUrgentPointer() {
376 return fUrgentPointer;
377 }
378
379 /**
380 * Getter method that returns the options. This method returns null if no
381 * options are present.
382 *
383 * @return The options of the packet.
384 */
385 public @Nullable byte[] getOptions() {
386 byte[] options = fOptions;
387 if (options == null) {
388 return null;
389 }
390 return Arrays.copyOf(options, options.length);
391 }
392
393 @Override
394 public boolean validate() {
395 // Not yet implemented. ATM, we consider that all packets are valid.
396 // This is the case for all packets.
397 // TODO Implement it.
398 return true;
399 }
400
401 @Override
402 public TCPEndpoint getSourceEndpoint() {
403 @Nullable
404 TCPEndpoint endpoint = fSourceEndpoint;
405 if (endpoint == null) {
406 endpoint = new TCPEndpoint(this, true);
407 }
408 fSourceEndpoint = endpoint;
409 return fSourceEndpoint;
410 }
411
412 @Override
413 public TCPEndpoint getDestinationEndpoint() {
414 @Nullable
415 TCPEndpoint endpoint = fDestinationEndpoint;
416
417 if (endpoint == null) {
418 endpoint = new TCPEndpoint(this, false);
419 }
420 fDestinationEndpoint = endpoint;
421 return fDestinationEndpoint;
422 }
423
424 @Override
425 public Map<String, String> getFields() {
426 Map<String, String> map = fFields;
427 if (map == null) {
428 Builder<String, String> builder = ImmutableMap.<String, String> builder()
429 .put("Source Port", String.valueOf(fSourcePort)) //$NON-NLS-1$
430 .put("Destination Port", String.valueOf(fDestinationPort)) //$NON-NLS-1$
431 .put("Sequence Number", String.valueOf(fSequenceNumber)) //$NON-NLS-1$
432 .put("Acknowledgement Number", String.valueOf(fAcknowledgmentNumber)) //$NON-NLS-1$
433 .put("Length", String.valueOf(fDataOffset * TCPValues.BLOCK_SIZE) + " bytes") //$NON-NLS-1$ //$NON-NLS-2$
434 .put("ECN-Nonce Flag", String.valueOf(fNSFlag)) //$NON-NLS-1$
435 .put("Congestion Window Reduced Flag", String.valueOf(fCWRFlag)) //$NON-NLS-1$
436 .put("ECN-Echo Flag", String.valueOf(fECEFlag)) //$NON-NLS-1$
437 .put("Urgent Flag", String.valueOf(fURGFlag)) //$NON-NLS-1$
438 .put("ACK Flag", String.valueOf(fACKFlag)) //$NON-NLS-1$
439 .put("PSH Flag", String.valueOf(fPSHFlag)) //$NON-NLS-1$
440 .put("RST Flag", String.valueOf(fRSTFlag)) //$NON-NLS-1$
441 .put("SYN Flag", String.valueOf(fSYNFlag)) //$NON-NLS-1$
442 .put("FIN Flag", String.valueOf(fFINFlag)) //$NON-NLS-1$
443 .put("Window Size Value", String.valueOf(fWindowSize)) //$NON-NLS-1$
444 .put("Checksum", String.format("%s%04x", "0x", fChecksum)) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
445 .put("Urgent Pointer", String.format("%s%04x", "0x", fUrgentPointer)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
446 byte[] options = fOptions;
447 if (options == null) {
448 builder.put("Options", EMPTY_STRING); //$NON-NLS-1$
449 } else {
450 builder.put("Options", ConversionHelper.bytesToHex(options, true)); //$NON-NLS-1$
451
452 }
453 fFields = checkNotNull(builder.build());
454 return fFields;
455 }
456 return map;
457 }
458
459 @Override
460 public String getLocalSummaryString() {
461 return "Src Port: " + fSourcePort + ", Dst Port: " + fDestinationPort + //$NON-NLS-1$ //$NON-NLS-2$
462 ", Seq: " + fSequenceNumber + ", Ack: " + fAcknowledgmentNumber + //$NON-NLS-1$ //$NON-NLS-2$
463 ", Len: " + (fDataOffset * TCPValues.BLOCK_SIZE); //$NON-NLS-1$ }
464 }
465
466 @Override
467 protected String getSignificationString() {
468 StringBuilder sb = new StringBuilder();
469 sb.append(fSourcePort)
470 .append(" > ") //$NON-NLS-1$
471 .append(fDestinationPort);
472
473 if (!(generateFlagString().equals(EMPTY_STRING))) {
474 sb.append(' ')
475 .append('[')
476 .append(generateFlagString())
477 .append(']');
478 }
479 sb.append(" Seq=") //$NON-NLS-1$
480 .append(fSequenceNumber);
481
482 if (fACKFlag) {
483 sb.append(" Ack=") //$NON-NLS-1$
484 .append(fAcknowledgmentNumber);
485 }
486
487 sb.append(" Len=") //$NON-NLS-1$
488 .append((fDataOffset * TCPValues.BLOCK_SIZE));
489
490 return NonNullUtils.nullToEmptyString(sb); }
491
492 private String generateFlagString() {
493 StringBuilder sb = new StringBuilder();
494 boolean start = true;
495
496 if (fSYNFlag) {
497 if (!start) {
498 sb.append(", "); //$NON-NLS-1$
499 }
500 sb.append("SYN"); //$NON-NLS-1$
501 start = false;
502 }
503 if (fACKFlag) {
504 if (!start) {
505 sb.append(", "); //$NON-NLS-1$
506 }
507 sb.append("ACK"); //$NON-NLS-1$
508 start = false;
509 }
510 if (fFINFlag) {
511 if (!start) {
512 sb.append(", "); //$NON-NLS-1$
513 }
514 sb.append("FIN"); //$NON-NLS-1$
515 start = false;
516 }
517 if (fRSTFlag) {
518 if (!start) {
519 sb.append(", "); //$NON-NLS-1$
520 }
521 sb.append("RST"); //$NON-NLS-1$
522 start = false;
523 }
524 if (fPSHFlag) {
525 if (!start) {
526 sb.append(", "); //$NON-NLS-1$
527 }
528 sb.append("PSH"); //$NON-NLS-1$
529 start = false;
530 }
531 if (fURGFlag) {
532 if (!start) {
533 sb.append(", "); //$NON-NLS-1$
534 }
535 sb.append("URG"); //$NON-NLS-1$
536 start = false;
537 }
538 if (fNSFlag) {
539 if (!start) {
540 sb.append(", "); //$NON-NLS-1$
541 }
542 sb.append("NS"); //$NON-NLS-1$
543 start = false;
544 }
545 if (fCWRFlag) {
546 if (!start) {
547 sb.append(", "); //$NON-NLS-1$
548 }
549 sb.append("CWR"); //$NON-NLS-1$
550 start = false;
551 }
552 if (fECEFlag) {
553 if (!start) {
554 sb.append(", "); //$NON-NLS-1$
555 }
556 sb.append("ECE"); //$NON-NLS-1$
557 start = false;
558 }
559 return NonNullUtils.nullToEmptyString(sb);
560 }
561
562 @Override
563 public int hashCode() {
564 final int prime = 31;
565 int result = 1;
566 result = prime * result + (fACKFlag ? 1231 : 1237);
567 result = prime * result + (int) (fAcknowledgmentNumber ^ (fAcknowledgmentNumber >>> 32));
568 result = prime * result + (fCWRFlag ? 1231 : 1237);
569 result = prime * result + fChecksum;
570 final Packet child = fChildPacket;
571 if (child != null) {
572 result = prime * result + child.hashCode();
573 } else {
574 result = prime * result;
575 }
576 result = prime * result + fDataOffset;
577 result = prime * result + fDestinationPort;
578 result = prime * result + (fECEFlag ? 1231 : 1237);
579 result = prime * result + (fFINFlag ? 1231 : 1237);
580 result = prime * result + (fNSFlag ? 1231 : 1237);
581 result = prime * result + Arrays.hashCode(fOptions);
582 result = prime * result + (fPSHFlag ? 1231 : 1237);
583 final ByteBuffer payload = fPayload;
584 if (payload != null) {
585 result = prime * result + payload.hashCode();
586 } else {
587 result = prime * result;
588 }
589 result = prime * result + (fRSTFlag ? 1231 : 1237);
590 result = prime * result + fReservedField;
591 result = prime * result + (fSYNFlag ? 1231 : 1237);
592 result = prime * result + (int) (fSequenceNumber ^ (fSequenceNumber >>> 32));
593 result = prime * result + fSourcePort;
594 result = prime * result + (fURGFlag ? 1231 : 1237);
595 result = prime * result + fUrgentPointer;
596 result = prime * result + fWindowSize;
597 return result;
598 }
599
600 @Override
601 public boolean equals(@Nullable Object obj) {
602 if (this == obj) {
603 return true;
604 }
605 if (obj == null) {
606 return false;
607 }
608 if (getClass() != obj.getClass()) {
609 return false;
610 }
611 TCPPacket other = (TCPPacket) obj;
612 if (fACKFlag != other.fACKFlag) {
613 return false;
614 }
615 if (fAcknowledgmentNumber != other.fAcknowledgmentNumber) {
616 return false;
617 }
618 if (fCWRFlag != other.fCWRFlag) {
619 return false;
620 }
621 if (fChecksum != other.fChecksum) {
622 return false;
623 }
624 if(!NonNullUtils.equalsNullable(fChildPacket, other.fChildPacket)){
625 return false;
626 }
627 if (fDataOffset != other.fDataOffset) {
628 return false;
629 }
630 if (fDestinationPort != other.fDestinationPort) {
631 return false;
632 }
633 if (fECEFlag != other.fECEFlag) {
634 return false;
635 }
636 if (fFINFlag != other.fFINFlag) {
637 return false;
638 }
639 if (fNSFlag != other.fNSFlag) {
640 return false;
641 }
642 if (!Arrays.equals(fOptions, other.fOptions)) {
643 return false;
644 }
645 if (fPSHFlag != other.fPSHFlag) {
646 return false;
647 }
648 if(!NonNullUtils.equalsNullable(fPayload, other.fPayload)){
649 return false;
650 }
651 if (fRSTFlag != other.fRSTFlag) {
652 return false;
653 }
654 if (fReservedField != other.fReservedField) {
655 return false;
656 }
657 if (fSYNFlag != other.fSYNFlag) {
658 return false;
659 }
660 if (fSequenceNumber != other.fSequenceNumber) {
661 return false;
662 }
663 if (fSourcePort != other.fSourcePort) {
664 return false;
665 }
666 if (fURGFlag != other.fURGFlag) {
667 return false;
668 }
669 if (fUrgentPointer != other.fUrgentPointer) {
670 return false;
671 }
672 if (fWindowSize != other.fWindowSize) {
673 return false;
674 }
675 return true;
676 }
677
678 }
This page took 0.046501 seconds and 4 git commands to generate.