source: lib/format_erf.c @ 19c6cbe

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

Fixed bug where tracesplit and associated tools were not flushing remaining data at the end of their execution.
Resolved warning about unsigned/signed comparison in format_erf.
Added/removed a few newlines over the course of my debugging.

  • Property mode set to 100644
File size: 25.2 KB
RevLine 
[4dedc28]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 */
[9c6aa95]30#define _GNU_SOURCE
[4dedc28]31
[39b37d2]32#include "config.h"
[641dc7c]33#include "common.h"
[4dedc28]34#include "libtrace.h"
[9e2a109]35#include "libtrace_int.h"
[72bfe20]36#include "format_helper.h"
[91ebc50]37#include "parse_cmd.h"
[4dedc28]38
39#include <assert.h>
40#include <errno.h>
[1fc2f6a]41#include <fcntl.h>
[b69afb1]42#include <stdio.h>
[9c6aa95]43#include <string.h>
44#include <stdlib.h>
[4dedc28]45
[e5c2bc4]46#ifdef HAVE_DAG
[97c8d58]47#include <sys/mman.h>
48#endif
49
[23971d0]50#ifdef WIN32
51#  include <io.h>
52#  include <share.h>
53#  define PATH_MAX _MAX_PATH
54#  define snprintf sprintf_s
55#else
56#  include <netdb.h>
[3fcb8b4]57#  ifndef PATH_MAX
58#       define PATH_MAX 4096
59#  endif
[deed208]60#  include <sys/ioctl.h>
[23971d0]61#endif
62
[14d8a63]63
[803ea87]64#define COLLECTOR_PORT 3435
65
[f3ed52a]66static struct libtrace_format_t erf;
[e5c2bc4]67#ifdef HAVE_DAG
[f3ed52a]68static struct libtrace_format_t dag;
[1974620]69#endif
70
[d5879cc]71#define DATA(x) ((struct erf_format_data_t *)x->format_data)
72#define DATAOUT(x) ((struct erf_format_data_out_t *)x->format_data)
73
[ab4cb04]74#define CONNINFO DATA(libtrace)->conn_info
75#define INPUT DATA(libtrace)->input
76#define OUTPUT DATAOUT(libtrace)->output
[e5c2bc4]77#ifdef HAVE_DAG
[ab4cb04]78#define DAG DATA(libtrace)->dag
[da34e20]79#define DUCK DATA(libtrace)->duck
[1974620]80#endif
[ab4cb04]81#define OPTIONS DATAOUT(libtrace)->options
[d5879cc]82struct erf_format_data_t {
[9e2a109]83        union {
84                struct {
85                        char *hostname;
86                        short port;
87                } rt;
88        } conn_info;
[1974620]89       
90        union {
[9e2a109]91                int fd;
[edb18ce]92                libtrace_io_t *file;
[9e2a109]93        } input;
94
[0d57541]95        struct {
96                enum { INDEX_UNKNOWN=0, INDEX_NONE, INDEX_EXISTS } exists;
[edb18ce]97                libtrace_io_t *index;
[0d57541]98                off_t index_len;
99        } seek;
100
[e5c2bc4]101#ifdef HAVE_DAG
[9e2a109]102        struct {
[da34e20]103                uint32_t last_duck;     
104                uint32_t duck_freq;
105                uint32_t last_pkt;
[cd7eec7]106                libtrace_t *dummy_duck;
[da34e20]107        } duck;
108       
109        struct {
[9e2a109]110                void *buf; 
111                unsigned bottom;
112                unsigned top;
113                unsigned diff;
114                unsigned curr;
115                unsigned offset;
[0e9b9f8]116                unsigned int dagstream;
[9e2a109]117        } dag;
[1974620]118#endif
[9e2a109]119};
120
[d5879cc]121struct erf_format_data_out_t {
[9e2a109]122        union {
123                struct {
124                        char *hostname;
125                        short port;
126                } rt;
127                char *path;
128        } conn_info;
129
130        union {
131                struct {
132                        int level;
[7068467]133                        int fileflag;
[9e2a109]134                } erf;
135               
136        } options;
137       
138        union {
139                int fd;
140                struct rtserver_t * rtserver;
[edb18ce]141                libtrace_io_t *file;
[9e2a109]142        } output;
143};
144
[7068467]145/** Structure holding status information for a packet */
146typedef struct libtrace_packet_status {
147        uint8_t type;
148        uint8_t reserved;
149        uint16_t message;
150} libtrace_packet_status_t;
151
[0d57541]152typedef struct erf_index_t {
153        uint64_t timestamp;
154        uint64_t offset; 
155} erf_index_t;
[7068467]156
[7050c10]157#ifdef HAVE_DAG
[e6d963c]158static int dag_init_input(libtrace_t *libtrace) {
[eeab9832]159        struct stat buf;
160
[9fae46b]161        libtrace->format_data = (struct erf_format_data_t *)
162                malloc(sizeof(struct erf_format_data_t));
[6dbc47a]163        if (stat(libtrace->uridata, &buf) == -1) {
[0ea3526]164                trace_set_err(libtrace,errno,"stat(%s)",libtrace->uridata);
[d5879cc]165                return -1;
[4dedc28]166        } 
[0e9b9f8]167
168        DAG.dagstream = 0;
169       
[4dedc28]170        if (S_ISCHR(buf.st_mode)) {
[7068467]171                /* DEVICE */
[6dbc47a]172                if((INPUT.fd = dag_open(libtrace->uridata)) < 0) {
[0ea3526]173                        trace_set_err(libtrace,errno,"Cannot open DAG %s",
[6dbc47a]174                                        libtrace->uridata);
[d5879cc]175                        return -1;
[4dedc28]176                }
[ffc8c8d]177                if((DAG.buf = (void *)dag_mmap(INPUT.fd)) == MAP_FAILED) {
[0ea3526]178                        trace_set_err(libtrace,errno,"Cannot mmap DAG %s",
[6dbc47a]179                                        libtrace->uridata);
[d5879cc]180                        return -1;
[4dedc28]181                }
182        } else {
[0ea3526]183                trace_set_err(libtrace,errno,"Not a valid dag device: %s",
[6dbc47a]184                                libtrace->uridata);
[d5879cc]185                return -1;
[4dedc28]186        }
[da34e20]187
188        DUCK.last_duck = 0;
[cd7eec7]189        DUCK.duck_freq = 0; 
[da34e20]190        DUCK.last_pkt = 0;
[cd7eec7]191        DUCK.dummy_duck = NULL;
[da34e20]192       
[d5879cc]193        return 0;
[4dedc28]194}
[eeab9832]195
[cd7eec7]196static int dag_config_input(libtrace_t *libtrace, trace_option_t option,
197                                void *data) {
198        switch(option) {
199                case TRACE_META_FREQ:
200                        DUCK.duck_freq = *(int *)data;
201                        return 0;
202                case TRACE_OPTION_SNAPLEN:
203                        /* Surely we can set this?? Fall through for now*/
204               
205                case TRACE_OPTION_PROMISC:
206                        /* DAG already operates in a promisc fashion */
207
208                case TRACE_OPTION_FILTER:
209
210                default:
211                        trace_set_err(libtrace, TRACE_ERR_UNKNOWN_OPTION,
212                                        "Unknown or unsupported option: %i",
213                                        option);
214                        return -1;
215        }
216        assert (0);
217}
[fe43699]218#endif
[4dedc28]219
[8f4152b]220/* Dag erf ether packets have a 2 byte padding before the packet
221 * so that the ip header is aligned on a 32 bit boundary.
222 */
[eeab9832]223static int erf_get_padding(const libtrace_packet_t *packet)
[8f4152b]224{
[f57715c8]225        if (packet->trace->format->type==TRACE_FORMAT_ERF) {
226                dag_record_t *erfptr = (dag_record_t *)packet->header;
227                switch(erfptr->type) {
228                        case TYPE_ETH:          return 2;
229                        default:                return 0;
230                }
231        }
232        else {
233                switch(trace_get_link_type(packet)) {
234                        case TYPE_ETH:          return 2;
235                        default:                return 0;
236                }
[8f4152b]237        }
238}
239
[eeab9832]240static int erf_get_framing_length(const libtrace_packet_t *packet)
[8f4152b]241{
242        return dag_record_size + erf_get_padding(packet);
243}
244
245
[eeab9832]246static int erf_init_input(libtrace_t *libtrace) 
[3d4d52d]247{
[d5879cc]248        libtrace->format_data = malloc(sizeof(struct erf_format_data_t));
[9c4b5e3]249       
[9e830d4]250        INPUT.file = 0;
[25efeac]251
[d5879cc]252        return 0; /* success */
[65a5900]253}
254
[0d57541]255static int erf_start_input(libtrace_t *libtrace)
[65a5900]256{
[6c248a9]257        if (INPUT.file)
258                return 0; /* success */
259
[ab4cb04]260        INPUT.file = trace_open_file(libtrace);
[3d4d52d]261
[ab4cb04]262        if (!INPUT.file)
263                return -1;
[3d4d52d]264
[d5879cc]265        return 0; /* success */
[4dedc28]266}
267
[0d57541]268/* Binary search through the index to find the closest point before
269 * the packet.  Consider in future having a btree index perhaps?
270 */
271static int erf_fast_seek_start(libtrace_t *libtrace,uint64_t erfts)
272{
273        size_t max_off = DATA(libtrace)->seek.index_len/sizeof(erf_index_t);
274        size_t min_off = 0;
275        off_t current;
276        erf_index_t record;
277        do {
278                current=(max_off+min_off)>>2;
279
[edb18ce]280                libtrace_io_seek(DATA(libtrace)->seek.index,
[0d57541]281                                current*sizeof(record),
282                                SEEK_SET);
[edb18ce]283                libtrace_io_read(DATA(libtrace)->seek.index,
[0d57541]284                                &record,sizeof(record));
285                if (record.timestamp < erfts) {
286                        min_off=current;
287                }
288                if (record.timestamp > erfts) {
289                        max_off=current;
290                }
291                if (record.timestamp == erfts)
292                        break;
293        } while(min_off<max_off);
294
295        /* If we've passed it, seek backwards.  This loop shouldn't
296         * execute more than twice.
297         */
298        do {
[edb18ce]299                libtrace_io_seek(DATA(libtrace)->seek.index,
[0d57541]300                                current*sizeof(record),SEEK_SET);
[edb18ce]301                libtrace_io_read(DATA(libtrace)->seek.index,
[0d57541]302                                &record,sizeof(record));
303                current--;
304        } while(record.timestamp>erfts);
305
306        /* We've found our location in the trace, now use it. */
[edb18ce]307        libtrace_io_seek(INPUT.file,record.offset,SEEK_SET);
[0d57541]308
309        return 0; /* success */
310}
311
312/* There is no index.  Seek through the entire trace from the start, nice
313 * and slowly.
314 */
315static int erf_slow_seek_start(libtrace_t *libtrace,uint64_t erfts)
316{
317        if (INPUT.file) {
[edb18ce]318                libtrace_io_close(INPUT.file);
[0d57541]319        }
320        INPUT.file = trace_open_file(libtrace);
321        if (!INPUT.file)
322                return -1;
323        return 0;
324}
325
326static int erf_seek_erf(libtrace_t *libtrace,uint64_t erfts)
327{
328        libtrace_packet_t *packet;
329        off_t off = 0;
330
331        if (DATA(libtrace)->seek.exists==INDEX_UNKNOWN) {
332                char buffer[PATH_MAX];
333                snprintf(buffer,sizeof(buffer),"%s.idx",libtrace->uridata);
[5b4404a]334                DATA(libtrace)->seek.index=libtrace_io_open(buffer,"rb");
[0d57541]335                if (DATA(libtrace)->seek.index) {
336                        DATA(libtrace)->seek.exists=INDEX_EXISTS;
337                }
338                else {
339                        DATA(libtrace)->seek.exists=INDEX_NONE;
340                }
341        }
342
343        /* If theres an index, use it to find the nearest packet that isn't
344         * after the time we're looking for.  If there is no index we need
345         * to seek slowly through the trace from the beginning.  Sigh.
346         */
347        switch(DATA(libtrace)->seek.exists) {
348                case INDEX_EXISTS:
349                        erf_fast_seek_start(libtrace,erfts);
350                        break;
351                case INDEX_NONE:
352                        erf_slow_seek_start(libtrace,erfts);
353                        break;
354                case INDEX_UNKNOWN:
355                        assert(0);
356                        break;
357        }
358
359        /* Now seek forward looking for the correct timestamp */
360        packet=trace_create_packet();
361        do {
362                trace_read_packet(libtrace,packet);
363                if (trace_get_erf_timestamp(packet)==erfts)
364                        break;
[edb18ce]365                off=libtrace_io_tell(INPUT.file);
[0d57541]366        } while(trace_get_erf_timestamp(packet)<erfts);
367
[edb18ce]368        libtrace_io_seek(INPUT.file,off,SEEK_SET);
[0d57541]369
370        return 0;
371}
372
[eeab9832]373static int erf_init_output(libtrace_out_t *libtrace) {
[747c501]374        libtrace->format_data = malloc(sizeof(struct erf_format_data_out_t));
[91ebc50]375
[3073c04]376        OPTIONS.erf.level = 0;
[6b2d5ed]377        OPTIONS.erf.fileflag = O_CREAT | O_WRONLY;
[5baec88]378        OUTPUT.file = 0;
379
[fe76c55]380        return 0;
[5baec88]381}
382
[9e830d4]383static int erf_config_output(libtrace_out_t *libtrace, trace_option_output_t option,
384                void *value) {
[91ebc50]385
[7068467]386        switch (option) {
387                case TRACE_OPTION_OUTPUT_COMPRESS:
388                        OPTIONS.erf.level = *(int*)value;
389                        return 0;
390                case TRACE_OPTION_OUTPUT_FILEFLAGS:
391                        OPTIONS.erf.fileflag = *(int*)value;
392                        return 0;
393                default:
394                        /* Unknown option */
[0ea3526]395                        trace_set_err_out(libtrace,TRACE_ERR_UNKNOWN_OPTION,
[880aa58]396                                        "Unknown option");
[7068467]397                        return -1;
398        }
[91ebc50]399}
400
401
[7050c10]402#ifdef HAVE_DAG
[eeab9832]403static int dag_pause_input(libtrace_t *libtrace) {
[e5c2bc4]404#ifdef DAG_VERSION_2_4
[9e2a109]405        dag_stop(INPUT.fd);
[0e9b9f8]406#else
407        if (dag_stop_stream(INPUT.fd, DAG.dagstream) < 0) {
408                trace_set_err(libtrace, errno, "Could not stop DAG stream");
409                return -1;
410        }
411        if (dag_detach_stream(INPUT.fd, DAG.dagstream) < 0) {
412                trace_set_err(libtrace, errno, "Could not detach DAG stream");
413                return -1;
414        }
415#endif
[eeab9832]416        return 0; /* success */
417}
418
419static int dag_fin_input(libtrace_t *libtrace) {
420        /* dag pause input implicitly called to cleanup before this */
[0e9b9f8]421       
[eeab9832]422        dag_close(INPUT.fd);
[cd7eec7]423        if (DUCK.dummy_duck)
424                trace_destroy_dead(DUCK.dummy_duck);
[c2d5f23]425        free(libtrace->format_data);
[eeab9832]426        return 0; /* success */
[4dedc28]427}
[fe43699]428#endif
[4dedc28]429
[eeab9832]430static int erf_fin_input(libtrace_t *libtrace) {
[ebe0c7f]431        if (INPUT.file)
432                libtrace_io_close(INPUT.file);
[6dbc47a]433        free(libtrace->format_data);
[9c6aa95]434        return 0;
[4dedc28]435}
436
[eeab9832]437static int erf_fin_output(libtrace_out_t *libtrace) {
[edb18ce]438        libtrace_io_close(OUTPUT.file);
[ae8196e]439        free(libtrace->format_data);
[9c6aa95]440        return 0;
[1fc2f6a]441}
442 
[e5c2bc4]443#ifdef HAVE_DAG
444#ifdef DAG_VERSION_2_4
[da34e20]445static int dag_get_duckinfo(libtrace_t *libtrace, 
446                                libtrace_packet_t *packet) {
447        dag_inf lt_dag_inf;
448       
449        if (packet->buf_control == TRACE_CTRL_EXTERNAL || 
450                        !packet->buffer) {
451                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
452                packet->buf_control = TRACE_CTRL_PACKET;
453                if (!packet->buffer) {
454                        trace_set_err(libtrace, errno,
455                                        "Cannot allocate packet buffer");
456                        return -1;
457                }
458        }
459       
460        packet->header = 0;
461        packet->payload = packet->buffer;
462       
463        if ((ioctl(INPUT.fd, DAG_IOINF, &lt_dag_inf) < 0)) {
464                trace_set_err(libtrace, errno,
465                                "Error using DAG_IOINF");
466                return -1;
467        }
468        if (!IsDUCK(&lt_dag_inf)) {
469                printf("WARNING: %s does not have modern clock support - No DUCK information will be gathered\n", libtrace->uridata);
470                return 0;
471        }
472
473        if ((ioctl(INPUT.fd, DAG_IOGETDUCK, (duck_inf *)packet->payload) 
474                                < 0)) {
475                trace_set_err(libtrace, errno, "Error using DAG_IOGETDUCK");
476                return -1;
477        }
478
479        packet->type = RT_DUCK_2_4;
[cd7eec7]480        if (!DUCK.dummy_duck) 
481                DUCK.dummy_duck = trace_create_dead("duck:dummy");
482        packet->trace = DUCK.dummy_duck;
[a7d1914]483        return sizeof(duck_inf);
[da34e20]484}       
485#else
486static int dag_get_duckinfo(libtrace_t *libtrace, 
487                                libtrace_packet_t *packet) {
488        daginf_t lt_dag_inf;
489       
490        if (packet->buf_control == TRACE_CTRL_EXTERNAL || 
491                        !packet->buffer) {
492                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
493                packet->buf_control = TRACE_CTRL_PACKET;
494                if (!packet->buffer) {
495                        trace_set_err(libtrace, errno,
496                                        "Cannot allocate packet buffer");
497                        return -1;
498                }
499        }
500       
501        packet->header = 0;
502        packet->payload = packet->buffer;
503       
[deed208]504        /* No need to check if we can get DUCK or not - we're modern
505         * enough */
[da34e20]506        if ((ioctl(INPUT.fd, DAGIOCDUCK, (duckinf_t *)packet->payload) 
507                                < 0)) {
508                trace_set_err(libtrace, errno, "Error using DAGIOCDUCK");
509                return -1;
510        }
511
512        packet->type = RT_DUCK_2_5;
[cd7eec7]513        if (!DUCK.dummy_duck) 
514                DUCK.dummy_duck = trace_create_dead("rt:localhost:3434");
515        packet->trace = DUCK.dummy_duck;       
[a7d1914]516        return sizeof(duck_inf);
[da34e20]517}       
518#endif
519
[eeab9832]520static int dag_read(libtrace_t *libtrace, int block_flag) {
[7050c10]521
[56ef532]522        if (DAG.diff != 0) 
523                return DAG.diff;
524
[9e2a109]525        DAG.bottom = DAG.top;
[eeab9832]526
[9e2a109]527        DAG.top = dag_offset(
528                        INPUT.fd,
529                        &(DAG.bottom),
[5baec88]530                        block_flag);
[7050c10]531
[eeab9832]532        DAG.diff = DAG.top - DAG.bottom;
533
[9e2a109]534        DAG.offset = 0;
[eeab9832]535        return DAG.diff;
[4dedc28]536}
537
[0d57541]538/* FIXME: dag_read_packet shouldn't update the pointers, dag_fin_packet
539 * should do that.
540 */
[eeab9832]541static int dag_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
[4dedc28]542        int numbytes;
543        int size;
[da34e20]544        struct timeval tv;
[4dedc28]545        dag_record_t *erfptr;
[14d8a63]546
[da34e20]547        if (DUCK.last_pkt - DUCK.last_duck > DUCK.duck_freq && 
548                        DUCK.duck_freq != 0) {
549                size = dag_get_duckinfo(libtrace, packet);
550                DUCK.last_duck = DUCK.last_pkt;
551                if (size != 0) {
552                        return size;
553                }
554                /* No DUCK support, so don't waste our time anymore */
555                DUCK.duck_freq = 0;
556        }
557       
[c1db742]558        if (packet->buf_control == TRACE_CTRL_PACKET) {
559                packet->buf_control = TRACE_CTRL_EXTERNAL;
[14d8a63]560                free(packet->buffer);
561                packet->buffer = 0;
562        }
[afd0b73]563       
564        packet->type = RT_DATA_ERF;
565       
[eeab9832]566        if ((numbytes = dag_read(libtrace,0)) < 0) 
[56ef532]567                return numbytes;
[eeab9832]568        assert(numbytes>0);
[4dedc28]569
[7068467]570        /*DAG always gives us whole packets */
[eeab9832]571        erfptr = (dag_record_t *) ((char *)DAG.buf + 
[1974620]572                        (DAG.bottom + DAG.offset));
[4dedc28]573        size = ntohs(erfptr->rlen);
574
[eeab9832]575        assert( size >= dag_record_size );
576        assert( size < LIBTRACE_PACKET_BUFSIZE);
[14d8a63]577       
578        packet->buffer = erfptr;
579        packet->header = erfptr;
[6dbc47a]580        if (((dag_record_t *)packet->buffer)->flags.rxerror == 1) {
[4abd50b]581                /* rxerror means the payload is corrupt - drop it
582                 * by tweaking rlen */
[14d8a63]583                packet->payload = NULL;
[4abd50b]584                erfptr->rlen = htons(erf_get_framing_length(packet));
[14d8a63]585        } else {
[eeab9832]586                packet->payload = (char*)packet->buffer
587                        + erf_get_framing_length(packet);
[14d8a63]588        }
[4dedc28]589
[1974620]590        DAG.offset += size;
591        DAG.diff -= size;
[4dedc28]592
[da34e20]593        tv = trace_get_timeval(packet);
594        DUCK.last_pkt = tv.tv_sec;
595       
[a7d1914]596        return packet->payload ? size : erf_get_framing_length(packet);
[4dedc28]597}
[eeab9832]598
599static int dag_start_input(libtrace_t *libtrace) {
[e5c2bc4]600#ifdef DAG_VERSION_2_4
[eeab9832]601        if(dag_start(INPUT.fd) < 0) {
602                trace_set_err(libtrace,errno,"Cannot start DAG %s",
603                                libtrace->uridata);
604                return -1;
605        }
[0e9b9f8]606#else
607        if (dag_attach_stream(INPUT.fd, DAG.dagstream, 0, 0) < 0) {
608                trace_set_err(libtrace, errno, "Cannot attach DAG stream");
609                return -1;
610        }
611        if (dag_start_stream(INPUT.fd, DAG.dagstream) < 0) {
612                trace_set_err(libtrace, errno, "Cannot start DAG stream");
613                return -1;
614        }
615#endif
[eeab9832]616        /* dags appear to have a bug where if you call dag_start after
617         * calling dag_stop, and at least one packet has arrived, bad things
618         * happen.  flush the memory hole
619         */
620        while(dag_read(libtrace,1)!=0)
621                DAG.diff=0;
622        return 0;
623}
[9e3902e]624#endif
[4dedc28]625
[eeab9832]626static int erf_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
[4dedc28]627        int numbytes;
628        int size;
[7068467]629        void *buffer2 = packet->buffer;
[4dedc28]630        int rlen;
[14d8a63]631
[c1db742]632        if (!packet->buffer || packet->buf_control == TRACE_CTRL_EXTERNAL) {
[7068467]633                packet->buffer = malloc(LIBTRACE_PACKET_BUFSIZE);
[c1db742]634                packet->buf_control = TRACE_CTRL_PACKET;
[5eeba76]635                if (!packet->buffer) {
636                        trace_set_err(libtrace, errno, 
637                                        "Cannot allocate memory");
638                        return -1;
639                }
[7068467]640        }
641
[5eeba76]642       
643       
[0a6638f]644        packet->header = packet->buffer;
[afd0b73]645        packet->type = RT_DATA_ERF;
[14d8a63]646
[edb18ce]647        if ((numbytes=libtrace_io_read(INPUT.file,
[7068467]648                                        packet->buffer,
[4dedc28]649                                        dag_record_size)) == -1) {
[0ea3526]650                trace_set_err(libtrace,errno,"read(%s)",
[52f8fc2]651                                libtrace->uridata);
[4dedc28]652                return -1;
653        }
[959f88f]654        /* EOF */
[4dedc28]655        if (numbytes == 0) {
656                return 0;
657        }
[65a41fd]658
[7068467]659        rlen = ntohs(((dag_record_t *)packet->buffer)->rlen);
660        buffer2 = (char*)packet->buffer + dag_record_size;
[4dedc28]661        size = rlen - dag_record_size;
[0a6638f]662
[d304a7f]663        assert(size < LIBTRACE_PACKET_BUFSIZE);
[dc13302]664
[0f7f688]665        /* Unknown/corrupt */
[7068467]666        assert(((dag_record_t *)packet->buffer)->type < 10);
[4dedc28]667       
[7068467]668        /* read in the rest of the packet */
[edb18ce]669        if ((numbytes=libtrace_io_read(INPUT.file,
[4dedc28]670                                        buffer2,
[8f4152b]671                                        size)) != size) {
[5b4404a]672                if (numbytes==-1) {
673                        trace_set_err(libtrace,errno, "read(%s)", libtrace->uridata);
674                        return -1;
675                }
[f57715c8]676                trace_set_err(libtrace,EIO,"Truncated packet (wanted %d, got %d)", size, numbytes);
[5b4404a]677                /* Failed to read the full packet?  must be EOF */
[f57715c8]678                return -1;
[eaa5529]679        }
[7068467]680        if (((dag_record_t *)packet->buffer)->flags.rxerror == 1) {
[14d8a63]681                packet->payload = NULL;
682        } else {
[7068467]683                packet->payload = (char*)packet->buffer + erf_get_framing_length(packet);
[14d8a63]684        }
[4dedc28]685        return rlen;
686}
687
[fe76c55]688static int erf_dump_packet(libtrace_out_t *libtrace,
[0ff6ddf]689                dag_record_t *erfptr, int pad, void *buffer) {
[1fc2f6a]690        int numbytes = 0;
[0ff6ddf]691        int size;
[85a0d42]692
[edb18ce]693        if ((numbytes = libtrace_io_write(OUTPUT.file, erfptr, dag_record_size + pad)) != dag_record_size+pad) {
[0ea3526]694                trace_set_err_out(libtrace,errno,
695                                "write(%s)",libtrace->uridata);
[1974620]696                return -1;
697        }
[65a41fd]698
[0ff6ddf]699        size=ntohs(erfptr->rlen)-(dag_record_size+pad);
700        numbytes=libtrace_io_write(OUTPUT.file, buffer, size);
701        if (numbytes != size) {
[0ea3526]702                trace_set_err_out(libtrace,errno,
703                                "write(%s)",libtrace->uridata);
[0a6638f]704                return -1;
[df2dff9]705        }
[0a6638f]706        return numbytes + pad + dag_record_size;
707}
708
709static int erf_start_output(libtrace_out_t *libtrace)
710{
711        OUTPUT.file = trace_open_file_out(libtrace,
712                        OPTIONS.erf.level,
713                        OPTIONS.erf.fileflag);
714        if (!OUTPUT.file) {
715                return -1;
716        }
717        return 0;
[1974620]718}
[3a169d7]719
[cf612fa]720static bool find_compatible_linktype(libtrace_out_t *libtrace,
721                                libtrace_packet_t *packet)
[3a169d7]722{
723        /* Keep trying to simplify the packet until we can find
724         * something we can do with it */
725        do {
726                char type=libtrace_to_erf_type(trace_get_link_type(packet));
727
728                /* Success */
729                if (type != (char)-1)
730                        return true;
731
732                if (!demote_packet(packet)) {
[cf612fa]733                        trace_set_err_out(libtrace,
[3a169d7]734                                        TRACE_ERR_NO_CONVERSION,
735                                        "No erf type for packet (%i)",
736                                        trace_get_link_type(packet));
737                        return false;
738                }
739
740        } while(1);
741
742        return true;
743}
[1974620]744               
[0a6638f]745static int erf_write_packet(libtrace_out_t *libtrace, 
[cf612fa]746                libtrace_packet_t *packet) 
[0a6638f]747{
[1974620]748        int numbytes = 0;
[8f4152b]749        int pad = 0;
[14d8a63]750        dag_record_t *dag_hdr = (dag_record_t *)packet->header;
751        void *payload = packet->payload;
[1974620]752
[0a6638f]753        assert(OUTPUT.file);
[5baec88]754
[cd7eec7]755        if (!packet->header) {
[4f53786]756                /*trace_set_err_output(libtrace, TRACE_ERR_BAD_PACKET,
757                                "Packet has no header - probably an RT packet");
758                */
[cd7eec7]759                return -1;
760        }
761       
[8f4152b]762        pad = erf_get_padding(packet);
[65a41fd]763
[3e66b30]764        /* If we've had an rxerror, we have no payload to write - fix
765         * rlen to be the correct length
766         */
[d923b5a]767        /* I Think this is bogus, we should somehow figure out
768         * a way to write out the payload even if it is gibberish -- Perry */
[65a41fd]769        if (payload == NULL) {
770                dag_hdr->rlen = htons(dag_record_size + pad);
[19c6cbe]771               
[65a41fd]772        } 
773       
[85a0d42]774        if (packet->trace->format == &erf 
[e5c2bc4]775#ifdef HAVE_DAG
[85a0d42]776                        || packet->trace->format == &dag
[1974620]777#endif
[6dbc47a]778                        ) {
[1974620]779                numbytes = erf_dump_packet(libtrace,
[85a0d42]780                                (dag_record_t *)packet->header,
[8f4152b]781                                pad,
[0ff6ddf]782                                payload
[0a6638f]783                                );
[1974620]784        } else {
[fe76c55]785                dag_record_t erfhdr;
[7068467]786                /* convert format - build up a new erf header */
787                /* Timestamp */
[60e37e0]788                erfhdr.ts = bswap_host_to_le64(trace_get_erf_timestamp(packet));
789
790                /* Flags. Can't do this */
791                memset(&erfhdr.flags,1,sizeof(erfhdr.flags));
[19c6cbe]792                if (trace_get_direction(packet)!=~0U)
[60e37e0]793                        erfhdr.flags.iface = trace_get_direction(packet);
794
[cf612fa]795                if (!find_compatible_linktype(libtrace,packet))
[6c248a9]796                        return -1;
[3a169d7]797
[d923b5a]798                payload=packet->payload;
799                pad = erf_get_padding(packet);
800
[3a169d7]801                erfhdr.type = libtrace_to_erf_type(trace_get_link_type(packet));
802
[7068467]803                /* Packet length (rlen includes format overhead) */
[0ff6ddf]804                assert(trace_get_capture_length(packet)>0 
805                                && trace_get_capture_length(packet)<=65536);
806                assert(erf_get_framing_length(packet)>0 
807                                && trace_get_framing_length(packet)<=65536);
808                assert(
809                        trace_get_capture_length(packet)+erf_get_framing_length(packet)>0
810                      &&trace_get_capture_length(packet)+erf_get_framing_length(packet)<=65536);
[f57715c8]811                erfhdr.rlen = htons(trace_get_capture_length(packet) 
812                        + erf_get_framing_length(packet));
[7068467]813                /* loss counter. Can't do this */
[1974620]814                erfhdr.lctr = 0;
[bad6a93]815                /* Wire length, does not include padding! */
816                erfhdr.wlen = htons(trace_get_wire_length(packet));
[fe76c55]817
[7068467]818                /* Write it out */
[1974620]819                numbytes = erf_dump_packet(libtrace,
820                                &erfhdr,
[8f4152b]821                                pad,
[0ff6ddf]822                                payload);
[1974620]823        }
[1fc2f6a]824        return numbytes;
825}
826
[eeab9832]827static libtrace_linktype_t erf_get_link_type(const libtrace_packet_t *packet) {
[4dedc28]828        dag_record_t *erfptr = 0;
[14d8a63]829        erfptr = (dag_record_t *)packet->header;
[7068467]830        return erf_type_to_libtrace(erfptr->type);
[4dedc28]831}
832
[431548c5]833static libtrace_direction_t erf_get_direction(const libtrace_packet_t *packet) {
[4dedc28]834        dag_record_t *erfptr = 0;
[14d8a63]835        erfptr = (dag_record_t *)packet->header;
[4dedc28]836        return erfptr->flags.iface;
837}
838
[431548c5]839static libtrace_direction_t erf_set_direction(libtrace_packet_t *packet, libtrace_direction_t direction) {
[4dedc28]840        dag_record_t *erfptr = 0;
[14d8a63]841        erfptr = (dag_record_t *)packet->header;
[4dedc28]842        erfptr->flags.iface = direction;
843        return erfptr->flags.iface;
844}
845
[eeab9832]846static uint64_t erf_get_erf_timestamp(const libtrace_packet_t *packet) {
[4dedc28]847        dag_record_t *erfptr = 0;
[14d8a63]848        erfptr = (dag_record_t *)packet->header;
[60e37e0]849        return bswap_le_to_host64(erfptr->ts);
[4dedc28]850}
851
[eeab9832]852static int erf_get_capture_length(const libtrace_packet_t *packet) {
[4dedc28]853        dag_record_t *erfptr = 0;
[bad6a93]854        int caplen;
[4abd50b]855        if (packet->payload == NULL)
856                return 0; 
857       
[14d8a63]858        erfptr = (dag_record_t *)packet->header;
[bad6a93]859        caplen = ntohs(erfptr->rlen) - erf_get_framing_length(packet);
860        if (ntohs(erfptr->wlen) < caplen)
861                return ntohs(erfptr->wlen);
862
[7c8eacf]863        return (ntohs(erfptr->rlen) - erf_get_framing_length(packet));
[4dedc28]864}
865
[eeab9832]866static int erf_get_wire_length(const libtrace_packet_t *packet) {
[4dedc28]867        dag_record_t *erfptr = 0;
[14d8a63]868        erfptr = (dag_record_t *)packet->header;
[bad6a93]869        return ntohs(erfptr->wlen);
[4dedc28]870}
871
[eeab9832]872static size_t erf_set_capture_length(libtrace_packet_t *packet, size_t size) {
[4dedc28]873        dag_record_t *erfptr = 0;
874        assert(packet);
[d3b2234]875        if(size  > trace_get_capture_length(packet)) {
[7068467]876                /* can't make a packet larger */
[d3b2234]877                return trace_get_capture_length(packet);
[4dedc28]878        }
[14d8a63]879        erfptr = (dag_record_t *)packet->header;
[7c8eacf]880        erfptr->rlen = htons(size + erf_get_framing_length(packet));
[d3b2234]881        return trace_get_capture_length(packet);
[4dedc28]882}
883
[56ef532]884#ifdef HAVE_DAG
[eeab9832]885libtrace_eventobj_t trace_event_dag(libtrace_t *trace, libtrace_packet_t *packet) {
886        libtrace_eventobj_t event = {0,0,0.0,0};
[56ef532]887        int dag_fd;
888        int data;
889
[52f8fc2]890        if (trace->format->get_fd) {
[c1f2553]891                dag_fd = trace->format->get_fd(trace);
[56ef532]892        } else {
893                dag_fd = 0;
894        }
895       
896        data = dag_read(trace, DAGF_NONBLOCK);
897
898        if (data > 0) {
899                event.size = trace_read_packet(trace,packet);
900                event.type = TRACE_EVENT_PACKET;
901                return event;
902        }
903        event.type = TRACE_EVENT_SLEEP;
904        event.seconds = 0.0001;
905        return event;
906}
907#endif
908
[e5c2bc4]909#ifdef HAVE_DAG
[dd22d84]910static void dag_help() {
[fe43699]911        printf("dag format module: $Revision$\n");
912        printf("Supported input URIs:\n");
913        printf("\tdag:/dev/dagn\n");
914        printf("\n");
915        printf("\te.g.: dag:/dev/dag0\n");
916        printf("\n");
917        printf("Supported output URIs:\n");
918        printf("\tnone\n");
919        printf("\n");
[dd22d84]920}
[1974620]921#endif
922
[dd22d84]923static void erf_help() {
[fe43699]924        printf("erf format module: $Revision$\n");
925        printf("Supported input URIs:\n");
926        printf("\terf:/path/to/file\t(uncompressed)\n");
927        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
[ef55d05]928        printf("\terf:-\t(stdin, either compressed or not)\n");
[fe43699]929        printf("\terf:/path/to/socket\n");
930        printf("\n");
931        printf("\te.g.: erf:/tmp/trace\n");
932        printf("\n");
933        printf("Supported output URIs:\n");
[ef55d05]934        printf("\terf:path/to/file\t(uncompressed)\n");
935        printf("\terf:/path/to/file.gz\t(gzip-compressed)\n");
936        printf("\terf:-\t(stdout, either compressed or not)\n");
937        printf("\n");
938        printf("\te.g.: erf:/tmp/trace\n");
939        printf("\n");
940        printf("Supported output options:\n");
941        printf("\t-z\tSpecify the gzip compression, ranging from 0 (uncompressed) to 9 - defaults to 1\n");
[fe43699]942        printf("\n");
[dd22d84]943
[ef55d05]944       
[dd22d84]945}
946
[9e2a109]947static struct libtrace_format_t erf = {
[4dedc28]948        "erf",
949        "$Id$",
[6dbc47a]950        TRACE_FORMAT_ERF,
[7050c10]951        erf_init_input,                 /* init_input */       
[37195b4]952        NULL,                           /* config_input */
[65a5900]953        erf_start_input,                /* start_input */
[1fbd938]954        NULL,                           /* pause_input */
[1fc2f6a]955        erf_init_output,                /* init_output */
[91ebc50]956        erf_config_output,              /* config_output */
[0a6638f]957        erf_start_output,               /* start_output */
[7050c10]958        erf_fin_input,                  /* fin_input */
[1fc2f6a]959        erf_fin_output,                 /* fin_output */
[7050c10]960        erf_read_packet,                /* read_packet */
[eeab9832]961        NULL,                           /* fin_packet */
[1fc2f6a]962        erf_write_packet,               /* write_packet */
[7050c10]963        erf_get_link_type,              /* get_link_type */
964        erf_get_direction,              /* get_direction */
965        erf_set_direction,              /* set_direction */
966        erf_get_erf_timestamp,          /* get_erf_timestamp */
967        NULL,                           /* get_timeval */
968        NULL,                           /* get_seconds */
[0d57541]969        erf_seek_erf,                   /* seek_erf */
[1fbd938]970        NULL,                           /* seek_timeval */
971        NULL,                           /* seek_seconds */
[7050c10]972        erf_get_capture_length,         /* get_capture_length */
973        erf_get_wire_length,            /* get_wire_length */
[7c8eacf]974        erf_get_framing_length,         /* get_framing_length */
[dd22d84]975        erf_set_capture_length,         /* set_capture_length */
[4aa4615]976        NULL,                           /* get_fd */
[72bfe20]977        trace_event_trace,              /* trace_event */
[eeab9832]978        erf_help,                       /* help */
979        NULL                            /* next pointer */
[4dedc28]980};
981
[fe43699]982#ifdef HAVE_DAG
[9e2a109]983static struct libtrace_format_t dag = {
[4dedc28]984        "dag",
985        "$Id$",
[6dbc47a]986        TRACE_FORMAT_ERF,
[7050c10]987        dag_init_input,                 /* init_input */       
[cd7eec7]988        dag_config_input,               /* config_input */
[65a5900]989        dag_start_input,                /* start_input */
[eeab9832]990        dag_pause_input,                /* pause_input */
[7050c10]991        NULL,                           /* init_output */
[91ebc50]992        NULL,                           /* config_output */
[37195b4]993        NULL,                           /* start_output */
[7050c10]994        dag_fin_input,                  /* fin_input */
995        NULL,                           /* fin_output */
996        dag_read_packet,                /* read_packet */
[eeab9832]997        NULL,                           /* fin_packet */
[7050c10]998        NULL,                           /* write_packet */
999        erf_get_link_type,              /* get_link_type */
1000        erf_get_direction,              /* get_direction */
1001        erf_set_direction,              /* set_direction */
1002        erf_get_erf_timestamp,          /* get_erf_timestamp */
1003        NULL,                           /* get_timeval */
1004        NULL,                           /* get_seconds */
[6dbc47a]1005        NULL,                           /* seek_erf */
1006        NULL,                           /* seek_timeval */
1007        NULL,                           /* seek_seconds */
[7050c10]1008        erf_get_capture_length,         /* get_capture_length */
1009        erf_get_wire_length,            /* get_wire_length */
[7c8eacf]1010        erf_get_framing_length,         /* get_framing_length */
[dd22d84]1011        erf_set_capture_length,         /* set_capture_length */
[72bfe20]1012        NULL,                           /* get_fd */
[56ef532]1013        trace_event_dag,                /* trace_event */
[eeab9832]1014        dag_help,                       /* help */
1015        NULL                            /* next pointer */
[4dedc28]1016};
[fe43699]1017#endif
[4dedc28]1018
[c0cd256]1019void erf_constructor() {
[7c8eacf]1020        register_format(&erf);
[fe43699]1021#ifdef HAVE_DAG
[7c8eacf]1022        register_format(&dag);
[fe43699]1023#endif
[4dedc28]1024}
Note: See TracBrowser for help on using the repository browser.