Annotation of 43BSDTahoe/etc/ping.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1987 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted
        !             6:  * provided that the above copyright notice and this paragraph are
        !             7:  * duplicated in all such forms and that any documentation,
        !             8:  * advertising materials, and other materials related to such
        !             9:  * distribution and use acknowledge that the software was developed
        !            10:  * by the University of California, Berkeley.  The name of the
        !            11:  * University may not be used to endorse or promote products derived
        !            12:  * from this software without specific prior written permission.
        !            13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            15:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: char copyright[] =
        !            20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
        !            21:  All rights reserved.\n";
        !            22: #endif /* not lint */
        !            23: 
        !            24: #ifndef lint
        !            25: static char sccsid[] = "@(#)ping.c     4.9 (Berkeley) 6/18/88";
        !            26: #endif /* not lint */
        !            27: 
        !            28: /*
        !            29:  *                     P I N G . C
        !            30:  *
        !            31:  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
        !            32:  * measure round-trip-delays and packet loss across network paths.
        !            33:  *
        !            34:  * Author -
        !            35:  *     Mike Muuss
        !            36:  *     U. S. Army Ballistic Research Laboratory
        !            37:  *     December, 1983
        !            38:  * Modified at Uc Berkeley
        !            39:  *
        !            40:  * Status -
        !            41:  *     Public Domain.  Distribution Unlimited.
        !            42:  *
        !            43:  * Bugs -
        !            44:  *     More statistics could always be gathered.
        !            45:  *     This program has to run SUID to ROOT to access the ICMP socket.
        !            46:  */
        !            47: 
        !            48: #include <stdio.h>
        !            49: #include <errno.h>
        !            50: #include <sys/time.h>
        !            51: 
        !            52: #include <sys/param.h>
        !            53: #include <sys/socket.h>
        !            54: #include <sys/file.h>
        !            55: 
        !            56: #include <netinet/in_systm.h>
        !            57: #include <netinet/in.h>
        !            58: #include <netinet/ip.h>
        !            59: #include <netinet/ip_icmp.h>
        !            60: #include <netdb.h>
        !            61: 
        !            62: #define        MAXWAIT         10      /* max time to wait for response, sec. */
        !            63: #define        MAXPACKET       4096    /* max packet size */
        !            64: #ifndef MAXHOSTNAMELEN
        !            65: #define MAXHOSTNAMELEN 64
        !            66: #endif
        !            67: 
        !            68: int    verbose;
        !            69: u_char packet[MAXPACKET];
        !            70: int    options;
        !            71: extern int errno;
        !            72: 
        !            73: int s;                 /* Socket file descriptor */
        !            74: struct hostent *hp;    /* Pointer to host info */
        !            75: struct timezone tz;    /* leftover */
        !            76: 
        !            77: struct sockaddr whereto;/* Who to ping */
        !            78: int datalen;           /* How much data */
        !            79: 
        !            80: char usage[] = "Usage:  ping [-drv] host [data size] [npackets]\n";
        !            81: 
        !            82: char *hostname;
        !            83: char hnamebuf[MAXHOSTNAMELEN];
        !            84: char *inet_ntoa();
        !            85: 
        !            86: int npackets;
        !            87: int ntransmitted = 0;          /* sequence # for outbound packets = #sent */
        !            88: int ident;
        !            89: 
        !            90: int nreceived = 0;             /* # of packets we got back */
        !            91: int timing = 0;
        !            92: int tmin = 999999999;
        !            93: int tmax = 0;
        !            94: int tsum = 0;                  /* sum of all times, for doing average */
        !            95: int finish(), catcher();
        !            96: 
        !            97: /*
        !            98:  *                     M A I N
        !            99:  */
        !           100: main(argc, argv)
        !           101: char *argv[];
        !           102: {
        !           103:        struct sockaddr_in from;
        !           104:        char **av = argv;
        !           105:        char *toaddr = NULL;
        !           106:        struct sockaddr_in *to = (struct sockaddr_in *) &whereto;
        !           107:        int on = 1;
        !           108:        struct protoent *proto;
        !           109: 
        !           110:        argc--, av++;
        !           111:        while (argc > 0 && *av[0] == '-') {
        !           112:                while (*++av[0]) switch (*av[0]) {
        !           113:                        case 'd':
        !           114:                                options |= SO_DEBUG;
        !           115:                                break;
        !           116:                        case 'r':
        !           117:                                options |= SO_DONTROUTE;
        !           118:                                break;
        !           119:                        case 'v':
        !           120:                                verbose++;
        !           121:                                break;
        !           122:                }
        !           123:                argc--, av++;
        !           124:        }
        !           125:        if( argc < 1)  {
        !           126:                printf(usage);
        !           127:                exit(1);
        !           128:        }
        !           129: 
        !           130:        bzero( (char *)&whereto, sizeof(struct sockaddr) );
        !           131:        to->sin_family = AF_INET;
        !           132:        to->sin_addr.s_addr = inet_addr(av[0]);
        !           133:        if (to->sin_addr.s_addr != -1) {
        !           134:                strcpy(hnamebuf, av[0]);
        !           135:                hostname = hnamebuf;
        !           136:        } else {
        !           137:                hp = gethostbyname(av[0]);
        !           138:                if (hp) {
        !           139:                        to->sin_family = hp->h_addrtype;
        !           140:                        bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
        !           141:                        hostname = hp->h_name;
        !           142:                        toaddr = inet_ntoa(to->sin_addr.s_addr);
        !           143:                } else {
        !           144:                        printf("%s: unknown host %s\n", argv[0], av[0]);
        !           145:                        exit(1);
        !           146:                }
        !           147:        }
        !           148: 
        !           149:        if( argc >= 2 )
        !           150:                datalen = atoi( av[1] );
        !           151:        else
        !           152:                datalen = 64-8;
        !           153:        if (datalen > MAXPACKET) {
        !           154:                fprintf(stderr, "ping: packet size too large\n");
        !           155:                exit(1);
        !           156:        }
        !           157:        if (datalen >= sizeof(struct timeval))
        !           158:                timing = 1;
        !           159:        if (argc > 2)
        !           160:                npackets = atoi(av[2]);
        !           161: 
        !           162:        ident = getpid() & 0xFFFF;
        !           163: 
        !           164:        if ((proto = getprotobyname("icmp")) == NULL) {
        !           165:                fprintf(stderr, "icmp: unknown protocol\n");
        !           166:                exit(10);
        !           167:        }
        !           168:        if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
        !           169:                perror("ping: socket");
        !           170:                exit(5);
        !           171:        }
        !           172:        if (options & SO_DEBUG)
        !           173:                setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on));
        !           174:        if (options & SO_DONTROUTE)
        !           175:                setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on));
        !           176: 
        !           177:        printf("PING %s", hostname);
        !           178:        if (toaddr)
        !           179:                printf(" (%s)", toaddr);
        !           180:        printf(": %d data bytes\n", datalen);
        !           181:                                
        !           182: 
        !           183:        setlinebuf( stdout );
        !           184: 
        !           185:        signal( SIGINT, finish );
        !           186:        signal(SIGALRM, catcher);
        !           187: 
        !           188:        catcher();      /* start things going */
        !           189: 
        !           190:        for (;;) {
        !           191:                int len = sizeof (packet);
        !           192:                int fromlen = sizeof (from);
        !           193:                int cc;
        !           194: 
        !           195:                if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) {
        !           196:                        if( errno == EINTR )
        !           197:                                continue;
        !           198:                        perror("ping: recvfrom");
        !           199:                        continue;
        !           200:                }
        !           201:                pr_pack( packet, cc, &from );
        !           202:                if (npackets && nreceived >= npackets)
        !           203:                        finish();
        !           204:        }
        !           205:        /*NOTREACHED*/
        !           206: }
        !           207: 
        !           208: /*
        !           209:  *                     C A T C H E R
        !           210:  * 
        !           211:  * This routine causes another PING to be transmitted, and then
        !           212:  * schedules another SIGALRM for 1 second from now.
        !           213:  * 
        !           214:  * Bug -
        !           215:  *     Our sense of time will slowly skew (ie, packets will not be launched
        !           216:  *     exactly at 1-second intervals).  This does not affect the quality
        !           217:  *     of the delay and loss statistics.
        !           218:  */
        !           219: catcher()
        !           220: {
        !           221:        int waittime;
        !           222: 
        !           223:        pinger();
        !           224:        if (npackets == 0 || ntransmitted < npackets)
        !           225:                alarm(1);
        !           226:        else {
        !           227:                if (nreceived) {
        !           228:                        waittime = 2 * tmax / 1000;
        !           229:                        if (waittime == 0)
        !           230:                                waittime = 1;
        !           231:                } else
        !           232:                        waittime = MAXWAIT;
        !           233:                signal(SIGALRM, finish);
        !           234:                alarm(waittime);
        !           235:        }
        !           236: }
        !           237: 
        !           238: /*
        !           239:  *                     P I N G E R
        !           240:  * 
        !           241:  * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
        !           242:  * will be added on by the kernel.  The ID field is our UNIX process ID,
        !           243:  * and the sequence number is an ascending integer.  The first 8 bytes
        !           244:  * of the data portion are used to hold a UNIX "timeval" struct in VAX
        !           245:  * byte-order, to compute the round-trip time.
        !           246:  */
        !           247: pinger()
        !           248: {
        !           249:        static u_char outpack[MAXPACKET];
        !           250:        register struct icmp *icp = (struct icmp *) outpack;
        !           251:        int i, cc;
        !           252:        register struct timeval *tp = (struct timeval *) &outpack[8];
        !           253:        register u_char *datap = &outpack[8+sizeof(struct timeval)];
        !           254: 
        !           255:        icp->icmp_type = ICMP_ECHO;
        !           256:        icp->icmp_code = 0;
        !           257:        icp->icmp_cksum = 0;
        !           258:        icp->icmp_seq = ntransmitted++;
        !           259:        icp->icmp_id = ident;           /* ID */
        !           260: 
        !           261:        cc = datalen+8;                 /* skips ICMP portion */
        !           262: 
        !           263:        if (timing)
        !           264:                gettimeofday( tp, &tz );
        !           265: 
        !           266:        for( i=8; i<datalen; i++)       /* skip 8 for time */
        !           267:                *datap++ = i;
        !           268: 
        !           269:        /* Compute ICMP checksum here */
        !           270:        icp->icmp_cksum = in_cksum( icp, cc );
        !           271: 
        !           272:        /* cc = sendto(s, msg, len, flags, to, tolen) */
        !           273:        i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );
        !           274: 
        !           275:        if( i < 0 || i != cc )  {
        !           276:                if( i<0 )  perror("sendto");
        !           277:                printf("ping: wrote %s %d chars, ret=%d\n",
        !           278:                        hostname, cc, i );
        !           279:                fflush(stdout);
        !           280:        }
        !           281: }
        !           282: 
        !           283: /*
        !           284:  *                     P R _ T Y P E
        !           285:  *
        !           286:  * Convert an ICMP "type" field to a printable string.
        !           287:  */
        !           288: char *
        !           289: pr_type( t )
        !           290: register int t;
        !           291: {
        !           292:        static char *ttab[] = {
        !           293:                "Echo Reply",
        !           294:                "ICMP 1",
        !           295:                "ICMP 2",
        !           296:                "Dest Unreachable",
        !           297:                "Source Quence",
        !           298:                "Redirect",
        !           299:                "ICMP 6",
        !           300:                "ICMP 7",
        !           301:                "Echo",
        !           302:                "ICMP 9",
        !           303:                "ICMP 10",
        !           304:                "Time Exceeded",
        !           305:                "Parameter Problem",
        !           306:                "Timestamp",
        !           307:                "Timestamp Reply",
        !           308:                "Info Request",
        !           309:                "Info Reply"
        !           310:        };
        !           311: 
        !           312:        if( t < 0 || t > 16 )
        !           313:                return("OUT-OF-RANGE");
        !           314: 
        !           315:        return(ttab[t]);
        !           316: }
        !           317: 
        !           318: /*
        !           319:  *                     P R _ P A C K
        !           320:  *
        !           321:  * Print out the packet, if it came from us.  This logic is necessary
        !           322:  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
        !           323:  * which arrive ('tis only fair).  This permits multiple copies of this
        !           324:  * program to be run without having intermingled output (or statistics!).
        !           325:  */
        !           326: pr_pack( buf, cc, from )
        !           327: char *buf;
        !           328: int cc;
        !           329: struct sockaddr_in *from;
        !           330: {
        !           331:        struct ip *ip;
        !           332:        register struct icmp *icp;
        !           333:        register long *lp = (long *) packet;
        !           334:        register int i;
        !           335:        struct timeval tv;
        !           336:        struct timeval *tp;
        !           337:        int hlen, triptime;
        !           338: 
        !           339:        from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr );
        !           340:        gettimeofday( &tv, &tz );
        !           341: 
        !           342:        ip = (struct ip *) buf;
        !           343:        hlen = ip->ip_hl << 2;
        !           344:        if (cc < hlen + ICMP_MINLEN) {
        !           345:                if (verbose)
        !           346:                        printf("packet too short (%d bytes) from %s\n", cc,
        !           347:                                inet_ntoa(ntohl(from->sin_addr.s_addr)));
        !           348:                return;
        !           349:        }
        !           350:        cc -= hlen;
        !           351:        icp = (struct icmp *)(buf + hlen);
        !           352:        if( icp->icmp_type != ICMP_ECHOREPLY )  {
        !           353:                if (verbose) {
        !           354:                        printf("%d bytes from %s: ", cc,
        !           355:                                inet_ntoa(ntohl(from->sin_addr.s_addr)));
        !           356:                        printf("icmp_type=%d (%s)\n",
        !           357:                                icp->icmp_type, pr_type(icp->icmp_type) );
        !           358:                        for( i=0; i<12; i++)
        !           359:                            printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++ );
        !           360:                        printf("icmp_code=%d\n", icp->icmp_code );
        !           361:                }
        !           362:                return;
        !           363:        }
        !           364:        if( icp->icmp_id != ident )
        !           365:                return;                 /* 'Twas not our ECHO */
        !           366: 
        !           367:        tp = (struct timeval *)&icp->icmp_data[0];
        !           368:        printf("%d bytes from %s: ", cc,
        !           369:                inet_ntoa(ntohl(from->sin_addr.s_addr)));
        !           370:        printf("icmp_seq=%d. ", icp->icmp_seq );
        !           371:        if (timing) {
        !           372:                tvsub( &tv, tp );
        !           373:                triptime = tv.tv_sec*1000+(tv.tv_usec/1000);
        !           374:                printf("time=%d. ms\n", triptime );
        !           375:                tsum += triptime;
        !           376:                if( triptime < tmin )
        !           377:                        tmin = triptime;
        !           378:                if( triptime > tmax )
        !           379:                        tmax = triptime;
        !           380:        } else
        !           381:                putchar('\n');
        !           382:        nreceived++;
        !           383: }
        !           384: 
        !           385: 
        !           386: /*
        !           387:  *                     I N _ C K S U M
        !           388:  *
        !           389:  * Checksum routine for Internet Protocol family headers (C Version)
        !           390:  *
        !           391:  */
        !           392: in_cksum(addr, len)
        !           393: u_short *addr;
        !           394: int len;
        !           395: {
        !           396:        register int nleft = len;
        !           397:        register u_short *w = addr;
        !           398:        register u_short answer;
        !           399:        register int sum = 0;
        !           400:        u_short odd_byte = 0;
        !           401: 
        !           402:        /*
        !           403:         *  Our algorithm is simple, using a 32 bit accumulator (sum),
        !           404:         *  we add sequential 16 bit words to it, and at the end, fold
        !           405:         *  back all the carry bits from the top 16 bits into the lower
        !           406:         *  16 bits.
        !           407:         */
        !           408:        while( nleft > 1 )  {
        !           409:                sum += *w++;
        !           410:                nleft -= 2;
        !           411:        }
        !           412: 
        !           413:        /* mop up an odd byte, if necessary */
        !           414:        if( nleft == 1 ) {
        !           415:                *(u_char *)(&odd_byte) = *(u_char *)w;
        !           416:                sum += odd_byte;
        !           417:        }
        !           418: 
        !           419:        /*
        !           420:         * add back carry outs from top 16 bits to low 16 bits
        !           421:         */
        !           422:        sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
        !           423:        sum += (sum >> 16);                     /* add carry */
        !           424:        answer = ~sum;                          /* truncate to 16 bits */
        !           425:        return (answer);
        !           426: }
        !           427: 
        !           428: /*
        !           429:  *                     T V S U B
        !           430:  * 
        !           431:  * Subtract 2 timeval structs:  out = out - in.
        !           432:  * 
        !           433:  * Out is assumed to be >= in.
        !           434:  */
        !           435: tvsub( out, in )
        !           436: register struct timeval *out, *in;
        !           437: {
        !           438:        if( (out->tv_usec -= in->tv_usec) < 0 )   {
        !           439:                out->tv_sec--;
        !           440:                out->tv_usec += 1000000;
        !           441:        }
        !           442:        out->tv_sec -= in->tv_sec;
        !           443: }
        !           444: 
        !           445: /*
        !           446:  *                     F I N I S H
        !           447:  *
        !           448:  * Print out statistics, and give up.
        !           449:  * Heavily buffered STDIO is used here, so that all the statistics
        !           450:  * will be written with 1 sys-write call.  This is nice when more
        !           451:  * than one copy of the program is running on a terminal;  it prevents
        !           452:  * the statistics output from becomming intermingled.
        !           453:  */
        !           454: finish()
        !           455: {
        !           456:        printf("\n----%s PING Statistics----\n", hostname );
        !           457:        printf("%d packets transmitted, ", ntransmitted );
        !           458:        printf("%d packets received, ", nreceived );
        !           459:        if (ntransmitted)
        !           460:            printf("%d%% packet loss",
        !           461:                (int) (((ntransmitted-nreceived)*100) / ntransmitted ) );
        !           462:        printf("\n");
        !           463:        if (nreceived && timing)
        !           464:            printf("round-trip (ms)  min/avg/max = %d/%d/%d\n",
        !           465:                tmin,
        !           466:                tsum / nreceived,
        !           467:                tmax );
        !           468:        fflush(stdout);
        !           469:        exit(0);
        !           470: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.