source: tools/tracetop/tracetop.cc @ ca076e7

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since ca076e7 was ca076e7, checked in by Shane Alcock <salcock@…>, 8 years ago
  • Fixed broken -B option in tracetop - was also missing from the getopt_long string
  • Fixed missing break when -B is enabled in tracetop
  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[a6da077]1/* Show the top 'n' flows from a libtrace source
2 *
3 */
4#define __STDC_FORMAT_MACROS 1
[7876f38]5#include "config.h"
[a6da077]6#include "libtrace.h"
7#include <stdio.h>
8#include <getopt.h>
9#include <stdlib.h>
10#include <map>
11#include <queue>
12#include <inttypes.h>
[d4242e4]13#include <sys/socket.h>
14#include <netdb.h>
[c9754d0]15#include <string.h>
[c7c10de]16#include <assert.h>
[59751a5]17#ifdef HAVE_NETPACKET_PACKET_H
18#include <netpacket/packet.h>
19#include <net/ethernet.h>
[2216d25]20#else
21#include <net/if_dl.h>
[59751a5]22#endif
23
[11754a6]24#if HAVE_NCURSES_NCURSES_H
25#include <ncurses/ncurses.h>
26#else
27#include <ncurses.h>
28#endif
29
[7babe98]30typedef enum { BITS_PER_SEC, BYTES, PERCENT } display_t;
[59751a5]31display_t display_as = BYTES;
[7babe98]32float interval=2;
[c549d3f]33double last_report=0;
[7babe98]34
35bool use_sip = true;
36bool use_dip = true;
37bool use_sport = true;
38bool use_dport = true;
39bool use_protocol = true;
[c549d3f]40bool quit = false;
[4325ef8]41bool fullspeed = false;
[c7c10de]42bool wide_display = false;
[7babe98]43
44uint64_t total_bytes=0;
45uint64_t total_packets=0;
[d4242e4]46
47int cmp_sockaddr_in6(const struct sockaddr_in6 *a, const struct sockaddr_in6 *b)
48{
49        if (a->sin6_port != b->sin6_port)
50                return a->sin6_port - b->sin6_port;
51        return memcmp(a->sin6_addr.s6_addr,b->sin6_addr.s6_addr,sizeof(a->sin6_addr.s6_addr));
52}
53
54int cmp_sockaddr_in(const struct sockaddr_in *a, const struct sockaddr_in *b)
55{
56        if (a->sin_port != b->sin_port)
57                return a->sin_port - b->sin_port;
58        return a->sin_addr.s_addr - b->sin_addr.s_addr;
59}
60
[59751a5]61#ifdef HAVE_NETPACKET_PACKET_H
62int cmp_sockaddr_ll(const struct sockaddr_ll *a, const struct sockaddr_ll *b)
63{
64        return memcmp(a->sll_addr, b->sll_addr, b->sll_halen);
65}
[524ebb5]66#else
67int cmp_sockaddr_dl(const struct sockaddr_dl *a, const struct sockaddr_dl *b)
68{
69        return memcmp(a->sdl_data, b->sdl_data, b->sdl_alen);
70}
71
[59751a5]72#endif
73
[d4242e4]74int cmp_sockaddr(const struct sockaddr *a, const struct sockaddr *b)
75{
76        if (a->sa_family != b->sa_family) {
77                return a->sa_family - b->sa_family;
78        }
79        switch (a->sa_family) {
80                case AF_INET:
81                        return cmp_sockaddr_in((struct sockaddr_in *)a,(struct sockaddr_in*)b);
82                case AF_INET6:
83                        return cmp_sockaddr_in6((struct sockaddr_in6 *)a,(struct sockaddr_in6*)b);
[59751a5]84#ifdef HAVE_NETPACKET_PACKET_H
85                case AF_PACKET:
86                        return cmp_sockaddr_ll((struct sockaddr_ll *)a,(struct sockaddr_ll*)b);
[524ebb5]87#else
88                case AF_LINK:
89                        return cmp_sockaddr_dl((struct sockaddr_dl *)a, (struct sockaddr_dl *)b);
[59751a5]90#endif
[d4242e4]91                case AF_UNSPEC:
92                        return 0; /* Can't compare UNSPEC's! */
93                default:
94                        fprintf(stderr,"Don't know how to compare family %d\n",a->sa_family);
95                        abort();
96        }
97}
98
99char *trace_sockaddr2string(const struct sockaddr *a, socklen_t salen, char *buffer, size_t bufflen)
100{
101        static char intbuffer[NI_MAXHOST];
102        char *mybuf = buffer ? buffer : intbuffer;
103        size_t mybufflen = buffer ? bufflen : sizeof(intbuffer);
104        int err;
[2216d25]105
106        /* Some systems (FreeBSD and Solaris, I'm looking at you) have a bug
107         * where they can't deal with the idea of a sockaddr_storage being
108         * passed into getnameinfo. Linux just deals by looking
109         * at sa_family and figuring out what sockaddr it is really.
110         *
111         * Anyway, the fix appears to be to manually hax the sockaddr length
112         * to be the right value for the underlying family.
113         */
[59751a5]114        switch (a->sa_family) {
115                case AF_INET:
[2216d25]116                        salen = sizeof(struct sockaddr_in);
117                        if ((err=getnameinfo(a, salen, mybuf, mybufflen, NULL, 0, NI_NUMERICHOST))!=0) {
118                                strncpy(mybuf,gai_strerror(err),mybufflen);
119                        }
120                        break;
[59751a5]121                case AF_INET6:
[2216d25]122                        salen = sizeof(struct sockaddr_in6);
[59751a5]123                        if ((err=getnameinfo(a, salen, mybuf, mybufflen, NULL, 0, NI_NUMERICHOST))!=0) {
124                                strncpy(mybuf,gai_strerror(err),mybufflen);
125                        }
126                        break;
127#ifdef HAVE_NETPACKET_PACKET_H
128                case AF_PACKET:
129                        trace_ether_ntoa(((struct sockaddr_ll*)a)->sll_addr, mybuf);
130                        break;
[2216d25]131#else
132                case AF_LINK:
133                        trace_ether_ntoa((uint8_t *)((struct sockaddr_dl *)a)->sdl_data, mybuf);
134                        break;
[59751a5]135#endif
136                default:
137                        snprintf(mybuf,mybufflen,"Unknown family %d",a->sa_family);
[d4242e4]138        }
139        return mybuf;
140}
[a6da077]141
[cde85f8]142static void set_port_for_sockaddr(struct sockaddr *sa,uint16_t port)
143{
144        switch (sa->sa_family) {
145                case AF_INET:
146                        ((struct sockaddr_in *)sa)->sin_port = htons(port);
147                        break;
148                case AF_INET6:
149                        ((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
150                        break;
151        }
152}
153
154static void clear_addr_for_sockaddr(struct sockaddr *sa)
155{
156        switch (sa->sa_family) {
157                case AF_INET:
158                        ((struct sockaddr_in *)sa)->sin_addr.s_addr = 0;
159                        break;
160                case AF_INET6:
161                        memset((void*)&((struct sockaddr_in6 *)sa)->sin6_addr,0,sizeof(((struct sockaddr_in6 *)sa)->sin6_addr));
162                        break;
163        }
164}
165
166static uint16_t get_port_from_sockaddr(struct sockaddr *sa)
167{
168        switch (sa->sa_family) {
169                case AF_INET:
170                        return ntohs(((struct sockaddr_in *)sa)->sin_port);
171                        break;
172                case AF_INET6:
173                        return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
174                        break;
175        }
[04a0ba4]176
177        return 0;
[cde85f8]178}
179
[a6da077]180struct flowkey_t {
[d4242e4]181        struct sockaddr_storage sip;
182        struct sockaddr_storage dip;
[a6da077]183        uint16_t sport;
184        uint16_t dport;
185        uint8_t protocol;
186
187        bool operator <(const flowkey_t &b) const {
[d4242e4]188                int c;
189
[7babe98]190                if (use_sip) {
191                        c = cmp_sockaddr((struct sockaddr*)&sip,(struct sockaddr*)&b.sip);
192                        if (c != 0) return c<0;
193                }
194                if (use_dip) {
195                        c = cmp_sockaddr((struct sockaddr*)&dip,(struct sockaddr*)&b.dip);
196                        if (c != 0) return c<0;
197                }
[d4242e4]198
[a6da077]199                return protocol < b.protocol;
200        }
201};
202
203struct flowdata_t {
204        uint64_t packets;
205        uint64_t bytes;
206};
207
208typedef std::map<flowkey_t,flowdata_t> flows_t;
209
210flows_t flows;
211
[7babe98]212const char *nice_bandwidth(double bytespersec)
213{
214        static char ret[1024];
215        double bitspersec = bytespersec*8;
216
217        if (bitspersec>1e12)
218                snprintf(ret,sizeof(ret),"%.03fTb/s", bitspersec/1e12);
219        else if (bitspersec>1e9)
220                snprintf(ret,sizeof(ret),"%.03fGb/s", bitspersec/1e9);
221        else if (bitspersec>1e6)
222                snprintf(ret,sizeof(ret),"%.03fMb/s", bitspersec/1e6);
223        else if (bitspersec>1e3)
224                snprintf(ret,sizeof(ret),"%.03fkb/s", bitspersec/1e3);
225        else
226                snprintf(ret,sizeof(ret),"%.03fb/s", bitspersec);
227        return ret;
228}
229
[a6da077]230static void per_packet(libtrace_packet_t *packet)
231{
232        flowkey_t flowkey;
233        flows_t::iterator it;
[d4242e4]234
[cde85f8]235        if (trace_get_source_address(packet,(struct sockaddr*)&flowkey.sip)==NULL)
[d4242e4]236                flowkey.sip.ss_family = AF_UNSPEC;
[cde85f8]237
238        if (trace_get_destination_address(packet,(struct sockaddr*)&flowkey.dip)==NULL)
[d4242e4]239                flowkey.dip.ss_family = AF_UNSPEC;
[cde85f8]240
241        if (!use_sip)
242                clear_addr_for_sockaddr((struct sockaddr *)&flowkey.sip);
243
244        if (!use_dip)
245                clear_addr_for_sockaddr((struct sockaddr *)&flowkey.dip);
246
247        if (!use_sport)
248                set_port_for_sockaddr((struct sockaddr *)&flowkey.sip,0);
249
250        if (!use_dport) 
251                set_port_for_sockaddr((struct sockaddr *)&flowkey.dip,0);
252
[7babe98]253        if (use_protocol && trace_get_transport(packet,&flowkey.protocol, NULL) == NULL)
[e7307f9]254                flowkey.protocol = 255;
[cde85f8]255
[d4242e4]256
[a6da077]257        it = flows.find(flowkey);
258        if (it == flows.end()) {
259                flowdata_t flowdata = { 0, 0 };
260                flows_t::value_type insdata(flowkey,flowdata);
261                std::pair<flows_t::iterator,bool> ins= flows.insert(insdata);
262                it = ins.first;
263        }
264
265        ++it->second.packets;
[05a3177]266        it->second.bytes+=trace_get_wire_length(packet);
[59751a5]267
[7babe98]268        ++total_packets;
[05a3177]269        total_bytes+=trace_get_wire_length(packet);
[7babe98]270
[a6da077]271}
272
273struct flow_data_t {
274        uint64_t bytes;
275        uint64_t packets;
[d4242e4]276        struct sockaddr_storage sip;
277        struct sockaddr_storage dip;
[a6da077]278        uint8_t protocol;
279
280        bool operator< (const flow_data_t &b) const {
281                if (bytes != b.bytes) return bytes < b.bytes;
282                return packets < b.packets;
283        }
284};
285
286static void do_report()
287{
288        typedef  std::priority_queue<flow_data_t> pq_t;
289        int row,col;
290        pq_t pq;
291        for(flows_t::const_iterator it=flows.begin();it!=flows.end();++it) {
292                flow_data_t data;
293                data.bytes = it->second.bytes,
294                data.packets = it->second.packets,
295                data.sip = it->first.sip;
296                data.dip = it->first.dip;
297                data.protocol = it->first.protocol;
298                pq.push(data);
299        }
300        getmaxyx(stdscr,row,col);
[7babe98]301        move(0,0);
[37f537f]302        printw("Total Bytes: %10" PRIu64 " (%s)\tTotal Packets: %10" PRIu64, total_bytes, nice_bandwidth(total_bytes/interval), total_packets);
[7babe98]303        clrtoeol();
[a6da077]304        attrset(A_REVERSE);
[7babe98]305        move(1,0);
306        if (use_sip) {
[c7c10de]307                if (wide_display)
[91283e8]308                        printw("%42s", "source ip");
[c7c10de]309                else
310                        printw("%20s", "source ip");
311                       
[7babe98]312                if (use_sport)
313                        printw("/");
314                else
315                        printw("\t");
316        }
317        if (use_sport)
[91283e8]318                printw("%s  ", "sport");
[7babe98]319        if (use_dip) {
[c7c10de]320                if (wide_display)
[91283e8]321                        printw("%42s", "dest ip");
[c7c10de]322                else
323                        printw("%20s", "dest ip");
[7babe98]324                if (use_dport)
325                        printw("/");
326                else
327                        printw("\t");
328        }
329        if (use_dport)
[91283e8]330                printw("%s  ", "dport");
[7babe98]331        if (use_protocol)
[e99ba00]332                printw("%10s\t", "proto");
[7babe98]333        switch(display_as) {
334                case BYTES:
[37f537f]335                        printw("%7s","Bytes\t");
[7babe98]336                        break;
337                case BITS_PER_SEC:
338                        printw("%14s\t","Bits/sec");
339                        break;
340                case PERCENT:
341                        printw("%% bytes\t");
342                        break;
343        }
344        printw("Packets");
345
[a6da077]346        attrset(A_NORMAL);
[d4242e4]347        char sipstr[1024];
348        char dipstr[1024];
[7babe98]349        for(int i=1; i<row-3 && !pq.empty(); ++i) {
350                move(i+1,0);
351                if (use_sip) {
[c7c10de]352                        if (wide_display) {
[91283e8]353                                printw("%42s",
[c7c10de]354                                        trace_sockaddr2string(
355                                                (struct sockaddr*)&pq.top().sip,
356                                                sizeof(struct sockaddr_storage),
357                                                sipstr,sizeof(sipstr)));
358                        } else {
359                                printw("%20s",
360                                        trace_sockaddr2string(
361                                                (struct sockaddr*)&pq.top().sip,
362                                                sizeof(struct sockaddr_storage),
363                                                sipstr,sizeof(sipstr)));
364                        }
[7babe98]365                        if (use_sport)
366                                printw("/");
367                        else
368                                printw("\t");
369                }
370                if (use_sport)
[91283e8]371                        printw("%-5d  ", get_port_from_sockaddr((struct sockaddr*)&pq.top().sip));
[7babe98]372                if (use_dip) {
[c7c10de]373                        if (wide_display) {
[91283e8]374                                printw("%42s",
[c7c10de]375                                        trace_sockaddr2string(
376                                                (struct sockaddr*)&pq.top().dip,
377                                                sizeof(struct sockaddr_storage),
378                                                dipstr,sizeof(dipstr)));
379                        } else {
380                                printw("%20s",
381                                        trace_sockaddr2string(
382                                                (struct sockaddr*)&pq.top().dip,
383                                                sizeof(struct sockaddr_storage),
384                                                dipstr,sizeof(dipstr)));
385
386                        }
[7babe98]387                        if (use_dport)
388                                printw("/");
389                        else
390                                printw("\t");
391                }
392                if (use_dport)
[91283e8]393                        printw("%-5d  ", get_port_from_sockaddr((struct sockaddr*)&pq.top().dip));
[7babe98]394                if (use_protocol) {
395                        struct protoent *proto = getprotobynumber(pq.top().protocol);
396                        if (proto) 
[91283e8]397                                printw("%-10s  ", proto->p_name);
[7babe98]398                        else
[91283e8]399                                printw("%10d  ",pq.top().protocol);
[7babe98]400                }
[752353b]401                switch (display_as) {
402                        case BYTES:
[37f537f]403                                printw("%7"PRIu64"\t%7"PRIu64"\n",
[752353b]404                                                pq.top().bytes,
405                                                pq.top().packets);
406                                break;
407                        case BITS_PER_SEC:
[7babe98]408                                printw("%14.03f\t%"PRIu64"\n",
[752353b]409                                                8.0*pq.top().bytes/interval,
410                                                pq.top().packets);
[ca076e7]411                                break;
[7babe98]412                        case PERCENT:
413                                printw("%6.2f%%\t%6.2f%%\n",
414                                                100.0*pq.top().bytes/total_bytes,
415                                                100.0*pq.top().packets/total_packets);
[752353b]416                }
[a6da077]417                pq.pop();
418        }
419        flows.clear();
[7babe98]420        total_packets = 0;
421        total_bytes = 0;
[a6da077]422
[5dd06d6]423        clrtobot();
[a6da077]424        refresh();
425}
426
[c549d3f]427static void run_trace(libtrace_t *trace)
428{
429        libtrace_packet_t *packet = trace_create_packet();
430        libtrace_eventobj_t obj;
431        fd_set rfds;
432        struct timeval sleep_tv;
433        struct timeval *tv = NULL;
434
435        do {
436                int maxfd=0;
437                FD_ZERO(&rfds);
438                FD_SET(0, &rfds); /* stdin */
439                tv=NULL;
440                maxfd=0;
441
442                obj = trace_event(trace, packet);
443                switch(obj.type) {
444                        case TRACE_EVENT_IOWAIT:
445                                FD_SET(obj.fd, &rfds);
446                                maxfd = obj.fd;
447                                break;
448
449                        case TRACE_EVENT_SLEEP:
450                                sleep_tv.tv_sec = (int)obj.seconds;
451                                sleep_tv.tv_usec = (int)((obj.seconds - sleep_tv.tv_sec)*1000000.0);
452
453                                tv = &sleep_tv;
454                                break;;
455
456                        case TRACE_EVENT_TERMINATE:
457                                trace_destroy_packet(packet);
458                                return;
459
460                        case TRACE_EVENT_PACKET:
461                                if (obj.size == -1)
462                                        break;
463                                if (trace_get_seconds(packet) - last_report >= interval) {
464                                        do_report();
465                                               
466                                        last_report=trace_get_seconds(packet);
467                                }
468                                if (trace_read_packet(trace,packet) <= 0) {
469                                        obj.size = -1;
470                                        break;
471                                }
472                                per_packet(packet);
473                                continue;
474                }
475
476                if (tv && tv->tv_sec > interval) {
477                        tv->tv_sec = (int)interval;
478                        tv->tv_usec = 0;
479                }
480
481                select(maxfd+1, &rfds, 0, 0, tv);
482                if (FD_ISSET(0, &rfds)) {
483                        switch (getch()) {
484                                case '%':
485                                        display_as = PERCENT;
486                                        break;
487                                case 'b':
488                                        display_as = BITS_PER_SEC;
489                                        break;
490                                case 'B':
491                                        display_as = BYTES;
492                                        break;
493                                case '\x1b': /* Escape */
494                                case 'q':
495                                        quit = true;
496                                        trace_destroy_packet(packet);
497                                        return;
498                                case '1': use_sip       = !use_sip; break;
499                                case '2': use_sport     = !use_sport; break;
500                                case '3': use_dip       = !use_dip; break;
501                                case '4': use_dport     = !use_dport; break;
502                                case '5': use_protocol  = !use_protocol; break;
503                        }
504                }
505        } while (obj.type != TRACE_EVENT_TERMINATE || obj.size == -1);
506
507        trace_destroy_packet(packet);
508} 
509
[a6da077]510static void usage(char *argv0)
511{
[c549d3f]512        fprintf(stderr,"usage: %s [options] libtraceuri...\n",argv0);
513        fprintf(stderr," --filter bpfexpr\n");
514        fprintf(stderr," -f bpfexpr\n");
515        fprintf(stderr,"\t\tApply a bpf filter expression\n");
516        fprintf(stderr," --snaplen snaplen\n");
517        fprintf(stderr," -s snaplen\n");
518        fprintf(stderr,"\t\tCapture only snaplen bytes\n");
519        fprintf(stderr," --promisc 0|1\n");
520        fprintf(stderr," -p 0|1\n");
521        fprintf(stderr,"\t\tEnable/Disable promiscuous mode\n");
522        fprintf(stderr," --bits-per-sec\n");
523        fprintf(stderr," -B\n");
524        fprintf(stderr,"\t\tDisplay usage in bits per second, not bytes per second\n");
525        fprintf(stderr," --percent\n");
526        fprintf(stderr," -P\n");
527        fprintf(stderr,"\t\tDisplay usage in percentage of total usage\n");
528        fprintf(stderr," --interval int\n");
529        fprintf(stderr," -i int\n");
530        fprintf(stderr,"\t\tUpdate the display every int seconds\n");
[c7c10de]531        fprintf(stderr," --wide\n");
532        fprintf(stderr," -w\n");
533        fprintf(stderr,"\t\tExpand IP address fields to fit IPv6 addresses\n");
[a6da077]534}
535
536int main(int argc, char *argv[])
537{
538        libtrace_t *trace;
539        libtrace_filter_t *filter=NULL;
540        int snaplen=-1;
541        int promisc=-1;
542
[7babe98]543        setprotoent(1);
544
[a6da077]545        while(1) {
546                int option_index;
547                struct option long_options[] = {
548                        { "filter",             1, 0, 'f' },
549                        { "snaplen",            1, 0, 's' },
[501a8eb]550                        { "promisc",            0, 0, 'p' },
[a6da077]551                        { "help",               0, 0, 'h' },
552                        { "libtrace-help",      0, 0, 'H' },
[7babe98]553                        { "bits-per-sec",       0, 0, 'B' },
554                        { "percent",            0, 0, 'P' },
555                        { "interval",           1, 0, 'i' },
[4325ef8]556                        { "fast",               0, 0, 'F' },
[c7c10de]557                        { "wide",               0, 0, 'w' },
[a6da077]558                        { NULL,                 0, 0, 0 }
559                };
560
[ca076e7]561                int c= getopt_long(argc, argv, "BPf:Fs:p:hHi:w12345",
[a6da077]562                                long_options, &option_index);
563
564                if (c==-1)
565                        break;
566
567                switch (c) {
568                        case 'f':
569                                filter=trace_create_filter(optarg);
570                                break;
[4325ef8]571                        case 'F':
572                                fullspeed = true;
573                                break;
[a6da077]574                        case 's':
575                                snaplen=atoi(optarg);
576                                break;
577                        case 'p':
578                                promisc=atoi(optarg);
579                                break;
580                        case 'H':
581                                trace_help();
582                                return 1;
[7babe98]583                        case 'B':
[752353b]584                                display_as = BITS_PER_SEC;
585                                break;
[7babe98]586                        case 'P':
587                                display_as = PERCENT;
588                                break;
589                        case 'i':
590                                interval = atof(optarg);
591                                if (interval<=0) {
592                                        fprintf(stderr,"Interval must be >0\n");
593                                        return 1;
594                                }
595                                break;
[c7c10de]596                        case 'w':
597                                wide_display = true;
598                                break;
[5c866be]599                        case '1': use_sip       = !use_sip; break;
600                        case '2': use_sport     = !use_sport; break;
601                        case '3': use_dip       = !use_dip; break;
602                        case '4': use_dport     = !use_dport; break;
603                        case '5': use_protocol  = !use_protocol; break;
[a6da077]604                        default:
605                                fprintf(stderr,"Unknown option: %c\n",c);
606                                /* FALL THRU */
607                        case 'h':
608                                usage(argv[0]);
609                                return 1;
610                }
611        }
612
613        if (optind>=argc) {
614                fprintf(stderr,"Missing input uri\n");
615                usage(argv[0]);
616                return 1;
617        }
618
619        initscr(); cbreak(); noecho();
620
[c549d3f]621        while (!quit && optind<argc) {
[a6da077]622                trace = trace_create(argv[optind]);
623                ++optind;
624
625                if (trace_is_err(trace)) {
626                        endwin();
627                        trace_perror(trace,"Opening trace file");
628                        return 1;
629                }
630
631                if (snaplen>0)
632                        if (trace_config(trace,TRACE_OPTION_SNAPLEN,&snaplen)) {
633                                trace_perror(trace,"ignoring: ");
634                        }
635                if (filter)
636                        if (trace_config(trace,TRACE_OPTION_FILTER,filter)) {
637                                trace_perror(trace,"ignoring: ");
638                        }
639                if (promisc!=-1) {
640                        if (trace_config(trace,TRACE_OPTION_PROMISC,&promisc)) {
641                                trace_perror(trace,"ignoring: ");
642                        }
643                }
[4325ef8]644                if (fullspeed) {
645                        int flag=1;
646                        if (trace_config(trace,TRACE_OPTION_EVENT_REALTIME,&flag)) {
647                                trace_perror(trace,"Setting EVENT_REALTIME option");
648                        }
649                }
[a6da077]650
651                if (trace_start(trace)) {
652                        endwin();
653                        trace_perror(trace,"Starting trace");
654                        trace_destroy(trace);
655                        return 1;
656                }
657
[c549d3f]658                run_trace(trace);
[a6da077]659
660                if (trace_is_err(trace)) {
661                        trace_perror(trace,"Reading packets");
662                }
663
664                trace_destroy(trace);
665        }
666
667        endwin();
[7babe98]668        endprotoent();
[a6da077]669
670        return 0;
671}
Note: See TracBrowser for help on using the repository browser.