source: lib/trace.c @ d2d527f

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since d2d527f was d2d527f, checked in by Daniel Lawson <dlawson@…>, 16 years ago

bump to 2.0.18

internal gzip decompression routine

  • Property mode set to 100644
File size: 57.6 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
31
32/** @file
33 *
34 * @brief Trace file processing library
35 *
36 * @author Daniel Lawson
37 * @author Perry Lorier
38 *
39 * @internal
40 */
41#define _GNU_SOURCE
42#include "common.h"
43#include "config.h"
44#include <assert.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <netdb.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sys/stat.h>
52#include <sys/types.h>
53
54#ifdef HAVE_LIMITS_H
55#  include <limits.h>
56#endif
57
58#ifdef HAVE_SYS_LIMITS_H
59#  include <sys/limits.h>
60#endif
61
62#include <sys/socket.h>
63#include <sys/un.h>
64#include <sys/mman.h>
65#include <unistd.h>
66
67#ifdef HAVE_NET_IF_ARP_H
68#  include <net/if_arp.h>
69#endif
70
71#ifdef HAVE_NET_IF_H
72#  include <net/if.h>
73#endif
74
75#ifdef HAVE_NETINET_IN_H
76#  include <netinet/in.h>
77#endif
78
79#ifdef HAVE_NET_ETHERNET_H
80#  include <net/ethernet.h>
81#endif
82
83#ifdef HAVE_NETINET_IF_ETHER_H
84#  include <netinet/if_ether.h>
85#endif
86
87#include <time.h>
88#include <sys/ioctl.h>
89
90#ifdef HAVE_INTTYPES_H
91#  include <inttypes.h>
92#else
93#  error "Can't find inttypes.h - this needs to be fixed"
94#endif
95
96#ifdef HAVE_STDDEF_H
97#  include <stddef.h>
98#else
99# error "Can't find stddef.h - do you define ptrdiff_t elsewhere?"
100#endif
101
102#include "libtrace.h"
103#include "fifo.h"
104
105#if HAVE_PCAP_BPF_H
106#  include <pcap-bpf.h>
107#else
108#  ifdef HAVE_NET_BPF_H
109#    include <net/bpf.h>
110#  endif
111#endif
112
113#if HAVE_PCAP_H
114#  include <pcap.h>
115#  ifdef HAVE_PCAP_INT_H
116#    include <pcap-int.h>
117#  endif
118#endif
119
120#ifdef HAVE_ZLIB_H
121#  include <zlib.h>
122#endif
123
124
125#include "wag.h"
126
127#ifdef HAVE_DAG_API
128#  include "dagnew.h"
129#  include "dagapi.h"
130#else
131#  include "dagformat.h"
132#endif
133
134
135typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
136
137typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
138
139#if HAVE_BPF
140/** A type encapsulating a bpf filter
141 * This type covers the compiled bpf filter, as well as the original filter
142 * string
143 *
144 */
145struct libtrace_filter_t {
146        struct bpf_insn *filter;
147        char * filterstring;
148};
149#endif
150
151/** The information about traces that are open
152 * @internal
153 */
154struct libtrace_t {
155        format_t format;        /**< The format that this trace is in */
156        source_t sourcetype;    /**< The type (device,file, etc */
157        union {
158                /** Information about rtclients */
159                struct {
160                        char *hostname;
161                        short port;
162                } rt;
163                char *path;             /**< information for local sockets */
164                char *interface;        /**< intormation for reading of network
165                                             interfaces */
166        } conn_info;
167        /** Information about the current state of the input device */
168        union {
169                int fd;
170                FILE *file;
171#if HAVE_PCAP
172                pcap_t *pcap;
173#endif
174        } input;
175        struct fifo_t *fifo;   
176        struct {
177                void *buf; 
178                unsigned bottom;
179                unsigned top;
180                unsigned diff;
181                unsigned curr;
182                unsigned offset;
183        } dag;
184        struct {
185                void *buffer;
186                int size;
187        } packet;
188        double tdelta;
189        double trace_start_ts;
190        double real_start_ts;
191        double trace_last_ts;
192
193        double last_ts;
194        double start_ts;
195        struct {
196#define COMP_IBUF_SIZE 65536
197                void *ibuf;
198                void *cbuf;
199               
200                uint64_t ibuf_pos;
201                uint64_t cbuf_max;
202                uint64_t cbuf_pos;
203                struct fifo_t *cfifo;   
204        } comp;
205};
206
207struct trace_sll_header_t {
208        uint16_t pkttype;               /* packet type */
209        uint16_t hatype;                /* link-layer address type */
210        uint16_t halen;                 /* link-layer address length */
211        char addr[8];                   /* link-layer address */
212        uint16_t protocol;              /* protocol */
213};
214
215#ifndef PF_RULESET_NAME_SIZE
216#define PF_RULESET_NAME_SIZE 16
217#endif
218
219#ifndef IFNAMSIZ
220#define IFNAMSIZ 16
221#endif
222
223struct trace_pflog_header_t {
224        uint8_t    length;
225        sa_family_t   af;
226        uint8_t    action;
227        uint8_t    reason;
228        char       ifname[IFNAMSIZ];
229        char       ruleset[PF_RULESET_NAME_SIZE];
230        uint32_t   rulenr;
231        uint32_t   subrulenr;
232        uint8_t    dir;
233        uint8_t    pad[3];
234};
235
236
237/* forward declarations for local functions */
238
239int trace_uncompress(void * dest, size_t destLen, const void *source, size_t sourceLen);
240int trace_comp_read(struct libtrace_t *trace, void *buffer, size_t len);
241
242
243#define RP_BUFSIZE 65536
244
245#define URI_PROTO_LINE 16
246static int init_trace(struct libtrace_t **libtrace, char *uri) {
247        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
248        char *uridata = 0;                 
249        struct stat buf;
250       
251        // parse the URI to determine what sort of event we are dealing with
252       
253        // want snippet before the : to get the uri base type.
254
255        if((uridata = strchr(uri,':')) == NULL) {
256                // badly formed URI - needs a :
257                return 0;
258        }
259
260        if ((*uridata - *uri) > URI_PROTO_LINE) {
261                // badly formed URI - uri type is too long
262                return 0;
263        }
264        strncpy(scan,uri, (uridata - uri));
265
266        (*libtrace)->tdelta = 0.0;
267
268        if (!strncasecmp(scan,"erf",3)) {
269                (*libtrace)->format=ERF;
270#if HAVE_PCAP
271        } else if (!strncasecmp(scan,"pcapint",7)) {
272                (*libtrace)->format=PCAPINT;
273        } else if (!strncasecmp(scan,"pcap",4)) {
274                (*libtrace)->format=PCAP;
275#else
276        } else if (!strncasecmp(scan,"pcap",4)) { // also catches pcapint
277                fprintf(stderr,"This version of libtrace has been compiled without PCAP support\n");
278                return 0;
279#endif
280       
281#if HAVE_DAG
282        } else if (!strncasecmp(scan,"dag",3)) {
283                (*libtrace)->format=DAG;
284#else
285        } else if (!strncasecmp(scan,"dag",3)) {
286                fprintf(stderr,"This version of libtrace has been compiled without DAG support\n");
287                return 0;
288#endif
289        } else if (!strncasecmp(scan,"rtclient",7)) {
290                (*libtrace)->format=RTCLIENT;
291        } else if (!strncasecmp(scan,"wagint",6)) {
292        struct ports_t *port;
293                (*libtrace)->format=WAGINT;
294        } else if (!strncasecmp(scan,"wag",3)) {
295                (*libtrace)->format=WAG;
296        } else {
297                //badly formed URI
298                return 0;
299        }
300       
301        // push uridata past the delimiter
302        uridata++;
303       
304        // libtrace->format now contains the type of uri
305        // libtrace->uridata contains the appropriate data for this
306       
307        switch((*libtrace)->format) {
308#if HAVE_PCAP
309                case PCAPINT:
310#endif
311                case WAGINT:
312                        /* Can have uridata of the following format
313                         * eth0
314                         * etc
315                         */
316                        // We basically assume this is correct.
317                        (*libtrace)->sourcetype = INTERFACE;   
318                        (*libtrace)->conn_info.path = strdup(uridata);
319                        break;
320#if HAVE_PCAP
321                case PCAP:
322#endif
323                case ERF:
324                case WAG:
325                        /*
326                         * Can have uridata of the following format
327                         * /path/to/socket (probably not PCAP)
328                         * /path/to/file
329                         * /path/to/file.gz (not PCAP)
330                         * /dev/device (use PCAPINT)
331                         * -
332                         */
333                        if (!strncmp(uridata,"-",1)) {
334                                (*libtrace)->sourcetype = STDIN;
335                        } else {
336                                if (stat(uridata,&buf) == -1) {
337                                        perror("stat");
338                                        return 0;
339                                }
340                                if (S_ISSOCK(buf.st_mode)) {
341                                        (*libtrace)->sourcetype = SOCKET;
342                                } else if (S_ISCHR(buf.st_mode)) {
343                                        (*libtrace)->sourcetype = DEVICE;
344                                } else {
345                                        (*libtrace)->sourcetype = TRACE;
346                                }
347                                (*libtrace)->conn_info.path = strdup(uridata);
348                        }
349                        break;
350                case DAG:
351#if HAVE_DAG
352                        /*
353                         * Can have uridata of the following format:
354                         * /dev/device
355                         */
356                        if (stat(uridata,&buf) == -1) {
357                                perror("stat");
358                                return 0;
359                        }
360                        if (S_ISCHR(buf.st_mode)) {
361                                (*libtrace)->sourcetype = DEVICE;
362                        } else {
363                                fprintf(stderr,"%s isn't a valid char device, exiting\n",uridata);
364                                exit(1);
365                        }
366                        (*libtrace)->conn_info.path = strdup(uridata);
367#endif
368                        break;
369
370                case RTCLIENT:
371                        /*
372                         * Can have the uridata in the format
373                         * hostname
374                         * hostname:port
375                         */
376                        (*libtrace)->sourcetype = RT;
377                        if (strlen(uridata) == 0) {
378                                (*libtrace)->conn_info.rt.hostname = 
379                                        strdup("localhost");
380                                (*libtrace)->conn_info.rt.port = 
381                                        COLLECTOR_PORT;
382                                break;
383                        }
384                        if ((scan = strchr(uridata,':')) == NULL) {
385                                (*libtrace)->conn_info.rt.hostname = 
386                                        strdup(uridata);
387                                (*libtrace)->conn_info.rt.port = 
388                                        COLLECTOR_PORT;
389                        } else {
390                                (*libtrace)->conn_info.rt.hostname =
391                                        (char *)strndup(uridata,(scan - uridata));
392                                       
393                                (*libtrace)->conn_info.rt.port = 
394                                        atoi(++scan);                           
395                        }
396                        break;
397        }
398       
399
400        (*libtrace)->fifo = create_fifo(1048576);
401        assert( (*libtrace)->fifo);
402        //(*libtrace)->packet.buffer = 0;
403        //(*libtrace)->packet.size = 0;
404       
405        (*libtrace)->comp.ibuf = 0;
406        (*libtrace)->comp.cbuf = 0;
407        (*libtrace)->comp.cfifo = create_fifo(1048576);
408
409        return 1;
410}
411
412/** Create a trace file from a URI
413 *
414 * @returns opaque pointer to a libtrace_t
415 *
416 * Valid URI's are:
417 *  erf:/path/to/erf/file
418 *  erf:/path/to/erf/file.gz
419 *  erf:/path/to/rtclient/socket
420 *  erf:-                       (stdin)
421 *  pcapint:pcapinterface               (eg: pcapint:eth0)
422 *  pcap:/path/to/pcap/file
423 *  pcap:-
424 *  rtclient:hostname
425 *  rtclient:hostname:port
426 *  wag:-
427 *  wag:/path/to/wag/file
428 *  wag:/path/to/wag/file.gz
429 *  wag:/path/to/wag/socket
430 *  wagint:/dev/device
431 *
432 * URIs which have yet to be implemented are:
433 * dag:/dev/dagcard
434 * pcap:/path/to/pcap/socket
435 *
436 * If an error occured when attempting to open a trace, NULL is returned
437 * and an error is output to stdout.
438 */
439struct libtrace_t *trace_create(char *uri) {
440        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
441        struct hostent *he;
442        struct sockaddr_in remote;
443        struct sockaddr_un unix_sock;
444#if HAVE_PCAP
445        char errbuf[PCAP_ERRBUF_SIZE];
446#endif
447
448        if(init_trace(&libtrace,uri) == 0) {
449                return 0;
450        }
451       
452        switch(libtrace->sourcetype) {
453                case RT:
454                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
455                                perror("gethostbyname");
456                                return 0;
457                        } 
458                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
459                                perror("socket");
460                                return 0;
461                        }
462
463                        remote.sin_family = AF_INET;   
464                        remote.sin_port = htons(libtrace->conn_info.rt.port);
465                        remote.sin_addr = *((struct in_addr *)he->h_addr);
466                        bzero(&(remote.sin_zero), 8);
467
468                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
469                                                sizeof(struct sockaddr)) == -1) {
470                                perror("connect (inet)");
471                                return 0;
472                        }
473                        break;
474                case TRACE:
475#if HAVE_PCAP
476                        if (libtrace->format == PCAP) {
477                                if ((libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf)) == NULL) {
478                                        fprintf(stderr,"%s\n",errbuf);
479                                        return 0;
480                                }
481                        } else {
482#else
483                        {
484#endif
485                                // We just open files now, because we
486                                // do the decompression internally
487                                libtrace->input.file = fopen(libtrace->conn_info.path, "r");
488                        }
489                        break;
490                case STDIN:
491#if HAVE_PCAP
492                        if (libtrace->format == PCAP) {
493                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
494                        } else {
495#else
496                        {
497#endif
498#if HAVE_ZLIB
499                                libtrace->input.file = gzdopen(STDIN, "r");
500#else   
501                                libtrace->input.file = stdin;
502#endif
503                        }
504                        break;
505                case SOCKET:
506                        /* Pcap doesn't work */
507                        if (libtrace->format != PCAP) {
508                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
509                                        perror("socket");
510                                        return 0;
511                                }
512                                unix_sock.sun_family = AF_UNIX;
513                                bzero(unix_sock.sun_path,108);
514                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
515
516                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
517                                                        sizeof(struct sockaddr)) == -1) {
518                                        perror("connect (unix)");
519                                        return 0;
520                                }
521                        }
522                        break;
523                case DEVICE:
524                case INTERFACE:
525                        switch (libtrace->format) {
526#if HAVE_PCAP
527                                case PCAPINT:
528                                case PCAP:
529                                        libtrace->input.pcap = pcap_open_live(
530                                                libtrace->conn_info.path,
531                                                4096,
532                                                1,
533                                                1,
534                                                errbuf);
535                                        break;
536#endif
537                                case WAGINT:
538                                case WAG:
539                                        libtrace->input.fd = open(
540                                                libtrace->conn_info.path,
541                                                O_RDONLY);
542                                        break;
543#if HAVE_DAG
544                                case DAG:
545                                        if((libtrace->input.fd = dag_open(libtrace->conn_info.path)) < 0) {
546                                                fprintf(stderr,"Cannot open DAG %s: %m\n", libtrace->conn_info.path,errno);
547                                                exit(0);
548                                        }
549                                        if((libtrace->dag.buf = dag_mmap(libtrace->input.fd)) == MAP_FAILED) {
550                                                fprintf(stderr,"Cannot mmap DAG %s: %m\n", libtrace->conn_info.path,errno);
551                                                exit(0);
552                                        }
553                                        if(dag_start(libtrace->input.fd) < 0) {
554                                                fprintf(stderr,"Cannot start DAG %s: %m\n", libtrace->conn_info.path,errno);
555                                                exit(0);
556                                        }
557                                        break;
558#endif
559                                default:
560                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
561                                        break;
562                                       
563                        }
564                        break;
565                default:
566                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
567                        exit(0);
568               
569        }
570        return libtrace;
571}
572
573/** Close a trace file, freeing up any resources it may have been using
574 *
575 */
576void trace_destroy(struct libtrace_t *libtrace) {
577        assert(libtrace);
578#if HAVE_PCAP
579        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
580                pcap_close(libtrace->input.pcap);
581#else
582        if (0) {
583#endif
584        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
585                close(libtrace->input.fd);
586#if HAVE_DAG
587        } else if (libtrace->format == DAG) {
588                dag_stop(libtrace->input.fd);
589#endif
590        } else {
591                fclose(libtrace->input.file);   
592        }       
593        // need to free things!
594        destroy_fifo(libtrace->fifo);
595        destroy_fifo(libtrace->comp.cfifo);
596
597        if (libtrace->comp.ibuf) {
598                free(libtrace->comp.ibuf);
599                free(libtrace->comp.cbuf);
600        }
601       
602        free(libtrace);
603}
604
605static int trace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
606        int numbytes;
607        static short lctr = 0;
608        struct dag_record_t *recptr = 0;
609        int rlen;
610        assert(libtrace);
611        assert(len >= 0);
612
613        if (buffer == 0)
614                buffer = malloc(len);
615
616        while(1) {
617                switch(libtrace->sourcetype) {
618                        case SOCKET:
619                        case RT:
620
621#ifndef MSG_NOSIGNAL
622#define MSG_NOSIGNAL 0
623#endif
624                                // read from the network
625                                if ((numbytes=recv(libtrace->input.fd, 
626                                                                buffer, 
627                                                                len, 
628                                                                MSG_NOSIGNAL)) == -1) {
629                                        if (errno == EINTR) {
630                                                // ignore EINTR in case
631                                                // a caller is using signals
632                                                continue;
633                                        }
634                                        perror("recv");
635                                        return -1;
636                                }
637                                break;
638                        case DEVICE:
639                                switch(libtrace->format) {
640#if HAVE_DAG
641                                        case DAG:
642
643                                                libtrace->dag.bottom = libtrace->dag.top;
644                                                libtrace->dag.top = dag_offset(
645                                                                libtrace->input.fd,
646                                                                &(libtrace->dag.bottom),
647                                                                0);
648                                                libtrace->dag.diff = libtrace->dag.top -
649                                                        libtrace->dag.bottom;
650                                               
651                                                numbytes=libtrace->dag.diff;
652                                                libtrace->dag.offset = 0;
653                                               
654                                                break;
655#endif
656                                        default:
657                                                if ((numbytes=read(libtrace->input.fd, 
658                                                                buffer, 
659                                                                len)) == -1) {
660                                                perror("read");
661                                                return -1;
662                                                }
663                                }
664                                break;
665                        default:
666#if HAVE_ZLIB
667                                if ((numbytes=trace_comp_read(libtrace,
668                                //if ((numbytes=gzread(libtrace->input.file,
669                                                                buffer,
670                                                                len)) == -1) {
671                                        //perror("gzread");
672                                        return -1;
673                                }
674#else
675                                if ((numbytes=fread(buffer,len,1,libtrace->input.file)) == 0 ) {
676                                        if(feof(libtrace->input.file)) {
677                                                return 0;
678                                        }
679                                        if(ferror(libtrace->input.file)) {
680                                                perror("fread");
681                                                return -1;
682                                        }
683                                        return 0;
684                                }
685#endif
686                }
687                break;
688        }
689        return numbytes;
690
691}
692
693#if HAVE_PCAP
694void trace_pcap_handler(u_char *user, const struct pcap_pkthdr *pcaphdr, const u_char *pcappkt) {
695        struct libtrace_packet_t *packet = (struct libtrace_packet_t *)user;   
696        void *buffer = packet->buffer;
697        int numbytes = 0;
698       
699        memcpy(buffer,pcaphdr,sizeof(struct pcap_pkthdr));
700        numbytes = pcaphdr->len;
701        memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,numbytes);
702
703        packet->size = numbytes + sizeof(struct pcap_pkthdr);
704
705}
706#endif
707/** Read one packet from the trace into buffer
708 *
709 * @param libtrace      the libtrace opaque pointer
710 * @param packet        the packet opaque pointer
711 * @returns false if it failed to read a packet
712 *
713 */
714int trace_read_packet(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
715        int numbytes;
716        int size;
717        char buf[RP_BUFSIZE];
718#if HAVE_PCAP
719        //struct pcap_pkthdr *pcaphdr = malloc(sizeof(struct pcap_pkthdr));
720        const u_char *pcappkt;
721        int pcapbytes = 0;
722#endif
723        dag_record_t *erfptr;
724        int read_required = 0;
725
726        void *buffer = 0;
727        if (!libtrace) {
728                fprintf(stderr,"Oi! You called trace_read_packet() with a NULL libtrace parameter!\n");
729        }
730        assert(libtrace);
731        assert(packet);
732     
733        /* Store the trace we are reading from into the packet opaque
734         * structure */
735        packet->trace = libtrace;
736
737        buffer = packet->buffer;
738#if HAVE_PCAP
739        /* PCAP gives us it's own per-packet interface. Let's use it */
740        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
741                /* pcap_next doesn't return enough information for us
742                 * newer libpcap has pcap_next_ex, which does, but we'd
743                 * really rather have it all the time. */
744               
745                //if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
746                /*
747                if ((pcapbytes = pcap_next_ex(libtrace->input.pcap,
748                                                &pcaphdr,
749                                                &pcappkt)) < 0 ) {
750                */
751                /* Instead of pcap_next/pcap_next_ex, we do this ourselves
752                 * with a trivial callback function. This lets us
753                 * catch the same errors as pcap_next_ex, but removes
754                 * the requirement for libpcap >= 0.8.x
755                 */
756                while ((pcapbytes = pcap_dispatch(libtrace->input.pcap,
757                                                1, /* number of packets */
758                                                &trace_pcap_handler,
759                                                (u_char *)packet)) == 0);
760                       
761                if (pcapbytes < 0 ) {                   
762                        return -1;
763                }
764                return (packet->size - sizeof(struct pcap_pkthdr));
765                //memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
766                //numbytes = pcaphdr->len;
767                //memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,numbytes);
768       
769                //packet->size = numbytes + sizeof(struct pcap_pkthdr);
770                //return numbytes;
771        } 
772#endif
773
774        /* If we're reading from an ERF input, it's an offline trace. We can make some assumptions */
775        if (libtrace->format == ERF) {
776                void *buffer2 = buffer;
777                int rlen;
778                // read in the trace header
779                if ((numbytes=trace_comp_read(libtrace,
780                //if ((numbytes=gzread(libtrace->input.file,
781                                                buffer,
782                                                dag_record_size)) == -1) {
783                        //perror("gzread");
784                        return -1;
785                }
786                if (numbytes == 0) {
787                        return 0;
788                }
789                rlen = ntohs(((dag_record_t *)buffer)->rlen);
790                size = rlen - dag_record_size;
791                assert(size < LIBTRACE_PACKET_BUFSIZE);
792                buffer2 = buffer +  dag_record_size;
793
794                // read in the rest of the packet
795                if ((numbytes=trace_comp_read(libtrace,
796                //if ((numbytes=gzread(libtrace->input.file,
797                                                buffer2,
798                                                size)) == -1) {
799                        //perror("gzread");
800                        return -1;
801                }
802                //if ((numbytes + dag_record_size) != rlen) {
803                //      printf("read %d wanted %d\n",numbytes +dag_record_size, rlen);
804                //}
805                packet->size = rlen;
806                       
807                return rlen;
808        }
809
810#if HAVE_DAG
811        if (libtrace->format == DAG) {
812                if (libtrace->dag.diff == 0) {
813                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE)) <= 0) 
814                                return numbytes;
815                }
816                // DAG always gives us whole packets.
817
818                erfptr = (dag_record_t *) ((void *)libtrace->dag.buf + (libtrace->dag.bottom + libtrace->dag.offset));
819                size = ntohs(erfptr->rlen);
820
821                if ( size  > LIBTRACE_PACKET_BUFSIZE) {
822                        printf("%d\n",size);
823                        assert( size < LIBTRACE_PACKET_BUFSIZE);
824                }
825
826                // have to copy it out of the memory hole at this stage:
827                memcpy(packet->buffer, erfptr, size);
828
829                packet->size = size;
830                libtrace->dag.offset += size;
831                libtrace->dag.diff -= size;
832               
833                assert(libtrace->dag.diff >= 0);
834                //assert(libtrace->dag.offset <= libtrace->dag.top);
835                return (size);
836               
837        }
838#endif
839        do {
840                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
841                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE))<=0){
842                                return numbytes; 
843                        }
844                        assert(libtrace->fifo);
845                        fifo_write(libtrace->fifo,buf,numbytes);
846
847                        read_required = 0;
848                }
849
850                switch (libtrace->format) {
851                        case RTCLIENT:
852                                // only do this if we're reading from the RT interface
853                                if (fifo_out_read(libtrace->fifo, &packet->status, sizeof(int)) == 0) {
854                                        read_required = 1;
855                                        continue;
856                                }
857
858                                fifo_out_update(libtrace->fifo,sizeof(int));
859
860                                /* FALL THRU */
861                        case ERF:
862                        //case DAG:
863                                // read in the erf header
864                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
865                                        fifo_out_reset(libtrace->fifo);
866                                        read_required = 1;
867                                        continue;
868                                }
869
870                                size = ntohs(((dag_record_t *)buffer)->rlen);
871                                break;
872                        case WAG:
873                                if ((numbytes = fifo_out_read(libtrace->fifo,
874                                                                &size,
875                                                                sizeof(size))) 
876                                                                == 0) {
877                                        fifo_out_reset(libtrace->fifo);
878                                        read_required = 1;
879                                        continue;
880                                }
881                                size*=4;
882                                break;
883                        default:
884                                fprintf(stderr,"Unknown type in _read()\n");
885                                assert(0);
886                }
887
888                assert(size < LIBTRACE_PACKET_BUFSIZE);
889
890                // read in the full packet
891                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
892                        fifo_out_reset(libtrace->fifo);
893                        read_required = 1;
894                        continue;
895                }
896
897                // got in our whole packet, so...
898                fifo_out_update(libtrace->fifo,size);
899
900                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
901                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
902                } else {
903                        fifo_ack_update(libtrace->fifo,size);
904                }
905               
906                packet->size = numbytes;
907                return numbytes;
908
909        } while (1);
910}
911
912
913/** get a pointer to the link layer
914 * @param packet        a pointer to a libtrace_packet structure
915 *
916 * @returns a pointer to the link layer, or NULL if there is no link layer
917 * you should call trace_get_link_type() to find out what type of link layer this is
918 */
919void *trace_get_link(const struct libtrace_packet_t *packet) {
920        const void *ethptr = 0;
921        dag_record_t *erfptr = 0;
922        struct wag_event_t *event = (struct wag_event_t *)packet->buffer;
923        struct wag_data_event_t *data_event;
924       
925       
926        switch(packet->trace->format) {
927                case ERF:
928                case DAG:
929                case RTCLIENT:
930                        erfptr = (dag_record_t *)packet->buffer;
931                        if (erfptr->flags.rxerror == 1) {
932                                return NULL;
933                        }
934                        if (trace_get_link_type(packet)==TRACE_TYPE_ETH) 
935                                ethptr = ((uint8_t *)packet->buffer + 
936                                                dag_record_size + 2);
937                        else
938                                ethptr = ((uint8_t *)packet->buffer + 
939                                                dag_record_size + 2);
940                        break;
941#if HAVE_PCAP
942                case PCAPINT:
943                case PCAP:
944                        ethptr = (packet->buffer + sizeof(struct pcap_pkthdr));
945                        break;
946#endif
947                case WAGINT:
948                case WAG:
949                        switch (event->type) {
950                                case 0x0:
951                                        data_event = (void*)&(event->payload);
952                                        return data_event->data;
953                                default:
954                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
955                                        return NULL;
956                        }
957                       
958                default:
959                        fprintf(stderr,"Don't know this trace format\n");
960                        assert(0);
961        }
962        return (void *)ethptr;
963}
964
965/** get a pointer to the IP header (if any)
966 * @param packet        a pointer to a libtrace_packet structure
967 *
968 * @returns a pointer to the IP header, or NULL if there is not an IP packet
969 */
970struct libtrace_ip *trace_get_ip(const struct libtrace_packet_t *packet) {
971        struct libtrace_ip *ipptr = 0;
972
973        switch(trace_get_link_type(packet)) {
974                case TRACE_TYPE_80211:
975                        { 
976                               
977                                struct ieee_802_11_header *wifi = trace_get_link(packet);       
978                                if (!wifi) {
979                                        ipptr = NULL;
980                                        break;
981                                }
982
983                                // Data packet?
984                                if (wifi->type != 2) {
985                                        ipptr = NULL;
986                                }
987                                else {
988                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
989                                        if (eth->type != 0x0008) {
990                                                ipptr=NULL;
991                                        } else {
992                                                ipptr=(void*)eth->data;
993                                        }
994                                }
995                        }
996                        break;
997                case TRACE_TYPE_ETH:
998                        {
999                                struct ether_header *eth = 
1000                                        trace_get_link(packet);
1001                                if (!eth) {
1002                                        ipptr = NULL;
1003                                        break;
1004                                }
1005                                if (ntohs(eth->ether_type)!=0x0800) {
1006                                        ipptr = NULL;
1007                                }
1008                                else {
1009                                        ipptr = ((void *)eth) + 14;
1010                                }
1011                                break;
1012                        }
1013                case TRACE_TYPE_NONE:
1014                        ipptr = trace_get_link(packet);
1015                        break;
1016                case TRACE_TYPE_LINUX_SLL:
1017                        {
1018                                struct trace_sll_header_t *sll;
1019
1020                                sll = trace_get_link(packet);
1021                                if (!sll) {
1022                                        ipptr = NULL;
1023                                        break;
1024                                }
1025                                if (ntohs(sll->protocol)!=0x0800) {
1026                                        ipptr = NULL;
1027                                }
1028                                else {
1029                                        ipptr = ((void*)sll)+sizeof(*sll);
1030                                }
1031                        }
1032                        break;
1033                case TRACE_TYPE_PFLOG:
1034                        {
1035                                struct trace_pflog_header_t *pflog;
1036                                pflog = trace_get_link(packet);
1037                                if (!pflog) {
1038                                        ipptr = NULL;
1039                                        break;
1040                                }
1041                                if (pflog->af != AF_INET) {
1042                                        ipptr = NULL;
1043                                } else {
1044                                        ipptr = ((void*)pflog)+sizeof(*pflog);
1045                                }
1046                        }
1047                        break;
1048                case TRACE_TYPE_ATM:
1049                        {
1050                                struct atm_rec *atm = 
1051                                        trace_get_link(packet);
1052                                // TODO: Find out what ATM does, and return
1053                                //       NULL for non IP data
1054                                //       Presumably it uses the normal stuff
1055                                if (!atm) {
1056                                        ipptr = NULL;
1057                                        break;
1058                                }
1059                                ipptr =  (void*)&atm->pload;
1060                                break;
1061                        }
1062                default:
1063                        fprintf(stderr,"Don't understand link layer type %i in trace_get_ip()\n",
1064                                trace_get_link_type(packet));
1065                        ipptr=NULL;
1066                        break;
1067        }
1068
1069        return ipptr;
1070}
1071
1072#define SW_IP_OFFMASK 0xff1f
1073
1074/** get a pointer to the TCP header (if any)
1075 * @param packet        a pointer to a libtrace_packet structure
1076 *
1077 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
1078 */
1079struct libtrace_tcp *trace_get_tcp(const struct libtrace_packet_t *packet) {
1080        struct libtrace_tcp *tcpptr = 0;
1081        struct libtrace_ip *ipptr = 0;
1082
1083        if(!(ipptr = trace_get_ip(packet))) {
1084                return 0;
1085        }
1086        if ((ipptr->ip_p == 6) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0))  {
1087                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1088        }
1089        return tcpptr;
1090}
1091
1092/** get a pointer to the TCP header (if any) given a pointer to the IP header
1093 * @param ip            The IP header
1094 * @param[out] skipped  An output variable of the number of bytes skipped
1095 *
1096 * @returns a pointer to the TCP header, or NULL if this is not a TCP packet
1097 *
1098 * Skipped can be NULL, in which case it will be ignored by the program.
1099 */
1100struct libtrace_tcp *get_tcp_from_ip(const struct libtrace_ip *ip, int *skipped)
1101{
1102#define SW_IP_OFFMASK 0xff1f
1103        struct libtrace_tcp *tcpptr = 0;
1104
1105        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1106                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1107        }
1108
1109        if (skipped)
1110                *skipped=(ip->ip_hl*4);
1111
1112        return tcpptr;
1113}
1114
1115/** get a pointer to the UDP header (if any)
1116 * @param packet        a pointer to a libtrace_packet structure
1117 *
1118 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
1119 */
1120struct libtrace_udp *trace_get_udp(const struct libtrace_packet_t *packet) {
1121        struct libtrace_udp *udpptr = 0;
1122        struct libtrace_ip *ipptr = 0;
1123       
1124        if(!(ipptr = trace_get_ip(packet))) {
1125                return 0;
1126        }
1127        if ((ipptr->ip_p == 17) && ((ipptr->ip_off & SW_IP_OFFMASK) == 0)) {
1128                udpptr = (struct libtrace_udp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1129        }
1130
1131        return udpptr;
1132}
1133
1134/** get a pointer to the UDP header (if any) given a pointer to the IP header
1135 * @param ip            The IP header
1136 * @param[out] skipped  An output variable of the number of bytes skipped
1137 *
1138 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
1139 *
1140 * Skipped can be NULL, in which case it will be ignored by the program.
1141 */
1142struct libtrace_udp *get_udp_from_ip(const struct libtrace_ip *ip, int *skipped)
1143{
1144        struct libtrace_udp *udpptr = 0;
1145
1146        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1147                udpptr = (struct libtrace_udp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1148        }
1149
1150        if (skipped)
1151                *skipped=(ip->ip_hl*4);
1152
1153        return udpptr;
1154}
1155
1156
1157/** get a pointer to the ICMP header (if any)
1158 * @param packet        a pointer to a libtrace_packet structure
1159 *
1160 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
1161 */
1162struct libtrace_icmp *trace_get_icmp(const struct libtrace_packet_t *packet) {
1163        struct libtrace_icmp *icmpptr = 0;
1164        struct libtrace_ip *ipptr = 0;
1165       
1166        if(!(ipptr = trace_get_ip(packet))) {
1167                return 0;
1168        }
1169        if ((ipptr->ip_p == 1)&& ((ipptr->ip_off & SW_IP_OFFMASK) == 0 )){
1170                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
1171        }
1172        return icmpptr;
1173}
1174
1175/** get a pointer to the ICMP header (if any) given a pointer to the IP header
1176 * @param ip            The IP header
1177 * @param[out] skipped  An output variable of the number of bytes skipped
1178 *
1179 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
1180 *
1181 * Skipped can be NULL, in which case it will be ignored by the program.
1182 */
1183struct libtrace_icmp *get_icmp_from_ip(struct libtrace_ip *ip, int *skipped)
1184{
1185        struct libtrace_icmp *icmpptr = 0;
1186
1187        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
1188                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
1189        }
1190
1191        if (skipped)
1192                *skipped=(ip->ip_hl*4);
1193
1194        return icmpptr;
1195}
1196/** parse an ip or tcp option
1197 * @param[in,out] ptr   the pointer to the current option
1198 * @param[in,out] len   the length of the remaining buffer
1199 * @param[out] type     the type of the option
1200 * @param[out] optlen   the length of the option
1201 * @param[out] data     the data of the option
1202 *
1203 * @returns bool true if there is another option (and the fields are filled in)
1204 *               or false if this was the last option.
1205 *
1206 * This updates ptr to point to the next option after this one, and updates
1207 * len to be the number of bytes remaining in the options area.  Type is updated
1208 * to be the code of this option, and data points to the data of this option,
1209 * with optlen saying how many bytes there are.
1210 *
1211 * @note Beware of fragmented packets.
1212 * @author Perry Lorier
1213 */
1214int trace_get_next_option(unsigned char **ptr,int *len,
1215                        unsigned char *type,
1216                        unsigned char *optlen,
1217                        unsigned char **data)
1218{
1219        if (*len<=0)
1220                return 0;
1221        *type=**ptr;
1222        switch(*type) {
1223                case 0: /* End of options */
1224                        return 0;
1225                case 1: /* Pad */
1226                        (*ptr)++;
1227                        (*len)--;
1228                        return 1;
1229                default:
1230                        *optlen = *(*ptr+1);
1231                        if (*optlen<2)
1232                                return 0; // I have no idea wtf is going on
1233                                          // with these packets
1234                        (*len)-=*optlen;
1235                        (*data)=(*ptr+2);
1236                        (*ptr)+=*optlen;
1237                        if (*len<0)
1238                                return 0;
1239                        return 1;
1240        }
1241        assert(0);
1242}
1243
1244
1245/** Get the current time in DAG time format
1246 * @param packet        a pointer to a libtrace_packet structure
1247 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
1248 * past 1970-01-01, the lower 32bits are partial seconds)
1249 * @author Daniel Lawson
1250 */ 
1251uint64_t trace_get_erf_timestamp(const struct libtrace_packet_t *packet) {
1252        uint64_t timestamp = 0;
1253        dag_record_t *erfptr = 0;
1254        struct pcap_pkthdr *pcapptr = 0;
1255        struct wag_event_t *wagptr = 0;
1256        switch (packet->trace->format) {
1257                case DAG:
1258                case ERF:
1259                case RTCLIENT:
1260                        erfptr = (dag_record_t *)packet->buffer;
1261                        timestamp = erfptr->ts;
1262                        break;
1263#if HAVE_PCAP
1264                case PCAPINT:
1265                case PCAP:
1266                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1267                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
1268                                (((uint64_t)pcapptr->ts.tv_usec*UINT_MAX)/1000000));
1269                        break;
1270#endif
1271                case WAGINT:
1272                case WAG:
1273                        wagptr = (struct wag_event_t *)packet->buffer;
1274                        timestamp = wagptr->timestamp_lo;
1275                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
1276                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
1277                                  | ((timestamp/44000000)<<32);
1278                        break;
1279                default:
1280                        fprintf(stderr,"Unknown format in trace_get_erf_timestamp\n");
1281                        timestamp = 0;
1282        }
1283        return timestamp;
1284}
1285
1286/** Get the current time in struct timeval
1287 * @param packet        a pointer to a libtrace_packet structure
1288 *
1289 * @returns time that this packet was seen in a struct timeval
1290 * @author Daniel Lawson
1291 * @author Perry Lorier
1292 */ 
1293struct timeval trace_get_timeval(const struct libtrace_packet_t *packet) {
1294        struct timeval tv;
1295#if HAVE_PCAP
1296        struct pcap_pkthdr *pcapptr = 0;
1297#endif
1298        uint64_t ts;
1299        //uint32_t seconds;
1300        switch (packet->trace->format) {
1301#if HAVE_PCAP
1302                case PCAPINT:
1303                case PCAP:
1304                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1305                        // ick. FIXME
1306                        tv = pcapptr->ts;
1307                        break;
1308#endif
1309                case WAGINT:
1310                case WAG:
1311                case DAG:
1312                case ERF:
1313                case RTCLIENT:
1314                default:
1315                        // FIXME: This isn't portable to big-endian machines
1316                        ts = trace_get_erf_timestamp(packet);
1317#if __BYTE_ORDER == __BIG_ENDIAN
1318                        tv.tv_sec = ts & 0xFFFFFFFF;
1319#elif __BYTE_ORDER == __LITTLE_ENDIAN
1320                        tv.tv_sec = ts >> 32;
1321#else
1322#error "What on earth are you running this on?"
1323#endif
1324                        ts = (1000000 * (ts & 0xffffffffULL));
1325                        ts += (ts & 0x80000000ULL) << 1;
1326                        tv.tv_usec = ts >> 32;
1327                        if (tv.tv_usec >= 1000000) {
1328                                tv.tv_usec -= 1000000;
1329                                tv.tv_sec += 1;
1330                        }
1331                        break;
1332        }
1333        return tv;
1334}
1335
1336/** Get the current time in floating point seconds
1337 * @param packet        a pointer to a libtrace_packet structure
1338 * @returns time that this packet was seen in 64bit floating point seconds
1339 * @author Perry Lorier
1340 */ 
1341double trace_get_seconds(const struct libtrace_packet_t *packet) {
1342        uint64_t ts;
1343        ts = trace_get_erf_timestamp(packet);
1344        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
1345}
1346
1347/** Get the size of the packet in the trace
1348 * @param packet the packet opaque pointer
1349 * @returns the size of the packet in the trace
1350 * @author Perry Lorier
1351 * @note Due to this being a header capture, or anonymisation, this may not
1352 * be the same size as the original packet.  See trace_get_wire_length() for the
1353 * original size of the packet.
1354 * @note This can (and often is) different for different packets in a trace!
1355 * @par
1356 *  This is sometimes called the "snaplen".
1357 */ 
1358int trace_get_capture_length(const struct libtrace_packet_t *packet) {
1359        dag_record_t *erfptr = 0;
1360#if HAVE_PCAP
1361        struct pcap_pkthdr *pcapptr = 0;
1362#endif
1363        struct wag_event_t *wag_event;
1364        switch (packet->trace->format) {
1365                case DAG:
1366                case ERF:
1367                case RTCLIENT:
1368                        erfptr = (dag_record_t *)packet->buffer;
1369                        return ntohs(erfptr->rlen);
1370#if HAVE_PCAP
1371                case PCAPINT:
1372                case PCAP:
1373                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1374                        //return ntohs(pcapptr->caplen);
1375                        return pcapptr->caplen;
1376#endif
1377                case WAGINT:
1378                case WAG:
1379                        wag_event = (struct wag_event_t *)packet->buffer;
1380                        switch(wag_event->type) {
1381                                case 0:
1382                                        return wag_event->length*4-(
1383                                                sizeof(struct wag_event_t)+
1384                                                sizeof(struct wag_data_event_t)
1385                                                );
1386                                default:
1387                                        assert(0);
1388                        }
1389                default:
1390                        assert(0);
1391        }
1392        return -1;
1393}
1394       
1395/** Get the size of the packet as it was seen on the wire.
1396 * @param packet        a pointer to a libtrace_packet structure
1397 *
1398 * @returns the size of the packet as it was on the wire.
1399 * @author Perry Lorier
1400 * @author Daniel Lawson
1401 * @note Due to the trace being a header capture, or anonymisation this may
1402 * not be the same as the Capture Len.
1403 */ 
1404int trace_get_wire_length(const struct libtrace_packet_t *packet){
1405        dag_record_t *erfptr = 0;
1406#if HAVE_PCAP
1407        struct pcap_pkthdr *pcapptr = 0;
1408#endif
1409        struct wag_event_t *wag_event = 0;
1410        switch (packet->trace->format) {
1411                case DAG:
1412                case ERF:
1413                case RTCLIENT:
1414                        erfptr = (dag_record_t *)packet->buffer;
1415                        return ntohs(erfptr->wlen);
1416                        break;
1417#if HAVE_PCAP
1418                case PCAPINT:
1419                case PCAP:
1420                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1421                        return ntohs(pcapptr->len);
1422                        break;
1423#endif
1424                case WAGINT:
1425                case WAG:
1426                        wag_event = (struct wag_event_t *)packet->buffer;
1427                        switch(wag_event->type) {
1428                                case 0:
1429                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
1430                                default:
1431                                        assert(0);
1432                        }
1433        }
1434        return -1;
1435
1436}
1437
1438/** Get the type of the link layer
1439 * @param packet        a pointer to a libtrace_packet structure
1440 * @returns libtrace_linktype_t
1441 * @author Perry Lorier
1442 * @author Daniel Lawson
1443 */
1444libtrace_linktype_t trace_get_link_type(const struct libtrace_packet_t *packet ) {
1445        dag_record_t *erfptr = 0;
1446#if HAVE_PCAP
1447        struct pcap_pkthdr *pcapptr = 0;
1448#endif
1449        int linktype = 0;
1450        switch (packet->trace->format) {
1451                case DAG:
1452                case ERF:
1453                case RTCLIENT:
1454                        erfptr = (dag_record_t *)packet->buffer;
1455                        switch (erfptr->type) {
1456                                case TYPE_ETH: return TRACE_TYPE_ETH;
1457                                case TYPE_ATM: return TRACE_TYPE_ATM;
1458                                default: assert(0);
1459                        }
1460                        return erfptr->type;
1461                       
1462                        break;
1463#if HAVE_PCAP
1464                case PCAPINT:
1465                case PCAP:
1466                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1467                        linktype = pcap_datalink(packet->trace->input.pcap);
1468                        switch (linktype) {
1469                                case DLT_NULL:
1470                                        return TRACE_TYPE_NONE;
1471                                case DLT_EN10MB:
1472                                        return TRACE_TYPE_ETH; 
1473                                case DLT_ATM_RFC1483:
1474                                        return TRACE_TYPE_ATM;
1475                                case DLT_IEEE802_11:
1476                                        return TRACE_TYPE_80211;
1477#ifdef DLT_LINUX_SLL
1478                                case DLT_LINUX_SLL:
1479                                        return TRACE_TYPE_LINUX_SLL;
1480#endif
1481#ifdef DLT_PFLOG
1482                                case DLT_PFLOG:
1483                                        return TRACE_TYPE_PFLOG;
1484#endif
1485                        }
1486                        break;
1487#endif
1488                case WAGINT:
1489                case WAG:
1490                        return TRACE_TYPE_80211;
1491        }
1492        return -1;
1493}
1494
1495/** Get the source MAC addres
1496 * @param packet        a pointer to a libtrace_packet structure
1497 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
1498 * @author Perry Lorier
1499 */
1500uint8_t *trace_get_source_mac(const struct libtrace_packet_t *packet) {
1501        void *link = trace_get_link(packet);
1502        struct ieee_802_11_header *wifi = link;
1503        struct ether_header *ethptr = link;
1504        if (!link)
1505                return NULL;
1506        switch (trace_get_link_type(packet)) {
1507                case TRACE_TYPE_80211:
1508                        return (uint8_t*)&wifi->mac2;
1509                case TRACE_TYPE_ETH:
1510                        return (uint8_t*)&ethptr->ether_shost;
1511                default:
1512                        fprintf(stderr,"Not implemented\n");
1513                        assert(0);
1514        }
1515}
1516
1517/** Get the destination MAC addres
1518 * @param packet a libtrace_packet pointer
1519 * @returns a pointer to the destination mac, (or NULL if there is no
1520 * destination MAC)
1521 * @author Perry Lorier
1522 */
1523uint8_t *trace_get_destination_mac(const struct libtrace_packet_t *packet) {
1524        void *link = trace_get_link(packet);
1525        struct ieee_802_11_header *wifi = link;
1526        struct ether_header *ethptr = link;
1527        if (!link)
1528                return NULL;
1529        switch (trace_get_link_type(packet)) {
1530                case TRACE_TYPE_80211:
1531                        return (uint8_t*)&wifi->mac1;
1532                case TRACE_TYPE_ETH:
1533                        return (uint8_t*)&ethptr->ether_dhost;
1534                default:
1535                        fprintf(stderr,"Not implemented\n");
1536                        assert(0);
1537        }
1538}
1539
1540
1541/** process a libtrace event
1542 * @param trace the libtrace opaque pointer
1543 * @param packet the libtrace_packet opaque pointer
1544 * @returns
1545 *  TRACE_EVENT_IOWAIT  Waiting on I/O on fd
1546 *  TRACE_EVENT_SLEEP   Next event in seconds
1547 *  TRACE_EVENT_PACKET  Packet arrived in buffer with size size
1548 *  TRACE_EVENT_TERMINATE Trace terminated (perhaps with an error condition)
1549 * FIXME currently keeps a copy of the packet inside the trace pointer,
1550 * which in turn is stored inside the new packet object...
1551 * @author Perry Lorier
1552 */
1553struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
1554                struct libtrace_packet_t *packet) {
1555        struct libtrace_eventobj_t event;
1556
1557        if (!trace) {
1558                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
1559        }
1560        assert(trace);
1561        assert(packet);
1562
1563        /* Store the trace we are reading from into the packet opaque
1564         * structure */
1565        packet->trace = trace;
1566
1567        /* Is there a packet ready? */
1568        switch (trace->sourcetype) {
1569#if HAVE_PCAP
1570                case INTERFACE:
1571                        {
1572                                int data;
1573                                event.fd = pcap_fileno(trace->input.pcap);
1574                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1575                                        perror("ioctl(FIONREAD)");
1576                                }
1577                                if (data>0) {
1578                                        event.size = trace_read_packet(trace,packet);
1579                                        event.type = TRACE_EVENT_PACKET;
1580                                        return event;
1581                                }
1582                                event.type = TRACE_EVENT_IOWAIT;
1583                                return event;
1584                        }
1585#endif
1586                case SOCKET:
1587                case DEVICE:
1588                case RT:
1589                        {
1590                                int data;
1591                                event.fd = trace->input.fd;
1592                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1593                                        perror("ioctl(FIONREAD)");
1594                                }
1595                                if (data>0) {
1596                                        event.size = trace_read_packet(trace,packet);
1597                                        event.type = TRACE_EVENT_PACKET;
1598                                        return event;
1599                                }
1600                                event.type = TRACE_EVENT_IOWAIT;
1601                                return event;
1602                        }
1603                case STDIN:
1604                case TRACE:
1605                        {
1606                                double ts;
1607                                double now;
1608                                struct timeval stv;
1609                                /* "Prime" the pump */
1610                                if (!trace->packet.buffer) {
1611                                        trace->packet.buffer = malloc(4096);
1612                                        trace->packet.size=
1613                                                trace_read_packet(trace,packet);
1614                                        event.size = trace->packet.size;
1615                                        if (trace->packet.size > 0 ) {
1616                                                memcpy(trace->packet.buffer,packet->buffer,trace->packet.size);
1617                                        } else {
1618                                                // return here, the test for event.size will sort out the error
1619                                                event.type = TRACE_EVENT_PACKET;
1620                                                return event;
1621                                        }
1622                                }
1623
1624                                ts=trace_get_seconds(packet);
1625                                if (trace->tdelta!=0) {
1626                                        // Get the adjusted current time
1627                                        gettimeofday(&stv, NULL);
1628                                        now = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1629                                        now -= trace->tdelta; // adjust for trace delta
1630                                       
1631                                       
1632                                        // if the trace timestamp is still in the future,
1633                                        // return a SLEEP event, otherwise fire the packet
1634                                        if (ts > now) {
1635                                                event.seconds = ts - trace->trace_last_ts;
1636                                                event.type = TRACE_EVENT_SLEEP;
1637                                                return event;
1638                                        }
1639                                } else {
1640                                        gettimeofday(&stv, NULL);
1641                                        // work out the difference between the start of trace replay,
1642                                        // and the first packet in the trace
1643                                        trace->tdelta = stv.tv_sec + ((double)stv.tv_usec / 1000000.0);
1644                                        trace->tdelta -= ts;
1645
1646                                }
1647                               
1648                                        // This is the first packet, so just fire away.
1649                                packet->size = trace->packet.size;
1650                                memcpy(packet->buffer,trace->packet.buffer,trace->packet.size);
1651
1652                                free(trace->packet.buffer);
1653                                trace->packet.buffer = 0;
1654                                event.type = TRACE_EVENT_PACKET;
1655                               
1656                                trace->trace_last_ts = ts;
1657
1658                                return event;
1659                        }
1660                default:
1661                        assert(0);
1662        }
1663        assert(0);
1664}
1665
1666/** setup a BPF filter
1667 * @param filterstring a char * containing the bpf filter string
1668 * @returns opaque pointer pointer to a libtrace_filter_t object
1669 * @author Daniel Lawson
1670 */
1671struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
1672#if HAVE_BPF
1673        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1674        filter->filterstring = strdup(filterstring);
1675        filter->filter = 0;
1676        return filter;
1677#else
1678        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1679        return 0;
1680#endif
1681}
1682
1683/** apply a BPF filter
1684 * @param filter the filter opaque pointer
1685 * @param packet the packet opaque pointer
1686 * @returns 0 if the filter fails, 1 if it succeeds
1687 * @author Daniel Lawson
1688 */
1689int trace_bpf_filter(struct libtrace_filter_t *filter,
1690                        const struct libtrace_packet_t *packet) {
1691#if HAVE_BPF
1692        void *linkptr = 0;
1693        int clen = 0;
1694        assert(filter);
1695        assert(packet);
1696        linkptr = trace_get_link(packet);
1697        if (!linkptr) {
1698                return 0;
1699        }
1700       
1701        clen = trace_get_capture_length(packet);
1702       
1703
1704        if (filter->filterstring && ! filter->filter) {
1705                pcap_t *pcap;
1706                struct bpf_program bpfprog;
1707
1708                switch (trace_get_link_type(packet)) {
1709                        case TRACE_TYPE_ETH:
1710                                pcap = (pcap_t *)pcap_open_dead(DLT_EN10MB, 1500);
1711                                break;
1712#ifdef DLT_LINUX_SLL
1713                        case TRACE_TYPE_LINUX_SLL:
1714                                pcap = (pcap_t *)pcap_open_dead(DLT_LINUX_SLL, 1500);
1715                                break;
1716#endif
1717#ifdef DLT_PFLOG
1718                        case TRACE_TYPE_PFLOG:
1719                                pcap = (pcap_t *)pcap_open_dead(DLT_PFLOG, 1500);
1720                                break;
1721#endif
1722                        default:
1723                                printf("only works for ETH and LINUX_SLL (ppp) at the moment\n");
1724                                assert(0);
1725                }               
1726
1727                // build filter
1728                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1729                        printf("bpf compilation error: %s: %s\n", 
1730                                pcap_geterr(pcap),filter->filterstring);
1731                        assert(0);
1732                }
1733                pcap_close(pcap);
1734                filter->filter = bpfprog.bf_insns;     
1735        }
1736
1737        assert(filter->filter);
1738        return bpf_filter(filter->filter, linkptr, clen, clen);
1739#else
1740        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1741        return 0;
1742#endif
1743}
1744
1745/** Set the direction flag, if it has one
1746 * @param packet the packet opaque pointer
1747 * @param direction the new direction (0,1,2,3)
1748 * @returns a signed value containing the direction flag, or -1 if this is not supported
1749 * @author Daniel Lawson
1750 */
1751int8_t trace_set_direction(struct libtrace_packet_t *packet, int8_t direction) {
1752       
1753        dag_record_t *erfptr = 0;
1754        assert(packet);
1755
1756        switch(packet->trace->format) {
1757                case DAG:
1758                case ERF:
1759                case RTCLIENT:
1760                        erfptr = (dag_record_t *)packet->buffer;
1761                        erfptr->flags.iface = direction;
1762                        break;
1763                default:
1764                        direction = -1;
1765        }
1766       
1767        return direction;
1768       
1769       
1770}
1771
1772/** Get the direction flag, if it has one
1773 * @param packet a pointer to a libtrace_packet structure
1774 * @returns a signed value containing the direction flag, or -1 if this is not supported
1775 * The direction is defined as 0 for packets originating locally (ie, outbound)
1776 * and 1 for packets originating remotely (ie, inbound).
1777 * Other values are possible, which might be overloaded to mean special things
1778 * for a special trace.
1779 * @author Daniel Lawson
1780 */
1781int8_t trace_get_direction(const struct libtrace_packet_t *packet) {
1782       
1783        int8_t direction;
1784        dag_record_t *erfptr = 0;
1785        assert(packet);
1786        direction = -1;
1787
1788        switch(packet->trace->format) {
1789                case DAG:
1790                case ERF:
1791                case RTCLIENT:
1792                        erfptr = (dag_record_t *)packet->buffer;
1793                        direction = erfptr->flags.iface;
1794                        break;
1795                case PCAP:
1796                case PCAPINT:
1797                        switch (trace_get_link_type(packet)) {
1798                                case TRACE_TYPE_LINUX_SLL:
1799                                {
1800                                        struct trace_sll_header_t *sll;
1801                                        sll = trace_get_link(packet);
1802                                        if (!sll) {
1803                                                return -1;
1804                                        }
1805                                        /* 0 == LINUX_SLL_HOST */
1806                                        /* the Waikato Capture point defines "packets
1807                                         * originating locally" (ie, outbound), with a
1808                                         * direction of 0, and "packets destined locally"
1809                                         * (ie, inbound), with a direction of 1.
1810                                         * This is kind-of-opposite to LINUX_SLL.
1811                                         * We return consistent values here, however
1812                                         *
1813                                         * Note that in recent versions of pcap, you can
1814                                         * use "inbound" and "outbound" on ppp in linux
1815                                         */
1816                                        if (ntohs(sll->pkttype==0)) {
1817
1818                                                direction = 1;
1819                                        }
1820                                        else {
1821                                                direction = 0;
1822                                        }
1823                                        break;
1824                                }
1825                                case TRACE_TYPE_PFLOG:
1826                                {
1827                                        struct trace_pflog_header_t *pflog;
1828                                        pflog = trace_get_link(packet);
1829                                        if (!pflog) {
1830                                                return -1;
1831                                        }
1832                                        /* enum    { PF_IN=0, PF_OUT=1 }; */
1833                                        if (ntohs(pflog->dir==0)) {
1834
1835                                                direction = 1;
1836                                        }
1837                                        else {
1838                                                direction = 0;
1839                                        }
1840                                        break;
1841                                }
1842                                default:
1843                                        /* pass */
1844                                        break;
1845                        }
1846                default:
1847                        /* pass */
1848                        break;
1849        }
1850       
1851        return direction;
1852       
1853       
1854}
1855
1856struct ports_t {
1857        uint16_t src;
1858        uint16_t dst;
1859};
1860
1861/* Return the client port
1862 */
1863uint16_t trace_get_source_port(const struct libtrace_packet_t *packet)
1864{
1865        struct libtrace_ip *ip = trace_get_ip(packet);
1866        struct ports_t *port;
1867        if (6 != ip->ip_p
1868          && 17 != ip->ip_p)
1869                return 0;
1870        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1871                return 0;
1872
1873        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1874
1875        return htons(port->src);
1876}
1877
1878/* Same as get_source_port except use the destination port */
1879uint16_t trace_get_destination_port(const struct libtrace_packet_t *packet)
1880{
1881        struct libtrace_ip *ip = trace_get_ip(packet);
1882        struct ports_t *port;
1883
1884        if (6 != ip->ip_p
1885          && 17 != ip->ip_p)
1886                return 0;
1887
1888        if (0 != (ip->ip_off & SW_IP_OFFMASK))
1889                return 0;
1890
1891        port = (struct ports_t *)((ptrdiff_t)ip + (ip->ip_hl * 4));
1892
1893        return htons(port->dst);
1894}
1895
1896#define ROOT_SERVER(x) ((x) < 512)
1897#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1898#define NONROOT_SERVER(x) ((x) >= 5000)
1899#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1900#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1901#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1902#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1903
1904/* Attempt to deduce the 'server' port
1905 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1906 * @param source the TCP or UDP source port
1907 * @param dest the TCP or UDP destination port
1908 * @returns a hint as to which port is the server port
1909 * @author Daniel Lawson
1910 */
1911int8_t trace_get_server_port(uint8_t protocol, uint16_t source, uint16_t dest) {
1912        /*
1913         * * If the ports are equal, return DEST
1914         * * Check for well-known ports in the given protocol
1915         * * Root server ports: 0 - 511
1916         * * Root client ports: 512 - 1023
1917         * * non-root client ports: 1024 - 4999
1918         * * non-root server ports: 5000+
1919         * * Check for static ranges: 1024 - 49151
1920         * * Check for dynamic ranges: 49152 - 65535
1921         * * flip a coin.
1922         */
1923
1924        uint16_t server, client;
1925
1926        /* equal */
1927        if (source == client)
1928                return USE_DEST;
1929
1930        /* root server port, 0 - 511 */
1931        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1932                if (source < dest)
1933                        return USE_SOURCE;
1934                return USE_DEST;
1935        }
1936
1937        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1938                return USE_SOURCE;
1939        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1940                return USE_DEST;
1941
1942        /* non-root server */
1943        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1944                if (source < dest)
1945                        return USE_SOURCE;
1946                return USE_DEST;
1947        }
1948        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1949                return USE_SOURCE;
1950        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1951                return USE_DEST;
1952
1953        /* root client */
1954        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1955                if (source < dest)
1956                        return USE_SOURCE;
1957                return USE_DEST;
1958        }
1959        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1960                /* prefer root-client over nonroot-client */
1961                if (NONROOT_CLIENT(dest))
1962                        return USE_SOURCE;
1963                return USE_DEST;
1964        }
1965        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1966                /* prefer root-client over nonroot-client */
1967                if (NONROOT_CLIENT(source))
1968                        return USE_DEST;
1969                return USE_SOURCE;
1970        }
1971       
1972        /* nonroot client */
1973        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1974                if (source < dest) 
1975                        return USE_SOURCE;
1976                return USE_DEST;
1977        }
1978        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1979                return USE_DEST;
1980        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1981                return USE_SOURCE;
1982
1983        /* dynamic range */
1984        if (DYNAMIC(source) && DYNAMIC(dest))
1985                if (source < dest)
1986                        return USE_SOURCE;
1987                return USE_DEST;
1988        if (DYNAMIC(source) && !DYNAMIC(dest))
1989                return USE_DEST;
1990        if (!DYNAMIC(source) && DYNAMIC(dest))
1991                return USE_SOURCE;
1992        /*
1993        if (SERVER(source) && CLIENT(dest))
1994                return USE_SOURCE;
1995       
1996        if (SERVER(dest) && CLIENT(source))
1997                return USE_DEST;
1998        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1999                return USE_SOURCE;
2000        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
2001                return USE_DEST;
2002        */
2003        // failing that test...
2004        if (source < dest) {
2005                return USE_SOURCE;
2006        } 
2007        return USE_DEST;
2008       
2009}
2010
2011/** Truncate the packet at the suggested length
2012 * @param packet        the packet opaque pointer
2013 * @param size          the new length of the packet
2014 * @returns the new length of the packet, or the original length of the
2015 * packet if unchanged
2016 * NOTE: len refers to the network-level payload of the packet, and not
2017 * any capture headers included as well. For example, to truncate a packet
2018 * after the IP header, set scan to sizeof(ethernet_header) + sizeof(ip_header)
2019 * @author Daniel Lawson
2020 */
2021size_t trace_truncate_packet(struct libtrace_packet_t *packet, size_t size) {
2022        dag_record_t *erfptr;
2023#if HAVE_PCAP
2024        struct pcap_pkthdr *pcaphdr;
2025#endif
2026
2027        assert(packet);
2028
2029        if (size > packet->size) {
2030                // can't make a packet larger
2031                return packet->size;
2032        }
2033        switch (packet->trace->format) {
2034#if HAVE_PCAP
2035                case PCAPINT:
2036                case PCAP:
2037                        pcaphdr = (struct pcap_pkthdr *)packet->buffer;
2038                        pcaphdr->caplen = size + sizeof(struct pcap_pkthdr);
2039                        packet->size = pcaphdr->caplen;
2040                        break;
2041#endif
2042                case ERF:
2043                case DAG:
2044                case RTCLIENT:
2045                        erfptr = (dag_record_t *)packet->buffer;
2046                        erfptr->rlen = ntohs(size + sizeof(dag_record_t));
2047                        packet->size = size + sizeof(dag_record_t);
2048                        break;
2049                case WAGINT:
2050                case WAG:
2051                        // don't know how to do this?
2052                        break;
2053        }
2054        return packet->size;
2055}
2056
2057//#ifdef HAVE_ZLIB
2058/* uncompr.c -- decompress a memory buffer
2059 * Copyright (C) 1995-2003 Jean-loup Gailly.
2060 * For conditions of distribution and use, see copyright notice in zlib.h
2061 */
2062
2063
2064/* ===========================================================================
2065     Decompresses the source buffer into the destination buffer.  sourceLen is
2066   the byte length of the source buffer. Upon entry, destLen is the total
2067   size of the destination buffer, which must be large enough to hold the
2068   entire uncompressed data. (The size of the uncompressed data must have
2069   been saved previously by the compressor and transmitted to the decompressor
2070   by some mechanism outside the scope of this compression library.)
2071   Upon exit, destLen is the actual size of the compressed buffer.
2072     This function can be used to decompress a whole file at once if the
2073   input file is mmap'ed.
2074
2075     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
2076   enough memory, Z_BUF_ERROR if there was not enough room in the output
2077   buffer, or Z_DATA_ERROR if the input data was corrupted.
2078*/
2079int trace_uncompress (void *dest, size_t destLen, const void *source, size_t sourceLen)
2080{
2081    z_stream stream;
2082    int err;
2083
2084    stream.next_in = (Bytef*)source;
2085    stream.avail_in = (uInt)sourceLen;
2086    /* Check for source > 64K on 16-bit machine: */
2087    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
2088
2089    stream.next_out = dest;
2090    stream.avail_out = destLen;
2091    if ((uLong)stream.avail_out != destLen) return Z_BUF_ERROR;
2092
2093    stream.zalloc = (alloc_func)0;
2094    stream.zfree = (free_func)0;
2095
2096    err = inflateInit(&stream);
2097    if (err != Z_OK) return err;
2098
2099    err = inflate(&stream, Z_FINISH);
2100    if (err != Z_STREAM_END) {
2101        inflateEnd(&stream);
2102        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
2103            return Z_DATA_ERROR;
2104        return err;
2105    }
2106    destLen = stream.total_out;
2107
2108    err = inflateEnd(&stream);
2109    return err;
2110}
2111
2112
2113int trace_comp_read(struct libtrace_t *trace, void *buffer, size_t len) {
2114        //we want to read len bytes out of the compressed file stored in *fh.
2115        //store this in buffer, and return the number of bytes read.
2116       
2117        size_t numbytes = 0;
2118        size_t ret = 0;
2119       
2120        if (trace->comp.ibuf == 0) {
2121                trace->comp.ibuf = malloc(COMP_IBUF_SIZE);
2122                trace->comp.cbuf_max = COMP_IBUF_SIZE * 3;
2123                trace->comp.cbuf = malloc(trace->comp.cbuf_max);
2124        }
2125
2126        if (fifo_out_available(trace->comp.cfifo) < len) {
2127
2128                if ((numbytes = fread(trace->comp.ibuf, 
2129                                                COMP_IBUF_SIZE,
2130                                                1,
2131                                                trace->input.file)) == 0 ) {
2132                        if (feof(trace->input.file)) {
2133                                return 0;
2134                        }
2135                        if (ferror(trace->input.file)) {
2136                                perror("fread");
2137                                return -1;
2138                        }
2139                }
2140
2141                // attempt to uncompress. This is wrapped up so
2142                // that if the buffer is too small, it resizes
2143                // and loops until it isn't too small
2144                do {
2145                        trace->comp.cbuf_pos = trace->comp.cbuf_max;
2146                        // trace->comp.cbuf_pos is the size of the compression buffer
2147                        ret = trace_incompress(trace->comp.cbuf,
2148                                trace->comp.cbuf_pos,
2149                                trace->comp.ibuf,
2150                                COMP_IBUF_SIZE);
2151                        // trace->comp.cbuf_pos is NOW how much of the compression buffer is used;
2152                        if (ret == Z_BUF_ERROR) {
2153                                trace->comp.cbuf_max *= 2;
2154                                trace->comp.cbuf = realloc(trace->comp.cbuf,trace->comp.cbuf_max);
2155                        }
2156                } while(ret == Z_BUF_ERROR);
2157       
2158                // bad. Exit.
2159                if (ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
2160                        return -1;
2161                }
2162
2163                fifo_write(trace->comp.cfifo,trace->comp.cbuf,trace->comp.cbuf_pos);
2164        }
2165
2166        if ((numbytes = fifo_out_read(trace->comp.cfifo, buffer, len)) == 0 ) {
2167                fprintf(stderr,"Couldn't read from compressed file, bailing\n");
2168                return -1;
2169        }
2170
2171        return len;     
2172}
2173//#endif
Note: See TracBrowser for help on using the repository browser.