source: lib/format_helper.c @ 17dc71c

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 17dc71c was 91ea76c, checked in by Shane Alcock <salcock@…>, 9 years ago
  • Detect if a user is attempting to read a compressed format that their libtrace build does not support and provide an appropriate error. Previously, we'd just try to read the trace with a stdout reader, resulting in some very confusing results.
  • Property mode set to 100644
File size: 9.3 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Daniel Lawson
8 *          Perry Lorier
9 *          Shane Alcock
10 *         
11 * All rights reserved.
12 *
13 * This code has been developed by the University of Waikato WAND
14 * research group. For further information please see http://www.wand.net.nz/
15 *
16 * libtrace is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * libtrace is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with libtrace; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29 *
30 * $Id$
31 *
32 */
33
34#include "config.h"
35#include <sys/types.h>
36#include <fcntl.h> /* for O_LARGEFILE */
37#include <math.h>
38#include "libtrace.h"
39#include "libtrace_int.h"
40#include "wandio.h"
41
42#include <stdlib.h>
43#include <stdio.h>
44#include <string.h>
45#include <errno.h>
46#include <time.h>
47#include "format_helper.h"
48
49#include <assert.h>
50#include <stdarg.h>
51
52#ifdef WIN32
53#  include <io.h>
54#  include <share.h>
55#  include <sys/timeb.h>
56
57struct libtrace_eventobj_t trace_event_device(struct libtrace_t *trace, struct libtrace_packet_t *packet) {
58    struct libtrace_eventobj_t event = {0,0,0.0,0};
59
60    trace_set_err(trace,TRACE_ERR_OPTION_UNAVAIL, "trace_event() is not "
61            "supported on devices under windows in this version");
62
63    event.type = TRACE_EVENT_TERMINATE;
64    return event;
65}
66#else
67#  include <sys/ioctl.h>
68
69/* Generic event function for live capture devices / interfaces */
70struct libtrace_eventobj_t trace_event_device(struct libtrace_t *trace, 
71                                        struct libtrace_packet_t *packet) {
72        struct libtrace_eventobj_t event = {0,0,0.0,0};
73
74        fd_set rfds, rfds_param;
75        int ret;
76        int max_fd;
77        struct timeval tv;
78
79        assert(trace != NULL);
80        assert(packet != NULL);
81       
82        FD_ZERO(&rfds);
83        FD_ZERO(&rfds_param);
84
85        if (trace->format->get_fd) {
86                event.fd = trace->format->get_fd(trace);
87                FD_SET(event.fd, &rfds);
88                max_fd = event.fd;
89        } else {
90                event.fd = 0;
91                max_fd = -1;
92        }
93
94        /* Use select() to perform a quick poll to check that there is data
95         * available - we used to use FIONREAD here but that does not work
96         * for mmapped pcap sockets. As recent pcap on linux (e.g. Ubuntu 9.04)
97         * uses mmapped sockets by default, I've switched over to this
98         * solution. */
99
100        do {
101                tv.tv_sec = 0;
102                tv.tv_usec = 0;
103                rfds_param = rfds;
104
105                ret = select(max_fd + 1, &rfds_param, NULL, NULL, &tv);
106                if (ret == -1 && errno != EINTR) {
107                        event.type = TRACE_EVENT_TERMINATE;
108                        return event;
109                }
110        } while (ret == -1);
111
112        if (FD_ISSET(event.fd, &rfds_param)) {
113                event.size = trace_read_packet(trace,packet);
114               
115                if (event.size < 1) {
116                        /* Covers error and EOF events - terminate rather
117                         * than report a packet as available */
118                        if (trace_is_err(trace)) {
119                                trace_perror(trace, "read packet");
120                        }
121                        event.type = TRACE_EVENT_TERMINATE;
122                } else {
123
124                        event.type = TRACE_EVENT_PACKET;
125                }
126                return event;
127        }
128        event.type= TRACE_EVENT_IOWAIT;
129        return event;
130}
131#endif
132
133/* Generic event function for trace files */ 
134struct libtrace_eventobj_t trace_event_trace(struct libtrace_t *trace, struct libtrace_packet_t *packet) {
135        struct libtrace_eventobj_t event = {0,0,0.0,0};
136        double ts;
137        double now;
138#ifdef WIN32
139        struct __timeb64 tstruct;
140#else
141        struct timeval stv;
142#endif
143
144        if (!trace->event.packet) {
145                trace->event.packet = trace_create_packet();
146        }
147
148        if (!trace->event.waiting) {
149                /* There is no packet event waiting for us, so create a new
150                 * libtrace packet in the event structure and read the next
151                 * packet into that.
152                 *
153                 * If a SLEEP event is reported this time around, the read
154                 * packet can therefore be saved until the next time this
155                 * function is called. */
156
157                trace->event.psize=
158                        trace_read_packet(trace,trace->event.packet);
159                if (trace->event.psize<1) {
160                        /* Return here, the test for event.size will sort out
161                         * the error  */
162                        if (trace_is_err(trace)) {
163                                trace_perror(trace, "read packet");
164                        }
165                        event.type = TRACE_EVENT_TERMINATE;
166                        trace_destroy_packet(trace->event.packet);
167                        trace->event.packet = NULL;
168                        packet->buffer = NULL;
169                        packet->header = NULL;
170                        packet->payload = NULL;
171                        packet->buf_control = TRACE_CTRL_EXTERNAL;
172                        return event;
173                }
174        }
175
176        /* The goal here is to replicate the inter-packet gaps that are
177         * present in the trace. */
178
179        ts=trace_get_seconds(trace->event.packet);
180
181        /* Get the current walltime */
182#ifdef WIN32
183        _ftime64(&tstruct);
184        now = tstruct.time + 
185                ((double)tstruct.millitm / 1000.0);
186#else
187        gettimeofday(&stv, NULL);
188        now = stv.tv_sec + 
189                ((double)stv.tv_usec / 1000000.0);
190#endif
191
192       
193        if (fabs(trace->event.tdelta)>1e-9) {
194                /* Subtract the tdelta from the walltime to get a suitable
195                 * "relative" time */
196                now -= trace->event.tdelta; 
197
198                /* If the trace timestamp is still in the future, return a
199                 * SLEEP event, otherwise return the packet */
200                if (ts > now) {
201                        event.seconds = ts - 
202                                trace->event.trace_last_ts;
203                        trace->event.trace_last_ts = ts;
204                        event.type = TRACE_EVENT_SLEEP;
205                        trace->event.waiting = true;
206                        return event;
207                }
208        } else {
209                /* Work out the difference between the walltime at the start
210                 * of the trace replay and the timestamp of the first packet
211                 * in the trace. This will be used to convert the walltime
212                 * into a timeline that is relative to the timestamps in the
213                 * trace file.
214                 */
215                trace->event.tdelta = now - ts;
216        }
217
218        /* This is the first packet, so just fire away. */
219        /* TODO: finalise packet */
220       
221        /* XXX: Could we do this more efficiently? */
222
223        /* We do a lot of freeing and creating of packet buffers with this
224         * method, but at least it works unlike what was here previously */
225        //if (packet->buf_control == TRACE_CTRL_PACKET) {
226        //      free(packet->buffer);
227        //}
228       
229        /* The packet that we had read earlier is now ready to be returned
230         * to the user - switch all the pointers etc. over */   
231        packet->type = trace->event.packet->type;
232        packet->trace = trace->event.packet->trace;
233        packet->header = trace->event.packet->header;
234        packet->payload = trace->event.packet->payload;
235       
236        packet->buffer = trace->event.packet->buffer;
237        packet->buf_control = trace->event.packet->buf_control;
238
239        //trace->event.packet->buffer = NULL;
240        //trace->event.packet->buf_control = TRACE_CTRL_EXTERNAL;
241       
242        //trace_destroy_packet(trace->event.packet);
243        //trace->event.packet = NULL;
244
245        event.type = TRACE_EVENT_PACKET;
246
247        trace->event.trace_last_ts = ts;
248        trace->event.waiting = false;
249
250        return event;
251}
252
253/* Catch undefined O_LARGEFILE on *BSD etc */
254#ifndef O_LARGEFILE
255#  define O_LARGEFILE 0
256#endif
257
258/* Catching O_BINARY on all sane OS's */
259#ifndef O_BINARY
260#  define O_BINARY 0
261#endif
262
263/* Open a file for reading using the new Libtrace IO system */
264io_t *trace_open_file(libtrace_t *trace)
265{
266        io_t *io=wandio_create(trace->uridata);
267        if (!io) {
268                if (errno != 0) {
269                        trace_set_err(trace,errno,"Unable to open %s",trace->uridata);
270                } else {
271                        trace_set_err(trace,TRACE_ERR_UNSUPPORTED_COMPRESS,"Unsupported compression error: %s", trace->uridata);
272                }
273        }
274        return io;
275}
276
277/* Open a file for writing using the new Libtrace IO system */ 
278iow_t *trace_open_file_out(libtrace_out_t *trace, int compress_type, int level, int fileflag)
279{
280        assert(level<10);
281        assert(level>=0);
282
283        return wandio_wcreate(trace->uridata, compress_type, level, fileflag);
284}
285
286
287/** Sets the error status for an input trace
288 * @param errcode either an Econstant from libc, or a LIBTRACE_ERROR
289 * @param msg a plaintext error message
290 * @internal
291 */
292void trace_set_err(libtrace_t *trace,int errcode,const char *msg,...)
293{
294        char buf[256];
295        va_list va;
296        va_start(va,msg);
297        assert(errcode != 0 && "An error occurred, but it is unknown what it is");
298        trace->err.err_num=errcode;
299        if (errcode>0) {
300                vsnprintf(buf,sizeof(buf),msg,va);
301                snprintf(trace->err.problem,sizeof(trace->err.problem),
302                                "%s: %s",buf,strerror(errcode));
303        } else {
304                vsnprintf(trace->err.problem,sizeof(trace->err.problem),
305                                msg,va);
306        }
307        va_end(va);
308}
309
310/** Sets the error status for an output trace
311 * @param errcode either an Econstant from libc, or a LIBTRACE_ERROR
312 * @param msg a plaintext error message
313 * @internal
314 */
315void trace_set_err_out(libtrace_out_t *trace,int errcode,const char *msg,...)
316{
317        char buf[256];
318        va_list va;
319        va_start(va,msg);
320        assert(errcode != 0 && "An error occurred, but it is unknown what it is");
321        trace->err.err_num=errcode;
322        if (errcode>0) {
323                vsnprintf(buf,sizeof(buf),msg,va);
324                snprintf(trace->err.problem,sizeof(trace->err.problem),
325                                "%s: %s",buf,strerror(errno));
326        } else {
327                vsnprintf(trace->err.problem,sizeof(trace->err.problem),
328                                msg,va);
329        }
330        va_end(va);
331}
332
333/* Byte swapping functions for various inttypes */
334uint64_t byteswap64(uint64_t num)
335{
336        return (byteswap32((num&0xFFFFFFFF00000000ULL)>>32))
337              |((uint64_t)byteswap32(num&0x00000000FFFFFFFFULL)<<32);
338}
339
340uint32_t byteswap32(uint32_t num)
341{
342        return ((num&0x000000FFU)<<24)
343                | ((num&0x0000FF00U)<<8)
344                | ((num&0x00FF0000U)>>8)
345                | ((num&0xFF000000U)>>24);
346}
347
348uint16_t byteswap16(uint16_t num)
349{
350        return ((num<<8)&0xFF00)|((num>>8)&0x00FF);
351}
352
Note: See TracBrowser for help on using the repository browser.