home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / KA9Q / MSWIN / ICMPCMD.ZIP / ICMPCMD.C next >
Encoding:
C/C++ Source or Header  |  1992-02-05  |  8.0 KB  |  319 lines

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