summaryrefslogtreecommitdiff
path: root/sys/src/cmd/cifs/ping.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/cifs/ping.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/cifs/ping.c')
-rwxr-xr-xsys/src/cmd/cifs/ping.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/sys/src/cmd/cifs/ping.c b/sys/src/cmd/cifs/ping.c
new file mode 100755
index 000000000..0aaaaa7e8
--- /dev/null
+++ b/sys/src/cmd/cifs/ping.c
@@ -0,0 +1,132 @@
+#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;
+}