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