home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / ICMPCMD.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  7KB  |  284 lines

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: icmpcmd.c 1.2 93/07/16 11:45:26 ROOT_DOS Exp $
  7. *    14 Jun 93    1.2        GT    Fix warnings.                                    *
  8. ****************************************************************************/
  9.  
  10. #include <stdio.h>
  11. #include "global.h"
  12. #include "icmp.h"
  13. #include "ip.h"
  14. #include "mbuf.h"
  15. #include "netuser.h"
  16. #include "internet.h"
  17. #include "timer.h"
  18. #include "socket.h"
  19. #include "proc.h"
  20. #include "session.h"
  21. #include "cmdparse.h"
  22. #include "commands.h"
  23.  
  24. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  25. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  26. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  27. static void pingtx __ARGS((int s,void *ping1,void *p));
  28. static void pinghdr __ARGS((struct session *sp,struct ping *ping));
  29.  
  30. static struct cmds Icmpcmds[] = {
  31.     { "echo",        doicmpec,    0, 0, NULLCHAR },
  32.     { "status",    doicmpstat,    0, 0, NULLCHAR },
  33.     { "trace",    doicmptr,    0, 0, NULLCHAR },
  34.     { NULLCHAR }
  35. };
  36.  
  37. int Icmp_trace;
  38. static int Icmp_echo = 1;
  39.  
  40. int
  41. doicmp(argc,argv,p)
  42. int argc;
  43. char *argv[];
  44. void *p;
  45. {
  46.     return subcmd(Icmpcmds,argc,argv,p);
  47. }
  48.  
  49. static int
  50. doicmpstat(argc,argv,p)
  51. int argc;
  52. char *argv[];
  53. void *p;
  54. {
  55.     register int i;
  56.     int lim;
  57.  
  58.     /* Note that the ICMP variables are shown in column order, because
  59.      * that lines up the In and Out variables on the same line
  60.      */
  61.     lim = NUMICMPMIB/2;
  62.     for(i=1;i<=lim;i++){
  63.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  64.          Icmp_mib[i].value.integer);
  65.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  66.          Icmp_mib[i+lim].value.integer);
  67.     }
  68.     return 0;
  69. }
  70. static int
  71. doicmptr(argc,argv,p)
  72. int argc;
  73. char *argv[];
  74. void *p;
  75. {
  76.     return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
  77. }
  78. static int
  79. doicmpec(argc,argv,p)
  80. int argc;
  81. char *argv[];
  82. void *p;
  83. {
  84.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  85. }
  86.  
  87. /* Send ICMP Echo Request packets */
  88. int
  89. doping(argc,argv,p)
  90. int argc;
  91. char *argv[];
  92. void *p;
  93. {
  94.     struct proc *pinger = NULLPROC;    /* Transmit process */
  95.     struct sockaddr_in from;
  96.     struct icmp icmp;
  97.     struct mbuf *bp;
  98.     int32 timestamp,rtt,abserr;
  99.     int s,fromlen;
  100.     struct ping ping;
  101.     struct session *sp;
  102.  
  103.     memset((char *)&ping,0,sizeof(ping));
  104.     /* Allocate a session descriptor */
  105.     if((sp = ping.sp = newsession(argv[1],PING)) == NULLSESSION){
  106.         tprintf("Too many sessions\n");
  107.         return 1;
  108.     }
  109.     if((sp->s = s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  110.         tprintf("Can't create socket\n");
  111.         keywait(NULLCHAR,1);
  112.         freesession(sp);
  113.         return 1;
  114.     }
  115.     tprintf("Resolving %s... ",sp->name);
  116.     if((ping.target = resolve(sp->name)) == 0){
  117.         tprintf("Host %s unknown\n",sp->name);
  118.         keywait(NULLCHAR,1);
  119.         freesession(sp);
  120.         return 1;
  121.     }
  122.     if(argc > 2)
  123.         ping.len = atoi(argv[2]);
  124.  
  125.     if(argc > 3)
  126.         ping.interval = atol(argv[3]);
  127.  
  128.  
  129.     /* Optionally ping a range of IP addresses */
  130.     if(argc > 4)
  131.         ping.incflag = 1;
  132.  
  133.     if(ping.interval != 0){
  134.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  135.     } else {
  136.         /* One shot ping; let echo_proc hook handle response.
  137.          * An ID of MAXINT16 will not be confused with a legal socket
  138.          * number, which is used to identify repeated pings
  139.          */
  140.         pingem(s,ping.target,0,MAXINT16,ping.len);
  141.         freesession(sp);
  142.         return 0;
  143.     }
  144.     /* Now collect the replies */
  145.     pinghdr(sp,&ping);
  146.     for(;;){
  147.         fromlen = sizeof(from);
  148.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  149.             break;
  150.         ntohicmp(&icmp,&bp);
  151.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  152.             /* Ignore other people's responses */
  153.             free_p(bp);
  154.             continue;
  155.         }
  156.         /* Get stamp */
  157.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  158.          != sizeof(timestamp)){
  159.             /* The timestamp is missing! */
  160.             free_p(bp);    /* Probably not necessary */
  161.             continue;
  162.         }
  163.         free_p(bp);
  164.  
  165.         ping.responses++;
  166.  
  167.         /* Compute round trip time, update smoothed estimates */
  168.         rtt = msclock() - timestamp;
  169.         abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  170.  
  171.         if(ping.responses == 1){
  172.             /* First response, base entire SRTT on it */
  173.             ping.srtt = rtt;
  174.             ping.mdev = 0;
  175.         } else {
  176.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  177.             ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  178.         }
  179.         if((ping.responses % 20) == 0)
  180.             pinghdr(sp,&ping);
  181.         tprintf("%10lu%10lu%5lu%10lu%10lu%10lu\n",
  182.          ping.sent,ping.responses,
  183.          (ping.responses*100 + ping.sent/2)/ping.sent,
  184.          rtt,ping.srtt,ping.mdev);
  185.     }
  186.     if(pinger != NULLPROC)
  187.         killproc(pinger);
  188.     freesession(sp);
  189.     return 0;
  190. }
  191. static void
  192. pinghdr(sp,ping)
  193. struct session *sp;
  194. struct ping *ping;
  195. {
  196.     tprintf("Pinging %s (%s); data %d interval %lu ms:\n",
  197.      sp->name,inet_ntoa(ping->target),ping->len,ping->interval);
  198.     tprintf("      sent      rcvd    %       rtt   avg rtt      mdev\n");
  199. }
  200.  
  201. void
  202. echo_proc(source,dest,icmp,bp)
  203. int32 source;
  204. int32 dest;
  205. struct icmp *icmp;
  206. struct mbuf *bp;
  207. {
  208.     int32 timestamp,rtt;
  209.  
  210.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  211.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  212.      == sizeof(timestamp)){
  213.         /* Compute round trip time */
  214.         rtt = msclock() - timestamp;
  215.         tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  216.     }
  217.     free_p(bp);
  218. }
  219. /* Ping transmit process. Runs until killed */
  220. static void
  221. pingtx(s,ping1,p)
  222. int s;        /* Socket to use */
  223. void *ping1;
  224. void *p;
  225. {
  226.     struct ping *ping;
  227.  
  228.     ping = (struct ping *)ping1;
  229.     ping->sent = 0;
  230.     if(ping->incflag){
  231.         for(;;){
  232.             pingem(s,ping->target++,0,MAXINT16,ping->len);
  233.             ping->sent++;
  234.             pause(ping->interval);
  235.         }
  236.     } else {
  237.         for(;;){
  238.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  239.             pause(ping->interval);
  240.         }
  241.     }
  242. }
  243.  
  244.  
  245. /* Send ICMP Echo Request packet */
  246. int
  247. pingem(s,target,seq,id,len)
  248. int s;        /* Raw socket on which to send ping */
  249. int32 target;    /* Site to be pinged */
  250. int16 seq;    /* ICMP Echo Request sequence number */
  251. int16 id;    /* ICMP Echo Request ID */
  252. int16 len;    /* Length of optional data field */
  253. {
  254.     struct mbuf *data;
  255.     struct mbuf *bp;
  256.     struct icmp icmp;
  257.     struct sockaddr_in to;
  258.     int32 clock;
  259.  
  260.     clock = msclock();
  261.     data = ambufw((int16)(len+sizeof(clock)));
  262.     data->cnt = len+sizeof(clock);
  263.     /* Set optional data field, if any, to all 55's */
  264.     if(len != 0)
  265.         memset(data->data+sizeof(clock),0x55,len);
  266.  
  267.     /* Insert timestamp and build ICMP header */
  268.     memcpy(data->data,(char *)&clock,sizeof(clock));
  269.     icmpOutEchos++;
  270.     icmpOutMsgs++;
  271.     icmp.type = ICMP_ECHO;
  272.     icmp.code = 0;
  273.     icmp.args.echo.seq = seq;
  274.     icmp.args.echo.id = id;
  275.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  276.         free_p(data);
  277.         return 0;
  278.     }
  279.     to.sin_family = AF_INET;
  280.     to.sin_addr.s_addr = target;
  281.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  282.     return 0;
  283. }
  284.