home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / network / src_1218.zip / ICMPCMD.C < prev    next >
C/C++ Source or Header  |  1991-08-04  |  7KB  |  278 lines

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