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