dnsruby 1.1

Sign up to get free protection for your applications and to get access to all the features.
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