tmf: Initial commit of Pcap Parser
[deliverable/tracecompass.git] / org.eclipse.linuxtools.pcap.core / src / org / eclipse / linuxtools / 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.linuxtools.pcap.core.protocol.tcp;
14
15 import java.nio.ByteBuffer;
16 import java.nio.ByteOrder;
17 import java.util.Arrays;
18 import java.util.Map;
19
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.eclipse.linuxtools.pcap.core.packet.BadPacketException;
23 import org.eclipse.linuxtools.pcap.core.packet.Packet;
24 import org.eclipse.linuxtools.pcap.core.protocol.Protocol;
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.util.ConversionHelper;
28
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.ImmutableMap.Builder;
31
32 /**
33 * Class that represents a TCP packet.
34 *
35 * @author Vincent Perot
36 */
37 public 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 {
80 super(file, parent, Protocol.TCP);
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
487 final ByteBuffer payload = fPayload;
488 if (payload != null) {
489 sb.append(" Len=") //$NON-NLS-1$
490 .append(payload.array().length);
491 } else {
492 sb.append(" Len=0"); //$NON-NLS-1$
493 }
494
495 String string = sb.toString();
496 if (string == null) {
497 return EMPTY_STRING;
498 }
499 return string;
500 }
501
502 private String generateFlagString() {
503 StringBuilder sb = new StringBuilder();
504 boolean start = true;
505
506 if (fSYNFlag) {
507 if (!start) {
508 sb.append(", "); //$NON-NLS-1$
509 }
510 sb.append("SYN"); //$NON-NLS-1$
511 start = false;
512 }
513 if (fACKFlag) {
514 if (!start) {
515 sb.append(", "); //$NON-NLS-1$
516 }
517 sb.append("ACK"); //$NON-NLS-1$
518 start = false;
519 }
520 if (fFINFlag) {
521 if (!start) {
522 sb.append(", "); //$NON-NLS-1$
523 }
524 sb.append("FIN"); //$NON-NLS-1$
525 start = false;
526 }
527 if (fRSTFlag) {
528 if (!start) {
529 sb.append(", "); //$NON-NLS-1$
530 }
531 sb.append("RST"); //$NON-NLS-1$
532 start = false;
533 }
534 if (fPSHFlag) {
535 if (!start) {
536 sb.append(", "); //$NON-NLS-1$
537 }
538 sb.append("PSH"); //$NON-NLS-1$
539 start = false;
540 }
541 if (fURGFlag) {
542 if (!start) {
543 sb.append(", "); //$NON-NLS-1$
544 }
545 sb.append("URG"); //$NON-NLS-1$
546 start = false;
547 }
548 if (fNSFlag) {
549 if (!start) {
550 sb.append(", "); //$NON-NLS-1$
551 }
552 sb.append("NS"); //$NON-NLS-1$
553 start = false;
554 }
555 if (fCWRFlag) {
556 if (!start) {
557 sb.append(", "); //$NON-NLS-1$
558 }
559 sb.append("CWR"); //$NON-NLS-1$
560 start = false;
561 }
562 if (fECEFlag) {
563 if (!start) {
564 sb.append(", "); //$NON-NLS-1$
565 }
566 sb.append("ECE"); //$NON-NLS-1$
567 start = false;
568 }
569 String string = sb.toString();
570 if (string == null) {
571 return EMPTY_STRING;
572 }
573 return string;
574 }
575
576 @Override
577 public int hashCode() {
578 final int prime = 31;
579 int result = 1;
580 result = prime * result + (fACKFlag ? 1231 : 1237);
581 result = prime * result + (int) (fAcknowledgmentNumber ^ (fAcknowledgmentNumber >>> 32));
582 result = prime * result + (fCWRFlag ? 1231 : 1237);
583 result = prime * result + fChecksum;
584 final Packet child = fChildPacket;
585 if (child != null) {
586 result = prime * result + child.hashCode();
587 } else {
588 result = prime * result;
589 }
590 result = prime * result + fDataOffset;
591 result = prime * result + fDestinationPort;
592 result = prime * result + (fECEFlag ? 1231 : 1237);
593 result = prime * result + (fFINFlag ? 1231 : 1237);
594 result = prime * result + (fNSFlag ? 1231 : 1237);
595 result = prime * result + Arrays.hashCode(fOptions);
596 result = prime * result + (fPSHFlag ? 1231 : 1237);
597 final ByteBuffer payload = fPayload;
598 if (payload != null) {
599 result = prime * result + payload.hashCode();
600 } else {
601 result = prime * result;
602 }
603 result = prime * result + (fRSTFlag ? 1231 : 1237);
604 result = prime * result + fReservedField;
605 result = prime * result + (fSYNFlag ? 1231 : 1237);
606 result = prime * result + (int) (fSequenceNumber ^ (fSequenceNumber >>> 32));
607 result = prime * result + fSourcePort;
608 result = prime * result + (fURGFlag ? 1231 : 1237);
609 result = prime * result + fUrgentPointer;
610 result = prime * result + fWindowSize;
611 return result;
612 }
613
614 @Override
615 public boolean equals(@Nullable Object obj) {
616 if (this == obj) {
617 return true;
618 }
619 if (obj == null) {
620 return false;
621 }
622 if (getClass() != obj.getClass()) {
623 return false;
624 }
625 TCPPacket other = (TCPPacket) obj;
626 if (fACKFlag != other.fACKFlag) {
627 return false;
628 }
629 if (fAcknowledgmentNumber != other.fAcknowledgmentNumber) {
630 return false;
631 }
632 if (fCWRFlag != other.fCWRFlag) {
633 return false;
634 }
635 if (fChecksum != other.fChecksum) {
636 return false;
637 }
638 final Packet child = fChildPacket;
639 if (child != null) {
640 if (!child.equals(other.fChildPacket)) {
641 return false;
642 }
643 } else {
644 if (other.fChildPacket != null) {
645 return false;
646 }
647 }
648
649 if (fDataOffset != other.fDataOffset) {
650 return false;
651 }
652 if (fDestinationPort != other.fDestinationPort) {
653 return false;
654 }
655 if (fECEFlag != other.fECEFlag) {
656 return false;
657 }
658 if (fFINFlag != other.fFINFlag) {
659 return false;
660 }
661 if (fNSFlag != other.fNSFlag) {
662 return false;
663 }
664 if (!Arrays.equals(fOptions, other.fOptions)) {
665 return false;
666 }
667 if (fPSHFlag != other.fPSHFlag) {
668 return false;
669 }
670 final ByteBuffer fPayload2 = fPayload;
671 if (fPayload2 != null) {
672 if (!fPayload2.equals(other.fPayload)) {
673 return false;
674 }
675 } else {
676 if (other.fPayload != null) {
677 return false;
678 }
679 }
680 if (fRSTFlag != other.fRSTFlag) {
681 return false;
682 }
683 if (fReservedField != other.fReservedField) {
684 return false;
685 }
686 if (fSYNFlag != other.fSYNFlag) {
687 return false;
688 }
689 if (fSequenceNumber != other.fSequenceNumber) {
690 return false;
691 }
692 if (fSourcePort != other.fSourcePort) {
693 return false;
694 }
695 if (fURGFlag != other.fURGFlag) {
696 return false;
697 }
698 if (fUrgentPointer != other.fUrgentPointer) {
699 return false;
700 }
701 if (fWindowSize != other.fWindowSize) {
702 return false;
703 }
704 return true;
705 }
706
707 }
This page took 0.070432 seconds and 5 git commands to generate.