| /******************************************************************************* |
| * Copyright (c) 2014, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Vincent Perot - Initial API and implementation |
| * Viet-Hung Phan - Support pcapNg |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.pcap.core.protocol.pcap; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Map; |
| import java.util.Objects; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.internal.pcap.core.packet.BadPacketException; |
| import org.eclipse.tracecompass.internal.pcap.core.packet.Packet; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.PcapProtocol; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.ethernet2.EthernetIIPacket; |
| import org.eclipse.tracecompass.internal.pcap.core.protocol.unknown.UnknownPacket; |
| import org.eclipse.tracecompass.internal.pcap.core.trace.PcapFile; |
| import org.eclipse.tracecompass.internal.pcap.core.util.ConversionHelper; |
| import org.eclipse.tracecompass.internal.pcap.core.util.LinkTypeHelper; |
| import org.eclipse.tracecompass.internal.pcap.core.util.PcapTimestampScale; |
| |
| import com.google.common.collect.ImmutableMap; |
| |
| /** |
| * Class that represents a Pcap/PcapNg packet. This is the highest level of |
| * encapsulation. This class will serves both pcap and pcapNg packet |
| * |
| * @author Vincent Perot |
| */ |
| |
| public abstract class PcapPacket extends Packet { |
| |
| private @Nullable Packet fChildPacket; |
| private @Nullable ByteBuffer fPayload; |
| |
| private long fTimestamp; |
| private long fIncludedLength; |
| private long fOriginalLength; |
| private long fPacketIndex; |
| |
| private @Nullable PcapEndpoint fSourceEndpoint; |
| private @Nullable PcapEndpoint fDestinationEndpoint; |
| |
| private @Nullable Map<String, String> fFields; |
| |
| /** |
| * Constructor of the Pcap and PcapNg Packet class. |
| * |
| * @param file |
| * The file that contains this packet. |
| */ |
| public PcapPacket(PcapFile file) { |
| super(file, null, PcapProtocol.PCAP); |
| } |
| |
| @Override |
| public @Nullable Packet getChildPacket() { |
| return fChildPacket; |
| } |
| |
| /** |
| * Setter method that stores the child packet |
| * |
| * @param childPacket |
| * The child of packet |
| */ |
| public void setChildPacket(@Nullable Packet childPacket) { |
| fChildPacket = childPacket; |
| } |
| |
| @Override |
| public @Nullable ByteBuffer getPayload() { |
| if (fPayload != null) { |
| fPayload.position(0); |
| } |
| return fPayload; |
| } |
| |
| /** |
| * Setter method that stores the packet payload data |
| * |
| * @param payLoad |
| * The packet payload data |
| */ |
| public void setPayload(ByteBuffer payLoad) { |
| fPayload = payLoad; |
| } |
| |
| /** |
| * Getter method that returns the timestamp of this packet, in |
| * microseconds/nanoseconds relative to epoch. |
| * |
| * @return The timestamp of the packet. |
| */ |
| public long getTimestamp() { |
| return fTimestamp; |
| } |
| |
| /** |
| * Setter method that stores the packet timestamp |
| * |
| * @param timeStamp |
| * The packet timestamp |
| */ |
| public void setTimeStamp(long timeStamp) { |
| fTimestamp = timeStamp; |
| } |
| |
| /** |
| * Getter method that returns the length in bytes of the packet that was |
| * included in the {@link PcapFile}. |
| * |
| * @return The included length of the packet. |
| */ |
| public long getIncludedLength() { |
| return fIncludedLength; |
| } |
| |
| /** |
| * Setter method that stores the packet included length |
| * |
| * @param includedLength |
| * The packet included length |
| */ |
| public void setIncludedLength(long includedLength) { |
| fIncludedLength = includedLength; |
| } |
| |
| /** |
| * Getter method that returns the original length in bytes of the packet. |
| * |
| * @return The included length of the packet. |
| */ |
| public long getOriginalLength() { |
| return fOriginalLength; |
| } |
| |
| /** |
| * Setter method that stores the packet original length |
| * |
| * @param originalLength |
| * The packet original length |
| */ |
| public void setOriginalLength(long originalLength) { |
| fOriginalLength = originalLength; |
| } |
| |
| /** |
| * Method that indicates if this packet was truncated at capture time. |
| * |
| * @return Whether the packet is truncated or not. |
| */ |
| public boolean isTruncated() { |
| return fIncludedLength != fOriginalLength; |
| } |
| |
| /** |
| * Getter method that returns the index of the packet. |
| * |
| * @return The index of the packet. |
| */ |
| public long getIndex() { |
| return fPacketIndex; |
| } |
| |
| /** |
| * Setter method that stores the packet index |
| * |
| * @param packetIndex |
| * The packet index |
| */ |
| public void setIndex(long packetIndex) { |
| fPacketIndex = packetIndex; |
| } |
| |
| @Override |
| public String toString() { |
| // TODO Decide if first capture is 0 or 1. Right now, it is 0. |
| String string = getProtocol().getName() + " " + fPacketIndex + //$NON-NLS-1$ |
| ": " + fOriginalLength + " bytes on wire, " + //$NON-NLS-1$ //$NON-NLS-2$ |
| fIncludedLength + " bytes captured.\nArrival time: " + //$NON-NLS-1$ |
| ConversionHelper.toGMTTime(fTimestamp, getTimestampScale()) + "\n"; //$NON-NLS-1$ |
| |
| final Packet child = fChildPacket; |
| if (child != null) { |
| return string + child.toString(); |
| } |
| return string; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * See http://www.tcpdump.org/linktypes.html |
| */ |
| @Override |
| protected @Nullable Packet findChildPacket() throws BadPacketException { |
| @Nullable ByteBuffer payload = fPayload; |
| if (payload == null) { |
| return null; |
| } |
| |
| // The link type |
| switch ((int) getDataLinkType()) { |
| case LinkTypeHelper.LINKTYPE_ETHERNET: |
| return new EthernetIIPacket(getPcapFile(), this, payload); |
| default: |
| return new UnknownPacket(getPcapFile(), this, payload); |
| } |
| } |
| |
| @Override |
| public boolean validate() { |
| // Not yet implemented. ATM, we consider that all packets are valid. |
| // This is the case for all packets. |
| // TODO Implement it. |
| return true; |
| } |
| |
| @Override |
| public PcapEndpoint getSourceEndpoint() { |
| PcapEndpoint endpoint = fSourceEndpoint; |
| if (endpoint == null) { |
| endpoint = new PcapEndpoint(this, true); |
| } |
| fSourceEndpoint = endpoint; |
| return fSourceEndpoint; |
| } |
| |
| @Override |
| public PcapEndpoint getDestinationEndpoint() { |
| PcapEndpoint endpoint = fDestinationEndpoint; |
| |
| if (endpoint == null) { |
| endpoint = new PcapEndpoint(this, false); |
| } |
| fDestinationEndpoint = endpoint; |
| return fDestinationEndpoint; |
| } |
| |
| // TODO handle plural form correctly |
| // TODO microsec |
| @Override |
| public Map<String, String> getFields() { |
| Map<String, String> map = fFields; |
| if (map == null) { |
| ImmutableMap.Builder<String, String> builder = ImmutableMap.builder(); |
| builder.put("Frame", String.valueOf(fPacketIndex)); //$NON-NLS-1$ |
| builder.put("Frame Length", String.valueOf(fOriginalLength) + " bytes"); //$NON-NLS-1$ //$NON-NLS-2$ |
| builder.put("Capture Length", String.valueOf(fIncludedLength) + " bytes"); //$NON-NLS-1$ //$NON-NLS-2$ |
| builder.put("Capture Time", ConversionHelper.toGMTTime(fTimestamp, getTimestampScale())); //$NON-NLS-1$ |
| |
| fFields = builder.build(); |
| return fFields; |
| } |
| return map; |
| } |
| |
| @Override |
| public String getLocalSummaryString() { |
| return "Frame " + fPacketIndex + ": " + fOriginalLength + " bytes on wire, " + fIncludedLength + " bytes captured"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| |
| @Override |
| protected String getSignificationString() { |
| return "New Frame: " + fOriginalLength + " bytes on wire"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| |
| Packet child = fChildPacket; |
| if (child == null) { |
| result = prime * result; |
| } else { |
| result = prime * result + child.hashCode(); |
| } |
| |
| result = prime * result + (int) (fIncludedLength ^ (fIncludedLength >>> 32)); |
| result = prime * result + (int) (fOriginalLength ^ (fOriginalLength >>> 32)); |
| result = prime * result + (int) (fPacketIndex ^ (fPacketIndex >>> 32)); |
| |
| if (child == null) { |
| result = prime * result + payloadHashCode(fPayload); |
| } |
| |
| result = prime * result + (int) (fTimestamp ^ (fTimestamp >>> 32)); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| PcapPacket other = (PcapPacket) obj; |
| if (!Objects.equals(fChildPacket, other.fChildPacket)) { |
| return false; |
| } |
| if (fIncludedLength != other.fIncludedLength) { |
| return false; |
| } |
| if (fOriginalLength != other.fOriginalLength) { |
| return false; |
| } |
| if (fPacketIndex != other.fPacketIndex) { |
| return false; |
| } |
| if (fChildPacket == null && !payloadEquals(fPayload, other.fPayload)) { |
| return false; |
| } |
| return (fTimestamp == other.fTimestamp); |
| } |
| |
| /** |
| * Getter method that returns the Timestamp precision of the packet. |
| * |
| * @return the Timestamp precision. |
| */ |
| public PcapTimestampScale getTimestampScale() { |
| return getPcapFile().getTimestampPrecision(); |
| } |
| |
| /** |
| * Getter method for the data link type of the packet. This parameter is |
| * used to determine higher-level protocols (Ethernet, WLAN, SLL). |
| * |
| * @return The data link type of the packet. |
| */ |
| public abstract long getDataLinkType(); |
| } |