source: lib/format_duck.c @ 32ee9b2

cachetimestampsdeveloprc-4.0.4ringdecrementfixringperformance
Last change on this file since 32ee9b2 was 32ee9b2, checked in by Shane Alcock <salcock@…>, 2 years ago

Add new trace_flush_output() to public API

Can be used to force a libtrace output to dump any buffered output
to disk immediately.

Note that if the file is compressed or the output trace format
requires a trailer, the flushed file will still not be properly
readable afterwards as this will not result in any trailers
being written. You'll still have to close the file for that.

Mainly this is useful for ensuring that output file sizes grow
over time in situations where the amount of output is relatively
small, rather than staying stuck at 0 bytes until we either reach
1MB of output or the file is closed. For instance, you could have
a timer that calls trace_flush_output() every 30 seconds so that
the output file size will grow if any packets were written in the
last 30 seconds.

  • Property mode set to 100644
File size: 10.2 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 "libtrace.h"
28#include "libtrace_int.h"
29#include "format_helper.h"
30#include "wandio.h"
31#include <stdlib.h>
32#include "rt_protocol.h"
33
34#include <errno.h>
35#include <assert.h>
36#include <stdio.h>
37#include <fcntl.h>
38
39/* This format module deals with reading and writing DUCK records.
40 *
41 * Both DUCK record types (the DAG 2.4 and 2.5 versions) are supported by this
42 * module.
43 *
44 * We differentiate between DUCK versions by writing the RT type to the start
45 * of the DUCK trace. This means that this code can only read DUCK files that
46 * were written using libtrace 3.
47 */
48
49#define DATA(x) ((struct duck_format_data_t *)x->format_data)
50#define DATAOUT(x) ((struct duck_format_data_out_t *)x->format_data)
51
52#define OUTPUT DATAOUT(libtrace)
53
54struct duck_format_data_t {
55        char *path;
56        int dag_version;
57};
58
59struct duck_format_data_out_t {
60        char *path;
61        int level;
62        int compress_type;
63        int fileflag;
64        iow_t *file;
65        int dag_version;       
66};
67
68static int duck_init_input(libtrace_t *libtrace) {
69        libtrace->format_data = malloc(sizeof(struct duck_format_data_t));
70
71        DATA(libtrace)->dag_version = 0;
72        return 0;
73}
74
75static int duck_init_output(libtrace_out_t *libtrace) {
76        libtrace->format_data = malloc(sizeof(struct duck_format_data_out_t));
77       
78        OUTPUT->level = 0;
79        OUTPUT->compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
80        OUTPUT->fileflag = O_CREAT | O_WRONLY;
81        OUTPUT->file = 0;
82        OUTPUT->dag_version = 0;
83        return 0;
84}
85
86static int duck_config_output(libtrace_out_t *libtrace, 
87                                trace_option_output_t option,
88                                void *data) {
89        switch (option) {
90                case TRACE_OPTION_OUTPUT_COMPRESS:
91                        OUTPUT->level = *(int *)data;
92                        return 0;
93                case TRACE_OPTION_OUTPUT_COMPRESSTYPE:
94                        OUTPUT->compress_type = *(int *)data;
95                        return 0;
96                case TRACE_OPTION_OUTPUT_FILEFLAGS:
97                        OUTPUT->fileflag = *(int *)data;
98                        return 0;
99                default:
100                        trace_set_err_out(libtrace, TRACE_ERR_UNKNOWN_OPTION,
101                                        "Unknown option");
102                        return -1;
103        }
104        assert(0);
105}
106
107static int duck_start_input(libtrace_t *libtrace) {
108       
109        if (libtrace->io)
110                /* File already open */
111                return 0;
112       
113        libtrace->io = trace_open_file(libtrace);
114        if (!libtrace->io)
115                return -1;
116
117        return 0;
118}
119
120static int duck_start_output(libtrace_out_t *libtrace) {
121        OUTPUT->file = trace_open_file_out(libtrace, 
122                                                OUTPUT->compress_type,
123                                                OUTPUT->level,
124                                                OUTPUT->fileflag);
125        if (!OUTPUT->file) {
126                return -1;
127        }
128        return 0;
129}
130
131static int duck_fin_input(libtrace_t *libtrace) {
132        wandio_destroy(libtrace->io);
133        free(libtrace->format_data);
134
135        return 0;
136}
137
138static int duck_fin_output(libtrace_out_t *libtrace) {
139        wandio_wdestroy(OUTPUT->file);
140        free(libtrace->format_data);
141        return 0;
142}
143
144static int duck_prepare_packet(libtrace_t *libtrace, libtrace_packet_t *packet,
145                void *buffer, libtrace_rt_types_t rt_type, uint32_t flags) {
146
147        if (packet->buffer != buffer &&
148                        packet->buf_control == TRACE_CTRL_PACKET) {
149                free(packet->buffer);
150        }
151
152        if ((flags & TRACE_PREP_OWN_BUFFER) == TRACE_PREP_OWN_BUFFER) {
153                packet->buf_control = TRACE_CTRL_PACKET;
154        } else
155                packet->buf_control = TRACE_CTRL_EXTERNAL;
156
157
158        packet->buffer = buffer;
159        packet->header = NULL;
160        packet->payload = buffer;
161        packet->type = rt_type;
162
163        if (libtrace->format_data == NULL) {
164                if (duck_init_input(libtrace))
165                        return -1;
166        }
167
168        return 0;
169}
170
171static int duck_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
172
173        int numbytes = 0;
174        uint32_t version = 0;
175        unsigned int duck_size;
176        uint32_t flags = 0;
177       
178        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
179                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
180                if (!packet->buffer) {
181                        trace_set_err(libtrace, errno,
182                                        "Cannot allocate memory");
183                        return -1;
184                }
185        }
186
187        flags |= TRACE_PREP_OWN_BUFFER;
188       
189        if (DATA(libtrace)->dag_version == 0) {
190                /* Read in the duck version from the start of the trace */
191                if ((numbytes = wandio_read(libtrace->io, &version, 
192                                        sizeof(version))) != sizeof(uint32_t)) {
193                        trace_set_err(libtrace, errno, 
194                                        "Reading DUCK version failed");
195                        return -1;
196                }
197                if (numbytes == 0) {
198                        return 0;
199                }
200                DATA(libtrace)->dag_version = bswap_le_to_host32(version);
201        }
202       
203
204        if (DATA(libtrace)->dag_version == TRACE_RT_DUCK_2_4) {
205                duck_size = sizeof(duck2_4_t);
206                packet->type = TRACE_RT_DUCK_2_4;
207        } else if (DATA(libtrace)->dag_version == TRACE_RT_DUCK_2_5) {
208                duck_size = sizeof(duck2_5_t);
209                packet->type = TRACE_RT_DUCK_2_5;
210        } else if (DATA(libtrace)->dag_version == TRACE_RT_DUCK_5_0) {
211                duck_size = sizeof(duck5_0_t);
212                packet->type = TRACE_RT_DUCK_5_0;
213        } else {
214                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
215                                "Unrecognised DUCK version %i", 
216                                DATA(libtrace)->dag_version);
217                return -1;
218        }
219
220        if ((numbytes = wandio_read(libtrace->io, packet->buffer,
221                                        (size_t)duck_size)) != (int)duck_size) {
222                if (numbytes == -1) {
223                        trace_set_err(libtrace, errno, "Reading DUCK failed");
224                        return -1;
225                }
226                else if (numbytes == 0) {
227                        return 0;
228                }
229                else {
230                        trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Truncated DUCK packet");
231                }
232        }
233
234        if (duck_prepare_packet(libtrace, packet, packet->buffer, packet->type,
235                                flags)) 
236                return -1;
237       
238        return numbytes;
239}
240
241static int duck_write_packet(libtrace_out_t *libtrace, 
242                libtrace_packet_t *packet) 
243{
244
245        int numbytes = 0;
246        uint32_t duck_version;
247
248        if (packet->type != TRACE_RT_DUCK_2_4
249                        && packet->type != TRACE_RT_DUCK_2_5 &&
250                        packet->type != TRACE_RT_DUCK_5_0) {
251                trace_set_err_out(libtrace, TRACE_ERR_BAD_PACKET,
252                                "Only DUCK packets may be written to a DUCK file");
253                return -1;
254        }
255       
256        assert(OUTPUT->file);
257
258        if (OUTPUT->dag_version == 0) {
259        /* Writing the DUCK version will help with reading it back in later! */
260                duck_version = bswap_host_to_le32(packet->type);
261                if ((numbytes = wandio_wwrite(OUTPUT->file, &duck_version,
262                                sizeof(duck_version))) != sizeof(uint32_t)){
263                        trace_set_err_out(libtrace, errno, 
264                                        "Writing DUCK version failed");
265                        return -1;
266                }
267                OUTPUT->dag_version = packet->type;
268        }
269       
270        if ((numbytes = wandio_wwrite(OUTPUT->file, packet->payload, 
271                                        trace_get_capture_length(packet))) !=
272                                (int)trace_get_capture_length(packet)) {
273                trace_set_err_out(libtrace, errno, "Writing DUCK failed");
274                return -1;
275        }
276        return numbytes;
277}
278
279static int duck_get_capture_length(const libtrace_packet_t *packet) {
280        switch(packet->type) {
281                case TRACE_RT_DUCK_2_4:
282                        return sizeof(duck2_4_t);
283                case TRACE_RT_DUCK_2_5:
284                        return sizeof(duck2_5_t);
285                case TRACE_RT_DUCK_5_0:
286                        return sizeof(duck5_0_t);
287                default:
288                        trace_set_err(packet->trace,TRACE_ERR_BAD_PACKET,
289                                        "Not a duck packet");
290                        return -1;
291        }
292        return 0;
293}
294
295static int duck_get_framing_length(const libtrace_packet_t *packet UNUSED) 
296{
297        return 0;
298}
299
300static int duck_get_wire_length(const libtrace_packet_t *packet UNUSED) 
301{
302        return 0;
303}
304
305static libtrace_linktype_t duck_get_link_type(
306                                const libtrace_packet_t *packet UNUSED) 
307{
308        return TRACE_TYPE_DUCK;
309}
310
311static void duck_help(void) {
312        printf("Endace DUCK format module\n");
313        printf("Supported input uris:\n");
314        printf("\tduck:/path/to/input/file\n");
315        printf("Supported output uris:\n");
316        printf("\tduck:/path/to/output/file\n");
317        printf("\n");
318        return;
319}
320static struct libtrace_format_t duck = {
321        "duck",
322        "$Id$",
323        TRACE_FORMAT_DUCK,
324        NULL,                           /* probe filename */
325        NULL,                           /* probe magic */
326        duck_init_input,                /* init_input */
327        NULL,                           /* config_input */
328        duck_start_input,               /* start_input */
329        NULL,                           /* pause_input */
330        duck_init_output,               /* init_output */
331        duck_config_output,             /* config_output */
332        duck_start_output,              /* start_output */
333        duck_fin_input,                 /* fin_input */
334        duck_fin_output,                /* fin_output */
335        duck_read_packet,               /* read_packet */
336        duck_prepare_packet,            /* prepare_packet */
337        NULL,                           /* fin_packet */
338        duck_write_packet,              /* write_packet */
339        NULL,                           /* flush_output */
340        duck_get_link_type,             /* get_link_type */
341        NULL,                           /* get_direction */
342        NULL,                           /* set_direction */
343        NULL,                           /* get_erf_timestamp */
344        NULL,                           /* get_timeval */
345        NULL,                           /* get_timespec */
346        NULL,                           /* get_seconds */
347        NULL,                           /* seek_erf */
348        NULL,                           /* seek_timeval */
349        NULL,                           /* seek_seconds */
350        duck_get_capture_length,        /* get_capture_length */
351        duck_get_wire_length,           /* get_wire_length */
352        duck_get_framing_length,        /* get_framing_length */
353        NULL,                           /* set_capture_length */
354        NULL,                           /* get_received_packets */
355        NULL,                           /* get_filtered_packets */
356        NULL,                           /* get_dropped_packets */
357        NULL,                           /* get_statistics */
358        NULL,                           /* get_fd */
359        NULL,                           /* trace_event */
360        duck_help,                      /* help */
361        NULL,                            /* next pointer */
362        NON_PARALLEL(false)
363};
364
365void duck_constructor(void) {
366        register_format(&duck);
367}       
Note: See TracBrowser for help on using the repository browser.