123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- #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
- */
- int
- ping(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;
- }
|