141 lines · 3.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <fcall.h>#include <thread.h>#include <libsec.h>#include <9p.h> extern char *Debug; typedef struct Pingcache Pingcache;struct Pingcache {	Pingcache*next;	long	rtt;	char	*host;	long	expire;}; typedef struct {	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];} Icmp; 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, 	Npings		= 8,	Payload		= 32, 	Cachetime	= 60,}; static Pingcache *Cache; /* * We ignore the first result as that is probably bigger * than expected due to IP sorting out the routing to the host */intping(char *host, int timeout){	int rtt, fd, i, seq;	long now;	vlong then;	uchar buf[128];	Icmp *ip;	Pingcache *c; 	now = time(nil);	for(c = Cache; c; c = c->next)		if(strcmp(c->host, host) == 0 && now < c->expire){			if(Debug && strstr(Debug, "dfs") != nil)				print("\t\tping host=%s timeout=%d - cache hit\n",					host, timeout);			return c->rtt;		} 	rtt = -1;	ip = (Icmp*)buf; 	if((fd = dial(netmkaddr(host, "icmp", "1"), 0, 0, 0)) == -1)		goto fail; 	for(seq = 0; seq < Npings; seq++){		then = nsec();		for(i = Payload; i < sizeof buf; i++)			buf[i] = i + seq;		ip->type = EchoRequest;		ip->code = 0;		ip->seq[0] = seq;		ip->seq[1] = seq;		alarm(timeout);		if(write(fd, ip, sizeof buf) != sizeof buf ||		    read(fd, ip, sizeof buf) != sizeof buf)			goto fail;		alarm(0);		if(ip->type != EchoReply || ip->code != 0 ||		    ip->seq[0] != seq || ip->seq[1] != seq)			goto fail;		for(i = Payload; i < sizeof buf; i++)			if((uchar)buf[i] != (uchar)(i + seq))				goto fail;		rtt = (rtt + nsec() - then) / 2;	}fail:	if(fd != -1)		close(fd); 	if(Debug && strstr(Debug, "dfs") != nil)		print("\t\tping host=%s timeout=%d rtt=%d - failed\n",			host, timeout, rtt); 	/*	 * failures get cached too	 */	for(c = Cache; c; c = c->next)		if(strcmp(c->host, host) == 0)			break;	if(c == nil){		c = emalloc9p(sizeof(Pingcache));		c->host = estrdup9p(host);		c->next = Cache;		Cache = c;	}	c->rtt = rtt;	c->expire = now+Cachetime;	return rtt;}