/*
mtr -- a network diagnostic tool
Copyright (C) 1997,1998 Matt Kimball
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/select.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include "mtr.h"
#include "display.h"
#include "dns.h"
#include "net.h"
extern int Interactive;
extern int MaxPing;
extern int ForceMaxPing;
extern float WaitTime;
double dnsinterval;
static struct timeval intervaltime;
int display_offset = 0;
void select_loop(void) {
fd_set readfd;
int anyset = 0;
int maxfd = 0;
int dnsfd, netfd;
int NumPing = 0;
int paused = 0;
struct timeval lasttime, thistime, selecttime;
int dt;
int rv;
gettimeofday(&lasttime, NULL);
while(1) {
dt = calc_deltatime (WaitTime);
intervaltime.tv_sec = dt / 1000000;
intervaltime.tv_usec = dt % 1000000;
FD_ZERO(&readfd);
maxfd = 0;
if(Interactive) {
FD_SET(0, &readfd);
maxfd = 1;
}
if (dns) {
dnsfd = dns_waitfd();
FD_SET(dnsfd, &readfd);
if(dnsfd >= maxfd) maxfd = dnsfd + 1;
} else
dnsfd = 0;
netfd = net_waitfd();
FD_SET(netfd, &readfd);
if(netfd >= maxfd) maxfd = netfd + 1;
do {
if(anyset || paused) {
selecttime.tv_sec = 0;
selecttime.tv_usec = 0;
rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
} else {
if(Interactive) display_redraw();
gettimeofday(&thistime, NULL);
if(thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec ||
(thistime.tv_sec == lasttime.tv_sec + intervaltime.tv_sec &&
thistime.tv_usec >= lasttime.tv_usec + intervaltime.tv_usec)) {
lasttime = thistime;
if(NumPing >= MaxPing && (!Interactive || ForceMaxPing))
return;
if (net_send_batch())
NumPing++;
}
selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec);
selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec);
if (selecttime.tv_usec < 0) {
--selecttime.tv_sec;
selecttime.tv_usec += 1000000;
}
selecttime.tv_usec = intervaltime.tv_usec - selecttime.tv_usec;
selecttime.tv_sec = intervaltime.tv_sec - selecttime.tv_sec;
if (selecttime.tv_usec < 0) {
--selecttime.tv_sec;
selecttime.tv_usec += 1000000;
}
if (dns) {
if ((selecttime.tv_sec > (time_t)dnsinterval) ||
((selecttime.tv_sec == (time_t)dnsinterval) &&
(selecttime.tv_usec > ((time_t)(dnsinterval * 1000000) % 1000000)))) {
selecttime.tv_sec = (time_t)dnsinterval;
selecttime.tv_usec = (time_t)(dnsinterval * 1000000) % 1000000;
}
}
rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
}
} while ((rv < 0) && (errno == EINTR));
if (rv < 0) {
perror ("Select failed");
exit (1);
}
anyset = 0;
/* Have we got new packets back? */
if(FD_ISSET(netfd, &readfd)) {
net_process_return();
anyset = 1;
}
if (dns) {
/* Handle any pending resolver events */
dnsinterval = WaitTime;
dns_events(&dnsinterval);
}
/* Have we finished a nameservice lookup? */
if(dns && FD_ISSET(dnsfd, &readfd)) {
dns_ack();
anyset = 1;
}
/* Has a key been pressed? */
if(FD_ISSET(0, &readfd)) {
switch (display_keyaction()) {
case ActionQuit:
return;
break;
case ActionReset:
net_reset();
break;
case ActionDisplay:
display_mode = (display_mode+1) % 3;
break;
case ActionClear:
display_clear();
break;
case ActionPause:
paused=1;
break;
case ActionResume:
paused=0;
break;
case ActionDNS:
if (dns) {
use_dns = !use_dns;
display_clear();
}
break;
case ActionScrollDown:
display_offset += 5;
break;
case ActionScrollUp:
display_offset -= 5;
if (display_offset < 0) {
display_offset = 0;
}
break;
}
anyset = 1;
}
}
return;
}