source: lib/trace.c @ 101aa76

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

added new uris - pcapint and wagint for specifying pcap and wag interfaces

  • Property mode set to 100644
File size: 29.0 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);
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        if (libtrace->format == PCAP || libtrace->format == PCAPINT) {
383                if ((pcappkt = pcap_next(libtrace->input.pcap, &pcaphdr)) == NULL) {
384                        return -1;
385                }
386                memcpy(buffer,&pcaphdr,sizeof(struct pcap_pkthdr));
387                memcpy(buffer + sizeof(struct pcap_pkthdr),pcappkt,pcaphdr.len);
388                numbytes = pcaphdr.len;
389
390                return numbytes;
391        } 
392
393        do {
394                if (fifo_out_available(libtrace->fifo) == 0 || read_required) {
395                        if ((numbytes = libtrace_read(libtrace,buf,4096))<=0){
396                                return numbytes; 
397                        }
398                        fifo_write(libtrace->fifo,buf,numbytes);
399
400                        read_required = 0;
401                }
402
403                switch (libtrace->format) {
404                        case RTCLIENT:
405                                // only do this if we're reading from the RT interface
406                                if (fifo_out_read(libtrace->fifo, status, sizeof(int)) == 0) {
407                                        read_required = 1;
408                                        continue;
409                                }
410
411                                fifo_out_update(libtrace->fifo,sizeof(int));
412
413                                /* FALL THRU */
414                        case ERF:
415                        case DAG:
416                                // read in the erf header
417                                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
418                                        fifo_out_reset(libtrace->fifo);
419                                        read_required = 1;
420                                        continue;
421                                }
422
423                                size = ntohs(((dag_record_t *)buffer)->rlen);
424                                break;
425                        case WAG:
426                                if ((numbytes = fifo_out_read(libtrace->fifo,
427                                                                &size,
428                                                                sizeof(size))) 
429                                                                == 0) {
430                                        fifo_out_reset(libtrace->fifo);
431                                        read_required = 1;
432                                        continue;
433                                }
434                                size*=4;
435                                break;
436                        default:
437                                fprintf(stderr,"Unknown type in _read()\n");
438                                assert(0);
439                }
440
441                assert(len > size);
442
443                // read in the full packet
444                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
445                        fifo_out_reset(libtrace->fifo);
446                        read_required = 1;
447                        continue;
448                }
449
450                // got in our whole packet, so...
451                fifo_out_update(libtrace->fifo,size);
452
453                if (libtrace->sourcetype == SOCKET || libtrace->sourcetype == RT) {
454                        fifo_ack_update(libtrace->fifo,size + sizeof(int));
455                } else {
456                        fifo_ack_update(libtrace->fifo,size);
457                }
458               
459                return numbytes;
460
461        } while (1);
462}
463
464
465/** get a pointer to the link layer
466 * @param libtrace      a pointer to the trace object returned from gettrace
467 * @param buffer        a pointer to a filled in buffer
468 * @param buflen        a pointer to the size of the buffer
469 *
470 * @returns a pointer to the link layer, or NULL if there is no link layer
471 * you should call get_link_type() to find out what type of link layer this is
472 */
473void *get_link(struct libtrace_t *libtrace, void *buffer, int buflen) {
474        void *ethptr = 0;
475        struct wag_event_t *event = buffer;
476        struct wag_data_event_t *data_event;
477       
478        switch(libtrace->format) {
479                case ERF:
480                case DAG:
481                case RTCLIENT:
482                        // DAG people are insane, deal with ethernet having
483                        // some extra padding and crap
484                        if (get_link_type(libtrace,buffer,buflen)==TRACE_TYPE_ETH) 
485                                ethptr = ((uint8_t *)buffer + 16 + 2);
486                        else
487                                ethptr = ((uint8_t *)buffer + 16 + 2);
488                        break;
489                case PCAPINT:
490                case PCAP:
491                        ethptr = (struct ether_header *)(buffer + sizeof(struct pcap_pkthdr));
492                        break;
493                case WAGINT:
494                case WAG:
495                        switch (event->type) {
496                                case 0x0:
497                                        data_event = (void*)&(event->payload);
498                                        return data_event->data;
499                                default:
500                                        fprintf(stderr,"Unknown WAG Event (0x%08x)\n",event->type);
501                                        return NULL;
502                        }
503                       
504                default:
505                        fprintf(stderr,"Dunno this trace format\n");
506                        assert(0);
507        }
508        return ethptr;
509}
510
511/** get a pointer to the IP header (if any)
512 * @param libtrace      a pointer to the trace object returned from gettrace
513 * @param buffer        a pointer to a filled in buffer
514 * @param buflen        a pointer to the size of the buffer
515 *
516 * @returns a pointer to the IP header, or NULL if there is not an IP packet
517 */
518struct libtrace_ip *get_ip(struct libtrace_t *libtrace, void *buffer, int buflen) {
519        struct libtrace_ip *ipptr = 0;
520
521        switch(get_link_type(libtrace,buffer,buflen)) {
522                case TRACE_TYPE_80211:
523                        { 
524                               
525                                struct ieee_802_11_header *wifi = get_link(libtrace, buffer, buflen);   
526
527                                // Data packet?
528                                if (wifi->type != 2) {
529                                        ipptr = NULL;
530                                }
531                                else {
532                                        struct ieee_802_11_payload *eth = (void*)wifi->data;
533                                        if (eth->type != 0x0008) {
534                                                ipptr=NULL;
535                                        } else {
536                                                ipptr=(void*)eth->data;
537                                        }
538                                }
539                        }
540                        break;
541                case TRACE_TYPE_ETH:
542                        {
543                                struct ether_header *eth = get_link(libtrace,
544                                                buffer, buflen);
545                                if (ntohs(eth->ether_type)!=0x0800) {
546                                        ipptr = NULL;
547                                }
548                                else {
549                                        ipptr = ((void *)eth) + 14;
550                                }
551                                break;
552                        }
553                case TRACE_TYPE_ATM:
554                        {
555                                struct atm_rec *atm = get_link(libtrace,
556                                                buffer, buflen);
557                                // TODO: Find out what ATM does, and return
558                                //       NULL for non IP data
559                                //       Presumably it uses the normal stuff
560                                ipptr =  (void*)&atm->pload;
561                                break;
562                        }
563                default:
564                        fprintf(stderr,"Don't understand link layer type %i in get_ip()\n",
565                                get_link_type(libtrace,buffer,buflen));
566                        ipptr=NULL;
567                        break;
568        }
569
570        return ipptr;
571}
572
573
574/** get a pointer to the TCP header (if any)
575 * @param libtrace      a pointer to the trace object returned from gettrace
576 * @param buffer        a pointer to a filled in buffer
577 * @param buflen        a pointer to the size of the buffer
578 *
579 * @returns a pointer to the TCP header, or NULL if there is not a TCP packet
580 */
581struct libtrace_tcp *get_tcp(struct libtrace_t *libtrace, void *buffer, int buflen) {
582        struct libtrace_tcp *tcpptr = 0;
583        struct libtrace_ip *ipptr = 0;
584
585        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
586                return 0;
587        }
588        if (ipptr->ip_p == 6) {
589                tcpptr = (struct libtrace_tcp *)((int)ipptr + (ipptr->ip_hl * 4));
590        }
591        return tcpptr;
592}
593
594/** get a pointer to the UDP header (if any)
595 * @param libtrace      a pointer to the trace object returned from gettrace
596 * @param buffer        a pointer to a filled in buffer
597 * @param buflen        a pointer to the size of the buffer
598 *
599 * @returns a pointer to the UDP header, or NULL if this is not a UDP packet
600 */
601struct libtrace_udp *get_udp(struct libtrace_t *libtrace, void *buffer, int buflen) {
602        struct libtrace_udp *udpptr = 0;
603        struct libtrace_ip *ipptr = 0;
604       
605        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
606                return 0;
607        }
608        if (ipptr->ip_p == 17) {
609                udpptr = (struct libtrace_udp *)((int)ipptr + (ipptr->ip_hl * 4));
610        }
611        return udpptr;
612}
613
614/** get a pointer to the ICMP header (if any)
615 * @param libtrace      a pointer to the trace object returned from gettrace
616 * @param buffer        a pointer to a filled in buffer
617 * @param buflen        a pointer to the size of the buffer
618 *
619 * @returns a pointer to the ICMP header, or NULL if this is not a ICMP packet
620 */
621struct libtrace_icmp *get_icmp(struct libtrace_t *libtrace, void *buffer, int buflen) {
622        struct libtrace_icmp *icmpptr = 0;
623        struct libtrace_ip *ipptr = 0;
624       
625        if(!(ipptr = get_ip(libtrace,buffer,buflen))) {
626                return 0;
627        }
628        if (ipptr->ip_p == 1) {
629                icmpptr = (struct libtrace_icmp *)((int)ipptr + (ipptr->ip_hl * 4));
630        }
631        return icmpptr;
632}
633
634/** Get the current time in DAG time format
635 * @param libtrace the libtrace opaque pointer
636 * @param buffer a pointer to a filled in buffer
637 * @param buflen the length of the buffer
638 * @returns a 64 bit timestamp in DAG ERF format (upper 32 bits are the seconds
639 * past 1970-01-01, the lower 32bits are partial seconds)
640 * @author Daniel Lawson
641 */ 
642uint64_t get_erf_timestamp(struct libtrace_t *libtrace, void *buffer, int buflen) {
643        uint64_t timestamp = 0;
644        dag_record_t *erfptr = 0;
645        struct pcap_pkthdr *pcapptr = 0;
646        struct wag_event_t *wagptr = 0;
647        switch (libtrace->format) {
648                case DAG:
649                case ERF:
650                case RTCLIENT:
651                        erfptr = (dag_record_t *)buffer;
652                        timestamp = erfptr->ts;
653                        break;
654                case PCAPINT:
655                case PCAP:
656                        pcapptr = (struct pcap_pkthdr *)buffer;
657                        timestamp = ((((uint64_t)pcapptr->ts.tv_sec) << 32) + \
658                                (pcapptr->ts.tv_usec*UINT_MAX/1000000));
659                        break;
660                case WAGINT:
661                case WAG:
662                        wagptr = buffer;
663                        timestamp = wagptr->timestamp_lo;
664                        timestamp |= (uint64_t)wagptr->timestamp_hi<<32;
665                        timestamp = ((timestamp%44000000)*(UINT_MAX/44000000))
666                                  | ((timestamp/44000000)<<32);
667                        break;
668                default:
669                        fprintf(stderr,"Unknown format in get_erf_timestamp\n");
670                        timestamp = 0;
671        }
672        return timestamp;
673}
674
675/** Get the current time in struct timeval
676 * @param libtrace the libtrace opaque pointer
677 * @param buffer a pointer to a filled in buffer
678 * @param buflen the length of the buffer
679 * @returns time that this packet was seen in a struct timeval
680 * @author Daniel Lawson
681 * @author Perry Lorier
682 */ 
683struct timeval get_timeval(struct libtrace_t *libtrace, void *buffer, int buflen) {
684        struct timeval tv;
685        struct pcap_pkthdr *pcapptr = 0;
686        uint64_t ts;
687        switch (libtrace->format) {
688                case PCAPINT:
689                case PCAP:
690                        pcapptr = (struct pcap_pkthdr *)buffer;
691                        tv = pcapptr->ts;
692                        break;
693                case WAGINT:
694                case WAG:
695                case DAG:
696                case ERF:
697                case RTCLIENT:
698                default:
699                        ts = get_erf_timestamp(libtrace,buffer,buflen);
700                        tv.tv_sec = ts >> 32;
701                        tv.tv_usec = ((long)ts)*1000000/UINT_MAX;
702                        break;
703        }
704        return tv;
705}
706
707/** Get the current time in floating point seconds
708 * @param libtrace the libtrace opaque pointer
709 * @param buffer a pointer to a filled in buffer
710 * @param buflen the length of the buffer
711 * @returns time that this packet was seen in 64bit floating point seconds
712 * @author Perry Lorier
713 */ 
714double get_seconds(struct libtrace_t *libtrace, void *buffer, int buflen) {
715        uint64_t ts;
716        ts = get_erf_timestamp(libtrace,buffer,buflen);
717        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
718}
719
720/** Get the size of the packet in the trace
721 * @param libtrace the libtrace opaque pointer
722 * @param buffer a pointer to a filled in buffer
723 * @param buflen the length of the buffer
724 * @returns the size of the packet in the trace
725 * @author Perry Lorier
726 * @note Due to this being a header capture, or anonymisation, this may not
727 * be the same size as the original packet.  See get_wire_length() for the
728 * original size of the packet.
729 * @note This can (and often is) different for different packets in a trace!
730 * @par
731 *  This is sometimes called the "snaplen".
732 */ 
733int get_capture_length(struct libtrace_t *libtrace, void *buffer, int buflen) {
734        dag_record_t *erfptr = 0;
735        struct pcap_pkthdr *pcapptr = 0;
736        struct wag_event_t *wag_event;
737        switch (libtrace->format) {
738                case DAG:
739                case ERF:
740                case RTCLIENT:
741                        erfptr = (dag_record_t *)buffer;
742                        return ntohs(erfptr->rlen);
743                case PCAPINT:
744                case PCAP:
745                        pcapptr = (struct pcap_pkthdr *)buffer;
746                        return ntohs(pcapptr->caplen);
747                case WAGINT:
748                case WAG:
749                        wag_event = buffer;
750                        switch(wag_event->type) {
751                                case 0:
752                                        return wag_event->length*4-(
753                                                sizeof(struct wag_event_t)+
754                                                sizeof(struct wag_data_event_t)
755                                                );
756                                default:
757                                        assert(0);
758                        }
759                default:
760                        assert(0);
761        }
762        return -1;
763}
764       
765/** Get the size of the packet as it was seen on the wire.
766 * @param libtrace the libtrace opaque pointer
767 * @param buffer a pointer to a filled in buffer
768 * @param buflen the length of the buffer
769 * @returns the size of the packet as it was on the wire.
770 * @author Perry Lorier
771 * @author Daniel Lawson
772 * @note Due to the trace being a header capture, or anonymisation this may
773 * not be the same as the Capture Len.
774 */ 
775int get_wire_length(struct libtrace_t *libtrace, void *buffer, int buflen){
776        dag_record_t *erfptr = 0;
777        struct pcap_pkthdr *pcapptr = 0;
778        struct wag_event_t *wag_event = 0;
779        switch (libtrace->format) {
780                case DAG:
781                case ERF:
782                case RTCLIENT:
783                        erfptr = (dag_record_t *)buffer;
784                        return ntohs(erfptr->wlen);
785                        break;
786                case PCAPINT:
787                case PCAP:
788                        pcapptr = (struct pcap_pkthdr *)buffer;
789                        return ntohs(pcapptr->len);
790                        break;
791                case WAGINT:
792                case WAG:
793                        wag_event = buffer;
794                        switch(wag_event->type) {
795                                case 0:
796                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
797                                default:
798                                        assert(0);
799                        }
800        }
801        return -1;
802
803}
804
805/** Get the type of the link layer
806 * @param libtrace the libtrace opaque pointer
807 * @param buffer a pointer to a filled in buffer
808 * @param buflen the length of the buffer
809 * @returns libtrace_linktype_t
810 * @author Perry Lorier
811 * @author Daniel Lawson
812 */
813libtrace_linktype_t get_link_type(
814                struct libtrace_t *libtrace, 
815                void *buffer, 
816                int buflen) {
817        dag_record_t *erfptr = 0;
818        struct pcap_pkthdr *pcapptr = 0;
819        int linktype = 0;
820        switch (libtrace->format) {
821                case DAG:
822                case ERF:
823                case RTCLIENT:
824                        erfptr = (dag_record_t *)buffer;
825                        switch (erfptr->type) {
826                                case TYPE_ETH: return TRACE_TYPE_ETH;
827                                case TYPE_ATM: return TRACE_TYPE_ATM;
828                                default: assert(0);
829                        }
830                        return erfptr->type;
831                       
832                        break;
833                case PCAPINT:
834                case PCAP:
835                        pcapptr = (struct pcap_pkthdr *)buffer;
836                        linktype = pcap_datalink(libtrace->input.pcap);
837                        switch (linktype) {
838                                case 1:
839                                        return TRACE_TYPE_ETH; 
840                                case 11:
841                                        return TRACE_TYPE_ATM;
842                                case DLT_IEEE802_11:
843                                        return TRACE_TYPE_80211;
844                        }
845                        break;
846                case WAGINT:
847                case WAG:
848                        return TRACE_TYPE_80211;
849        }
850        return -1;
851}
852
853/** Get the source MAC addres
854 * @param libtrace the libtrace opaque pointer
855 * @param buffer a pointer to a filled in buffer
856 * @param buflen the length of the buffer
857 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
858 * @author Perry Lorier
859 */
860uint8_t *get_source_mac(struct libtrace_t *libtrace,
861                void *buffer,
862                int buflen) {
863        void *link = get_link(libtrace,buffer,buflen);
864        struct ieee_802_11_header *wifi = link;
865        struct ether_header *ethptr = link;
866        if (!link)
867                return NULL;
868        switch (get_link_type(libtrace,buffer,buflen)) {
869                case TRACE_TYPE_80211:
870                        return (uint8_t*)&wifi->mac2;
871                case TRACE_TYPE_ETH:
872                        return (uint8_t*)&ethptr->ether_shost;
873                default:
874                        fprintf(stderr,"Not implemented\n");
875                        assert(0);
876        }
877}
878
879/** Get the destination MAC addres
880 * @param libtrace the libtrace opaque pointer
881 * @param buffer a pointer to a filled in buffer
882 * @param buflen the length of the buffer
883 * @returns a pointer to the destination mac, (or NULL if there is no
884 * destination MAC)
885 * @author Perry Lorier
886 */
887uint8_t *get_destination_mac(struct libtrace_t *libtrace,
888                void *buffer,
889                int buflen) {
890        void *link = get_link(libtrace,buffer,buflen);
891        struct ieee_802_11_header *wifi = link;
892        struct ether_header *ethptr = link;
893        if (!link)
894                return NULL;
895        switch (get_link_type(libtrace,buffer,buflen)) {
896                case TRACE_TYPE_80211:
897                        return (uint8_t*)&wifi->mac1;
898                case TRACE_TYPE_ETH:
899                        return (uint8_t*)&ethptr->ether_dhost;
900                default:
901                        fprintf(stderr,"Not implemented\n");
902                        assert(0);
903        }
904}
905
906
907/** process a libtrace event
908 * @returns
909 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
910 *  TRACE_EVENT_SLEEP   Next event in <seconds>
911 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
912 */
913libtrace_event_t libtrace_event(struct libtrace_t *trace,
914                        int *fd,double *seconds,
915                        void *buffer, int *size)
916{
917        *seconds = 0;
918        *fd = 0;
919        /* Is there a packet ready? */
920        switch (trace->sourcetype) {
921                case INTERFACE:
922                        {
923                                int data;
924                                *fd = pcap_fileno(trace->input.pcap);
925                                if(ioctl(*fd,FIONREAD,&data)==-1){
926                                        perror("ioctl(FIONREAD)");
927                                }
928                                if (data>0) {
929                                        return TRACE_EVENT_PACKET;
930                                }
931                                return TRACE_EVENT_IOWAIT;
932                        }
933                case SOCKET:
934                case DEVICE:
935                case RT:
936                        {
937                                int data;
938                                if(ioctl(trace->input.fd,FIONREAD,&data)==-1){
939                                        perror("ioctl(FIONREAD)");
940                                }
941                                if (data>0) {
942                                        return TRACE_EVENT_PACKET;
943                                }
944                                *fd = trace->input.fd;
945                                return TRACE_EVENT_IOWAIT;
946                        }
947                case STDIN:
948                case TRACE:
949                        {
950                                int status;
951                                double ts;
952                                /* "Prime" the pump */
953                                if (!trace->packet.buffer) {
954                                        trace->packet.buffer = malloc(4096);
955                                        trace->packet.size=libtrace_read_packet(trace,
956                                                        trace->packet.buffer,
957                                                        4096,
958                                                        &status);
959                                }
960                                ts=get_seconds(trace,
961                                        trace->packet.buffer,
962                                        trace->packet.size);
963                                if (trace->last_ts!=0) {
964                                        *seconds = ts - trace->last_ts;
965                                        if (*seconds>time(NULL)-trace->start_ts)
966                                                return TRACE_EVENT_SLEEP;
967                                }
968                                else {
969                                        trace->start_ts = time(NULL);
970                                        trace->last_ts = ts;
971                                }
972
973                                *size = trace->packet.size;
974                                memcpy(buffer,trace->packet.buffer,*size);
975
976                                free(trace->packet.buffer);
977                                trace->packet.buffer = 0;
978                                return TRACE_EVENT_PACKET;
979                        }
980                default:
981                        assert(0);
982        }
983        /* Shouldn't get here */
984        assert(0);
985}
Note: See TracBrowser for help on using the repository browser.