blob: 8ed40e8245772941ee51e774e84ff4753d971a37 [file] [log] [blame]
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.pcap.core.util;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
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.pcap.PcapPacket;
import org.eclipse.tracecompass.internal.pcap.core.trace.PcapFile;
import org.eclipse.tracecompass.internal.pcap.core.util.LinkTypeHelper;
import org.eclipse.tracecompass.internal.pcap.core.util.PcapTimestampScale;
import org.eclipse.tracecompass.internal.tmf.pcap.core.event.PcapEvent;
import org.eclipse.tracecompass.internal.tmf.pcap.core.event.PcapEventField;
import org.eclipse.tracecompass.internal.tmf.pcap.core.event.PcapEventType;
import org.eclipse.tracecompass.internal.tmf.pcap.core.event.PcapRootEventField;
import org.eclipse.tracecompass.internal.tmf.pcap.core.trace.PcapTrace;
import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
import org.eclipse.tracecompass.tmf.core.event.TmfEventType;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
/**
* Factory class that helps generating Pcap Events.
*
* @author Vincent Perot
*/
public final class PcapEventFactory {
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final Map<PcapProtocol, TmfEventType> fEventTypes = new HashMap<>();
private PcapEventFactory() {
}
/**
* Method that create a PcapEvent from a packet.
*
* @param pcapPacket
* The packet to generate the event from.
* @param pcap
* The pcap file to which the packet belongs.
* @param trace
* The trace to which this packet belongs.
* @return The generated PcapEvent.
*/
public static @Nullable PcapEvent createEvent(PcapPacket pcapPacket, PcapFile pcap, PcapTrace trace) {
long rank = pcapPacket.getIndex();
long timestamp = pcapPacket.getTimestamp();
PcapTimestampScale scale = pcapPacket.getTimestampScale();
ITmfTimestamp tmfTimestamp;
switch (scale) {
case MICROSECOND:
long us = trace.getTimestampTransform().transform(timestamp * 1000) / 1000;
tmfTimestamp = TmfTimestamp.fromMicros(us);
break;
case NANOSECOND:
long ns = trace.getTimestampTransform().transform(timestamp);
tmfTimestamp = TmfTimestamp.fromNanos(ns);
break;
default:
throw new IllegalArgumentException("The timestamp precision is not valid!"); //$NON-NLS-1$
}
Path filePath = pcap.getPath().getFileName();
@NonNull String fileName = (filePath == null ? EMPTY_STRING : checkNotNull(filePath.toString()));
String dataLink = Messages.PcapEventFactory_LinkType + ':' + LinkTypeHelper.toString((int) pcapPacket.getDataLinkType());
ITmfEventField[] fields = generatePacketFields(pcapPacket);
ITmfEventField field = new PcapRootEventField(fields, pcapPacket);
Packet packet = pcapPacket.getMostEcapsulatedPacket();
if (!fEventTypes.containsKey(packet.getProtocol())) {
String typeIdString = PcapEventType.DEFAULT_PCAP_TYPE_ID + ':' + packet.getProtocol().getShortName();
fEventTypes.put(packet.getProtocol(), new PcapEventType(typeIdString, null));
}
TmfEventType eventType = fEventTypes.get(packet.getProtocol());
if (eventType == null) {
eventType = new TmfEventType();
}
return new PcapEvent(trace, rank, tmfTimestamp, dataLink, eventType, field, fileName, packet);
}
private static ITmfEventField[] generatePacketFields(Packet packet) {
// TODO This is SOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO slow. Must find a
// way to use less intermediate data structures.
List<ITmfEventField> fieldList = new ArrayList<>();
List<ITmfEventField> subfieldList = new ArrayList<>();
Packet localPacket = packet.getPacket(PcapProtocol.PCAP);
while (localPacket != null) {
subfieldList.clear();
for (Map.Entry<String, String> entry : localPacket.getFields().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
subfieldList.add(new TmfEventField(key, value, null));
}
ITmfEventField[] subfieldArray = subfieldList.toArray(new ITmfEventField[subfieldList.size()]);
fieldList.add(new PcapEventField(localPacket.getProtocol().getName(), EMPTY_STRING, subfieldArray, localPacket));
localPacket = localPacket.getChildPacket();
}
return fieldList.toArray(new ITmfEventField[fieldList.size()]);
}
}