source: lib/trace.c @ 7b2a39b

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

Make format_linux only compile if the machine we're compiling it on supports it.

  • Property mode set to 100644
File size: 37.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 * @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 <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <sys/stat.h>
51#include <sys/types.h>
52#include <stdarg.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#ifdef HAVE_NET_IF_ARP_H
63#  include <net/if_arp.h>
64#endif
65
66#ifdef HAVE_NET_IF_H
67#  include <net/if.h>
68#endif
69
70#ifdef HAVE_NETINET_IN_H
71#  include <netinet/in.h>
72#endif
73
74#ifdef HAVE_NET_ETHERNET_H
75#  include <net/ethernet.h>
76#endif
77
78#ifdef HAVE_NETINET_IF_ETHER_H
79#  include <netinet/if_ether.h>
80#endif
81
82#include <time.h>
83
84#include "libtrace.h"
85#include "fifo.h"
86#include "libtrace_int.h"
87#include "parse_cmd.h"
88
89#if HAVE_PCAP_BPF_H
90#  include <pcap-bpf.h>
91#else
92#  ifdef HAVE_NET_BPF_H
93#    include <net/bpf.h>
94#  endif
95#endif
96
97#include "libtrace_int.h"
98#include "format_helper.h"
99#include "rt_protocol.h"
100
101#define MAXOPTS 1024
102
103
104static struct libtrace_format_t *formats_list = 0;
105
106/* strncpy is not assured to copy the final \0, so we
107 * will use our own one that does
108 */
109static void xstrncpy(char *dest, const char *src, size_t n)
110{
111        strncpy(dest,src,n);
112        dest[n]='\0';
113}
114 
115static char *xstrndup(const char *src,size_t n)
116{       
117        char *ret=(char*)malloc(n+1);
118        xstrncpy(ret,src,n);
119        return ret;
120}
121
122void register_format(struct libtrace_format_t *f) {
123        assert(f->next==NULL);
124        f->next=formats_list;
125        formats_list=f;
126        /* Now, verify things */
127#if 0
128        if (format_list[nformats]->init_input) {
129#define REQUIRE(x) \
130                if (!format_list[nformats]->x) \
131                        fprintf(stderr,"%s: Input format should provide " #x "\n",format_list[nformats]->name)
132                REQUIRE(read_packet);
133                REQUIRE(start_input);
134                REQUIRE(config_input);
135                REQUIRE(pause_input);
136                REQUIRE(fin_input);
137                REQUIRE(get_link_type);
138                REQUIRE(get_capture_length);
139                REQUIRE(get_wire_length);
140                REQUIRE(get_framing_length);
141                REQUIRE(trace_event);
142                if (!format_list[nformats]->get_erf_timestamp
143                        && !format_list[nformats]->get_seconds
144                        && !format_list[nformats]->get_timeval) {
145                        fprintf(stderr,"%s: A trace format capable of input, should provide at least one of\n"
146"get_erf_timestamp, get_seconds or trace_timeval\n",format_list[nformats]->name);
147                }
148                if (format_list[nformats]->trace_event==trace_event_device) {
149                        REQUIRE(get_fd);
150                }
151                else {
152                        if (format_list[nformats]->get_fd) {
153                                fprintf(stderr,"%s: Unnecessary get_fd\n",
154                                                format_list[nformats]->name);
155                        }
156                }
157#undef REQUIRE
158        }
159        else {
160#define REQUIRE(x) \
161                if (format_list[nformats]->x) \
162                        fprintf(stderr,"%s: Non Input format shouldn't need " #x "\n",format_list[nformats]->name)
163                REQUIRE(read_packet);
164                REQUIRE(start_input);
165                REQUIRE(pause_input);
166                REQUIRE(fin_input);
167                REQUIRE(get_link_type);
168                REQUIRE(get_capture_length);
169                REQUIRE(get_wire_length);
170                REQUIRE(get_framing_length);
171                REQUIRE(trace_event);
172                REQUIRE(get_seconds);
173                REQUIRE(get_timeval);
174                REQUIRE(get_erf_timestamp);
175#undef REQUIRE
176        }
177        if (format_list[nformats]->init_output) {
178#define REQUIRE(x) \
179                if (!format_list[nformats]->x) \
180                        fprintf(stderr,"%s: Output format should provide " #x "\n",format_list[nformats]->name)
181                REQUIRE(write_packet);
182                REQUIRE(start_output);
183                REQUIRE(config_output);
184                REQUIRE(fin_output);
185#undef REQUIRE
186        }
187        else {
188#define REQUIRE(x) \
189                if (format_list[nformats]->x) \
190                        fprintf(stderr,"%s: Non Output format shouldn't need " #x "\n",format_list[nformats]->name)
191                REQUIRE(write_packet);
192                REQUIRE(start_output);
193                REQUIRE(config_output);
194                REQUIRE(fin_output);
195#undef REQUIRE
196        }
197#endif
198}
199
200void erf_constructor();
201void legacy_constructor();
202void linuxnative_constructor();
203void pcap_constructor();
204void pcapfile_constructor();
205void rt_constructor();
206void wag_constructor();
207
208/* call all the constructors if they haven't yet all been called */
209void trace_init(void)
210{
211        if (!formats_list) {
212                erf_constructor();
213                legacy_constructor();
214#ifdef HAVE_NETPACKET_PACKET_H
215                linuxnative_constructor();
216#endif
217#ifdef HAVE_PCAP
218                pcap_constructor();
219#endif
220                pcapfile_constructor();
221                rt_constructor();
222                wag_constructor();
223        }
224}
225
226/* Prints help information for libtrace
227 *
228 * Function prints out some basic help information regarding libtrace,
229 * and then prints out the help() function registered with each input module
230 */
231DLLEXPORT void trace_help() {
232        struct libtrace_format_t *tmp;
233        trace_init();
234        printf("libtrace %s\n",PACKAGE_VERSION);
235        for(tmp=formats_list;tmp;tmp=tmp->next) {
236                if (tmp->help)
237                        tmp->help();
238        }
239}
240
241#define RP_BUFSIZE 65536
242#define URI_PROTO_LINE 16
243
244/* Gets the name of the output format for a given output trace.
245 *
246 * @params libtrace     the output trace to get the name of the format for
247 * @returns callee-owned null-terminated char* containing the output format
248 *
249 */
250DLLEXPORT SIMPLE_FUNCTION
251char *trace_get_output_format(const struct libtrace_out_t *libtrace) {
252        char * format = libtrace->format->name;
253
254        return format;
255}
256
257
258/* Create a trace file from a URI
259 *
260 * @params char * containing a valid libtrace URI
261 * @returns opaque pointer to a libtrace_t
262 *
263 * Valid URI's are:
264 *  erf:/path/to/erf/file
265 *  erf:/path/to/erf/file.gz
266 *  erf:/path/to/rtclient/socket
267 *  erf:-                       (stdin)
268 *  dag:/dev/dagcard
269 *  pcapint:pcapinterface               (eg: pcapint:eth0)
270 *  pcap:/path/to/pcap/file
271 *  pcap:-
272 *  rtclient:hostname
273 *  rtclient:hostname:port
274 *  wag:-
275 *  wag:/path/to/wag/file
276 *  wag:/path/to/wag/file.gz
277 *  wag:/path/to/wag/socket
278 *
279 * If an error occured when attempting to open a trace, NULL is returned
280 * and an error is output to stdout.
281 */
282DLLEXPORT struct libtrace_t *trace_create(const char *uri) {
283        struct libtrace_t *libtrace = 
284                        (struct libtrace_t *)malloc(sizeof(struct libtrace_t));
285        char *scan = 0;
286        const char *uridata = 0;                 
287        struct libtrace_format_t *tmp;
288
289        trace_init();
290
291        assert(uri && "Passing NULL to trace_create makes me a very sad program");
292       
293        libtrace->err.err_num = TRACE_ERR_NOERROR;
294        libtrace->format=NULL;
295       
296        /* parse the URI to determine what sort of event we are dealing with */
297        if ((uridata = trace_parse_uri(uri, &scan)) == 0) {
298                trace_set_err(libtrace,TRACE_ERR_BAD_FORMAT,"Bad uri format (%s)",uri);
299                return libtrace;
300        }
301       
302        libtrace->event.tdelta = 0.0;
303        libtrace->filter = NULL;
304        libtrace->snaplen = 0;
305        libtrace->started=false;
306
307        for (tmp=formats_list;tmp;tmp=tmp->next) {
308                if (strlen(scan) == strlen(tmp->name) &&
309                                strncasecmp(scan, tmp->name, strlen(scan)) == 0
310                                ) {
311                        libtrace->format=tmp;
312                        break;
313                }
314        }
315        if (libtrace->format == 0) {
316                trace_set_err(libtrace, TRACE_ERR_BAD_FORMAT,
317                                "Unknown format (%s)",scan);
318                return libtrace;
319        }
320
321        libtrace->uridata = strdup(uridata);
322        /* libtrace->format now contains the type of uri
323         * libtrace->uridata contains the appropriate data for this
324         */
325       
326        if (libtrace->format->init_input) {
327                int err=libtrace->format->init_input(libtrace);
328                assert (err==-1 || err==0);
329                if (err==-1) {
330                        /* init_input should call trace_set_err to set
331                         * the error message
332                         */
333                        return libtrace;
334                }
335        } else {
336                trace_set_err(libtrace,TRACE_ERR_NO_INIT,
337                                "Format does not support input (%s)",scan);
338                return libtrace;
339        }
340       
341
342        libtrace->fifo = create_tracefifo(1048576);
343        if (!libtrace->fifo) {
344                trace_set_err(libtrace,ENOMEM,"Could not allocate memory for fifo");
345                free(scan);
346                return libtrace;
347        }
348        assert(libtrace->fifo);
349        free(scan);
350        trace_set_err(libtrace,0,"");
351        return libtrace;
352}
353
354/* Creates a "dummy" trace file that has only the format type set.
355 *
356 * @returns opaque pointer to a (sparsely initialised) libtrace_t
357 *
358 * IMPORTANT: Do not attempt to call trace_read_packet or other such functions
359 * with the dummy trace. Its intended purpose is to act as a packet->trace for
360 * libtrace_packet_t's that are not associated with a libtrace_t structure.
361 */
362DLLEXPORT struct libtrace_t * trace_create_dead (const char *uri) {
363        struct libtrace_t *libtrace = (struct libtrace_t *)
364                                        malloc(sizeof(struct libtrace_t));
365        char *scan = (char *)calloc(sizeof(char),URI_PROTO_LINE);
366        char *uridata;
367        struct libtrace_format_t *tmp;
368       
369        libtrace->err.err_num = TRACE_ERR_NOERROR;
370
371        if((uridata = strchr(uri,':')) == NULL) {
372                xstrncpy(scan, uri, strlen(uri));
373        } else {
374                xstrncpy(scan,uri, (uridata - uri));
375        }
376       
377        libtrace->format = 0;   
378       
379        for(tmp=formats_list;tmp;tmp=tmp->next) {
380                if (strlen(scan) == strlen(tmp->name) &&
381                                !strncasecmp(scan,
382                                        tmp->name,
383                                        strlen(scan))) {
384                                libtrace->format=tmp;
385                                break;
386                                }
387        }
388        if (libtrace->format == 0) {
389                trace_set_err(libtrace,TRACE_ERR_BAD_FORMAT,
390                                "Unknown format (%s)",scan);
391                return 0;
392        }
393
394        libtrace->format_data = NULL;
395        free(scan);
396        return libtrace;
397
398}
399
400/* Creates a trace output file from a URI.
401 *
402 * @param uri   the uri string describing the output format and destination
403 * @returns opaque pointer to a libtrace_output_t
404 *
405 *  If an error occured when attempting to open the output trace, NULL is
406 *  returned and trace_errno is set.
407 */
408       
409DLLEXPORT libtrace_out_t *trace_create_output(const char *uri) {
410        libtrace_out_t *libtrace = 
411                        (libtrace_out_t*)malloc(sizeof(struct libtrace_out_t));
412       
413        char *scan = 0;
414        const char *uridata = 0;
415        struct libtrace_format_t *tmp;
416
417        trace_init();
418
419        libtrace->err.err_num = TRACE_ERR_NOERROR;
420        strcat(libtrace->err.problem,"Error message set\n");
421       
422        /* parse the URI to determine what sort of event we are dealing with */
423
424        if ((uridata = trace_parse_uri(uri, &scan)) == 0) {
425                trace_set_err_out(libtrace,TRACE_ERR_BAD_FORMAT,
426                                "Bad uri format (%s)",uri);
427                return libtrace;
428        }
429       
430        libtrace->format = NULL;
431        for(tmp=formats_list;tmp;tmp=tmp->next) {
432                if (strlen(scan) == strlen(tmp->name) &&
433                                !strncasecmp(scan,
434                                        tmp->name,
435                                        strlen(scan))) {
436                                libtrace->format=tmp;
437                                break;
438                                }
439        }
440        if (libtrace->format == NULL) {
441                trace_set_err_out(libtrace,TRACE_ERR_BAD_FORMAT,
442                                "Unknown output format (%s)",scan);
443                return libtrace;
444        }
445        libtrace->uridata = strdup(uridata);
446
447
448        /* libtrace->format now contains the type of uri
449         * libtrace->uridata contains the appropriate data for this
450         */
451
452        if (libtrace->format->init_output) {
453                /* 0 on success, -1 on failure */
454                switch(libtrace->format->init_output(libtrace)) {
455                        case -1: /* failure */
456                                free(libtrace);
457                                return libtrace;
458                        case 0: /* success */
459                                break;
460                        default:
461                                assert(!"init_output() should return -1 for failure, or 0 for success");
462                }
463        } else {
464                trace_set_err_out(libtrace,TRACE_ERR_NO_INIT_OUT,
465                                "Format does not support writing (%s)",scan);
466                return libtrace;
467        }
468
469
470        free(scan);
471        libtrace->started=false;
472        return libtrace;
473}
474
475/* Start a trace
476 * @param libtrace      the input trace to start
477 * @returns 0 on success
478 *
479 * This does the work associated with actually starting up
480 * the trace.  it may fail.
481 */
482DLLEXPORT int trace_start(struct libtrace_t *libtrace)
483{
484        assert(libtrace);
485        if (libtrace->format->start_input) {
486                int ret=libtrace->format->start_input(libtrace);
487                if (ret < 0) {
488                        return ret;
489                }
490        }
491
492        libtrace->started=true;
493        return 0;
494}
495
496DLLEXPORT int trace_start_output(libtrace_out_t *libtrace) 
497{
498        assert(libtrace);
499        if (libtrace->format->start_output) {
500                int ret=libtrace->format->start_output(libtrace);
501                if (ret < 0) {
502                        return ret;
503                }
504        }
505
506        libtrace->started=true;
507        return 0;
508}
509
510DLLEXPORT int trace_pause(libtrace_t *libtrace)
511{
512        assert(libtrace);
513        assert(libtrace->started && "BUG: Called trace_pause without calling trace_start first");
514        if (libtrace->format->pause_input)
515                libtrace->format->pause_input(libtrace);
516        libtrace->started=false;
517        return 0;
518}
519
520DLLEXPORT int trace_config(libtrace_t *libtrace,
521                trace_option_t option,
522                void *value)
523{
524        int ret;
525        if (libtrace->format->config_input) {
526                ret=libtrace->format->config_input(libtrace,option,value);
527                if (ret==0)
528                        return 0;
529        }
530        switch(option) {
531                case TRACE_OPTION_SNAPLEN:
532                        libtrace->snaplen=*(int*)value;
533                        return 0;
534                case TRACE_OPTION_FILTER:
535                        libtrace->filter=(struct libtrace_filter_t *)value;
536                        return 0;
537                case TRACE_OPTION_PROMISC:
538                        trace_set_err(libtrace,TRACE_ERR_OPTION_UNAVAIL,
539                                "Promisc mode is not supported by this format module");
540                        return -1;
541        }
542        trace_set_err(libtrace,TRACE_ERR_UNKNOWN_OPTION,
543                "Unknown option %i", option);
544        return -1;
545}
546
547/* Parses an output options string and calls the appropriate function to deal with output options.
548 *
549 * @param libtrace      the output trace object to apply the options to
550 * @param options       the options string
551 * @returns -1 if option configuration failed, 0 otherwise
552 *
553 * @author Shane Alcock
554 */
555DLLEXPORT int trace_config_output(struct libtrace_out_t *libtrace, 
556                trace_option_output_t option,
557                void *value) {
558        if (libtrace->format->config_output) {
559                return libtrace->format->config_output(libtrace, option, value);
560        }
561        return -1;
562}
563
564/* Close a trace file, freeing up any resources it may have been using
565 *
566 */
567DLLEXPORT void trace_destroy(struct libtrace_t *libtrace) {
568        assert(libtrace);
569        if (libtrace->started && libtrace->format->pause_input)
570                libtrace->format->pause_input(libtrace);
571        libtrace->format->fin_input(libtrace);
572        /* need to free things! */
573        free(libtrace->uridata);
574        destroy_tracefifo(libtrace->fifo);
575        free(libtrace);
576}
577
578
579DLLEXPORT void trace_destroy_dead(struct libtrace_t *libtrace) {
580        assert(libtrace);
581        free(libtrace);
582}
583/* Close an output trace file, freeing up any resources it may have been using
584 *
585 * @param libtrace      the output trace file to be destroyed
586 *
587 * @author Shane Alcock
588 * */
589DLLEXPORT void trace_destroy_output(struct libtrace_out_t *libtrace) {
590        assert(libtrace);
591        libtrace->format->fin_output(libtrace);
592        free(libtrace->uridata);
593        free(libtrace);
594}
595
596DLLEXPORT libtrace_packet_t *trace_create_packet() {
597        libtrace_packet_t *packet = 
598                (libtrace_packet_t*)calloc(1,sizeof(libtrace_packet_t));
599        packet->buf_control=TRACE_CTRL_PACKET;
600        return packet;
601}
602
603DLLEXPORT libtrace_packet_t *trace_copy_packet(const libtrace_packet_t *packet) {
604        libtrace_packet_t *dest = 
605                (libtrace_packet_t *)malloc(sizeof(libtrace_packet_t));
606        dest->trace=packet->trace;
607        dest->buffer=malloc(
608                        trace_get_framing_length(packet)
609                        +trace_get_capture_length(packet));
610        dest->header=dest->buffer;
611        dest->payload=(void*)
612                ((char*)dest->buffer+trace_get_framing_length(packet));
613        dest->size=packet->size;
614        dest->type=packet->type;
615        dest->buf_control=TRACE_CTRL_PACKET;
616        memcpy(dest->header,packet->header,trace_get_framing_length(packet));
617        memcpy(dest->payload,packet->payload,trace_get_capture_length(packet));
618
619        return dest;
620}
621
622/** Destroy a packet object
623 *
624 * sideeffect: sets packet to NULL
625 */
626DLLEXPORT void trace_destroy_packet(struct libtrace_packet_t **packet) {
627        if ((*packet)->buf_control == TRACE_CTRL_PACKET) {
628                free((*packet)->buffer);
629        }
630        free((*packet));
631        *packet = NULL;
632}       
633
634/* Read one packet from the trace into buffer
635 *
636 * @param libtrace      the libtrace opaque pointer
637 * @param packet        the packet opaque pointer
638 * @returns 0 on EOF, negative value on error
639 *
640 */
641DLLEXPORT int trace_read_packet(libtrace_t *libtrace, libtrace_packet_t *packet) {
642
643        assert(libtrace && "You called trace_read_packet() with a NULL libtrace parameter!\n");
644        assert(libtrace->started && "BUG: You must call libtrace_start() before trace_read_packet()\n");
645        assert(packet);
646        assert((packet->buf_control==TRACE_CTRL_PACKET || packet->buf_control==TRACE_CTRL_EXTERNAL)&&
647                "BUG: You must allocate a packet using packet_create()");
648     
649        /* Store the trace we are reading from into the packet opaque
650         * structure */
651        packet->trace = libtrace;
652
653        if (libtrace->format->read_packet) {
654                do {
655                        packet->size=libtrace->format->read_packet(libtrace,packet);
656                        if (packet->size==(size_t)-1 || packet->size==0) {
657                                return packet->size;
658                        }
659                        if (libtrace->filter) {
660                                /* If the filter doesn't match, read another
661                                 * packet
662                                 */
663                                if (!trace_bpf_filter(libtrace->filter,packet)){
664                                        continue;
665                                }
666                        }
667                        if (libtrace->snaplen>0) {
668                                /* Snap the packet */
669                                trace_set_capture_length(packet,
670                                                libtrace->snaplen);
671                        }
672                        return packet->size;
673                } while(1);
674        }
675        trace_set_err(libtrace,TRACE_ERR_BAD_FORMAT,"This format does not support reading packets\n");
676        packet->size=-1;
677        return -1;
678}
679
680/* Writes a packet to the specified output
681 *
682 * @param libtrace      describes the output format, destination, etc.
683 * @param packet        the packet to be written out
684 * @returns the number of bytes written, -1 if write failed
685 *
686 * @author Shane Alcock
687 * */
688DLLEXPORT int trace_write_packet(struct libtrace_out_t *libtrace, const struct libtrace_packet_t *packet) {
689        assert(libtrace);
690        assert(packet); 
691        /* Verify the packet is valid */
692        assert(packet->size<65536);
693        assert(packet->size>0);
694        assert(libtrace->started);
695
696        if (libtrace->format->write_packet) {
697                return libtrace->format->write_packet(libtrace, packet);
698        }
699        return -1;
700}
701
702DLLEXPORT void *trace_get_link(const struct libtrace_packet_t *packet) {
703        return (void *)packet->payload;
704}
705
706/*
707typedef struct legacy_framing {
708        uint64_t        ts;
709        uint32_t        crc;
710        uint32_t        header;
711        uint32_t        data[12]; // pad to 64 bytes
712} legacy_framing_t;
713*/
714
715
716/* Get the current time in DAG time format
717 * @param packet        a pointer to a libtrace_packet structure
718 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
719 * past 1970-01-01, the lower 32bits are partial seconds)
720 * @author Daniel Lawson
721 */ 
722DLLEXPORT uint64_t trace_get_erf_timestamp(const libtrace_packet_t *packet) {
723        uint64_t timestamp = 0;
724        double seconds = 0.0;
725        struct timeval ts;
726
727        assert(packet->size>0 && packet->size<65536);
728
729        if (packet->trace->format->get_erf_timestamp) {
730                /* timestamp -> timestamp */
731                timestamp = packet->trace->format->get_erf_timestamp(packet);
732        } else if (packet->trace->format->get_timeval) {
733                /* timeval -> timestamp */
734                ts = packet->trace->format->get_timeval(packet);
735                timestamp = ((((uint64_t)ts.tv_sec) << 32) + \
736                                (((uint64_t)ts.tv_usec * UINT_MAX)/1000000));
737        } else if (packet->trace->format->get_seconds) {
738                /* seconds -> timestamp */
739                seconds = packet->trace->format->get_seconds(packet);
740                timestamp = ((uint64_t)((uint32_t)seconds) << 32) + \
741                      (uint64_t)(( seconds - (uint32_t)seconds   ) * UINT_MAX);
742        }
743        return timestamp;
744}
745
746/* Get the current time in struct timeval
747 * @param packet        a pointer to a libtrace_packet structure
748 *
749 * @returns time that this packet was seen in a struct timeval
750 * @author Daniel Lawson
751 * @author Perry Lorier
752 */ 
753DLLEXPORT struct timeval trace_get_timeval(const libtrace_packet_t *packet) {
754        struct timeval tv;
755        uint64_t ts = 0;
756        double seconds = 0.0;
757        assert(packet->size>0 && packet->size<65536);
758        if (packet->trace->format->get_timeval) {
759                /* timeval -> timeval */
760                tv = packet->trace->format->get_timeval(packet);
761        } else if (packet->trace->format->get_erf_timestamp) {
762                /* timestamp -> timeval */
763                ts = packet->trace->format->get_erf_timestamp(packet);
764#if __BYTE_ORDER == __BIG_ENDIAN
765                tv.tv_sec = ts & 0xFFFFFFFF;
766#elif __BYTE_ORDER == __LITTLE_ENDIAN
767                tv.tv_sec = ts >> 32;
768#else
769#error "What on earth are you running this on?"
770#endif
771                tv.tv_usec = ((ts&0xFFFFFFFF)*1000000)>>32;
772                if (tv.tv_usec >= 1000000) {
773                        tv.tv_usec -= 1000000;
774                        tv.tv_sec += 1;
775                }
776        } else if (packet->trace->format->get_seconds) {
777                /* seconds -> timeval */
778                seconds = packet->trace->format->get_seconds(packet);
779                tv.tv_sec = (uint32_t)seconds;
780                tv.tv_usec = (uint32_t)(((seconds - tv.tv_sec) * 1000000)/UINT_MAX);
781        }
782
783        return tv;
784}
785
786/* Get the current time in floating point seconds
787 * @param packet        a pointer to a libtrace_packet structure
788 * @returns time that this packet was seen in 64bit floating point seconds
789 * @author Perry Lorier
790 */ 
791DLLEXPORT double trace_get_seconds(const struct libtrace_packet_t *packet) {
792        double seconds = 0.0;
793        uint64_t ts = 0;
794        struct timeval tv;
795
796        assert(packet->size>0 && packet->size<65536);
797       
798        if (packet->trace->format->get_seconds) {
799                /* seconds->seconds */
800                seconds = packet->trace->format->get_seconds(packet);
801        } else if (packet->trace->format->get_erf_timestamp) {
802                /* timestamp -> seconds */
803                ts = packet->trace->format->get_erf_timestamp(packet);
804                seconds =  (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
805        } else if (packet->trace->format->get_timeval) {
806                /* timeval -> seconds */
807                tv = packet->trace->format->get_timeval(packet);
808                seconds = tv.tv_sec + ((tv.tv_usec * 1.0) / 1000000);
809        }
810
811        return seconds;
812}
813
814DLLEXPORT size_t trace_get_capture_length(const libtrace_packet_t *packet) {
815
816        assert(packet->size<65536);
817
818        if (packet->trace->format->get_capture_length) {
819                return packet->trace->format->get_capture_length(packet);
820        }
821        return -1;
822}
823       
824/* Get the size of the packet as it was seen on the wire.
825 * @param packet        a pointer to a libtrace_packet structure
826 *
827 * @returns the size of the packet as it was on the wire.
828 * @author Perry Lorier
829 * @author Daniel Lawson
830 * @note Due to the trace being a header capture, or anonymisation this may
831 * not be the same as the Capture Len.
832 */ 
833DLLEXPORT size_t trace_get_wire_length(const libtrace_packet_t *packet){
834        assert(packet->size>0 && packet->size<65536);
835
836        if (packet->trace->format->get_wire_length) {
837                return packet->trace->format->get_wire_length(packet);
838        }
839        return -1;
840
841}
842
843/* Get the length of the capture framing headers.
844 * @param packet        the packet opaque pointer
845 * @returns the size of the packet as it was on the wire.
846 * @author Perry Lorier
847 * @author Daniel Lawson
848 * @note this length corresponds to the difference between the size of a
849 * captured packet in memory, and the captured length of the packet
850 */ 
851DLLEXPORT SIMPLE_FUNCTION
852size_t trace_get_framing_length(const libtrace_packet_t *packet) {
853        if (packet->trace->format->get_framing_length) {
854                return packet->trace->format->get_framing_length(packet);
855        }
856        return -1;
857}
858
859
860/* Get the type of the link layer
861 * @param packet        a pointer to a libtrace_packet structure
862 * @returns libtrace_linktype_t
863 * @author Perry Lorier
864 * @author Daniel Lawson
865 */
866DLLEXPORT libtrace_linktype_t trace_get_link_type(const libtrace_packet_t *packet ) {
867        if (packet->trace->format->get_link_type) {
868                return packet->trace->format->get_link_type(packet);
869        }
870        return (libtrace_linktype_t)-1;
871}
872
873/* process a libtrace event
874 * @param trace the libtrace opaque pointer
875 * @param packet the libtrace_packet opaque pointer
876 * @returns
877 *  TRACE_EVENT_IOWAIT  Waiting on I/O on fd
878 *  TRACE_EVENT_SLEEP   Next event in seconds
879 *  TRACE_EVENT_PACKET  Packet arrived in buffer with size size
880 *  TRACE_EVENT_TERMINATE Trace terminated (perhaps with an error condition)
881 * FIXME currently keeps a copy of the packet inside the trace pointer,
882 * which in turn is stored inside the new packet object...
883 * @author Perry Lorier
884 */
885DLLEXPORT struct libtrace_eventobj_t trace_event(struct libtrace_t *trace, 
886                struct libtrace_packet_t *packet) {
887        struct libtrace_eventobj_t event = {TRACE_EVENT_IOWAIT,0,0.0,0};
888
889        if (!trace) {
890                fprintf(stderr,"You called trace_event() with a NULL trace object!\n");
891        }
892        assert(trace);
893        assert(packet);
894
895        /* Store the trace we are reading from into the packet opaque
896         * structure */
897        packet->trace = trace;
898
899        if (packet->trace->format->trace_event) {
900                return packet->trace->format->trace_event(trace,packet);
901        } else {
902                return event;
903        }
904
905}
906
907/* setup a BPF filter
908 * @param filterstring a char * containing the bpf filter string
909 * @returns opaque pointer pointer to a libtrace_filter_t object
910 * @author Daniel Lawson
911 */
912DLLEXPORT struct libtrace_filter_t *trace_bpf_setfilter(const char *filterstring) {
913#if HAVE_BPF
914        struct libtrace_filter_t *filter = (struct libtrace_filter_t*)
915                                malloc(sizeof(struct libtrace_filter_t));
916        filter->filterstring = strdup(filterstring);
917        filter->flag = 0;
918        return filter;
919#else
920        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
921        return 0;
922#endif
923}
924
925/* compile a bpf filter, now we know what trace it's on
926 * @internal
927 *
928 * @returns -1 on error, 0 on success
929 */
930int trace_bpf_compile(libtrace_filter_t *filter,
931                const libtrace_packet_t *packet ) {
932#if HAVE_BPF
933        void *linkptr = 0;
934        assert(filter);
935
936        /* If this isn't a real packet, then fail */
937        linkptr = trace_get_link(packet);
938        if (!linkptr) {
939                trace_set_err(packet->trace,
940                                TRACE_ERR_BAD_PACKET,"Packet has no payload");
941                return -1;
942        }
943       
944        if (filter->filterstring && ! filter->flag) {
945                pcap_t *pcap;
946                libtrace_linktype_t linktype=trace_get_link_type(packet);
947                if (linktype==(libtrace_linktype_t)-1) {
948                        trace_set_err(packet->trace,TRACE_ERR_BAD_PACKET,
949                                        "Packet has an unknown linktype");
950                        return -1;
951                }
952                if (libtrace_to_pcap_dlt(linktype) == -1) {
953                        trace_set_err(packet->trace,TRACE_ERR_BAD_PACKET,
954                                        "Unknown pcap equivilent linktype");
955                        return -1;
956                }
957                pcap=(pcap_t *)pcap_open_dead(
958                                libtrace_to_pcap_dlt(linktype),
959                                1500);
960                /* build filter */
961                if (pcap_compile( pcap, &filter->filter, filter->filterstring, 
962                                        1, 0)) {
963                        pcap_close(pcap);
964                        trace_set_err(packet->trace,TRACE_ERR_BAD_PACKET,
965                                        "Packet has no payload");
966                        return -1;
967                }
968                pcap_close(pcap);
969                filter->flag=1;
970        }
971        return 0;
972#else
973        assert(!"This should never be called when BPF not enabled");
974        trace_set_err(packet->trace,TRACE_ERR_OPTION_UNAVAIL,
975                                "Feature unavailable");
976        return -1;
977#endif
978}
979
980DLLEXPORT int trace_bpf_filter(struct libtrace_filter_t *filter,
981                        const struct libtrace_packet_t *packet) {
982#if HAVE_BPF
983        void *linkptr = 0;
984        int clen = 0;
985        assert(filter);
986        assert(packet);
987        linkptr = trace_get_link(packet);
988        if (!linkptr) {
989                return 0;
990        }
991
992        /* We need to compile it now, because before we didn't know what the
993         * link type was
994         */
995        if (trace_bpf_compile(filter,packet)==-1)
996                return -1;
997       
998        clen = trace_get_capture_length(packet);
999
1000        assert(filter->flag);
1001        return bpf_filter(filter->filter.bf_insns, linkptr, clen, clen);
1002#else
1003        fprintf(stderr,"This version of libtrace does not have bpf filter support\n");
1004        return 0;
1005#endif
1006}
1007
1008/* Set the direction flag, if it has one
1009 * @param packet the packet opaque pointer
1010 * @param direction the new direction (0,1,2,3)
1011 * @returns a signed value containing the direction flag, or -1 if this is not supported
1012 * @author Daniel Lawson
1013 */
1014DLLEXPORT int8_t trace_set_direction(struct libtrace_packet_t *packet, int8_t direction) {
1015        assert(packet);
1016        assert(packet->size>0 && packet->size<65536);
1017        if (packet->trace->format->set_direction) {
1018                return packet->trace->format->set_direction(packet,direction);
1019        }
1020        return -1;
1021}
1022
1023/* Get the direction flag, if it has one
1024 * @param packet a pointer to a libtrace_packet structure
1025 * @returns a signed value containing the direction flag, or -1 if this is not supported
1026 * The direction is defined as 0 for packets originating locally (ie, outbound)
1027 * and 1 for packets originating remotely (ie, inbound).
1028 * Other values are possible, which might be overloaded to mean special things
1029 * for a special trace.
1030 * @author Daniel Lawson
1031 */
1032DLLEXPORT int8_t trace_get_direction(const struct libtrace_packet_t *packet) {
1033        assert(packet);
1034        assert(packet->size>0 && packet->size<65536);
1035        if (packet->trace->format->get_direction) {
1036                return packet->trace->format->get_direction(packet);
1037        }
1038        return -1;
1039}
1040
1041#define ROOT_SERVER(x) ((x) < 512)
1042#define ROOT_CLIENT(x) ((512 <= (x)) && ((x) < 1024))
1043#define NONROOT_SERVER(x) ((x) >= 5000)
1044#define NONROOT_CLIENT(x) ((1024 <= (x)) && ((x) < 5000))
1045#define DYNAMIC(x) ((49152 < (x)) && ((x) < 65535))
1046#define SERVER(x) ROOT_SERVER(x) || NONROOT_SERVER(x)
1047#define CLIENT(x) ROOT_CLIENT(x) || NONROOT_CLIENT(x)
1048
1049/* Attempt to deduce the 'server' port
1050 * @param protocol the IP protocol (eg, 6 or 17 for TCP or UDP)
1051 * @param source the TCP or UDP source port
1052 * @param dest the TCP or UDP destination port
1053 * @returns a hint as to which port is the server port
1054 * @author Daniel Lawson
1055 */
1056DLLEXPORT int8_t trace_get_server_port(uint8_t protocol UNUSED, uint16_t source, uint16_t dest) {
1057        /*
1058         * * If the ports are equal, return DEST
1059         * * Check for well-known ports in the given protocol
1060         * * Root server ports: 0 - 511
1061         * * Root client ports: 512 - 1023
1062         * * non-root client ports: 1024 - 4999
1063         * * non-root server ports: 5000+
1064         * * Check for static ranges: 1024 - 49151
1065         * * Check for dynamic ranges: 49152 - 65535
1066         * * flip a coin.
1067         */
1068       
1069        /* equal */
1070        if (source == dest)
1071                return USE_DEST;
1072
1073        /* root server port, 0 - 511 */
1074        if (ROOT_SERVER(source) && ROOT_SERVER(dest)) {
1075                if (source < dest)
1076                        return USE_SOURCE;
1077                return USE_DEST;
1078        }
1079
1080        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1081                return USE_SOURCE;
1082        if (!ROOT_SERVER(source) && ROOT_SERVER(dest))
1083                return USE_DEST;
1084
1085        /* non-root server */
1086        if (NONROOT_SERVER(source) && NONROOT_SERVER(dest)) {
1087                if (source < dest)
1088                        return USE_SOURCE;
1089                return USE_DEST;
1090        }
1091        if (NONROOT_SERVER(source) && !NONROOT_SERVER(dest))
1092                return USE_SOURCE;
1093        if (!NONROOT_SERVER(source) && NONROOT_SERVER(dest))
1094                return USE_DEST;
1095
1096        /* root client */
1097        if (ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1098                if (source < dest)
1099                        return USE_SOURCE;
1100                return USE_DEST;
1101        }
1102        if (ROOT_CLIENT(source) && !ROOT_CLIENT(dest)) {
1103                /* prefer root-client over nonroot-client */
1104                if (NONROOT_CLIENT(dest))
1105                        return USE_SOURCE;
1106                return USE_DEST;
1107        }
1108        if (!ROOT_CLIENT(source) && ROOT_CLIENT(dest)) {
1109                /* prefer root-client over nonroot-client */
1110                if (NONROOT_CLIENT(source))
1111                        return USE_DEST;
1112                return USE_SOURCE;
1113        }
1114       
1115        /* nonroot client */
1116        if (NONROOT_CLIENT(source) && NONROOT_CLIENT(dest)) {
1117                if (source < dest) 
1118                        return USE_SOURCE;
1119                return USE_DEST;
1120        }
1121        if (NONROOT_CLIENT(source) && !NONROOT_CLIENT(dest))
1122                return USE_DEST;
1123        if (!NONROOT_CLIENT(source) && NONROOT_CLIENT(dest))
1124                return USE_SOURCE;
1125
1126        /* dynamic range */
1127        if (DYNAMIC(source) && DYNAMIC(dest))
1128                if (source < dest)
1129                        return USE_SOURCE;
1130                return USE_DEST;
1131        if (DYNAMIC(source) && !DYNAMIC(dest))
1132                return USE_DEST;
1133        if (!DYNAMIC(source) && DYNAMIC(dest))
1134                return USE_SOURCE;
1135        /*
1136        if (SERVER(source) && CLIENT(dest))
1137                return USE_SOURCE;
1138       
1139        if (SERVER(dest) && CLIENT(source))
1140                return USE_DEST;
1141        if (ROOT_SERVER(source) && !ROOT_SERVER(dest))
1142                return USE_SOURCE;
1143        if (ROOT_SERVER(dest) && !ROOT_SERVER(source))
1144                return USE_DEST;
1145        */
1146        /* failing that test... */
1147        if (source < dest) {
1148                return USE_SOURCE;
1149        } 
1150        return USE_DEST;
1151       
1152}
1153
1154/* Truncate the packet at the suggested length
1155 * @param packet        the packet opaque pointer
1156 * @param size          the new length of the packet
1157 * @returns the new size of the packet
1158 * @note size and the return size refer to the network-level payload of the
1159 * packet, and do not include any capture headers. For example, to truncate a
1160 * packet after the IP header, set size to sizeof(ethernet_header) +
1161 * sizeof(ip_header)
1162 * @note If the original network-level payload is smaller than size, then the
1163 * original size is returned and the packet is left unchanged.
1164 * @author Daniel Lawson
1165 */
1166DLLEXPORT size_t trace_set_capture_length(struct libtrace_packet_t *packet, size_t size) {
1167        assert(packet);
1168        assert(packet->size>0 && packet->size<65536);
1169
1170        if (packet->trace->format->set_capture_length) {
1171                int caplen=packet->trace->format->set_capture_length(packet,size);
1172                if (caplen!=-1) {
1173                        packet->size=trace_get_framing_length(packet)+caplen;
1174                }
1175                return caplen;
1176        }
1177
1178        return -1;
1179}
1180
1181DLLEXPORT const char * trace_parse_uri(const char *uri, char **format) {
1182        const char *uridata = 0;
1183       
1184        if((uridata = strchr(uri,':')) == NULL) {
1185                /* badly formed URI - needs a : */
1186                return 0;
1187        }
1188
1189        if ((uridata - uri) > URI_PROTO_LINE) {
1190                /* badly formed URI - uri type is too long */
1191                return 0;
1192        }
1193
1194        *format=xstrndup(uri, (uridata - uri));
1195
1196        /* push uridata past the delimiter */
1197        uridata++;
1198       
1199        return uridata;
1200}
1201
1202enum base_format_t trace_get_format(struct libtrace_packet_t *packet) 
1203{
1204        assert(packet);
1205
1206        return packet->trace->format->type;
1207}
1208       
1209DLLEXPORT libtrace_err_t trace_get_err(libtrace_t *trace)
1210{
1211        libtrace_err_t err = trace->err;
1212        trace->err.err_num = 0; /* "OK" */
1213        trace->err.problem[0]='\0';
1214        return err;
1215}
1216
1217DLLEXPORT bool trace_is_err(libtrace_t *trace)
1218{
1219        return trace->err.err_num != 0;
1220}
1221
1222DLLEXPORT void trace_perror(libtrace_t *trace,const char *msg,...)
1223{
1224        char buf[256];
1225        va_list va;
1226        va_start(va,msg);
1227        vsnprintf(buf,sizeof(buf),msg,va);
1228        va_end(va);
1229        if(trace->err.err_num) {
1230                fprintf(stderr,"%s(%s): %s\n",
1231                                buf,trace->uridata,trace->err.problem);
1232        } else {
1233                fprintf(stderr,"%s(%s): No error\n",
1234                                buf,trace->uridata);
1235        }
1236        trace->err.err_num = 0; /* "OK" */
1237        trace->err.problem[0]='\0';
1238}
1239
1240DLLEXPORT libtrace_err_t trace_get_err_output(libtrace_out_t *trace)
1241{
1242        libtrace_err_t err = trace->err;
1243        trace->err.err_num = 0; /* "OK" */
1244        trace->err.problem[0]='\0';
1245        return err;
1246}
1247
1248DLLEXPORT bool trace_is_err_output(libtrace_out_t *trace)
1249{
1250        return trace->err.err_num != 0;
1251}
1252
1253DLLEXPORT void trace_perror_output(libtrace_out_t *trace,const char *msg,...)
1254{
1255        char buf[256];
1256        va_list va;
1257        va_start(va,msg);
1258        vsnprintf(buf,sizeof(buf),msg,va);
1259        va_end(va);
1260        if(trace->err.err_num) {
1261                fprintf(stderr,"%s(%s): %s\n",
1262                                buf,trace->uridata,trace->err.problem);
1263        } else {
1264                fprintf(stderr,"%s(%s): No error\n",buf,trace->uridata);
1265        }
1266}
1267
1268DLLEXPORT int trace_seek_erf_timestamp(libtrace_t *trace, uint64_t ts)
1269{
1270        if (trace->format->seek_erf) {
1271                return trace->format->seek_erf(trace,ts);
1272        }
1273        else {
1274                if (trace->format->seek_timeval) {
1275                        struct timeval tv;
1276#if __BYTE_ORDER == __BIG_ENDIAN
1277                        tv.tv_sec = ts & 0xFFFFFFFF;
1278#elif __BYTE_ORDER == __LITTLE_ENDIAN
1279                        tv.tv_sec = ts >> 32;
1280#else
1281#error "What on earth are you running this on?"
1282#endif
1283                        tv.tv_usec = ((ts&0xFFFFFFFF)*1000000)>>32;
1284                        if (tv.tv_usec >= 1000000) {
1285                                tv.tv_usec -= 1000000;
1286                                tv.tv_sec += 1;
1287                        }
1288                        return trace->format->seek_timeval(trace,tv);
1289                }
1290                if (trace->format->seek_seconds) {
1291                        double seconds = 
1292                                (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
1293                        return trace->format->seek_seconds(trace,seconds);
1294                }
1295                trace_set_err(trace,
1296                                TRACE_ERR_OPTION_UNAVAIL,
1297                                "Feature unimplemented");
1298                return -1;
1299        }
1300}
1301
1302DLLEXPORT int trace_seek_seconds(libtrace_t *trace, double seconds)
1303{
1304        if (trace->format->seek_seconds) {
1305                return trace->format->seek_seconds(trace,seconds);
1306        }
1307        else {
1308                if (trace->format->seek_timeval) {
1309                        struct timeval tv;
1310                        tv.tv_sec = (uint32_t)seconds;
1311                        tv.tv_usec = (uint32_t)(((seconds - tv.tv_sec) * 1000000)/UINT_MAX);
1312                        return trace->format->seek_timeval(trace,tv);
1313                }
1314                if (trace->format->seek_erf) {
1315                        uint64_t timestamp = 
1316                                ((uint64_t)((uint32_t)seconds) << 32) + \
1317                            (uint64_t)(( seconds - (uint32_t)seconds   ) * UINT_MAX);
1318                        return trace->format->seek_erf(trace,timestamp);
1319                }
1320                trace_set_err(trace,
1321                                TRACE_ERR_OPTION_UNAVAIL,
1322                                "Feature unimplemented");
1323                return -1;
1324        }
1325}
1326
1327DLLEXPORT int trace_seek_timeval(libtrace_t *trace, struct timeval tv)
1328{
1329        if (trace->format->seek_timeval) {
1330                return trace->format->seek_timeval(trace,tv);
1331        }
1332        else {
1333                if (trace->format->seek_erf) {
1334                        uint64_t timestamp = ((((uint64_t)tv.tv_sec) << 32) + \
1335                                (((uint64_t)tv.tv_usec * UINT_MAX)/1000000));
1336                        return trace->format->seek_erf(trace,timestamp);
1337                }
1338                if (trace->format->seek_seconds) {
1339                        double seconds = tv.tv_sec + ((tv.tv_usec * 1.0)/1000000);
1340                        return trace->format->seek_seconds(trace,seconds);
1341                }
1342                trace_set_err(trace,
1343                                TRACE_ERR_OPTION_UNAVAIL,
1344                                "Feature unimplemented");
1345                return -1;
1346        }
1347}
1348
1349DLLEXPORT char *trace_ether_ntoa(const uint8_t *addr, char *buf)
1350{
1351        char *buf2 = buf;
1352        static char staticbuf[18]={0,};
1353        if (!buf2)
1354                buf2=staticbuf;
1355        snprintf(buf2,18,"%02x:%02x:%02x:%02x:%02x:%02x",
1356                        addr[0],addr[1],addr[2],
1357                        addr[3],addr[4],addr[5]);
1358        return buf2;
1359}
1360
1361DLLEXPORT uint8_t *trace_ether_aton(const char *buf, uint8_t *addr)
1362{
1363        uint8_t *buf2 = addr;
1364        unsigned int tmp[6];
1365        static uint8_t staticaddr[6];
1366        if (!buf2)
1367                buf2=staticaddr;
1368        sscanf(buf,"%x:%x:%x:%x:%x:%x",
1369                        &tmp[0],&tmp[1],&tmp[2],
1370                        &tmp[3],&tmp[4],&tmp[5]);
1371        buf2[0]=tmp[0]; buf2[1]=tmp[1]; buf2[2]=tmp[2];
1372        buf2[3]=tmp[3]; buf2[4]=tmp[4]; buf2[5]=tmp[5];
1373        return buf2;
1374}
1375
Note: See TracBrowser for help on using the repository browser.