henesyinit from p9f0ed2a895 years agoHistory
293 lines · 4.6 KB · C
RawDownload
#include <u.h>#include <libc.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{	int	seq;	// sequence number	vlong	time;	// time sent	int	rtt;	int	ttl;	Req	 *next;};Req	*first;		// request listReq	*last;		// ...Lock	listlock; char *argv0;int debug;int quiet;int lostmsgs;int rcvdmsgs;int done;vlong sum;  void usage(void);void lost(Req*);void reply(Req*); #define SECOND 1000000000LL#define MINUTE (60LL*SECOND) voidusage(void){	fprint(2, "usage: %s destination\n", argv0);	exits("usage");} static voidcatch(void *a, char *msg){	USED(a);	if(strstr(msg, "alarm"))		noted(NCONT);	else		noted(NDFLT);} voidclean(ushort seq, vlong now, int ttl){	Req **l, *r; 	lock(&listlock);	for(l = &first; *l; ){		r = *l;		if(now-r->time > MINUTE || r->seq == seq){			*l = r->next;			r->time = now-r->time;			r->ttl = ttl;			if(r->seq != seq)				lost(r);			else				reply(r);			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, j;	Req *r;	ushort seq;	ulong randn; 	ip = (Icmp*)buf; 	srand(time(0));	seq = rand(); 	ip->type = EchoRequest;	ip->code = 0; 	for(i = 0; i < n; i++){		if(i != 0)			sleep(interval);		r = malloc(sizeof *r);		if(r != nil){			ip->seq[0] = seq;			ip->seq[1] = seq>>8;			r->seq = seq;			r->next = nil;			randn = seq;			for(j = 32; j < msglen; j++) {				randn = randn*1103515245 + 12345;				buf[j] = randn>>24;			}			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;	ulong randn; 	ip = (Icmp*)buf;	sum = 0; 	while(!done || first != nil){		alarm((nmsg-lostmsgs-rcvdmsgs)*interval+5000);		n = read(fd, buf, sizeof(buf));		alarm(0);		now = nsec();		if(n <= 0)			break;		if(n < msglen){			print("bad len %d/%d\n", n, msglen);			continue;		}		x = (ip->seq[1]<<8)|ip->seq[0];		munged = 0;		randn = x;		for(i = 32; i < msglen; i++) {			randn = randn*1103515245 + 12345;			if(buf[i] != (randn>>24))				munged++;		}		if(munged)			print("corrupted reply\n");		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->ttl);	}		lock(&listlock);	for(r = first; r; r = r->next)		lostmsgs++;	unlock(&listlock); 	if(lostmsgs)		print("%d out of %d messages lost\n", lostmsgs, lostmsgs+rcvdmsgs);} voidmain(int argc, char **argv){	int fd;	int msglen, interval, nmsg;	Waitmsg w; 	nsec();		/* make sure time file is already open */ 	msglen = interval = 0;	nmsg = MAXMSG;	ARGBEGIN {	case 'd':		debug++;		break;	case 's':		msglen = atoi(ARGF());		break;	case 'i':		interval = atoi(ARGF());		break;	case 'n':		nmsg = atoi(ARGF());		break;	case 'q':		quiet = 1;		break;	} ARGEND;	if(msglen < 32)		msglen = 64;	if(msglen >= 65*1024)		msglen = 65*1024-1;	if(interval <= 0)		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(&w);		exits(0);	}} voidlost(Req *){	lostmsgs++;} voidreply(Req *r){	rcvdmsgs++;	r->time /= 1000LL;	sum += r->time;	if(!quiet)		print("rtt %lld µs, avg rtt %lld µs, ttl = %d\n",			r->time, sum/rcvdmsgs, r->ttl);}