source: lib/format_helper.c @ 3fc7948

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 3fc7948 was 3fc7948, checked in by Shane Alcock <salcock@…>, 12 years ago

Major rewrite of trace_event_device

  • Replaced FIONREAD ioctl with a select() to check whether data is available. The select() is probably slower but the ioctl was not working for newer versions of pcap under linux, due to the use of mmaped packet sockets which would not report the expected value for that ioctl.
  • Added checks for the return value of trace_read_packet so that we can catch any error or EOF events that occur rather than always returning a PACKET event

Thanks to Benjamin Black for bringing this to our attention.

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