ping.c 3.1 KB

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