dnsruby 1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. data/EVENTMACHINE +64 -0
  2. data/README +63 -0
  3. data/doc/classes/Dnsruby.html +463 -0
  4. data/doc/classes/Dnsruby/Algorithms.html +171 -0
  5. data/doc/classes/Dnsruby/Classes.html +197 -0
  6. data/doc/classes/Dnsruby/Classes.src/M000209.html +23 -0
  7. data/doc/classes/Dnsruby/Classes.src/M000210.html +19 -0
  8. data/doc/classes/Dnsruby/CodeMapper.html +375 -0
  9. data/doc/classes/Dnsruby/CodeMapper.src/M000186.html +18 -0
  10. data/doc/classes/Dnsruby/CodeMapper.src/M000187.html +33 -0
  11. data/doc/classes/Dnsruby/CodeMapper.src/M000188.html +21 -0
  12. data/doc/classes/Dnsruby/CodeMapper.src/M000189.html +19 -0
  13. data/doc/classes/Dnsruby/CodeMapper.src/M000190.html +19 -0
  14. data/doc/classes/Dnsruby/CodeMapper.src/M000191.html +18 -0
  15. data/doc/classes/Dnsruby/CodeMapper.src/M000192.html +22 -0
  16. data/doc/classes/Dnsruby/CodeMapper.src/M000193.html +22 -0
  17. data/doc/classes/Dnsruby/CodeMapper.src/M000194.html +22 -0
  18. data/doc/classes/Dnsruby/CodeMapper.src/M000195.html +31 -0
  19. data/doc/classes/Dnsruby/CodeMapper.src/M000196.html +19 -0
  20. data/doc/classes/Dnsruby/Config.html +413 -0
  21. data/doc/classes/Dnsruby/Config.src/M000148.html +18 -0
  22. data/doc/classes/Dnsruby/Config.src/M000149.html +19 -0
  23. data/doc/classes/Dnsruby/Config.src/M000150.html +19 -0
  24. data/doc/classes/Dnsruby/Config.src/M000151.html +25 -0
  25. data/doc/classes/Dnsruby/Config.src/M000152.html +21 -0
  26. data/doc/classes/Dnsruby/Config.src/M000153.html +38 -0
  27. data/doc/classes/Dnsruby/Config.src/M000154.html +26 -0
  28. data/doc/classes/Dnsruby/Config.src/M000155.html +22 -0
  29. data/doc/classes/Dnsruby/Config.src/M000156.html +27 -0
  30. data/doc/classes/Dnsruby/Config.src/M000157.html +22 -0
  31. data/doc/classes/Dnsruby/Config.src/M000158.html +21 -0
  32. data/doc/classes/Dnsruby/DNS.html +571 -0
  33. data/doc/classes/Dnsruby/DNS.src/M000258.html +24 -0
  34. data/doc/classes/Dnsruby/DNS.src/M000259.html +18 -0
  35. data/doc/classes/Dnsruby/DNS.src/M000260.html +18 -0
  36. data/doc/classes/Dnsruby/DNS.src/M000261.html +20 -0
  37. data/doc/classes/Dnsruby/DNS.src/M000262.html +19 -0
  38. data/doc/classes/Dnsruby/DNS.src/M000263.html +20 -0
  39. data/doc/classes/Dnsruby/DNS.src/M000264.html +18 -0
  40. data/doc/classes/Dnsruby/DNS.src/M000265.html +19 -0
  41. data/doc/classes/Dnsruby/DNS.src/M000266.html +20 -0
  42. data/doc/classes/Dnsruby/DNS.src/M000267.html +28 -0
  43. data/doc/classes/Dnsruby/DNS.src/M000268.html +19 -0
  44. data/doc/classes/Dnsruby/DNS.src/M000269.html +20 -0
  45. data/doc/classes/Dnsruby/DNS.src/M000270.html +31 -0
  46. data/doc/classes/Dnsruby/DecodeError.html +120 -0
  47. data/doc/classes/Dnsruby/Dnssec.html +287 -0
  48. data/doc/classes/Dnsruby/Dnssec.src/M000249.html +23 -0
  49. data/doc/classes/Dnsruby/Dnssec.src/M000250.html +19 -0
  50. data/doc/classes/Dnsruby/Dnssec.src/M000251.html +90 -0
  51. data/doc/classes/Dnsruby/Dnssec.src/M000252.html +76 -0
  52. data/doc/classes/Dnsruby/EncodeError.html +120 -0
  53. data/doc/classes/Dnsruby/FormErr.html +119 -0
  54. data/doc/classes/Dnsruby/Header.html +501 -0
  55. data/doc/classes/Dnsruby/Header.src/M000231.html +35 -0
  56. data/doc/classes/Dnsruby/Header.src/M000232.html +18 -0
  57. data/doc/classes/Dnsruby/Header.src/M000233.html +18 -0
  58. data/doc/classes/Dnsruby/Header.src/M000234.html +21 -0
  59. data/doc/classes/Dnsruby/Header.src/M000235.html +20 -0
  60. data/doc/classes/Dnsruby/Header.src/M000236.html +32 -0
  61. data/doc/classes/Dnsruby/Header.src/M000237.html +27 -0
  62. data/doc/classes/Dnsruby/Header.src/M000238.html +26 -0
  63. data/doc/classes/Dnsruby/Header.src/M000239.html +47 -0
  64. data/doc/classes/Dnsruby/Header.src/M000240.html +28 -0
  65. data/doc/classes/Dnsruby/Header.src/M000241.html +30 -0
  66. data/doc/classes/Dnsruby/Hosts.html +316 -0
  67. data/doc/classes/Dnsruby/Hosts.src/M000197.html +20 -0
  68. data/doc/classes/Dnsruby/Hosts.src/M000198.html +19 -0
  69. data/doc/classes/Dnsruby/Hosts.src/M000199.html +20 -0
  70. data/doc/classes/Dnsruby/Hosts.src/M000200.html +21 -0
  71. data/doc/classes/Dnsruby/Hosts.src/M000201.html +19 -0
  72. data/doc/classes/Dnsruby/Hosts.src/M000202.html +20 -0
  73. data/doc/classes/Dnsruby/Hosts.src/M000203.html +21 -0
  74. data/doc/classes/Dnsruby/IPv4.html +233 -0
  75. data/doc/classes/Dnsruby/IPv4.src/M000204.html +32 -0
  76. data/doc/classes/Dnsruby/IPv4.src/M000205.html +19 -0
  77. data/doc/classes/Dnsruby/IPv4.src/M000206.html +18 -0
  78. data/doc/classes/Dnsruby/IPv4.src/M000207.html +18 -0
  79. data/doc/classes/Dnsruby/IPv4.src/M000208.html +18 -0
  80. data/doc/classes/Dnsruby/IPv6.html +281 -0
  81. data/doc/classes/Dnsruby/IPv6.src/M000242.html +60 -0
  82. data/doc/classes/Dnsruby/IPv6.src/M000243.html +22 -0
  83. data/doc/classes/Dnsruby/IPv6.src/M000244.html +20 -0
  84. data/doc/classes/Dnsruby/IPv6.src/M000245.html +18 -0
  85. data/doc/classes/Dnsruby/Message.html +803 -0
  86. data/doc/classes/Dnsruby/Message.src/M000119.html +38 -0
  87. data/doc/classes/Dnsruby/Message.src/M000120.html +26 -0
  88. data/doc/classes/Dnsruby/Message.src/M000121.html +22 -0
  89. data/doc/classes/Dnsruby/Message.src/M000122.html +22 -0
  90. data/doc/classes/Dnsruby/Message.src/M000123.html +20 -0
  91. data/doc/classes/Dnsruby/Message.src/M000124.html +20 -0
  92. data/doc/classes/Dnsruby/Message.src/M000125.html +20 -0
  93. data/doc/classes/Dnsruby/Message.src/M000126.html +20 -0
  94. data/doc/classes/Dnsruby/Message.src/M000127.html +18 -0
  95. data/doc/classes/Dnsruby/Message.src/M000128.html +20 -0
  96. data/doc/classes/Dnsruby/Message.src/M000129.html +23 -0
  97. data/doc/classes/Dnsruby/Message.src/M000130.html +30 -0
  98. data/doc/classes/Dnsruby/Message.src/M000131.html +20 -0
  99. data/doc/classes/Dnsruby/Message.src/M000132.html +18 -0
  100. data/doc/classes/Dnsruby/Message.src/M000133.html +56 -0
  101. data/doc/classes/Dnsruby/Message.src/M000134.html +35 -0
  102. data/doc/classes/Dnsruby/Message.src/M000135.html +46 -0
  103. data/doc/classes/Dnsruby/Message/Section.html +160 -0
  104. data/doc/classes/Dnsruby/Message/Section.src/M000141.html +29 -0
  105. data/doc/classes/Dnsruby/Message/Section.src/M000142.html +30 -0
  106. data/doc/classes/Dnsruby/MetaTypes.html +136 -0
  107. data/doc/classes/Dnsruby/Modes.html +171 -0
  108. data/doc/classes/Dnsruby/NXDomain.html +119 -0
  109. data/doc/classes/Dnsruby/Name.html +330 -0
  110. data/doc/classes/Dnsruby/Name.src/M000104.html +28 -0
  111. data/doc/classes/Dnsruby/Name.src/M000105.html +20 -0
  112. data/doc/classes/Dnsruby/Name.src/M000106.html +18 -0
  113. data/doc/classes/Dnsruby/Name.src/M000107.html +21 -0
  114. data/doc/classes/Dnsruby/Name.src/M000108.html +22 -0
  115. data/doc/classes/Dnsruby/Name.src/M000109.html +18 -0
  116. data/doc/classes/Dnsruby/Name/Label.html +300 -0
  117. data/doc/classes/Dnsruby/Name/Label.src/M000110.html +21 -0
  118. data/doc/classes/Dnsruby/Name/Label.src/M000111.html +18 -0
  119. data/doc/classes/Dnsruby/Name/Label.src/M000112.html +22 -0
  120. data/doc/classes/Dnsruby/Name/Label.src/M000113.html +18 -0
  121. data/doc/classes/Dnsruby/Name/Label.src/M000114.html +18 -0
  122. data/doc/classes/Dnsruby/Name/Label.src/M000115.html +18 -0
  123. data/doc/classes/Dnsruby/Name/Label.src/M000116.html +18 -0
  124. data/doc/classes/Dnsruby/Name/Label.src/M000117.html +18 -0
  125. data/doc/classes/Dnsruby/Name/Label.src/M000118.html +18 -0
  126. data/doc/classes/Dnsruby/NotImp.html +119 -0
  127. data/doc/classes/Dnsruby/OpCode.html +146 -0
  128. data/doc/classes/Dnsruby/OtherResolvError.html +119 -0
  129. data/doc/classes/Dnsruby/QTypes.html +146 -0
  130. data/doc/classes/Dnsruby/Question.html +301 -0
  131. data/doc/classes/Dnsruby/Question.src/M000226.html +47 -0
  132. data/doc/classes/Dnsruby/Question.src/M000227.html +18 -0
  133. data/doc/classes/Dnsruby/Question.src/M000228.html +18 -0
  134. data/doc/classes/Dnsruby/Question.src/M000229.html +32 -0
  135. data/doc/classes/Dnsruby/Question.src/M000230.html +18 -0
  136. data/doc/classes/Dnsruby/RCode.html +211 -0
  137. data/doc/classes/Dnsruby/RR.html +648 -0
  138. data/doc/classes/Dnsruby/RR.src/M000001.html +18 -0
  139. data/doc/classes/Dnsruby/RR.src/M000002.html +22 -0
  140. data/doc/classes/Dnsruby/RR.src/M000003.html +18 -0
  141. data/doc/classes/Dnsruby/RR.src/M000004.html +18 -0
  142. data/doc/classes/Dnsruby/RR.src/M000005.html +26 -0
  143. data/doc/classes/Dnsruby/RR.src/M000006.html +18 -0
  144. data/doc/classes/Dnsruby/RR.src/M000007.html +36 -0
  145. data/doc/classes/Dnsruby/RR.src/M000008.html +100 -0
  146. data/doc/classes/Dnsruby/RR.src/M000009.html +18 -0
  147. data/doc/classes/Dnsruby/RR.src/M000010.html +18 -0
  148. data/doc/classes/Dnsruby/RR.src/M000011.html +22 -0
  149. data/doc/classes/Dnsruby/RR.src/M000012.html +29 -0
  150. data/doc/classes/Dnsruby/RR.src/M000013.html +24 -0
  151. data/doc/classes/Dnsruby/RR/ANY.html +133 -0
  152. data/doc/classes/Dnsruby/RR/CERT.html +180 -0
  153. data/doc/classes/Dnsruby/RR/CERT/CertificateTypes.html +169 -0
  154. data/doc/classes/Dnsruby/RR/CNAME.html +151 -0
  155. data/doc/classes/Dnsruby/RR/DNAME.html +150 -0
  156. data/doc/classes/Dnsruby/RR/DNSKEY.html +422 -0
  157. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000044.html +20 -0
  158. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000045.html +21 -0
  159. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000046.html +28 -0
  160. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000047.html +22 -0
  161. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000048.html +18 -0
  162. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000049.html +22 -0
  163. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000050.html +18 -0
  164. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000051.html +26 -0
  165. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000052.html +38 -0
  166. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000053.html +45 -0
  167. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000054.html +21 -0
  168. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000055.html +24 -0
  169. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000056.html +32 -0
  170. data/doc/classes/Dnsruby/RR/DNSKEY.src/M000057.html +24 -0
  171. data/doc/classes/Dnsruby/RR/DS.html +286 -0
  172. data/doc/classes/Dnsruby/RR/DS.src/M000039.html +22 -0
  173. data/doc/classes/Dnsruby/RR/DS.src/M000040.html +28 -0
  174. data/doc/classes/Dnsruby/RR/DS.src/M000041.html +24 -0
  175. data/doc/classes/Dnsruby/RR/DS.src/M000042.html +28 -0
  176. data/doc/classes/Dnsruby/RR/DS.src/M000043.html +36 -0
  177. data/doc/classes/Dnsruby/RR/DomainName.html +175 -0
  178. data/doc/classes/Dnsruby/RR/DomainName.src/M000083.html +18 -0
  179. data/doc/classes/Dnsruby/RR/Generic.html +133 -0
  180. data/doc/classes/Dnsruby/RR/HINFO.html +155 -0
  181. data/doc/classes/Dnsruby/RR/IN.html +155 -0
  182. data/doc/classes/Dnsruby/RR/IN/A.html +200 -0
  183. data/doc/classes/Dnsruby/RR/IN/A.src/M000017.html +18 -0
  184. data/doc/classes/Dnsruby/RR/IN/A.src/M000018.html +18 -0
  185. data/doc/classes/Dnsruby/RR/IN/A.src/M000019.html +18 -0
  186. data/doc/classes/Dnsruby/RR/IN/AAAA.html +139 -0
  187. data/doc/classes/Dnsruby/RR/IN/AFSDB.html +145 -0
  188. data/doc/classes/Dnsruby/RR/IN/PX.html +143 -0
  189. data/doc/classes/Dnsruby/RR/IN/SRV.html +238 -0
  190. data/doc/classes/Dnsruby/RR/IN/SRV.src/M000014.html +29 -0
  191. data/doc/classes/Dnsruby/RR/IN/SRV.src/M000015.html +26 -0
  192. data/doc/classes/Dnsruby/RR/IN/SRV.src/M000016.html +22 -0
  193. data/doc/classes/Dnsruby/RR/IN/WKS.html +166 -0
  194. data/doc/classes/Dnsruby/RR/IN/WKS.src/M000020.html +20 -0
  195. data/doc/classes/Dnsruby/RR/ISDN.html +155 -0
  196. data/doc/classes/Dnsruby/RR/LOC.html +395 -0
  197. data/doc/classes/Dnsruby/RR/LOC.src/M000025.html +32 -0
  198. data/doc/classes/Dnsruby/RR/LOC.src/M000026.html +23 -0
  199. data/doc/classes/Dnsruby/RR/LOC.src/M000027.html +25 -0
  200. data/doc/classes/Dnsruby/RR/LOC.src/M000028.html +21 -0
  201. data/doc/classes/Dnsruby/RR/LOC.src/M000029.html +20 -0
  202. data/doc/classes/Dnsruby/RR/LOC.src/M000030.html +23 -0
  203. data/doc/classes/Dnsruby/RR/MB.html +150 -0
  204. data/doc/classes/Dnsruby/RR/MG.html +150 -0
  205. data/doc/classes/Dnsruby/RR/MINFO.html +156 -0
  206. data/doc/classes/Dnsruby/RR/MR.html +150 -0
  207. data/doc/classes/Dnsruby/RR/MX.html +155 -0
  208. data/doc/classes/Dnsruby/RR/NAPTR.html +190 -0
  209. data/doc/classes/Dnsruby/RR/NS.html +151 -0
  210. data/doc/classes/Dnsruby/RR/NSAP.html +293 -0
  211. data/doc/classes/Dnsruby/RR/NSAP.src/M000093.html +19 -0
  212. data/doc/classes/Dnsruby/RR/NSAP.src/M000094.html +19 -0
  213. data/doc/classes/Dnsruby/RR/NSAP.src/M000095.html +22 -0
  214. data/doc/classes/Dnsruby/RR/NSAP.src/M000096.html +31 -0
  215. data/doc/classes/Dnsruby/RR/NSEC.html +301 -0
  216. data/doc/classes/Dnsruby/RR/NSEC.src/M000031.html +19 -0
  217. data/doc/classes/Dnsruby/RR/NSEC.src/M000032.html +18 -0
  218. data/doc/classes/Dnsruby/RR/NSEC.src/M000033.html +34 -0
  219. data/doc/classes/Dnsruby/RR/NSEC.src/M000034.html +18 -0
  220. data/doc/classes/Dnsruby/RR/NSEC.src/M000035.html +71 -0
  221. data/doc/classes/Dnsruby/RR/NSEC.src/M000036.html +18 -0
  222. data/doc/classes/Dnsruby/RR/NSEC.src/M000037.html +80 -0
  223. data/doc/classes/Dnsruby/RR/NSEC.src/M000038.html +23 -0
  224. data/doc/classes/Dnsruby/RR/NSEC3.html +366 -0
  225. data/doc/classes/Dnsruby/RR/NSEC3.src/M000085.html +28 -0
  226. data/doc/classes/Dnsruby/RR/NSEC3.src/M000086.html +18 -0
  227. data/doc/classes/Dnsruby/RR/NSEC3.src/M000087.html +18 -0
  228. data/doc/classes/Dnsruby/RR/NSEC3.src/M000088.html +22 -0
  229. data/doc/classes/Dnsruby/RR/NSEC3.src/M000089.html +18 -0
  230. data/doc/classes/Dnsruby/RR/NSEC3.src/M000090.html +21 -0
  231. data/doc/classes/Dnsruby/RR/NSEC3.src/M000091.html +21 -0
  232. data/doc/classes/Dnsruby/RR/NSEC3.src/M000092.html +29 -0
  233. data/doc/classes/Dnsruby/RR/NSEC3PARAM.html +279 -0
  234. data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000077.html +28 -0
  235. data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000078.html +18 -0
  236. data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000079.html +22 -0
  237. data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000080.html +21 -0
  238. data/doc/classes/Dnsruby/RR/NSEC3PARAM.src/M000081.html +25 -0
  239. data/doc/classes/Dnsruby/RR/PTR.html +132 -0
  240. data/doc/classes/Dnsruby/RR/RP.html +183 -0
  241. data/doc/classes/Dnsruby/RR/RP.src/M000082.html +19 -0
  242. data/doc/classes/Dnsruby/RR/RRSIG.html +357 -0
  243. data/doc/classes/Dnsruby/RR/RRSIG.src/M000097.html +26 -0
  244. data/doc/classes/Dnsruby/RR/RRSIG.src/M000098.html +28 -0
  245. data/doc/classes/Dnsruby/RR/RRSIG.src/M000099.html +23 -0
  246. data/doc/classes/Dnsruby/RR/RRSIG.src/M000100.html +23 -0
  247. data/doc/classes/Dnsruby/RR/RRSIG.src/M000101.html +46 -0
  248. data/doc/classes/Dnsruby/RR/RRSIG.src/M000102.html +50 -0
  249. data/doc/classes/Dnsruby/RR/RRSIG.src/M000103.html +27 -0
  250. data/doc/classes/Dnsruby/RR/RT.html +155 -0
  251. data/doc/classes/Dnsruby/RR/SOA.html +233 -0
  252. data/doc/classes/Dnsruby/RR/SOA.src/M000066.html +24 -0
  253. data/doc/classes/Dnsruby/RR/SOA.src/M000067.html +27 -0
  254. data/doc/classes/Dnsruby/RR/SPF.html +138 -0
  255. data/doc/classes/Dnsruby/RR/TKEY.html +313 -0
  256. data/doc/classes/Dnsruby/RR/TKEY.src/M000021.html +19 -0
  257. data/doc/classes/Dnsruby/RR/TKEY.src/M000022.html +29 -0
  258. data/doc/classes/Dnsruby/RR/TKEY.src/M000023.html +21 -0
  259. data/doc/classes/Dnsruby/RR/TKEY.src/M000024.html +29 -0
  260. data/doc/classes/Dnsruby/RR/TSIG.html +524 -0
  261. data/doc/classes/Dnsruby/RR/TSIG.src/M000068.html +24 -0
  262. data/doc/classes/Dnsruby/RR/TSIG.src/M000069.html +32 -0
  263. data/doc/classes/Dnsruby/RR/TSIG.src/M000070.html +54 -0
  264. data/doc/classes/Dnsruby/RR/TSIG.src/M000071.html +121 -0
  265. data/doc/classes/Dnsruby/RR/TSIG.src/M000072.html +33 -0
  266. data/doc/classes/Dnsruby/RR/TSIG.src/M000073.html +25 -0
  267. data/doc/classes/Dnsruby/RR/TSIG.src/M000074.html +36 -0
  268. data/doc/classes/Dnsruby/RR/TSIG.src/M000075.html +22 -0
  269. data/doc/classes/Dnsruby/RR/TSIG.src/M000076.html +29 -0
  270. data/doc/classes/Dnsruby/RR/TXT.html +233 -0
  271. data/doc/classes/Dnsruby/RR/TXT.src/M000061.html +18 -0
  272. data/doc/classes/Dnsruby/RR/TXT.src/M000062.html +18 -0
  273. data/doc/classes/Dnsruby/RR/TXT.src/M000063.html +20 -0
  274. data/doc/classes/Dnsruby/RR/TXT.src/M000064.html +27 -0
  275. data/doc/classes/Dnsruby/RR/TXT.src/M000065.html +25 -0
  276. data/doc/classes/Dnsruby/RR/X25.html +203 -0
  277. data/doc/classes/Dnsruby/RR/X25.src/M000058.html +18 -0
  278. data/doc/classes/Dnsruby/RR/X25.src/M000059.html +18 -0
  279. data/doc/classes/Dnsruby/RR/X25.src/M000060.html +22 -0
  280. data/doc/classes/Dnsruby/RRSet.html +404 -0
  281. data/doc/classes/Dnsruby/RRSet.src/M000211.html +23 -0
  282. data/doc/classes/Dnsruby/RRSet.src/M000212.html +18 -0
  283. data/doc/classes/Dnsruby/RRSet.src/M000213.html +18 -0
  284. data/doc/classes/Dnsruby/RRSet.src/M000214.html +47 -0
  285. data/doc/classes/Dnsruby/RRSet.src/M000215.html +42 -0
  286. data/doc/classes/Dnsruby/RRSet.src/M000216.html +18 -0
  287. data/doc/classes/Dnsruby/RRSet.src/M000217.html +20 -0
  288. data/doc/classes/Dnsruby/RRSet.src/M000218.html +18 -0
  289. data/doc/classes/Dnsruby/RRSet.src/M000219.html +18 -0
  290. data/doc/classes/Dnsruby/RRSet.src/M000220.html +18 -0
  291. data/doc/classes/Dnsruby/RRSet.src/M000221.html +18 -0
  292. data/doc/classes/Dnsruby/RRSet.src/M000222.html +22 -0
  293. data/doc/classes/Dnsruby/RRSet.src/M000223.html +18 -0
  294. data/doc/classes/Dnsruby/RRSet.src/M000224.html +22 -0
  295. data/doc/classes/Dnsruby/RRSet.src/M000225.html +18 -0
  296. data/doc/classes/Dnsruby/Refused.html +119 -0
  297. data/doc/classes/Dnsruby/Resolv.html +401 -0
  298. data/doc/classes/Dnsruby/Resolv.src/M000159.html +18 -0
  299. data/doc/classes/Dnsruby/Resolv.src/M000160.html +18 -0
  300. data/doc/classes/Dnsruby/Resolv.src/M000161.html +18 -0
  301. data/doc/classes/Dnsruby/Resolv.src/M000162.html +18 -0
  302. data/doc/classes/Dnsruby/Resolv.src/M000163.html +18 -0
  303. data/doc/classes/Dnsruby/Resolv.src/M000164.html +18 -0
  304. data/doc/classes/Dnsruby/Resolv.src/M000165.html +18 -0
  305. data/doc/classes/Dnsruby/Resolv.src/M000166.html +19 -0
  306. data/doc/classes/Dnsruby/Resolv.src/M000167.html +20 -0
  307. data/doc/classes/Dnsruby/Resolv.src/M000168.html +29 -0
  308. data/doc/classes/Dnsruby/Resolv.src/M000169.html +19 -0
  309. data/doc/classes/Dnsruby/Resolv.src/M000170.html +20 -0
  310. data/doc/classes/Dnsruby/Resolv.src/M000171.html +25 -0
  311. data/doc/classes/Dnsruby/ResolvError.html +117 -0
  312. data/doc/classes/Dnsruby/ResolvTimeout.html +117 -0
  313. data/doc/classes/Dnsruby/Resolver.html +1055 -0
  314. data/doc/classes/Dnsruby/Resolver.src/M000271.html +21 -0
  315. data/doc/classes/Dnsruby/Resolver.src/M000272.html +27 -0
  316. data/doc/classes/Dnsruby/Resolver.src/M000273.html +28 -0
  317. data/doc/classes/Dnsruby/Resolver.src/M000274.html +18 -0
  318. data/doc/classes/Dnsruby/Resolver.src/M000275.html +51 -0
  319. data/doc/classes/Dnsruby/Resolver.src/M000276.html +21 -0
  320. data/doc/classes/Dnsruby/Resolver.src/M000277.html +22 -0
  321. data/doc/classes/Dnsruby/Resolver.src/M000278.html +18 -0
  322. data/doc/classes/Dnsruby/Resolver.src/M000279.html +20 -0
  323. data/doc/classes/Dnsruby/Resolver.src/M000280.html +19 -0
  324. data/doc/classes/Dnsruby/Resolver.src/M000281.html +19 -0
  325. data/doc/classes/Dnsruby/Resolver.src/M000282.html +19 -0
  326. data/doc/classes/Dnsruby/Resolver.src/M000283.html +19 -0
  327. data/doc/classes/Dnsruby/Resolver.src/M000284.html +19 -0
  328. data/doc/classes/Dnsruby/Resolver.src/M000285.html +19 -0
  329. data/doc/classes/Dnsruby/Resolver.src/M000286.html +19 -0
  330. data/doc/classes/Dnsruby/Resolver.src/M000287.html +19 -0
  331. data/doc/classes/Dnsruby/Resolver.src/M000288.html +19 -0
  332. data/doc/classes/Dnsruby/Resolver.src/M000289.html +19 -0
  333. data/doc/classes/Dnsruby/Resolver.src/M000290.html +19 -0
  334. data/doc/classes/Dnsruby/Resolver.src/M000291.html +19 -0
  335. data/doc/classes/Dnsruby/Resolver.src/M000292.html +26 -0
  336. data/doc/classes/Dnsruby/Resolver.src/M000293.html +18 -0
  337. data/doc/classes/Dnsruby/Resolver.src/M000294.html +23 -0
  338. data/doc/classes/Dnsruby/Resolver.src/M000295.html +18 -0
  339. data/doc/classes/Dnsruby/ServFail.html +119 -0
  340. data/doc/classes/Dnsruby/SingleResolver.html +674 -0
  341. data/doc/classes/Dnsruby/SingleResolver.src/M000172.html +18 -0
  342. data/doc/classes/Dnsruby/SingleResolver.src/M000173.html +24 -0
  343. data/doc/classes/Dnsruby/SingleResolver.src/M000174.html +36 -0
  344. data/doc/classes/Dnsruby/SingleResolver.src/M000175.html +18 -0
  345. data/doc/classes/Dnsruby/SingleResolver.src/M000176.html +19 -0
  346. data/doc/classes/Dnsruby/SingleResolver.src/M000177.html +50 -0
  347. data/doc/classes/Dnsruby/SingleResolver.src/M000178.html +19 -0
  348. data/doc/classes/Dnsruby/SingleResolver.src/M000179.html +21 -0
  349. data/doc/classes/Dnsruby/SingleResolver.src/M000180.html +25 -0
  350. data/doc/classes/Dnsruby/SingleResolver.src/M000181.html +54 -0
  351. data/doc/classes/Dnsruby/SingleResolver.src/M000182.html +27 -0
  352. data/doc/classes/Dnsruby/SingleResolver.src/M000183.html +27 -0
  353. data/doc/classes/Dnsruby/SingleResolver.src/M000184.html +35 -0
  354. data/doc/classes/Dnsruby/SingleResolver.src/M000185.html +21 -0
  355. data/doc/classes/Dnsruby/TheLog.html +196 -0
  356. data/doc/classes/Dnsruby/TheLog.src/M000246.html +20 -0
  357. data/doc/classes/Dnsruby/TheLog.src/M000247.html +20 -0
  358. data/doc/classes/Dnsruby/TheLog.src/M000248.html +20 -0
  359. data/doc/classes/Dnsruby/Types.html +436 -0
  360. data/doc/classes/Dnsruby/Update.html +368 -0
  361. data/doc/classes/Dnsruby/Update.src/M000253.html +32 -0
  362. data/doc/classes/Dnsruby/Update.src/M000254.html +36 -0
  363. data/doc/classes/Dnsruby/Update.src/M000255.html +32 -0
  364. data/doc/classes/Dnsruby/Update.src/M000256.html +41 -0
  365. data/doc/classes/Dnsruby/Update.src/M000257.html +34 -0
  366. data/doc/classes/Dnsruby/VerifyError.html +119 -0
  367. data/doc/classes/Dnsruby/ZoneTransfer.html +300 -0
  368. data/doc/classes/Dnsruby/ZoneTransfer.src/M000143.html +18 -0
  369. data/doc/classes/Dnsruby/ZoneTransfer.src/M000144.html +24 -0
  370. data/doc/classes/Dnsruby/ZoneTransfer.src/M000145.html +35 -0
  371. data/doc/classes/Dnsruby/ZoneTransfer/Delta.html +200 -0
  372. data/doc/classes/Dnsruby/ZoneTransfer/Delta.src/M000146.html +19 -0
  373. data/doc/classes/Dnsruby/ZoneTransfer/Delta.src/M000147.html +19 -0
  374. data/doc/created.rid +1 -0
  375. data/doc/files/lib/Dnsruby/Config_rb.html +101 -0
  376. data/doc/files/lib/Dnsruby/DNS_rb.html +110 -0
  377. data/doc/files/lib/Dnsruby/Hosts_rb.html +108 -0
  378. data/doc/files/lib/Dnsruby/Resolver_rb.html +109 -0
  379. data/doc/files/lib/Dnsruby/SingleResolver_rb.html +108 -0
  380. data/doc/files/lib/Dnsruby/TheLog_rb.html +110 -0
  381. data/doc/files/lib/Dnsruby/code_mapper_rb.html +101 -0
  382. data/doc/files/lib/Dnsruby/dnssec_rb.html +107 -0
  383. data/doc/files/lib/Dnsruby/event_machine_interface_rb.html +108 -0
  384. data/doc/files/lib/Dnsruby/ipv4_rb.html +101 -0
  385. data/doc/files/lib/Dnsruby/ipv6_rb.html +101 -0
  386. data/doc/files/lib/Dnsruby/message_rb.html +109 -0
  387. data/doc/files/lib/Dnsruby/name_rb.html +101 -0
  388. data/doc/files/lib/Dnsruby/resource/AAAA_rb.html +101 -0
  389. data/doc/files/lib/Dnsruby/resource/AFSDB_rb.html +101 -0
  390. data/doc/files/lib/Dnsruby/resource/A_rb.html +101 -0
  391. data/doc/files/lib/Dnsruby/resource/CERT_rb.html +101 -0
  392. data/doc/files/lib/Dnsruby/resource/DNSKEY_rb.html +101 -0
  393. data/doc/files/lib/Dnsruby/resource/DS_rb.html +101 -0
  394. data/doc/files/lib/Dnsruby/resource/HINFO_rb.html +101 -0
  395. data/doc/files/lib/Dnsruby/resource/IN_rb.html +112 -0
  396. data/doc/files/lib/Dnsruby/resource/ISDN_rb.html +101 -0
  397. data/doc/files/lib/Dnsruby/resource/LOC_rb.html +101 -0
  398. data/doc/files/lib/Dnsruby/resource/MINFO_rb.html +101 -0
  399. data/doc/files/lib/Dnsruby/resource/MX_rb.html +101 -0
  400. data/doc/files/lib/Dnsruby/resource/NAPTR_rb.html +101 -0
  401. data/doc/files/lib/Dnsruby/resource/NSAP_rb.html +101 -0
  402. data/doc/files/lib/Dnsruby/resource/NSEC3PARAM_rb.html +101 -0
  403. data/doc/files/lib/Dnsruby/resource/NSEC3_rb.html +101 -0
  404. data/doc/files/lib/Dnsruby/resource/NSEC_rb.html +101 -0
  405. data/doc/files/lib/Dnsruby/resource/OPT_rb.html +101 -0
  406. data/doc/files/lib/Dnsruby/resource/PX_rb.html +101 -0
  407. data/doc/files/lib/Dnsruby/resource/RP_rb.html +101 -0
  408. data/doc/files/lib/Dnsruby/resource/RRSIG_rb.html +101 -0
  409. data/doc/files/lib/Dnsruby/resource/RT_rb.html +101 -0
  410. data/doc/files/lib/Dnsruby/resource/SOA_rb.html +101 -0
  411. data/doc/files/lib/Dnsruby/resource/SPF_rb.html +101 -0
  412. data/doc/files/lib/Dnsruby/resource/SRV_rb.html +101 -0
  413. data/doc/files/lib/Dnsruby/resource/TKEY_rb.html +101 -0
  414. data/doc/files/lib/Dnsruby/resource/TSIG_rb.html +114 -0
  415. data/doc/files/lib/Dnsruby/resource/TXT_rb.html +108 -0
  416. data/doc/files/lib/Dnsruby/resource/X25_rb.html +101 -0
  417. data/doc/files/lib/Dnsruby/resource/domain_name_rb.html +101 -0
  418. data/doc/files/lib/Dnsruby/resource/generic_rb.html +131 -0
  419. data/doc/files/lib/Dnsruby/resource/resource_rb.html +110 -0
  420. data/doc/files/lib/Dnsruby/select_thread_rb.html +111 -0
  421. data/doc/files/lib/Dnsruby/update_rb.html +101 -0
  422. data/doc/files/lib/Dnsruby/zone_transfer_rb.html +101 -0
  423. data/doc/files/lib/dnsruby_rb.html +118 -0
  424. data/doc/fr_class_index.html +108 -0
  425. data/doc/fr_file_index.html +75 -0
  426. data/doc/fr_method_index.html +321 -0
  427. data/doc/index.html +24 -0
  428. data/lib/Dnsruby/Config.rb +363 -0
  429. data/lib/Dnsruby/DNS.rb +293 -0
  430. data/lib/Dnsruby/Hosts.rb +126 -0
  431. data/lib/Dnsruby/Resolver.rb +999 -0
  432. data/lib/Dnsruby/SingleResolver.rb +493 -0
  433. data/lib/Dnsruby/TheLog.rb +60 -0
  434. data/lib/Dnsruby/code_mapper.rb +165 -0
  435. data/lib/Dnsruby/dnssec.rb +357 -0
  436. data/lib/Dnsruby/event_machine_interface.rb +264 -0
  437. data/lib/Dnsruby/ipv4.rb +74 -0
  438. data/lib/Dnsruby/ipv6.rb +144 -0
  439. data/lib/Dnsruby/message.rb +961 -0
  440. data/lib/Dnsruby/name.rb +332 -0
  441. data/lib/Dnsruby/resource/A.rb +56 -0
  442. data/lib/Dnsruby/resource/AAAA.rb +54 -0
  443. data/lib/Dnsruby/resource/AFSDB.rb +68 -0
  444. data/lib/Dnsruby/resource/CERT.rb +89 -0
  445. data/lib/Dnsruby/resource/DNSKEY.rb +242 -0
  446. data/lib/Dnsruby/resource/DS.rb +162 -0
  447. data/lib/Dnsruby/resource/HINFO.rb +52 -0
  448. data/lib/Dnsruby/resource/IN.rb +70 -0
  449. data/lib/Dnsruby/resource/ISDN.rb +54 -0
  450. data/lib/Dnsruby/resource/LOC.rb +255 -0
  451. data/lib/Dnsruby/resource/MINFO.rb +70 -0
  452. data/lib/Dnsruby/resource/MX.rb +66 -0
  453. data/lib/Dnsruby/resource/NAPTR.rb +90 -0
  454. data/lib/Dnsruby/resource/NSAP.rb +172 -0
  455. data/lib/Dnsruby/resource/NSEC.rb +243 -0
  456. data/lib/Dnsruby/resource/NSEC3.rb +173 -0
  457. data/lib/Dnsruby/resource/NSEC3PARAM.rb +120 -0
  458. data/lib/Dnsruby/resource/OPT.rb +210 -0
  459. data/lib/Dnsruby/resource/PX.rb +71 -0
  460. data/lib/Dnsruby/resource/RP.rb +67 -0
  461. data/lib/Dnsruby/resource/RRSIG.rb +256 -0
  462. data/lib/Dnsruby/resource/RT.rb +67 -0
  463. data/lib/Dnsruby/resource/SOA.rb +95 -0
  464. data/lib/Dnsruby/resource/SPF.rb +29 -0
  465. data/lib/Dnsruby/resource/SRV.rb +112 -0
  466. data/lib/Dnsruby/resource/TKEY.rb +163 -0
  467. data/lib/Dnsruby/resource/TSIG.rb +584 -0
  468. data/lib/Dnsruby/resource/TXT.rb +76 -0
  469. data/lib/Dnsruby/resource/X25.rb +53 -0
  470. data/lib/Dnsruby/resource/domain_name.rb +54 -0
  471. data/lib/Dnsruby/resource/generic.rb +151 -0
  472. data/lib/Dnsruby/resource/resource.rb +561 -0
  473. data/lib/Dnsruby/select_thread.rb +449 -0
  474. data/lib/Dnsruby/update.rb +262 -0
  475. data/lib/Dnsruby/zone_transfer.rb +332 -0
  476. data/lib/dnsruby.rb +512 -0
  477. data/test/custom.txt +4 -0
  478. data/test/resolv.conf +4 -0
  479. data/test/tc_axfr.rb +32 -0
  480. data/test/tc_dns.rb +230 -0
  481. data/test/tc_dnskey.rb +52 -0
  482. data/test/tc_dnsruby.rb +42 -0
  483. data/test/tc_dnssec.rb +88 -0
  484. data/test/tc_ds.rb +38 -0
  485. data/test/tc_escapedchars.rb +484 -0
  486. data/test/tc_event_machine_deferrable.rb +85 -0
  487. data/test/tc_event_machine_res.rb +174 -0
  488. data/test/tc_event_machine_single_res.rb +101 -0
  489. data/test/tc_event_machine_soak.rb +98 -0
  490. data/test/tc_header.rb +104 -0
  491. data/test/tc_misc.rb +139 -0
  492. data/test/tc_name.rb +53 -0
  493. data/test/tc_nsec.rb +36 -0
  494. data/test/tc_nsec3.rb +63 -0
  495. data/test/tc_nsec3param.rb +30 -0
  496. data/test/tc_packet.rb +179 -0
  497. data/test/tc_packet_unique_push.rb +102 -0
  498. data/test/tc_question.rb +51 -0
  499. data/test/tc_res_config.rb +92 -0
  500. data/test/tc_res_env.rb +51 -0
  501. data/test/tc_res_file.rb +42 -0
  502. data/test/tc_res_opt.rb +187 -0
  503. data/test/tc_resolver.rb +184 -0
  504. data/test/tc_rr-opt.rb +82 -0
  505. data/test/tc_rr-txt.rb +137 -0
  506. data/test/tc_rr-unknown.rb +99 -0
  507. data/test/tc_rr.rb +258 -0
  508. data/test/tc_rrset.rb +58 -0
  509. data/test/tc_rrsig.rb +32 -0
  510. data/test/tc_single_resolver.rb +169 -0
  511. data/test/tc_soak.rb +200 -0
  512. data/test/tc_soak_base.rb +136 -0
  513. data/test/tc_tcp.rb +35 -0
  514. data/test/tc_tkey.rb +75 -0
  515. data/test/tc_tsig.rb +237 -0
  516. data/test/tc_update.rb +215 -0
  517. data/test/ts_dnsruby.rb +17 -0
  518. data/test/ts_offline.rb +42 -0
  519. data/test/ts_online.rb +107 -0
  520. metadata +627 -0
