GPLization banner introduced to *.[hc] files
[sip-router] / utils / ngrep / ngrep.c
1 /*
2  * $Id$
3  *
4  * Copyright (c) 2001  Jordan Ritter <jpr5@darkridge.com>
5  *
6  * Please refer to the COPYRIGHT file for more information. 
7  * 
8  *
9  * Copyright (C) 2001-2003 Fhg Fokus
10  *
11  * This file is part of ser, a free SIP server.
12  *
13  * ser is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version
17  *
18  * For a license to use the ser software under conditions
19  * other than those described here, or to purchase support for this
20  * software, please contact iptel.org by e-mail at the following addresses:
21  *    info@iptel.org
22  *
23  * ser is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License 
29  * along with this program; if not, write to the Free Software 
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  */
32
33
34 #if defined(BSD) || defined(SOLARIS) || defined(MACOSX)
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 #include <net/if.h>
42 #include <sys/tty.h>
43 #endif
44
45 #if defined(OSF1)
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <net/route.h>
51 #include <sys/mbuf.h>
52 #endif
53
54 #if defined(LINUX)
55 #include <getopt.h>
56 #include <arpa/inet.h>
57 #include <ctype.h>
58 #include <time.h>
59 #endif
60
61 #if defined(AIX)
62 #include <sys/machine.h>
63 #include <sys/types.h>
64 #include <netinet/in.h>
65 #include <time.h>
66 #endif
67
68 #include <netinet/ip.h>
69 #include <netinet/tcp.h>
70 #include <netinet/udp.h>
71 #include <netinet/ip_icmp.h>
72
73 #include <pcap.h>
74 #include <net/bpf.h>
75
76 #include <stdlib.h>
77 #include <string.h>
78 #include <signal.h>
79 #include <sys/ioctl.h>
80
81 #include <locale.h>
82
83 #ifdef USE_PCRE
84 #include "pcre-3.4/pcre.h"
85 #else
86 #include "regex-0.12/regex.h"
87 #endif
88
89 #include "ngrep.h"
90
91 #define dump(_a,_b) ( show_eol ? \
92         dump_line_by_line((_a),(_b)) : _dump((_a),(_b)) )
93
94
95 static char rcsver[] = "$Revision$";
96
97 int snaplen = 65535, promisc = 1, to = 1000;
98 int show_empty = 0, show_hex = 0, quiet = 0;
99 int match_after = 0, keep_matching = 0;
100 int invert_match = 0, bin_match = 0;
101 int matches = 0, max_matches = 0;
102 int live_read = 1, want_delay = 0;
103
104 int show_eol=0;
105
106 char pc_err[PCAP_ERRBUF_SIZE];
107 #ifdef USE_PCRE
108 int err_offset;
109 char *re_err = NULL;
110 #else
111 const char *re_err = NULL;
112 #endif
113
114 int re_match_word = 0, re_ignore_case = 0;
115
116 #ifdef USE_PCRE
117 pcre *pattern = NULL;
118 pcre_extra *pattern_extra = NULL;
119 #else 
120 struct re_pattern_buffer pattern;
121 #endif
122
123 char *match_data = NULL, *bin_data = NULL, *filter = NULL;
124 int (*match_func)() = &blank_match_func;
125 int match_len = 0;
126
127 struct bpf_program pcapfilter;
128 struct in_addr net, mask;
129 pcap_t *pd = NULL;
130 char *dev = NULL;
131 int link_offset;
132
133 char *read_file = NULL, *dump_file = NULL;
134 pcap_dumper_t *pd_dump = NULL;
135
136 struct timeval prev_ts = {0, 0}, prev_delay_ts = {0,0};
137 void (*print_time)() = NULL, (*dump_delay)() = dump_delay_proc_init;
138
139 unsigned ws_row, ws_col;
140
141
142 int main(int argc, char **argv) {
143   int c;
144
145   signal(SIGINT,  clean_exit);
146   signal(SIGQUIT, clean_exit);
147   signal(SIGABRT, clean_exit);
148   signal(SIGPIPE, clean_exit);
149   signal(SIGWINCH, update_windowsize);
150
151   setlocale(LC_ALL, "");
152
153   while ((c = getopt(argc, argv, "LhXViwqpevxlDtTs:n:d:A:I:O:")) != EOF) {
154     switch (c) {
155         case 'L':
156                 show_eol=1;
157                 break;
158     case 'I':  
159       read_file = optarg;
160       break;
161     case 'O':
162       dump_file = optarg;
163       break;
164     case 'A': 
165       match_after = atoi(optarg) + 1;
166       break;
167     case 'd': 
168       dev = optarg;
169       break;
170     case 'n':
171       max_matches = atoi(optarg);
172       break;
173     case 's':
174       snaplen = atoi(optarg);
175       break;
176     case 'T':
177       print_time = &print_time_diff_init;
178       break;
179     case 't':
180       print_time = &print_time_absolute;
181       break;
182     case 'D':
183       want_delay = 1;
184       break;
185     case 'l':
186       setvbuf(stdout, NULL, _IOLBF, 0);
187       break;
188     case 'x':
189       show_hex++;
190       break;
191     case 'v':
192       invert_match++;
193       break;
194     case 'e':
195       show_empty++;
196       break;
197     case 'p':
198       promisc = 0;
199       break;
200     case 'q':
201       quiet++;
202       break;
203     case 'w':
204       re_match_word++;
205       break;
206     case 'i':
207       re_ignore_case++;
208       break;
209     case 'V':
210       version();
211     case 'X':
212       bin_match++;
213       break;
214     case 'h':
215       usage(0);
216     default:
217       usage(-1);
218     }
219   }
220
221
222   if (argv[optind]) 
223     match_data = argv[optind++];
224
225   if (read_file) {
226     if (!(pd = pcap_open_offline(read_file, pc_err))) {
227       perror(pc_err);
228       clean_exit(-1);
229     }
230
231     live_read = 0;
232     printf("input: %s\n", read_file);
233
234   } else {
235     if (!dev)
236       if (!(dev = pcap_lookupdev(pc_err))) {
237         perror(pc_err);
238         clean_exit(-1);
239       }
240     
241     if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) {
242       perror(pc_err);
243       clean_exit(-1);
244     }
245
246     if (pcap_lookupnet(dev, &net.s_addr, &mask.s_addr, pc_err) == -1) {
247       perror(pc_err);
248       memset(&net, 0, sizeof(net));
249       memset(&mask, 0, sizeof(mask));
250     } 
251
252     if (!quiet) {
253       printf("interface: %s", dev);
254       if (net.s_addr && mask.s_addr) {
255         printf(" (%s/", inet_ntoa(net));
256         printf("%s)", inet_ntoa(mask)); 
257       }
258       printf("\n");
259     }
260   }
261
262
263   if (argv[optind]) {
264     filter = get_filter(&argv[optind]); 
265
266     if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
267       free(filter); 
268       filter = get_filter(&argv[optind-1]); 
269
270 #ifdef NEED_RESTART
271       PCAP_RESTART();
272 #endif
273       if (pcap_compile(pd, &pcapfilter, filter, 0, mask.s_addr)) {
274         pcap_perror(pd, "pcap compile");
275         clean_exit(-1);
276       } else match_data = NULL;
277     }
278
279     if (!quiet) printf("filter: %s\n", filter); 
280     
281     if (pcap_setfilter(pd, &pcapfilter)) {
282       pcap_perror(pd, "pcap set");
283       clean_exit(-1);
284     }
285   }
286
287   if (match_data) {
288     if (bin_match) {
289       int i = 0, n;
290       char *s, *d;
291       int len;
292
293       if (re_match_word || re_ignore_case) {
294         fprintf(stderr, "fatal: regex switches are incompatible with binary matching\n");
295         clean_exit(-1);
296       }
297
298       len = strlen(match_data);
299       if (len % 2 != 0 || !strishex(match_data)) {
300         fprintf(stderr, "fatal: invalid hex string specified\n");
301         clean_exit(-1);
302       }
303
304       bin_data = malloc(len / 2);
305       memset(bin_data, 0, len / 2);
306       d = bin_data;
307
308       if ((s = strchr(match_data, 'x'))) 
309         len -= ++s - match_data - 1;
310       else s = match_data;
311
312       while (i <= len) {
313         sscanf(s+i, "%2x", &n);
314         *d++ = n;
315         i += 2;
316       }
317
318       match_len = len / 2;
319       match_func = &bin_match_func;
320
321     } else {
322
323 #ifdef USE_PCRE
324       int pcre_options = PCRE_UNGREEDY;
325
326       if (re_ignore_case) 
327         pcre_options |= PCRE_CASELESS;
328       
329       re_err = malloc(512);
330 #else
331       re_syntax_options = RE_SYNTAX_EGREP;
332       
333       if (re_ignore_case) {
334         char *s;
335         int i;
336         
337         pattern.translate = (char*)malloc(256);
338         s = pattern.translate;
339         for (i = 0; i < 256; i++) 
340           s[i] = i;
341         for (i = 'A'; i <= 'Z'; i++) 
342           s[i] = i + 32;
343
344         s = match_data;
345         while (*s) 
346           *s++ = tolower(*s);
347       } else pattern.translate = NULL;
348 #endif
349
350       if (re_match_word) {
351         char *word_regex = malloc(strlen(match_data) * 3 + strlen(WORD_REGEX));
352         sprintf(word_regex, WORD_REGEX, match_data, match_data, match_data);
353         match_data = word_regex;
354       }
355
356 #ifdef USE_PCRE
357       pattern = pcre_compile(match_data, pcre_options, (const char **)&re_err, &err_offset, 0);
358       if (!pattern) {
359         fprintf(stderr, "compile failed: %s\n", re_err);
360         clean_exit(-1);
361       }
362
363       pattern_extra = pcre_study(pattern, 0, (const char **)&re_err);
364       
365       free(re_err);
366       re_err = NULL;
367 #else
368       re_err = re_compile_pattern(match_data, strlen(match_data), &pattern);
369       if (re_err) {
370         fprintf(stderr, "regex compile: %s\n", re_err);
371         clean_exit(-1);
372       }
373
374       pattern.fastmap = (char*)malloc(256);
375       if (re_compile_fastmap(&pattern)) {
376         perror("fastmap compile failed");
377         clean_exit(-1);
378       }
379 #endif
380
381       match_func = &re_match_func;
382     }
383
384     if (!quiet && match_data && strlen(match_data)) 
385       printf("%smatch: %s%s\n", invert_match?"don't ":"", 
386              (bin_data && !strchr(match_data, 'x'))?"0x":"", match_data);
387   }
388
389
390   if (filter) free(filter);
391   if (re_match_word) free(match_data);
392
393
394   switch(pcap_datalink(pd)) {
395   case DLT_EN10MB:
396     link_offset = ETHHDR_SIZE;
397     break;
398
399   case DLT_IEEE802:
400     link_offset = TOKENRING_SIZE;
401     break;
402     
403   case DLT_FDDI:
404     link_offset = FDDIHDR_SIZE;
405     break;
406
407   case DLT_SLIP: 
408     link_offset = SLIPHDR_SIZE;
409     break;
410     
411   case DLT_PPP:
412     link_offset = PPPHDR_SIZE;
413     break;
414
415   case DLT_RAW: 
416     link_offset = RAWHDR_SIZE;
417     break;
418
419   case DLT_LOOP:
420   case DLT_NULL:
421     link_offset = LOOPHDR_SIZE;
422     break;
423
424   case DLT_LINUX_SLL:
425     link_offset = ISDNHDR_SIZE;
426     break;
427
428   default:
429     fprintf(stderr, "fatal: unsupported interface type %d\n", pcap_datalink(pd));
430     clean_exit(-1);
431   }
432   
433   if (dump_file) {
434     if (!(pd_dump = pcap_dump_open(pd, dump_file))) {
435       fprintf(stderr, "fatal: %s\n", pcap_geterr(pd));
436       clean_exit(-1);
437     } else printf("output: %s\n", dump_file);
438   }
439
440   update_windowsize(0);
441
442   while (pcap_loop(pd, 0, (pcap_handler)process, 0));
443
444   clean_exit(0);
445 }       
446
447
448 void process(u_char *data1, struct pcap_pkthdr* h, u_char *p) {
449   struct ip* ip_packet = (struct ip *)(p + link_offset);
450
451 #if defined(AIX)
452 #undef ip_hl
453   unsigned ip_hl = ip_packet->ip_ff.ip_fhl*4;
454 #else
455   unsigned ip_hl = ip_packet->ip_hl*4;
456 #endif
457
458   unsigned ip_off = ntohs(ip_packet->ip_off);
459   unsigned fragmented = ip_off & (IP_MF | IP_OFFMASK);
460   unsigned frag_offset = fragmented?(ip_off & IP_OFFMASK) * 8:0;
461
462   char *data;
463   int len;
464
465   switch (ip_packet->ip_p) {
466   case IPPROTO_TCP: {
467     struct tcphdr* tcp = (struct tcphdr *)(((char *)ip_packet) + ip_hl);
468     unsigned tcphdr_offset = fragmented?0:(tcp->th_off * 4);
469
470     if (!quiet) {
471       printf("#");
472       fflush(stdout);
473     }
474     
475     data = ((char*)tcp) + tcphdr_offset;
476
477     if ((len = ntohs(ip_packet->ip_len)) < h->caplen)
478       len -= ip_hl + tcphdr_offset;
479     else len = h->caplen - link_offset - ip_hl - tcphdr_offset;
480
481     if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
482         || keep_matching) { 
483
484       if (!live_read && want_delay)
485         dump_delay(h);
486
487       printf("\nT ");
488
489       if (print_time) 
490         print_time(h);
491
492       if (tcphdr_offset || !frag_offset) {
493         printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(tcp->th_sport));
494         printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(tcp->th_dport));
495         printf(" [%s%s%s%s%s%s]",
496                (tcp->th_flags & TH_ACK)?"A":"",
497                (tcp->th_flags & TH_SYN)?"S":"",
498                (tcp->th_flags & TH_RST)?"R":"",
499                (tcp->th_flags & TH_FIN)?"F":"",
500                (tcp->th_flags & TH_URG)?"U":"",
501                (tcp->th_flags & TH_PUSH)?"P":"");
502       } else {
503         printf("%s -", inet_ntoa(ip_packet->ip_src));
504         printf("> %s", inet_ntoa(ip_packet->ip_dst));
505       }
506
507       if (fragmented) 
508         printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
509                                 frag_offset, len); 
510       else printf("\n");
511       
512       if (pd_dump) {
513         pcap_dump((u_char*)pd_dump, h, p);
514         if (!quiet) dump(data, len);
515       } else dump(data, len);
516     }
517   }
518   break;
519
520   case IPPROTO_UDP: {
521     struct udphdr* udp = (struct udphdr *)(((char *)ip_packet) + ip_hl);
522     unsigned udphdr_offset = (fragmented)?0:sizeof(struct udphdr); 
523
524     if (!quiet) {
525       printf("#"); 
526       fflush(stdout);
527     }
528
529     data = ((char*)udp) + udphdr_offset;
530
531     if ((len = ntohs(ip_packet->ip_len)) < h->caplen)
532       len -= ip_hl + udphdr_offset;
533     else len = h->caplen - link_offset - ip_hl - udphdr_offset;
534
535     if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
536         || keep_matching) { 
537
538       if (!live_read && want_delay)
539         dump_delay(h);
540
541       printf("\nU ");
542
543       if (print_time) 
544         print_time(h);
545
546       if (udphdr_offset || !frag_offset) {
547 #ifdef HAVE_DUMB_UDPHDR
548         printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(udp->source));
549         printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(udp->dest));
550 #else
551         printf("%s:%d -", inet_ntoa(ip_packet->ip_src), ntohs(udp->uh_sport));
552         printf("> %s:%d", inet_ntoa(ip_packet->ip_dst), ntohs(udp->uh_dport));
553 #endif
554       } else {
555         printf("%s -", inet_ntoa(ip_packet->ip_src));
556         printf("> %s", inet_ntoa(ip_packet->ip_dst));
557       }
558
559       if (fragmented) 
560         printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
561                frag_offset, len); 
562       else printf("\n");
563       
564       if (pd_dump) {
565         pcap_dump((u_char*)pd_dump, h, p);
566         if (!quiet) dump(data, len);
567       } else dump(data, len);
568     }
569   }
570   break;
571
572   case IPPROTO_ICMP: {
573     struct icmp* ic = (struct icmp *)(((char *)ip_packet) + ip_hl);
574     unsigned icmphdr_offset = fragmented?0:4;
575
576     if (!quiet) {
577       printf("#"); 
578       fflush(stdout);
579     }
580
581     data = ((char*)ic) + icmphdr_offset;
582
583     if ((len = ntohs(ip_packet->ip_len)) < h->caplen)
584       len -= ip_hl + icmphdr_offset;
585     else len = h->caplen - link_offset - ip_hl - icmphdr_offset;
586
587     if (((len || show_empty) && (((int)(*match_func)(data, len)) != invert_match))
588         || keep_matching) { 
589
590       if (!live_read && want_delay)
591         dump_delay(h);
592
593       printf("\nI ");
594
595       if (print_time) 
596         print_time(h);
597
598       printf("%s -", inet_ntoa(ip_packet->ip_src));
599       printf("> %s", inet_ntoa(ip_packet->ip_dst));
600
601       if (icmphdr_offset || !frag_offset) 
602         printf(" %d:%d", ic->icmp_type, ic->icmp_code);
603
604       if (fragmented) 
605         printf(" %s%d@%d:%d\n", frag_offset?"+":"", ntohs(ip_packet->ip_id),
606                                 frag_offset, len); 
607       else printf("\n");
608
609       if (pd_dump) {
610         pcap_dump((u_char*)pd_dump, h, p);
611         if (!quiet) dump(data, len);
612       } else dump(data, len);
613     }
614   }
615   break;
616   
617   }
618
619   if (match_after && keep_matching)
620     keep_matching--;
621 }
622
623
624 int re_match_func(char *data, int len) {
625 #ifdef USE_PCRE
626   switch(pcre_exec(pattern, 0, data, len, 0, 0, 0, 0)) {
627    case PCRE_ERROR_NULL:
628    case PCRE_ERROR_BADOPTION:
629    case PCRE_ERROR_BADMAGIC: 
630    case PCRE_ERROR_UNKNOWN_NODE: 
631    case PCRE_ERROR_NOMEMORY:
632      perror("she's dead, jim\n");
633      clean_exit(-2);
634
635    case PCRE_ERROR_NOMATCH: 
636      return 0;
637   }
638 #else
639   switch (re_search(&pattern, data, len, 0, len, 0)) {
640    case -2: 
641      perror("she's dead, jim\n");
642      clean_exit(-2);
643
644    case -1:
645      return 0;
646   }
647 #endif
648   
649   if (max_matches && ++matches > max_matches)
650     clean_exit(0);
651
652   if (match_after && keep_matching != match_after)
653     keep_matching = match_after;
654
655   return 1;
656 }
657
658
659 int bin_match_func(char *data, int len) {
660   int stop = len - match_len;
661   int i = 0;
662
663   if (stop < 0)
664     return 0;
665
666   while (i <= stop) 
667     if (!memcmp(data+(i++), bin_data, match_len)) {
668       if (max_matches && ++matches > max_matches)
669         clean_exit(0);
670
671       if (match_after && keep_matching != match_after)
672         keep_matching = match_after;
673
674       return 1;
675     }
676
677   return 0;
678 }
679
680
681 int blank_match_func(char *data, int len) {
682   if (max_matches && ++matches > max_matches)
683     clean_exit(0);
684
685   return 1;
686 }
687
688 void dump_line_by_line( char *data, int len )
689 {
690         unsigned width;
691         char *c;
692         
693         c=data;
694
695         while( c< data + len) {
696                 if (*c=='\n') {
697                         puts("");
698                 } else {
699                         putchar(isprint(*c)?*c:'.');
700                 }
701                 c++;
702
703         }
704         puts("");
705
706 }
707
708
709 void _dump(char *data, int len) {  
710   if (len > 0) {
711     unsigned width = show_hex?16:(ws_col-5);
712     char *str = data;
713     int j, i = 0;
714
715     while (i < len) {
716       printf("  ");
717
718       if (show_hex) 
719         for (j = 0; j < width; j++) {
720           if (i+j < len) 
721             printf("%02x ", (unsigned char)str[j]);
722           else printf("   ");
723
724           if ((j+1) % (width/2) == 0)
725             printf("   ");
726         }
727
728       for (j = 0; j < width; j++) 
729         if (i+j < len) 
730           printf("%c", isprint(str[j])?str[j]:'.');
731         else printf(" ");
732       
733       str += width;
734       i += j;
735
736       printf("\n");
737     }
738   }
739 }
740
741
742 char *get_filter(char **argv) {
743   char **arg = argv, *theirs, *mine;
744   char *from, *to;
745   int len = 0;
746
747   if (!*arg)
748     return NULL;
749
750   while (*arg) 
751     len += strlen(*arg++) + 1;
752
753   if (!(theirs = (char*)malloc(len + 1)) || 
754       !(mine = (char*)malloc(len + sizeof(IP_ONLY))))
755     return NULL;
756
757   memset(theirs, 0, len + 1);
758   memset(mine, 0, len + sizeof(IP_ONLY));
759
760   arg = argv;
761   to = theirs;
762
763   while ((from = *arg++)) {
764     while ((*to++ = *from++));
765     *(to-1) = ' ';
766   }
767
768   sprintf(mine, IP_ONLY, theirs);
769
770   free(theirs);
771   return mine;
772 }
773
774
775 int strishex(char *str) {
776   char *s;
777   if ((s = strchr(str, 'x'))) 
778     s++;
779   else s = str;
780
781   while (*s) 
782     if (!isxdigit(*s++))
783       return 0;
784
785   return 1;
786 }
787
788
789 void print_time_absolute(struct pcap_pkthdr *h) {
790 #ifdef MACOSX
791   struct tm *t = localtime((const time_t *)&h->ts.tv_sec);
792 #else
793   struct tm *t = localtime(&h->ts.tv_sec);
794 #endif
795
796   printf("%02d/%02d/%02d %02d:%02d:%02d.%06d ",
797          t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour,
798          t->tm_min, t->tm_sec, h->ts.tv_usec);
799 }
800
801
802 void print_time_diff_init(struct pcap_pkthdr *h) {
803   print_time = &print_time_diff;
804
805   prev_ts.tv_sec = h->ts.tv_sec;
806   prev_ts.tv_usec = h->ts.tv_usec;
807   
808   print_time(h);
809 }
810
811 void print_time_diff(struct pcap_pkthdr *h) { 
812   unsigned secs, usecs;
813
814   secs = h->ts.tv_sec - prev_ts.tv_sec;
815   if (h->ts.tv_usec >= prev_ts.tv_usec)
816     usecs = h->ts.tv_usec - prev_ts.tv_usec;
817   else {
818     secs--; 
819     usecs = 1000000 - (prev_ts.tv_usec - h->ts.tv_usec);
820   }
821
822   printf("+%d.%06d ", secs, usecs);
823
824   prev_ts.tv_sec = h->ts.tv_sec;
825   prev_ts.tv_usec = h->ts.tv_usec;
826 }
827
828 void dump_delay_proc_init(struct pcap_pkthdr *h) {
829   dump_delay = &dump_delay_proc;
830
831   prev_delay_ts.tv_sec = h->ts.tv_sec;
832   prev_delay_ts.tv_usec = h->ts.tv_usec;
833
834   dump_delay(h);
835 }
836
837 void dump_delay_proc(struct pcap_pkthdr *h) {
838   unsigned secs, usecs;
839
840   secs = h->ts.tv_sec - prev_delay_ts.tv_sec;
841   if (h->ts.tv_usec >= prev_delay_ts.tv_usec)
842     usecs = h->ts.tv_usec - prev_delay_ts.tv_usec;
843   else {
844     secs--; 
845     usecs = 1000000 - (prev_delay_ts.tv_usec - h->ts.tv_usec);
846   }
847
848   sleep(secs);
849   usleep(usecs);
850   
851   prev_delay_ts.tv_sec = h->ts.tv_sec;
852   prev_delay_ts.tv_usec = h->ts.tv_usec;
853 }
854
855
856 void update_windowsize(int e) {
857   const struct winsize ws;
858   
859   if (!ioctl(0, TIOCGWINSZ, &ws)) {
860     ws_row = ws.ws_row;
861     ws_col = ws.ws_col;
862   } else {
863     ws_row = 24;
864     ws_col = 80;
865   }
866 }
867
868
869 void usage(int e) {
870   printf("usage: ngrep <-hLXViwqpevxlDtT> <-IO pcap_dump> <-n num> <-d dev> <-A num>\n"
871          "                               <-s snaplen> <match expression> <bpf filter>\n");
872   exit(e);
873 }
874
875
876 void version(void) {
877   printf("ngrep: V%s, %s\n", VERSION, rcsver);
878   exit(0);
879 }
880
881
882 void clean_exit(int sig) {
883   struct pcap_stat s;
884   if (!quiet && sig >= 0) printf("exit\n");
885
886 #ifdef USE_PCRE
887   if (re_err) free(re_err);
888   if (pattern) pcre_free(pattern);
889   if (pattern_extra) pcre_free(pattern_extra);
890 #else
891   if (pattern.translate) free(pattern.translate);
892   if (pattern.fastmap) free(pattern.fastmap);
893 #endif
894
895   if (bin_data) free(bin_data);
896   
897   if (!quiet && sig >= 0 && !read_file &&
898       pd && !pcap_stats(pd, &s)) 
899     printf("%d received, %d dropped\n", s.ps_recv, s.ps_drop);
900
901   if (pd) pcap_close(pd);
902   if (pd_dump) pcap_dump_close(pd_dump);
903
904   exit(sig);
905 }
906
907