source: lib/format_helper.c @ 412550d

develop
Last change on this file since 412550d was 412550d, checked in by Shane Alcock <salcock@…>, 2 years ago

Fix bug where trace_event was ignoring all read packets.

  • Property mode set to 100644
File size: 12.7 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "config.h"
27#include <sys/types.h>
28#include <fcntl.h> /* for O_LARGEFILE */
29#include <math.h>
30#include "libtrace.h"
31#include "libtrace_int.h"
32#include "wandio.h"
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37#include <errno.h>
38#include <time.h>
39#include "format_helper.h"
40
41#include <assert.h>
42#include <stdarg.h>
43
44#ifdef WIN32
45#  include <io.h>
46#  include <share.h>
47#  include <sys/timeb.h>
48
49struct libtrace_eventobj_t trace_event_device(struct libtrace_t *trace, struct libtrace_packet_t *packet) {
50    struct libtrace_eventobj_t event = {0,0,0.0,0};
51
52    trace_set_err(trace,TRACE_ERR_OPTION_UNAVAIL, "trace_event() is not "
53            "supported on devices under windows in this version");
54
55    event.type = TRACE_EVENT_TERMINATE;
56    return event;
57}
58#else
59#  include <sys/ioctl.h>
60
61/* Generic event function for live capture devices / interfaces */
62struct libtrace_eventobj_t trace_event_device(struct libtrace_t *trace, 
63                                        struct libtrace_packet_t *packet) {
64        struct libtrace_eventobj_t event = {0,0,0.0,0};
65
66        fd_set rfds, rfds_param;
67        int ret;
68        int max_fd;
69        struct timeval tv;
70
71        assert(trace != NULL);
72        assert(packet != NULL);
73       
74        FD_ZERO(&rfds);
75        FD_ZERO(&rfds_param);
76
77        if (trace->format->get_fd) {
78                event.fd = trace->format->get_fd(trace);
79                FD_SET(event.fd, &rfds);
80                max_fd = event.fd;
81        } else {
82                event.fd = 0;
83                max_fd = -1;
84        }
85
86        /* Use select() to perform a quick poll to check that there is data
87         * available - we used to use FIONREAD here but that does not work
88         * for mmapped pcap sockets. As recent pcap on linux (e.g. Ubuntu 9.04)
89         * uses mmapped sockets by default, I've switched over to this
90         * solution. */
91
92        do {
93                tv.tv_sec = 0;
94                tv.tv_usec = 0;
95                rfds_param = rfds;
96
97                ret = select(max_fd + 1, &rfds_param, NULL, NULL, &tv);
98                if (ret == -1 && errno != EINTR) {
99                        event.type = TRACE_EVENT_TERMINATE;
100                        return event;
101                }
102        } while (ret == -1);
103
104        if (FD_ISSET(event.fd, &rfds_param)) {
105                event.size = trace_read_packet(trace,packet);
106                if (event.size < 1) {
107                        /* Covers error and EOF events - terminate rather
108                         * than report a packet as available */
109                        if (trace_is_err(trace)) {
110                                trace_perror(trace, "read packet");
111                        }
112                        event.type = TRACE_EVENT_TERMINATE;
113                } else {
114
115                        event.type = TRACE_EVENT_PACKET;
116                }
117                return event;
118        }
119        event.type= TRACE_EVENT_IOWAIT;
120        return event;
121}
122#endif
123
124/* Generic event function for trace files */ 
125struct libtrace_eventobj_t trace_event_trace(struct libtrace_t *trace, struct libtrace_packet_t *packet) {
126        struct libtrace_eventobj_t event = {0,0,0.0,0};
127        double ts;
128        double now;
129        double sincebeginnow = 0;
130        double sincebegintrace = 0;
131
132#ifdef WIN32
133        struct __timeb64 tstruct;
134#else
135        struct timeval stv;
136#endif
137
138        if (!trace->event.packet) {
139                trace->event.packet = trace_create_packet();
140        }
141
142        if (!trace->event.waiting) {
143                /* There is no packet event waiting for us, so create a new
144                 * libtrace packet in the event structure and read the next
145                 * packet into that.
146                 *
147                 * If a SLEEP event is reported this time around, the read
148                 * packet can therefore be saved until the next time this
149                 * function is called. */
150
151                trace->event.psize=
152                        trace_read_packet(trace,trace->event.packet);
153                if (trace->event.psize<1) {
154                        /* Return here, the test for event.size will sort out
155                         * the error  */
156                        if (trace_is_err(trace)) {
157                                trace_perror(trace, "read packet");
158                        }
159                        event.type = TRACE_EVENT_TERMINATE;
160                        trace_destroy_packet(trace->event.packet);
161                        trace->event.packet = NULL;
162                        packet->buffer = NULL;
163                        packet->header = NULL;
164                        packet->payload = NULL;
165                        packet->buf_control = TRACE_CTRL_EXTERNAL;
166                        return event;
167                }
168        }
169
170        /* The goal here is to replicate the inter-packet gaps that are
171         * present in the trace. */
172
173        ts=trace_get_seconds(trace->event.packet);
174
175        /* Get the current walltime */
176#ifdef WIN32
177        _ftime64(&tstruct);
178        now = tstruct.time + 
179                ((double)tstruct.millitm / 1000.0);
180#else
181        gettimeofday(&stv, NULL);
182        now = stv.tv_sec + 
183                ((double)stv.tv_usec / 1000000.0);
184#endif
185
186       
187        if (fabs(trace->event.first_ts)>1e-9) {
188                /* Subtract the tdelta from the starting times to get a suitable
189                 * "relative" time */
190                sincebeginnow = (now - trace->event.first_now);
191                sincebegintrace = (ts - trace->event.first_ts);
192
193                /* If the trace timestamp is still in the future, return a
194                 * SLEEP event, otherwise return the packet */
195                if (sincebeginnow <= sincebegintrace / (double)trace->replayspeedup) {
196                        event.seconds = ((sincebegintrace / (double)trace->replayspeedup) - sincebeginnow);
197                        event.type = TRACE_EVENT_SLEEP;
198                        trace->event.waiting = true;
199                        return event;
200                }
201        } else {
202                /* Work out the difference between the walltime at the start
203                 * of the trace replay and the timestamp of the first packet
204                 * in the trace. This will be used to convert the walltime
205                 * into a timeline that is relative to the timestamps in the
206                 * trace file.
207                 */
208                trace->event.first_now = (double)now;
209                trace->event.first_ts = (double)ts;
210        }
211
212        /* The packet that we had read earlier is now ready to be returned
213         * to the user - switch all the pointers etc. over */   
214        packet->type = trace->event.packet->type;
215        packet->trace = trace->event.packet->trace;
216        packet->header = trace->event.packet->header;
217        packet->payload = trace->event.packet->payload;
218       
219        packet->buffer = trace->event.packet->buffer;
220        packet->buf_control = trace->event.packet->buf_control;
221
222        packet->which_trace_start = trace->event.packet->which_trace_start;
223
224        event.type = TRACE_EVENT_PACKET;
225
226        trace->event.waiting = false;
227
228        return event;
229}
230
231/* Catch undefined O_LARGEFILE on *BSD etc */
232#ifndef O_LARGEFILE
233#  define O_LARGEFILE 0
234#endif
235
236/* Catching O_BINARY on all sane OS's */
237#ifndef O_BINARY
238#  define O_BINARY 0
239#endif
240
241/* Open a file for reading using the new Libtrace IO system */
242io_t *trace_open_file(libtrace_t *trace)
243{
244        io_t *io=wandio_create(trace->uridata);
245
246        if (!io) {
247                if (errno != 0) {
248                        trace_set_err(trace,errno,"Unable to open %s",trace->uridata);
249                } else {
250                        trace_set_err(trace,TRACE_ERR_UNSUPPORTED_COMPRESS,"Unsupported compression error: %s", trace->uridata);
251                }
252        }
253        return io;
254}
255
256/* Open a file for writing using the new Libtrace IO system */ 
257iow_t *trace_open_file_out(libtrace_out_t *trace, int compress_type, int level, int fileflag)
258{
259        iow_t *io = NULL;
260
261        if (level < 0 || level > 9) {
262                trace_set_err_out(trace, TRACE_ERR_UNSUPPORTED_COMPRESS, 
263                                "Compression level %d is invalid, must be between 0 and 9 inclusive", 
264                                level);
265                return NULL;
266        }
267
268        if (compress_type < 0 || 
269                        compress_type >= TRACE_OPTION_COMPRESSTYPE_LAST) {
270                trace_set_err_out(trace, TRACE_ERR_UNSUPPORTED_COMPRESS,
271                                "Invalid compression type %d", compress_type);
272                return NULL;
273        }
274
275        io = wandio_wcreate(trace->uridata, compress_type, level, fileflag);
276
277        if (!io) {
278                trace_set_err_out(trace, errno, "Unable to create output file %s", trace->uridata);
279        }
280        return io;
281}
282
283
284/** Sets the error status for an input trace
285 * @param errcode either an Econstant from libc, or a LIBTRACE_ERROR
286 * @param msg a plaintext error message
287 * @internal
288 */
289void trace_set_err(libtrace_t *trace,int errcode,const char *msg,...)
290{
291        char buf[256];
292        va_list va;
293        va_start(va,msg);
294        assert(errcode != 0 && "An error occurred, but it is unknown what it is");
295        trace->err.err_num=errcode;
296        if (errcode>0) {
297                vsnprintf(buf,sizeof(buf),msg,va);
298                snprintf(trace->err.problem,sizeof(trace->err.problem),
299                                "%s: %s",buf,strerror(errcode));
300        } else {
301                vsnprintf(trace->err.problem,sizeof(trace->err.problem),
302                                msg,va);
303        }
304        va_end(va);
305}
306
307/** Sets the error status for an output trace
308 * @param errcode either an Econstant from libc, or a LIBTRACE_ERROR
309 * @param msg a plaintext error message
310 * @internal
311 */
312void trace_set_err_out(libtrace_out_t *trace,int errcode,const char *msg,...)
313{
314        char buf[256];
315        va_list va;
316        va_start(va,msg);
317        assert(errcode != 0 && "An error occurred, but it is unknown what it is");
318        trace->err.err_num=errcode;
319        if (errcode>0) {
320                vsnprintf(buf,sizeof(buf),msg,va);
321                snprintf(trace->err.problem,sizeof(trace->err.problem),
322                                "%s: %s",buf,strerror(errno));
323        } else {
324                vsnprintf(trace->err.problem,sizeof(trace->err.problem),
325                                msg,va);
326        }
327        va_end(va);
328}
329
330/** Attempts to determine the direction for a pcap (or pcapng) packet.
331 *
332 * @param packet        The packet in question.
333 * @return A valid libtrace_direction_t describing the direction that the
334 *         packet was travelling, if direction can be determined. Otherwise
335 *         returns TRACE_DIR_UNKNOWN.
336 * @internal
337 *
338 * Note that we can determine the direction for only certain types of packets
339 * if they are captured using pcap/pcapng, specifically SLL and PFLOG captures.
340 */
341libtrace_direction_t pcap_get_direction(const libtrace_packet_t *packet) {
342        libtrace_direction_t direction  = -1;
343        switch(pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))) {
344                /* We can only get the direction for PCAP packets that have
345                 * been encapsulated in Linux SLL or PFLOG */
346                case TRACE_TYPE_LINUX_SLL:
347                {
348                        libtrace_sll_header_t *sll;
349                        libtrace_linktype_t linktype;
350
351                        sll = (libtrace_sll_header_t*)trace_get_packet_buffer(
352                                        packet,
353                                        &linktype,
354                                        NULL);
355                        if (!sll) {
356                                trace_set_err(packet->trace,
357                                        TRACE_ERR_BAD_PACKET,
358                                                "Bad or missing packet");
359                                return -1;
360                        }
361                        /* 0 == LINUX_SLL_HOST */
362                        /* the Waikato Capture point defines "packets
363                         * originating locally" (ie, outbound), with a
364                         * direction of 0, and "packets destined locally"
365                         * (ie, inbound), with a direction of 1.
366                         * This is kind-of-opposite to LINUX_SLL.
367                         * We return consistent values here, however
368                         *
369                         * Note that in recent versions of pcap, you can
370                         * use "inbound" and "outbound" on ppp in linux
371                         */
372                        if (ntohs(sll->pkttype == 0)) {
373                                direction = TRACE_DIR_INCOMING;
374                        } else {
375                                direction = TRACE_DIR_OUTGOING;
376                        }
377                        break;
378
379                }
380               case TRACE_TYPE_PFLOG:
381                {
382                        libtrace_pflog_header_t *pflog;
383                        libtrace_linktype_t linktype;
384
385                        pflog=(libtrace_pflog_header_t*)trace_get_packet_buffer(
386                                        packet,&linktype,NULL);
387                        if (!pflog) {
388                                trace_set_err(packet->trace,
389                                                TRACE_ERR_BAD_PACKET,
390                                                "Bad or missing packet");
391                                return -1;
392                        }
393                        /* enum    { PF_IN=0, PF_OUT=1 }; */
394                        if (ntohs(pflog->dir==0)) {
395
396                                direction = TRACE_DIR_INCOMING;
397                        }
398                        else {
399                                direction = TRACE_DIR_OUTGOING;
400                        }
401                        break;
402                }
403                default:
404                        break;
405        }       
406        return direction;
407}
408
409
Note: See TracBrowser for help on using the repository browser.