xref: /plan9/sys/src/cmd/cifs/ping.c (revision 671dfc474d1a5bcbeda8be1356d2abfa05b91489)
1*671dfc47SDavid du Colombier #include <u.h>
2*671dfc47SDavid du Colombier #include <libc.h>
3*671dfc47SDavid du Colombier #include <fcall.h>
4*671dfc47SDavid du Colombier #include <thread.h>
5*671dfc47SDavid du Colombier #include <libsec.h>
6*671dfc47SDavid du Colombier #include <9p.h>
7*671dfc47SDavid du Colombier 
8*671dfc47SDavid du Colombier extern char *Debug;
9*671dfc47SDavid du Colombier 
10*671dfc47SDavid du Colombier typedef struct Pingcache Pingcache;
11*671dfc47SDavid du Colombier struct Pingcache {
12*671dfc47SDavid du Colombier 	Pingcache*next;
13*671dfc47SDavid du Colombier 	long	rtt;
14*671dfc47SDavid du Colombier 	char	*host;
15*671dfc47SDavid du Colombier 	long	expire;
16*671dfc47SDavid du Colombier };
17*671dfc47SDavid du Colombier 
18*671dfc47SDavid du Colombier typedef struct {
19*671dfc47SDavid du Colombier 	uchar	vihl;		/* Version and header length */
20*671dfc47SDavid du Colombier 	uchar	tos;		/* Type of service */
21*671dfc47SDavid du Colombier 	uchar	length[2];	/* packet length */
22*671dfc47SDavid du Colombier 	uchar	id[2];		/* Identification */
23*671dfc47SDavid du Colombier 	uchar	frag[2];	/* Fragment information */
24*671dfc47SDavid du Colombier 	uchar	ttl;		/* Time to live */
25*671dfc47SDavid du Colombier 	uchar	proto;		/* Protocol */
26*671dfc47SDavid du Colombier 	uchar	ipcksum[2];	/* Header checksum */
27*671dfc47SDavid du Colombier 	uchar	src[4];		/* Ip source */
28*671dfc47SDavid du Colombier 	uchar	dst[4];		/* Ip destination */
29*671dfc47SDavid du Colombier 	uchar	type;
30*671dfc47SDavid du Colombier 	uchar	code;
31*671dfc47SDavid du Colombier 	uchar	cksum[2];
32*671dfc47SDavid du Colombier 	uchar	icmpid[2];
33*671dfc47SDavid du Colombier 	uchar	seq[2];
34*671dfc47SDavid du Colombier 	uchar	data[1];
35*671dfc47SDavid du Colombier } Icmp;
36*671dfc47SDavid du Colombier 
37*671dfc47SDavid du Colombier enum {			/* Packet Types */
38*671dfc47SDavid du Colombier 	EchoReply	= 0,
39*671dfc47SDavid du Colombier 	Unreachable	= 3,
40*671dfc47SDavid du Colombier 	SrcQuench	= 4,
41*671dfc47SDavid du Colombier 	EchoRequest	= 8,
42*671dfc47SDavid du Colombier 	TimeExceed	= 11,
43*671dfc47SDavid du Colombier 	Timestamp	= 13,
44*671dfc47SDavid du Colombier 	TimestampReply	= 14,
45*671dfc47SDavid du Colombier 	InfoRequest	= 15,
46*671dfc47SDavid du Colombier 	InfoReply	= 16,
47*671dfc47SDavid du Colombier 
48*671dfc47SDavid du Colombier 	ICMP_IPSIZE	= 20,
49*671dfc47SDavid du Colombier 	ICMP_HDRSIZE	= 8,
50*671dfc47SDavid du Colombier 
51*671dfc47SDavid du Colombier 	Npings		= 8,
52*671dfc47SDavid du Colombier 	Payload		= 32,
53*671dfc47SDavid du Colombier 
54*671dfc47SDavid du Colombier 	Cachetime	= 60,
55*671dfc47SDavid du Colombier };
56*671dfc47SDavid du Colombier 
57*671dfc47SDavid du Colombier static Pingcache *Cache;
58*671dfc47SDavid du Colombier 
59*671dfc47SDavid du Colombier /*
60*671dfc47SDavid du Colombier  * We ignore the first result as that is probably bigger
61*671dfc47SDavid du Colombier  * than expected due to IP sorting out the routing to the host
62*671dfc47SDavid du Colombier  */
63*671dfc47SDavid du Colombier int
ping(char * host,int timeout)64*671dfc47SDavid du Colombier ping(char *host, int timeout)
65*671dfc47SDavid du Colombier {
66*671dfc47SDavid du Colombier 	int rtt, fd, i, seq;
67*671dfc47SDavid du Colombier 	long now;
68*671dfc47SDavid du Colombier 	vlong then;
69*671dfc47SDavid du Colombier 	uchar buf[128];
70*671dfc47SDavid du Colombier 	Icmp *ip;
71*671dfc47SDavid du Colombier 	Pingcache *c;
72*671dfc47SDavid du Colombier 
73*671dfc47SDavid du Colombier 	now = time(nil);
74*671dfc47SDavid du Colombier 	for(c = Cache; c; c = c->next)
75*671dfc47SDavid du Colombier 		if(strcmp(c->host, host) == 0 && now < c->expire){
76*671dfc47SDavid du Colombier 			if(Debug && strstr(Debug, "dfs") != nil)
77*671dfc47SDavid du Colombier 				print("\t\tping host=%s timeout=%d - cache hit\n",
78*671dfc47SDavid du Colombier 					host, timeout);
79*671dfc47SDavid du Colombier 			return c->rtt;
80*671dfc47SDavid du Colombier 		}
81*671dfc47SDavid du Colombier 
82*671dfc47SDavid du Colombier 	rtt = -1;
83*671dfc47SDavid du Colombier 	ip = (Icmp*)buf;
84*671dfc47SDavid du Colombier 
85*671dfc47SDavid du Colombier 	if((fd = dial(netmkaddr(host, "icmp", "1"), 0, 0, 0)) == -1)
86*671dfc47SDavid du Colombier 		goto fail;
87*671dfc47SDavid du Colombier 
88*671dfc47SDavid du Colombier 	for(seq = 0; seq < Npings; seq++){
89*671dfc47SDavid du Colombier 		then = nsec();
90*671dfc47SDavid du Colombier 		for(i = Payload; i < sizeof buf; i++)
91*671dfc47SDavid du Colombier 			buf[i] = i + seq;
92*671dfc47SDavid du Colombier 		ip->type = EchoRequest;
93*671dfc47SDavid du Colombier 		ip->code = 0;
94*671dfc47SDavid du Colombier 		ip->seq[0] = seq;
95*671dfc47SDavid du Colombier 		ip->seq[1] = seq;
96*671dfc47SDavid du Colombier 		alarm(timeout);
97*671dfc47SDavid du Colombier 		if(write(fd, ip, sizeof buf) != sizeof buf ||
98*671dfc47SDavid du Colombier 		    read(fd, ip, sizeof buf) != sizeof buf)
99*671dfc47SDavid du Colombier 			goto fail;
100*671dfc47SDavid du Colombier 		alarm(0);
101*671dfc47SDavid du Colombier 		if(ip->type != EchoReply || ip->code != 0 ||
102*671dfc47SDavid du Colombier 		    ip->seq[0] != seq || ip->seq[1] != seq)
103*671dfc47SDavid du Colombier 			goto fail;
104*671dfc47SDavid du Colombier 		for(i = Payload; i < sizeof buf; i++)
105*671dfc47SDavid du Colombier 			if((uchar)buf[i] != (uchar)(i + seq))
106*671dfc47SDavid du Colombier 				goto fail;
107*671dfc47SDavid du Colombier 		rtt = (rtt + nsec() - then) / 2;
108*671dfc47SDavid du Colombier 	}
109*671dfc47SDavid du Colombier fail:
110*671dfc47SDavid du Colombier 	if(fd != -1)
111*671dfc47SDavid du Colombier 		close(fd);
112*671dfc47SDavid du Colombier 
113*671dfc47SDavid du Colombier 	if(Debug && strstr(Debug, "dfs") != nil)
114*671dfc47SDavid du Colombier 		print("\t\tping host=%s timeout=%d rtt=%d - failed\n",
115*671dfc47SDavid du Colombier 			host, timeout, rtt);
116*671dfc47SDavid du Colombier 
117*671dfc47SDavid du Colombier 	/*
118*671dfc47SDavid du Colombier 	 * failures get cached too
119*671dfc47SDavid du Colombier 	 */
120*671dfc47SDavid du Colombier 	for(c = Cache; c; c = c->next)
121*671dfc47SDavid du Colombier 		if(strcmp(c->host, host) == 0)
122*671dfc47SDavid du Colombier 			break;
123*671dfc47SDavid du Colombier 	if(c == nil){
124*671dfc47SDavid du Colombier 		c = emalloc9p(sizeof(Pingcache));
125*671dfc47SDavid du Colombier 		c->host = estrdup9p(host);
126*671dfc47SDavid du Colombier 		c->next = Cache;
127*671dfc47SDavid du Colombier 		Cache = c;
128*671dfc47SDavid du Colombier 	}
129*671dfc47SDavid du Colombier 	c->rtt = rtt;
130*671dfc47SDavid du Colombier 	c->expire = now+Cachetime;
131*671dfc47SDavid du Colombier 	return rtt;
132*671dfc47SDavid du Colombier }
133