1*4ac22c89SDavid du Colombier /* ping for ip v4 and v6 */ 27dd7cddfSDavid du Colombier #include <u.h> 37dd7cddfSDavid du Colombier #include <libc.h> 43ff48bf5SDavid du Colombier #include <ip.h> 57dd7cddfSDavid du Colombier 6*4ac22c89SDavid du Colombier enum 7*4ac22c89SDavid du Colombier { 8*4ac22c89SDavid du Colombier /* Packet Types */ 9*4ac22c89SDavid du Colombier EchoReply = 0, 10*4ac22c89SDavid du Colombier Unreachable = 3, 11*4ac22c89SDavid du Colombier SrcQuench = 4, 12*4ac22c89SDavid du Colombier EchoRequest = 8, 13*4ac22c89SDavid du Colombier TimeExceed = 11, 14*4ac22c89SDavid du Colombier Timestamp = 13, 15*4ac22c89SDavid du Colombier TimestampReply = 14, 16*4ac22c89SDavid du Colombier InfoRequest = 15, 17*4ac22c89SDavid du Colombier InfoReply = 16, 18*4ac22c89SDavid du Colombier 19*4ac22c89SDavid du Colombier EchoReplyV6 = 129, 20*4ac22c89SDavid du Colombier EchoRequestV6 = 128, 21*4ac22c89SDavid du Colombier 22*4ac22c89SDavid du Colombier MAXMSG = 32, 23*4ac22c89SDavid du Colombier SLEEPMS = 1000, 24*4ac22c89SDavid du Colombier 25*4ac22c89SDavid du Colombier SECOND = 1000000000LL, 26*4ac22c89SDavid du Colombier MINUTE = 60*SECOND, 27*4ac22c89SDavid du Colombier }; 28*4ac22c89SDavid du Colombier 297dd7cddfSDavid du Colombier typedef struct Icmp Icmp; 307dd7cddfSDavid du Colombier struct Icmp 317dd7cddfSDavid du Colombier { 327dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */ 337dd7cddfSDavid du Colombier uchar tos; /* Type of service */ 347dd7cddfSDavid du Colombier uchar length[2]; /* packet length */ 357dd7cddfSDavid du Colombier uchar id[2]; /* Identification */ 367dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */ 377dd7cddfSDavid du Colombier uchar ttl; /* Time to live */ 387dd7cddfSDavid du Colombier uchar proto; /* Protocol */ 397dd7cddfSDavid du Colombier uchar ipcksum[2]; /* Header checksum */ 407dd7cddfSDavid du Colombier uchar src[4]; /* Ip source */ 417dd7cddfSDavid du Colombier uchar dst[4]; /* Ip destination */ 427dd7cddfSDavid du Colombier uchar type; 437dd7cddfSDavid du Colombier uchar code; 447dd7cddfSDavid du Colombier uchar cksum[2]; 457dd7cddfSDavid du Colombier uchar icmpid[2]; 467dd7cddfSDavid du Colombier uchar seq[2]; 477dd7cddfSDavid du Colombier uchar data[1]; 487dd7cddfSDavid du Colombier }; 497dd7cddfSDavid du Colombier 50*4ac22c89SDavid du Colombier typedef struct Icmp6 Icmp6; 51*4ac22c89SDavid du Colombier struct Icmp6 52*4ac22c89SDavid du Colombier { 53*4ac22c89SDavid du Colombier uchar vcf[4]; 54*4ac22c89SDavid du Colombier uchar ploadlen[2]; 55*4ac22c89SDavid du Colombier uchar proto; 56*4ac22c89SDavid du Colombier uchar ttl; 57*4ac22c89SDavid du Colombier uchar src[16]; /* Ip source */ 58*4ac22c89SDavid du Colombier uchar dst[16]; /* Ip destination */ 59*4ac22c89SDavid du Colombier uchar type; 60*4ac22c89SDavid du Colombier uchar code; 61*4ac22c89SDavid du Colombier uchar cksum[2]; 62*4ac22c89SDavid du Colombier uchar icmpid[2]; 63*4ac22c89SDavid du Colombier uchar seq[2]; 64*4ac22c89SDavid du Colombier uchar data[1]; 657dd7cddfSDavid du Colombier }; 667dd7cddfSDavid du Colombier 677dd7cddfSDavid du Colombier typedef struct Req Req; 687dd7cddfSDavid du Colombier struct Req 697dd7cddfSDavid du Colombier { 70*4ac22c89SDavid du Colombier ushort seq; /* sequence number */ 71*4ac22c89SDavid du Colombier vlong time; /* time sent */ 723ff48bf5SDavid du Colombier vlong rtt; 737dd7cddfSDavid du Colombier int ttl; 743ff48bf5SDavid du Colombier int replied; 757dd7cddfSDavid du Colombier Req *next; 767dd7cddfSDavid du Colombier }; 77*4ac22c89SDavid du Colombier 78*4ac22c89SDavid du Colombier typedef struct { 79*4ac22c89SDavid du Colombier char *net; 80*4ac22c89SDavid du Colombier int echoreply; 81*4ac22c89SDavid du Colombier unsigned icmphdrsz; 82*4ac22c89SDavid du Colombier int (*getttl)(void *v); 83*4ac22c89SDavid du Colombier int (*getseq)(void *v); 84*4ac22c89SDavid du Colombier void (*putseq)(void *v, ushort seq); 85*4ac22c89SDavid du Colombier int (*gettype)(void *v); 86*4ac22c89SDavid du Colombier void (*settype)(void *v); 87*4ac22c89SDavid du Colombier int (*getcode)(void *v); 88*4ac22c89SDavid du Colombier void (*setcode)(void *v); 89*4ac22c89SDavid du Colombier void (*prreply)(Req *r, void *v); 90*4ac22c89SDavid du Colombier void (*prlost)(ushort seq, void *v); 91*4ac22c89SDavid du Colombier } Proto; 92*4ac22c89SDavid du Colombier 93*4ac22c89SDavid du Colombier Req *first; /* request list */ 94*4ac22c89SDavid du Colombier Req *last; /* ... */ 957dd7cddfSDavid du Colombier Lock listlock; 967dd7cddfSDavid du Colombier 977dd7cddfSDavid du Colombier char *argv0; 987dd7cddfSDavid du Colombier int debug; 997dd7cddfSDavid du Colombier int quiet; 10000c1ae4bSDavid du Colombier int lostonly; 1017dd7cddfSDavid du Colombier int lostmsgs; 1027dd7cddfSDavid du Colombier int rcvdmsgs; 1037dd7cddfSDavid du Colombier int done; 104da51d93aSDavid du Colombier int rint; 1057dd7cddfSDavid du Colombier vlong sum; 1063ff48bf5SDavid du Colombier ushort firstseq; 1073ff48bf5SDavid du Colombier int addresses; 1080b9a5132SDavid du Colombier int flood; 1097dd7cddfSDavid du Colombier 110*4ac22c89SDavid du Colombier void lost(Req*, void*); 111*4ac22c89SDavid du Colombier void reply(Req*, void*); 1127dd7cddfSDavid du Colombier 113*4ac22c89SDavid du Colombier static void 114*4ac22c89SDavid du Colombier usage(void) 115*4ac22c89SDavid du Colombier { 116*4ac22c89SDavid du Colombier fprint(2, 117*4ac22c89SDavid du Colombier "usage: %s [-6alq] [-s msgsize] [-i millisecs] [-n #pings] dest\n", 118*4ac22c89SDavid du Colombier argv0); 119*4ac22c89SDavid du Colombier exits("usage"); 120*4ac22c89SDavid du Colombier } 1217dd7cddfSDavid du Colombier 1227dd7cddfSDavid du Colombier static void 1237dd7cddfSDavid du Colombier catch(void *a, char *msg) 1247dd7cddfSDavid du Colombier { 1257dd7cddfSDavid du Colombier USED(a); 1267dd7cddfSDavid du Colombier if(strstr(msg, "alarm")) 1277dd7cddfSDavid du Colombier noted(NCONT); 1288aafde0cSDavid du Colombier else if(strstr(msg, "die")) 1298aafde0cSDavid du Colombier exits("errors"); 1307dd7cddfSDavid du Colombier else 1317dd7cddfSDavid du Colombier noted(NDFLT); 1327dd7cddfSDavid du Colombier } 1337dd7cddfSDavid du Colombier 134*4ac22c89SDavid du Colombier 135*4ac22c89SDavid du Colombier static int 136*4ac22c89SDavid du Colombier getttl4(void *v) 137*4ac22c89SDavid du Colombier { 138*4ac22c89SDavid du Colombier return ((Icmp *)v)->ttl; 139*4ac22c89SDavid du Colombier } 140*4ac22c89SDavid du Colombier 141*4ac22c89SDavid du Colombier static int 142*4ac22c89SDavid du Colombier getttl6(void *v) 143*4ac22c89SDavid du Colombier { 144*4ac22c89SDavid du Colombier return ((Icmp6 *)v)->ttl; 145*4ac22c89SDavid du Colombier } 146*4ac22c89SDavid du Colombier 147*4ac22c89SDavid du Colombier static int 148*4ac22c89SDavid du Colombier getseq4(void *v) 149*4ac22c89SDavid du Colombier { 150*4ac22c89SDavid du Colombier return nhgets(((Icmp *)v)->seq); 151*4ac22c89SDavid du Colombier } 152*4ac22c89SDavid du Colombier 153*4ac22c89SDavid du Colombier static int 154*4ac22c89SDavid du Colombier getseq6(void *v) 155*4ac22c89SDavid du Colombier { 156*4ac22c89SDavid du Colombier Icmp6 *ip6 = v; 157*4ac22c89SDavid du Colombier 158*4ac22c89SDavid du Colombier return ip6->seq[1]<<8 | ip6->seq[0]; 159*4ac22c89SDavid du Colombier } 160*4ac22c89SDavid du Colombier 161*4ac22c89SDavid du Colombier static void 162*4ac22c89SDavid du Colombier putseq4(void *v, ushort seq) 163*4ac22c89SDavid du Colombier { 164*4ac22c89SDavid du Colombier hnputs(((Icmp *)v)->seq, seq); 165*4ac22c89SDavid du Colombier } 166*4ac22c89SDavid du Colombier 167*4ac22c89SDavid du Colombier static void 168*4ac22c89SDavid du Colombier putseq6(void *v, ushort seq) 169*4ac22c89SDavid du Colombier { 170*4ac22c89SDavid du Colombier ((Icmp6 *)v)->seq[0] = seq; 171*4ac22c89SDavid du Colombier ((Icmp6 *)v)->seq[1] = seq>>8; 172*4ac22c89SDavid du Colombier } 173*4ac22c89SDavid du Colombier 174*4ac22c89SDavid du Colombier static int 175*4ac22c89SDavid du Colombier gettype4(void *v) 176*4ac22c89SDavid du Colombier { 177*4ac22c89SDavid du Colombier return ((Icmp *)v)->type; 178*4ac22c89SDavid du Colombier } 179*4ac22c89SDavid du Colombier 180*4ac22c89SDavid du Colombier static int 181*4ac22c89SDavid du Colombier gettype6(void *v) 182*4ac22c89SDavid du Colombier { 183*4ac22c89SDavid du Colombier return ((Icmp6 *)v)->type; 184*4ac22c89SDavid du Colombier } 185*4ac22c89SDavid du Colombier 186*4ac22c89SDavid du Colombier static void 187*4ac22c89SDavid du Colombier settype4(void *v) 188*4ac22c89SDavid du Colombier { 189*4ac22c89SDavid du Colombier ((Icmp *)v)->type = EchoRequest; 190*4ac22c89SDavid du Colombier } 191*4ac22c89SDavid du Colombier 192*4ac22c89SDavid du Colombier static void 193*4ac22c89SDavid du Colombier settype6(void *v) 194*4ac22c89SDavid du Colombier { 195*4ac22c89SDavid du Colombier ((Icmp6 *)v)->type = EchoRequestV6; 196*4ac22c89SDavid du Colombier } 197*4ac22c89SDavid du Colombier 198*4ac22c89SDavid du Colombier static int 199*4ac22c89SDavid du Colombier getcode4(void *v) 200*4ac22c89SDavid du Colombier { 201*4ac22c89SDavid du Colombier return ((Icmp *)v)->code; 202*4ac22c89SDavid du Colombier } 203*4ac22c89SDavid du Colombier 204*4ac22c89SDavid du Colombier static int 205*4ac22c89SDavid du Colombier getcode6(void *v) 206*4ac22c89SDavid du Colombier { 207*4ac22c89SDavid du Colombier return ((Icmp6 *)v)->code; 208*4ac22c89SDavid du Colombier } 209*4ac22c89SDavid du Colombier 210*4ac22c89SDavid du Colombier static void 211*4ac22c89SDavid du Colombier setcode4(void *v) 212*4ac22c89SDavid du Colombier { 213*4ac22c89SDavid du Colombier ((Icmp *)v)->code = 0; 214*4ac22c89SDavid du Colombier } 215*4ac22c89SDavid du Colombier 216*4ac22c89SDavid du Colombier static void 217*4ac22c89SDavid du Colombier setcode6(void *v) 218*4ac22c89SDavid du Colombier { 219*4ac22c89SDavid du Colombier ((Icmp6 *)v)->code = 0; 220*4ac22c89SDavid du Colombier } 221*4ac22c89SDavid du Colombier 222*4ac22c89SDavid du Colombier static void 223*4ac22c89SDavid du Colombier prlost4(ushort seq, void *v) 224*4ac22c89SDavid du Colombier { 225*4ac22c89SDavid du Colombier Icmp *ip4 = v; 226*4ac22c89SDavid du Colombier 227*4ac22c89SDavid du Colombier print("lost %ud: %V->%V\n", seq, ip4->src, ip4->dst); 228*4ac22c89SDavid du Colombier } 229*4ac22c89SDavid du Colombier 230*4ac22c89SDavid du Colombier static void 231*4ac22c89SDavid du Colombier prlost6(ushort seq, void *v) 232*4ac22c89SDavid du Colombier { 233*4ac22c89SDavid du Colombier Icmp6 *ip6 = v; 234*4ac22c89SDavid du Colombier 235*4ac22c89SDavid du Colombier print("lost %ud: %I->%I\n", seq, ip6->src, ip6->dst); 236*4ac22c89SDavid du Colombier } 237*4ac22c89SDavid du Colombier 238*4ac22c89SDavid du Colombier static void 239*4ac22c89SDavid du Colombier prreply4(Req *r, void *v) 240*4ac22c89SDavid du Colombier { 241*4ac22c89SDavid du Colombier Icmp *ip4 = v; 242*4ac22c89SDavid du Colombier 243*4ac22c89SDavid du Colombier print("%ud: %V->%V rtt %lld µs, avg rtt %lld µs, ttl = %d\n", 244*4ac22c89SDavid du Colombier r->seq - firstseq, ip4->src, ip4->dst, r->rtt, sum/rcvdmsgs, 245*4ac22c89SDavid du Colombier r->ttl); 246*4ac22c89SDavid du Colombier } 247*4ac22c89SDavid du Colombier 248*4ac22c89SDavid du Colombier static void 249*4ac22c89SDavid du Colombier prreply6(Req *r, void *v) 250*4ac22c89SDavid du Colombier { 251*4ac22c89SDavid du Colombier Icmp *ip6 = v; 252*4ac22c89SDavid du Colombier 253*4ac22c89SDavid du Colombier print("%ud: %I->%I rtt %lld µs, avg rtt %lld µs, ttl = %d\n", 254*4ac22c89SDavid du Colombier r->seq - firstseq, ip6->src, ip6->dst, r->rtt, sum/rcvdmsgs, 255*4ac22c89SDavid du Colombier r->ttl); 256*4ac22c89SDavid du Colombier } 257*4ac22c89SDavid du Colombier 258*4ac22c89SDavid du Colombier static Proto v4pr = { 259*4ac22c89SDavid du Colombier "icmp", 260*4ac22c89SDavid du Colombier EchoReply, 261*4ac22c89SDavid du Colombier sizeof(Icmp), 262*4ac22c89SDavid du Colombier getttl4, 263*4ac22c89SDavid du Colombier getseq4, 264*4ac22c89SDavid du Colombier putseq4, 265*4ac22c89SDavid du Colombier gettype4, 266*4ac22c89SDavid du Colombier settype4, 267*4ac22c89SDavid du Colombier getcode4, 268*4ac22c89SDavid du Colombier setcode4, 269*4ac22c89SDavid du Colombier prreply4, 270*4ac22c89SDavid du Colombier prlost4, 271*4ac22c89SDavid du Colombier }; 272*4ac22c89SDavid du Colombier static Proto v6pr = { 273*4ac22c89SDavid du Colombier "icmpv6", 274*4ac22c89SDavid du Colombier EchoReplyV6, 275*4ac22c89SDavid du Colombier sizeof(Icmp6), 276*4ac22c89SDavid du Colombier getttl6, 277*4ac22c89SDavid du Colombier getseq6, 278*4ac22c89SDavid du Colombier putseq6, 279*4ac22c89SDavid du Colombier gettype6, 280*4ac22c89SDavid du Colombier settype6, 281*4ac22c89SDavid du Colombier getcode6, 282*4ac22c89SDavid du Colombier setcode6, 283*4ac22c89SDavid du Colombier prreply6, 284*4ac22c89SDavid du Colombier prlost6, 285*4ac22c89SDavid du Colombier }; 286*4ac22c89SDavid du Colombier 287*4ac22c89SDavid du Colombier static Proto *proto = &v4pr; 288*4ac22c89SDavid du Colombier 2897dd7cddfSDavid du Colombier void 290*4ac22c89SDavid du Colombier clean(ushort seq, vlong now, void *v) 2917dd7cddfSDavid du Colombier { 2927dd7cddfSDavid du Colombier Req **l, *r; 2937dd7cddfSDavid du Colombier 2947dd7cddfSDavid du Colombier lock(&listlock); 2950b9a5132SDavid du Colombier last = nil; 2967dd7cddfSDavid du Colombier for(l = &first; *l; ){ 2977dd7cddfSDavid du Colombier r = *l; 2983ff48bf5SDavid du Colombier 299*4ac22c89SDavid du Colombier if(v && r->seq == seq){ 3003ff48bf5SDavid du Colombier r->rtt = now-r->time; 301*4ac22c89SDavid du Colombier r->ttl = (*proto->getttl)(v); 302*4ac22c89SDavid du Colombier reply(r, v); 3033ff48bf5SDavid du Colombier } 3043ff48bf5SDavid du Colombier 3053ff48bf5SDavid du Colombier if(now-r->time > MINUTE){ 3067dd7cddfSDavid du Colombier *l = r->next; 3073ff48bf5SDavid du Colombier r->rtt = now-r->time; 308*4ac22c89SDavid du Colombier if(v) 309*4ac22c89SDavid du Colombier r->ttl = (*proto->getttl)(v); 3103ff48bf5SDavid du Colombier if(r->replied == 0) 311*4ac22c89SDavid du Colombier lost(r, v); 3127dd7cddfSDavid du Colombier free(r); 31359cc4ca5SDavid du Colombier }else{ 31459cc4ca5SDavid du Colombier last = r; 315*4ac22c89SDavid du Colombier l = &r->next; 3167dd7cddfSDavid du Colombier } 31759cc4ca5SDavid du Colombier } 3187dd7cddfSDavid du Colombier unlock(&listlock); 3197dd7cddfSDavid du Colombier } 3207dd7cddfSDavid du Colombier 3217dd7cddfSDavid du Colombier void 3227dd7cddfSDavid du Colombier sender(int fd, int msglen, int interval, int n) 3237dd7cddfSDavid du Colombier { 324da51d93aSDavid du Colombier int i, extra; 3257dd7cddfSDavid du Colombier ushort seq; 326*4ac22c89SDavid du Colombier char buf[64*1024+512]; 327*4ac22c89SDavid du Colombier Req *r; 3287dd7cddfSDavid du Colombier 3297dd7cddfSDavid du Colombier srand(time(0)); 3303ff48bf5SDavid du Colombier firstseq = seq = rand(); 3317dd7cddfSDavid du Colombier 332*4ac22c89SDavid du Colombier for(i = proto->icmphdrsz; i < msglen; i++) 3339a747e4fSDavid du Colombier buf[i] = i; 334*4ac22c89SDavid du Colombier (*proto->settype)(buf); 335*4ac22c89SDavid du Colombier (*proto->setcode)(buf); 3367dd7cddfSDavid du Colombier 3377dd7cddfSDavid du Colombier for(i = 0; i < n; i++){ 338da51d93aSDavid du Colombier if(i != 0){ 339da51d93aSDavid du Colombier extra = rint? nrand(interval): 0; 340da51d93aSDavid du Colombier sleep(interval + extra); 341da51d93aSDavid du Colombier } 3427dd7cddfSDavid du Colombier r = malloc(sizeof *r); 343*4ac22c89SDavid du Colombier if (r == nil) 344*4ac22c89SDavid du Colombier continue; 345*4ac22c89SDavid du Colombier (*proto->putseq)(buf, seq); 3467dd7cddfSDavid du Colombier r->seq = seq; 3477dd7cddfSDavid du Colombier r->next = nil; 3480b9a5132SDavid du Colombier r->replied = 0; 3490b9a5132SDavid du Colombier r->time = nsec(); /* avoid early free in reply! */ 3507dd7cddfSDavid du Colombier lock(&listlock); 3517dd7cddfSDavid du Colombier if(first == nil) 3527dd7cddfSDavid du Colombier first = r; 3537dd7cddfSDavid du Colombier else 3547dd7cddfSDavid du Colombier last->next = r; 3557dd7cddfSDavid du Colombier last = r; 3567dd7cddfSDavid du Colombier unlock(&listlock); 3577dd7cddfSDavid du Colombier r->time = nsec(); 358*4ac22c89SDavid du Colombier if(write(fd, buf, msglen) < msglen){ 3597dd7cddfSDavid du Colombier fprint(2, "%s: write failed: %r\n", argv0); 3607dd7cddfSDavid du Colombier return; 3617dd7cddfSDavid du Colombier } 3627dd7cddfSDavid du Colombier seq++; 3637dd7cddfSDavid du Colombier } 3647dd7cddfSDavid du Colombier done = 1; 3657dd7cddfSDavid du Colombier } 3667dd7cddfSDavid du Colombier 3677dd7cddfSDavid du Colombier void 368fbfc9db9SDavid du Colombier rcvr(int fd, int msglen, int interval, int nmsg) 3697dd7cddfSDavid du Colombier { 3707dd7cddfSDavid du Colombier int i, n, munged; 371*4ac22c89SDavid du Colombier ushort x; 3727dd7cddfSDavid du Colombier vlong now; 373*4ac22c89SDavid du Colombier uchar buf[64*1024+512]; 37459cc4ca5SDavid du Colombier Req *r; 3757dd7cddfSDavid du Colombier 3767dd7cddfSDavid du Colombier sum = 0; 3778aafde0cSDavid du Colombier while(lostmsgs+rcvdmsgs < nmsg){ 37859cc4ca5SDavid du Colombier alarm((nmsg-lostmsgs-rcvdmsgs)*interval+5000); 379*4ac22c89SDavid du Colombier n = read(fd, buf, sizeof buf); 3807dd7cddfSDavid du Colombier alarm(0); 3817dd7cddfSDavid du Colombier now = nsec(); 3828aafde0cSDavid du Colombier if(n <= 0){ /* read interrupted - time to go */ 3838aafde0cSDavid du Colombier clean(0, now+MINUTE, nil); 3848aafde0cSDavid du Colombier continue; 38500c1ae4bSDavid du Colombier } 3867dd7cddfSDavid du Colombier if(n < msglen){ 3877dd7cddfSDavid du Colombier print("bad len %d/%d\n", n, msglen); 3887dd7cddfSDavid du Colombier continue; 3897dd7cddfSDavid du Colombier } 39080ee5cbfSDavid du Colombier munged = 0; 391*4ac22c89SDavid du Colombier for(i = proto->icmphdrsz; i < msglen; i++) 392*4ac22c89SDavid du Colombier if(buf[i] != (uchar)i) 39380ee5cbfSDavid du Colombier munged++; 39480ee5cbfSDavid du Colombier if(munged) 395*4ac22c89SDavid du Colombier print("corrupted reply\n"); 396*4ac22c89SDavid du Colombier x = (*proto->getseq)(buf); 397*4ac22c89SDavid du Colombier if((*proto->gettype)(buf) != proto->echoreply || 398*4ac22c89SDavid du Colombier (*proto->getcode)(buf) != 0) { 3997dd7cddfSDavid du Colombier print("bad sequence/code/type %d/%d/%d\n", 400*4ac22c89SDavid du Colombier (*proto->gettype)(buf), (*proto->getcode)(buf), 401*4ac22c89SDavid du Colombier x); 4027dd7cddfSDavid du Colombier continue; 4037dd7cddfSDavid du Colombier } 404*4ac22c89SDavid du Colombier clean(x, now, buf); 4057dd7cddfSDavid du Colombier } 40659cc4ca5SDavid du Colombier 40759cc4ca5SDavid du Colombier lock(&listlock); 40859cc4ca5SDavid du Colombier for(r = first; r; r = r->next) 4093ff48bf5SDavid du Colombier if(r->replied == 0) 41059cc4ca5SDavid du Colombier lostmsgs++; 41159cc4ca5SDavid du Colombier unlock(&listlock); 41259cc4ca5SDavid du Colombier 4137dd7cddfSDavid du Colombier if(lostmsgs) 414*4ac22c89SDavid du Colombier print("%d out of %d messages lost\n", lostmsgs, 415*4ac22c89SDavid du Colombier lostmsgs+rcvdmsgs); 4167dd7cddfSDavid du Colombier } 4177dd7cddfSDavid du Colombier 4187dd7cddfSDavid du Colombier void 4197dd7cddfSDavid du Colombier main(int argc, char **argv) 4207dd7cddfSDavid du Colombier { 421*4ac22c89SDavid du Colombier int fd, msglen, interval, nmsg; 422*4ac22c89SDavid du Colombier char *ds; 4237dd7cddfSDavid du Colombier 4247dd7cddfSDavid du Colombier nsec(); /* make sure time file is already open */ 4257dd7cddfSDavid du Colombier 4263ff48bf5SDavid du Colombier fmtinstall('V', eipfmt); 4273ff48bf5SDavid du Colombier 4287dd7cddfSDavid du Colombier msglen = interval = 0; 4297dd7cddfSDavid du Colombier nmsg = MAXMSG; 4307dd7cddfSDavid du Colombier ARGBEGIN { 431*4ac22c89SDavid du Colombier case '6': 432*4ac22c89SDavid du Colombier proto = &v6pr; 433*4ac22c89SDavid du Colombier break; 434*4ac22c89SDavid du Colombier case 'a': 435*4ac22c89SDavid du Colombier addresses = 1; 43600c1ae4bSDavid du Colombier break; 4377dd7cddfSDavid du Colombier case 'd': 4387dd7cddfSDavid du Colombier debug++; 4397dd7cddfSDavid du Colombier break; 440*4ac22c89SDavid du Colombier case 'f': 441*4ac22c89SDavid du Colombier flood = 1; 4427dd7cddfSDavid du Colombier break; 4437dd7cddfSDavid du Colombier case 'i': 444*4ac22c89SDavid du Colombier interval = atoi(EARGF(usage())); 445*4ac22c89SDavid du Colombier break; 446*4ac22c89SDavid du Colombier case 'l': 447*4ac22c89SDavid du Colombier lostonly++; 4487dd7cddfSDavid du Colombier break; 4497dd7cddfSDavid du Colombier case 'n': 450*4ac22c89SDavid du Colombier nmsg = atoi(EARGF(usage())); 4513ff48bf5SDavid du Colombier break; 4527dd7cddfSDavid du Colombier case 'q': 4537dd7cddfSDavid du Colombier quiet = 1; 4547dd7cddfSDavid du Colombier break; 455da51d93aSDavid du Colombier case 'r': 456da51d93aSDavid du Colombier rint = 1; 457da51d93aSDavid du Colombier break; 458*4ac22c89SDavid du Colombier case 's': 459*4ac22c89SDavid du Colombier msglen = atoi(EARGF(usage())); 460*4ac22c89SDavid du Colombier break; 461*4ac22c89SDavid du Colombier default: 462*4ac22c89SDavid du Colombier usage(); 4630b9a5132SDavid du Colombier break; 4647dd7cddfSDavid du Colombier } ARGEND; 465*4ac22c89SDavid du Colombier 466*4ac22c89SDavid du Colombier if(msglen < proto->icmphdrsz) 467*4ac22c89SDavid du Colombier msglen = proto->icmphdrsz; 468*4ac22c89SDavid du Colombier if(msglen < 64) 4697dd7cddfSDavid du Colombier msglen = 64; 4707dd7cddfSDavid du Colombier if(msglen >= 65*1024) 4717dd7cddfSDavid du Colombier msglen = 65*1024-1; 4720b9a5132SDavid du Colombier if(interval <= 0 && !flood) 4737dd7cddfSDavid du Colombier interval = SLEEPMS; 4747dd7cddfSDavid du Colombier 4757dd7cddfSDavid du Colombier if(argc < 1) 4767dd7cddfSDavid du Colombier usage(); 4777dd7cddfSDavid du Colombier 4787dd7cddfSDavid du Colombier notify(catch); 4797dd7cddfSDavid du Colombier 480*4ac22c89SDavid du Colombier ds = netmkaddr(argv[0], proto->net, "1"); 481*4ac22c89SDavid du Colombier fd = dial(ds, 0, 0, 0); 4827dd7cddfSDavid du Colombier if(fd < 0){ 483*4ac22c89SDavid du Colombier fprint(2, "%s: couldn't dial %s: %r\n", argv0, ds); 4847dd7cddfSDavid du Colombier exits("dialing"); 4857dd7cddfSDavid du Colombier } 4867dd7cddfSDavid du Colombier 487*4ac22c89SDavid du Colombier print("sending %d %d byte messages %d ms apart to %s\n", 488*4ac22c89SDavid du Colombier nmsg, msglen, interval, ds); 4897dd7cddfSDavid du Colombier 4907dd7cddfSDavid du Colombier switch(rfork(RFPROC|RFMEM|RFFDG)){ 4917dd7cddfSDavid du Colombier case -1: 4927dd7cddfSDavid du Colombier fprint(2, "%s: can't fork: %r\n", argv0); 493*4ac22c89SDavid du Colombier /* fallthrough */ 4947dd7cddfSDavid du Colombier case 0: 495fbfc9db9SDavid du Colombier rcvr(fd, msglen, interval, nmsg); 4967dd7cddfSDavid du Colombier exits(0); 4977dd7cddfSDavid du Colombier default: 4987dd7cddfSDavid du Colombier sender(fd, msglen, interval, nmsg); 4999a747e4fSDavid du Colombier wait(); 500443f8232SDavid du Colombier exits(lostmsgs ? "lost messages" : ""); 5017dd7cddfSDavid du Colombier } 5027dd7cddfSDavid du Colombier } 5037dd7cddfSDavid du Colombier 5047dd7cddfSDavid du Colombier void 505*4ac22c89SDavid du Colombier reply(Req *r, void *v) 5067dd7cddfSDavid du Colombier { 5073ff48bf5SDavid du Colombier r->rtt /= 1000LL; 5083ff48bf5SDavid du Colombier sum += r->rtt; 5098aafde0cSDavid du Colombier if(!r->replied) 5108aafde0cSDavid du Colombier rcvdmsgs++; 511*4ac22c89SDavid du Colombier if(!quiet && !lostonly) 5123ff48bf5SDavid du Colombier if(addresses) 513*4ac22c89SDavid du Colombier (*proto->prreply)(r, v); 5143ff48bf5SDavid du Colombier else 5153ff48bf5SDavid du Colombier print("%ud: rtt %lld µs, avg rtt %lld µs, ttl = %d\n", 516*4ac22c89SDavid du Colombier r->seq - firstseq, r->rtt, sum/rcvdmsgs, r->ttl); 5173ff48bf5SDavid du Colombier r->replied = 1; 5187dd7cddfSDavid du Colombier } 51900c1ae4bSDavid du Colombier 52000c1ae4bSDavid du Colombier void 521*4ac22c89SDavid du Colombier lost(Req *r, void *v) 52200c1ae4bSDavid du Colombier { 523*4ac22c89SDavid du Colombier if(!quiet) 524*4ac22c89SDavid du Colombier if(addresses && v != nil) 525*4ac22c89SDavid du Colombier (*proto->prlost)(r->seq - firstseq, v); 52600c1ae4bSDavid du Colombier else 5278aafde0cSDavid du Colombier print("lost %ud\n", r->seq - firstseq); 52800c1ae4bSDavid du Colombier lostmsgs++; 52900c1ae4bSDavid du Colombier } 530