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