ping.c 3.0 KB

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