Return to select.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / ui |
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
1.1.1.3 ! misho 6: it under the terms of the GNU General Public License version 2 as
1.1 misho 7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
1.1.1.2 misho 14: You should have received a copy of the GNU General Public License along
15: with this program; if not, write to the Free Software Foundation, Inc.,
16: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1 misho 17: */
18:
19: #include "config.h"
20:
21: #include <sys/types.h>
22: #include <sys/time.h>
23: #include <stdlib.h>
24: #include <stdio.h>
25: #include <unistd.h>
26: #include <time.h>
27: #include <sys/select.h>
28: #include <string.h>
29: #include <math.h>
30: #include <errno.h>
31: #ifdef HAVE_ERROR_H
32: #include <error.h>
33: #else
34: #include "portability/error.h"
35: #endif
36:
37: #include "mtr.h"
38: #include "dns.h"
39: #include "net.h"
40: #include "asn.h"
41: #include "display.h"
42: #include "select.h"
43:
44: void select_loop(
45: struct mtr_ctl *ctl)
46: {
47: fd_set readfd;
48: fd_set writefd;
49: int anyset = 0;
50: int maxfd = 0;
51: int dnsfd, netfd;
52: #ifdef ENABLE_IPV6
53: int dnsfd6;
54: #endif
55: int NumPing = 0;
56: int paused = 0;
57: struct timeval lasttime, thistime, selecttime;
58: struct timeval startgrace;
59: int dt;
60: int rv;
61: int graceperiod = 0;
62: struct timeval intervaltime;
63: static double dnsinterval = 0;
64:
65: memset(&startgrace, 0, sizeof(startgrace));
66:
67: gettimeofday(&lasttime, NULL);
68:
69: while (1) {
70: dt = calc_deltatime(ctl->WaitTime);
71: intervaltime.tv_sec = dt / 1000000;
72: intervaltime.tv_usec = dt % 1000000;
73:
74: FD_ZERO(&readfd);
75: FD_ZERO(&writefd);
76:
77: maxfd = 0;
78:
79: if (ctl->Interactive) {
80: FD_SET(0, &readfd);
81: maxfd = 1;
82: }
83: #ifdef ENABLE_IPV6
84: if (ctl->dns) {
85: dnsfd6 = dns_waitfd6();
86: if (dnsfd6 >= 0) {
87: FD_SET(dnsfd6, &readfd);
88: if (dnsfd6 >= maxfd)
89: maxfd = dnsfd6 + 1;
90: } else {
91: dnsfd6 = 0;
92: }
93: } else
94: dnsfd6 = 0;
95: #endif
96: if (ctl->dns) {
97: dnsfd = dns_waitfd();
98: FD_SET(dnsfd, &readfd);
99: if (dnsfd >= maxfd)
100: maxfd = dnsfd + 1;
101: } else
102: dnsfd = 0;
103:
104: netfd = net_waitfd();
105: FD_SET(netfd, &readfd);
106: if (netfd >= maxfd)
107: maxfd = netfd + 1;
108:
109: do {
110: if (anyset || paused) {
111: /* Set timeout to 0.1s.
112: * While this is almost instantaneous for human operators,
113: * it's slow enough for computers to go do something else;
114: * this prevents mtr from hogging 100% CPU time on one core.
115: */
116: selecttime.tv_sec = 0;
117: selecttime.tv_usec = paused ? 100000 : 0;
118:
119: rv = select(maxfd, (void *) &readfd, &writefd, NULL,
120: &selecttime);
121:
122: } else {
123: if (ctl->Interactive)
124: display_redraw(ctl);
125:
126: gettimeofday(&thistime, NULL);
127:
128: if (thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec
129: || (thistime.tv_sec ==
130: lasttime.tv_sec + intervaltime.tv_sec
131: && thistime.tv_usec >=
132: lasttime.tv_usec + intervaltime.tv_usec)) {
133: lasttime = thistime;
134:
135: if (!graceperiod) {
136: if (NumPing >= ctl->MaxPing
137: && (!ctl->Interactive || ctl->ForceMaxPing)) {
138: graceperiod = 1;
139: startgrace = thistime;
140: }
141:
142: /* do not send out batch when we've already initiated grace period */
143: if (!graceperiod && net_send_batch(ctl))
144: NumPing++;
145: }
146: }
147:
148: if (graceperiod) {
149: dt = (thistime.tv_usec - startgrace.tv_usec) +
150: 1000000 * (thistime.tv_sec - startgrace.tv_sec);
151: if ((ctl->GraceTime * 1000 * 1000) < dt)
152: return;
153: }
154:
155: selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec);
156: selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec);
157: if (selecttime.tv_usec < 0) {
158: --selecttime.tv_sec;
159: selecttime.tv_usec += 1000000;
160: }
161: selecttime.tv_usec =
162: intervaltime.tv_usec - selecttime.tv_usec;
163: selecttime.tv_sec =
164: intervaltime.tv_sec - selecttime.tv_sec;
165: if (selecttime.tv_usec < 0) {
166: --selecttime.tv_sec;
167: selecttime.tv_usec += 1000000;
168: }
169:
170: if (ctl->dns) {
171: if ((selecttime.tv_sec > (time_t) dnsinterval) ||
172: ((selecttime.tv_sec == (time_t) dnsinterval) &&
173: (selecttime.tv_usec >
174: ((time_t) (dnsinterval * 1000000) % 1000000)))) {
175: selecttime.tv_sec = (time_t) dnsinterval;
176: selecttime.tv_usec =
177: (time_t) (dnsinterval * 1000000) % 1000000;
178: }
179: }
180:
181: rv = select(maxfd, (void *) &readfd, NULL, NULL,
182: &selecttime);
183: }
184: } while ((rv < 0) && (errno == EINTR));
185:
186: if (rv < 0) {
187: error(EXIT_FAILURE, errno, "Select failed");
188: }
189: anyset = 0;
190:
191: /* Have we got new packets back? */
192: if (FD_ISSET(netfd, &readfd)) {
193: net_process_return(ctl);
194: anyset = 1;
195: }
196:
197: if (ctl->dns) {
198: /* Handle any pending resolver events */
199: dnsinterval = ctl->WaitTime;
200: }
201:
202: /* Have we finished a nameservice lookup? */
203: #ifdef ENABLE_IPV6
204: if (ctl->dns && dnsfd6 && FD_ISSET(dnsfd6, &readfd)) {
205: dns_ack6();
206: anyset = 1;
207: }
208: #endif
209: if (ctl->dns && dnsfd && FD_ISSET(dnsfd, &readfd)) {
210: dns_ack(ctl);
211: anyset = 1;
212: }
213:
214: /* Has a key been pressed? */
215: if (FD_ISSET(0, &readfd)) {
216: switch (display_keyaction(ctl)) {
217: case ActionQuit:
218: return;
219: break;
220: case ActionReset:
221: net_reset(ctl);
222: break;
223: case ActionDisplay:
224: ctl->display_mode =
225: (ctl->display_mode + 1) % DisplayModeMAX;
226: break;
227: case ActionClear:
228: display_clear(ctl);
229: break;
230: case ActionPause:
231: paused = 1;
232: break;
233: case ActionResume:
234: paused = 0;
235: break;
236: case ActionMPLS:
237: ctl->enablempls = !ctl->enablempls;
238: display_clear(ctl);
239: break;
240: case ActionDNS:
241: if (ctl->dns) {
242: ctl->use_dns = !ctl->use_dns;
243: display_clear(ctl);
244: }
245: break;
246: #ifdef HAVE_IPINFO
247: case ActionII:
248: ctl->ipinfo_no++;
249: if (ctl->ipinfo_no > ctl->ipinfo_max)
250: ctl->ipinfo_no = 0;
251: break;
252: case ActionAS:
253: ctl->ipinfo_no = ctl->ipinfo_no ? 0 : ctl->ipinfo_max;
254: break;
255: #endif
256:
257: case ActionScrollDown:
258: ctl->display_offset += 5;
259: break;
260: case ActionScrollUp:
261: ctl->display_offset -= 5;
262: if (ctl->display_offset < 0) {
263: ctl->display_offset = 0;
264: }
265: break;
266: }
267: anyset = 1;
268: }
269: }
270: return;
271: }