source: lib/format_erf.c @ 4bd8a5b

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 4bd8a5b was 4bd8a5b, checked in by Perry Lorier <perry@…>, 14 years ago

Cleanup a gazillion warnings

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