File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / ui / select.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:07:30 2021 UTC (3 years, 3 months ago) by misho
Branches: mtr, MAIN
CVS tags: v0_94, HEAD
mtr 0.94

    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
    6:     it under the terms of the GNU General Public License version 2 as 
    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: 
   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.
   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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>