Blame ui/select.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 1997,1998  Matt Kimball
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as 
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.h"
Packit b802ec
Packit b802ec
#include <sys/types.h>
Packit b802ec
#include <sys/time.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <stdio.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
#include <time.h>
Packit b802ec
#include <sys/select.h>
Packit b802ec
#include <string.h>
Packit b802ec
#include <math.h>
Packit b802ec
#include <errno.h>
Packit b802ec
#ifdef HAVE_ERROR_H
Packit b802ec
#include <error.h>
Packit b802ec
#else
Packit b802ec
#include "portability/error.h"
Packit b802ec
#endif
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
#include "dns.h"
Packit b802ec
#include "net.h"
Packit b802ec
#include "asn.h"
Packit b802ec
#include "display.h"
Packit b802ec
#include "select.h"
Packit b802ec
Packit b802ec
void select_loop(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    fd_set readfd;
Packit b802ec
    fd_set writefd;
Packit b802ec
    int anyset = 0;
Packit b802ec
    int maxfd = 0;
Packit b802ec
    int dnsfd, netfd;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    int dnsfd6;
Packit b802ec
#endif
Packit b802ec
    int NumPing = 0;
Packit b802ec
    int paused = 0;
Packit b802ec
    struct timeval lasttime, thistime, selecttime;
Packit b802ec
    struct timeval startgrace;
Packit b802ec
    int dt;
Packit b802ec
    int rv;
Packit b802ec
    int graceperiod = 0;
Packit b802ec
    struct timeval intervaltime;
Packit b802ec
    static double dnsinterval = 0;
Packit b802ec
Packit b802ec
    memset(&startgrace, 0, sizeof(startgrace));
Packit b802ec
Packit b802ec
    gettimeofday(&lasttime, NULL);
Packit b802ec
Packit b802ec
    while (1) {
Packit b802ec
        dt = calc_deltatime(ctl->WaitTime);
Packit b802ec
        intervaltime.tv_sec = dt / 1000000;
Packit b802ec
        intervaltime.tv_usec = dt % 1000000;
Packit b802ec
Packit b802ec
        FD_ZERO(&readfd);
Packit b802ec
        FD_ZERO(&writefd);
Packit b802ec
Packit b802ec
        maxfd = 0;
Packit b802ec
Packit b802ec
        if (ctl->Interactive) {
Packit b802ec
            FD_SET(0, &readfd);
Packit b802ec
            maxfd = 1;
Packit b802ec
        }
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
        if (ctl->dns) {
Packit b802ec
            dnsfd6 = dns_waitfd6();
Packit b802ec
            if (dnsfd6 >= 0) {
Packit b802ec
                FD_SET(dnsfd6, &readfd);
Packit b802ec
                if (dnsfd6 >= maxfd)
Packit b802ec
                    maxfd = dnsfd6 + 1;
Packit b802ec
            } else {
Packit b802ec
                dnsfd6 = 0;
Packit b802ec
            }
Packit b802ec
        } else
Packit b802ec
            dnsfd6 = 0;
Packit b802ec
#endif
Packit b802ec
        if (ctl->dns) {
Packit b802ec
            dnsfd = dns_waitfd();
Packit b802ec
            FD_SET(dnsfd, &readfd);
Packit b802ec
            if (dnsfd >= maxfd)
Packit b802ec
                maxfd = dnsfd + 1;
Packit b802ec
        } else
Packit b802ec
            dnsfd = 0;
Packit b802ec
Packit b802ec
        netfd = net_waitfd();
Packit b802ec
        FD_SET(netfd, &readfd);
Packit b802ec
        if (netfd >= maxfd)
Packit b802ec
            maxfd = netfd + 1;
Packit b802ec
Packit b802ec
        do {
Packit b802ec
            if (anyset || paused) {
Packit b802ec
                /* Set timeout to 0.1s.
Packit b802ec
                 * While this is almost instantaneous for human operators,
Packit b802ec
                 * it's slow enough for computers to go do something else;
Packit b802ec
                 * this prevents mtr from hogging 100% CPU time on one core.
Packit b802ec
                 */
Packit b802ec
                selecttime.tv_sec = 0;
Packit b802ec
                selecttime.tv_usec = paused ? 100000 : 0;
Packit b802ec
Packit b802ec
                rv = select(maxfd, (void *) &readfd, &writefd, NULL,
Packit b802ec
                            &selecttime);
Packit b802ec
Packit b802ec
            } else {
Packit b802ec
                if (ctl->Interactive)
Packit b802ec
                    display_redraw(ctl);
Packit b802ec
Packit b802ec
                gettimeofday(&thistime, NULL);
Packit b802ec
Packit b802ec
                if (thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec
Packit b802ec
                    || (thistime.tv_sec ==
Packit b802ec
                        lasttime.tv_sec + intervaltime.tv_sec
Packit b802ec
                        && thistime.tv_usec >=
Packit b802ec
                        lasttime.tv_usec + intervaltime.tv_usec)) {
Packit b802ec
                    lasttime = thistime;
Packit b802ec
Packit b802ec
                    if (!graceperiod) {
Packit b802ec
                        if (NumPing >= ctl->MaxPing
Packit b802ec
                            && (!ctl->Interactive || ctl->ForceMaxPing)) {
Packit b802ec
                            graceperiod = 1;
Packit b802ec
                            startgrace = thistime;
Packit b802ec
                        }
Packit b802ec
Packit b802ec
                        /* do not send out batch when we've already initiated grace period */
Packit b802ec
                        if (!graceperiod && net_send_batch(ctl))
Packit b802ec
                            NumPing++;
Packit b802ec
                    }
Packit b802ec
                }
Packit b802ec
Packit b802ec
                if (graceperiod) {
Packit b802ec
                    dt = (thistime.tv_usec - startgrace.tv_usec) +
Packit b802ec
                        1000000 * (thistime.tv_sec - startgrace.tv_sec);
Packit b802ec
                    if ((ctl->GraceTime * 1000 * 1000) < dt)
Packit b802ec
                        return;
Packit b802ec
                }
Packit b802ec
Packit b802ec
                selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec);
Packit b802ec
                selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec);
Packit b802ec
                if (selecttime.tv_usec < 0) {
Packit b802ec
                    --selecttime.tv_sec;
Packit b802ec
                    selecttime.tv_usec += 1000000;
Packit b802ec
                }
Packit b802ec
                selecttime.tv_usec =
Packit b802ec
                    intervaltime.tv_usec - selecttime.tv_usec;
Packit b802ec
                selecttime.tv_sec =
Packit b802ec
                    intervaltime.tv_sec - selecttime.tv_sec;
Packit b802ec
                if (selecttime.tv_usec < 0) {
Packit b802ec
                    --selecttime.tv_sec;
Packit b802ec
                    selecttime.tv_usec += 1000000;
Packit b802ec
                }
Packit b802ec
Packit b802ec
                if (ctl->dns) {
Packit b802ec
                    if ((selecttime.tv_sec > (time_t) dnsinterval) ||
Packit b802ec
                        ((selecttime.tv_sec == (time_t) dnsinterval) &&
Packit b802ec
                         (selecttime.tv_usec >
Packit b802ec
                          ((time_t) (dnsinterval * 1000000) % 1000000)))) {
Packit b802ec
                        selecttime.tv_sec = (time_t) dnsinterval;
Packit b802ec
                        selecttime.tv_usec =
Packit b802ec
                            (time_t) (dnsinterval * 1000000) % 1000000;
Packit b802ec
                    }
Packit b802ec
                }
Packit b802ec
Packit b802ec
                rv = select(maxfd, (void *) &readfd, NULL, NULL,
Packit b802ec
                            &selecttime);
Packit b802ec
            }
Packit b802ec
        } while ((rv < 0) && (errno == EINTR));
