source: lib/trace.c @ 63a2713

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

fixed a broken bzero

  • 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,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        switch (libtrace->format) {
690                case PCAPINT:
691                case PCAP:
692                        pcapptr = (struct pcap_pkthdr *)buffer;
693                        tv = pcapptr->ts;
694                        break;
695                case WAGINT:
696                case WAG:
697                case DAG:
698                case ERF:
699                case RTCLIENT:
700                default:
701                        ts = get_erf_timestamp(libtrace,buffer,buflen);
702                        tv.tv_sec = ts >> 32;
703                        tv.tv_usec = ((long)ts)*1000000/UINT_MAX;
704                        break;
705        }
706        return tv;
707}
708
709/** Get the current time in floating point seconds
710 * @param libtrace the libtrace opaque pointer
711 * @param buffer a pointer to a filled in buffer
712 * @param buflen the length of the buffer
713 * @returns time that this packet was seen in 64bit floating point seconds
714 * @author Perry Lorier
715 */ 
716double get_seconds(struct libtrace_t *libtrace, void *buffer, int buflen) {
717        uint64_t ts;
718        ts = get_erf_timestamp(libtrace,buffer,buflen);
719        return (ts>>32) + ((ts & UINT_MAX)*1.0 / UINT_MAX);
720}
721
722/** Get the size of the packet in the trace
723 * @param libtrace the libtrace opaque pointer
724 * @param buffer a pointer to a filled in buffer
725 * @param buflen the length of the buffer
726 * @returns the size of the packet in the trace
727 * @author Perry Lorier
728 * @note Due to this being a header capture, or anonymisation, this may not
729 * be the same size as the original packet.  See get_wire_length() for the
730 * original size of the packet.
731 * @note This can (and often is) different for different packets in a trace!
732 * @par
733 *  This is sometimes called the "snaplen".
734 */ 
735int get_capture_length(struct libtrace_t *libtrace, void *buffer, int buflen) {
736        dag_record_t *erfptr = 0;
737        struct pcap_pkthdr *pcapptr = 0;
738        struct wag_event_t *wag_event;
739        switch (libtrace->format) {
740                case DAG:
741                case ERF:
742                case RTCLIENT:
743                        erfptr = (dag_record_t *)buffer;
744                        return ntohs(erfptr->rlen);
745                case PCAPINT:
746                case PCAP:
747                        pcapptr = (struct pcap_pkthdr *)buffer;
748                        return ntohs(pcapptr->caplen);
749                case WAGINT:
750                case WAG:
751                        wag_event = buffer;
752                        switch(wag_event->type) {
753                                case 0:
754                                        return wag_event->length*4-(
755                                                sizeof(struct wag_event_t)+
756                                                sizeof(struct wag_data_event_t)
757                                                );
758                                default:
759                                        assert(0);
760                        }
761                default:
762                        assert(0);
763        }
764        return -1;
765}
766       
767/** Get the size of the packet as it was seen on the wire.
768 * @param libtrace the libtrace opaque pointer
769 * @param buffer a pointer to a filled in buffer
770 * @param buflen the length of the buffer
771 * @returns the size of the packet as it was on the wire.
772 * @author Perry Lorier
773 * @author Daniel Lawson
774 * @note Due to the trace being a header capture, or anonymisation this may
775 * not be the same as the Capture Len.
776 */ 
777int get_wire_length(struct libtrace_t *libtrace, void *buffer, int buflen){
778        dag_record_t *erfptr = 0;
779        struct pcap_pkthdr *pcapptr = 0;
780        struct wag_event_t *wag_event = 0;
781        switch (libtrace->format) {
782                case DAG:
783                case ERF:
784                case RTCLIENT:
785                        erfptr = (dag_record_t *)buffer;
786                        return ntohs(erfptr->wlen);
787                        break;
788                case PCAPINT:
789                case PCAP:
790                        pcapptr = (struct pcap_pkthdr *)buffer;
791                        return ntohs(pcapptr->len);
792                        break;
793                case WAGINT:
794                case WAG:
795                        wag_event = buffer;
796                        switch(wag_event->type) {
797                                case 0:
798                                        return ((struct wag_data_event_t *)(&wag_event->payload))->frame_length;
799                                default:
800                                        assert(0);
801                        }
802        }
803        return -1;
804
805}
806
807/** Get the type of the link layer
808 * @param libtrace the libtrace opaque pointer
809 * @param buffer a pointer to a filled in buffer
810 * @param buflen the length of the buffer
811 * @returns libtrace_linktype_t
812 * @author Perry Lorier
813 * @author Daniel Lawson
814 */
815libtrace_linktype_t get_link_type(
816                struct libtrace_t *libtrace, 
817                void *buffer, 
818                int buflen) {
819        dag_record_t *erfptr = 0;
820        struct pcap_pkthdr *pcapptr = 0;
821        int linktype = 0;
822        switch (libtrace->format) {
823                case DAG:
824                case ERF:
825                case RTCLIENT:
826                        erfptr = (dag_record_t *)buffer;
827                        switch (erfptr->type) {
828                                case TYPE_ETH: return TRACE_TYPE_ETH;
829                                case TYPE_ATM: return TRACE_TYPE_ATM;
830                                default: assert(0);
831                        }
832                        return erfptr->type;
833                       
834                        break;
835                case PCAPINT:
836                case PCAP:
837                        pcapptr = (struct pcap_pkthdr *)buffer;
838                        linktype = pcap_datalink(libtrace->input.pcap);
839                        switch (linktype) {
840                                case 1:
841                                        return TRACE_TYPE_ETH; 
842                                case 11:
843                                        return TRACE_TYPE_ATM;
844                                case DLT_IEEE802_11:
845                                        return TRACE_TYPE_80211;
846                        }
847                        break;
848                case WAGINT:
849                case WAG:
850                        return TRACE_TYPE_80211;
851        }
852        return -1;
853}
854
855/** Get the source MAC addres
856 * @param libtrace the libtrace opaque pointer
857 * @param buffer a pointer to a filled in buffer
858 * @param buflen the length of the buffer
859 * @returns a pointer to the source mac, (or NULL if there is no source MAC)
860 * @author Perry Lorier
861 */
862uint8_t *get_source_mac(struct libtrace_t *libtrace,
863                void *buffer,
864                int buflen) {
865        void *link = get_link(libtrace,buffer,buflen);
866        struct ieee_802_11_header *wifi = link;
867        struct ether_header *ethptr = link;
868        if (!link)
869                return NULL;
870        switch (get_link_type(libtrace,buffer,buflen)) {
871                case TRACE_TYPE_80211:
872                        return (uint8_t*)&wifi->mac2;
873                case TRACE_TYPE_ETH:
874                        return (uint8_t*)&ethptr->ether_shost;
875                default:
876                        fprintf(stderr,"Not implemented\n");
877                        assert(0);
878        }
879}
880
881/** Get the destination MAC addres
882 * @param libtrace the libtrace opaque pointer
883 * @param buffer a pointer to a filled in buffer
884 * @param buflen the length of the buffer
885 * @returns a pointer to the destination mac, (or NULL if there is no
886 * destination MAC)
887 * @author Perry Lorier
888 */
889uint8_t *get_destination_mac(struct libtrace_t *libtrace,
890                void *buffer,
891                int buflen) {
892        void *link = get_link(libtrace,buffer,buflen);
893        struct ieee_802_11_header *wifi = link;
894        struct ether_header *ethptr = link;
895        if (!link)
896                return NULL;
897        switch (get_link_type(libtrace,buffer,buflen)) {
898                case TRACE_TYPE_80211:
899                        return (uint8_t*)&wifi->mac1;
900                case TRACE_TYPE_ETH:
901                        return (uint8_t*)&ethptr->ether_dhost;
902                default:
903                        fprintf(stderr,"Not implemented\n");
904                        assert(0);
905        }
906}
907
908
909/** process a libtrace event
910 * @returns
911 *  TRACE_EVENT_IOWAIT  Waiting on I/O on <fd>
912 *  TRACE_EVENT_SLEEP   Next event in <seconds>
913 *  TRACE_EVENT_PACKET  Packet arrived in <buffer> with size <size>
914 */
915libtrace_event_t libtrace_event(struct libtrace_t *trace,
916                        int *fd,double *seconds,
917                        void *buffer, int *size)
918{
919        *seconds = 0;
920        *fd = 0;
921        /* Is there a packet ready? */
922        switch (trace->sourcetype) {
923                case INTERFACE:
924                        {
925                                int data;
926                                *fd = pcap_fileno(trace->input.pcap);
927                                if(ioctl(*fd,FIONREAD,&data)==-1){
928                                        perror("ioctl(FIONREAD)");
929                                }
930                                if (data>0) {
931                                        return TRACE_EVENT_PACKET;
932                                }
933                                return TRACE_EVENT_IOWAIT;
934                        }
935                case SOCKET:
936                case DEVICE:
937                case RT:
938                        {
939                                int data;
940                                if(ioctl(trace->input.fd,FIONREAD,&data)==-1){
941                                        perror("ioctl(FIONREAD)");
942                                }
943                                if (data>0) {
944                                        return TRACE_EVENT_PACKET;
945                                }
946                                *fd = trace->input.fd;
947                                return TRACE_EVENT_IOWAIT;
948                        }
949                case STDIN:
950                case TRACE:
951                        {
952                                int status;
953                                double ts;
954                                /* "Prime" the pump */
955                                if (!trace->packet.buffer) {
956                                        trace->packet.buffer = malloc(4096);
957                                        trace->packet.size=libtrace_read_packet(trace,
958                                                        trace->packet.buffer,
959                                                        4096,
960                                                        &status);
961                                }
962                                ts=get_seconds(trace,
963                                        trace->packet.buffer,
964                                        trace->packet.size);
965                                if (trace->last_ts!=0) {
966                                        *seconds = ts - trace->last_ts;
967                                        if (*seconds>time(NULL)-trace->start_ts)
968                                                return TRACE_EVENT_SLEEP;
969                                }
970                                else {
971                                        trace->start_ts = time(NULL);
972                                        trace->last_ts = ts;
973                                }
974
975                                *size = trace->packet.size;
976                                memcpy(buffer,trace->packet.buffer,*size);
977
978                                free(trace->packet.buffer);
979                                trace->packet.buffer = 0;
980                                return TRACE_EVENT_PACKET;
981                        }
982                default:
983                        assert(0);
984        }
985        /* Shouldn't get here */
986        assert(0);
987}
Note: See TracBrowser for help on using the repository browser.