source: lib/trace.c @ dadc609

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

fixed get_timeval to return a correct tv from ERF type records

  • Property mode set to 100644
File size: 29.2 KB
Line 
1/** @file
2 *
3 * @brief Trace file processing library
4 *
5 * @author Daniel Lawson
6 * @author Perry Lorier
7 *
8 */
9// $Id$
10#define _GNU_SOURCE
11#include <assert.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <net/ethernet.h>
15#include <netdb.h>
16#include <pcap.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <unistd.h>
25#include <time.h>
26#include <sys/ioctl.h>
27
28#include "libtrace.h"
29#include "fifo.h"
30
31#include "dagformat.h"
32
33#include "wag.h"
34
35#include <zlib.h>
36
37
38typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
39
40typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
41
42struct libtrace_t {
43        format_t format;
44        source_t sourcetype;
45        union {
46                struct {
47                        char *hostname;
48                        short port;
49                } rt;
50                char *path;
51                char *interface;
52        } conn_info;
53        union {
54                int fd;
55                gzFile *file;
56                pcap_t *pcap;
57        } input;
58        struct fifo_t *fifo;   
59        struct {
60                void *buffer;
61                int size;
62        } packet;
63        double last_ts;
64        double start_ts;
65};
66
67static int init_trace(struct libtrace_t **libtrace, char *uri) {
68        char *scan = calloc(sizeof(char),16);
69        char *uridata;
70       
71        // parse the URI to determine what sort of event we are dealing with
72       
73        // want snippet before the : to get the uri base type.
74
75        if((uridata = strchr(uri,':')) == NULL) {
76                // badly formed URI
77                return 0;
78        }
79
80        if ((*uridata - *uri) > 16) {
81                // badly formed URI
82                return 0;
83        }
84        strncpy(scan,uri, (uridata - uri));
85
86        if (!strncasecmp(scan,"erf",3)) {
87                (*libtrace)->format=ERF;
88        } else if (!strncasecmp(scan,"pcapint",7)) {
89                (*libtrace)->format=PCAPINT;
90        } else if (!strncasecmp(scan,"pcap",4)) {
91                (*libtrace)->format=PCAP;
92        } else if (!strncasecmp(scan,"dag",3)) {
93                (*libtrace)->format=DAG;
94        } else if (!strncasecmp(scan,"rtclient",7)) {
95                (*libtrace)->format=RTCLIENT;
96        } else if (!strncasecmp(scan,"wagint",6)) {
97                (*libtrace)->format=WAGINT;
98        } else if (!strncasecmp(scan,"wag",3)) {
99                (*libtrace)->format=WAG;
100        } else {
101                //badly formed URI
102                return 0;
103        }
104       
105        // push uridata past the delimiter
106        uridata++;
107       
108        // libtrace->format now contains the type of uri
109        // libtrace->uridata contains the appropriate data for this
110       
111        switch((*libtrace)->format) {
112                case PCAPINT:
113                case WAGINT:
114                        /* Can have uridata of the following format
115                         * eth0
116                         * etc
117                         */
118                        // We basically assume this is correct.
119                        (*libtrace)->sourcetype = INTERFACE;   
120                        (*libtrace)->conn_info.path = strdup(uridata);
121                        break;
122                case PCAP:
123                case ERF:
124                case WAG:
125                case DAG:
126                        /*
127                         * Can have uridata of the following format
128                         * /path/to/socket
129                         * /path/to/file
130                         * /path/to/file.gz
131                         * /dev/device
132                         * -
133                         */
134                        if (!strncmp(uridata,"-",1)) {
135                                (*libtrace)->sourcetype = STDIN;
136                        } else {
137                                struct stat buf;
138                                if (stat(uridata,&buf) == -1) {
139                                        perror("stat");
140                                        return 0;
141                                }
142                                if (S_ISSOCK(buf.st_mode)) {
143                                        (*libtrace)->sourcetype = SOCKET;
144                                } else if (S_ISCHR(buf.st_mode)) {
145                                        (*libtrace)->sourcetype = DEVICE;
146                                } else {
147                                        (*libtrace)->sourcetype = TRACE;
148                                }
149                                (*libtrace)->conn_info.path = strdup(uridata);
150                        }
151                        break;
152
153                case RTCLIENT:
154                        /*
155                         * Can have the uridata in the format
156                         * hostname
157                         * hostname:port
158                         */
159                        (*libtrace)->sourcetype = RT;
160                        if (strlen(uridata) == 0) {
161                                (*libtrace)->conn_info.rt.hostname = 
162                                        strdup("localhost");
163                                (*libtrace)->conn_info.rt.port = 
164                                        COLLECTOR_PORT;
165                                break;
166                        }
167                        if ((scan = strchr(uridata,':')) == NULL) {
168                                (*libtrace)->conn_info.rt.hostname = 
169                                        strdup(uridata);
170                                (*libtrace)->conn_info.rt.port = 
171                                        COLLECTOR_PORT;
172                        } else {
173                                (*libtrace)->conn_info.rt.hostname =
174                                        strndup(uridata,(scan - uridata));
175                                       
176                                (*libtrace)->conn_info.rt.port = 
177                                        atoi(++scan);                           
178                        }
179                        break;
180        }
181       
182
183        (*libtrace)->fifo = create_fifo(1048576);
184        (*libtrace)->packet.buffer = 0;
185        (*libtrace)->packet.size = 0;
186
187        return 1;
188}
189
190/** Create a trace file from a URI
191 *
192 * @returns opaque pointer to a libtrace_t
193 *
194 * Valid URI's are:
195 *  - erf:/path/to/erf/file
196 *  - erf:/path/to/erf/file.gz
197 *  - erf:/path/to/rtclient/socket
198 *  - erf:-  (stdin)
199 *  - dag:/dev/dagcard                  (implementd?)
200 *  - pcap:pcapinterface                (eg: pcap:eth0)
201 *  - pcap:/path/to/pcap/file
202 *  - pcap:/path/to/pcap/file.gz
203 *  - pcap:/path/to/pcap/socket         (implemented?)
204 *  - pcap:-
205 *  - rtclient:hostname
206 *  - rtclient:hostname:port
207 *  - wag:/path/to/wag/file
208 *  - wag:/path/to/wag/file.gz
209 *  - wag:/path/to/wag/socket
210 *  - wag:/dev/device
211 *
212 *  If an error occured why attempting to open the trace file, NULL is returned
213 *  and an error is output to stdout.
214 */
215struct libtrace_t *create_trace(char *uri) {
216        struct libtrace_t *libtrace = malloc(sizeof(struct libtrace_t));
217        struct hostent *he;
218        struct sockaddr_in remote;
219        struct sockaddr_un unix_sock;
220        char errbuf[PCAP_ERRBUF_SIZE];
221
222        if(init_trace(&libtrace,uri) == 0) {
223                return 0;
224        }
225       
226        switch(libtrace->sourcetype) {
227                case RT:
228                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) { 
229                                perror("gethostbyname");
230                                return 0;
231                        } 
232                        if ((libtrace->input.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
233                                perror("socket");
234                                return 0;
235                        }
236
237                        remote.sin_family = AF_INET;   
238                        remote.sin_port = htons(libtrace->conn_info.rt.port);
239                        remote.sin_addr = *((struct in_addr *)he->h_addr);
240                        bzero(&(remote.sin_zero), 8);
241
242                        if (connect(libtrace->input.fd, (struct sockaddr *)&remote,
243                                                sizeof(struct sockaddr)) == -1) {
244                                perror("connect (inet)");
245                                return 0;
246                        }
247                        break;
248                case TRACE:
249                        if (libtrace->format == PCAP) {
250                                libtrace->input.pcap = pcap_open_offline(libtrace->conn_info.path, errbuf); 
251                        } else {
252                                libtrace->input.file = gzopen(libtrace->conn_info.path, "r");
253                        }
254                        break;
255                case STDIN:
256                        if (libtrace->format == PCAP) {
257                                libtrace->input.pcap = pcap_open_offline("-",errbuf); 
258                        } else {
259                                libtrace->input.file = gzdopen(STDIN, "r");
260                        }
261                        break;
262                case SOCKET:
263                        /* Pcap doesn't work */
264                        if (libtrace->format != PCAP) {
265                                if ((libtrace->input.fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
266                                        perror("socket");
267                                        return 0;
268                                }
269                                unix_sock.sun_family = AF_UNIX;
270                                bzero(unix_sock.sun_path,108);
271                                snprintf(unix_sock.sun_path,108,"%s",libtrace->conn_info.path);
272
273                                if (connect(libtrace->input.fd, (struct sockaddr *)&unix_sock,
274                                                        sizeof(struct sockaddr)) == -1) {
275                                        perror("connect (unix)");
276                                        return 0;
277                                }
278                        }
279                        break;
280                case DEVICE:
281                case INTERFACE:
282                        switch (libtrace->format) {
283                                case PCAPINT:
284                                case PCAP:
285                                        libtrace->input.pcap = pcap_open_live(
286                                                libtrace->conn_info.path,
287                                                4096,
288                                                1,
289                                                0,
290                                                errbuf);
291                                        break;
292                                default:
293                                        fprintf(stderr,"Unknown format trace, hoping I can just read\n");
294                                case WAGINT:
295                                case WAG:
296                                        libtrace->input.fd = open(
297                                                libtrace->conn_info.path,
298                                                O_RDONLY);
299                                        break;
300                        }
301                        break;
302                default:
303                        fprintf(stderr,"Unsupported source type for libtrace, terminating (%i)\n",libtrace->sourcetype);
304                        exit(0);
305               
306        }
307        return libtrace;
308}
309
310/** Close a trace file, freeing up any resources it may have been using
311 *
312 */
313void destroy_trace(struct libtrace_t *libtrace) {
314        assert(libtrace);
315        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
316                pcap_close(libtrace->input.pcap);
317        } else if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
318                close(libtrace->input.fd);
319        } else {
320                gzclose(libtrace->input.file);
321        }       
322        // need to free things!
323        destroy_fifo(libtrace->fifo);
324        free(libtrace);
325}
326
327static int libtrace_read(struct libtrace_t *libtrace, void *buffer, size_t len) {
328        int numbytes;
329        assert(libtrace);
330        assert(len >= 0);
331
332        if (buffer == 0)
333                buffer = malloc(len);
334
335        /* TODO: Make me a switch */
336        if(libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
337                // read from the network
338                if ((numbytes=recv(libtrace->input.fd, buffer, len, 0)) == -1) {
339                        perror("recv");
340                        return -1;
341                }
342        } else if (libtrace->sourcetype == DEVICE) {
343                if ((numbytes=read(libtrace->input.fd, buffer, len)) == -1) {
344                        perror("read");
345                        return -1;
346                }
347        } else {
348                if ((numbytes=gzread(libtrace->input.file,buffer,len)) == -1) {
349                        perror("gzread");
350                        return -1;
351                }
352        }
353        return numbytes;
354
355}
356
357/** Read one packet from the trace into buffer
358 *
359 * @param libtrace      the trace to read from
360 * @param buffer        the buffer to read into
361 * @param len           the length of the buffer
362 * @returns number of bytes copied.
363 *
364 * @note the buffer must be at least as large as the largest packet (plus
365 * link layer, and trace packet metadata overhead)
366 */
367int libtrace_read_packet(struct libtrace_t *libtrace, void *buffer, size_t len, int *status) {
368        int numbytes;
369        int size;
370        char buf[4096];
371        struct pcap_pkthdr pcaphdr;
372        const u_char *pcappkt;
373        int read_required = 0;
374        if (!libtrace) {
375                fprintf(stderr,"Oi! You called libtrace_read_packet() with a NULL libtrace parameter!\n");
376        }
377        assert(libtrace);
378        assert(buffer);
379        assert(status);
380        assert(len > 104); // we know we see packets this big anyway. Don't be silly.
381
382        bzero(buffer,len);
383       
384        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
385                if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
386                        return -1;
387                }
388                memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
389                memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,pcaphdr.len);
390                numbytes = pcaphdr.len;
391
392                return numbytes;
393        } 
394
395        do {
396                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
397                        if ((numbytes = libtrace_read(libtrace,buf,4096))<=0){
398                                return numbytes; 
399                        }
400                        fifo_write(libtrace->fifo,buf,numbytes);
401
402                        read_required = 0;
403                }
404
405                switch (libtrace->format) {
406                        case RTCLIENT:
407                                // only do this if we're reading from the RT interface
408                                if (fifo_out_read(libtrace->fifo, status, sizeof(int)) == 0) {
409                                        read_required = 1;
410                                        continue;
411                                }
412
413                                fifo_out_update(libtrace->fifo,sizeof(int));
414
415                                /* FALL THRU */
416                        case ERF:
417                        case DAG:
418                                // read in the erf header
419                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
420                                        fifo_out_reset(libtrace->fifo);
421                                        read_required = 1;
422                                        continue;
423                                }
424
425                                size = ntohs(((dag_record_t *)buffer)->rlen);
426                                break;
427                        case WAG:
428                                if ((numbytes = fifo_out_read(libtrace->fifo,
429                                                                &size,
430                                                                sizeof(size))) 
431                                                                == 0) {
432                                        fifo_out_reset(libtrace->fifo);
433                                        read_required = 1;
434                                        continue;
435                                }
436                                size*=4;
437                                break;
438                        default:
439                                fprintf(stderr,"Unknown type in _read()\n");
440                                assert(0);
441                }
442
443                assert(len > size);
444
445                // read in the full packet
446                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
447                        fifo_out_reset(libtrace->fifo);
448                        read_required = 1;
449                        continue;
450                }
451
452                // got in our whole packet, so...
453                fifo_out_update(libtrace->fifo,size);
454
455                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
456                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
457                } else {
458                        fifo_ack_update(libtrace->fifo,size);
459                }
460               
461                return numbytes;
462
463        } while (1);
464}
465
466
467/** get a pointer to the link layer
468 * @param libtrace      a pointer to the trace object returned from gettrace
469 * @param buffer        a pointer to a filled in buffer
470 * @param buflen        a pointer to the size of the buffer
471 *
472 * @returns a pointer to the link layer, or NULL if there is no link layer
473 * you should call get_link_type() to find out what type of link layer this is
474 */
475void *get_link(struct libtrace_t *libtrace, void *buffer, int buflen) {
476        void *ethptr = 0;
477        struct wag_event_t *event = buffer;
478        struct wag_data_event_t *data_event;
479       
480        switch(libtrace->format) {
481                case ERF:
482                case DAG:
483                case RTCLIENT:
484                        // DAG people are insane, deal with ethernet having
485                        // some extra padding and crap
486                        if (get_link_type(libtrace,buffer,buflen)==TRACE_TYPE_ETH) 
487                                ethptr = ((uint8_t *)buffer + 16 + 2);
488                        else
489                                ethptr = ((uint8_t *)buffer + 16 + 2);
490                        break;
491                case PCAPINT:
492                case PCAP:
493                        ethptr = (struct ether_header *)(buffer + sizeof(struct pcap_pkthdr));
494                        break;
495                case WAGINT:
496                case WAG:
497                        switch (event->type) {
498                                case 0x0:
499                                        data_event = (void*)&(event->payload);
500                                        return data_event->data;
501                                default:
502                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
503                                        return NULL;
504                        }
505                       
506                default:
507                        fprintf(stderr,"Dunno this trace format\n");
508                        assert(0);
509        }
510        return ethptr;
511}
512
513/** get a pointer to the IP header (if any)
514 * @param libtrace      a pointer to the trace object returned from gettrace
515 * @param buffer        a pointer to a filled in buffer
516 * @param buflen        a pointer to the size of the buffer
517 *
518 * @returns a pointer to the IP header, or NULL if there is not an IP packet
519 */
520struct libtrace_ip *get_ip(struct libtrace_t *libtrace, void *buffer, int buflen) {
521        struct libtrace_ip *ipptr = 0;
522
523        switch(get_link_type(libtrace,buffer,buflen)) {
524                case TRACE_TYPE_80211:
525                        { 
526                               
527                                struct ieee_802_11_header *wifi = get_link(libtrace, buffer, buflen);   
528
529                                // Data packet?
530                                if (wifi->type != 2) {
531                                        ipptr = NULL;
532                                }
533                                else {
534                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
535                                        if (eth->type != 0x0008) {
536                                                ipptr=NULL;
537                                        } else {
538                                                ipptr=(void*)eth->data;
539                                        }
540                                }
541                        }
542                        break;
543                case TRACE_TYPE_ETH:
544                        {
545                                struct ether_header *eth = get_link(libtrace,
546                                                buffer, buflen);
547                                if (ntohs(eth->ether_type)!=0x0800) {
548                                        ipptr = NULL;
549                                }
550                                else {
551                                        ipptr = ((void *)eth) + 14;
552                                }
553                                break;
554                        }
555                case TRACE_TYPE_ATM:
556                        {
557                                struct atm_rec *atm = get_link(libtrace,
558                                                buffer, buflen);
559                                // TODO: Find out what ATM does, and return
560                                //       NULL for non IP data
561                                //       Presumably it uses the normal stuff
562                                ipptr =  (void*)&atm->pload;
563                                break;
564                        }
565                default:
566                        fprintf(stderr,"Don't understand link layer type %i in get_ip()\n",
567                                get_link_type(libtrace,buffer,buflen));
568                        ipptr=NULL;
569                        break;
570        }
571
572        return ipptr;
573}
574
575
576/** get a pointer to the TCP header (if any)
577 * @param libtrace      a pointer to the trace object returned from gettrace
578 * @param buffer        a pointer to a filled in buffer
579 * @param buflen        a pointer to the size of the buffer
580 *
581 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
582 */
583struct libtrace_tcp *get_tcp(struct libtrace_t *libtrace, void *buffer, int buflen) {
584        struct libtrace_tcp *tcpptr = 0;
585        struct libtrace_ip *ipptr = 0;
586
587        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
588                return 0;
589        }
590        if (ipptr->ip_p == 6) {
591                tcpptr = (struct libtrace_tcp *)((int)ipptr + (ipptr->ip_hl * 4));
592        }
593        return tcpptr;
594}
595
596/** get a pointer to the UDP header (if any)
597 * @param libtrace      a pointer to the trace object returned from gettrace
598 * @param buffer        a pointer to a filled in buffer
599 * @param buflen        a pointer to the size of the buffer
600 *
601 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
602 */
603struct libtrace_udp *get_udp(struct libtrace_t *libtrace, void *buffer, int buflen) {
604        struct libtrace_udp *udpptr = 0;
605        struct libtrace_ip *ipptr = 0;
606       
607        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
608                return 0;
609        }
610        if (ipptr->ip_p == 17) {
611                udpptr = (struct libtrace_udp *)((int)ipptr + (ipptr->ip_hl * 4));
612        }
613        return udpptr;
614}
615
616/** get a pointer to the ICMP header (if any)
617 * @param libtrace      a pointer to the trace object returned from gettrace
618 * @param buffer        a pointer to a filled in buffer
619 * @param buflen        a pointer to the size of the buffer
620 *
621 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
622 */
623struct libtrace_icmp *get_icmp(struct libtrace_t *libtrace, void *buffer, int buflen) {
624        struct libtrace_icmp *icmpptr = 0;
625        struct libtrace_ip *ipptr = 0;
626       
627        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
628                return 0;
629        }
630        if (ipptr->ip_p == 1) {
631                icmpptr = (struct libtrace_icmp *)((int)ipptr + (ipptr->ip_hl * 4));
632        }
633        return icmpptr;
634}
635
636/** Get the current time in DAG time format
637 * @param libtrace the libtrace opaque pointer
638 * @param buffer a pointer to a filled in buffer
639 * @param buflen the length of the buffer
640 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
641 * past 1970-01-01, the lower 32bits are partial seconds)
642 * @author Daniel Lawson
643 */ 
644uint64_t get_erf_timestamp(struct libtrace_t *libtrace, void *buffer, int buflen) {
645        uint64_t timestamp = 0;
646        dag_record_t *erfptr = 0;
647        struct pcap_pkthdr *pcapptr = 0;
648        struct wag_event_t *wagptr = 0;
649        switch (libtrace->format) {
650                case DAG:
651                case ERF:
652                case RTCLIENT:
653                        erfptr = (dag_record_t *)buffer;
654                        timestamp = erfptr->ts;
655                        break;
656                case PCAPINT:
657                case PCAP:
658                        pcapptr = (struct pcap_pkthdr *)buffer;
659                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
660                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
661                        break;
662                case WAGINT:
663                case WAG:
664                        wagptr = buffer;
665                        timestamp = wagptr->timestamp_lo;
666                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
667                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
668                                  | ((timestamp/44000000)<<32);
669                        break;
670                default:
671                        fprintf(stderr,"Unknown format in get_erf_timestamp\n");
672                        timestamp = 0;
673        }
674        return timestamp;
675}
676
677/** Get the current time in struct timeval
678 * @param libtrace the libtrace opaque pointer
679 * @param buffer a pointer to a filled in buffer
680 * @param buflen the length of the buffer
681 * @returns time that this packet was seen in a struct timeval
682 * @author Daniel Lawson
683 * @author Perry Lorier
684 */ 
685struct timeval get_timeval(struct libtrace_t *libtrace, void *buffer, int buflen) {
686        struct timeval tv;
687        struct pcap_pkthdr *pcapptr = 0;
688        uint64_t ts;
689        uint32_t seconds;
690        switch (libtrace->format) {
691                case PCAPINT:
692                case PCAP:
693                        pcapptr = (struct pcap_pkthdr *)buffer;
694                        tv = pcapptr->ts;
695                        break;
696                case WAGINT:
697                case WAG:
698                case DAG:
699                case ERF:
700                case RTCLIENT:
701                default:
702                        // FIXME: This isn't portable to big-endian machines
703                        ts = get_erf_timestamp(libtrace,buffer,buflen);
704                        tv.tv_sec = ts >> 32;           
705                        ts = (1000000 * (ts & 0xffffffffULL));
706                        ts += (ts & 0x80000000ULL) << 1;
707                        tv.tv_usec = ts >> 32;
708                        if (tv.tv_usec >= 1000000) {
709                                tv.tv_usec -= 1000000;
710                                tv.tv_sec += 1;
711                        }
712                        break;
713        }
714        return tv;
715}
716
717/** Get the current time in floating point seconds
718 * @param libtrace the libtrace opaque pointer
719 * @param buffer a pointer to a filled in buffer
720 * @param buflen the length of the buffer
721 * @returns time that this packet was seen in 64bit floating point seconds
722 * @author Perry Lorier
723 */ 
724double get_seconds(struct libtrace_t *libtrace, void *buffer, int buflen) {
725        uint64_t ts;
726        ts = get_erf_timestamp(libtrace,buffer,buflen);
727        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
728}
729
730/** Get the size of the packet in the trace
731 * @param libtrace the libtrace opaque pointer
732 * @param buffer a pointer to a filled in buffer
733 * @param buflen the length of the buffer
734 * @returns the size of the packet in the trace
735 * @author Perry Lorier
736 * @note Due to this being a header capture, or anonymisation, this may not
737 * be the same size as the original packet.  See get_wire_length() for the
738 * original size of the packet.
739 * @note This can (and often is) different for different packets in a trace!
740 * @par
741 *  This is sometimes called the "snaplen".
742 */ 
743int get_capture_length(struct libtrace_t *libtrace, void *buffer, int buflen) {
744        dag_record_t *erfptr = 0;
745        struct pcap_pkthdr *pcapptr = 0;
746        struct wag_event_t *wag_event;
747        switch (libtrace->format) {
748                case DAG:
749                case ERF:
750                case RTCLIENT:
751                        erfptr = (dag_record_t *)buffer;
752                        return ntohs(erfptr->rlen);
753                case PCAPINT:
754                case PCAP:
755                        pcapptr = (struct pcap_pkthdr *)buffer;
756                        return ntohs(pcapptr->caplen);
757                case WAGINT:
758                case WAG:
759                        wag_event = buffer;
760                        switch(wag_event->type) {
761                                case 0:
762                                        return wag_event->length*4-(
763                                                sizeof(struct wag_event_t)+
764                                                sizeof(struct wag_data_event_t)
765                                                );
766                                default:
767                                        assert(0);
768                        }
769                default:
770                        assert(0);
771        }
772        return -1;
773}
774       
775/** Get the size of the packet as it was seen on the wire.
776 * @param libtrace the libtrace opaque pointer
777 * @param buffer a pointer to a filled in buffer
778 * @param buflen the length of the buffer
779 * @returns the size of the packet as it was on the wire.
780 * @author Perry Lorier
781 * @author Daniel Lawson
782 * @note Due to the trace being a header capture, or anonymisation this may
783 * not be the same as the Capture Len.
784 */ 
785int get_wire_length(struct libtrace_t *libtrace, void *buffer, int buflen){
786        dag_record_t *erfptr = 0;
787        struct pcap_pkthdr *pcapptr = 0;
788        struct wag_event_t *wag_event = 0;
789        switch (libtrace->format) {
790                case DAG:
791                case ERF:
792                case RTCLIENT:
793                        erfptr = (dag_record_t *)buffer;
794                        return ntohs(erfptr->wlen);
795                        break;
796                case PCAPINT:
797                case PCAP:
798                        pcapptr = (struct pcap_pkthdr *)buffer;
799                        return ntohs(pcapptr->len);
800                        break;
801                case WAGINT:
802                case WAG:
803                        wag_event = buffer;
804                        switch(wag_event->type) {
805                                case 0:
806                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
807                                default:
808                                        assert(0);
809                        }
810        }
811        return -1;
812
813}
814
815/** Get the type of the link layer
816 * @param libtrace the libtrace opaque pointer
817 * @param buffer a pointer to a filled in buffer
818 * @param buflen the length of the buffer
819 * @returns libtrace_linktype_t
820 * @author Perry Lorier
821 * @author Daniel Lawson
822 */
823libtrace_linktype_t get_link_type(
824                struct libtrace_t *libtrace, 
825                void *buffer, 
826                int buflen) {
827        dag_record_t *erfptr = 0;
828        struct pcap_pkthdr *pcapptr = 0;
829        int linktype = 0;
830        switch (libtrace->format) {
831                case DAG:
832                case ERF:
833                case RTCLIENT:
834                        erfptr = (dag_record_t *)buffer;
835                        switch (erfptr->type) {
836                                case TYPE_ETH: return TRACE_TYPE_ETH;
837                                case TYPE_ATM: return TRACE_TYPE_ATM;
838                                default: assert(0);
839                        }
840                        return erfptr->type;
841                       
842                        break;
843                case PCAPINT:
844                case PCAP:
845                        pcapptr = (struct pcap_pkthdr *)buffer;
846                        linktype = pcap_datalink(libtrace->input.pcap);
847                        switch (linktype) {
848                                case 1:
849                                        return TRACE_TYPE_ETH; 
850                                case 11:
851                                        return TRACE_TYPE_ATM;
852                                case DLT_IEEE802_11:
853                                        return TRACE_TYPE_80211;
854                        }
855                        break;
856                case WAGINT:
857                case WAG:
858                        return TRACE_TYPE_80211;
859        }
860        return -1;
861}
862
863/** Get the source MAC addres
864 * @param libtrace the libtrace opaque pointer
865 * @param buffer a pointer to a filled in buffer
866 * @param buflen the length of the buffer
867 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
868 * @author Perry Lorier
869 */
870uint8_t *get_source_mac(struct libtrace_t *libtrace,
871                void *buffer,
872                int buflen) {
873        void *link = get_link(libtrace,buffer,buflen);
874        struct ieee_802_11_header *wifi = link;
875        struct ether_header *ethptr = link;
876        if (!link)
877                return NULL;
878        switch (get_link_type(libtrace,buffer,buflen)) {
879                case TRACE_TYPE_80211:
880                        return (uint8_t*)&wifi->mac2;
881                case TRACE_TYPE_ETH:
882                        return (uint8_t*)&ethptr->ether_shost;
883                default:
884                        fprintf(stderr,"Not implemented\n");
885                        assert(0);
886        }
887}
888
889/** Get the destination MAC addres
890 * @param libtrace the libtrace opaque pointer
891 * @param buffer a pointer to a filled in buffer
892 * @param buflen the length of the buffer
893 * @returns a pointer to the destination mac, (or NULL if there is no
894 * destination MAC)
895 * @author Perry Lorier
896 */
897uint8_t *get_destination_mac(struct libtrace_t *libtrace,
898                void *buffer,
899                int buflen) {
900        void *link = get_link(libtrace,buffer,buflen);
901        struct ieee_802_11_header *wifi = link;
902        struct ether_header *ethptr = link;
903        if (!link)
904                return NULL;
905        switch (get_link_type(libtrace,buffer,buflen)) {
906                case TRACE_TYPE_80211:
907                        return (uint8_t*)&wifi->mac1;
908                case TRACE_TYPE_ETH:
909                        return (uint8_t*)&ethptr->ether_dhost;
910                default:
911                        fprintf(stderr,"Not implemented\n");
912                        assert(0);
913        }
914}
915
916
917/** process a libtrace event
918 * @returns
919 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
920 *  TRACE_EVENT_SLEEP   Next event in <seconds>
921 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
922 */
923libtrace_event_t libtrace_event(struct libtrace_t *trace,
924                        int *fd,double *seconds,
925                        void *buffer, int *size)
926{
927        *seconds = 0;
928        *fd = 0;
929        /* Is there a packet ready? */
930        switch (trace->sourcetype) {
931                case INTERFACE:
932                        {
933                                int data;
934                                *fd = pcap_fileno(trace->input.pcap);
935                                if(ioctl(*fd,FIONREAD,&data)==-1){
936                                        perror("ioctl(FIONREAD)");
937                                }
938                                if (data>0) {
939                                        return TRACE_EVENT_PACKET;
940                                }
941                                return TRACE_EVENT_IOWAIT;
942                        }
943                case SOCKET:
944                case DEVICE:
945                case RT:
946                        {
947                                int data;
948                                if(ioctl(trace->input.fd,FIONREAD,&data)==-1){
949                                        perror("ioctl(FIONREAD)");
950                                }
951                                if (data>0) {
952                                        return TRACE_EVENT_PACKET;
953                                }
954                                *fd = trace->input.fd;
955                                return TRACE_EVENT_IOWAIT;
956                        }
957                case STDIN:
958                case TRACE:
959                        {
960                                int status;
961                                double ts;
962                                /* "Prime" the pump */
963                                if (!trace->packet.buffer) {
964                                        trace->packet.buffer = malloc(4096);
965                                        trace->packet.size=libtrace_read_packet(trace,
966                                                        trace->packet.buffer,
967                                                        4096,
968                                                        &status);
969                                }
970                                ts=get_seconds(trace,
971                                        trace->packet.buffer,
972                                        trace->packet.size);
973                                if (trace->last_ts!=0) {
974                                        *seconds = ts - trace->last_ts;
975                                        if (*seconds>time(NULL)-trace->start_ts)
976                                                return TRACE_EVENT_SLEEP;
977                                }
978                                else {
979                                        trace->start_ts = time(NULL);
980                                        trace->last_ts = ts;
981                                }
982
983                                *size = trace->packet.size;
984                                memcpy(buffer,trace->packet.buffer,*size);
985
986                                free(trace->packet.buffer);
987                                trace->packet.buffer = 0;
988                                return TRACE_EVENT_PACKET;
989                        }
990                default:
991                        assert(0);
992        }
993        /* Shouldn't get here */
994        assert(0);
995}
Note: See TracBrowser for help on using the repository browser.