Packit b802ec
Packit b802ec
        if (rv < 0) {
Packit b802ec
            error(EXIT_FAILURE, errno, "Select failed");
Packit b802ec
        }
Packit b802ec
        anyset = 0;
Packit b802ec
Packit b802ec
        /*  Have we got new packets back?  */
Packit b802ec
        if (FD_ISSET(netfd, &readfd)) {
Packit b802ec
            net_process_return(ctl);
Packit b802ec
            anyset = 1;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        if (ctl->dns) {
Packit b802ec
            /* Handle any pending resolver events */
Packit b802ec
            dnsinterval = ctl->WaitTime;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        /*  Have we finished a nameservice lookup?  */
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
        if (ctl->dns && dnsfd6 && FD_ISSET(dnsfd6, &readfd)) {
Packit b802ec
            dns_ack6();
Packit b802ec
            anyset = 1;
Packit b802ec
        }
Packit b802ec
#endif
Packit b802ec
        if (ctl->dns && dnsfd && FD_ISSET(dnsfd, &readfd)) {
Packit b802ec
            dns_ack(ctl);
Packit b802ec
            anyset = 1;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        /*  Has a key been pressed?  */
Packit b802ec
        if (FD_ISSET(0, &readfd)) {
Packit b802ec
            switch (display_keyaction(ctl)) {
Packit b802ec
            case ActionQuit:
Packit b802ec
                return;
Packit b802ec
                break;
Packit b802ec
            case ActionReset:
Packit b802ec
                net_reset(ctl);
Packit b802ec
                break;
Packit b802ec
            case ActionDisplay:
Packit b802ec
                ctl->display_mode =
Packit b802ec
                    (ctl->display_mode + 1) % DisplayModeMAX;
Packit b802ec
                break;
Packit b802ec
            case ActionClear:
Packit b802ec
                display_clear(ctl);
Packit b802ec
                break;
Packit b802ec
            case ActionPause:
Packit b802ec
                paused = 1;
Packit b802ec
                break;
Packit b802ec
            case ActionResume:
Packit b802ec
                paused = 0;
Packit b802ec
                break;
Packit b802ec
            case ActionMPLS:
Packit b802ec
                ctl->enablempls = !ctl->enablempls;
Packit b802ec
                display_clear(ctl);
Packit b802ec
                break;
Packit b802ec
            case ActionDNS:
Packit b802ec
                if (ctl->dns) {
Packit b802ec
                    ctl->use_dns = !ctl->use_dns;
Packit b802ec
                    display_clear(ctl);
Packit b802ec
                }
Packit b802ec
                break;
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
            case ActionII:
Packit b802ec
                ctl->ipinfo_no++;
Packit b802ec
                if (ctl->ipinfo_no > ctl->ipinfo_max)
Packit b802ec
                    ctl->ipinfo_no = 0;
Packit b802ec
                break;
Packit b802ec
            case ActionAS:
Packit b802ec
                ctl->ipinfo_no = ctl->ipinfo_no ? 0 : ctl->ipinfo_max;
Packit b802ec
                break;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
            case ActionScrollDown:
Packit b802ec
                ctl->display_offset += 5;
Packit b802ec
                break;
Packit b802ec
            case ActionScrollUp:
Packit b802ec
                ctl->display_offset -= 5;
Packit b802ec
                if (ctl->display_offset < 0) {
Packit b802ec
                    ctl->display_offset = 0;
Packit b802ec
                }
Packit b802ec
                break;
Packit b802ec
            }
Packit b802ec
            anyset = 1;
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
    return;
Packit b802ec
}