ping.c 2.6 KB

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