source: tools/tracemerge/tracemerge.c @ c0c8843

develop
Last change on this file since c0c8843 was c0c8843, checked in by Jacob Van Walraven <jcv9@…>, 22 months ago

Fix segfault when a meta packet was the final packet

  • Property mode set to 100644
File size: 8.0 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
27
28#include <libtrace.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <inttypes.h>
32#include <stdbool.h>
33#include <getopt.h>
34#include <signal.h>
35#include <string.h>
36
37static void usage(char *argv0)
38{
39        fprintf(stderr,"Usage:\n"
40        "%s flags outputuri traceuri [traceuri...]\n"
41        "-i [interfaces_per_input] --set-interface [interfaces_per_input]\n"
42        "                       Each trace is allocated an interface. Default leaves this flag as\n"
43        "                       read from the original traces, if appropriate\n"
44        "-u --unique-packets    Discard duplicate packets\n"
45        "-z level --compress-level level\n"
46        "                       Compression level\n"
47        "-Z method --compress-type method\n"
48        "                       Compression method\n"
49        "-H --libtrace-help     Print libtrace runtime documentation\n"
50        ,argv0);
51        exit(1);
52}
53
54volatile int done=0;
55
56static void cleanup_signal(int sig UNUSED)
57{
58        done=1;
59        trace_interrupt();
60}
61
62int main(int argc, char *argv[])
63{
64       
65        struct libtrace_out_t *output;
66        struct libtrace_t **input;
67        struct libtrace_packet_t **packet;
68        bool *live;
69        int interfaces_per_input=0;
70        bool unique_packets=false;
71        int i=0;
72        uint64_t last_ts=0;
73        struct sigaction sigact;
74        int compression=-1;
75        char *compress_type_str = NULL;
76        trace_option_compresstype_t compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
77
78        while (1) {
79                int option_index;
80                struct option long_options[] = {
81                        { "set-interface",      2, 0, 'i' },
82                        { "unique-packets",     0, 0, 'u' },
83                        { "libtrace-help",      0, 0, 'H' },
84                        { "compress-level",     1, 0, 'z' },
85                        { "compress-type",      1, 0, 'Z' },
86                        { NULL,                 0, 0, 0   },
87                };
88
89                int c=getopt_long(argc, argv, "i::uHz:Z:",
90                                long_options, &option_index);
91
92                if (c==-1)
93                        break;
94
95                switch (c) {
96                        case 'i':
97                                if (optarg) 
98                                        interfaces_per_input=atoi(optarg);
99                                else
100                                        interfaces_per_input=1;
101                                break;
102                        case 'u': unique_packets=true; break;
103                        case 'H':
104                                  trace_help();
105                                  exit(1);
106                                  break;
107                        case 'z':
108                                compression = atoi(optarg);
109                                if (compression<0 || compression>9) {
110                                        fprintf(stderr,"Compression level must be between 0 and 9\n");
111                                        usage(argv[0]);
112                                }
113                                break;
114
115                        case 'Z':
116                                compress_type_str = optarg;
117                                break;
118                        default:
119                                fprintf(stderr,"unknown option: %c\n",c);
120                                usage(argv[0]);
121
122                }
123
124        }
125
126        if (optind+2>argc)
127                usage(argv[0]);
128
129        if (compress_type_str == NULL && compression >= 0) {
130                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
131                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
132        }
133
134        else if (compress_type_str == NULL) {
135                /* If a level or type is not specified, use the "none"
136                 * compression module */
137                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
138        }
139
140        /* I decided to be fairly generous in what I accept for the
141         * compression type string */
142        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
143                        strncmp(compress_type_str, "zlib", 4) == 0) {
144                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
145        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
146                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
147        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
148                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
149        } else if (strncmp(compress_type_str, "xz", 2) == 0) {
150                compress_type = TRACE_OPTION_COMPRESSTYPE_LZMA;
151        } else if (strncmp(compress_type_str, "no", 2) == 0) {
152                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
153        } else {
154                fprintf(stderr, "Unknown compression type: %s\n",
155                        compress_type_str);
156                return 1;
157        }
158
159
160        output=trace_create_output(argv[optind++]);
161        if (trace_is_err_output(output)) {
162                trace_perror_output(output,"trace_create_output");
163                return 1;
164        }
165
166        if (compression >= 0 && 
167                        trace_config_output(output, 
168                        TRACE_OPTION_OUTPUT_COMPRESS, &compression) == -1) {
169                trace_perror_output(output,"Unable to set compression level");
170                return 1;
171        }
172
173        if (trace_config_output(output, TRACE_OPTION_OUTPUT_COMPRESSTYPE,
174                        &compress_type) == -1) {
175                trace_perror_output(output, "Unable to set compression method");
176                return 1;
177        }
178
179        if (trace_start_output(output)==-1) {
180                trace_perror_output(output,"trace_start_output");
181                return 1;
182        }
183
184        sigact.sa_handler = cleanup_signal;
185        sigemptyset(&sigact.sa_mask);
186        sigact.sa_flags = SA_RESTART;
187
188        sigaction(SIGINT,&sigact,NULL);
189        sigaction(SIGTERM,&sigact,NULL);
190
191        input=calloc((size_t)(argc-optind),sizeof(struct libtrace_t *));
192        packet=calloc((size_t)(argc-optind),sizeof(struct libtrace_packet_t *));
193        live=calloc((size_t)(argc-optind),sizeof(bool));
194        for(i=0;i<argc-optind;++i) {
195                libtrace_t *f;
196                libtrace_packet_t *p;
197                f=trace_create(argv[i+optind]);
198                if (trace_is_err(f)) {
199                        trace_perror(f,"trace_create");
200                        return 1;
201                }
202                if (trace_start(f)==-1) {
203                        trace_perror(f,"trace_start");
204                        return 1;
205                }
206                p=trace_create_packet();
207                input[i]=f;
208                packet[i]=p;
209                if (trace_read_packet(f,packet[i])>0){
210                        live[i]=true;
211                }
212        }
213
214        while(1) {
215                uint64_t oldest_ts=0;
216                uint64_t this_ts = 0;
217                int oldest=-1;
218                int curr_dir;
219                if (done)
220                        break;
221                for(i=0;i<argc-optind;++i) {
222                        if (!live[i] && input[i]) {
223                                int ret=trace_read_packet(input[i],packet[i]);
224                                if (ret<0) {
225                                        /* Error */
226                                        trace_perror(input[i], "%s", argv[i+2]);
227                                        trace_destroy(input[i]);
228                                        input[i]=NULL;
229                                }
230                                else if (ret==0) {
231                                        /* EOF */
232                                        trace_destroy(input[i]);
233                                        input[i]=NULL;
234                                }
235                                else
236                                        live[i]=true;
237                        }
238                        if (live[i]) {
239                                this_ts = trace_get_erf_timestamp(packet[i]);
240
241                                /* If the ts is 0 and its a meta packet just output it
242                                 * and read new packets until we get one that has a ts */
243                                while (this_ts == 0 && IS_LIBTRACE_META_PACKET(packet[i])) {
244                                        trace_write_packet(output,packet[i]);
245
246                                        /* read another packet, break if reached EOF */
247                                        if (trace_read_packet(input[i],packet[i])>0) {
248                                                live[i] = true;
249                                        } else { break; }
250                                        //fprintf(stderr, "get timestamp\n");
251                                        this_ts = trace_get_erf_timestamp(packet[i]);
252                                        //fprintf(stderr, "got timestamp\n");
253                                }
254
255                                if (this_ts != 0 && (oldest==-1 ||
256                                                oldest_ts>this_ts)) {
257                                        oldest=i;
258                                        oldest_ts=this_ts;
259                                }
260                        }
261                }
262                /* We have run out of packets! */
263                if (oldest==-1) {
264                        break;
265                }
266
267                live[oldest]=false;
268
269                curr_dir = trace_get_direction(packet[oldest]);
270                if (curr_dir != -1 && interfaces_per_input) {
271                        /* If there are more interfaces than
272                         * interfaces_per_input, then clamp at the
273                         * highest input.  This means things should
274                         * end up in "OTHER" or the unused 3rd bin if
275                         * we're lucky */
276                        curr_dir = curr_dir < interfaces_per_input
277                                ? curr_dir
278                                : interfaces_per_input-1;
279
280                        trace_set_direction(packet[oldest],
281                                        oldest*interfaces_per_input
282                                        +curr_dir);
283                }
284
285                if (unique_packets && oldest_ts == last_ts)
286                        continue;
287
288                if (trace_write_packet(output,packet[oldest]) < 0) {
289                        trace_perror_output(output, "trace_write_packet");
290                        break;
291                }
292
293                last_ts=oldest_ts;
294               
295        }
296        trace_destroy_output(output);
297
298        return 0;
299}
Note: See TracBrowser for help on using the repository browser.