1 /* ping for ip v4 and v6 */
14 SECOND = 1000000000LL,
18 typedef struct Req Req;
21 ushort seq; /* sequence number */
22 vlong time; /* time sent */
36 void (*prreply)(Req *r, void *v);
37 void (*prlost)(ushort seq, void *v);
41 Req *first; /* request list */
60 void lost(Req*, void*);
61 void reply(Req*, void*);
67 "usage: %s [-6alq] [-s msgsize] [-i millisecs] [-n #pings] dest\n",
73 catch(void *a, char *msg)
76 if(strstr(msg, "alarm"))
78 else if(strstr(msg, "die"))
85 prlost4(ushort seq, void *v)
89 print("lost %ud: %V -> %V\n", seq, ip4->src, ip4->dst);
93 prlost6(ushort seq, void *v)
97 print("lost %ud: %I -> %I\n", seq, ip6->src, ip6->dst);
101 prreply4(Req *r, void *v)
105 print("%ud: %V -> %V rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
106 r->seq - firstseq, ip4->src, ip4->dst, r->rtt, sum/rcvdmsgs,
111 prreply6(Req *r, void *v)
115 print("%ud: %I -> %I rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
116 r->seq - firstseq, ip6->src, ip6->dst, r->rtt, sum/rcvdmsgs,
120 static Proto v4pr = {
122 EchoRequest, EchoReply,
126 static Proto v6pr = {
128 EchoRequestV6, EchoReplyV6,
133 static Proto *proto = &v4pr;
141 return (Icmphdr *)(p + proto->iphdrsz);
145 clean(ushort seq, vlong now, void *v)
152 if (proto->version == 4)
153 ttl = ((Ip4hdr *)v)->ttl;
155 ttl = ((Ip6hdr *)v)->ttl;
159 for(l = &first; *l; ){
162 if(v && r->seq == seq){
163 r->rtt = now-r->time;
168 if(now-r->time > MINUTE){
170 r->rtt = now-r->time;
185 sender(int fd, int msglen, int interval, int n)
189 char buf[64*1024+512];
194 firstseq = seq = rand();
197 memset(buf, 0, proto->iphdrsz + ICMP_HDRSIZE);
198 for(i = proto->iphdrsz + ICMP_HDRSIZE; i < msglen; i++)
200 icmp->type = proto->echocmd;
203 if(rint != 0 && interval <= 0)
206 for(i = 0; i < n; i++){
209 extra = nrand(interval);
210 sleep(interval + extra);
212 r = malloc(sizeof *r);
215 hnputs(icmp->seq, seq);
219 r->time = nsec(); /* avoid early free in reply! */
228 if(write(fd, buf, msglen) < msglen){
229 fprint(2, "%s: write failed: %r\n", argv0);
238 rcvr(int fd, int msglen, int interval, int nmsg)
244 uchar buf[64*1024+512];
249 while(lostmsgs+rcvdmsgs < nmsg){
250 alarm((nmsg-lostmsgs-rcvdmsgs)*interval+waittime);
251 n = read(fd, buf, sizeof buf);
254 strcpy(err, "got eof");
256 rerrstr(err, sizeof(err));
260 clean(0, now+MINUTE, nil);
261 if(strstr(err, "interrupted") == nil)
266 print("bad len %d/%d\n", n, msglen);
271 for(i = proto->iphdrsz + ICMP_HDRSIZE; i < msglen; i++)
272 if(buf[i] != (uchar)i)
275 print("corrupted reply\n");
276 x = nhgets(icmp->seq);
277 if(icmp->type != proto->echoreply || icmp->code != 0) {
278 print("bad type/code/sequence %d/%d/%d (want %d/%d/%d)\n",
279 icmp->type, icmp->code, x,
280 proto->echoreply, 0, x);
287 for(r = first; r; r = r->next)
292 if(!quiet && lostmsgs)
293 print("%d out of %d messages lost\n", lostmsgs,
304 main(int argc, char **argv)
306 int fd, msglen, interval, nmsg;
308 nsec(); /* make sure time file is already open */
310 fmtinstall('V', eipfmt);
311 fmtinstall('I', eipfmt);
313 msglen = interval = 0;
329 interval = atoi(EARGF(usage()));
337 nmsg = atoi(EARGF(usage()));
348 msglen = atoi(EARGF(usage()));
351 waittime = atoi(EARGF(usage()));
360 if(msglen < proto->iphdrsz + ICMP_HDRSIZE)
361 msglen = proto->iphdrsz + ICMP_HDRSIZE;
364 if(msglen >= 64*1024)
366 if(interval <= 0 && !flood)
374 if(strstr(argv[0], "icmpv6!") != nil)
377 fd = dial(netmkaddr(argv[0], proto->net, "1"), nil, nil, nil);
383 fprint(2, "%s: couldn't dial: %r\n", argv0);
387 NetConnInfo *nci = getnetconninfo(nil, fd);
388 print("sending %d %d byte messages %d ms apart to %s\n",
389 nmsg, msglen, interval, nci != nil? nci->raddr: argv[0]);
392 switch(rfork(RFPROC|RFMEM|RFFDG)){
394 fprint(2, "%s: can't fork: %r\n", argv0);
397 rcvr(fd, msglen, interval, nmsg);
400 sender(fd, msglen, interval, nmsg);
402 exits(lostmsgs ? "lost messages" : "");
407 reply(Req *r, void *v)
413 if(!quiet && !lostonly)
415 (*proto->prreply)(r, v);
417 print("%ud: rtt %lld µs, avg rtt %lld µs, ttl = %d\n",
418 r->seq - firstseq, r->rtt, sum/rcvdmsgs, r->ttl);
423 lost(Req *r, void *v)
426 if(addresses && v != nil)
427 (*proto->prlost)(r->seq - firstseq, v);
429 print("lost %ud\n", r->seq - firstseq);