need init of fromlen once per loop
[unix-history] / usr / src / sbin / ping / ping.c
index 55f6ed5..827c6e7 100644 (file)
@@ -1,6 +1,29 @@
+/*
+ * Copyright (c) 1987, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)ping.c     4.2 (Berkeley) %G%";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1987, 1988 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ping.c     4.12 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
  *                     P I N G . C
 
 /*
  *                     P I N G . C
@@ -37,10 +60,13 @@ static char sccsid[] = "@(#)ping.c  4.2 (Berkeley) %G%";
 #include <netdb.h>
 
 #define        MAXWAIT         10      /* max time to wait for response, sec. */
 #include <netdb.h>
 
 #define        MAXWAIT         10      /* max time to wait for response, sec. */
-char   ttyobuf[4096];
+#define        MAXPACKET       4096    /* max packet size */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
 
 int    verbose;
 
 int    verbose;
-u_char packet[1024];
+u_char packet[MAXPACKET];
 int    options;
 extern int errno;
 
 int    options;
 extern int errno;
 
@@ -51,12 +77,14 @@ struct timezone tz; /* leftover */
 struct sockaddr whereto;/* Who to ping */
 int datalen;           /* How much data */
 
 struct sockaddr whereto;/* Who to ping */
 int datalen;           /* How much data */
 
-char usage[] = "Usage:  ping [-drv] host [data size]\n";
+char usage[] = "Usage:  ping [-drv] host [data size] [npackets]\n";
 
 char *hostname;
 
 char *hostname;
-char hnamebuf[64];
+char hnamebuf[MAXHOSTNAMELEN];
+char *inet_ntoa();
 
 int npackets;
 
 int npackets;
+int burst = 1;
 int ntransmitted = 0;          /* sequence # for outbound packets = #sent */
 int ident;
 
 int ntransmitted = 0;          /* sequence # for outbound packets = #sent */
 int ident;
 
@@ -75,8 +103,10 @@ char *argv[];
 {
        struct sockaddr_in from;
        char **av = argv;
 {
        struct sockaddr_in from;
        char **av = argv;
+       char *toaddr = NULL;
        struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
        int on = 1;
        struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
        int on = 1;
+       struct protoent *proto;
 
        argc--, av++;
        while (argc > 0 && *av[0] == '-') {
 
        argc--, av++;
        while (argc > 0 && *av[0] == '-') {
@@ -99,26 +129,32 @@ char *argv[];
        }
 
        bzero( (char *)&whereto, sizeof(struct sockaddr) );
        }
 
        bzero( (char *)&whereto, sizeof(struct sockaddr) );
-       hp = gethostbyname(av[0]);
-       if (hp) {
+       to->sin_family = AF_INET;
+       to->sin_addr.s_addr = inet_addr(av[0]);
+       if (to->sin_addr.s_addr != -1) {
+               strcpy(hnamebuf, av[0]);
+               hostname = hnamebuf;
+       } else {
+               hp = gethostbyname(av[0]);
+               if (!hp) {
+                       fprintf(stderr, "ping: %s: ", av[0]);
+                       herror((char *)NULL);
+                       exit(1);
+               }
                to->sin_family = hp->h_addrtype;
                bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
                hostname = hp->h_name;
                to->sin_family = hp->h_addrtype;
                bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
                hostname = hp->h_name;
-       } else {
-               to->sin_family = AF_INET;
-               to->sin_addr.s_addr = inet_addr(av[1]);
-               if (to->sin_addr.s_addr == -1) {
-                       printf("%s: unknown host %s\n", argv[0], av[1]);
-                       return;
-               }
-               strcpy(hnamebuf, av[1]);
-               hostname = hnamebuf;
+               toaddr = inet_ntoa(to->sin_addr.s_addr);
        }
 
        if( argc >= 2 )
                datalen = atoi( av[1] );
        else
                datalen = 64-8;
        }
 
        if( argc >= 2 )
                datalen = atoi( av[1] );
        else
                datalen = 64-8;
+       if (datalen > MAXPACKET) {
+               fprintf(stderr, "ping: packet size too large\n");
+               exit(1);
+       }
        if (datalen >= sizeof(struct timeval))
                timing = 1;
        if (argc > 2)
        if (datalen >= sizeof(struct timeval))
                timing = 1;
        if (argc > 2)
@@ -126,7 +162,11 @@ char *argv[];
 
        ident = getpid() & 0xFFFF;
 
 
        ident = getpid() & 0xFFFF;
 
-       if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
+       if ((proto = getprotobyname("icmp")) == NULL) {
+               fprintf(stderr, "icmp: unknown protocol\n");
+               exit(10);
+       }
+       if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
                perror("ping: socket");
                exit(5);
        }
                perror("ping: socket");
                exit(5);
        }
@@ -135,9 +175,13 @@ char *argv[];
        if (options & SO_DONTROUTE)
                setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
 
        if (options & SO_DONTROUTE)
                setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
 
-       printf("PING %s: %d data bytes\n", hostname, datalen );
+       printf("PING %s", hostname);
+       if (toaddr)
+               printf(" (%s)", toaddr);
+       printf(": %d data bytes\n", datalen);
+                               
 
 
-       setbuffer( stdout, ttyobuf, sizeof(ttyobuf) );
+       setlinebuf( stdout );
 
        signal( SIGINT, finish );
        signal(SIGALRM, catcher);
 
        signal( SIGINT, finish );
        signal(SIGALRM, catcher);
@@ -146,9 +190,10 @@ char *argv[];
 
        for (;;) {
                int len = sizeof (packet);
 
        for (;;) {
                int len = sizeof (packet);
-               int fromlen = sizeof (from);
+               int fromlen;
                int cc;
 
                int cc;
 
+               fromlen = sizeof (from);
                if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
                        if( errno == EINTR )
                                continue;
                if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
                        if( errno == EINTR )
                                continue;
@@ -203,9 +248,9 @@ catcher()
  */
 pinger()
 {
  */
 pinger()
 {
-       static u_char outpack[1024];
+       static u_char outpack[MAXPACKET];
        register struct icmp *icp = (struct icmp *) outpack;
        register struct icmp *icp = (struct icmp *) outpack;
-       int i, cc;
+       int i, cc, n;
        register struct timeval *tp = (struct timeval *) &outpack[8];
        register u_char *datap = &outpack[8+sizeof(struct timeval)];
 
        register struct timeval *tp = (struct timeval *) &outpack[8];
        register u_char *datap = &outpack[8+sizeof(struct timeval)];
 
@@ -227,13 +272,15 @@ pinger()
        icp->icmp_cksum = in_cksum( icp, cc );
 
        /* cc = sendto(s, msg, len, flags, to, tolen) */
        icp->icmp_cksum = in_cksum( icp, cc );
 
        /* cc = sendto(s, msg, len, flags, to, tolen) */
-       i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
+       for (n = 0; n < burst; n++) {
+               i = sendto(s, outpack, cc, 0, &whereto, sizeof(whereto));
 
 
-       if( i < 0 || i != cc )  {
-               if( i<0 )  perror("sendto");
-               printf("ping: wrote %s %d chars, ret=%d\n",
-                       hostname, cc, i );
-               fflush(stdout);
+               if( i < 0 || i != cc )  {
+                       if( i<0 )  perror("sendto");
+                       printf("ping: wrote %s %d chars, ret=%d\n",
+                               hostname, cc, i );
+                       fflush(stdout);
+               }
        }
 }
 
        }
 }
 
@@ -280,36 +327,50 @@ register int t;
  * which arrive ('tis only fair).  This permits multiple copies of this
  * program to be run without having intermingled output (or statistics!).
  */
  * which arrive ('tis only fair).  This permits multiple copies of this
  * program to be run without having intermingled output (or statistics!).
  */
-pr_pack( icp, cc, from )
-register struct icmp *icp;
+pr_pack( buf, cc, from )
+char *buf;
 int cc;
 struct sockaddr_in *from;
 {
 int cc;
 struct sockaddr_in *from;
 {
+       struct ip *ip;
+       register struct icmp *icp;
        register long *lp = (long *) packet;
        register int i;
        struct timeval tv;
        register long *lp = (long *) packet;
        register int i;
        struct timeval tv;
-       struct timeval *tp = (struct timeval *) &packet[8];
-       int triptime;
+       struct timeval *tp;
+       int hlen, triptime;
 
        from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
        gettimeofday( &tv, &tz );
 
 
        from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
        gettimeofday( &tv, &tz );
 
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       if (cc < hlen + ICMP_MINLEN) {
+               if (verbose)
+                       printf("packet too short (%d bytes) from %s\n", cc,
+                               inet_ntoa(ntohl(from->sin_addr.s_addr)));
+               return;
+       }
+       cc -= hlen;
+       icp = (struct icmp *)(buf + hlen);
        if( icp->icmp_type != ICMP_ECHOREPLY )  {
                if (verbose) {
        if( icp->icmp_type != ICMP_ECHOREPLY )  {
                if (verbose) {
-                       printf("%d bytes from x%x: ", cc, from->sin_addr.s_addr);
+                       printf("%d bytes from %s: ", cc,
+                               inet_ntoa(ntohl(from->sin_addr.s_addr)));
                        printf("icmp_type=%d (%s)\n",
                                icp->icmp_type, pr_type(icp->icmp_type) );
                        for( i=0; i<12; i++)
                        printf("icmp_type=%d (%s)\n",
                                icp->icmp_type, pr_type(icp->icmp_type) );
                        for( i=0; i<12; i++)
-                       printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++ );
+                           printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++ );
                        printf("icmp_code=%d\n", icp->icmp_code );
                        printf("icmp_code=%d\n", icp->icmp_code );
-                       fflush(stdout);
                }
                return;
        }
        if( icp->icmp_id != ident )
                return;                 /* 'Twas not our ECHO */
 
                }
                return;
        }
        if( icp->icmp_id != ident )
                return;                 /* 'Twas not our ECHO */
 
-       printf("%d bytes from x%x: ", cc, from->sin_addr.s_addr);
+       tp = (struct timeval *)&icp->icmp_data[0];
+       printf("%d bytes from %s: ", cc,
+               inet_ntoa(ntohl(from->sin_addr.s_addr)));
        printf("icmp_seq=%d. ", icp->icmp_seq );
        if (timing) {
                tvsub( &tv, tp );
        printf("icmp_seq=%d. ", icp->icmp_seq );
        if (timing) {
                tvsub( &tv, tp );
@@ -323,94 +384,50 @@ struct sockaddr_in *from;
        } else
                putchar('\n');
        nreceived++;
        } else
                putchar('\n');
        nreceived++;
-       fflush(stdout);
 }
 
 
 /*
  *                     I N _ C K S U M
  *
 }
 
 
 /*
  *                     I N _ C K S U M
  *
- * Checksum routine for Internet Protocol family headers (VAX Version).
+ * Checksum routine for Internet Protocol family headers (C Version)
  *
  *
- * Shamelessly pilfered from /sys/vax/in_cksum.c, with all the MBUF stuff
- * ripped out.
  */
  */
-#if vax
 in_cksum(addr, len)
 u_short *addr;
 int len;
 {
 in_cksum(addr, len)
 u_short *addr;
 int len;
 {
-       register int nleft = len;       /* on vax, (user mode), r11 */
-       register int xxx;               /* on vax, (user mode), r10 */
-       register u_short *w = addr;     /* on vax, known to be r9 */
-       register int sum = 0;           /* on vax, known to be r8 */
-
+       register int nleft = len;
+       register u_short *w = addr;
+       register u_short answer;
+       register int sum = 0;
+       u_short odd_byte = 0;
 
        /*
 
        /*
-        * Force to long boundary so we do longword aligned
-        * memory operations.  It is too hard to do byte
-        * adjustment, do only word adjustment.
+        *  Our algorithm is simple, using a 32 bit accumulator (sum),
+        *  we add sequential 16 bit words to it, and at the end, fold
+        *  back all the carry bits from the top 16 bits into the lower
+        *  16 bits.
         */
         */
-       if (((int)w&0x2) && nleft >= 2) {
+       while( nleft > 1 )  {
                sum += *w++;
                nleft -= 2;
        }
                sum += *w++;
                nleft -= 2;
        }
-       /*
-        * Do as much of the checksum as possible 32 bits at at time.
-        * In fact, this loop is unrolled to make overhead from
-        * branches &c small.
-        *
-        * We can do a 16 bit ones complement sum 32 bits at a time
-        * because the 32 bit register is acting as two 16 bit
-        * registers for adding, with carries from the low added
-        * into the high (by normal carry-chaining) and carries
-        * from the high carried into the low on the next word
-        * by use of the adwc instruction.  This lets us run
-        * this loop at almost memory speed.
-        *
-        * Here there is the danger of high order carry out, and
-        * we carefully use adwc.
-        */
-       while ((nleft -= 32) >= 0) {
-#undef ADD
-               asm("clrl r0");         /* clears carry */
-#define ADD            asm("adwc (r9)+,r8;");
-               ADD; ADD; ADD; ADD; ADD; ADD; ADD; ADD;
-               asm("adwc $0,r8");
-       }
-       nleft += 32;
-       while ((nleft -= 8) >= 0) {
-               asm("clrl r0");
-               ADD; ADD;
-               asm("adwc $0,r8");
-       }
-       nleft += 8;
-       /*
-        * Now eliminate the possibility of carry-out's by
-        * folding back to a 16 bit number (adding high and
-        * low parts together.)  Then mop up trailing words
-        * and maybe an odd byte.
-        */
-       { asm("ashl $-16,r8,r0; addw2 r0,r8");
-         asm("adwc $0,r8; movzwl r8,r8"); }
-       while ((nleft -= 2) >= 0) {
-               asm("movzwl (r9)+,r0; addl2 r0,r8");
-       }
-       if (nleft == -1) {
-               sum += *(u_char *)w;
+
+       /* mop up an odd byte, if necessary */
+       if( nleft == 1 ) {
+               *(u_char *)(&odd_byte) = *(u_char *)w;
+               sum += odd_byte;
        }
 
        /*
        }
 
        /*
-        * Add together high and low parts of sum
-        * and carry to get cksum.
-        * Have to be careful to not drop the last
-        * carry here.
+        * add back carry outs from top 16 bits to low 16 bits
         */
         */
-       { asm("ashl $-16,r8,r0; addw2 r0,r8; adwc $0,r8");
-         asm("mcoml r8,r8; movzwl r8,r8"); }
-       return (sum);
+       sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
+       sum += (sum >> 16);                     /* add carry */
+       answer = ~sum;                          /* truncate to 16 bits */
+       return (answer);
 }
 }
-#endif vax
 
 /*
  *                     T V S U B
 
 /*
  *                     T V S U B
@@ -443,9 +460,14 @@ finish()
        printf("\n----%s PING Statistics----\n", hostname );
        printf("%d packets transmitted, ", ntransmitted );
        printf("%d packets received, ", nreceived );
        printf("\n----%s PING Statistics----\n", hostname );
        printf("%d packets transmitted, ", ntransmitted );
        printf("%d packets received, ", nreceived );
-       if (ntransmitted)
-           printf("%d%% packet loss",
-               (int) (((ntransmitted-nreceived)*100) / ntransmitted ) );
+       if (ntransmitted) {
+               if (nreceived <= ntransmitted)
+                   printf("%d%% packet loss",
+                       (int) (((ntransmitted-nreceived)*100) / ntransmitted));
+               else
+                   printf("%.2f responses per request",
+                       (float) nreceived / (float) ntransmitted);
+       }
        printf("\n");
        if (nreceived && timing)
            printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",
        printf("\n");
        if (nreceived && timing)
            printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",