📄 ping.c
字号:
#include <u.h>#include <libc.h>#include <ip.h>typedef struct Icmp Icmp;struct Icmp{ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar ttl; /* Time to live */ uchar proto; /* Protocol */ uchar ipcksum[2]; /* Header checksum */ uchar src[4]; /* Ip source */ uchar dst[4]; /* Ip destination */ uchar type; uchar code; uchar cksum[2]; uchar icmpid[2]; uchar seq[2]; uchar data[1];};enum{ /* Packet Types */ EchoReply = 0, Unreachable = 3, SrcQuench = 4, EchoRequest = 8, TimeExceed = 11, Timestamp = 13, TimestampReply = 14, InfoRequest = 15, InfoReply = 16, ICMP_IPSIZE = 20, ICMP_HDRSIZE = 8, MAXMSG = 32, SLEEPMS = 1000,};typedef struct Req Req;struct Req{ ushort seq; // sequence number vlong time; // time sent vlong rtt; int ttl; int replied; Req *next;};Req *first; // request listReq *last; // ...Lock listlock;char *argv0;int debug;int quiet;int lostonly;int lostmsgs;int rcvdmsgs;int done;int rint;vlong sum;ushort firstseq;int addresses;int flood;void usage(void);void lost(Req*, Icmp*);void reply(Req*, Icmp*);#define SECOND 1000000000LL#define MINUTE (60LL*SECOND)static voidcatch(void *a, char *msg){ USED(a); if(strstr(msg, "alarm")) noted(NCONT); else if(strstr(msg, "die")) exits("errors"); else noted(NDFLT);}voidclean(ushort seq, vlong now, Icmp *ip){ Req **l, *r; lock(&listlock); last = nil; for(l = &first; *l; ){ r = *l; if(ip && r->seq == seq){ r->rtt = now-r->time; r->ttl = ip->ttl; reply(r, ip); } if(now-r->time > MINUTE){ *l = r->next; r->rtt = now-r->time; if(ip) r->ttl = ip->ttl; if(r->replied == 0) lost(r, ip); free(r); }else{ last = r; l = &(r->next); } } unlock(&listlock);}voidsender(int fd, int msglen, int interval, int n){ char buf[64*1024+512]; Icmp *ip; int i, extra; Req *r; ushort seq; ip = (Icmp*)buf; srand(time(0)); firstseq = seq = rand(); for(i = 32; i < msglen; i++) buf[i] = i; ip->type = EchoRequest; ip->code = 0; for(i = 0; i < n; i++){ if(i != 0){ extra = rint? nrand(interval): 0; sleep(interval + extra); } r = malloc(sizeof *r); if(r != nil){ hnputs(ip->seq, seq); r->seq = seq; r->next = nil; r->replied = 0; r->time = nsec(); /* avoid early free in reply! */ lock(&listlock); if(first == nil) first = r; else last->next = r; last = r; unlock(&listlock); r->time = nsec(); if(write(fd, ip, msglen) < msglen){ fprint(2, "%s: write failed: %r\n", argv0); return; } seq++; } } done = 1;}voidrcvr(int fd, int msglen, int interval, int nmsg){ uchar buf[64*1024+512]; Icmp *ip; ushort x; int i, n, munged; vlong now; Req *r; ip = (Icmp*)buf; sum = 0; while(lostmsgs+rcvdmsgs < nmsg){ alarm((nmsg-lostmsgs-rcvdmsgs)*interval+5000); n = read(fd, buf, sizeof(buf)); alarm(0); now = nsec(); if(n <= 0){ /* read interrupted - time to go */ clean(0, now+MINUTE, nil); continue; } if(n < msglen){ print("bad len %d/%d\n", n, msglen); continue; } munged = 0; for(i = 32; i < msglen; i++) if(buf[i] != (i&0xff)) munged++; if(munged) print("currupted reply\n"); x = nhgets(ip->seq); if(ip->type != EchoReply || ip->code != 0) { print("bad sequence/code/type %d/%d/%d\n", ip->type, ip->code, x); continue; } clean(x, now, ip); } lock(&listlock); for(r = first; r; r = r->next) if(r->replied == 0) lostmsgs++; unlock(&listlock); if(lostmsgs) print("%d out of %d messages lost\n", lostmsgs, lostmsgs+rcvdmsgs);}voidusage(void){ fprint(2, "usage: %s [-alq] [-s msgsize] [-i millisecs] [-n #pings] destination\n", argv0); exits("usage");}voidmain(int argc, char **argv){ int fd; int msglen, interval, nmsg; nsec(); /* make sure time file is already open */ fmtinstall('V', eipfmt); msglen = interval = 0; nmsg = MAXMSG; ARGBEGIN { case 'l': lostonly++; break; case 'd': debug++; break; case 's': msglen = atoi(ARGF()); break; case 'i': interval = atoi(ARGF()); break; case 'n': nmsg = atoi(ARGF()); break; case 'a': addresses = 1; break; case 'q': quiet = 1; break; case 'r': rint = 1; break; case 'f': flood = 1; break; } ARGEND; if(msglen < 32) msglen = 64; if(msglen >= 65*1024) msglen = 65*1024-1; if(interval <= 0 && !flood) interval = SLEEPMS; if(argc < 1) usage(); notify(catch); fd = dial(netmkaddr(argv[0], "icmp", "1"), 0, 0, 0); if(fd < 0){ fprint(2, "%s: couldn't dial: %r\n", argv0); exits("dialing"); } print("sending %d %d byte messages %d ms apart\n", nmsg, msglen, interval); switch(rfork(RFPROC|RFMEM|RFFDG)){ case -1: fprint(2, "%s: can't fork: %r\n", argv0); case 0: rcvr(fd, msglen, interval, nmsg); exits(0); default: sender(fd, msglen, interval, nmsg); wait(); exits(lostmsgs ? "lost messages" : ""); }}voidreply(Req *r, Icmp *ip){ r->rtt /= 1000LL; sum += r->rtt; if(!r->replied) rcvdmsgs++; if(!quiet && !lostonly){ if(addresses) print("%ud: %V->%V rtt %lld µs, avg rtt %lld µs, ttl = %d\n", r->seq-firstseq, ip->src, ip->dst, r->rtt, sum/rcvdmsgs, r->ttl); else print("%ud: rtt %lld µs, avg rtt %lld µs, ttl = %d\n", r->seq-firstseq, r->rtt, sum/rcvdmsgs, r->ttl); } r->replied = 1;}voidlost(Req *r, Icmp *ip){ if(!quiet){ if(addresses) print("lost %ud: %V->%V\n", r->seq-firstseq, ip->src, ip->dst); else print("lost %ud\n", r->seq-firstseq); } lostmsgs++;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -