Commit | Line | Data |
---|---|---|
b6eb4dce 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 | ||
13 | package org.eclipse.linuxtools.tmf.pcap.core.trace; | |
14 | ||
15 | import java.io.IOException; | |
16 | import java.nio.channels.ClosedChannelException; | |
17 | import java.util.Map; | |
18 | ||
19 | import org.eclipse.core.resources.IProject; | |
20 | import org.eclipse.core.resources.IResource; | |
21 | import org.eclipse.core.runtime.IStatus; | |
22 | import org.eclipse.core.runtime.Status; | |
23 | import org.eclipse.jdt.annotation.NonNull; | |
24 | import org.eclipse.jdt.annotation.Nullable; | |
25 | import org.eclipse.linuxtools.internal.tmf.pcap.core.Activator; | |
26 | import org.eclipse.linuxtools.internal.tmf.pcap.core.util.PcapEventFactory; | |
27 | import org.eclipse.linuxtools.pcap.core.packet.BadPacketException; | |
28 | import org.eclipse.linuxtools.pcap.core.protocol.pcap.PcapPacket; | |
29 | import org.eclipse.linuxtools.pcap.core.trace.BadPcapFileException; | |
30 | import org.eclipse.linuxtools.pcap.core.trace.PcapFile; | |
31 | import org.eclipse.linuxtools.pcap.core.util.LinkTypeHelper; | |
32 | import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; | |
33 | import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; | |
34 | import org.eclipse.linuxtools.tmf.core.trace.ITmfContext; | |
35 | import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser; | |
36 | import org.eclipse.linuxtools.tmf.core.trace.ITmfTraceProperties; | |
37 | import org.eclipse.linuxtools.tmf.core.trace.TmfContext; | |
38 | import org.eclipse.linuxtools.tmf.core.trace.TmfTrace; | |
39 | import org.eclipse.linuxtools.tmf.core.trace.TraceValidationStatus; | |
40 | import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation; | |
41 | import org.eclipse.linuxtools.tmf.core.trace.location.TmfLongLocation; | |
42 | import org.eclipse.linuxtools.tmf.pcap.core.event.PcapEvent; | |
43 | ||
44 | import com.google.common.collect.ImmutableMap; | |
45 | ||
46 | /** | |
47 | * Class that represents a TMF Pcap Trace. It is used to make the glue between | |
48 | * the Pcap parser and TMF. | |
49 | * | |
50 | * TODO handle fields in TmfEventType for the filter view. | |
51 | * | |
52 | * @author Vincent Perot | |
53 | */ | |
54 | public class PcapTrace extends TmfTrace implements ITmfEventParser, ITmfTraceProperties, AutoCloseable { | |
55 | ||
56 | @SuppressWarnings("null") | |
57 | private static final @NonNull Map<String, String> EMPTY_MAP = ImmutableMap.of(); | |
58 | private static final String EMPTY_STRING = ""; //$NON-NLS-1$ | |
59 | private static final int CONFIDENCE = 50; | |
60 | private @Nullable PcapFile fPcapFile; | |
61 | private @Nullable ImmutableMap<String, String> fTraceProperties = null; | |
62 | ||
63 | @Override | |
64 | public synchronized ITmfLocation getCurrentLocation() { | |
65 | PcapFile pcap = fPcapFile; | |
66 | if (pcap == null) { | |
67 | return new TmfLongLocation(0); | |
68 | } | |
69 | return new TmfLongLocation(pcap.getCurrentRank()); | |
70 | } | |
71 | ||
72 | @Override | |
73 | public synchronized double getLocationRatio(@Nullable ITmfLocation location) { | |
74 | TmfLongLocation loc = (TmfLongLocation) location; | |
75 | PcapFile pcap = fPcapFile; | |
76 | if (loc == null || pcap == null) { | |
77 | return 0; | |
78 | } | |
79 | try { | |
80 | return (pcap.getTotalNbPackets() == 0 ? 0 : ((double) loc.getLocationInfo()) / pcap.getTotalNbPackets()); | |
81 | } catch (IOException | BadPcapFileException e) { | |
82 | String message = e.getMessage(); | |
83 | if (message == null) { | |
84 | message = EMPTY_STRING; | |
85 | } | |
86 | Activator.logError(message, e); | |
87 | return 0; | |
88 | } | |
89 | ||
90 | } | |
91 | ||
92 | @Override | |
93 | public synchronized void initTrace(@Nullable IResource resource, @Nullable String path, @Nullable Class<? extends ITmfEvent> type) throws TmfTraceException { | |
94 | super.initTrace(resource, path, type); | |
95 | if (path == null) { | |
96 | throw new TmfTraceException("No path has been specified."); //$NON-NLS-1$ | |
97 | } | |
98 | try { | |
99 | fPcapFile = new PcapFile(path); | |
100 | } catch (IOException | BadPcapFileException e) { | |
101 | throw new TmfTraceException(e.getMessage(), e); | |
102 | } | |
103 | } | |
104 | ||
105 | @Override | |
106 | public synchronized @Nullable PcapEvent parseEvent(@Nullable ITmfContext context) { | |
107 | if (context == null) { | |
108 | return null; | |
109 | } | |
110 | ||
111 | long rank = context.getRank(); | |
112 | PcapPacket packet = null; | |
113 | PcapFile pcap = fPcapFile; | |
114 | if (pcap == null) { | |
115 | return null; | |
116 | } | |
117 | try { | |
118 | pcap.seekPacket(rank); | |
119 | packet = pcap.parseNextPacket(); | |
120 | } catch (ClosedChannelException e) { | |
121 | /* | |
122 | * This is handled independently and happens when the user closes | |
123 | * the trace while it is being parsed. It simply stops the parsing. | |
124 | * No need to log a error. | |
125 | */ | |
126 | return null; | |
127 | } catch (IOException | BadPcapFileException | BadPacketException e) { | |
128 | String message = e.getMessage(); | |
129 | if (message == null) { | |
130 | message = EMPTY_STRING; | |
131 | } | |
132 | Activator.logError(message, e); | |
133 | return null; | |
134 | } | |
135 | ||
136 | if (packet == null) { | |
137 | return null; | |
138 | } | |
139 | ||
140 | // Generate an event from this packet and return it. | |
141 | return PcapEventFactory.createEvent(packet, pcap, this); | |
142 | ||
143 | } | |
144 | ||
145 | @Override | |
146 | public synchronized ITmfContext seekEvent(double ratio) { | |
147 | long position; | |
148 | PcapFile pcap = fPcapFile; | |
149 | if (pcap == null) { | |
150 | return new TmfContext(new TmfLongLocation(0), 0); | |
151 | } | |
152 | ||
153 | try { | |
154 | /* | |
155 | * The ratio is between 0 and 1. We multiply it by the total number | |
156 | * of packets to get the position. | |
157 | */ | |
158 | position = (long) (ratio * pcap.getTotalNbPackets()); | |
159 | } catch (IOException | BadPcapFileException e) { | |
160 | String message = e.getMessage(); | |
161 | if (message == null) { | |
162 | message = EMPTY_STRING; | |
163 | } | |
164 | Activator.logError(message, e); | |
165 | return new TmfContext(new TmfLongLocation(0), 0); | |
166 | } | |
167 | TmfLongLocation loc = new TmfLongLocation(position); | |
168 | return new TmfContext(loc, loc.getLocationInfo()); | |
169 | } | |
170 | ||
171 | @Override | |
172 | public synchronized ITmfContext seekEvent(@Nullable ITmfLocation location) { | |
173 | TmfLongLocation loc = (TmfLongLocation) location; | |
174 | if (loc == null) { | |
175 | return new TmfContext(new TmfLongLocation(0)); | |
176 | } | |
177 | ||
178 | return new TmfContext(loc, loc.getLocationInfo()); | |
179 | } | |
180 | ||
181 | @Override | |
182 | public IStatus validate(@Nullable IProject project, @Nullable String path) { | |
183 | ||
184 | // All validations are made when making a new pcap file. | |
185 | if (path == null) { | |
186 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, EMPTY_STRING); | |
187 | } | |
188 | try (PcapFile file = new PcapFile(path)) { | |
189 | } catch (IOException | BadPcapFileException e) { | |
190 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.toString()); | |
191 | } | |
192 | return new TraceValidationStatus(CONFIDENCE, Activator.PLUGIN_ID); | |
193 | } | |
194 | ||
195 | @Override | |
196 | public synchronized void dispose() { | |
197 | super.dispose(); | |
198 | PcapFile pcap = fPcapFile; | |
199 | if (pcap == null) { | |
200 | return; | |
201 | } | |
202 | try { | |
203 | pcap.close(); | |
204 | fPcapFile = null; | |
205 | } catch (IOException e) { | |
206 | String message = e.getMessage(); | |
207 | if (message == null) { | |
208 | message = EMPTY_STRING; | |
209 | } | |
210 | Activator.logError(message, e); | |
211 | return; | |
212 | } | |
213 | } | |
214 | ||
215 | @Override | |
216 | public synchronized Map<String, String> getTraceProperties() { | |
217 | PcapFile pcap = fPcapFile; | |
218 | if (pcap == null) { | |
219 | return EMPTY_MAP; | |
220 | } | |
221 | ||
222 | ImmutableMap<String, String> properties = fTraceProperties; | |
223 | if (properties == null) { | |
224 | @SuppressWarnings("null") | |
225 | @NonNull ImmutableMap<String, String> newProperties = ImmutableMap.<String, String> builder() | |
226 | .put(Messages.PcapTrace_Version, String.format("%d%c%d", pcap.getMajorVersion(), '.', pcap.getMinorVersion())) //$NON-NLS-1$ | |
227 | .put(Messages.PcapTrace_TimeZoneCorrection, pcap.getTimeZoneCorrection() + " s") //$NON-NLS-1$ | |
228 | .put(Messages.PcapTrace_TimestampAccuracy, String.valueOf(pcap.getTimeAccuracy())) | |
229 | .put(Messages.PcapTrace_MaxSnapLength, pcap.getSnapLength() + " bytes") //$NON-NLS-1$ | |
230 | .put(Messages.PcapTrace_LinkLayerHeaderType, LinkTypeHelper.toString((int) pcap.getDataLinkType()) + " (" + pcap.getDataLinkType() + ")") //$NON-NLS-1$ //$NON-NLS-2$ | |
231 | .put(Messages.PcapTrace_FileEndianness, pcap.getByteOrder().toString()) | |
232 | .build(); | |
233 | fTraceProperties = newProperties; | |
234 | return newProperties; | |
235 | ||
236 | } | |
237 | ||
238 | return properties; | |
239 | } | |
240 | ||
241 | @Override | |
242 | public void close() { | |
243 | dispose(); | |
244 | } | |
245 | } |