source: lib/trace.c @ dce95f3

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

fixed part of the conditional codepath for pcap

  • Property mode set to 100644
File size: 44.0 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 */
40#define _GNU_SOURCE
41#include "common.h"
42#include "config.h"
43#include <assert.h>
44#include <errno.h>
45#include <fcntl.h>
46#include <netdb.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <sys/stat.h>
51#include <sys/types.h>
52
53#ifdef HAVE_LIMITS_H
54#  include <limits.h>
55#endif
56
57#ifdef HAVE_SYS_LIMITS_H
58#  include <sys/limits.h>
59#endif
60
61#include <sys/socket.h>
62#include <sys/un.h>
63#include <sys/mman.h>
64#include <unistd.h>
65#include <net/ethernet.h>
66#include <time.h>
67#include <sys/ioctl.h>
68
69#ifdef HAVE_STDINT_H
70#  include <stdint.h>
71#else
72#  error "Can't find stdint.h - you need to replace this"
73#endif
74
75#ifdef HAVE_STDDEF_H
76#  include <stddef.h>
77#else
78# error "Can't find stddef.h - do you define ptrdiff_t elsewhere?"
79#endif
80
81#include "libtrace.h"
82#include "fifo.h"
83
84#define HAVE_BPF 0
85#define HAVE_PCAP 0
86#define HAVE_ZLIB 0
87#define DAGDEVICE 0
88
89#if HAVE_PCAP_BPF_H
90#  include <pcap-bpf.h>
91#  ifndef HAVE_BPF
92#    define HAVE_BPF 1
93#  endif
94#else
95#  ifdef HAVE_NET_BPF_H
96#    include <net/bpf.h>
97#    ifndef HAVE_BPF
98#      define HAVE_BPF 1
99#    endif
100#  endif
101#endif
102
103#if HAVE_PCAP_H
104#  include <pcap.h>
105#  ifndef HAVE_PCAP
106#    define HAVE_PCAP 1
107#  endif
108#endif
109
110#ifdef HAVE_ZLIB_H
111#  include <zlib.h>
112#  ifndef HAVE_ZLIB
113#    define HAVE_ZLIB 1
114#  endif
115#endif
116
117
118#include "wag.h"
119
120#ifdef HAVE_DAG_API
121#  include "dagnew.h"
122#  include "dagapi.h"
123#  ifndef DAGDEVICE
124#    define DAGDEVICE 1
125#  endif
126#else
127#  include "dagformat.h"
128#endif
129
130
131typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
132
133typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
134
135#if HAVE_BPF
136struct libtrace_filter_t {
137        struct bpf_insn *filter;
138        char * filterstring;
139};
140#endif
141
142struct libtrace_t {
143        format_t format;
144        source_t sourcetype;
145        union {
146                struct {
147                        char *hostname;
148                        short port;
149                } rt;
150                char *path;
151                char *interface;
152        } conn_info;
153        union {
154                int fd;
155#if HAVE_ZLIB
156                gzFile *file;
157#else   
158                FILE *file;
159#endif
160#if HAVE_PCAP
161                pcap_t *pcap;
162#endif
163        } input;
164        struct fifo_t *fifo;   
165        struct {
166                void *buf; 
167                unsigned bottom;
168                unsigned top;
169                unsigned diff;
170                unsigned curr;
171                unsigned offset;
172        } dag;
173        struct {
174                void *buffer;
175                int size;
176        } packet;
177        double last_ts;
178        double start_ts;
179};
180
181#define RP_BUFSIZE 65536
182
183#define URI_PROTO_LINE 16
184static int init_trace(struct libtrace_t **libtrace, char *uri) {
185        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
186        char *uridata = 0;                 
187        struct stat buf;
188       
189        // parse the URI to determine what sort of event we are dealing with
190       
191        // want snippet before the : to get the uri base type.
192
193        if((uridata = strchr(uri,':')) == NULL) {
194                // badly formed URI - needs a :
195                return 0;
196        }
197
198        if ((*uridata - *uri) > URI_PROTO_LINE) {
199                // badly formed URI - uri type is too long
200                return 0;
201        }
202        strncpy(scan,uri, (uridata - uri));
203
204        if (!strncasecmp(scan,"erf",3)) {
205                (*libtrace)->format=ERF;
206#if HAVE_PCAP
207        } else if (!strncasecmp(scan,"pcapint",7)) {
208                (*libtrace)->format=PCAPINT;
209        } else if (!strncasecmp(scan,"pcap",4)) {
210                (*libtrace)->format=PCAP;
211#else
212        } else if (!strncasecmp(scan,"pcap",4)) { // also catches pcapint
213                fprintf(stderr,"This version of libtrace has been compiled without PCAP support\n");
214                return 0;
215#endif
216       
217#ifdef DAGDEVICE
218        } else if (!strncasecmp(scan,"dag",3)) {
219                (*libtrace)->format=DAG;
220#else
221        } else if (!strncasecmp(scan,"dag",3)) {
222                fprintf(stderr,"This version of libtrace has been compiled without DAG support\n");
223                return 0;
224#endif
225        } else if (!strncasecmp(scan,"rtclient",7)) {
226                (*libtrace)->format=RTCLIENT;
227        } else if (!strncasecmp(scan,"wagint",6)) {
228                (*libtrace)->format=WAGINT;
229        } else if (!strncasecmp(scan,"wag",3)) {
230                (*libtrace)->format=WAG;
231        } else {
232                //badly formed URI
233                return 0;
234        }
235       
236        // push uridata past the delimiter
237        uridata++;
238       
239        // libtrace->format now contains the type of uri
240        // libtrace->uridata contains the appropriate data for this
241       
242        switch((*libtrace)->format) {
243#if HAVE_PCAP
244                case PCAPINT:
245#endif
246                case WAGINT:
247                        /* Can have uridata of the following format
248                         * eth0
249                         * etc
250                         */
251                        // We basically assume this is correct.
252                        (*libtrace)->sourcetype = INTERFACE;   
253                        (*libtrace)->conn_info.path = strdup(uridata);
254                        break;
255#if HAVE_PCAP
256                case PCAP:
257#endif
258                case ERF:
259                case WAG:
260                        /*
261                         * Can have uridata of the following format
262                         * /path/to/socket (probably not PCAP)
263                         * /path/to/file
264                         * /path/to/file.gz (not PCAP)
265                         * /dev/device (use PCAPINT)
266                         * -
267                         */
268                        if (!strncmp(uridata,"-",1)) {
269                                (*libtrace)->sourcetype = STDIN;
270                        } else {
271                                if (stat(uridata,&buf) == -1) {
272                                        perror("stat");
273                                        return 0;
274                                }
275                                if (S_ISSOCK(buf.st_mode)) {
276                                        (*libtrace)->sourcetype = SOCKET;
277                                } else if (S_ISCHR(buf.st_mode)) {
278                                        (*libtrace)->sourcetype = DEVICE;
279                                } else {
280                                        (*libtrace)->sourcetype = TRACE;
281                                }
282                                (*libtrace)->conn_info.path = strdup(uridata);
283                        }
284                        break;
285                case DAG:
286#ifdef DAGDEVICE
287                        /*
288                         * Can have uridata of the following format:
289                         * /dev/device
290                         */
291                        if (stat(uridata,&buf) == -1) {
292                                perror("stat");
293                                return 0;
294                        }
295                        if (S_ISCHR(buf.st_mode)) {
296                                (*libtrace)->sourcetype = DEVICE;
297                        } else {
298                                fprintf(stderr,"%s isn't a valid char device, exiting\n",uridata);
299                                exit(1);
300                        }
301                        (*libtrace)->conn_info.path = strdup(uridata);
302#endif
303                        break;
304
305                case RTCLIENT:
306                        /*
307                         * Can have the uridata in the format
308                         * hostname
309                         * hostname:port
310                         */
311                        (*libtrace)->sourcetype = RT;
312                        if (strlen(uridata) == 0) {
313                                (*libtrace)->conn_info.rt.hostname = 
314                                        strdup("localhost");
315                                (*libtrace)->conn_info.rt.port = 
316                                        COLLECTOR_PORT;
317                                break;
318                        }
319                        if ((scan = strchr(uridata,':')) == NULL) {
320                                (*libtrace)->conn_info.rt.hostname = 
321                                        strdup(uridata);
322                                (*libtrace)->conn_info.rt.port = 
323                                        COLLECTOR_PORT;
324                        } else {
325                                (*libtrace)->conn_info.rt.hostname =
326                                        (char *)strndup(uridata,(scan - uridata));
327                                       
328                                (*libtrace)->conn_info.rt.port = 
329                                        atoi(++scan);                           
330                        }
331                        break;
332        }
333       
334
335        (*libtrace)->fifo = create_fifo(1048576);
336        assert( (*libtrace)->fifo);
337        //(*libtrace)->packet.buffer = 0;
338        //(*libtrace)->packet.size = 0;
339
340        return 1;
341}
342
343/** Create a trace file from a URI
344 *
345 * @returns opaque pointer to a libtrace_t
346 *
347 * Valid URI's are:
348 *  erf:/path/to/erf/file
349 *  erf:/path/to/erf/file.gz
350 *  erf:/path/to/rtclient/socket
351 *  erf:-                       (stdin)
352 *  pcapint:pcapinterface               (eg: pcapint:eth0)
353 *  pcap:/path/to/pcap/file
354 *  pcap:-
355 *  rtclient:hostname
356 *  rtclient:hostname:port
357 *  wag:-
358 *  wag:/path/to/wag/file
359 *  wag:/path/to/wag/file.gz
360 *  wag:/path/to/wag/socket
361 *  wagint:/dev/device
362 *
363 * URIs which have yet to be implemented are:
364 * dag:/dev/dagcard
365 * pcap:/path/to/pcap/socket
366 *
367 * If an error occured when attempting to open a trace, NULL is returned
368 * and an error is output to stdout.
369 */
370struct libtrace_t *trace_create(char *uri) {
371        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
372        struct hostent *he;
373        struct sockaddr_in remote;
374        struct sockaddr_un unix_sock;
375#if HAVE_PCAP
376        char errbuf[PCAP_ERRBUF_SIZE];
377#endif
378
379        if(init_trace(&libtrace,uri) == 0) {
380                return 0;
381        }
382       
383        switch(libtrace->sourcetype) {
384                case RT:
385                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
386                                perror("gethostbyname");
387                                return 0;
388                        } 
389                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
390                                perror("socket");
391                                return 0;
392                        }
393
394                        remote.sin_family = AF_INET;   
395                        remote.sin_port = htons(libtrace->conn_info.rt.port);
396                        remote.sin_addr = *((struct in_addr *)he->h_addr);
397                        bzero(&(remote.sin_zero), 8);
398
399                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
400                                                sizeof(struct sockaddr)) == -1) {
401                                perror("connect (inet)");
402                                return 0;
403                        }
404                        break;
405                case TRACE:
406#if HAVE_PCAP
407                        if (libtrace->format == PCAP) {
408                                if ((libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf)) == NULL) {
409                                        fprintf(stderr,"%s\n",errbuf);
410                                        return 0;
411                                }
412                        } else {
413#else
414                        {
415#endif
416#if HAVE_ZLIB
417                                libtrace->input.file = gzopen(libtrace->conn_info.path, "r");
418#else
419                                libtrace->input.file = fopen(libtrace->conn_info.path, "r");
420#endif
421                        }
422                        break;
423                case STDIN:
424#if HAVE_PCAP
425                        if (libtrace->format == PCAP) {
426                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
427                        } else {
428#else
429                        {
430#endif
431#if HAVE_ZLIB
432                                libtrace->input.file = gzdopen(STDIN, "r");
433#else   
434                                libtrace->input.file = fdopen(STDIN, "r");
435#endif
436                        }
437                        break;
438                case SOCKET:
439                        /* Pcap doesn't work */
440                        if (libtrace->format != PCAP) {
441                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
442                                        perror("socket");
443                                        return 0;
444                                }
445                                unix_sock.sun_family = AF_UNIX;
446                                bzero(unix_sock.sun_path,108);
447                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
448
449                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
450                                                        sizeof(struct sockaddr)) == -1) {
451                                        perror("connect (unix)");
452                                        return 0;
453                                }
454                        }
455                        break;
456                case DEVICE:
457                case INTERFACE:
458                        switch (libtrace->format) {
459#if HAVE_PCAP
460                                case PCAPINT:
461                                case PCAP:
462                                        libtrace->input.pcap = pcap_open_live(
463                                                libtrace->conn_info.path,
464                                                4096,
465                                                1,
466                                                0,
467                                                errbuf);
468                                        break;
469#endif
470                                case WAGINT:
471                                case WAG:
472                                        libtrace->input.fd = open(
473                                                libtrace->conn_info.path,
474                                                O_RDONLY);
475                                        break;
476#ifdef DAGDEVICE
477                                case DAG:
478                                        if((libtrace->input.fd = dag_open(libtrace->conn_info.path)) < 0) {
479                                                fprintf(stderr,"Cannot open DAG %s: %m\n", libtrace->conn_info.path,errno);
480                                                exit(0);
481                                        }
482                                        if((libtrace->dag.buf = dag_mmap(libtrace->input.fd)) == MAP_FAILED) {
483                                                fprintf(stderr,"Cannot mmap DAG %s: %m\n", libtrace->conn_info.path,errno);
484                                                exit(0);
485                                        }
486                                        if(dag_start(libtrace->input.fd) < 0) {
487                                                fprintf(stderr,"Cannot start DAG %s: %m\n", libtrace->conn_info.path,errno);
488                                                exit(0);
489                                        }
490                                        break;
491#endif
492                                default:
493                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
494                                        break;
495                                       
496                        }
497                        break;
498                default:
499                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
500                        exit(0);
501               
502        }
503        return libtrace;
504}
505
506/** Close a trace file, freeing up any resources it may have been using
507 *
508 */
509void trace_destroy(struct libtrace_t *libtrace) {
510        assert(libtrace);
511#if HAVE_PCAP
512        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
513                pcap_close(libtrace->input.pcap);
514#else
515        if (0) {
516#endif
517        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
518                close(libtrace->input.fd);
519#ifdef DAGDEVICE
520        } else if (libtrace->format == DAG) {
521                dag_stop(libtrace->input.fd);
522#endif
523        } else {
524#if HAVE_ZLIB
525                gzclose(libtrace->input.file);
526#else   
527                fclose(libtrace->input.file);   
528#endif
529        }       
530        // need to free things!
531        destroy_fifo(libtrace->fifo);
532        free(libtrace);
533}
534
535static int trace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
536        int numbytes;
537        static short lctr = 0;
538        struct dag_record_t *recptr = 0;
539        int rlen;
540        assert(libtrace);
541        assert(len >= 0);
542
543        if (buffer == 0)
544                buffer = malloc(len);
545
546        while(1) {
547                switch(libtrace->sourcetype) {
548                        case SOCKET:
549                        case RT:
550                                // read from the network
551                                if ((numbytes=recv(libtrace->input.fd, 
552                                                                buffer, 
553                                                                len, 
554                                                                MSG_NOSIGNAL)) == -1) {
555                                        if (errno == EINTR) {
556                                                // ignore EINTR in case
557                                                // a caller is using signals
558                                                continue;
559                                        }
560                                        perror("recv");
561                                        return -1;
562                                }
563                                break;
564                        case DEVICE:
565                                switch(libtrace->format) {
566#ifdef DAGDEVICE
567                                        case DAG:
568
569                                                libtrace->dag.bottom = libtrace->dag.top;
570                                                libtrace->dag.top = dag_offset(
571                                                                libtrace->input.fd,
572                                                                &(libtrace->dag.bottom),
573                                                                0);
574                                                libtrace->dag.diff = libtrace->dag.top -
575                                                        libtrace->dag.bottom;
576                                               
577                                                numbytes=libtrace->dag.diff;
578                                                libtrace->dag.offset = 0;
579                                               
580                                                break;
581#endif
582                                        default:
583                                                if ((numbytes=read(libtrace->input.fd, 
584                                                                buffer, 
585                                                                len)) == -1) {
586                                                perror("read");
587                                                return -1;
588                                                }
589                                }
590                                break;
591                        default:
592#if HAVE_ZLIB
593                                if ((numbytes=gzread(libtrace->input.file,
594                                                                buffer,
595                                                                len)) == -1) {
596                                        perror("gzread");
597                                        return -1;
598                                }
599#else
600                                if ((numbytes=fread(buffer,len,1,libtrace->input.file)) == 0 ) {
601                                        if(feof(libtrace->input.file)) {
602                                                return 0;
603                                        }
604                                        if(ferror(libtrace->input.file)) {
605                                                perror("fread");
606                                                return -1;
607                                        }
608                                        return 0;
609                                }
610#endif
611                }
612                break;
613        }
614        return numbytes;
615
616}
617
618/** Read one packet from the trace into buffer
619 *
620 * @param libtrace      the libtrace opaque pointer
621 * @param packet        the packet opaque pointer
622 * @returns false if it failed to read a packet
623 *
624 */
625int trace_read_packet(struct libtrace_t *libtrace, struct libtrace_packet_t *packet) {
626        int numbytes;
627        int size;
628        char buf[RP_BUFSIZE];
629#if HAVE_PCAP
630        struct pcap_pkthdr pcaphdr;
631        const u_char *pcappkt;
632#endif
633        dag_record_t *erfptr;
634        int read_required = 0;
635
636        void *buffer = 0;
637        if (!libtrace) {
638                fprintf(stderr,"Oi! You called trace_read_packet() with a NULL libtrace parameter!\n");
639        }
640        assert(libtrace);
641        assert(packet);
642     
643        /* Store the trace we are reading from into the packet opaque
644         * structure */
645        packet->trace = libtrace;
646
647        buffer = packet->buffer;
648#if HAVE_PCAP
649        /* PCAP gives us it's own per-packet interface. Let's use it */
650        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
651                if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
652                        return -1;
653                }
654                memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
655                memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,pcaphdr.len);
656                numbytes = pcaphdr.len;
657       
658                packet->size = numbytes + sizeof(struct pcap_pkthdr);
659                return numbytes;
660        } 
661#endif
662
663        /* If we're reading from an ERF input, it's an offline trace. We can make some assumptions */
664        if (libtrace->format == ERF) {
665                void *buffer2 = buffer;
666                // read in the trace header
667                if ((numbytes=gzread(libtrace->input.file,
668                                                buffer,
669                                                sizeof(dag_record_t))) == -1) {
670                        perror("gzread");
671                        return -1;
672                }
673                if (numbytes == 0) {
674                        return 0;
675                }
676                size = ntohs(((dag_record_t *)buffer)->rlen) - sizeof(dag_record_t);
677                assert(size < LIBTRACE_PACKET_BUFSIZE);
678                buffer2 = buffer +  sizeof(dag_record_t);
679
680                // read in the rest of the packet
681                if ((numbytes=gzread(libtrace->input.file,
682                                                buffer2,
683                                                size)) == -1) {
684                        perror("gzread");
685                        return -1;
686                }
687                packet->size = numbytes + sizeof(dag_record_t);
688                return sizeof(dag_record_t) + numbytes;
689        }
690
691#ifdef DAGDEVICE
692        if (libtrace->format == DAG) {
693                if (libtrace->dag.diff == 0) {
694                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE)) <= 0) 
695                                return numbytes;
696                }
697                // DAG always gives us whole packets.
698
699                erfptr = (dag_record_t *) ((void *)libtrace->dag.buf + (libtrace->dag.bottom + libtrace->dag.offset));
700                size = ntohs(erfptr->rlen);
701
702                if ( size  > LIBTRACE_PACKET_BUFSIZE) {
703                        printf("%d\n",size);
704                        assert( size < LIBTRACE_PACKET_BUFSIZE);
705                }
706
707                // have to copy it out of the memory hole at this stage:
708                memcpy(packet->buffer, erfptr, size);
709
710                packet->size = size;
711                libtrace->dag.offset += size;
712                libtrace->dag.diff -= size;
713               
714                assert(libtrace->dag.diff >= 0);
715                //assert(libtrace->dag.offset <= libtrace->dag.top);
716                return (size);
717               
718        }
719#endif
720        do {
721                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
722                        if ((numbytes = trace_read(libtrace,buf,RP_BUFSIZE))<=0){
723                                return numbytes; 
724                        }
725                        assert(libtrace->fifo);
726                        fifo_write(libtrace->fifo,buf,numbytes);
727
728                        read_required = 0;
729                }
730
731                switch (libtrace->format) {
732                        case RTCLIENT:
733                                // only do this if we're reading from the RT interface
734                                if (fifo_out_read(libtrace->fifo, &packet->status, sizeof(int)) == 0) {
735                                        read_required = 1;
736                                        continue;
737                                }
738
739                                fifo_out_update(libtrace->fifo,sizeof(int));
740
741                                /* FALL THRU */
742                        //case ERF:
743                        //case DAG:
744                                // read in the erf header
745                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
746                                        fifo_out_reset(libtrace->fifo);
747                                        read_required = 1;
748                                        continue;
749                                }
750
751                                size = ntohs(((dag_record_t *)buffer)->rlen);
752                                break;
753                        case WAG:
754                                if ((numbytes = fifo_out_read(libtrace->fifo,
755                                                                &size,
756                                                                sizeof(size))) 
757                                                                == 0) {
758                                        fifo_out_reset(libtrace->fifo);
759                                        read_required = 1;
760                                        continue;
761                                }
762                                size*=4;
763                                break;
764                        default:
765                                fprintf(stderr,"Unknown type in _read()\n");
766                                assert(0);
767                }
768
769                assert(size < LIBTRACE_PACKET_BUFSIZE);
770
771                // read in the full packet
772                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
773                        fifo_out_reset(libtrace->fifo);
774                        read_required = 1;
775                        continue;
776                }
777
778                // got in our whole packet, so...
779                fifo_out_update(libtrace->fifo,size);
780
781                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
782                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
783                } else {
784                        fifo_ack_update(libtrace->fifo,size);
785                }
786               
787                packet->size = numbytes;
788                return numbytes;
789
790        } while (1);
791}
792
793
794/** get a pointer to the link layer
795 * @param libtrace      a pointer to the trace object returned from gettrace
796 * @param buffer        a pointer to a filled in buffer
797 * @param buflen        a pointer to the size of the buffer
798 *
799 * @returns a pointer to the link layer, or NULL if there is no link layer
800 * you should call trace_get_link_type() to find out what type of link layer this is
801 */
802void *trace_get_link(struct libtrace_packet_t *packet) {
803        void *ethptr = 0;
804       
805        struct wag_event_t *event = (struct wag_event_t *)packet->buffer;
806        struct wag_data_event_t *data_event;
807       
808       
809        switch(packet->trace->format) {
810                case ERF:
811                case DAG:
812                case RTCLIENT:
813                        if (trace_get_link_type(packet)==TRACE_TYPE_ETH) 
814                                ethptr = ((uint8_t *)packet->buffer + 
815                                                dag_record_size + 2);
816                        else
817                                ethptr = ((uint8_t *)packet->buffer + 
818                                                dag_record_size + 2);
819                        break;
820#if HAVE_PCAP
821                case PCAPINT:
822                case PCAP:
823                        ethptr = (struct ether_header *)(packet->buffer + sizeof(struct pcap_pkthdr));
824                        break;
825#endif
826                case WAGINT:
827                case WAG:
828                        switch (event->type) {
829                                case 0x0:
830                                        data_event = (void*)&(event->payload);
831                                        return data_event->data;
832                                default:
833                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
834                                        return NULL;
835                        }
836                       
837                default:
838                        fprintf(stderr,"Dunno this trace format\n");
839                        assert(0);
840        }
841        return ethptr;
842}
843
844/** get a pointer to the IP header (if any)
845 * @param libtrace      a pointer to the trace object returned from gettrace
846 * @param buffer        a pointer to a filled in buffer
847 * @param buflen        a pointer to the size of the buffer
848 *
849 * @returns a pointer to the IP header, or NULL if there is not an IP packet
850 */
851struct libtrace_ip *trace_get_ip(struct libtrace_packet_t *packet) {
852        struct libtrace_ip *ipptr = 0;
853
854        switch(trace_get_link_type(packet)) {
855                case TRACE_TYPE_80211:
856                        { 
857                               
858                                struct ieee_802_11_header *wifi = trace_get_link(packet);       
859
860                                // Data packet?
861                                if (wifi->type != 2) {
862                                        ipptr = NULL;
863                                }
864                                else {
865                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
866                                        if (eth->type != 0x0008) {
867                                                ipptr=NULL;
868                                        } else {
869                                                ipptr=(void*)eth->data;
870                                        }
871                                }
872                        }
873                        break;
874                case TRACE_TYPE_ETH:
875                        {
876                                struct ether_header *eth = 
877                                        trace_get_link(packet);
878                                if (ntohs(eth->ether_type)!=0x0800) {
879                                        ipptr = NULL;
880                                }
881                                else {
882                                        ipptr = ((void *)eth) + 14;
883                                }
884                                break;
885                        }
886                case TRACE_TYPE_ATM:
887                        {
888                                struct atm_rec *atm = 
889                                        trace_get_link(packet);
890                                // TODO: Find out what ATM does, and return
891                                //       NULL for non IP data
892                                //       Presumably it uses the normal stuff
893                                ipptr =  (void*)&atm->pload;
894                                break;
895                        }
896                default:
897                        fprintf(stderr,"Don't understand link layer type %i in trace_get_ip()\n",
898                                trace_get_link_type(packet));
899                        ipptr=NULL;
900                        break;
901        }
902
903        return ipptr;
904}
905
906
907/** get a pointer to the TCP header (if any)
908 * @param libtrace      a pointer to the trace object returned from gettrace
909 * @param buffer        a pointer to a filled in buffer
910 * @param buflen        a pointer to the size of the buffer
911 *
912 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
913 */
914struct libtrace_tcp *trace_get_tcp(struct libtrace_packet_t *packet) {
915        struct libtrace_tcp *tcpptr = 0;
916        struct libtrace_ip *ipptr = 0;
917
918        if(!(ipptr = trace_get_ip(packet))) {
919                return 0;
920        }
921        if (ipptr->ip_p == 6) {
922                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
923        }
924        return tcpptr;
925}
926
927/** get a pointer to the UDP header (if any)
928 * @param libtrace      a pointer to the trace object returned from gettrace
929 * @param buffer        a pointer to a filled in buffer
930 * @param buflen        a pointer to the size of the buffer
931 *
932 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
933 */
934struct libtrace_udp *trace_get_udp(struct libtrace_packet_t *packet) {
935        struct libtrace_udp *udpptr = 0;
936        struct libtrace_ip *ipptr = 0;
937       
938        if(!(ipptr = trace_get_ip(packet))) {
939                return 0;
940        }
941        if (ipptr->ip_p == 17) {
942                udpptr = (struct libtrace_udp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
943        }
944        return udpptr;
945}
946
947/** get a pointer to the ICMP header (if any)
948 * @param libtrace      a pointer to the trace object returned from gettrace
949 * @param buffer        a pointer to a filled in buffer
950 * @param buflen        a pointer to the size of the buffer
951 *
952 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
953 */
954struct libtrace_icmp *trace_get_icmp(struct libtrace_packet_t *packet) {
955        struct libtrace_icmp *icmpptr = 0;
956        struct libtrace_ip *ipptr = 0;
957       
958        if(!(ipptr = trace_get_ip(packet))) {
959                return 0;
960        }
961        if (ipptr->ip_p == 1) {
962                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ipptr + (ipptr->ip_hl * 4));
963        }
964        return icmpptr;
965}
966
967/** Get the current time in DAG time format
968 * @param libtrace the libtrace opaque pointer
969 * @param buffer a pointer to a filled in buffer
970 * @param buflen the length of the buffer
971 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
972 * past 1970-01-01, the lower 32bits are partial seconds)
973 * @author Daniel Lawson
974 */ 
975uint64_t trace_get_erf_timestamp(struct libtrace_packet_t *packet) {
976        uint64_t timestamp = 0;
977        dag_record_t *erfptr = 0;
978        struct pcap_pkthdr *pcapptr = 0;
979        struct wag_event_t *wagptr = 0;
980        switch (packet->trace->format) {
981                case DAG:
982                case ERF:
983                case RTCLIENT:
984                        erfptr = (dag_record_t *)packet->buffer;
985                        timestamp = erfptr->ts;
986                        break;
987#if HAVE_PCAP
988                case PCAPINT:
989                case PCAP:
990                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
991                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
992                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
993                        break;
994#endif
995                case WAGINT:
996                case WAG:
997                        wagptr = (struct wag_event_t *)packet->buffer;
998                        timestamp = wagptr->timestamp_lo;
999                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
1000                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
1001                                  | ((timestamp/44000000)<<32);
1002                        break;
1003                default:
1004                        fprintf(stderr,"Unknown format in trace_get_erf_timestamp\n");
1005                        timestamp = 0;
1006        }
1007        return timestamp;
1008}
1009
1010/** Get the current time in struct timeval
1011 * @param libtrace the libtrace opaque pointer
1012 * @param buffer a pointer to a filled in buffer
1013 * @param buflen the length of the buffer
1014 * @returns time that this packet was seen in a struct timeval
1015 * @author Daniel Lawson
1016 * @author Perry Lorier
1017 */ 
1018struct timeval trace_get_timeval(struct libtrace_packet_t *packet) {
1019        struct timeval tv;
1020#if HAVE_PCAP
1021        struct pcap_pkthdr *pcapptr = 0;
1022#endif
1023        uint64_t ts;
1024        //uint32_t seconds;
1025        switch (packet->trace->format) {
1026#if HAVE_PCAP
1027                case PCAPINT:
1028                case PCAP:
1029                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1030                        tv = pcapptr->ts;
1031                        break;
1032#endif
1033                case WAGINT:
1034                case WAG:
1035                case DAG:
1036                case ERF:
1037                case RTCLIENT:
1038                default:
1039                        // FIXME: This isn't portable to big-endian machines
1040                        ts = trace_get_erf_timestamp(packet);
1041                        tv.tv_sec = ts >> 32;           
1042                        ts = (1000000 * (ts & 0xffffffffULL));
1043                        ts += (ts & 0x80000000ULL) << 1;
1044                        tv.tv_usec = ts >> 32;
1045                        if (tv.tv_usec >= 1000000) {
1046                                tv.tv_usec -= 1000000;
1047                                tv.tv_sec += 1;
1048                        }
1049                        break;
1050        }
1051        return tv;
1052}
1053
1054/** Get the current time in floating point seconds
1055 * @param libtrace the libtrace opaque pointer
1056 * @param buffer a pointer to a filled in buffer
1057 * @param buflen the length of the buffer
1058 * @returns time that this packet was seen in 64bit floating point seconds
1059 * @author Perry Lorier
1060 */ 
1061double trace_get_seconds(struct libtrace_packet_t *packet) {
1062        uint64_t ts;
1063        ts = trace_get_erf_timestamp(packet);
1064        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
1065}
1066
1067/** Get the size of the packet in the trace
1068 * @param packet the packet opaque pointer
1069 * @returns the size of the packet in the trace
1070 * @author Perry Lorier
1071 * @note Due to this being a header capture, or anonymisation, this may not
1072 * be the same size as the original packet.  See trace_get_wire_length() for the
1073 * original size of the packet.
1074 * @note This can (and often is) different for different packets in a trace!
1075 * @par
1076 *  This is sometimes called the "snaplen".
1077 */ 
1078int trace_get_capture_length(struct libtrace_packet_t *packet) {
1079        dag_record_t *erfptr = 0;
1080#if HAVE_PCAP
1081        struct pcap_pkthdr *pcapptr = 0;
1082#endif
1083        struct wag_event_t *wag_event;
1084        switch (packet->trace->format) {
1085                case DAG:
1086                case ERF:
1087                case RTCLIENT:
1088                        erfptr = (dag_record_t *)packet->buffer;
1089                        return ntohs(erfptr->rlen);
1090#if HAVE_PCAP
1091                case PCAPINT:
1092                case PCAP:
1093                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1094                        //return ntohs(pcapptr->caplen);
1095                        return pcapptr->caplen;
1096#endif
1097                case WAGINT:
1098                case WAG:
1099                        wag_event = (struct wag_event_t *)packet->buffer;
1100                        switch(wag_event->type) {
1101                                case 0:
1102                                        return wag_event->length*4-(
1103                                                sizeof(struct wag_event_t)+
1104                                                sizeof(struct wag_data_event_t)
1105                                                );
1106                                default:
1107                                        assert(0);
1108                        }
1109                default:
1110                        assert(0);
1111        }
1112        return -1;
1113}
1114       
1115/** Get the size of the packet as it was seen on the wire.
1116 * @param libtrace the libtrace opaque pointer
1117 * @param buffer a pointer to a filled in buffer
1118 * @param buflen the length of the buffer
1119 * @returns the size of the packet as it was on the wire.
1120 * @author Perry Lorier
1121 * @author Daniel Lawson
1122 * @note Due to the trace being a header capture, or anonymisation this may
1123 * not be the same as the Capture Len.
1124 */ 
1125int trace_get_wire_length(struct libtrace_packet_t *packet){
1126        dag_record_t *erfptr = 0;
1127#if HAVE_PCAP
1128        struct pcap_pkthdr *pcapptr = 0;
1129#endif
1130        struct wag_event_t *wag_event = 0;
1131        switch (packet->trace->format) {
1132                case DAG:
1133                case ERF:
1134                case RTCLIENT:
1135                        erfptr = (dag_record_t *)packet->buffer;
1136                        return ntohs(erfptr->wlen);
1137                        break;
1138#if HAVE_PCAP
1139                case PCAPINT:
1140                case PCAP:
1141                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1142                        return ntohs(pcapptr->len);
1143                        break;
1144#endif
1145                case WAGINT:
1146                case WAG:
1147                        wag_event = (struct wag_event_t *)packet->buffer;
1148                        switch(wag_event->type) {
1149                                case 0:
1150                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
1151                                default:
1152                                        assert(0);
1153                        }
1154        }
1155        return -1;
1156
1157}
1158
1159/** Get the type of the link layer
1160 * @param libtrace the libtrace opaque pointer
1161 * @param buffer a pointer to a filled in buffer
1162 * @param buflen the length of the buffer
1163 * @returns libtrace_linktype_t
1164 * @author Perry Lorier
1165 * @author Daniel Lawson
1166 */
1167libtrace_linktype_t trace_get_link_type(struct libtrace_packet_t *packet ) {
1168        dag_record_t *erfptr = 0;
1169#if HAVE_PCAP
1170        struct pcap_pkthdr *pcapptr = 0;
1171#endif
1172        int linktype = 0;
1173        switch (packet->trace->format) {
1174                case DAG:
1175                case ERF:
1176                case RTCLIENT:
1177                        erfptr = (dag_record_t *)packet->buffer;
1178                        switch (erfptr->type) {
1179                                case TYPE_ETH: return TRACE_TYPE_ETH;
1180                                case TYPE_ATM: return TRACE_TYPE_ATM;
1181                                default: assert(0);
1182                        }
1183                        return erfptr->type;
1184                       
1185                        break;
1186#if HAVE_PCAP
1187                case PCAPINT:
1188                case PCAP:
1189                        pcapptr = (struct pcap_pkthdr *)packet->buffer;
1190                        linktype = pcap_datalink(packet->trace->input.pcap);
1191                        switch (linktype) {
1192                                case 1:
1193                                        return TRACE_TYPE_ETH; 
1194                                case 11:
1195                                        return TRACE_TYPE_ATM;
1196                                case DLT_IEEE802_11:
1197                                        return TRACE_TYPE_80211;
1198                        }
1199                        break;
1200#endif
1201                case WAGINT:
1202                case WAG:
1203                        return TRACE_TYPE_80211;
1204        }
1205        return -1;
1206}
1207
1208/** Get the source MAC addres
1209 * @param libtrace the libtrace opaque pointer
1210 * @param buffer a pointer to a filled in buffer
1211 * @param buflen the length of the buffer
1212 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
1213 * @author Perry Lorier
1214 */
1215uint8_t *trace_get_source_mac(struct libtrace_packet_t *packet) {
1216        void *link = trace_get_link(packet);
1217        struct ieee_802_11_header *wifi = link;
1218        struct ether_header *ethptr = link;
1219        if (!link)
1220                return NULL;
1221        switch (trace_get_link_type(packet)) {
1222                case TRACE_TYPE_80211:
1223                        return (uint8_t*)&wifi->mac2;
1224                case TRACE_TYPE_ETH:
1225                        return (uint8_t*)&ethptr->ether_shost;
1226                default:
1227                        fprintf(stderr,"Not implemented\n");
1228                        assert(0);
1229        }
1230}
1231
1232/** Get the destination MAC addres
1233 * @param libtrace the libtrace opaque pointer
1234 * @param buffer a pointer to a filled in buffer
1235 * @param buflen the length of the buffer
1236 * @returns a pointer to the destination mac, (or NULL if there is no
1237 * destination MAC)
1238 * @author Perry Lorier
1239 */
1240uint8_t *trace_get_destination_mac(struct libtrace_packet_t *packet) {
1241        void *link = trace_get_link(packet);
1242        struct ieee_802_11_header *wifi = link;
1243        struct ether_header *ethptr = link;
1244        if (!link)
1245                return NULL;
1246        switch (trace_get_link_type(packet)) {
1247                case TRACE_TYPE_80211:
1248                        return (uint8_t*)&wifi->mac1;
1249                case TRACE_TYPE_ETH:
1250                        return (uint8_t*)&ethptr->ether_dhost;
1251                default:
1252                        fprintf(stderr,"Not implemented\n");
1253                        assert(0);
1254        }
1255}
1256
1257
1258/** process a libtrace event
1259 * @param trace the libtrace opaque pointer
1260 * @param packet the libtrace_packet opaque pointer
1261 * @param fd a pointer to a file descriptor to listen on
1262 * @param seconds a pointer the time in seconds since to the next event
1263 * @returns
1264 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
1265 *  TRACE_EVENT_SLEEP   Next event in <seconds>
1266 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
1267 * FIXME currently keeps a copy of the packet inside the trace pointer,
1268 * which in turn is stored inside the new packet object...
1269 * @author Perry Lorier
1270 */
1271struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
1272                struct libtrace_packet_t *packet) {
1273        struct libtrace_eventobj_t event;
1274
1275        if (!trace) {
1276                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
1277        }
1278        assert(trace);
1279        assert(packet);
1280
1281        /* Store the trace we are reading from into the packet opaque
1282         * structure */
1283        packet->trace = trace;
1284
1285        /* Is there a packet ready? */
1286        switch (trace->sourcetype) {
1287#if HAVE_PCAP
1288                case INTERFACE:
1289                        {
1290                                int data;
1291                                event.fd = pcap_fileno(trace->input.pcap);
1292                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1293                                        perror("ioctl(FIONREAD)");
1294                                }
1295                                if (data>0) {
1296                                        trace_read_packet(trace,packet);
1297                                        event.type = TRACE_EVENT_PACKET;
1298                                        return event;
1299                                }
1300                                event.type = TRACE_EVENT_IOWAIT;
1301                                return event;
1302                        }
1303#endif
1304                case SOCKET:
1305                case DEVICE:
1306                case RT:
1307                        {
1308                                int data;
1309                                event.fd = trace->input.fd;
1310                                if(ioctl(event.fd,FIONREAD,&data)==-1){
1311                                        perror("ioctl(FIONREAD)");
1312                                }
1313                                if (data>0) {
1314                                        trace_read_packet(trace,packet);
1315                                        event.type = TRACE_EVENT_PACKET;
1316                                        return event;
1317                                }
1318                                event.type = TRACE_EVENT_IOWAIT;
1319                                return event;
1320                        }
1321                case STDIN:
1322                case TRACE:
1323                        {
1324                                double ts;
1325                                /* "Prime" the pump */
1326                                if (!trace->packet.buffer) {
1327                                        trace->packet.buffer = malloc(4096);
1328                                        trace->packet.size=
1329                                                trace_read_packet(trace,packet);
1330                                }
1331                                ts=trace_get_seconds(packet);
1332                                if (trace->last_ts!=0) {
1333                                        event.seconds = ts - trace->last_ts;
1334                                        if (event.seconds>time(NULL)-trace->start_ts) {
1335                                                event.type = TRACE_EVENT_SLEEP;
1336                                                return event;
1337                                        }
1338                                       
1339                                }
1340                                else {
1341                                        trace->start_ts = time(NULL);
1342                                        trace->last_ts = ts;
1343                                }
1344
1345                                packet->size = trace->packet.size;
1346                                memcpy(packet->buffer,trace->packet.buffer,trace->packet.size);
1347
1348                                free(trace->packet.buffer);
1349                                trace->packet.buffer = 0;
1350                                event.type = TRACE_EVENT_PACKET;
1351                                return event;
1352                        }
1353                default:
1354                        assert(0);
1355        }
1356        assert(0);
1357}
1358
1359/** setup a BPF filter
1360 * @param filterstring a char * containing the bpf filter string
1361 * @returns opaque pointer pointer to a libtrace_filter_t object
1362 * @author Daniel Lawson
1363 */
1364struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
1365#if HAVE_BPF
1366        struct libtrace_filter_t *filter = malloc(sizeof(struct libtrace_filter_t));
1367        filter->filterstring = strdup(filterstring);
1368        filter->filter = 0;
1369        return filter;
1370#else
1371        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1372        return 0;
1373#endif
1374}
1375
1376/** apply a BPF filter
1377 * @param libtrace the libtrace opaque pointer
1378 * @param filter the filter opaque pointer
1379 * @param buffer a pointer to a filled buffer
1380 * @param buflen the length of the buffer
1381 * @returns 0 if the filter fails, 1 if it succeeds
1382 * @author Daniel Lawson
1383 */
1384int trace_bpf_filter(struct libtrace_filter_t *filter,
1385                        struct libtrace_packet_t *packet) {
1386#if HAVE_BPF
1387        void *linkptr = 0;
1388        int clen = 0;
1389        assert(filter);
1390        assert(packet);
1391        linkptr = trace_get_link(packet);       
1392        assert(linkptr);
1393        clen = trace_get_capture_length(packet);
1394       
1395
1396        if (filter->filterstring && ! filter->filter) {
1397                pcap_t *pcap;
1398                struct bpf_program bpfprog;
1399
1400                switch (trace_get_link_type(packet)) {
1401                        case TRACE_TYPE_ETH:
1402                                pcap = pcap_open_dead(DLT_EN10MB, 1500);
1403                                break;
1404                        default:
1405                                printf("only works for ETH at the moment\n");
1406                                assert(0);
1407                }               
1408
1409                // build filter
1410                if (pcap_compile( pcap, &bpfprog, filter->filterstring, 1, 0)) {
1411                        printf("bpf compilation error: %s\n", 
1412                                pcap_geterr(pcap));
1413                        assert(0);
1414                }
1415                pcap_close(pcap);
1416                filter->filter = bpfprog.bf_insns;     
1417        }
1418
1419        assert(filter->filter);
1420        return bpf_filter(filter->filter, linkptr, clen, clen);
1421#else
1422        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1423        return 0;
1424#endif
1425}
1426
1427/** Set the direction flag, if it has one
1428 * @param packet the packet opaque pointer
1429 * @param direction the new direction (0,1,2,3)
1430 * @returns a signed value containing the direction flag, or -1 if this is not supported
1431 * @author Daniel Lawson
1432 */
1433int8_t trace_set_direction(struct libtrace_packet_t *packet, int8_t direction) {
1434       
1435        dag_record_t *erfptr = 0;
1436        assert(packet);
1437
1438        switch(packet->trace->format) {
1439                case DAG:
1440                case ERF:
1441                case RTCLIENT:
1442                        erfptr = (dag_record_t *)packet->buffer;
1443                        erfptr->flags.iface = direction;
1444                        break;
1445                default:
1446                        direction = -1;
1447        }
1448       
1449        return direction;
1450       
1451       
1452}
1453
1454/** Get the direction flag, if it has one
1455 * @param libtrace the libtrace opaque pointer
1456 * @param buffer a point to a fille in buffer
1457 * @param buflen the length of the buffer
1458 * @returns a signed value containing the direction flag, or -1 if this is not supported
1459 * @author Daniel Lawson
1460 */
1461int8_t trace_get_direction(struct libtrace_packet_t *packet) {
1462       
1463        int8_t direction;
1464        dag_record_t *erfptr = 0;
1465        assert(packet);
1466
1467        switch(packet->trace->format) {
1468                case DAG:
1469                case ERF:
1470                case RTCLIENT:
1471                        erfptr = (dag_record_t *)packet->buffer;
1472                        direction = erfptr->flags.iface;
1473                        break;
1474                default:
1475                        direction = -1;
1476        }
1477       
1478        return direction;
1479       
1480       
1481}
1482
1483
1484/** Attempt to deduce the 'server' port
1485 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1486 * @param source the TCP or UDP source port
1487 * @param dest the TCP or UDP destination port
1488 * @returns a hint as to which port is the server port
1489 * @author Daniel Lawson
1490 */
1491#define ROOT_SERVER(x) ((x) < 512)
1492#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1493#define NONROOT_SERVER(x) ((x) >= 5000)
1494#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1495#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1496#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1497#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1498
1499int8_t trace_get_server_port(uint8_t protocol, uint16_t source, uint16_t dest) {
1500        /*
1501         * * If the ports are equal, return DEST
1502         * * Check for well-known ports in the given protocol
1503         * * Root server ports: 0 - 511
1504         * * Root client ports: 512 - 1023
1505         * * non-root client ports: 1024 - 4999
1506         * * non-root server ports: 5000+
1507         * * Check for static ranges: 1024 - 49151
1508         * * Check for dynamic ranges: 49152 - 65535
1509         * * flip a coin.
1510         */
1511
1512        uint16_t server, client;
1513
1514        /* equal */
1515        if (source == client)
1516                return USE_DEST;
1517
1518        /* root server port, 0 - 511 */
1519        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1520                if (source < dest)
1521                        return USE_SOURCE;
1522                return USE_DEST;
1523        }
1524
1525        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1526                return USE_SOURCE;
1527        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1528                return USE_DEST;
1529
1530        /* non-root server */
1531        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1532                if (source < dest)
1533                        return USE_SOURCE;
1534                return USE_DEST;
1535        }
1536        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1537                return USE_SOURCE;
1538        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1539                return USE_DEST;
1540
1541        /* root client */
1542        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1543                if (source < dest)
1544                        return USE_SOURCE;
1545                return USE_DEST;
1546        }
1547        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1548                /* prefer root-client over nonroot-client */
1549                if (NONROOT_CLIENT(dest))
1550                        return USE_SOURCE;
1551                return USE_DEST;
1552        }
1553        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1554                /* prefer root-client over nonroot-client */
1555                if (NONROOT_CLIENT(source))
1556                        return USE_DEST;
1557                return USE_SOURCE;
1558        }
1559       
1560        /* nonroot client */
1561        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1562                if (source < dest) 
1563                        return USE_SOURCE;
1564                return USE_DEST;
1565        }
1566        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1567                return USE_DEST;
1568        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1569                return USE_SOURCE;
1570
1571        /* dynamic range */
1572        if (DYNAMIC(source) && DYNAMIC(dest))
1573                if (source < dest)
1574                        return USE_SOURCE;
1575                return USE_DEST;
1576        if (DYNAMIC(source) && !DYNAMIC(dest))
1577                return USE_DEST;
1578        if (!DYNAMIC(source) && DYNAMIC(dest))
1579                return USE_SOURCE;
1580        /*
1581        if (SERVER(source) && CLIENT(dest))
1582                return USE_SOURCE;
1583       
1584        if (SERVER(dest) && CLIENT(source))
1585                return USE_DEST;
1586        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1587                return USE_SOURCE;
1588        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
1589                return USE_DEST;
1590        */
1591        // failing that test...
1592        if (source < dest) {
1593                return USE_SOURCE;
1594        } 
1595        return USE_DEST;
1596       
1597}
1598
1599/** Truncate the packet at the suggested length
1600 * @param packet        the packet opaque pointer
1601 * @param len           the new length of the packet
1602 * @returns the new length of the packet, or the original length of the
1603 * packet if unchanged
1604 * NOTE: len refers to the network-level payload of the packet, and not
1605 * any capture headers included as well. For example, to truncate a packet
1606 * after the IP header, set scan to sizeof(ethernet_header) + sizeof(ip_header)
1607 * @author Daniel Lawson
1608 */
1609size_t trace_truncate_packet(struct libtrace_packet_t *packet, size_t size) {
1610        dag_record_t *erfptr;
1611#if HAVE_PCAP
1612        struct pcap_pkthdr *pcaphdr;
1613#endif
1614
1615        assert(packet);
1616
1617        if (size > packet->size) {
1618                // can't make a packet larger
1619                return packet->size;
1620        }
1621        switch (packet->trace->format) {
1622#if HAVE_PCAP
1623                case PCAPINT:
1624                case PCAP:
1625                        pcaphdr = (struct pcap_pkthdr *)packet->buffer;
1626                        pcaphdr->caplen = size + sizeof(struct pcap_pkthdr);
1627                        packet->size = pcaphdr->caplen;
1628                        break;
1629#endif
1630                case ERF:
1631                case DAG:
1632                case RTCLIENT:
1633                        erfptr = (dag_record_t *)packet->buffer;
1634                        erfptr->rlen = ntohs(size + sizeof(dag_record_t));
1635                        packet->size = size + sizeof(dag_record_t);
1636                        break;
1637                case WAGINT:
1638                case WAG:
1639                        // don't know how to do this?
1640                        break;
1641        }
1642        return packet->size;
1643}
1644
Note: See TracBrowser for help on using the repository browser.