source: lib/format_erf.c @ 721c0e4

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

erf_read_packet no longer asserts on corrupt or truncated packets - it will now return a bad packet error instead

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007 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#define _GNU_SOURCE
31
32#include "config.h"
33#include "common.h"
34#include "libtrace.h"
35#include "libtrace_int.h"
36#include "format_helper.h"
37#include "format_erf.h"
38
39#include <assert.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45
46#ifdef WIN32
47#  include <io.h>
48#  include <share.h>
49#  define PATH_MAX _MAX_PATH
50#else
51#  include <netdb.h>
52#  ifndef PATH_MAX
53#       define PATH_MAX 4096
54#  endif
55#  include <sys/ioctl.h>
56#endif
57
58
59#define COLLECTOR_PORT 3435
60
61static struct libtrace_format_t erfformat;
62
63#define DATA(x) ((struct erf_format_data_t *)x->format_data)
64#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
65
66#define INPUT DATA(libtrace)->input
67#define OUTPUT DATAOUT(libtrace)->output
68#define OPTIONS DATAOUT(libtrace)->options
69struct erf_format_data_t {
70       
71        union {
72                int fd;
73                libtrace_io_t *file;
74        } input;
75
76        struct {
77                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
78                libtrace_io_t *index;
79                off_t index_len;
80        } seek;
81
82};
83
84struct erf_format_data_out_t {
85        union {
86                struct {
87                        int level;
88                        int fileflag;
89                } erf;
90               
91        } options;
92       
93        union {
94                int fd;
95                struct rtserver_t * rtserver;
96                libtrace_io_t *file;
97        } output;
98};
99
100/** Structure holding status information for a packet */
101typedef struct libtrace_packet_status {
102        uint8_t type;
103        uint8_t reserved;
104        uint16_t message;
105} libtrace_packet_status_t;
106
107typedef struct erf_index_t {
108        uint64_t timestamp;
109        uint64_t offset; 
110} erf_index_t;
111
112
113/* Dag erf ether packets have a 2 byte padding before the packet
114 * so that the ip header is aligned on a 32 bit boundary.
115 */
116static int erf_get_padding(const libtrace_packet_t *packet)
117{
118        if (packet->trace->format->type==TRACE_FORMAT_ERF) {
119                dag_record_t *erfptr = (dag_record_t *)packet->header;
120                switch(erfptr->type) {
121                        case TYPE_ETH:          return 2;
122                        default:                return 0;
123                }
124        }
125        else {
126                switch(trace_get_link_type(packet)) {
127                        case TYPE_ETH:          return 2;
128                        default:                return 0;
129                }
130        }
131}
132
133int erf_get_framing_length(const libtrace_packet_t *packet)
134{
135        return dag_record_size + erf_get_padding(packet);
136}
137
138
139static int erf_init_input(libtrace_t *libtrace) 
140{
141        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
142       
143        INPUT.file = 0;
144
145        return 0; /* success */
146}
147
148static int erf_start_input(libtrace_t *libtrace)
149{
150        if (INPUT.file)
151                return 0; /* success */
152
153        INPUT.file = trace_open_file(libtrace);
154
155        if (!INPUT.file)
156                return -1;
157
158        return 0; /* success */
159}
160
161/* Binary search through the index to find the closest point before
162 * the packet.  Consider in future having a btree index perhaps?
163 */
164static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
165{
166        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
167        size_t min_off = 0;
168        off_t current;
169        erf_index_t record;
170        do {
171                current=(max_off+min_off)>>2;
172
173                libtrace_io_seek(DATA(libtrace)->seek.index,
174                                (int64_t)(current*sizeof(record)),
175                                SEEK_SET);
176                libtrace_io_read(DATA(libtrace)->seek.index,
177                                &record,sizeof(record));
178                if (record.timestamp < erfts) {
179                        min_off=current;
180                }
181                if (record.timestamp > erfts) {
182                        max_off=current;
183                }
184                if (record.timestamp == erfts)
185                        break;
186        } while(min_off<max_off);
187
188        /* If we've passed it, seek backwards.  This loop shouldn't
189         * execute more than twice.
190         */
191        do {
192                libtrace_io_seek(DATA(libtrace)->seek.index,
193                                (int64_t)(current*sizeof(record)),SEEK_SET);
194                libtrace_io_read(DATA(libtrace)->seek.index,
195                                &record,sizeof(record));
196                current--;
197        } while(record.timestamp>erfts);
198
199        /* We've found our location in the trace, now use it. */
200        libtrace_io_seek(INPUT.file,(int64_t) record.offset,SEEK_SET);
201
202        return 0; /* success */
203}
204
205/* There is no index.  Seek through the entire trace from the start, nice
206 * and slowly.
207 */
208static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts UNUSED)
209{
210        if (INPUT.file) {
211                libtrace_io_close(INPUT.file);
212        }
213        INPUT.file = trace_open_file(libtrace);
214        if (!INPUT.file)
215                return -1;
216        return 0;
217}
218
219static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
220{
221        libtrace_packet_t *packet;
222        off_t off = 0;
223
224        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
225                char buffer[PATH_MAX];
226                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
227                DATA(libtrace)->seek.index=libtrace_io_open(buffer,"rb");
228                if (DATA(libtrace)->seek.index) {
229                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
230                }
231                else {
232                        DATA(libtrace)->seek.exists=INDEX_NONE;
233                }
234        }
235
236        /* If theres an index, use it to find the nearest packet that isn't
237         * after the time we're looking for.  If there is no index we need
238         * to seek slowly through the trace from the beginning.  Sigh.
239         */
240        switch(DATA(libtrace)->seek.exists) {
241                case INDEX_EXISTS:
242                        erf_fast_seek_start(libtrace,erfts);
243                        break;
244                case INDEX_NONE:
245                        erf_slow_seek_start(libtrace,erfts);
246                        break;
247                case INDEX_UNKNOWN:
248                        assert(0);
249                        break;
250        }
251
252        /* Now seek forward looking for the correct timestamp */
253        packet=trace_create_packet();
254        do {
255                trace_read_packet(libtrace,packet);
256                if (trace_get_erf_timestamp(packet)==erfts)
257                        break;
258                off=libtrace_io_tell(INPUT.file);
259        } while(trace_get_erf_timestamp(packet)<erfts);
260
261        libtrace_io_seek(INPUT.file,off,SEEK_SET);
262
263        return 0;
264}
265
266static int erf_init_output(libtrace_out_t *libtrace) {
267        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
268
269        OPTIONS.erf.level = 0;
270        OPTIONS.erf.fileflag = O_CREAT | O_WRONLY;
271        OUTPUT.file = 0;
272
273        return 0;
274}
275
276static int erf_config_output(libtrace_out_t *libtrace, trace_option_output_t option,
277                void *value) {
278
279        switch (option) {
280                case TRACE_OPTION_OUTPUT_COMPRESS:
281                        OPTIONS.erf.level = *(int*)value;
282                        return 0;
283                case TRACE_OPTION_OUTPUT_FILEFLAGS:
284                        OPTIONS.erf.fileflag = *(int*)value;
285                        return 0;
286                default:
287                        /* Unknown option */
288                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
289                                        "Unknown option");
290                        return -1;
291        }
292}
293
294
295
296static int erf_fin_input(libtrace_t *libtrace) {
297        if (INPUT.file)
298                libtrace_io_close(INPUT.file);
299        free(libtrace->format_data);
300        return 0;
301}
302
303static int erf_fin_output(libtrace_out_t *libtrace) {
304        if (OUTPUT.file)
305                libtrace_io_close(OUTPUT.file);
306        free(libtrace->format_data);
307        return 0;
308}
309 
310
311static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
312        int numbytes;
313        unsigned int size;
314        void *buffer2 = packet->buffer;
315        unsigned int rlen;
316
317        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
318                packet->buffer = malloc((size_t)LIBTRACE_PACKET_BUFSIZE);
319                packet->buf_control = TRACE_CTRL_PACKET;
320                if (!packet->buffer) {
321                        trace_set_err(libtrace, errno, 
322                                        "Cannot allocate memory");
323                        return -1;
324                }
325        }
326
327       
328       
329        packet->header = packet->buffer;
330        packet->type = TRACE_RT_DATA_ERF;
331
332        if ((numbytes=libtrace_io_read(INPUT.file,
333                                        packet->buffer,
334                                        (size_t)dag_record_size)) == -1) {
335                trace_set_err(libtrace,errno,"read(%s)",
336                                libtrace->uridata);
337                return -1;
338        }
339        /* EOF */
340        if (numbytes == 0) {
341                return 0;
342        }
343
344        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
345        buffer2 = (char*)packet->buffer + dag_record_size;
346        size = rlen - dag_record_size;
347
348        if (size >= LIBTRACE_PACKET_BUFSIZE) {
349                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Packet size %u larger than supported by libtrace - packet is probably corrupt", size);
350                return -1;
351        }
352
353        /* Unknown/corrupt */
354        if (((dag_record_t *)packet->buffer)->type >= 10) {
355                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET, "Corrupt or Unknown ERF type");
356                return -1;
357        }
358       
359        /* read in the rest of the packet */
360        if ((numbytes=libtrace_io_read(INPUT.file,
361                                        buffer2,
362                                        (size_t)size)) != (int)size) {
363                if (numbytes==-1) {
364                        trace_set_err(libtrace,errno, "read(%s)", libtrace->uridata);
365                        return -1;
366                }
367                trace_set_err(libtrace,EIO,"Truncated packet (wanted %d, got %d)", size, numbytes);
368                /* Failed to read the full packet?  must be EOF */
369                return -1;
370        }
371        if (((dag_record_t *)packet->buffer)->flags.rxerror == 1) {
372                packet->payload = NULL;
373        } else {
374                packet->payload = (char*)packet->buffer + erf_get_framing_length(packet);
375        }
376        return rlen;
377}
378
379static int erf_dump_packet(libtrace_out_t *libtrace,
380                dag_record_t *erfptr, unsigned int pad, void *buffer) {
381        int numbytes = 0;
382        int size;
383
384        if ((numbytes = 
385                libtrace_io_write(OUTPUT.file, 
386                                erfptr,
387                                (size_t)(dag_record_size + pad))) 
388                        != (int)(dag_record_size+pad)) {
389                trace_set_err_out(libtrace,errno,
390                                "write(%s)",libtrace->uridata);
391                return -1;
392        }
393
394        size=ntohs(erfptr->rlen)-(dag_record_size+pad);
395        numbytes=libtrace_io_write(OUTPUT.file, buffer, (size_t)size);
396        if (numbytes != size) {
397                trace_set_err_out(libtrace,errno,
398                                "write(%s)",libtrace->uridata);
399                return -1;
400        }
401        return numbytes + pad + dag_record_size;
402}
403
404static int erf_start_output(libtrace_out_t *libtrace)
405{
406        OUTPUT.file = trace_open_file_out(libtrace,
407                        OPTIONS.erf.level,
408                        OPTIONS.erf.fileflag);
409        if (!OUTPUT.file) {
410                return -1;
411        }
412        return 0;
413}
414
415static bool find_compatible_linktype(libtrace_out_t *libtrace,
416                                libtrace_packet_t *packet)
417{
418        /* Keep trying to simplify the packet until we can find
419         * something we can do with it */
420        do {
421                char type=libtrace_to_erf_type(trace_get_link_type(packet));
422
423                /* Success */
424                if (type != (char)-1)
425                        return true;
426
427                if (!demote_packet(packet)) {
428                        trace_set_err_out(libtrace,
429                                        TRACE_ERR_NO_CONVERSION,
430                                        "No erf type for packet (%i)",
431                                        trace_get_link_type(packet));
432                        return false;
433                }
434
435        } while(1);
436
437        return true;
438}
439               
440static int erf_write_packet(libtrace_out_t *libtrace, 
441                libtrace_packet_t *packet) 
442{
443        int numbytes = 0;
444        unsigned int pad = 0;
445        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
446        void *payload = packet->payload;
447
448        assert(OUTPUT.file);
449
450        if (!packet->header) {
451                /*trace_set_err_output(libtrace, TRACE_ERR_BAD_PACKET,
452                                "Packet has no header - probably an RT packet");
453                */
454                return -1;
455        }
456       
457        pad = erf_get_padding(packet);
458
459        /* If we've had an rxerror, we have no payload to write - fix
460         * rlen to be the correct length
461         */
462        /* I Think this is bogus, we should somehow figure out
463         * a way to write out the payload even if it is gibberish -- Perry */
464        if (payload == NULL) {
465                dag_hdr->rlen = htons(dag_record_size + pad);
466               
467        } 
468       
469        if (packet->type == TRACE_RT_DATA_ERF) {
470                        numbytes = erf_dump_packet(libtrace,
471                                (dag_record_t *)packet->header,
472                                pad,
473                                payload
474                                );
475        } else {
476                dag_record_t erfhdr;
477                /* convert format - build up a new erf header */
478                /* Timestamp */
479                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
480
481                /* Flags. Can't do this */
482                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
483                if (trace_get_direction(packet)!=~0U)
484                        erfhdr.flags.iface = trace_get_direction(packet);
485
486                if (!find_compatible_linktype(libtrace,packet))
487                        return -1;
488
489                payload=packet->payload;
490                pad = erf_get_padding(packet);
491
492                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
493
494                /* Packet length (rlen includes format overhead) */
495                assert(trace_get_capture_length(packet)>0 
496                                && trace_get_capture_length(packet)<=65536);
497                assert(erf_get_framing_length(packet)>0 
498                                && trace_get_framing_length(packet)<=65536);
499                assert(
500                        trace_get_capture_length(packet)+erf_get_framing_length(packet)>0
501                      &&trace_get_capture_length(packet)+erf_get_framing_length(packet)<=65536);
502                erfhdr.rlen = htons(trace_get_capture_length(packet) 
503                        + erf_get_framing_length(packet));
504                /* loss counter. Can't do this */
505                erfhdr.lctr = 0;
506                /* Wire length, does not include padding! */
507                erfhdr.wlen = htons(trace_get_wire_length(packet));
508
509                /* Write it out */
510                numbytes = erf_dump_packet(libtrace,
511                                &erfhdr,
512                                pad,
513                                payload);
514        }
515        return numbytes;
516}
517
518libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
519        dag_record_t *erfptr = 0;
520        erfptr = (dag_record_t *)packet->header;
521        if (erfptr->type != TYPE_LEGACY)
522                return erf_type_to_libtrace(erfptr->type);
523        else {
524                /* Sigh, lets start wildly guessing */
525                if (((char*)packet->payload)[4]==0x45)
526                        return TRACE_TYPE_PPP;
527                return ~0;
528        }
529}
530
531libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
532        dag_record_t *erfptr = 0;
533        erfptr = (dag_record_t *)packet->header;
534        return erfptr->flags.iface;
535}
536
537libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
538        dag_record_t *erfptr = 0;
539        erfptr = (dag_record_t *)packet->header;
540        erfptr->flags.iface = direction;
541        return erfptr->flags.iface;
542}
543
544uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
545        dag_record_t *erfptr = 0;
546        erfptr = (dag_record_t *)packet->header;
547        return bswap_le_to_host64(erfptr->ts);
548}
549
550int erf_get_capture_length(const libtrace_packet_t *packet) {
551        dag_record_t *erfptr = 0;
552        int caplen;
553        if (packet->payload == NULL)
554                return 0; 
555       
556        erfptr = (dag_record_t *)packet->header;
557        caplen = ntohs(erfptr->rlen) - erf_get_framing_length(packet);
558        if (ntohs(erfptr->wlen) < caplen)
559                return ntohs(erfptr->wlen);
560
561        return (ntohs(erfptr->rlen) - erf_get_framing_length(packet));
562}
563
564int erf_get_wire_length(const libtrace_packet_t *packet) {
565        dag_record_t *erfptr = 0;
566        erfptr = (dag_record_t *)packet->header;
567        return ntohs(erfptr->wlen);
568}
569
570size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
571        dag_record_t *erfptr = 0;
572        assert(packet);
573        if(size  > trace_get_capture_length(packet)) {
574                /* can't make a packet larger */
575                return trace_get_capture_length(packet);
576        }
577        erfptr = (dag_record_t *)packet->header;
578        erfptr->rlen = htons(size + erf_get_framing_length(packet));
579        return trace_get_capture_length(packet);
580}
581
582static void erf_help(void) {
583        printf("erf format module: $Revision$\n");
584        printf("Supported input URIs:\n");
585        printf("\terf:/path/to/file\t(uncompressed)\n");
586        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
587        printf("\terf:-\t(stdin, either compressed or not)\n");
588        printf("\terf:/path/to/socket\n");
589        printf("\n");
590        printf("\te.g.: erf:/tmp/trace\n");
591        printf("\n");
592        printf("Supported output URIs:\n");
593        printf("\terf:path/to/file\t(uncompressed)\n");
594        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
595        printf("\terf:-\t(stdout, either compressed or not)\n");
596        printf("\n");
597        printf("\te.g.: erf:/tmp/trace\n");
598        printf("\n");
599        printf("Supported output options:\n");
600        printf("\t-z\tSpecify the gzip compression, ranging from 0 (uncompressed) to 9 - defaults to 1\n");
601        printf("\n");
602
603       
604}
605
606static struct libtrace_format_t erfformat = {
607        "erf",
608        "$Id$",
609        TRACE_FORMAT_ERF,
610        erf_init_input,                 /* init_input */       
611        NULL,                           /* config_input */
612        erf_start_input,                /* start_input */
613        NULL,                           /* pause_input */
614        erf_init_output,                /* init_output */
615        erf_config_output,              /* config_output */
616        erf_start_output,               /* start_output */
617        erf_fin_input,                  /* fin_input */
618        erf_fin_output,                 /* fin_output */
619        erf_read_packet,                /* read_packet */
620        NULL,                           /* fin_packet */
621        erf_write_packet,               /* write_packet */
622        erf_get_link_type,              /* get_link_type */
623        erf_get_direction,              /* get_direction */
624        erf_set_direction,              /* set_direction */
625        erf_get_erf_timestamp,          /* get_erf_timestamp */
626        NULL,                           /* get_timeval */
627        NULL,                           /* get_seconds */
628        erf_seek_erf,                   /* seek_erf */
629        NULL,                           /* seek_timeval */
630        NULL,                           /* seek_seconds */
631        erf_get_capture_length,         /* get_capture_length */
632        erf_get_wire_length,            /* get_wire_length */
633        erf_get_framing_length,         /* get_framing_length */
634        erf_set_capture_length,         /* set_capture_length */
635        NULL,                           /* get_fd */
636        trace_event_trace,              /* trace_event */
637        erf_help,                       /* help */
638        NULL                            /* next pointer */
639};
640
641
642void erf_constructor(void) {
643        register_format(&erfformat);
644}
Note: See TracBrowser for help on using the repository browser.