@@ -0,0 +1,293 @@
1
+ #--
2
+ #Copyright 2007 Nominet UK
3
+ #
4
+ #Licensed under the Apache License, Version 2.0 (the "License");
5
+ #you may not use this file except in compliance with the License.
6
+ #You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ #Unless required by applicable law or agreed to in writing, software
11
+ #distributed under the License is distributed on an "AS IS" BASIS,
12
+ #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ #See the License for the specific language governing permissions and
14
+ #limitations under the License.
15
+ #++
16
+ require 'Dnsruby/Hosts'
17
+ require 'Dnsruby/Config'
18
+ require "Dnsruby/Resolver"
19
+ module Dnsruby
20
+
21
+ #== Dnsruby::DNS class
22
+ #Resolv::DNS performs DNS queries.
23
+ #
24
+ #=== class methods
25
+ #* Dnsruby::DNS.new(config_info=nil)
26
+ #
27
+ # ((|config_info|)) should be nil, a string or a hash.
28
+ # If nil is given, /etc/resolv.conf and platform specific information is used.
29
+ # If a string is given, it should be a filename which format is same as /etc/resolv.conf.
30
+ # If a hash is given, it may contains information for nameserver, search and ndots as follows.
31
+ #
32
+ # Dnsruby::DNS.new({:nameserver=>["210.251.121.21"], :search=>["ruby-lang.org"], :ndots=>1})
33
+ #
34
+ #* Dnsruby::DNS.open(config_info=nil)
35
+ #* Dnsruby::Resolv::DNS.open(config_info=nil) {|dns| ...}
36
+ #
37
+ #=== methods
38
+ #* Dnsruby::DNS#close
39
+ #
40
+ #* Dnsruby::DNS#getaddress(name)
41
+ #* Dnsruby::DNS#getaddresses(name)
42
+ #* Dnsruby::DNS#each_address(name) {|address| ...}
43
+ # address lookup methods.
44
+ #
45
+ # ((|name|)) must be an instance of Dnsruby::Name or String. Resultant
46
+ # address is represented as an instance of Dnsruby::IPv4 or Dnsruby::IPv6.
47
+ #
48
+ #* Dnsruby::DNS#getname(address)
49
+ #* Dnsruby::DNS#getnames(address)
50
+ #* Dnsruby::DNS#each_name(address) {|name| ...}
51
+ # These methods lookup hostnames .
52
+ #
53
+ # ((|address|)) must be an instance of Dnsruby::IPv4, Dnsruby::IPv6 or String.
54
+ # Resultant name is represented as an instance of Dnsruby::Name.
55
+ #
56
+ #* Dnsruby::DNS#getresource(name, type, class)
57
+ #* Dnsruby::DNS#getresources(name, type, class)
58
+ #* Dnsruby::DNS#each_resource(name, type, class) {|resource| ...}
59
+ # These methods lookup DNS resources of ((|name|)).
60
+ # ((|name|)) must be a instance of Dnsruby::Name or String.
61
+ #
62
+ # ((|type|)) must be a member of Dnsruby::Types
63
+ # ((|class|)) must be a member of Dnsruby::Classes
64
+ #
65
+ # Resultant resource is represented as an instance of (a subclass of)
66
+ # Dnsruby::RR.
67
+ # (Dnsruby::RR::IN::A, etc.)
68
+ #
69
+ #The searchlist and other Config info is applied to the domain name if appropriate. All the nameservers
70
+ #are tried (if there is no timely answer from the first).
71
+ #
72
+ #This class uses Resolver to perform the queries.
73
+ #
74
+ #Information taken from the following places :
75
+ #* STD0013
76
+ #* RFC 1035, etc.
77
+ #* ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
78
+ #* etc.
79
+ class DNS
80
+
81
+ #Creates a new DNS resolver. See Resolv::DNS.new for argument details.
82
+ #
83
+ #Yields the created DNS resolver to the block, if given, otherwise returns it.
84
+ def self.open(*args)
85
+ dns = new(*args)
86
+ return dns unless block_given?
87
+ begin
88
+ yield dns
89
+ ensure
90
+ dns.close
91
+ end
92
+ end
93
+
94
+ #Closes the resolver
95
+ def close
96
+ @resolver.close
97
+ end
98
+
99
+
100
+ def to_s
101
+ return "DNS : " + @config.to_s
102
+ end
103
+
104
+ #Creates a new DNS resolver
105
+ #
106
+ #+config_info+ can be:
107
+ #
108
+ #* nil:: Uses platform default (e.g. /etc/resolv.conf)
109
+ #* String:: Path to a file using /etc/resolv.conf's format
110
+ #* Hash:: Must contain :nameserver, :search and :ndots keys
111
+ # example :
112
+ #
113
+ # Dnsruby::DNS.new({:nameserver => ['210.251.121.21'],
114
+ # :search => ['ruby-lang.org'],
115
+ # :ndots => 1})
116
+ def initialize(config_info=nil)
117
+ @config = Config.new()
118
+ @config.set_config_info(config_info)
119
+ @resolver = Resolver.new(@config)
120
+ end
121
+
122
+ attr_reader :config
123
+
124
+ #Gets the first IP address of +name+ from the DNS resolver
125
+ #
126
+ #+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
127
+ #Dnsruby::IPv4 or a Dnsruby::IPv6
128
+ def getaddress(name)
129
+ each_address(name) {|address| return address}
130
+ raise ResolvError.new("DNS result has no information for #{name}")
131
+ end
132
+
133
+ #Gets all IP addresses of +name+ from the DNS resolver
134
+ #
135
+ #+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
136
+ #Dnsruby::IPv4 or a Dnsruby::IPv6
137
+ def getaddresses(name)
138
+ ret = []
139
+ each_address(name) {|address| ret << address}
140
+ return ret
141
+ end
142
+
143
+ #Iterates over all IP addresses of +name+ retrieved from the DNS resolver
144
+ #
145
+ #+name+ can be a Dnsruby::Name or a String. Retrieved address will be a
146
+ #Dnsruby::IPv4 or a Dnsruby::IPv6
147
+ def each_address(name)
148
+ each_resource(name) {|resource| yield resource.address}
149
+ end
150
+
151
+ #Gets the first hostname for +address+ from the DNS resolver
152
+ #
153
+ #+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
154
+ #name will be a Dnsruby::Name.
155
+ def getname(address)
156
+ each_name(address) {|name| return name}
157
+ raise ResolvError.new("DNS result has no information for #{address}")
158
+ end
159
+
160
+ #Gets all hostnames for +address+ from the DNS resolver
161
+ #
162
+ #+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
163
+ #name will be a Dnsruby::Name.
164
+ def getnames(address)
165
+ ret = []
166
+ each_name(address) {|name| ret << name}
167
+ return ret
168
+ end
169
+
170
+ #Iterates over all hostnames for +address+ retrieved from the DNS resolver
171
+ #
172
+ #+address+ must be a Dnsruby::IPv4, Dnsruby::IPv6 or a String. Retrieved
173
+ #name will be a Dnsruby::Name.
174
+ def each_name(address)
175
+ case address
176
+ when Name
177
+ ptr = address
178
+ when IPv4::Regex
179
+ ptr = IPv4.create(address).to_name
180
+ when IPv6::Regex
181
+ ptr = IPv6.create(address).to_name
182
+ else
183
+ raise ResolvError.new("cannot interpret as address: #{address}")
184
+ end
185
+ each_resource(ptr, Types.PTR, Classes.IN) {|resource| yield resource.domainname}
186
+ end
187
+
188
+ #Look up the first +type+, +klass+ resource for +name+
189
+ #
190
+ #+type+ defaults to Dnsruby::Types.A
191
+ #+klass+ defaults to Dnsruby::Classes.IN
192
+ #
193
+ #Returned resource is represented as a Dnsruby::RR instance, e.g.
194
+ #Dnsruby::RR::IN::A
195
+ def getresource(name, type=Types.A, klass=Classes.IN)
196
+ each_resource(name, type, klass) {|resource| return resource}
197
+ raise ResolvError.new("DNS result has no information for #{name}")
198
+ end
199
+
200
+ #Look up all +type+, +klass+ resources for +name+
201
+ #
202
+ #+type+ defaults to Dnsruby::Types.A
203
+ #+klass+ defaults to Dnsruby::Classes.IN
204
+ #
205
+ #Returned resource is represented as a Dnsruby::RR instance, e.g.
206
+ #Dnsruby::RR::IN::A
207
+ def getresources(name, type=Types.A, klass=Classes.IN)
208
+ ret = []
209
+ each_resource(name, type, klass) {|resource| ret << resource}
210
+ return ret
211
+ end
212
+
213
+ #Iterates over all +type+, +klass+ resources for +name+
214
+ #
215
+ #+type+ defaults to Dnsruby::Types.A
216
+ #+klass+ defaults to Dnsruby::Classes.IN
217
+ #
218
+ #Yielded resource is represented as a Dnsruby::RR instance, e.g.
219
+ #Dnsruby::RR::IN::A
220
+ def each_resource(name, type=Types.A, klass=Classes.IN, &proc)
221
+ type = Types.new(type)
222
+ klass = Classes.new(klass)
223
+ reply, reply_name = send_query(name, type, klass)
224
+ case reply.header.rcode.code
225
+ when RCode::NOERROR
226
+ extract_resources(reply, reply_name, type, klass, &proc)
227
+ return
228
+ # when RCode::NXDomain
229
+ # TheLog.debug("RCode::NXDomain returned - raising error")
230
+ # raise Config::NXDomain.new(reply_name.to_s)
231
+ else
232
+ TheLog.error("Unexpected rcode : #{reply.header.rcode.string}")
233
+ raise Config::OtherResolvError.new(reply_name.to_s)
234
+ end
235
+ end
236
+
237
+ def extract_resources(msg, name, type, klass) # :nodoc:
238
+ if type == Types.ANY
239
+ n0 = Name.create(name)
240
+ msg.each_answer {|rec|
241
+ yield rec if n0 == rec.name
242
+ }
243
+ end
244
+ yielded = false
245
+ n0 = Name.create(name)
246
+ msg.each_answer {|rec|
247
+ if n0 == rec.name
248
+ case rec.type
249
+ when type
250
+ if (rec.klass == klass)
251
+ yield rec
252
+ yielded = true
253
+ end
254
+ when Types.CNAME
255
+ n0 = rec.domainname
256
+ end
257
+ end
258
+ }
259
+ return if yielded
260
+ msg.each_answer {|rec|
261
+ if n0 == rec.name
262
+ case rec.type
263
+ when type
264
+ if (rec.klass == klass)
265
+ yield rec
266
+ end
267
+ end
268
+ end
269
+ }
270
+ end
271
+
272
+ def send_query(name, type=Types.A, klass=Classes.IN) # :nodoc:
273
+ candidates = @config.generate_candidates(name)
274
+ exception = nil
275
+ candidates.each do |candidate|
276
+ q = Queue.new
277
+ msg = Message.new
278
+ msg.header.rd = 1
279
+ msg.add_question(candidate, type, klass)
280
+ @resolver.send_async(msg, q)
281
+ id, ret, exception = q.pop
282
+ if (exception == nil && ret.header.rcode == RCode.NOERROR)
283
+ return ret, ret.question[0].qname
284
+ end
285
+ end
286
+ raise exception
287
+ end
288
+
289
+ end
290
+ end
291
+ #--
292
+ #@TODO@ Asynchronous interface. Some sort of Deferrable?
293
+ #++
@@ -0,0 +1,126 @@
1
+ #--
2
+ #Copyright 2007 Nominet UK
3
+ #
4
+ #Licensed under the Apache License, Version 2.0 (the "License");
5
+ #you may not use this file except in compliance with the License.
6
+ #You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ #Unless required by applicable law or agreed to in writing, software
11
+ #distributed under the License is distributed on an "AS IS" BASIS,
12
+ #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ #See the License for the specific language governing permissions and
14
+ #limitations under the License.
15
+ #++
16
+ module Dnsruby
17
+ #== Dnsruby::Hosts class
18
+ #Dnsruby::Hosts is a hostname resolver that uses the system hosts file
19
+ #
20
+ #=== class methods
21
+ #* Dnsruby::Hosts.new(hosts='/etc/hosts')
22
+ #
23
+ #=== methods
24
+ #* Dnsruby::Hosts#getaddress(name)
25
+ #* Dnsruby::Hosts#getaddresses(name)
26
+ #* Dnsruby::Hosts#each_address(name) {|address| ...}
27
+ # address lookup methods.
28
+ #
29
+ #* Dnsruby::Hosts#getname(address)
30
+ #* Dnsruby::Hosts#getnames(address)
31
+ #* Dnsruby::Hosts#each_name(address) {|name| ...}
32
+ # hostnames lookup methods.
33
+ #
34
+ class Hosts
35
+ if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
36
+ require 'win32/resolv'
37
+ DefaultFileName = Win32::Resolv.get_hosts_path
38
+ else
39
+ DefaultFileName = '/etc/hosts'
40
+ end
41
+
42
+ #Creates a new Dnsruby::Hosts using +filename+ for its data source
43
+ def initialize(filename = DefaultFileName)
44
+ @filename = filename
45
+ @mutex = Mutex.new
46
+ @initialized = nil
47
+ end
48
+
49
+ def lazy_initialize# :nodoc:
50
+ @mutex.synchronize {
51
+ unless @initialized
52
+ @name2addr = {}
53
+ @addr2name = {}
54
+ begin
55
+ open(@filename) {|f|
56
+ f.each {|line|
57
+ line.sub!(/#.*/, '')
58
+ addr, hostname, *aliases = line.split(/\s+/)
59
+ next unless addr
60
+ addr.untaint
61
+ hostname.untaint
62
+ @addr2name[addr] = [] unless @addr2name.include? addr
63
+ @addr2name[addr] << hostname
64
+ @addr2name[addr] += aliases
65
+ @name2addr[hostname] = [] unless @name2addr.include? hostname
66
+ @name2addr[hostname] << addr
67
+ aliases.each {|n|
68
+ n.untaint
69
+ @name2addr[n] = [] unless @name2addr.include? n
70
+ @name2addr[n] << addr
71
+ }
72
+ }
73
+ }
74
+ rescue Exception
75
+ # Java won't find this file if running on Windows
76
+ end
77
+ @name2addr.each {|name, arr| arr.reverse!}
78
+ @initialized = true
79
+ end
80
+ }
81
+ self
82
+ end
83
+
84
+ #Gets the first IP address for +name+ from the hosts file
85
+ def getaddress(name)
86
+ each_address(name) {|address| return address}
87
+ raise ResolvError.new("#{@filename} has no name: #{name}")
88
+ end
89
+
90
+ #Gets all IP addresses for +name+ from the hosts file
91
+ def getaddresses(name)
92
+ ret = []
93
+ each_address(name) {|address| ret << address}
94
+ return ret
95
+ end
96
+
97
+ #Iterates over all IP addresses for +name+ retrieved from the hosts file
98
+ def each_address(name, &proc)
99
+ lazy_initialize
100
+ if @name2addr.include?(name)
101
+ @name2addr[name].each(&proc)
102
+ end
103
+ end
104
+
105
+ #Gets the first hostname of +address+ from the hosts file
106
+ def getname(address)
107
+ each_name(address) {|name| return name}
108
+ raise ResolvError.new("#{@filename} has no address: #{address}")
109
+ end
110
+
111
+ #Gets all hostnames for +address+ from the hosts file
112
+ def getnames(address)
113
+ ret = []
114
+ each_name(address) {|name| ret << name}
115
+ return ret
116
+ end
117
+
118
+ #Iterates over all hostnames for +address+ retrieved from the hosts file
119
+ def each_name(address, &proc)
120
+ lazy_initialize
121
+ if @addr2name.include?(address)
122
+ @addr2name[address].each(&proc)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,999 @@
1
+ #--
2
+ #Copyright 2007 Nominet UK
3
+ #
4
+ #Licensed under the Apache License, Version 2.0 (the "License");
5
+ #you may not use this file except in compliance with the License.
6
+ #You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ #Unless required by applicable law or agreed to in writing, software
11
+ #distributed under the License is distributed on an "AS IS" BASIS,
12
+ #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ #See the License for the specific language governing permissions and
14
+ #limitations under the License.
15
+ #++
16
+ require "Dnsruby/SingleResolver"
17
+ module Dnsruby
18
+ #== Description
19
+ #Dnsruby::Resolver is a DNS stub resolver.
20
+ #This class uses a set of SingleResolvers to perform queries with retries across multiple nameservers.
21
+ #
22
+ #The retry policy is a combination of the Net::DNS and dnsjava approach, and has the option of :
23
+ #* A total timeout for the query (defaults to 0, meaning "no total timeout")
24
+ #* A retransmission system that targets the namervers concurrently once the first query round is
25
+ # complete, but in which the total time per query round is split between the number of nameservers
26
+ # targetted for the first round. and total time for query round is doubled for each query round
27
+ #
28
+ # Note that, if a total timeout is specified, then that will apply regardless of the retry policy
29
+ #(i.e. it may cut retries short).
30
+ #
31
+ # Note also that these timeouts are distinct from the SingleResolver's packet_timeout
32
+ #
33
+ #== Methods
34
+ #
35
+ #=== Synchronous
36
+ #These methods raise an exception or return a response message with rcode==NOERROR
37
+ #
38
+ #* Dnsruby::Resolver#send_message(msg)
39
+ #* Dnsruby::Resolver#query(name [, type [, klass]])
40
+ #
41
+ #=== Asynchronous
42
+ #These methods use a response queue to return the response and the error
43
+ #
44
+ #* Dnsruby::Resolver#send_async(msg, response_queue, query_id)
45
+ #
46
+ #== Event Loop
47
+ #Dnsruby runs a pure Ruby event loop to handle I/O in a single thread.
48
+ #It is also possible to configure Dnsruby to use EventMachine instead.
49
+ #See the Dnsruby::Resolver::use_eventmachine method for details.
50
+ #
51
+ #Note that, if using Dnsruby from an EventMachine loop, you will need to tell
52
+ #Dnsruby not to start the event loop itself :
53
+ #
54
+ # Dnsruby::Resolver::use_eventmachine(true)
55
+ # Dnsruby::Resolver::start_eventmachine_loop(false)
56
+ class Resolver
57
+ @@event_machine_available=false
58
+ begin
59
+ require 'Dnsruby/event_machine_interface'
60
+ @@event_machine_available=true
61
+ TheLog.debug("EventMachine loaded")
62
+ rescue LoadError
63
+ TheLog.error("EventMachine not found")
64
+ end
65
+ DefaultQueryTimeout = 0
66
+ DefaultPacketTimeout = 10
67
+ DefaultRetryTimes = 4
68
+ DefaultRetryDelay = 5
69
+ DefaultPort = 53
70
+ DefaultUDPSize = 512
71
+ # The port to send queries to on the resolver
72
+ attr_reader :port
73
+
74
+ # Should TCP be used as a transport rather than UDP?
75
+ attr_reader :use_tcp
76
+
77
+
78
+ attr_reader :tsig
79
+
80
+ # Should truncation be ignored?
81
+ # i.e. the TC bit is ignored and thus the resolver will not requery over TCP if TC is set
82
+ attr_reader :ignore_truncation
83
+
84
+ # The source address to send queries from
85
+ attr_reader :src_address
86
+ # The source port to send queries from
87
+ attr_reader :src_port
88
+
89
+ # Should TCP queries be sent on a persistent socket?
90
+ attr_reader :persistent_tcp
91
+ # Should UDP queries be sent on a persistent socket?
92
+ attr_reader :persistent_udp
93
+
94
+ # Should the Recursion Desired bit be set?
95
+ attr_reader :recurse
96
+
97
+ # The maximum UDP size to be used
98
+ attr_reader :udp_size
99
+
100
+ # The current Config
101
+ attr_reader :config
102
+
103
+ # The array of SingleResolvers used for sending query messages
104
+ attr_reader :single_resolvers
105
+
106
+ #The timeout for any individual packet. This is the timeout used by SingleResolver
107
+ attr_reader :packet_timeout
108
+
109
+ # Note that this timeout represents the total time a query may run for - multiple packets
110
+ # can be sent to multiple nameservers in this time.
111
+ # This is distinct from the SingleResolver per-packet timeout
112
+ # The query_timeout is not required - it will default to 0, which means "do not use query_timeout".
113
+ # If this is the case then the timeout will be dictated by the retry_times and retry_delay attributes
114
+ attr_accessor :query_timeout
115
+
116
+ # The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds
117
+ # between each retry. The first time round, retry_delay will be divided by the number of nameservers
118
+ # being targetted, and a new nameserver will be queried with the resultant delay.
119
+ attr_accessor :retry_times, :retry_delay
120
+
121
+ # Use DNSSEC for this Resolver
122
+ attr_reader :dnssec
123
+
124
+ @@use_eventmachine=false
125
+ @@start_eventmachine_loop=true
126
+
127
+ #--
128
+ #@TODO@ add load_balance? i.e. Target nameservers in a random, rather than pre-determined, order?
129
+ #++
130
+
131
+ # Query for a n. If a valid Message is received, then it is returned
132
+ # to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
133
+ #
134
+ # require 'Dnsruby'
135
+ # res = Dnsruby::Resolver.new
136
+ # response = res.query("example.com") # defaults to Types.A, Classes.IN
137
+ # response = res.query("example.com", Types.MX)
138
+ # response = res.query("208.77.188.166") # IPv4 address so PTR query will be made
139
+ # response = res.query("208.77.188.166", Types.PTR)
140
+ def query(name, type=Types.A, klass=Classes.IN)
141
+ msg = Message.new
142
+ msg.header.rd = 1
143
+ msg.add_question(name, type, klass)
144
+ return send_message(msg)
145
+ end
146
+
147
+ # Send a message, and wait for the response. If a valid Message is received, then it is returned
148
+ # to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
149
+ #
150
+ # send_async is called internally.
151
+ #
152
+ # example :
153
+ #
154
+ # require 'Dnsruby'
155
+ # res = Dnsruby::Resolver.new
156
+ # begin
157
+ # response = res.send_message(Message.new("example.com", Types.MX))
158
+ # rescue ResolvError
159
+ # # ...
160
+ # rescue ResolvTimeout
161
+ # # ...
162
+ # end
163
+ def send_message(message)
164
+ TheLog.debug("Resolver : sending message")
165
+ q = Queue.new
166
+ send_async(message, q)
167
+ id, result, error = q.pop
168
+ TheLog.debug("Resolver : result received")
169
+ if (error != nil)
170
+ raise error
171
+ else
172
+ return result
173
+ end
174
+ end
175
+
176
+
177
+ #Asynchronously send a Message to the server. The send can be done using just
178
+ #Dnsruby, or using EventMachine.
179
+ #
180
+ #== Dnsruby pure Ruby event loop :
181
+ #
182
+ #A client_queue is supplied by the client,
183
+ #along with an optional client_query_id to identify the response. The client_query_id
184
+ #is generated, if not supplied, and returned to the client.
185
+ #When the response is known,
186
+ #a tuple of (query_id, response_message, exception) will be added to the client_queue.
187
+ #
188
+ #The query is sent synchronously in the caller's thread. The select thread is then used to
189
+ #listen for and process the response (up to pushing it to the client_queue). The client thread
190
+ #is then used to retrieve the response and deal with it.
191
+ #
192
+ #Takes :
193
+ #
194
+ #* msg - the message to send
195
+ #* client_queue - a Queue to push the response to, when it arrives
196
+ #* client_query_id - an optional ID to identify the query to the client
197
+ #* use_tcp - whether to use TCP (defaults to SingleResolver.use_tcp)
198
+ #
199
+ #Returns :
200
+ #
201
+ #* client_query_id - to identify the query response to the client. This ID is
202
+ #generated if it is not passed in by the client
203
+ #
204
+ #=== Example invocations :
205
+ #
206
+ # id = res.send_async(msg, queue)
207
+ # NOT SUPPORTED : id = res.send_async(msg, queue, use_tcp)
208
+ # id = res.send_async(msg, queue, id)
209
+ # id = res.send_async(msg, queue, id, use_tcp)
210
+ #
211
+ #=== Example code :
212
+ #
213
+ # require 'Dnsruby'
214
+ # res = Dnsruby::Resolver.new
215
+ # query_id = 10 # can be any object you like
216
+ # query_queue = Queue.new
217
+ # res.send_async(Message.new("example.com", Types.MX), query_queue, query_id)
218
+ # query_id_2 = res.send_async(Message.new("example.com", Types.A), query_queue)
219
+ # # ...do a load of other stuff here...
220
+ # 2.times do
221
+ # response_id, response, exception = query_queue.pop
222
+ # # You can check the ID to see which query has been answered
223
+ # if (exception == nil)
224
+ # # deal with good response
225
+ # else
226
+ # # deal with problem
227
+ # end
228
+ # end
229
+ #
230
+ #== If EventMachine is being used :
231
+ #
232
+ #If EventMachine is being used (see Dnsruby::Resolver::use_eventmachine, then this method returns
233
+ #an EM::Deferrable object. When the response is known, then the Deferrable will complete.
234
+ #If a queue (and ID) is passed in, then the response will also be
235
+ #pushed to the Queue. Note that an ID is not automatically generated by this version.
236
+ #
237
+ #=== Example invocations :
238
+ #
239
+ # deferrable = res.send_async(msg)
240
+ # deferrable = res.send_async(msg, use_tcp)
241
+ # deferrable = res.send_async(msg, q, id, use_tcp)
242
+ #
243
+ #=== Example code
244
+ #* Here is an example of using the code in an EventMachine style :
245
+ #
246
+ # require 'Dnsruby'
247
+ # require 'eventmachine'
248
+ # res = Dnsruby::Resolver.new
249
+ # Dnsruby::Resolver.use_eventmachine
250
+ # Dnsruby::Resolver.start_eventmachine_loop(false)
251
+ # EventMachine::run {
252
+ # df = res.send_async(Dnsruby::Message.new("example.com"))
253
+ # df.callback {|msg|
254
+ # puts "Response : #{msg}"
255
+ # EM.stop}
256
+ # df.errback {|msg, err|
257
+ # puts "Response : #{msg}"
258
+ # puts "Error: #{err}"
259
+ # EM.stop}
260
+ # }
261
+ #
262
+ #* And an example in a normal Dnsruby style :
263
+ #
264
+ # require 'Dnsruby'
265
+ # res = Dnsruby::Resolver.new
266
+ # Dnsruby::Resolver.use_eventmachine
267
+ # Dnsruby::Resolver.start_eventmachine_loop(true) # default
268
+ # q = Queue.new
269
+ # id = res.send_async(Dnsruby::Message.new("example.com"),q)
270
+ # id, response, error = q.pop
271
+ #
272
+ def send_async(*args) # msg, client_queue, client_query_id)
273
+ if (Resolver.eventmachine?)
274
+ if (!@resolver_em)
275
+ @resolver_em = ResolverEM.new(self)
276
+ end
277
+ return @resolver_em.send_async(*args)
278
+ else
279
+ if (!@resolver_ruby) # @TODO@ Synchronize this?
280
+ @resolver_ruby = ResolverRuby.new(self)
281
+ end
282
+ return @resolver_ruby.send_async(*args)
283
+ end
284
+ end
285
+
286
+ # Close the Resolver. Unfinished queries are terminated with OtherResolvError.
287
+ def close
288
+ [@resolver_em, @resolver_ruby].each do |r| r.close if r end
289
+ end
290
+
291
+ # Create a new Resolver object. If no parameters are passed in, then the default
292
+ # system configuration will be used. Otherwise, a Hash may be passed in with the
293
+ # following optional elements :
294
+ #
295
+ #
296
+ # * :port
297
+ # * :use_tcp
298
+ # * :tsig
299
+ # * :ignore_truncation
300
+ # * :src_address
301
+ # * :src_port
302
+ # * :persistent_tcp
303
+ # * :persistent_udp
304
+ # * :recurse
305
+ # * :udp_size
306
+ # * :config_info - see Config
307
+ # * :nameserver - can be either a String or an array of Strings
308
+ # * :packet_timeout
309
+ # * :query_timeout
310
+ # * :retry_times
311
+ # * :retry_delay
312
+ def initialize(*args)
313
+ @resolver_em = nil
314
+ @resolver_ruby = nil
315
+ @src_address = nil
316
+ reset_attributes
317
+
318
+ # Process args
319
+ if (args.length==1)
320
+ if (args[0].class == Hash)
321
+ args[0].keys.each do |key|
322
+ begin
323
+ if (key == :config_info)
324
+ @config.set_config_info(args[0][:config_info])
325
+ elsif (key==:nameserver)
326
+ set_config_nameserver(args[0][:nameserver])
327
+ else
328
+ send(key.to_s+"=", args[0][key])
329
+ end
330
+ rescue Exception
331
+ TheLog.error("Argument #{key} not valid\n")
332
+ end
333
+ end
334
+ elsif (args[0].class == String)
335
+ set_config_nameserver(args[0])
336
+ elsif (args[0].class == Config)
337
+ # also accepts a Config object from Dnsruby::Resolv
338
+ @config = args[0]
339
+ end
340
+ else
341
+ # Anything to do?
342
+ end
343
+ if (@single_resolvers==[])
344
+ add_config_nameservers
345
+ end
346
+ update
347
+ end
348
+
349
+ def add_config_nameservers
350
+ # Add the Config nameservers
351
+ @config.nameserver.each do |ns|
352
+ @single_resolvers.push(SingleResolver.new({:server=>ns}))
353
+ end
354
+ end
355
+
356
+ def set_config_nameserver(n)
357
+ if (n).kind_of?String
358
+ @config.nameserver=[n]
359
+ else
360
+ @config.nameserver=n
361
+ end
362
+ end
363
+
364
+ def reset_attributes #:nodoc: all
365
+ if (@resolver_em)
366
+ @resolver_em.reset_attributes
367
+ end
368
+ if (@resolver_ruby)
369
+ @resolver_ruby.reset_attributes
370
+ end
371
+
372
+ # Attributes
373
+ @query_timeout = DefaultQueryTimeout
374
+ @retry_delay = DefaultRetryDelay
375
+ @retry_times = DefaultRetryTimes
376
+ @packet_timeout = DefaultPacketTimeout
377
+ @port = DefaultPort
378
+ @udp_size = DefaultUDPSize
379
+ @use_tcp = false
380
+ @tsig = nil
381
+ @ignore_truncation = false
382
+ @config = Config.new()
383
+ @src_addr = '0.0.0.0'
384
+ @src_port = 0
385
+ @recurse = true
386
+ @persistent_udp = false
387
+ @persistent_tcp = false
388
+ @single_resolvers=[]
389
+ @dnssec = true
390
+ end
391
+
392
+ def update #:nodoc: all
393
+ #Update any resolvers we have with the latest config
394
+ @single_resolvers.each do |res|
395
+ [:port, :use_tcp, :tsig, :ignore_truncation, :packet_timeout,
396
+ :src_address, :src_port, :persistent_tcp, :persistent_udp, :recurse,
397
+ :udp_size, :dnssec].each do |param|
398
+
399
+ res.send(param.to_s+"=", instance_variable_get("@"+param.to_s))
400
+ end
401
+ end
402
+ end
403
+
404
+ # Add a new SingleResolver to the list of resolvers this Resolver object will
405
+ # query.
406
+ def add_resolver(single)
407
+ @single_resolvers.push(single)
408
+ end
409
+
410
+ def nameserver=(n)
411
+ @single_resolvers=[]
412
+ set_config_nameserver(n)
413
+ add_config_nameservers
414
+ end
415
+
416
+ #--
417
+ #@TODO@ Should really auto-generate these methods.
418
+ #Also, any way to tie them up with SingleResolver RDoc?
419
+ #++
420
+
421
+ def packet_timeout=(t)
422
+ @packet_timeout = t
423
+ update
424
+ end
425
+
426
+ def port=(p)
427
+ @port = p
428
+ update
429
+ end
430
+
431
+ def use_tcp=(on)
432
+ @use_tcp = on
433
+ update
434
+ end
435
+
436
+ #Sets the TSIG to sign outgoing messages with.
437
+ #Pass in either a Dnsruby::RR::TSIG, or a key_name and key (or just a key)
438
+ #Pass in nil to stop tsig signing.
439
+ #* res.tsig=(tsig_rr)
440
+ #* res.tsig=(key_name, key)
441
+ #* res.tsig=nil # Stop the resolver from signing
442
+ def tsig=(t)
443
+ @tsig=t
444
+ update
445
+ end
446
+
447
+ def ignore_truncation=(on)
448
+ @ignore_truncation = on
449
+ update
450
+ end
451
+
452
+ def src_address=(a)
453
+ @src_address = a
454
+ update
455
+ end
456
+
457
+ def src_port=(a)
458
+ @src_port = a
459
+ update
460
+ end
461
+
462
+ def persistent_tcp=(on)
463
+ @persistent_tcp = on
464
+ update
465
+ end
466
+
467
+ def persistent_udp=(on)
468
+ @persistent_udp = on
469
+ update
470
+ end
471
+
472
+ def recurse=(a)
473
+ @recurse = a
474
+ update
475
+ end
476
+
477
+ def dnssec=(d)
478
+ @dnssec = d
479
+ update
480
+ end
481
+
482
+ def udp_size=(s)
483
+ @udp_size = s
484
+ update
485
+ end
486
+ #Tell Dnsruby to use EventMachine for I/O.
487
+ #
488
+ #If EventMachine is not used, then the pure Ruby event loop in Dnsruby will
489
+ #be used instead.
490
+ #
491
+ #If EventMachine is not available on the platform, then a RuntimeError will be raised.
492
+ #
493
+ #Takes a bool to say whether or not to use EventMachine.
494
+ def Resolver.use_eventmachine(on=true)
495
+ if (on && !@@event_machine_available)
496
+ raise RuntimeError.new("EventMachine is not available in this environment!")
497
+ end
498
+ @@use_eventmachine = on
499
+ if (on)
500
+ TheLog.info("EventMachine will be used for IO")
501
+ else
502
+ TheLog.info("EventMachine will not be used for IO")
503
+ end
504
+ end
505
+ #Check whether EventMachine will be used by Dnsruby
506
+ def Resolver.eventmachine?
507
+ return @@use_eventmachine
508
+ end
509
+ #If EventMachine is being used, then this method tells Dnsruby whether or not
510
+ #to start the EventMachine loop. If you want to use Dnsruby client code as
511
+ #is, but using EventMachine for I/O, then Dnsruby must start the EventMachine
512
+ #loop for you. This is the default behaviour.
513
+ #If you want to use EventMachine-style code, where everything is wrapped
514
+ #up in an EventMachine::run{} call, then this method should be called with
515
+ #false as the parameter.
516
+ #
517
+ #Takes a bool argument to say whether or not to start the event loop when required.
518
+ def Resolver.start_eventmachine_loop(on=true)
519
+ @@start_eventmachine_loop=on
520
+ if (on)
521
+ TheLog.info("EventMachine loop will be started by Dnsruby")
522
+ else
523
+ TheLog.info("EventMachine loop will not be started by Dnsruby")
524
+ end
525
+ end
526
+ #Checks whether Dnsruby will start the EventMachine loop when required.
527
+ def Resolver.start_eventmachine_loop?
528
+ return @@start_eventmachine_loop
529
+ end
530
+ def generate_timeouts(base=0) #:nodoc: all
531
+ #These should be be pegged to the single_resolver they are targetting :
532
+ # e.g. timeouts[timeout1]=nameserver
533
+ timeouts = {}
534
+ retry_delay = @retry_delay
535
+ @retry_times.times do |retry_count|
536
+ if (retry_count>0)
537
+ retry_delay *= 2
538
+ end
539
+ servers=[]
540
+ @single_resolvers.each do |r| servers.push(r.server) end
541
+ @single_resolvers.each_index do |i|
542
+ res= @single_resolvers[i]
543
+ offset = (i*@retry_delay.to_f/@single_resolvers.length)
544
+ if (retry_count==0)
545
+ timeouts[base+offset]=[res, retry_count]
546
+ else
547
+ if (timeouts.has_key?(base+retry_delay+offset))
548
+ TheLog.error("Duplicate timeout key!")
549
+ raise RuntimeError.new("Duplicate timeout key!")
550
+ end
551
+ timeouts[base+retry_delay+offset]=[res, retry_count]
552
+ end
553
+ end
554
+ end
555
+ return timeouts
556
+ end
557
+ end
558
+
559
+ # This class implements the I/O using EventMachine.
560
+ # This is the preferred implementation.
561
+ # NOTE - EM does not work properly on Windows with version 0.8.1 - do not use!
562
+ class ResolverEM #:nodoc: all
563
+ TIMER_PERIOD = 0.1
564
+ def initialize(parent)
565
+ @parent=parent
566
+ end
567
+ def reset_attributes #:nodoc: all
568
+ end
569
+ class PersistentData
570
+ attr_accessor :outstanding, :deferrable, :to_send, :timeouts, :timer_procs, :timer_keys_sorted, :finish
571
+ end
572
+ def send_async(*args) #msg, client_queue=nil, client_query_id=nil)
573
+ msg=args[0]
574
+ client_queue=nil
575
+ client_query_id=nil
576
+ if (args.length>1)
577
+ client_queue=args[1]
578
+ if (args.length > 2)
579
+ client_query_id = args[2]
580
+ end
581
+ end
582
+ # We want to send the query to the first resolver.
583
+ # We then want to set up all the timers for all of the events which might happen
584
+ # (first round timers, retry timers, etc.)
585
+ # The callbacks for these should be able to cancel any of the rest (including any for broken resolvers)
586
+ # We can then forget about the query, as all the callbacks will be lodged with EventMachine.
587
+
588
+ EventMachineInterface::start_em_for_resolver(self)
589
+ persistent_data = PersistentData.new
590
+ persistent_data.deferrable = EM::DefaultDeferrable.new
591
+ persistent_data.outstanding = []
592
+ persistent_data.to_send = 0
593
+ persistent_data.timeouts=@parent.generate_timeouts(Time.now)
594
+ persistent_data.timer_procs = {}
595
+ persistent_data.finish = false
596
+ persistent_data.timeouts.keys.sort.each do |timeout|
597
+ value = persistent_data.timeouts[timeout]
598
+ # timeout = timeout.round
599
+ single_resolver, retry_count = value
600
+ persistent_data.to_send+=1
601
+ df = nil
602
+ if (timeout == 0)
603
+ # Send immediately
604
+ TheLog.debug("Sending first EM query")
605
+ df = send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
606
+ persistent_data.outstanding.push(df)
607
+ else
608
+ # Send later
609
+ persistent_data.timer_procs[timeout]=Proc.new{
610
+ TheLog.debug("Sending #{timeout} delayed EM query")
611
+ df = send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
612
+ persistent_data.outstanding.push(df)
613
+ }
614
+ end
615
+ end
616
+ query_timeout = @parent.query_timeout
617
+ if (query_timeout > 0)
618
+ persistent_data.timer_procs[Time.now+query_timeout]=Proc.new{
619
+ cancel_queries(persistent_data)
620
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, nil, ResolvTimeout.new("Query timed out after query_timeout=#{query_timeout.round} seconds"))
621
+ }
622
+ end
623
+ persistent_data.timer_keys_sorted = persistent_data.timer_procs.keys.sort
624
+ EventMachine::add_timer(0) {process_eventmachine_timers(persistent_data)}
625
+ return persistent_data.deferrable
626
+ end
627
+
628
+ # Close the Resolver. Unfinished queries are terminated with OtherResolvError.
629
+ def close
630
+ # @TODO@ We need a list of open deferrables so that we can complete them
631
+ end
632
+
633
+ def process_eventmachine_timers(persistent_data)
634
+ if (persistent_data.finish)
635
+ return
636
+ end
637
+ now = Time.now
638
+ persistent_data.timer_keys_sorted.each do |timeout|
639
+ if (timeout > now)
640
+ break
641
+ end
642
+ persistent_data.timer_procs[timeout].call
643
+ persistent_data.timer_procs.delete(timeout)
644
+ persistent_data.timer_keys_sorted.delete(timeout)
645
+ end
646
+ EventMachine::add_timer(TIMER_PERIOD) {process_eventmachine_timers(persistent_data)}
647
+ end
648
+
649
+ def send_new_em_query(single_resolver, msg, client_queue, client_query_id, persistent_data)
650
+ df = single_resolver.send_async(msg) # client_queue, client_query_id)
651
+ persistent_data.to_send-=1
652
+ df.callback { |answer|
653
+ TheLog.debug("Response returned")
654
+ persistent_data.outstanding.delete(df)
655
+ cancel_queries(persistent_data)
656
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, answer, nil)
657
+ }
658
+ df.errback { |response, error|
659
+ TheLog.debug("Error #{error} returned")
660
+ persistent_data.outstanding.delete(df)
661
+ if (response!="cancelling")
662
+
663
+ if (error.kind_of?(ResolvTimeout))
664
+ # - if it was a timeout, then check which number it was, and how many retries are expected on that server
665
+ # - if it was the last retry, on the last server, then return a timeout to the client (and clean up)
666
+ # - otherwise, continue
667
+ # Do we have any more packets to send to this resolver?
668
+ if (persistent_data.outstanding.empty? && persistent_data.to_send==0)
669
+ TheLog.debug("Sending timeout to client")
670
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
671
+ end
672
+ elsif (error.kind_of?NXDomain)
673
+ # - if it was an NXDomain, then return that to the client, and stop all new queries (and clean up)
674
+ TheLog.debug("NXDomain - returning to client")
675
+ cancel_queries(persistent_data)
676
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
677
+ elsif (error.kind_of?FormErr)
678
+ # - if it was a FormErr, then return that to the client, and stop all new queries (and clean up)
679
+ TheLog.debug("FormErr - returning to client")
680
+ cancel_queries(persistent_data)
681
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
682
+ else
683
+ # - if it was any other error, then remove that server from the list for that query
684
+ # If a Too Many Open Files error, then don't remove, but let retry work.
685
+ if (!(error.to_s=~/Errno::EMFILE/))
686
+ remove_server(single_resolver, persistent_data)
687
+ TheLog.debug("Removing #{single_resolver.server} from resolver list for this query")
688
+ else
689
+ TheLog.debug("NOT Removing #{single_resolver.server} due to Errno::EMFILE")
690
+ end
691
+ # - if it was the last server, then return an error to the client (and clean up)
692
+ if (persistent_data.outstanding.empty? && persistent_data.to_send==0)
693
+ # if (outstanding.empty?)
694
+ TheLog.debug("Sending error to client")
695
+ return_to_client(persistent_data.deferrable, client_queue, client_query_id, response, error)
696
+ end
697
+ end
698
+ end
699
+ }
700
+ return df
701
+ end
702
+
703
+ def remove_server(server, persistent_data)
704
+ # Go through persistent_data.timeouts and check all the values for that resolver
705
+ persistent_data.timeouts.each do |key, value|
706
+ if (value[0] == server)
707
+ # Remove the server from the list
708
+ persistent_data.timer_procs.delete(key)
709
+ persistent_data.timer_keys_sorted.delete(key)
710
+ end
711
+ end
712
+ end
713
+
714
+ def cancel_queries(persistent_data)
715
+ TheLog.debug("Cancelling EM queries")
716
+ persistent_data.outstanding.each do |df|
717
+ df.set_deferred_status :failed, "cancelling", "cancelling"
718
+ end
719
+ # Cancel the next tick
720
+ persistent_data.finish = true
721
+ end
722
+
723
+ def return_to_client(deferrable, client_queue, client_query_id, answer, error)
724
+ if (client_queue)
725
+ client_queue.push([client_query_id, answer, error])
726
+ end
727
+ # We call set_defered_status when done
728
+ if (error != nil)
729
+ deferrable.set_deferred_status :failed, answer, error
730
+ else
731
+ deferrable.set_deferred_status :succeeded, answer
732
+ end
733
+ EventMachineInterface::stop_em_for_resolver(self)
734
+ end
735
+ end
736
+
737
+ # This class implements the I/O using pure Ruby, with no dependencies.
738
+ class ResolverRuby #:nodoc: all
739
+ def initialize(parent)
740
+ reset_attributes
741
+ @parent=parent
742
+ end
743
+ def reset_attributes #:nodoc: all
744
+ # data structures
745
+ @mutex=Mutex.new
746
+ @query_list = {}
747
+ @timeouts = {}
748
+ end
749
+ def send_async(*args) # msg, client_queue, client_query_id=nil)
750
+ msg=args[0]
751
+ client_queue=nil
752
+ client_query_id=nil
753
+ client_queue=args[1]
754
+ if (args.length > 2)
755
+ client_query_id = args[2]
756
+ end
757
+
758
+
759
+ # This is the whole point of the Resolver class.
760
+ # We want to use multiple SingleResolvers to run a query.
761
+ # So we kick off a system with select_thread where we send
762
+ # a query with a queue, but log ourselves as observers for that
763
+ # queue. When a new response is pushed on to the queue, then the
764
+ # select thread will call this class' handler method IN THAT THREAD.
765
+ # When the final response is known, this class then sticks it in
766
+ # to the client queue.
767
+
768
+ q = Queue.new
769
+ if (client_query_id==nil)
770
+ client_query_id = Time.now + rand(10000)
771
+ end
772
+
773
+ if (!client_queue.kind_of?Queue)
774
+ TheLog.error("Wrong type for client_queue in Resolver#send_async")
775
+ client_queue.push([client_query_id, ArgumentError.new("Wrong type of client_queue passed to Dnsruby::Resolver#send_async - should have been Queue, was #{client_queue.class}")])
776
+ return
777
+ end
778
+
779
+ if (!msg.kind_of?Message)
780
+ TheLog.error("Wrong type for msg in Resolver#send_async")
781
+ client_queue.push([client_query_id, ArgumentError.new("Wrong type of msg passed to Dnsruby::Resolver#send_async - should have been Message, was #{msg.class}")])
782
+ return
783
+ end
784
+
785
+ tick_needed=false
786
+ # add to our data structures
787
+ @mutex.synchronize{
788
+ tick_needed = true if @query_list.empty?
789
+ if (@query_list.has_key?client_query_id)
790
+ TheLog.error("Duplicate query id requested (#{client_query_id}")
791
+ client_queue.push([client_query_id, ArgumentError.new("Client query ID already in use")])
792
+ return
793
+ end
794
+ outstanding = []
795
+ @query_list[client_query_id]=[msg, client_queue, q, outstanding]
796
+
797
+ query_timeout = Time.now+@parent.query_timeout
798
+ if (@parent.query_timeout == 0)
799
+ query_timeout = Time.now+31536000 # a year from now
800
+ end
801
+ @timeouts[client_query_id]=[query_timeout, generate_timeouts()]
802
+ }
803
+
804
+ # Now do querying stuff using SingleResolver
805
+ # All this will be handled by the tick method (if we have 0 as the first timeout)
806
+ st = SelectThread.instance
807
+ st.add_observer(q, self)
808
+ tick if tick_needed
809
+ return client_query_id
810
+ end
811
+
812
+ def generate_timeouts() #:nodoc: all
813
+ # Create the timeouts for the query from the retry_times and retry_delay attributes.
814
+ # These are created at the same time in case the parameters change during the life of the query.
815
+ #
816
+ # These should be absolute, rather than relative
817
+ # The first value should be Time.now[
818
+ time_now = Time.now
819
+ timeouts=@parent.generate_timeouts(time_now)
820
+ return timeouts
821
+ end
822
+
823
+ # Close the Resolver. Unfinished queries are terminated with OtherResolvError.
824
+ def close
825
+ @mutex.synchronize {
826
+ @query_list.each do |client_query_id, values|
827
+ msg, client_queue, q, outstanding = values
828
+ send_result_and_close(client_queue, client_query_id, q, nil, OtherResolvError.new("Resolver closing!"))
829
+ end
830
+ }
831
+ end
832
+
833
+ # MUST BE CALLED IN A SYNCHRONIZED BLOCK!
834
+ #
835
+ # Send the result back to the client, and close the socket for that query by removing
836
+ # the query from the select thread.
837
+ def send_result_and_close(client_queue, client_query_id, select_queue, msg, error) #:nodoc: all
838
+ # We might still get some callbacks, which we should ignore
839
+ st = SelectThread.instance
840
+ st.remove_observer(select_queue, self)
841
+ # @mutex.synchronize{
842
+ # Remove the query from all of the data structures
843
+ @timeouts.delete(client_query_id)
844
+ @query_list.delete(client_query_id)
845
+ # }
846
+ # Return the response to the client
847
+ client_queue.push([client_query_id, msg, error])
848
+ end
849
+
850
+ # This method is called ten times a second from the select loop, in the select thread.
851
+ # It should arguably be called from another worker thread...
852
+ # Each tick, we check if any timeouts have occurred. If so, we take the appropriate action :
853
+ # Return a timeout to the client, or send a new query
854
+ def tick #:nodoc: all
855
+ # Handle the tick
856
+ # Do we have any retries due to be sent yet?
857
+ @mutex.synchronize{
858
+ time_now = Time.now
859
+ @timeouts.keys.each do |client_query_id|
860
+ msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
861
+ query_timeout, timeouts = @timeouts[client_query_id]
862
+ if (query_timeout < Time.now)
863
+ #Time the query out
864
+ send_result_and_close(client_queue, client_query_id, select_queue, nil, ResolvTimeout.new("Query timed out"))
865
+ next
866
+ end
867
+ timeouts_done = []
868
+ timeouts.keys.sort.each do |timeout|
869
+ if (timeout < time_now)
870
+ # Send the next query
871
+ res, retry_count = timeouts[timeout]
872
+ id = [res, msg, client_query_id, retry_count]
873
+ TheLog.debug("Sending msg to #{res.server}")
874
+ # We should keep a list of the queries which are outstanding
875
+ outstanding.push(id)
876
+ timeouts_done.push(timeout)
877
+ timeouts.delete(timeout)
878
+ res.send_async(msg, select_queue, id)
879
+ else
880
+ break
881
+ end
882
+ end
883
+ timeouts_done.each do |t|
884
+ timeouts.delete(t)
885
+ end
886
+ end
887
+ }
888
+ end
889
+
890
+ # This method is called by the SelectThread (in the select thread) when the queue has a new item on it.
891
+ # The queue interface is used to separate producer/consumer threads, but we're using it here in one thread.
892
+ # It's probably a good idea to create a new "worker thread" to take items from the select thread queue and
893
+ # call this method in the worker thread.
894
+ #
895
+ # Time to process a new queue event.
896
+ def handle_queue_event(queue, id) #:nodoc: all
897
+ # If we get a callback for an ID we don't know about, don't worry -
898
+ # just ignore it. It may be for a query we've already completed.
899
+ #
900
+ # So, get the next response from the queue (presuming there is one!)
901
+ #
902
+ # @TODO@ Tick could poll the queue and then call this method if needed - no need for observer interface.
903
+ # @TODO@ Currently, tick and handle_queue_event called from select_thread - could have thread chuck events in to tick_queue. But then, clients would have to call in on other thread!
904
+ #
905
+ if (queue.empty?)
906
+ TheLog.fatal("Queue empty in handle_queue_event!")
907
+ raise RuntimeError.new("Severe internal error - Queue empty in handle_queue_event")
908
+ end
909
+ event_id, response, error = queue.pop
910
+ # We should remove this packet from the list of outstanding packets for this query
911
+ resolver, msg, client_query_id, retry_count = id
912
+ if (id != event_id)
913
+ TheLog.error("Serious internal error!! #{id} expected, #{event_id} received")
914
+ raise RuntimeError.new("Serious internal error!! #{id} expected, #{event_id} received")
915
+ end
916
+ @mutex.synchronize{
917
+ if (@query_list[client_query_id]==nil)
918
+ TheLog.debug("Ignoring response for dead query")
919
+ return
920
+ end
921
+ msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
922
+ if (!outstanding.include?id)
923
+ TheLog.error("Query id not on outstanding list! #{outstanding.length} items. #{id} not on #{outstanding}")
924
+ raise RuntimeError.new("Query id not on outstanding!")
925
+ end
926
+ outstanding.delete(id)
927
+ }
928
+ # if (event.kind_of?(Exception))
929
+ if (error != nil)
930
+ handle_error_response(queue, event_id, error, response)
931
+ else # if (event.kind_of?(Message))
932
+ handle_response(queue, event_id, response)
933
+ # else
934
+ # TheLog.error("Random object #{event.class} returned through queue to Resolver")
935
+ end
936
+ end
937
+
938
+ def handle_error_response(select_queue, query_id, error, response) #:nodoc: all
939
+ #Handle an error
940
+ @mutex.synchronize{
941
+ TheLog.debug("handling error #{error.class}, #{error}")
942
+ # Check what sort of error it was :
943
+ resolver, msg, client_query_id, retry_count = query_id
944
+ msg, client_queue, select_queue, outstanding = @query_list[client_query_id]
945
+ if (error.kind_of?(ResolvTimeout))
946
+ # - if it was a timeout, then check which number it was, and how many retries are expected on that server
947
+ # - if it was the last retry, on the last server, then return a timeout to the client (and clean up)
948
+ # - otherwise, continue
949
+ # Do we have any more packets to send to this resolver?
950
+ timeouts = @timeouts[client_query_id]
951
+ if (outstanding.empty? && timeouts[1].values.empty?)
952
+ TheLog.debug("Sending timeout to client")
953
+ send_result_and_close(client_queue, client_query_id, select_queue, response, error)
954
+ end
955
+ elsif (error.kind_of?NXDomain)
956
+ # - if it was an NXDomain, then return that to the client, and stop all new queries (and clean up)
957
+ send_result_and_close(client_queue, client_query_id, select_queue, response, error)
958
+ else
959
+ # - if it was any other error, then remove that server from the list for that query
960
+ # If a Too Many Open Files error, then don't remove, but let retry work.
961
+ timeouts = @timeouts[client_query_id]
962
+ if (!(error.to_s=~/Errno::EMFILE/))
963
+ TheLog.debug("Removing #{resolver.server} from resolver list for this query")
964
+ timeouts[1].each do |key, value|
965
+ res = value[0]
966
+ if (res == resolver)
967
+ timeouts[1].delete(key)
968
+ end
969
+ end
970
+ else
971
+ TheLog.debug("NOT Removing #{resolver.server} due to Errno::EMFILE")
972
+ end
973
+ # - if it was the last server, then return an error to the client (and clean up)
974
+ if (outstanding.empty? && timeouts[1].values.empty?)
975
+ # if (outstanding.empty?)
976
+ TheLog.debug("Sending error to client")
977
+ send_result_and_close(client_queue, client_query_id, select_queue, response, error)
978
+ end
979
+ end
980
+ #@TODO@ If we're still sending packets for this query, but none are outstanding, then
981
+ #jumpstart the next query?
982
+ }
983
+ end
984
+
985
+ def handle_response(select_queue, query_id, response) #:nodoc: all
986
+ # Handle a good response
987
+ TheLog.debug("Handling good response")
988
+ resolver, msg, client_query_id, retry_count = query_id
989
+ @mutex.synchronize{
990
+ query, client_queue, s_queue, outstanding = @query_list[client_query_id]
991
+ if (s_queue != select_queue)
992
+ TheLog.error("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
993
+ raise RuntimeError.new("Serious internal error : expected select queue #{s_queue}, got #{select_queue}")
994
+ end
995
+ send_result_and_close(client_queue, client_query_id, select_queue, response, nil)
996
+ }
997
+ end
998
+ end
999
+ end