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