source: lib/format_erf.c @ 8cecc7c

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

Looks like we need the get_next_record after all - for some reason dag_advance_stream doesn't deal in whole records like dag_offset did in 2.4

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